From 89f6931b267988e8969715ded808cf8477f013a9 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Wed, 25 Jul 2018 21:05:35 -0400 Subject: [PATCH 001/109] Fix k_eff calc for runs with reset in the middle --- src/api.F90 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/api.F90 b/src/api.F90 index 8afc6061cd..e38b2d0b28 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -276,6 +276,10 @@ contains k_abs_tra = ZERO k_sum(:) = ZERO + ! Set the number of inactive batches (used to compute k_eff for the fission + ! bank). + n_inactive = current_batch + ! Clear active tally lists call active_analog_tallies % clear() call active_tracklength_tallies % clear() From c0d3e37e26761fc1c8c515d6743567cb7631dc71 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Mon, 30 Jul 2018 12:54:12 -0400 Subject: [PATCH 002/109] Add n_realizations_gen for robust keff calculation --- openmc/capi/tally.py | 2 +- src/api.F90 | 7 ++----- src/eigenvalue.F90 | 6 +++--- src/output.F90 | 4 ++-- src/simulation.F90 | 8 +++++++- src/state_point.F90 | 7 ++++--- src/tallies/tally.F90 | 4 ++-- src/tallies/tally_header.F90 | 5 +++-- 8 files changed, 24 insertions(+), 19 deletions(-) diff --git a/openmc/capi/tally.py b/openmc/capi/tally.py index d4d70af718..cb647b8cee 100644 --- a/openmc/capi/tally.py +++ b/openmc/capi/tally.py @@ -116,7 +116,7 @@ def global_tallies(): def num_realizations(): """Number of realizations of global tallies.""" - return c_int32.in_dll(_dll, 'n_realizations').value + return c_int32.in_dll(_dll, 'n_realizations_batch').value class Tally(_FortranObjectWithID): diff --git a/src/api.F90 b/src/api.F90 index e38b2d0b28..cf298512c5 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -267,7 +267,8 @@ contains end if ! Reset global tallies - n_realizations = 0 + n_realizations_batch = 0 + n_realizations_gen = 0 if (allocated(global_tallies)) then global_tallies(:, :) = ZERO end if @@ -276,10 +277,6 @@ contains k_abs_tra = ZERO k_sum(:) = ZERO - ! Set the number of inactive batches (used to compute k_eff for the fission - ! bank). - n_inactive = current_batch - ! Clear active tally lists call active_analog_tallies % clear() call active_tracklength_tallies % clear() diff --git a/src/eigenvalue.F90 b/src/eigenvalue.F90 index 7a11d1fb48..9b2cc8ff4b 100644 --- a/src/eigenvalue.F90 +++ b/src/eigenvalue.F90 @@ -380,7 +380,7 @@ contains ! Determine overall generation and number of active generations i = overall_generation() - n = i - n_inactive*gen_per_batch + n = n_realizations_gen if (n <= 0) then ! For inactive generations, use current generation k as estimate for next @@ -438,13 +438,13 @@ contains ! Make sure we have at least four realizations. Notice that at the end, ! there is a N-3 term in a denominator. - if (n_realizations <= 3) then + if (n_realizations_batch <= 3) then err = -1 return end if ! Initialize variables - n = real(n_realizations, 8) + n = real(n_realizations_batch, 8) ! Copy estimates of k-effective and its variance (not variance of the mean) kv(1) = global_tallies(RESULT_SUM, K_COLLISION) / n diff --git a/src/output.F90 b/src/output.F90 index 6197cdc11c..c8fa67f03c 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -569,7 +569,7 @@ contains ! display header block for results call header("Results", 4) - n = n_realizations + n = n_realizations_batch if (confidence_intervals) then ! Calculate t-value for confidence intervals @@ -714,7 +714,7 @@ contains ! Calculate t-value for confidence intervals if (confidence_intervals) then alpha = ONE - CONFIDENCE_LEVEL - t_value = t_percentile(ONE - alpha/TWO, n_realizations - 1) + t_value = t_percentile(ONE - alpha/TWO, n_realizations_batch - 1) else t_value = ONE end if diff --git a/src/simulation.F90 b/src/simulation.F90 index ffcfb8bab8..14b6ba688b 100644 --- a/src/simulation.F90 +++ b/src/simulation.F90 @@ -281,6 +281,9 @@ contains if (entropy_on) call shannon_entropy() ! Collect results and statistics + if (current_batch > n_inactive) then + n_realizations_gen = n_realizations_gen + 1 + end if call calculate_generation_keff() call calculate_average_keff() @@ -325,7 +328,7 @@ contains ! Reset global tally results if (current_batch <= n_inactive) then global_tallies(:,:) = ZERO - n_realizations = 0 + n_realizations_batch = 0 end if if (run_mode == MODE_EIGENVALUE) then @@ -373,6 +376,9 @@ contains if (run_mode == MODE_EIGENVALUE) then do current_gen = 1, gen_per_batch + if (current_batch > n_inactive) then + n_realizations_gen = n_realizations_gen + 1 + end if call calculate_average_keff() ! print out batch keff diff --git a/src/state_point.F90 b/src/state_point.F90 index ebb473d496..eef0cf370b 100644 --- a/src/state_point.F90 +++ b/src/state_point.F90 @@ -359,7 +359,7 @@ contains elseif (master) then ! Write number of global realizations - call write_dataset(file_id, "n_realizations", n_realizations) + call write_dataset(file_id, "n_realizations", n_realizations_batch) ! Write global tallies call write_dataset(file_id, "global_tallies", global_tallies) @@ -518,7 +518,7 @@ contains if (master) then ! Write number of realizations - call write_dataset(file_id, "n_realizations", n_realizations) + call write_dataset(file_id, "n_realizations", n_realizations_batch) ! Write number of global tallies call write_dataset(file_id, "n_global_tallies", N_GLOBAL_TALLIES) @@ -756,7 +756,8 @@ contains #endif ! Read number of realizations for global tallies - call read_dataset(n_realizations, file_id, "n_realizations", indep=.true.) + call read_dataset(n_realizations_batch, file_id, "n_realizations", & + indep=.true.) ! Read global tally data call read_dataset(global_tallies, file_id, "global_tallies") diff --git a/src/tallies/tally.F90 b/src/tallies/tally.F90 index ed0963a883..9761ef288a 100644 --- a/src/tallies/tally.F90 +++ b/src/tallies/tally.F90 @@ -3784,9 +3784,9 @@ contains ! Increase number of realizations (only used for global tallies) if (reduce_tallies) then - n_realizations = n_realizations + 1 + n_realizations_batch = n_realizations_batch + 1 else - n_realizations = n_realizations + n_procs + n_realizations_batch = n_realizations_batch + n_procs end if ! Accumulate on master only unless run is not reduced then do it on all diff --git a/src/tallies/tally_header.F90 b/src/tallies/tally_header.F90 index ee44685924..3418df12a6 100644 --- a/src/tallies/tally_header.F90 +++ b/src/tallies/tally_header.F90 @@ -145,8 +145,9 @@ module tally_header type(VectorInt), public :: active_tallies type(VectorInt), public :: active_surface_tallies - ! Normalization for statistics - integer(C_INT32_T), public, bind(C) :: n_realizations = 0 ! # of independent realizations + ! Normalization for batch-based and generation-based global tally statistics + integer(C_INT32_T), public, bind(C) :: n_realizations_batch = 0 + integer(C_INT32_T), public, bind(C) :: n_realizations_gen = 0 real(8), public :: total_weight ! total starting particle weight in realization contains From 5af37d4d5badf28d8864588cd66882b90e7585b5 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Tue, 31 Jul 2018 07:39:53 -0500 Subject: [PATCH 003/109] Use n_realizations for keff calculation --- openmc/capi/tally.py | 2 +- src/api.F90 | 3 +-- src/eigenvalue.F90 | 10 +++++++--- src/output.F90 | 12 ++++++++---- src/simulation.F90 | 8 +------- src/state_point.F90 | 7 +++---- src/tallies/tally.F90 | 4 ++-- src/tallies/tally_header.F90 | 5 ++--- 8 files changed, 25 insertions(+), 26 deletions(-) diff --git a/openmc/capi/tally.py b/openmc/capi/tally.py index cb647b8cee..d4d70af718 100644 --- a/openmc/capi/tally.py +++ b/openmc/capi/tally.py @@ -116,7 +116,7 @@ def global_tallies(): def num_realizations(): """Number of realizations of global tallies.""" - return c_int32.in_dll(_dll, 'n_realizations_batch').value + return c_int32.in_dll(_dll, 'n_realizations').value class Tally(_FortranObjectWithID): diff --git a/src/api.F90 b/src/api.F90 index cf298512c5..8afc6061cd 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -267,8 +267,7 @@ contains end if ! Reset global tallies - n_realizations_batch = 0 - n_realizations_gen = 0 + n_realizations = 0 if (allocated(global_tallies)) then global_tallies(:, :) = ZERO end if diff --git a/src/eigenvalue.F90 b/src/eigenvalue.F90 index 9b2cc8ff4b..d47bc4dab8 100644 --- a/src/eigenvalue.F90 +++ b/src/eigenvalue.F90 @@ -380,7 +380,11 @@ contains ! Determine overall generation and number of active generations i = overall_generation() - n = n_realizations_gen + if (current_batch > n_inactive) then + n = gen_per_batch*n_realizations + current_gen + else + n = 0 + end if if (n <= 0) then ! For inactive generations, use current generation k as estimate for next @@ -438,13 +442,13 @@ contains ! Make sure we have at least four realizations. Notice that at the end, ! there is a N-3 term in a denominator. - if (n_realizations_batch <= 3) then + if (n_realizations <= 3) then err = -1 return end if ! Initialize variables - n = real(n_realizations_batch, 8) + n = real(n_realizations, 8) ! Copy estimates of k-effective and its variance (not variance of the mean) kv(1) = global_tallies(RESULT_SUM, K_COLLISION) / n diff --git a/src/output.F90 b/src/output.F90 index c8fa67f03c..128080e61c 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -324,7 +324,11 @@ contains ! Determine overall generation and number of active generations i = overall_generation() - n = i - n_inactive*gen_per_batch + if (current_batch > n_inactive) then + n = gen_per_batch*n_realizations + current_gen + else + n = 0 + end if ! write out information about batch and generation write(UNIT=OUTPUT_UNIT, FMT='(2X,A9)', ADVANCE='NO') & @@ -357,7 +361,7 @@ contains ! Determine overall generation and number of active generations i = current_batch*gen_per_batch - n = i - n_inactive*gen_per_batch + n = n_realizations*gen_per_batch ! write out information batch and option independent output write(UNIT=OUTPUT_UNIT, FMT='(2X,A9)', ADVANCE='NO') & @@ -569,7 +573,7 @@ contains ! display header block for results call header("Results", 4) - n = n_realizations_batch + n = n_realizations if (confidence_intervals) then ! Calculate t-value for confidence intervals @@ -714,7 +718,7 @@ contains ! Calculate t-value for confidence intervals if (confidence_intervals) then alpha = ONE - CONFIDENCE_LEVEL - t_value = t_percentile(ONE - alpha/TWO, n_realizations_batch - 1) + t_value = t_percentile(ONE - alpha/TWO, n_realizations - 1) else t_value = ONE end if diff --git a/src/simulation.F90 b/src/simulation.F90 index 14b6ba688b..ffcfb8bab8 100644 --- a/src/simulation.F90 +++ b/src/simulation.F90 @@ -281,9 +281,6 @@ contains if (entropy_on) call shannon_entropy() ! Collect results and statistics - if (current_batch > n_inactive) then - n_realizations_gen = n_realizations_gen + 1 - end if call calculate_generation_keff() call calculate_average_keff() @@ -328,7 +325,7 @@ contains ! Reset global tally results if (current_batch <= n_inactive) then global_tallies(:,:) = ZERO - n_realizations_batch = 0 + n_realizations = 0 end if if (run_mode == MODE_EIGENVALUE) then @@ -376,9 +373,6 @@ contains if (run_mode == MODE_EIGENVALUE) then do current_gen = 1, gen_per_batch - if (current_batch > n_inactive) then - n_realizations_gen = n_realizations_gen + 1 - end if call calculate_average_keff() ! print out batch keff diff --git a/src/state_point.F90 b/src/state_point.F90 index eef0cf370b..ebb473d496 100644 --- a/src/state_point.F90 +++ b/src/state_point.F90 @@ -359,7 +359,7 @@ contains elseif (master) then ! Write number of global realizations - call write_dataset(file_id, "n_realizations", n_realizations_batch) + call write_dataset(file_id, "n_realizations", n_realizations) ! Write global tallies call write_dataset(file_id, "global_tallies", global_tallies) @@ -518,7 +518,7 @@ contains if (master) then ! Write number of realizations - call write_dataset(file_id, "n_realizations", n_realizations_batch) + call write_dataset(file_id, "n_realizations", n_realizations) ! Write number of global tallies call write_dataset(file_id, "n_global_tallies", N_GLOBAL_TALLIES) @@ -756,8 +756,7 @@ contains #endif ! Read number of realizations for global tallies - call read_dataset(n_realizations_batch, file_id, "n_realizations", & - indep=.true.) + call read_dataset(n_realizations, file_id, "n_realizations", indep=.true.) ! Read global tally data call read_dataset(global_tallies, file_id, "global_tallies") diff --git a/src/tallies/tally.F90 b/src/tallies/tally.F90 index 9761ef288a..ed0963a883 100644 --- a/src/tallies/tally.F90 +++ b/src/tallies/tally.F90 @@ -3784,9 +3784,9 @@ contains ! Increase number of realizations (only used for global tallies) if (reduce_tallies) then - n_realizations_batch = n_realizations_batch + 1 + n_realizations = n_realizations + 1 else - n_realizations_batch = n_realizations_batch + n_procs + n_realizations = n_realizations + n_procs end if ! Accumulate on master only unless run is not reduced then do it on all diff --git a/src/tallies/tally_header.F90 b/src/tallies/tally_header.F90 index 3418df12a6..ee44685924 100644 --- a/src/tallies/tally_header.F90 +++ b/src/tallies/tally_header.F90 @@ -145,9 +145,8 @@ module tally_header type(VectorInt), public :: active_tallies type(VectorInt), public :: active_surface_tallies - ! Normalization for batch-based and generation-based global tally statistics - integer(C_INT32_T), public, bind(C) :: n_realizations_batch = 0 - integer(C_INT32_T), public, bind(C) :: n_realizations_gen = 0 + ! Normalization for statistics + integer(C_INT32_T), public, bind(C) :: n_realizations = 0 ! # of independent realizations real(8), public :: total_weight ! total starting particle weight in realization contains From b88b9ba83126510a80b0499ace1ae57e507c2696 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Thu, 2 Aug 2018 15:52:18 -0500 Subject: [PATCH 004/109] Fix #1028 for restart runs --- src/simulation.F90 | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/simulation.F90 b/src/simulation.F90 index ffcfb8bab8..c11b5bc2fb 100644 --- a/src/simulation.F90 +++ b/src/simulation.F90 @@ -386,6 +386,13 @@ contains end do end if + ! Increment n_realizations as would ordinarily be done in finalize_batch + if (reduce_tallies) then + n_realizations = n_realizations + 1 + else + n_realizations = n_realizations + n_procs + end if + ! Write message at end if (current_batch == restart_batch) then call write_message("Resuming simulation...", 6) @@ -448,6 +455,19 @@ contains call initialize_source() end if + ! In restart, set the batch to begin from in order to reproduce the correct + ! average keff (used in sampling the fission bank). Use n_realizations from + ! the statepoint rather than n_inactive in case openmc_reset was called in + ! the previous run. + if (restart_run) then + if (reduce_tallies) then + current_batch = restart_batch - n_realizations + else + current_batch = restart_batch - n_realizations*n_procs + end if + n_realizations = 0 + end if + ! Display header if (master) then if (run_mode == MODE_FIXEDSOURCE) then From 6f99f1ae18265f37924afbb84c7ded30946534c0 Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Fri, 3 Aug 2018 09:38:39 -0500 Subject: [PATCH 005/109] Tally the particle only when it is within the range. --- src/tallies/tally_filter_zernike.F90 | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/tallies/tally_filter_zernike.F90 b/src/tallies/tally_filter_zernike.F90 index d005416138..ad4f592770 100644 --- a/src/tallies/tally_filter_zernike.F90 +++ b/src/tallies/tally_filter_zernike.F90 @@ -67,15 +67,17 @@ contains x = p % coord(1) % xyz(1) - this % x y = p % coord(1) % xyz(2) - this % y r = sqrt(x*x + y*y)/this % r - theta = atan2(y, x) + if (r <= 1) then + theta = atan2(y, x) + + ! Get moments for Zernike polynomial orders 0..n + call calc_zn(this % order, r, theta, zn) - ! Get moments for Zernike polynomial orders 0..n - call calc_zn(this % order, r, theta, zn) - - do i = 1, this % n_bins - call match % bins % push_back(i) - call match % weights % push_back(zn(i)) - end do + do i = 1, this % n_bins + call match % bins % push_back(i) + call match % weights % push_back(zn(i)) + end do + endif end subroutine get_all_bins subroutine to_statepoint(this, filter_group) From cdfa3565c9f95f793206a194563a1948a48e1572 Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Fri, 3 Aug 2018 12:42:18 -0500 Subject: [PATCH 006/109] Add math function for radial Zernike --- src/math.F90 | 10 ++++++++++ src/math_functions.cpp | 29 +++++++++++++++++++++++++++++ src/math_functions.h | 23 +++++++++++++++++++++++ 3 files changed, 62 insertions(+) diff --git a/src/math.F90 b/src/math.F90 index 33f1ab4d30..87c747f579 100644 --- a/src/math.F90 +++ b/src/math.F90 @@ -11,6 +11,7 @@ module math public :: calc_pn public :: calc_rn public :: calc_zn + public :: calc_zn_rad public :: evaluate_legendre public :: rotate_angle public :: maxwell_spectrum @@ -70,6 +71,15 @@ module math real(C_DOUBLE), intent(out) :: zn(((n + 1) * (n + 2)) / 2) end subroutine calc_zn + pure subroutine calc_zn_rad(n, rho, phi, zn_rad) bind(C, name='calc_zn_rad_c') + use ISO_C_BINDING + implicit none + integer(C_INT), value, intent(in) :: n + real(C_DOUBLE), value, intent(in) :: rho + real(C_DOUBLE), value, intent(in) :: phi + real(C_DOUBLE), intent(out) :: zn_rad((n / 2) + 1) + end subroutine calc_zn + subroutine rotate_angle_c_intfc(uvw, mu, phi) bind(C, name='rotate_angle_c') use ISO_C_BINDING implicit none diff --git a/src/math_functions.cpp b/src/math_functions.cpp index 31f86ea5f6..2a79bb4b24 100644 --- a/src/math_functions.cpp +++ b/src/math_functions.cpp @@ -587,6 +587,35 @@ void calc_zn_c(int n, double rho, double phi, double zn[]) { } +void calc_zn_rad_c(int n, double rho, double phi, double zn_rad[]) { + // Calculate R_p0(rho) as Zn_p0(rho) + // Set up the array of the coefficients + int length = int(n/2) + 1; + double zn_rad[length]; + double q = 0; + + // R_00 is always 1 + zn_rad[0] = 1; + + // Fill in the rest of the array (Eq 3.8 and Eq 3.10 in Chong) + for (int p = 2; p <= n; p += 2) { + int index = int(p/2); + if (p == 2) { + // Setting up R_22 to calculate R_20 (Eq 3.10 in Chong) + R_22 = std::pow(rho, 2); + zn_rad[index] = 2 * R_22 - zn_rad[0] + } + else { + double k1 = ((p + q) * (p - q) * (p - 2)) / 2.; + double k2 = 2 * p * (p - 1) * (p - 2); + double k3 = -q * q * (p - 1) - p * (p - 1) * (p - 2); + double k4 = (-p * (p + q - 2) * (p - q - 2)) / 2.; + zn_rad[index] = + ((k2 * rho * rho + k3) * zn_rad[index-1] + k4 * zn_rad[index-2]) / k1; + } + } +} + void rotate_angle_c(double uvw[3], double mu, double* phi) { // Copy original directional cosines diff --git a/src/math_functions.h b/src/math_functions.h index 2ceea98d87..98882463df 100644 --- a/src/math_functions.h +++ b/src/math_functions.h @@ -91,6 +91,29 @@ extern "C" void calc_rn_c(int n, const double uvw[3], double rn[]); extern "C" void calc_zn_c(int n, double rho, double phi, double zn[]); +//============================================================================== +//! Calculate only the even radial components of n-th order modified Zernike +//! polynomial moment with azimuthal dependency m = 0 for a given angle +//! (rho, theta) location on the unit disk. +//! +//! Since m = 0, n could only be even orders. Z_q0 = R_q0 +//! +//! This procedure uses the modified Kintner's method for calculating Zernike +//! polynomials as outlined in Chong, C. W., Raveendran, P., & Mukundan, +//! R. (2003). A comparative analysis of algorithms for fast computation of +//! Zernike moments. Pattern Recognition, 36(3), 731-742. +//! The normalization of the polynomials is such that the integral of Z_pq^2 +//! over the unit disk is exactly pi. +//! +//! @param n The maximum order requested +//! @param rho The radial parameter to specify location on the unit disk +//! @param phi The angle parameter to specify location on the unit disk +//! @param zn_rad The requested moments of order 0 to n (inclusive) +//! evaluated at rho and phi when m = 0. +//============================================================================== + +extern "C" void calc_zn_rad_c(int n, double rho, double phi, double zn_rad[]); + //============================================================================== //! Rotate the direction cosines through a polar angle whose cosine is mu and //! through an azimuthal angle sampled uniformly. From c7f3676722abaddc04f7b5065a512e034bad8ef5 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 3 Aug 2018 12:59:23 -0500 Subject: [PATCH 007/109] Fix doc issue in summary.rst --- docs/source/io_formats/summary.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/source/io_formats/summary.rst b/docs/source/io_formats/summary.rst index 76c412b860..1f30c69bb1 100644 --- a/docs/source/io_formats/summary.rst +++ b/docs/source/io_formats/summary.rst @@ -123,7 +123,8 @@ The current version of the summary file format is 6.0. **/macroscopics/** -:Attributes: - **n_macroscopics** (*int*) -- Number of macroscopic data sets +:Attributes: + - **n_macroscopics** (*int*) -- Number of macroscopic data sets in the problem. :Datasets: - **names** (*char[][]*) -- Names of the macroscopic data sets. From c64959de63dff25e8736f9b28d6c179c57fd8733 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 3 Aug 2018 12:59:50 -0500 Subject: [PATCH 008/109] Document governance model discussed at OpenMC developer's meeting --- CONTRIBUTING.md | 4 +- docs/source/devguide/contributing.rst | 114 ++++++++++++++++++++++++++ docs/source/devguide/index.rst | 9 +- docs/source/devguide/workflow.rst | 2 +- 4 files changed, 122 insertions(+), 7 deletions(-) create mode 100644 docs/source/devguide/contributing.rst diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b633bb9295..be506f919a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -36,8 +36,8 @@ development team will be happy to discuss it. ## How to Submit Changes All changes to OpenMC happen through pull requests. For a full overview of the -process, see the developer's guide section on [Development -Workflow](http://openmc.readthedocs.io/en/latest/devguide/workflow.html). +process, see the developer's guide section on [Contributing to +OpenMC](http://openmc.readthedocs.io/en/latest/devguide/contributing.html). ## Code Style diff --git a/docs/source/devguide/contributing.rst b/docs/source/devguide/contributing.rst new file mode 100644 index 0000000000..61ddb3d227 --- /dev/null +++ b/docs/source/devguide/contributing.rst @@ -0,0 +1,114 @@ +.. _devguide_contributing: + +====================== +Contributing to OpenMC +====================== + +Thank you for considering contributing to OpenMC! We look forward to welcoming +new members to the community and will do our best to help you get up to speed. +The purpose of this section is to document how the project is managed: how +contributions (bug fixes, enhancements, new features) are made, how they are +evaluated, who is permitted to merge pull requests, and what happens in the +event of disagreements. Once you have read through this section, the +:ref:`devguide_workflow` section outlines the actual mechanics of making a +contribution (forking, submitting a pull request, etc.). + +The goal of our governance model is to: + +- Encourage new contributions. +- Encourage contributors to remain involved. +- Avoid unnecessary processes and bureaucracy whenever possible. +- Create a transparent decision making process which makes it clear how + contributors can be involved in decision making. + +Overview +-------- + +OpenMC uses a liberal contribution model for project governance. Anyone involved +in development in a non-trivial capacity is given an opportunity to influence +the direction of the project. Project decisions are made through a +consensus-seeking process rather than by voting. + +Terminology +----------- + +- A *Contributor* is any individual creating or commenting on an issue or pull + request. +- A *Committer* is a subset of contributors who are authorized to review and + merge pull requests. +- The *TC* (Technical Committee) is a group of committers who have the authority + to make decisions on behalf of the project team in order to resolve disputes. +- The *Project Lead* is a single individual who has the authority to make a final + decision when the TC is unable to reach consensus. + +Contribution Process +-------------------- + +Any change to the OpenMC repository must be made through a pull request (PR). +This applies to all changes to documentation, code, binary files, etc. Even long +term committers and TC members must use pull requests. + +No pull request may be merged without being reviewed. + +For non-trivial contributions, pull requests should not be merged for at least +36 hours to ensure that contributors in other timezones have time to review. +Consideration should also be given to weekends and other holiday periods to +ensure active committers have reasonable time to become involved in the +discussion and review process if they wish. + +The default for each contribution is that it is accepted once no committer has +an objection. During review committers may also request that a specific +contributor who is most versed in a particular area review the PR before it can +be merged. Once all issues brought by committers are addressed it can be merged +by any committer. + +In the case of an objection being raised in a pull request by another committer, +all involved committers should seek to arrive at a consensus by way of +addressing concerns being expressed through discussion, compromise on the +proposed change, or withdrawal of the proposed change. + +If objections to a PR are made and committers cannot reach a consensus on how to +proceed, the decision is escalated to the TC. TC members should regularly +discuss pending contributions in order to find a resolution. It is expected that +only a small minority of issues be brought to the TC for resolution and that +discussion and compromise among committers be the default resolution mechanism. + +Becoming a Committer +-------------------- + +All contributors who make a non-trivial contribution will be added as a +committer in a timely manner. Committers are expected to follow this policy. + +TC Process +---------- + +The TC uses a "consensus seeking" process for issues that are escalated to the +TC. The group tries to find a resolution that has no objections among TC +members. If a consensus cannot be reached, the Project Lead has the ultimate +authority to make a final decision. It is expected that the majority of +decisions made by the TC are via a consensus seeking process and that the +Project Lead intercedes only as a last resort. + +Resolution may involve returning the issue to committers with suggestions on how +to move forward towards a consensus. + +Members can be added to the TC at any time. Any committer can nominate another +committer to the TC and the TC uses its standard consensus seeking process to +evaluate whether or not to add this new member. Members who do not participate +consistently at the level of a majority of the other members are expected to +resign. + +In the event that the Project Lead resigns or otherwise steps down, the TC uses +a consensus seeking process to choose a new Project Lead. + +Leadership Team +--------------- + +The TC consists of the following individuals: + +- `Paul Romano `_ +- `Sterling Harper `_ +- `Adam Nelson `_ +- `Benoit Forget `_ + +The Project Lead is Paul Romano. \ No newline at end of file diff --git a/docs/source/devguide/index.rst b/docs/source/devguide/index.rst index e40e7f6359..e2410f080d 100644 --- a/docs/source/devguide/index.rst +++ b/docs/source/devguide/index.rst @@ -4,16 +4,17 @@ Developer's Guide ================= -Welcome to the OpenMC Developer's Guide! This guide documents and explains the -structure of the OpenMC source code and how to do various development tasks such -as debugging. +Welcome to the OpenMC Developer's Guide! This guide documents how contributions +are made to OpenMC, what style rules exist for the code, how to run tests, and +other related topics. .. toctree:: :numbered: :maxdepth: 2 - styleguide + contributing workflow + styleguide tests user-input docbuild diff --git a/docs/source/devguide/workflow.rst b/docs/source/devguide/workflow.rst index 6201f429a0..d1deca515b 100644 --- a/docs/source/devguide/workflow.rst +++ b/docs/source/devguide/workflow.rst @@ -82,7 +82,7 @@ features and bug fixes. The general steps for contributing are as follows: you are making them. If the changes are related to an oustanding issue, make sure it is cross-referenced. -5. A trusted developer will review your pull request based on the criteria +5. A committer will review your pull request based on the criteria above. Any issues with the pull request can be discussed directly on the pull request page itself. From 1013782e125669bffcebb289707ab01a7dd8369a Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Fri, 3 Aug 2018 16:40:42 -0500 Subject: [PATCH 009/109] Add new filter file in CMakeLists --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 15c89142e0..878a41b935 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -377,6 +377,7 @@ add_library(libopenmc SHARED src/tallies/tally_filter_surface.F90 src/tallies/tally_filter_universe.F90 src/tallies/tally_filter_zernike.F90 + src/tallies/tally_filter_zernike_radial.F90 src/tallies/tally_header.F90 src/tallies/trigger.F90 src/tallies/trigger_header.F90 From dfa52096c51917741a1d1324f92e9aee326362b5 Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Fri, 3 Aug 2018 16:42:14 -0500 Subject: [PATCH 010/109] Add new filter for radial zernike --- src/tallies/tally_filter_zernike_radial.F90 | 203 ++++++++++++++++++++ 1 file changed, 203 insertions(+) create mode 100644 src/tallies/tally_filter_zernike_radial.F90 diff --git a/src/tallies/tally_filter_zernike_radial.F90 b/src/tallies/tally_filter_zernike_radial.F90 new file mode 100644 index 0000000000..6eaf97f536 --- /dev/null +++ b/src/tallies/tally_filter_zernike_radial.F90 @@ -0,0 +1,203 @@ +module tally_filter_zernike_radial + + use, intrinsic :: ISO_C_BINDING + + use constants + use error + use hdf5_interface + use math, only: calc_zn_rad + use particle_header, only: Particle + use string, only: to_str + use tally_filter_header + use xml_interface + + implicit none + private + +!=============================================================================== +! ZERNIKERADIALFILTER gives even order radial Zernike polynomial moments of a +! particle's position +!=============================================================================== + + type, public, extends(TallyFilter) :: ZernikeRadialFilter + integer :: order + real(8) :: x + real(8) :: y + real(8) :: r + contains + procedure :: from_xml + procedure :: get_all_bins + procedure :: to_statepoint + procedure :: text_label + end type ZernikeRadialFilter + +contains + +!=============================================================================== +! ZernikeRadialFilter methods +!=============================================================================== + + subroutine from_xml(this, node) + class(ZernikeRadialFilter), intent(inout) :: this + type(XMLNode), intent(in) :: node + + integer :: n + + ! Get center of cylinder and radius + call get_node_value(node, "x", this % x) + call get_node_value(node, "y", this % y) + call get_node_value(node, "r", this % r) + + ! Get specified order + call get_node_value(node, "order", n) + this % order = n + this % n_bins = n/2 + 1 + end subroutine from_xml + + subroutine get_all_bins(this, p, estimator, match) + class(ZernikeRadialFilter), intent(in) :: this + type(Particle), intent(in) :: p + integer, intent(in) :: estimator + type(TallyFilterMatch), intent(inout) :: match + + integer :: i + real(8) :: x, y, r + real(C_DOUBLE) :: zn_rad(this % n_bins) + + ! Determine normalized (r,theta) positions + x = p % coord(1) % xyz(1) - this % x + y = p % coord(1) % xyz(2) - this % y + r = sqrt(x*x + y*y)/this % r + if (r <= 1) then + + ! Get moments for even order Zernike polynomial orders 0..n + call calc_zn_rad(this % order, r, zn_rad) + + do i = 1, this % n_bins + call match % bins % push_back(i) + call match % weights % push_back(zn_rad(i)) + end do + endif + end subroutine get_all_bins + + subroutine to_statepoint(this, filter_group) + class(ZernikeRadialFilter), intent(in) :: this + integer(HID_T), intent(in) :: filter_group + + call write_dataset(filter_group, "type", "zernikeradial") + call write_dataset(filter_group, "n_bins", this % n_bins) + call write_dataset(filter_group, "order", this % order) + call write_dataset(filter_group, "x", this % x) + call write_dataset(filter_group, "y", this % y) + call write_dataset(filter_group, "r", this % r) + end subroutine to_statepoint + + function text_label(this, bin) result(label) + class(ZernikeRadialFilter), intent(in) :: this + integer, intent(in) :: bin + character(MAX_LINE_LEN) :: label + + label = "Zernike expansion, Z" // trim(to_str(2*bin)) // ",0" + ! integer :: n + ! integer :: first, last + + ! do n = 0, this % order, -2 + ! last = (n + 1)*(n + 2)/2 + ! if (bin <= last) then + ! first = last - n + ! m = -n + (bin - first)*2 + ! label = "Zernike expansion, Z" // trim(to_str(n)) // ",0" + ! exit + ! end if + ! end do + end function text_label + +!=============================================================================== +! C API FUNCTIONS +!=============================================================================== + + function openmc_zernike_radial_filter_get_order(index, order) result(err) bind(C) + ! Get the order of an expansion filter + integer(C_INT32_T), value :: index + integer(C_INT), intent(out) :: order + integer(C_INT) :: err + + err = verify_filter(index) + if (err == 0) then + select type (f => filters(index) % obj) + type is (ZernikeRadialFilter) + order = f % order + class default + err = E_INVALID_TYPE + call set_errmsg("Not a Zernike Radial filter.") + end select + end if + end function openmc_zernike_radial_filter_get_order + + + function openmc_zernike_radial_filter_get_params(index, x, y, r) result(err) bind(C) + ! Get the Zernike filter parameters + integer(C_INT32_T), value :: index + real(C_DOUBLE), intent(out) :: x + real(C_DOUBLE), intent(out) :: y + real(C_DOUBLE), intent(out) :: r + integer(C_INT) :: err + + err = verify_filter(index) + if (err == 0) then + select type (f => filters(index) % obj) + type is (ZernikeRadialFilter) + x = f % x + y = f % y + r = f % r + class default + err = E_INVALID_TYPE + call set_errmsg("Not a Zernike Radial filter.") + end select + end if + end function openmc_zernike_radial_filter_get_params + + + function openmc_zernike_radial_filter_set_order(index, order) result(err) bind(C) + ! Set the order of an expansion filter + integer(C_INT32_T), value :: index + integer(C_INT), value :: order + integer(C_INT) :: err + + err = verify_filter(index) + if (err == 0) then + select type (f => filters(index) % obj) + type is (ZernikeRadialFilter) + f % order = order + f % n_bins = order/2 + 1 + class default + err = E_INVALID_TYPE + call set_errmsg("Not a Zernike Radial filter.") + end select + end if + end function openmc_zernike_radial_filter_set_order + + + function openmc_zernike_radial_filter_set_params(index, x, y, r) result(err) bind(C) + ! Set the Zernike filter parameters + integer(C_INT32_T), value :: index + real(C_DOUBLE), intent(in), optional :: x + real(C_DOUBLE), intent(in), optional :: y + real(C_DOUBLE), intent(in), optional :: r + integer(C_INT) :: err + + err = verify_filter(index) + if (err == 0) then + select type (f => filters(index) % obj) + type is (ZernikeRadialFilter) + if (present(x)) f % x = x + if (present(y)) f % y = y + if (present(r)) f % r = r + class default + err = E_INVALID_TYPE + call set_errmsg("Not a Zernike Radial filter.") + end select + end if + end function openmc_zernike_radial_filter_set_params + +end module tally_filter_zernike_radial From f8cac6004980586262732837997d8f8393e20ce9 Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Fri, 3 Aug 2018 16:44:21 -0500 Subject: [PATCH 011/109] Add C API for the new radial zernike filters --- openmc/capi/filter.py | 30 ++++++++++++++++++++++++++++-- openmc/capi/math.py | 24 ++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/openmc/capi/filter.py b/openmc/capi/filter.py index 391e63f073..621c2a4f6c 100644 --- a/openmc/capi/filter.py +++ b/openmc/capi/filter.py @@ -20,7 +20,7 @@ __all__ = ['Filter', 'AzimuthalFilter', 'CellFilter', 'EnergyFunctionFilter', 'LegendreFilter', 'MaterialFilter', 'MeshFilter', 'MeshSurfaceFilter', 'MuFilter', 'PolarFilter', 'SphericalHarmonicsFilter', 'SpatialLegendreFilter', 'SurfaceFilter', - 'UniverseFilter', 'ZernikeFilter', 'filters'] + 'UniverseFilter', 'ZernikeFilter', 'ZernikeRadialFilter', 'filters'] # Tally functions _dll.openmc_cell_filter_get_bins.argtypes = [ @@ -95,6 +95,12 @@ _dll.openmc_zernike_filter_get_order.errcheck = _error_handler _dll.openmc_zernike_filter_set_order.argtypes = [c_int32, c_int] _dll.openmc_zernike_filter_set_order.restype = c_int _dll.openmc_zernike_filter_set_order.errcheck = _error_handler +_dll.openmc_zernike_radial_filter_get_order.argtypes = [c_int32, POINTER(c_int)] +_dll.openmc_zernike_radial_filter_get_order.restype = c_int +_dll.openmc_zernike_radial_filter_get_order.errcheck = _error_handler +_dll.openmc_zernike_radial_filter_set_order.argtypes = [c_int32, c_int] +_dll.openmc_zernike_radial_filter_set_order.restype = c_int +_dll.openmc_zernike_radial_filter_set_order.errcheck = _error_handler class Filter(_FortranObjectWithID): __instances = WeakValueDictionary() @@ -360,6 +366,25 @@ class ZernikeFilter(Filter): _dll.openmc_zernike_filter_set_order(self._index, order) +class ZernikeRadialFilter(Filter): + filter_type = 'zernikeradial' + + def __init__(self, order=None, uid=None, new=True, index=None): + super().__init__(uid, new, index) + if order is not None: + self.order = order + + @property + def order(self): + temp_order = c_int() + _dll.openmc_zernike_radial_filter_get_order(self._index, temp_order) + return temp_order.value + + @order.setter + def order(self, order): + _dll.openmc_zernike_radial_filter_set_order(self._index, order) + + _FILTER_TYPE_MAP = { 'azimuthal': AzimuthalFilter, 'cell': CellFilter, @@ -380,7 +405,8 @@ _FILTER_TYPE_MAP = { 'spatiallegendre': SpatialLegendreFilter, 'surface': SurfaceFilter, 'universe': UniverseFilter, - 'zernike': ZernikeFilter + 'zernike': ZernikeFilter, + 'zernikeradial': ZernikeRadialFilter } diff --git a/openmc/capi/math.py b/openmc/capi/math.py index d1d7abdf64..4f8bb5cdbe 100644 --- a/openmc/capi/math.py +++ b/openmc/capi/math.py @@ -21,6 +21,9 @@ _dll.calc_rn_c.argtypes = [c_int, ndpointer(c_double), ndpointer(c_double)] _dll.calc_zn_c.restype = None _dll.calc_zn_c.argtypes = [c_int, c_double, c_double, ndpointer(c_double)] +_dll.calc_zn_rad_c.restype = None +_dll.calc_zn_rad_c.argtypes = [c_int, c_double, ndpointer(c_double)] + _dll.rotate_angle_c.restype = None _dll.rotate_angle_c.argtypes = [ndpointer(c_double), c_double, POINTER(c_double)] @@ -154,6 +157,27 @@ def calc_zn(n, rho, phi): _dll.calc_zn_c(n, rho, phi, zn) return zn +def calc_zn_rad(n, rho): + """ Calculate the even orders in n-th order modified Zernike polynomial moment with no azimuthal dependency (m=0) for a given radial location in the unit disk. The normalization of the polynomials is such that the integral of Z_pq*Z_pq over the unit disk is exactly pi + + Parameters + ---------- + n : int + Maximum order + rho : float + Radial location in the unit disk + + Returns + ------- + numpy.ndarray + Corresponding resulting list of coefficients + + """ + + num_bins = n // 2 + 1 + zn_rad = np.zeros(num_bins, dtype=np.float64) + _dll.calc_zn_rad_c(n, rho, zn_rad) + return zn_rad def rotate_angle(uvw0, mu, phi=None): """ Rotates direction cosines through a polar angle whose cosine is From aa28f4a1452089e0e83ff2b82543d31f5f67ccb8 Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Fri, 3 Aug 2018 16:46:00 -0500 Subject: [PATCH 012/109] Add new python class for radial zernike filter --- openmc/filter.py | 2 +- openmc/filter_expansion.py | 133 +++++++++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+), 1 deletion(-) diff --git a/openmc/filter.py b/openmc/filter.py index 3180989eb7..ae44024941 100644 --- a/openmc/filter.py +++ b/openmc/filter.py @@ -22,7 +22,7 @@ _FILTER_TYPES = ( 'universe', 'material', 'cell', 'cellborn', 'surface', 'mesh', 'energy', 'energyout', 'mu', 'polar', 'azimuthal', 'distribcell', 'delayedgroup', 'energyfunction', 'cellfrom', 'legendre', 'spatiallegendre', - 'sphericalharmonics', 'zernike' + 'sphericalharmonics', 'zernike', 'zernikeradial' ) _CURRENT_NAMES = ( diff --git a/openmc/filter_expansion.py b/openmc/filter_expansion.py index 1970c07710..842d03477f 100644 --- a/openmc/filter_expansion.py +++ b/openmc/filter_expansion.py @@ -463,3 +463,136 @@ class ZernikeFilter(ExpansionFilter): subelement.text = str(self.r) return element + +class ZernikeRadialFilter(ExpansionFilter): + r"""Score radial Zernike expansion moments in space up to specified order. + + The Zernike polynomials are defined the same as in ZernikeFilter. + + .. math:: + Z_n^m(\rho, \theta) = R_n^m(\rho) \cos (m\theta), \quad m > 0 + + Z_n^{m}(\rho, \theta) = R_n^{m}(\rho) \sin (m\theta), \quad m < 0 + + Z_n^{m}(\rho, \theta) = R_n^{m}(\rho), \quad m = 0 + + where the radial polynomials are + + .. math:: + R_n^m(\rho) = \sum\limits_{k=0}^{(n-m)/2} \frac{(-1)^k (n-k)!}{k! ( + \frac{n+m}{2} - k)! (\frac{n-m}{2} - k)!} \rho^{n-2k}. + + With this definition, the integral of :math:`(Z_n^m)^2` over the unit disk + is :math:`\frac{\epsilon_m\pi}{2n+2}` for each polynomial where :math:`\epsilon_m` is + 2 if :math:`m` equals 0 and 1 otherwise. + + If there is only radial dependency, the polynomials are integrated over the azimuthal angles. The only terms left are :math:`Z_n^{0}(\rho, \theta) = R_n^{0}(\rho)`. Note that :math:`n` could only be even orders. Therefore, for a radial Zernike polynomials up to order of :math:`n`, there are :math:`\frac{n}{2} + 1` terms in total. + + Parameters + ---------- + order : int + Maximum radial Zernike polynomial order + x : float + x-coordinate of center of circle for normalization + y : float + y-coordinate of center of circle for normalization + r : int or None + Radius of circle for normalization + + Attributes + ---------- + order : int + Maximum radial Zernike polynomial order + x : float + x-coordinate of center of circle for normalization + y : float + y-coordinate of center of circle for normalization + r : int or None + Radius of circle for normalization + id : int + Unique identifier for the filter + num_bins : int + The number of filter bins + + """ + + def __init__(self, order, x=0.0, y=0.0, r=1.0, filter_id=None): + super().__init__(order, filter_id) + self.x = x + self.y = y + self.r = r + + def __hash__(self): + string = type(self).__name__ + '\n' + string += '{: <16}=\t{}\n'.format('\tOrder', self.order) + return hash(string) + + def __repr__(self): + string = type(self).__name__ + '\n' + string += '{: <16}=\t{}\n'.format('\tOrder', self.order) + string += '{: <16}=\t{}\n'.format('\tID', self.id) + return string + + @ExpansionFilter.order.setter + def order(self, order): + ExpansionFilter.order.__set__(self, order) + self.bins = ['Z{},0'.format(n) for n in range(0, order+1, 2)] + + @property + def x(self): + return self._x + + @x.setter + def x(self, x): + cv.check_type('x', x, Real) + self._x = x + + @property + def y(self): + return self._y + + @y.setter + def y(self, y): + cv.check_type('y', y, Real) + self._y = y + + @property + def r(self): + return self._r + + @r.setter + def r(self, r): + cv.check_type('r', r, Real) + self._r = r + + @classmethod + def from_hdf5(cls, group, **kwargs): + if group['type'].value.decode() != cls.short_name.lower(): + raise ValueError("Expected HDF5 data for filter type '" + + cls.short_name.lower() + "' but got '" + + group['type'].value.decode() + " instead") + + filter_id = int(group.name.split('/')[-1].lstrip('filter ')) + order = group['order'].value + x, y, r = group['x'].value, group['y'].value, group['r'].value + + return cls(order, x, y, r, filter_id) + + def to_xml_element(self): + """Return XML Element representing the filter. + + Returns + ------- + element : xml.etree.ElementTree.Element + XML element containing radial Zernike filter data + + """ + element = super().to_xml_element() + subelement = ET.SubElement(element, 'x') + subelement.text = str(self.x) + subelement = ET.SubElement(element, 'y') + subelement.text = str(self.y) + subelement = ET.SubElement(element, 'r') + subelement.text = str(self.r) + + return element \ No newline at end of file From 76c4ba0c7823899e5c929c3caa7d15179de21d8b Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Fri, 3 Aug 2018 16:47:32 -0500 Subject: [PATCH 013/109] Math for radial components of zernike polynomials --- src/math.F90 | 5 ++--- src/math_functions.cpp | 9 ++++----- src/math_functions.h | 2 +- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/math.F90 b/src/math.F90 index 87c747f579..ab5eff14c1 100644 --- a/src/math.F90 +++ b/src/math.F90 @@ -71,14 +71,13 @@ module math real(C_DOUBLE), intent(out) :: zn(((n + 1) * (n + 2)) / 2) end subroutine calc_zn - pure subroutine calc_zn_rad(n, rho, phi, zn_rad) bind(C, name='calc_zn_rad_c') + pure subroutine calc_zn_rad(n, rho, zn_rad) bind(C, name='calc_zn_rad_c') use ISO_C_BINDING implicit none integer(C_INT), value, intent(in) :: n real(C_DOUBLE), value, intent(in) :: rho - real(C_DOUBLE), value, intent(in) :: phi real(C_DOUBLE), intent(out) :: zn_rad((n / 2) + 1) - end subroutine calc_zn + end subroutine calc_zn_rad subroutine rotate_angle_c_intfc(uvw, mu, phi) bind(C, name='rotate_angle_c') use ISO_C_BINDING diff --git a/src/math_functions.cpp b/src/math_functions.cpp index 2a79bb4b24..53bf296dfe 100644 --- a/src/math_functions.cpp +++ b/src/math_functions.cpp @@ -587,11 +587,10 @@ void calc_zn_c(int n, double rho, double phi, double zn[]) { } -void calc_zn_rad_c(int n, double rho, double phi, double zn_rad[]) { +void calc_zn_rad_c(int n, double rho, double zn_rad[]) { // Calculate R_p0(rho) as Zn_p0(rho) // Set up the array of the coefficients - int length = int(n/2) + 1; - double zn_rad[length]; + double q = 0; // R_00 is always 1 @@ -602,8 +601,8 @@ void calc_zn_rad_c(int n, double rho, double phi, double zn_rad[]) { int index = int(p/2); if (p == 2) { // Setting up R_22 to calculate R_20 (Eq 3.10 in Chong) - R_22 = std::pow(rho, 2); - zn_rad[index] = 2 * R_22 - zn_rad[0] + double R_22 = std::pow(rho, 2); + zn_rad[index] = 2 * R_22 - zn_rad[0]; } else { double k1 = ((p + q) * (p - q) * (p - 2)) / 2.; diff --git a/src/math_functions.h b/src/math_functions.h index 98882463df..0993b1a01b 100644 --- a/src/math_functions.h +++ b/src/math_functions.h @@ -112,7 +112,7 @@ extern "C" void calc_zn_c(int n, double rho, double phi, double zn[]); //! evaluated at rho and phi when m = 0. //============================================================================== -extern "C" void calc_zn_rad_c(int n, double rho, double phi, double zn_rad[]); +extern "C" void calc_zn_rad_c(int n, double rho, double zn_rad[]); //============================================================================== //! Rotate the direction cosines through a polar angle whose cosine is mu and From 0f9920719f1f1278ba340eb36839e8289c5c02bf Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Fri, 3 Aug 2018 16:48:10 -0500 Subject: [PATCH 014/109] Update the constant for radial zernike filter --- src/constants.F90 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/constants.F90 b/src/constants.F90 index ab6887610e..f377f55f33 100644 --- a/src/constants.F90 +++ b/src/constants.F90 @@ -343,7 +343,7 @@ module constants integer, parameter :: NO_BIN_FOUND = -1 ! Tally filter and map types - integer, parameter :: N_FILTER_TYPES = 20 + integer, parameter :: N_FILTER_TYPES = 21 integer, parameter :: & FILTER_UNIVERSE = 1, & FILTER_MATERIAL = 2, & @@ -364,7 +364,8 @@ module constants FILTER_LEGENDRE = 17, & FILTER_SPH_HARMONICS = 18, & FILTER_SPTL_LEGENDRE = 19, & - FILTER_ZERNIKE = 20 + FILTER_ZERNIKE = 20, & + FILTER_ZERNIKE_RADIAL = 21 ! Mesh types integer, parameter :: & From 8e9ed84e111fa01e827d8fc38fc8a96b0e4749a8 Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Fri, 3 Aug 2018 16:49:51 -0500 Subject: [PATCH 015/109] Add the radial zernike filter in all the F90 files --- src/tallies/tally_filter.F90 | 5 +++++ src/tallies/tally_header.F90 | 3 +++ 2 files changed, 8 insertions(+) diff --git a/src/tallies/tally_filter.F90 b/src/tallies/tally_filter.F90 index 4b589cedbf..8d8bfadd57 100644 --- a/src/tallies/tally_filter.F90 +++ b/src/tallies/tally_filter.F90 @@ -26,6 +26,7 @@ module tally_filter use tally_filter_surface use tally_filter_universe use tally_filter_zernike + use tally_filter_zernike_radial implicit none @@ -88,6 +89,8 @@ contains type_ = 'universe' type is (ZernikeFilter) type_ = 'zernike' + type is (ZernikeRadialFilter) + type_ = 'zernikeradial' end select ! Convert Fortran string to null-terminated C string. We assume the @@ -159,6 +162,8 @@ contains allocate(UniverseFilter :: filters(index) % obj) case ('zernike') allocate(ZernikeFilter :: filters(index) % obj) + case ('zernikeradial') + allocate(ZernikeRadialFilter :: filters(index) % obj) case default err = E_UNASSIGNED call set_errmsg("Unknown filter type: " // trim(type_)) diff --git a/src/tallies/tally_header.F90 b/src/tallies/tally_header.F90 index ee44685924..224fafc3b8 100644 --- a/src/tallies/tally_header.F90 +++ b/src/tallies/tally_header.F90 @@ -339,6 +339,9 @@ contains type is (ZernikeFilter) j = FILTER_ZERNIKE this % estimator = ESTIMATOR_COLLISION + type is (ZernikeRadialFilter) + j = FILTER_ZERNIKE_RADIAL + this % estimator = ESTIMATOR_COLLISION end select this % find_filter(j) = i end do From 05010671ebbf8a2de6a32bac6911dea16465c95b Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Sun, 5 Aug 2018 16:33:53 -0500 Subject: [PATCH 016/109] Update contributing guide with @smharper feedback --- docs/source/devguide/contributing.rst | 30 ++++++++++++++------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/docs/source/devguide/contributing.rst b/docs/source/devguide/contributing.rst index 61ddb3d227..443777d4d4 100644 --- a/docs/source/devguide/contributing.rst +++ b/docs/source/devguide/contributing.rst @@ -52,15 +52,17 @@ No pull request may be merged without being reviewed. For non-trivial contributions, pull requests should not be merged for at least 36 hours to ensure that contributors in other timezones have time to review. -Consideration should also be given to weekends and other holiday periods to -ensure active committers have reasonable time to become involved in the -discussion and review process if they wish. +Consideration should be given to weekends and other holiday periods to ensure +active committers have reasonable time to become involved in the discussion and +review process if they wish. Any committer may request that the review period be +extended if they are unable to review the change within 36 hours. -The default for each contribution is that it is accepted once no committer has -an objection. During review committers may also request that a specific -contributor who is most versed in a particular area review the PR before it can -be merged. Once all issues brought by committers are addressed it can be merged -by any committer. +During review, a committer may request that a specific contributor who is most +versed in a particular area review the PR before it can be merged. + +A pull request can be merged by any committer, but only if no objections are +raised by any other committer. In the case of an objection being raised, all +involved committers should seek consensus through discussion and compromise. In the case of an objection being raised in a pull request by another committer, all involved committers should seek to arrive at a consensus by way of @@ -82,12 +84,12 @@ committer in a timely manner. Committers are expected to follow this policy. TC Process ---------- -The TC uses a "consensus seeking" process for issues that are escalated to the -TC. The group tries to find a resolution that has no objections among TC -members. If a consensus cannot be reached, the Project Lead has the ultimate -authority to make a final decision. It is expected that the majority of -decisions made by the TC are via a consensus seeking process and that the -Project Lead intercedes only as a last resort. +Any issues brought to the TC will be addressed among the committee with a +consensus-seeking process. The group tries to find a resolution that has no +objections among TC members. If a consensus cannot be reached, the Project Lead +has the ultimate authority to make a final decision. It is expected that the +majority of decisions made by the TC are via a consensus seeking process and +that the Project Lead intercedes only as a last resort. Resolution may involve returning the issue to committers with suggestions on how to move forward towards a consensus. From e75372f0271e576cb9cea923d47559577e4b5363 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Sun, 5 Aug 2018 16:57:22 -0500 Subject: [PATCH 017/109] Update workflow section --- docs/source/_images/fork.png | Bin 8601 -> 19133 bytes docs/source/_images/pullrequest.png | Bin 17703 -> 0 bytes docs/source/devguide/workflow.rst | 16 ++++++---------- 3 files changed, 6 insertions(+), 10 deletions(-) delete mode 100644 docs/source/_images/pullrequest.png diff --git a/docs/source/_images/fork.png b/docs/source/_images/fork.png index f43f64242e63127dc95282c64f5b062a31a9ea96..9bc63ae612d14871a01704f60bce6a83040f0567 100644 GIT binary patch literal 19133 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 z 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 literal 8601 zcmY+Kb8y|y_we60HXAf-V<(N#*lyg|ww>HIYGYfCZR^H18#lJ?U;FvaJTuSktj_xU zv9r79_4A8@Bq|aC5&!_G(o$l|007nUH&2fM^*6@nZTt2&fiseo6a(J=`Rw+>xW5ua z2PsWw06@n67eGL2I{sfFyouEZ@RXTqhgHmfmf}Ol%#=ZKY(sL?uCe$91ydYx%x*Iq?CRE&O3c zldw3=52UXclYxxFQeX;-yWQR07ji>=I)q4;y(f55Cuir=v8#0N@w3l+Jk;zN3h)Rp zP~U_;VDO7dQvFT-mA0Y&lORyw{Z|zF&XNsxoD-R21V;ya6Z50*K z*zM@oj=#H_ShVX=WwNlUtz5T0w9W&4!`~d-acb5Pu$rZz!lr#S @IUR?AP3eBOB zVZdFOo4Z*fdvkw0eOPX8_~+b;mYZ{OHhGrI@g|26V2t)Z#tn^*jm4;Y{K}p=_^Se@ zB=Yrk1UKBUzRx7+i_Mj8gdJ0`^ZVcheaRc(VjWI876lIaf+n9`htF7If4?z}aMmH9Gw7a7~tI;=q4a-3eNDPuQ^T~LRmE_*? zD}NZVR3%818n2P(EsI{m4x$`F68uJDRdM{}vL2j}mCpY(R5SM^@Uks~S~C4WeHm^>b&!x z@FC%TsukVw_daV?6ojn`eLlXD0*NaR<}qiVT_2uanunlcmubA6F&-^mgbXJ^?p6~S z0lToMK6$Rfxz#~?3v;ZG2lm==Bu(%cUoS1cZM5_8;f{jN7o84ggx(qB z3pj1`RT+Mn9VwLNmDI1EB^dkC;wj%(jy3&zAt`FtDVV(JeB~6~tuSnvIL8`r(b6fV zLV=%^NuPaz*A{QCf^!!7bd%}()#LDp3>c(|gP8VF4$j}VL{ijsN~|5&xAK37i&v(D zMY14Ic2Q5ljSgDsRY18ILXfw;-5E(@HeYx(Z?zx~A22i$od(}LP|_7VQSe=xpm4bO zhqnA#hA=N>Fu_Gm94DWIbiC{gj~ySUJq7Tz9O?`FK9`M9Gttq>6CGP*Bz^v}`cUg? z{zgDV^nAN9z-XFq?9Il_eeci2bpRK8SgXC3`P2om_VR+9CPC1;)t0ZQbzLv;Hn6G6 z+6wf&sUQtbBJ@`ZYUnvrl1C7{7RDb@`hU*Pw-1Svj#{32 zg&s~P+SsJr`b%d7^tf%i0}X-l39ud{W!8CD!4gc+@(nyU()aKICmQ>AEh&JA`HzvtZGg>YV`i` z_Lgo-t$OQt#?BrW3W(1bLF5?-)e`uqHCg*Xg}tC4OgS`-&H;cMnd#v)ORP`A1TYSy zc^px3`N+Qx6?33Fu(-SNG)?Bv9JuLZERHvhRTgNNNwE_c{N~YSKy*c`wrGV>qL${> zaMb%j|IN&O(fh8~h(tlV>BM%zCnQdOrYs=B;mq-q5;!kO*D%o(sBxqpL=W#NF`3Q86CfR*J zn^ZDW>VP`QKrA5{!UzBDxL4C~B%d)cuvH9UNzJB)XRALK+nsPEo)=)*h(bYh2V$8DEL958F8wzJNxn@LlH9`-U&a^gs&`De6R0>fjJ8rge}AltY{ z%y<$2OW2odKfYN&^L0dP=nP_Dt6!7I=1*Cc`)55Bbv$ZqCNd6j0Q14nQU2a2$%-bk z?AA;MK5t#aXni|3M%7XbSYf^SIXTZ)55bcAGMf)L`p@K%x!1^!>^Tp_SG3#mHT%a+ zpzGBvFLQ@uos1g8fyx^dV?m;{C-KeGIiIYVBYrsY7GZ<6nUz16#13h@5t#4vm}9^q z#ebDTYfTxuYd5ff4-ItEox7eT!Udj~-pw`+bm9Y@MBuKJ=k7>U!GwD;U;HrL6U zX_k4oRG$Nk3EU{T&R1+XgHoLdGAXhWdWqG4Bt>b{WJ3c=8qK#==OA!CH1ps)F;mxz z0aGeq(pgKySUM8MrYBwE`n==u8U5jc(pEZ$AfJ`3mA$sfaE~=A`}U<=z2UB?jzeFH zD#p)KSr2!oaVQ88nEbGosG7LQE7y4eFW&8HS`#s~W=JeYA(*WCp=-Iqbz{Z1cq*`c z?ZiaV*L2j;R+d4U8dGKyjpM78qx5qA5t@(urMfqvo#JZpwX3jGYaolMugX%h_aatS zo@Rll)~9O$BNY?s)1fb5?a>Y5Ux`{A6|g|!)-lapuPyA}T^oGXOVeCbP#guzs%YVX zRP3}XQ@gEC!CT=?#-l%TlpMwbQ+VgJN^Kv^0Edn4$}Yy{>}H>2uQ0q{#8psEMoj56 zPDPqOFF`+chE~=64|bZ@!jrb^48ACnAMb!pXH;#>#&LSz2Y7cNdv_TkH@5tGlmyzG z4dj=cmc;>x7NT*|xFnknD@$me7b4&IGMLD?D=^cx7GN)0UWWI^GnQN3?F$184Gq({ z>`$Y7NvSK>qPsJv`+N%23wVvK#*1 z{ug4-;Nf_jYU%_5VTFYEumo8*%h0H3Q_>a3KOUYV`>CAlpN-Jt{Cv2Mc&e+N3&ex? zu%7i5w*~wd2H-3FZarDQMsO_!%<3vAr^d0kE#r51qfz*^^H@TqJ_ft-b)&YwAO^2x z)vay#;E`#Hj7y7sDD)#5dlUeMq~VGhsV&^AtZ1>=G=;mVjhBgX$$N$&N_PqytG_y1 zsphSsr5+y6{BC=0>rPUU8*|w9h$TZ8z2gLb(|~|w&Gn3xknanLJhm(dm_4xUhVM+q zI?ZYubXE!6>zdor(6mZu_Z{1nY$W-%V{%7w9e96B3Rm9A;^$g3)1Sgwd1(m%5w6Sr zWw`Ej$>D}rH}kT^gwNQ8QS2aKQb)>HRSXJ<$t+kvVpkMQ;ty+UP$02H13XloC+epo zgQPlb#-@KBXj7ATCiFl7lRM8;CmxZwHa1vXa?zV>TIn7=EZS>N}J9C{w zCthT4Q=D^c)UIxz8L4+QpPaFgxU~oXv27tku07n6a`CCj6~Nl}lPg%E!ynUEdtrHj z>}Pu>zN|@PF9VxqIBksrjkC>$t@NI9Wm$g zKmQ2lFU6XcZC1f!(8KtVP(W=XXLGvDt%l*4htmnIPVt7r@=|k z17NlN!eR|bq%C3Yh7-?1m+xVV?~_0}1*F5fCuXzjg4q0cT6Ep+@Z*5O$6-i{m&wF< zFG@`4?5!`4Sz`yZ_+w^9vG~eC+U6!FqXV8fsWi9RQWu{Bj_#`Deh+@=GfKX{$#%M@ z@dLE6c?UV^p)8WsdCSwCHL%TbbMNeJXQc?i#>c-Oe$>fXn8{m!tTd}lj2kZ+K?!L( zcx;{4@hO%C?2V(k*)(0voYsdR#RGDj#6p_U<(Vw*r|F(sqbLEX-;K2eA-Nl4Yu+?& z>C%wXcs@>_gJ}mzPCcJzDJBQ1F^9me$}B~;_g%Zosnf_NO}E8nO#3bcpK2S=6V$bC z5lBx64cKBq017rCsXj*B3$h35dT^G?{2~xS&?d7E>Gf_PfmNRJYEugEANuM$x22ID) z0UfrZ_qZ|L+hT#*RHO-mUUhnX_B);Er^1ZU5kp+pMm-)6toptHxy@&NhkZRKav?R- z(61OXcELT)^T`(I zEZOhgBU;}cAAITgmP3O?Gl~F!Z3A8DDqI7txE1Q#=OL!`K3i{c^#z|x6`x&%XfU}f z+eN;6uKW1&y<8Y~*?s~5rR3M9$DQjCz|a0M+{Jrm+1Z{xId{Jvwo%r@oJ59FdD!yM zTHSkM_Pl*>B8~U*@aa9wS4M#<^L)nql%u4J=q;Ox*#r>ql`(R?d0L&it3rRBxeS9t z$=D0OZ#?;vXyHuXz`)VldXu9u>B5IP``a@9GLZekb`5``Uqa1003g~UhWKr&3$I$C zhkd&v{$hpCZ~lh<+yt@xJhO_VQM!1cZe?M^%vXefOx;guM!Dx{+K`j z@}pY!uP2~B(sy_rx6%RUDI0^w8@a&&u`A(;V6(B2vvJp4Cy1gwu(lEq@^&f$y;}C> zOaC|;bmsiFxl?fW`;wS+tZ^FiQcwXJ*!HjH(}z|M!&)Pi(cP(8QB6_9fNu?~LVJ`e_C> z!dAR8+I}6mC0?v>Y4~iIbhiehX%Kk-ZVd@Ff()qov)ITb7y@BYt(>?S#=T-cSxR{i zS^4NSQP*f9oWNTcgG6ph1~|jd+@jK&b=?_Bv3jc_Lj=hp+Vyc=nCl2k7QNK$Es5t- zzjbW~!{bxyD}yX*g2d#sLjmtl`J>!1mm3n$jtpRHNh}=A`ZB1dLaCFcYFY%1^a3O4 ztiV5~z{GO=zzEBl@|hDr6FTHY@*S=1gTfD~SeF<5V=%i(ONA^1Ekr{L06{gXZ#WG1 z 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 diff --git a/docs/source/_images/pullrequest.png b/docs/source/_images/pullrequest.png deleted file mode 100644 index 8cfc71e9cd3bc5ed8d8f49f7309c5b54b8121705..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17703 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 Ef?eNLmjD0& diff --git a/docs/source/devguide/workflow.rst b/docs/source/devguide/workflow.rst index d1deca515b..dfd738fc63 100644 --- a/docs/source/devguide/workflow.rst +++ b/docs/source/devguide/workflow.rst @@ -22,13 +22,11 @@ ongoing development takes place prior to a release and is not guaranteed to be stable. When the development team decides that a release should occur, the *develop* branch is merged into *master*. -Trivial changes to the code may be committed directly to the *develop* branch by -a trusted developer. However, most new features should be developed on a branch +All new features, enhancements, and bug fixes should be developed on a branch that branches off of *develop*. When the feature is completed, a `pull request`_ -is initiated on GitHub that is then reviewed by a trusted developer. If the pull -request is satisfactory, it is then merged into *develop*. Note that a trusted -developer may not review their own pull request (i.e., an independent code -review is required). +is initiated on GitHub that is then reviewed by a committer. If the pull request +is satisfactory, it is then merged into *develop*. Note that a committer may not +review their own pull request (i.e., an independent code review is required). Code Review Criteria -------------------- @@ -37,9 +35,9 @@ In order to be considered suitable for inclusion in the *develop* branch, the following criteria must be satisfied for all proposed changes: - Changes have a clear purpose and are useful. -- Compiles and passes the regression suite with all configurations (This is +- Compiles and passes all tests under multiple build configurations (This is checked by Travis CI). -- If appropriate, test cases are added to regression suite. +- If appropriate, test cases are added to regression or unit test suites. - No memory leaks (checked with valgrind_). - Conforms to the OpenMC `style guide`_. - No degradation of performance or greatly increased memory usage. This is not a @@ -76,8 +74,6 @@ features and bug fixes. The general steps for contributing are as follows: 4. Issue a pull request from GitHub and select the *develop* branch of openmc-dev/openmc as the target. - .. image:: ../_images/pullrequest.png - At a minimum, you should describe what the changes you've made are and why you are making them. If the changes are related to an oustanding issue, make sure it is cross-referenced. From 1a7b3c1cc0772d1b566d26fac2df3448d641f775 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 6 Aug 2018 06:39:08 -0500 Subject: [PATCH 018/109] Make it clear that PRs must be independently reviewed --- docs/source/devguide/contributing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/devguide/contributing.rst b/docs/source/devguide/contributing.rst index 443777d4d4..22dc643db9 100644 --- a/docs/source/devguide/contributing.rst +++ b/docs/source/devguide/contributing.rst @@ -48,7 +48,7 @@ Any change to the OpenMC repository must be made through a pull request (PR). This applies to all changes to documentation, code, binary files, etc. Even long term committers and TC members must use pull requests. -No pull request may be merged without being reviewed. +No pull request may be merged without being independently reviewed. For non-trivial contributions, pull requests should not be merged for at least 36 hours to ensure that contributors in other timezones have time to review. From 4c1c1c2cf00581e20a677df3a1e825d029d83690 Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Mon, 6 Aug 2018 08:37:23 -0500 Subject: [PATCH 019/109] Add unit test for Radial Zernike filter --- tests/unit_tests/test_filters.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/unit_tests/test_filters.py b/tests/unit_tests/test_filters.py index 488badbfaf..5817c4c3d2 100644 --- a/tests/unit_tests/test_filters.py +++ b/tests/unit_tests/test_filters.py @@ -100,6 +100,23 @@ def test_zernike(): assert elem.attrib['type'] == 'zernike' assert elem.find('order').text == str(n) +def test_zernike_radial(): + n = 4 + f = openmc.ZernikeRadialFilter(n, 0., 0., 1.) + assert f.order == n + assert f.bins[0] == 'Z0,0' + assert f.bins[-1] == 'Z{},0'.format(n) + assert len(f.bins) == n//2 + 1 + + # Make sure __repr__ works + repr(f) + + # to_xml_element() + elem = f.to_xml_element() + assert elem.tag == 'filter' + assert elem.attrib['type'] == 'zernikeradial' + assert elem.find('order').text == str(n) + def test_first_moment(run_in_tmpdir, box_model): plain_tally = openmc.Tally() From f0429f53647bd48212b688e35631e83db55f8cf4 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Mon, 6 Aug 2018 19:42:56 -0400 Subject: [PATCH 020/109] Read n_realizations from all processes --- src/state_point.F90 | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/state_point.F90 b/src/state_point.F90 index ebb473d496..b8d808f2ae 100644 --- a/src/state_point.F90 +++ b/src/state_point.F90 @@ -741,6 +741,9 @@ contains end if end if + ! Read number of realizations for global tallies + call read_dataset(n_realizations, file_id, "n_realizations", indep=.true.) + ! Check to make sure source bank is present if (path_source_point == path_state_point .and. .not. source_present) then call fatal_error("Source bank must be contained in statepoint restart & @@ -754,10 +757,6 @@ contains #else if (master) then #endif - - ! Read number of realizations for global tallies - call read_dataset(n_realizations, file_id, "n_realizations", indep=.true.) - ! Read global tally data call read_dataset(global_tallies, file_id, "global_tallies") From d65b7a11bd73426ef142056ada287841f8db0c4c Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Tue, 7 Aug 2018 10:19:29 -0500 Subject: [PATCH 021/109] Some travial modfication to meet the coding standard. --- openmc/capi/math.py | 7 ++++++- openmc/filter_expansion.py | 23 +++++++++++++-------- src/math_functions.cpp | 5 ++--- src/tallies/tally_filter_zernike_radial.F90 | 12 ----------- 4 files changed, 22 insertions(+), 25 deletions(-) diff --git a/openmc/capi/math.py b/openmc/capi/math.py index 4f8bb5cdbe..390ee466ff 100644 --- a/openmc/capi/math.py +++ b/openmc/capi/math.py @@ -157,8 +157,12 @@ def calc_zn(n, rho, phi): _dll.calc_zn_c(n, rho, phi, zn) return zn + def calc_zn_rad(n, rho): - """ Calculate the even orders in n-th order modified Zernike polynomial moment with no azimuthal dependency (m=0) for a given radial location in the unit disk. The normalization of the polynomials is such that the integral of Z_pq*Z_pq over the unit disk is exactly pi + """ Calculate the even orders in n-th order modified Zernike polynomial + moment with no azimuthal dependency (m=0) for a given radial location in + the unit disk. The normalization of the polynomials is such that the + integral of Z_pq*Z_pq over the unit disk is exactly pi. Parameters ---------- @@ -178,6 +182,7 @@ def calc_zn_rad(n, rho): zn_rad = np.zeros(num_bins, dtype=np.float64) _dll.calc_zn_rad_c(n, rho, zn_rad) return zn_rad + def rotate_angle(uvw0, mu, phi=None): """ Rotates direction cosines through a polar angle whose cosine is diff --git a/openmc/filter_expansion.py b/openmc/filter_expansion.py index 842d03477f..a756f7ba4a 100644 --- a/openmc/filter_expansion.py +++ b/openmc/filter_expansion.py @@ -234,8 +234,8 @@ class SphericalHarmonicsFilter(ExpansionFilter): r"""Score spherical harmonic expansion moments up to specified order. This filter allows you to obtain real spherical harmonic moments of either - the particle's direction or the cosine of the scattering angle. Specifying a - filter with order :math:`\ell` tallies moments for all orders from 0 to + the particle's direction or the cosine of the scattering angle. Specifying + a filter with order :math:`\ell` tallies moments for all orders from 0 to :math:`\ell`. Parameters @@ -342,11 +342,11 @@ class ZernikeFilter(ExpansionFilter): \frac{n+m}{2} - k)! (\frac{n-m}{2} - k)!} \rho^{n-2k}. With this definition, the integral of :math:`(Z_n^m)^2` over the unit disk - is :math:`\frac{\epsilon_m\pi}{2n+2}` for each polynomial where :math:`\epsilon_m` is - 2 if :math:`m` equals 0 and 1 otherwise. + is :math:`\frac{\epsilon_m\pi}{2n+2}` for each polynomial where + :math:`\epsilon_m` is 2 if :math:`m` equals 0 and 1 otherwise. - Specifying a filter with order N tallies moments for all :math:`n` from 0 to - N and each value of :math:`m`. The ordering of the Zernike polynomial + Specifying a filter with order N tallies moments for all :math:`n` from 0 + to N and each value of :math:`m`. The ordering of the Zernike polynomial moments follows the ANSI Z80.28 standard, where the one-dimensional index :math:`j` corresponds to the :math:`n` and :math:`m` by @@ -464,6 +464,7 @@ class ZernikeFilter(ExpansionFilter): return element + class ZernikeRadialFilter(ExpansionFilter): r"""Score radial Zernike expansion moments in space up to specified order. @@ -483,10 +484,14 @@ class ZernikeRadialFilter(ExpansionFilter): \frac{n+m}{2} - k)! (\frac{n-m}{2} - k)!} \rho^{n-2k}. With this definition, the integral of :math:`(Z_n^m)^2` over the unit disk - is :math:`\frac{\epsilon_m\pi}{2n+2}` for each polynomial where :math:`\epsilon_m` is - 2 if :math:`m` equals 0 and 1 otherwise. + is :math:`\frac{\epsilon_m\pi}{2n+2}` for each polynomial where + :math:`\epsilon_m` is 2 if :math:`m` equals 0 and 1 otherwise. - If there is only radial dependency, the polynomials are integrated over the azimuthal angles. The only terms left are :math:`Z_n^{0}(\rho, \theta) = R_n^{0}(\rho)`. Note that :math:`n` could only be even orders. Therefore, for a radial Zernike polynomials up to order of :math:`n`, there are :math:`\frac{n}{2} + 1` terms in total. + If there is only radial dependency, the polynomials are integrated over + the azimuthal angles. The only terms left are :math:`Z_n^{0}(\rho, \theta) + = R_n^{0}(\rho)`. Note that :math:`n` could only be even orders. + Therefore, for a radial Zernike polynomials up to order of :math:`n`, + there are :math:`\frac{n}{2} + 1` terms in total. Parameters ---------- diff --git a/src/math_functions.cpp b/src/math_functions.cpp index 3d60ce4d0b..8a36f7b922 100644 --- a/src/math_functions.cpp +++ b/src/math_functions.cpp @@ -601,10 +601,9 @@ void calc_zn_rad_c(int n, double rho, double zn_rad[]) { int index = int(p/2); if (p == 2) { // Setting up R_22 to calculate R_20 (Eq 3.10 in Chong) - double R_22 = std::pow(rho, 2); + double R_22 = rho * rho; zn_rad[index] = 2 * R_22 - zn_rad[0]; - } - else { + } else { double k1 = ((p + q) * (p - q) * (p - 2)) / 2.; double k2 = 2 * p * (p - 1) * (p - 2); double k3 = -q * q * (p - 1) - p * (p - 1) * (p - 2); diff --git a/src/tallies/tally_filter_zernike_radial.F90 b/src/tallies/tally_filter_zernike_radial.F90 index 6eaf97f536..1a4ed5ed55 100644 --- a/src/tallies/tally_filter_zernike_radial.F90 +++ b/src/tallies/tally_filter_zernike_radial.F90 @@ -98,18 +98,6 @@ contains character(MAX_LINE_LEN) :: label label = "Zernike expansion, Z" // trim(to_str(2*bin)) // ",0" - ! integer :: n - ! integer :: first, last - - ! do n = 0, this % order, -2 - ! last = (n + 1)*(n + 2)/2 - ! if (bin <= last) then - ! first = last - n - ! m = -n + (bin - first)*2 - ! label = "Zernike expansion, Z" // trim(to_str(n)) // ",0" - ! exit - ! end if - ! end do end function text_label !=============================================================================== From 87209a8af217f0cf9035c35cac014428e5b2cf73 Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Tue, 7 Aug 2018 11:22:11 -0500 Subject: [PATCH 022/109] ZernikeRadial as an extension of Zernike --- src/tallies/tally_filter_zernike.F90 | 119 ++++++++++-- src/tallies/tally_filter_zernike_radial.F90 | 191 -------------------- 2 files changed, 106 insertions(+), 204 deletions(-) delete mode 100644 src/tallies/tally_filter_zernike_radial.F90 diff --git a/src/tallies/tally_filter_zernike.F90 b/src/tallies/tally_filter_zernike.F90 index ad4f592770..d574c542d5 100644 --- a/src/tallies/tally_filter_zernike.F90 +++ b/src/tallies/tally_filter_zernike.F90 @@ -5,7 +5,7 @@ module tally_filter_zernike use constants use error use hdf5_interface - use math, only: calc_zn + use math, only: calc_zn, calc_zn_rad use particle_header, only: Particle use string, only: to_str use tally_filter_header @@ -24,19 +24,32 @@ module tally_filter_zernike real(8) :: y real(8) :: r contains - procedure :: from_xml - procedure :: get_all_bins - procedure :: to_statepoint - procedure :: text_label + procedure :: from_xml => from_xml_zn + procedure :: get_all_bins => get_all_bins_zn + procedure :: to_statepoint => to_statepoint_zn + procedure :: text_label => text_label_zn end type ZernikeFilter +!=============================================================================== +! ZERNIKERADIALFILTER gives even order radial Zernike polynomial moments of a +! particle's position +!=============================================================================== + + type, public, extends(ZernikeFilter) :: ZernikeRadialFilter + contains + procedure :: from_xml => from_xml_zn_rad + procedure :: get_all_bins => get_all_bins_zn_rad + procedure :: to_statepoint => to_statepoint_zn_rad + procedure :: text_label => text_label_zn_rad + end type ZernikeRadialFilter + contains !=============================================================================== ! ZernikeFilter methods !=============================================================================== - subroutine from_xml(this, node) + subroutine from_xml_zn(this, node) class(ZernikeFilter), intent(inout) :: this type(XMLNode), intent(in) :: node @@ -51,9 +64,9 @@ contains call get_node_value(node, "order", n) this % order = n this % n_bins = ((n + 1)*(n + 2))/2 - end subroutine from_xml + end subroutine from_xml_zn - subroutine get_all_bins(this, p, estimator, match) + subroutine get_all_bins_zn(this, p, estimator, match) class(ZernikeFilter), intent(in) :: this type(Particle), intent(in) :: p integer, intent(in) :: estimator @@ -78,9 +91,9 @@ contains call match % weights % push_back(zn(i)) end do endif - end subroutine get_all_bins + end subroutine get_all_bins_zn - subroutine to_statepoint(this, filter_group) + subroutine to_statepoint_zn(this, filter_group) class(ZernikeFilter), intent(in) :: this integer(HID_T), intent(in) :: filter_group @@ -90,9 +103,9 @@ contains call write_dataset(filter_group, "x", this % x) call write_dataset(filter_group, "y", this % y) call write_dataset(filter_group, "r", this % r) - end subroutine to_statepoint + end subroutine to_statepoint_zn - function text_label(this, bin) result(label) + function text_label_zn(this, bin) result(label) class(ZernikeFilter), intent(in) :: this integer, intent(in) :: bin character(MAX_LINE_LEN) :: label @@ -110,7 +123,74 @@ contains exit end if end do - end function text_label + end function text_label_zn + +!=============================================================================== +! ZernikeRadialFilter methods +!=============================================================================== + + subroutine from_xml_zn_rad(this, node) + class(ZernikeRadialFilter), intent(inout) :: this + type(XMLNode), intent(in) :: node + + integer :: n + + ! Get center of cylinder and radius + call get_node_value(node, "x", this % x) + call get_node_value(node, "y", this % y) + call get_node_value(node, "r", this % r) + + ! Get specified order + call get_node_value(node, "order", n) + this % order = n + this % n_bins = n/2 + 1 + end subroutine from_xml_zn_rad + + subroutine get_all_bins_zn_rad(this, p, estimator, match) + class(ZernikeRadialFilter), intent(in) :: this + type(Particle), intent(in) :: p + integer, intent(in) :: estimator + type(TallyFilterMatch), intent(inout) :: match + + integer :: i + real(8) :: x, y, r + real(C_DOUBLE) :: zn_rad(this % n_bins) + + ! Determine normalized (r,theta) positions + x = p % coord(1) % xyz(1) - this % x + y = p % coord(1) % xyz(2) - this % y + r = sqrt(x*x + y*y)/this % r + if (r <= 1) then + + ! Get moments for even order Zernike polynomial orders 0..n + call calc_zn_rad(this % order, r, zn_rad) + + do i = 1, this % n_bins + call match % bins % push_back(i) + call match % weights % push_back(zn_rad(i)) + end do + endif + end subroutine get_all_bins_zn_rad + + subroutine to_statepoint_zn_rad(this, filter_group) + class(ZernikeRadialFilter), intent(in) :: this + integer(HID_T), intent(in) :: filter_group + + call write_dataset(filter_group, "type", "zernikeradial") + call write_dataset(filter_group, "n_bins", this % n_bins) + call write_dataset(filter_group, "order", this % order) + call write_dataset(filter_group, "x", this % x) + call write_dataset(filter_group, "y", this % y) + call write_dataset(filter_group, "r", this % r) + end subroutine to_statepoint_zn_rad + + function text_label_zn_rad(this, bin) result(label) + class(ZernikeRadialFilter), intent(in) :: this + integer, intent(in) :: bin + character(MAX_LINE_LEN) :: label + + label = "Zernike expansion, Z" // trim(to_str(2*bin)) // ",0" + end function text_label_zn_rad !=============================================================================== ! C API FUNCTIONS @@ -127,6 +207,8 @@ contains select type (f => filters(index) % obj) type is (ZernikeFilter) order = f % order + type is (ZernikeRadialFilter) + order = f % order class default err = E_INVALID_TYPE call set_errmsg("Not a Zernike filter.") @@ -150,6 +232,10 @@ contains x = f % x y = f % y r = f % r + type is (ZernikeRadialFilter) + x = f % x + y = f % y + r = f % r class default err = E_INVALID_TYPE call set_errmsg("Not a Zernike filter.") @@ -170,6 +256,9 @@ contains type is (ZernikeFilter) f % order = order f % n_bins = ((order + 1)*(order + 2))/2 + type is (ZernikeRadialFilter) + f % order = order + f % n_bins = order/2 + 1 class default err = E_INVALID_TYPE call set_errmsg("Not a Zernike filter.") @@ -193,6 +282,10 @@ contains if (present(x)) f % x = x if (present(y)) f % y = y if (present(r)) f % r = r + type is (ZernikeRadialFilter) + if (present(x)) f % x = x + if (present(y)) f % y = y + if (present(r)) f % r = r class default err = E_INVALID_TYPE call set_errmsg("Not a Zernike filter.") diff --git a/src/tallies/tally_filter_zernike_radial.F90 b/src/tallies/tally_filter_zernike_radial.F90 deleted file mode 100644 index 1a4ed5ed55..0000000000 --- a/src/tallies/tally_filter_zernike_radial.F90 +++ /dev/null @@ -1,191 +0,0 @@ -module tally_filter_zernike_radial - - use, intrinsic :: ISO_C_BINDING - - use constants - use error - use hdf5_interface - use math, only: calc_zn_rad - use particle_header, only: Particle - use string, only: to_str - use tally_filter_header - use xml_interface - - implicit none - private - -!=============================================================================== -! ZERNIKERADIALFILTER gives even order radial Zernike polynomial moments of a -! particle's position -!=============================================================================== - - type, public, extends(TallyFilter) :: ZernikeRadialFilter - integer :: order - real(8) :: x - real(8) :: y - real(8) :: r - contains - procedure :: from_xml - procedure :: get_all_bins - procedure :: to_statepoint - procedure :: text_label - end type ZernikeRadialFilter - -contains - -!=============================================================================== -! ZernikeRadialFilter methods -!=============================================================================== - - subroutine from_xml(this, node) - class(ZernikeRadialFilter), intent(inout) :: this - type(XMLNode), intent(in) :: node - - integer :: n - - ! Get center of cylinder and radius - call get_node_value(node, "x", this % x) - call get_node_value(node, "y", this % y) - call get_node_value(node, "r", this % r) - - ! Get specified order - call get_node_value(node, "order", n) - this % order = n - this % n_bins = n/2 + 1 - end subroutine from_xml - - subroutine get_all_bins(this, p, estimator, match) - class(ZernikeRadialFilter), intent(in) :: this - type(Particle), intent(in) :: p - integer, intent(in) :: estimator - type(TallyFilterMatch), intent(inout) :: match - - integer :: i - real(8) :: x, y, r - real(C_DOUBLE) :: zn_rad(this % n_bins) - - ! Determine normalized (r,theta) positions - x = p % coord(1) % xyz(1) - this % x - y = p % coord(1) % xyz(2) - this % y - r = sqrt(x*x + y*y)/this % r - if (r <= 1) then - - ! Get moments for even order Zernike polynomial orders 0..n - call calc_zn_rad(this % order, r, zn_rad) - - do i = 1, this % n_bins - call match % bins % push_back(i) - call match % weights % push_back(zn_rad(i)) - end do - endif - end subroutine get_all_bins - - subroutine to_statepoint(this, filter_group) - class(ZernikeRadialFilter), intent(in) :: this - integer(HID_T), intent(in) :: filter_group - - call write_dataset(filter_group, "type", "zernikeradial") - call write_dataset(filter_group, "n_bins", this % n_bins) - call write_dataset(filter_group, "order", this % order) - call write_dataset(filter_group, "x", this % x) - call write_dataset(filter_group, "y", this % y) - call write_dataset(filter_group, "r", this % r) - end subroutine to_statepoint - - function text_label(this, bin) result(label) - class(ZernikeRadialFilter), intent(in) :: this - integer, intent(in) :: bin - character(MAX_LINE_LEN) :: label - - label = "Zernike expansion, Z" // trim(to_str(2*bin)) // ",0" - end function text_label - -!=============================================================================== -! C API FUNCTIONS -!=============================================================================== - - function openmc_zernike_radial_filter_get_order(index, order) result(err) bind(C) - ! Get the order of an expansion filter - integer(C_INT32_T), value :: index - integer(C_INT), intent(out) :: order - integer(C_INT) :: err - - err = verify_filter(index) - if (err == 0) then - select type (f => filters(index) % obj) - type is (ZernikeRadialFilter) - order = f % order - class default - err = E_INVALID_TYPE - call set_errmsg("Not a Zernike Radial filter.") - end select - end if - end function openmc_zernike_radial_filter_get_order - - - function openmc_zernike_radial_filter_get_params(index, x, y, r) result(err) bind(C) - ! Get the Zernike filter parameters - integer(C_INT32_T), value :: index - real(C_DOUBLE), intent(out) :: x - real(C_DOUBLE), intent(out) :: y - real(C_DOUBLE), intent(out) :: r - integer(C_INT) :: err - - err = verify_filter(index) - if (err == 0) then - select type (f => filters(index) % obj) - type is (ZernikeRadialFilter) - x = f % x - y = f % y - r = f % r - class default - err = E_INVALID_TYPE - call set_errmsg("Not a Zernike Radial filter.") - end select - end if - end function openmc_zernike_radial_filter_get_params - - - function openmc_zernike_radial_filter_set_order(index, order) result(err) bind(C) - ! Set the order of an expansion filter - integer(C_INT32_T), value :: index - integer(C_INT), value :: order - integer(C_INT) :: err - - err = verify_filter(index) - if (err == 0) then - select type (f => filters(index) % obj) - type is (ZernikeRadialFilter) - f % order = order - f % n_bins = order/2 + 1 - class default - err = E_INVALID_TYPE - call set_errmsg("Not a Zernike Radial filter.") - end select - end if - end function openmc_zernike_radial_filter_set_order - - - function openmc_zernike_radial_filter_set_params(index, x, y, r) result(err) bind(C) - ! Set the Zernike filter parameters - integer(C_INT32_T), value :: index - real(C_DOUBLE), intent(in), optional :: x - real(C_DOUBLE), intent(in), optional :: y - real(C_DOUBLE), intent(in), optional :: r - integer(C_INT) :: err - - err = verify_filter(index) - if (err == 0) then - select type (f => filters(index) % obj) - type is (ZernikeRadialFilter) - if (present(x)) f % x = x - if (present(y)) f % y = y - if (present(r)) f % r = r - class default - err = E_INVALID_TYPE - call set_errmsg("Not a Zernike Radial filter.") - end select - end if - end function openmc_zernike_radial_filter_set_params - -end module tally_filter_zernike_radial From abdd753d5926c92ef1ea15226084a800bb56d1b7 Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Tue, 7 Aug 2018 11:23:45 -0500 Subject: [PATCH 023/109] Delete unecessary names in files --- CMakeLists.txt | 1 - src/tallies/tally_filter.F90 | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5f5706124f..73b3a3851b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -380,7 +380,6 @@ add_library(libopenmc SHARED src/tallies/tally_filter_surface.F90 src/tallies/tally_filter_universe.F90 src/tallies/tally_filter_zernike.F90 - src/tallies/tally_filter_zernike_radial.F90 src/tallies/tally_header.F90 src/tallies/trigger.F90 src/tallies/trigger_header.F90 diff --git a/src/tallies/tally_filter.F90 b/src/tallies/tally_filter.F90 index e2dcdd87d4..efeac180e2 100644 --- a/src/tallies/tally_filter.F90 +++ b/src/tallies/tally_filter.F90 @@ -27,7 +27,7 @@ module tally_filter use tally_filter_surface use tally_filter_universe use tally_filter_zernike - use tally_filter_zernike_radial + ! use tally_filter_zernike_radial implicit none From 0b45dc66c4874b3d55f2a19b756ecfec21d87f8f Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Tue, 7 Aug 2018 11:34:29 -0500 Subject: [PATCH 024/109] Change the ZernikeRadial filter on the Python API side as a subclass of Zernike filter. --- openmc/capi/filter.py | 21 ---------- openmc/filter_expansion.py | 78 +------------------------------------- 2 files changed, 1 insertion(+), 98 deletions(-) diff --git a/openmc/capi/filter.py b/openmc/capi/filter.py index 621c2a4f6c..5bd451b300 100644 --- a/openmc/capi/filter.py +++ b/openmc/capi/filter.py @@ -95,12 +95,6 @@ _dll.openmc_zernike_filter_get_order.errcheck = _error_handler _dll.openmc_zernike_filter_set_order.argtypes = [c_int32, c_int] _dll.openmc_zernike_filter_set_order.restype = c_int _dll.openmc_zernike_filter_set_order.errcheck = _error_handler -_dll.openmc_zernike_radial_filter_get_order.argtypes = [c_int32, POINTER(c_int)] -_dll.openmc_zernike_radial_filter_get_order.restype = c_int -_dll.openmc_zernike_radial_filter_get_order.errcheck = _error_handler -_dll.openmc_zernike_radial_filter_set_order.argtypes = [c_int32, c_int] -_dll.openmc_zernike_radial_filter_set_order.restype = c_int -_dll.openmc_zernike_radial_filter_set_order.errcheck = _error_handler class Filter(_FortranObjectWithID): __instances = WeakValueDictionary() @@ -369,21 +363,6 @@ class ZernikeFilter(Filter): class ZernikeRadialFilter(Filter): filter_type = 'zernikeradial' - def __init__(self, order=None, uid=None, new=True, index=None): - super().__init__(uid, new, index) - if order is not None: - self.order = order - - @property - def order(self): - temp_order = c_int() - _dll.openmc_zernike_radial_filter_get_order(self._index, temp_order) - return temp_order.value - - @order.setter - def order(self, order): - _dll.openmc_zernike_radial_filter_set_order(self._index, order) - _FILTER_TYPE_MAP = { 'azimuthal': AzimuthalFilter, diff --git a/openmc/filter_expansion.py b/openmc/filter_expansion.py index a756f7ba4a..ad761f2ff7 100644 --- a/openmc/filter_expansion.py +++ b/openmc/filter_expansion.py @@ -465,7 +465,7 @@ class ZernikeFilter(ExpansionFilter): return element -class ZernikeRadialFilter(ExpansionFilter): +class ZernikeRadialFilter(ZernikeFilter): r"""Score radial Zernike expansion moments in space up to specified order. The Zernike polynomials are defined the same as in ZernikeFilter. @@ -521,83 +521,7 @@ class ZernikeRadialFilter(ExpansionFilter): """ - def __init__(self, order, x=0.0, y=0.0, r=1.0, filter_id=None): - super().__init__(order, filter_id) - self.x = x - self.y = y - self.r = r - - def __hash__(self): - string = type(self).__name__ + '\n' - string += '{: <16}=\t{}\n'.format('\tOrder', self.order) - return hash(string) - - def __repr__(self): - string = type(self).__name__ + '\n' - string += '{: <16}=\t{}\n'.format('\tOrder', self.order) - string += '{: <16}=\t{}\n'.format('\tID', self.id) - return string - @ExpansionFilter.order.setter def order(self, order): ExpansionFilter.order.__set__(self, order) self.bins = ['Z{},0'.format(n) for n in range(0, order+1, 2)] - - @property - def x(self): - return self._x - - @x.setter - def x(self, x): - cv.check_type('x', x, Real) - self._x = x - - @property - def y(self): - return self._y - - @y.setter - def y(self, y): - cv.check_type('y', y, Real) - self._y = y - - @property - def r(self): - return self._r - - @r.setter - def r(self, r): - cv.check_type('r', r, Real) - self._r = r - - @classmethod - def from_hdf5(cls, group, **kwargs): - if group['type'].value.decode() != cls.short_name.lower(): - raise ValueError("Expected HDF5 data for filter type '" - + cls.short_name.lower() + "' but got '" - + group['type'].value.decode() + " instead") - - filter_id = int(group.name.split('/')[-1].lstrip('filter ')) - order = group['order'].value - x, y, r = group['x'].value, group['y'].value, group['r'].value - - return cls(order, x, y, r, filter_id) - - def to_xml_element(self): - """Return XML Element representing the filter. - - Returns - ------- - element : xml.etree.ElementTree.Element - XML element containing radial Zernike filter data - - """ - element = super().to_xml_element() - subelement = ET.SubElement(element, 'x') - subelement.text = str(self.x) - subelement = ET.SubElement(element, 'y') - subelement.text = str(self.y) - subelement = ET.SubElement(element, 'r') - subelement.text = str(self.r) - - return element \ No newline at end of file From a4cdef712d75ce2934b34bc120d99653c37dd32b Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Tue, 7 Aug 2018 11:39:44 -0500 Subject: [PATCH 025/109] Remove comment --- src/tallies/tally_filter.F90 | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tallies/tally_filter.F90 b/src/tallies/tally_filter.F90 index efeac180e2..81b1958169 100644 --- a/src/tallies/tally_filter.F90 +++ b/src/tallies/tally_filter.F90 @@ -27,7 +27,6 @@ module tally_filter use tally_filter_surface use tally_filter_universe use tally_filter_zernike - ! use tally_filter_zernike_radial implicit none From 309a913b06ccbe542c4fe62f0543771d5be74968 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Tue, 7 Aug 2018 16:51:39 -0400 Subject: [PATCH 026/109] Add statepoint with source_bank to C-API Also simplify logic for write_source_point --- openmc/capi/core.py | 8 ++-- src/simulation.F90 | 26 ++++++++++--- src/state_point.F90 | 89 ++++++++++++++++++++------------------------- 3 files changed, 66 insertions(+), 57 deletions(-) diff --git a/openmc/capi/core.py b/openmc/capi/core.py index a1f908c1c5..903999628a 100644 --- a/openmc/capi/core.py +++ b/openmc/capi/core.py @@ -52,7 +52,7 @@ _dll.openmc_simulation_init.restype = c_int _dll.openmc_simulation_init.errcheck = _error_handler _dll.openmc_simulation_finalize.restype = c_int _dll.openmc_simulation_finalize.errcheck = _error_handler -_dll.openmc_statepoint_write.argtypes = [POINTER(c_char_p)] +_dll.openmc_statepoint_write.argtypes = [POINTER(c_char_p), POINTER(c_int)] _dll.openmc_statepoint_write.restype = c_int _dll.openmc_statepoint_write.errcheck = _error_handler @@ -269,7 +269,7 @@ def source_bank(): return as_array(ptr, (n.value,)).view(bank_dtype) -def statepoint_write(filename=None): +def statepoint_write(filename=None, write_source=False): """Write a statepoint file. Parameters @@ -277,11 +277,13 @@ def statepoint_write(filename=None): filename : str or None Path to the statepoint to write. If None is passed, a default name that contains the current batch will be written. + write_source : bool + Whether or not to include the source bank in the statepoint. """ if filename is not None: filename = c_char_p(filename.encode()) - _dll.openmc_statepoint_write(filename) + _dll.openmc_statepoint_write(filename, c_int(write_source)) @contextmanager diff --git a/src/simulation.F90 b/src/simulation.F90 index c8c9dfcf8e..cd7e68da46 100644 --- a/src/simulation.F90 +++ b/src/simulation.F90 @@ -317,6 +317,7 @@ contains #ifdef OPENMC_MPI integer :: mpi_err ! MPI error code #endif + character(MAX_FILE_LEN) :: filename ! Reduce tallies onto master process and accumulate call time_tallies % start() @@ -349,14 +350,29 @@ contains ! Write out state point if it's been specified for this batch if (statepoint_batch % contains(current_batch)) then - err = openmc_statepoint_write() + if (sourcepoint_batch % contains(current_batch) .and. source_write & + .and. .not. source_separate) then + err = openmc_statepoint_write(write_source=1) + else + err = openmc_statepoint_write(write_source=0) + end if + end if + + ! Write out a separate source point if it's been specified for this batch + if (sourcepoint_batch % contains(current_batch) .and. source_write & + .and. source_separate) call write_source_point() + + ! Write a continously-overwritten source point if requested. + if (source_latest) then + filename = trim(path_output) // 'source' // '.h5' + call write_source_point(filename) end if ! Write out source point if it's been specified for this batch - if ((sourcepoint_batch % contains(current_batch) .or. source_latest) .and. & - source_write) then - call write_source_point() - end if + !if ((sourcepoint_batch % contains(current_batch) .or. source_latest) .and. & + ! source_write) then + ! call write_source_point() + !end if end subroutine finalize_batch diff --git a/src/state_point.F90 b/src/state_point.F90 index dbc55be7a0..4d66a37aa5 100644 --- a/src/state_point.F90 +++ b/src/state_point.F90 @@ -58,8 +58,9 @@ contains ! OPENMC_STATEPOINT_WRITE writes an HDF5 statepoint file to disk !=============================================================================== - function openmc_statepoint_write(filename) result(err) bind(C) - type(C_PTR), intent(in), optional :: filename + function openmc_statepoint_write(filename, write_source) result(err) bind(C) + type(C_PTR), intent(in), optional :: filename + integer(C_INT), intent(in), optional :: write_source integer(C_INT) :: err integer :: i, j, k @@ -74,6 +75,7 @@ contains character(C_CHAR), pointer :: string(:) character(len=:, kind=C_CHAR), allocatable :: filename_ character(MAX_WORD_LEN, kind=C_CHAR) :: temp_name + logical :: parallel err = 0 if (present(filename)) then @@ -137,13 +139,6 @@ contains ! Write out current batch number call write_dataset(file_id, "current_batch", current_batch) - ! Indicate whether source bank is stored in statepoint - if (source_separate) then - call write_attribute(file_id, "source_present", 0) - else - call write_attribute(file_id, "source_present", 1) - end if - ! Write out information for eigenvalue run if (run_mode == MODE_EIGENVALUE) then call write_dataset(file_id, "n_inactive", n_inactive) @@ -432,17 +427,40 @@ contains call file_close(file_id) end if + +#ifdef PHDF5 + parallel = .true. +#else + parallel = .false. +#endif + + ! Write the source bank if desired + if (present(write_source)) then + if (write_source /= 0) then + if (master .or. parallel) then + file_id = file_open(filename_, 'a', parallel=.true.) + end if + call write_source_bank(file_id, work_index, source_bank) + call write_attribute(file_id, "source_present", 1) + if (master .or. parallel) call file_close(file_id) + else + call write_attribute(file_id, "source_present", 0) + end if + else + call write_attribute(file_id, "source_present", 0) + end if end function openmc_statepoint_write !=============================================================================== ! WRITE_SOURCE_POINT !=============================================================================== - subroutine write_source_point() + subroutine write_source_point(filename) + character(MAX_FILE_LEN), intent(in), optional :: filename logical :: parallel integer(HID_T) :: file_id - character(MAX_FILE_LEN) :: filename + character(MAX_FILE_LEN) :: filename_ ! When using parallel HDF5, the file is written to collectively by all ! processes. With MPI-only, the file is opened and written by the master @@ -454,47 +472,20 @@ contains parallel = .false. #endif - ! Check to write out source for a specified batch - if (sourcepoint_batch%contains(current_batch)) then - if (source_separate) then - filename = trim(path_output) // 'source.' // & - & zero_padded(current_batch, count_digits(n_max_batches)) - filename = trim(filename) // '.h5' - call write_message("Creating source file " // trim(filename) & - // "...", 5) - - ! Create separate source file - if (master .or. parallel) then - file_id = file_open(filename, 'w', parallel=.true.) - call write_attribute(file_id, "filetype", 'source') - end if - else - filename = trim(path_output) // 'statepoint.' // & - zero_padded(current_batch, count_digits(n_max_batches)) - filename = trim(filename) // '.h5' - - if (master .or. parallel) then - file_id = file_open(filename, 'a', parallel=.true.) - end if - end if - - call write_source_bank(file_id, work_index, source_bank) - if (master .or. parallel) call file_close(file_id) + if (present(filename)) then + filename_ = filename + else + filename_ = trim(path_output) // 'source.' // & + & zero_padded(current_batch, count_digits(n_max_batches)) + filename_ = trim(filename_) // '.h5' end if - ! Also check to write source separately in overwritten file - if (source_latest) then - filename = trim(path_output) // 'source' // '.h5' - call write_message("Creating source file " // trim(filename) // "...", 5) - if (master .or. parallel) then - file_id = file_open(filename, 'w', parallel=.true.) - call write_attribute(file_id, "filetype", 'source') - end if - - call write_source_bank(file_id, work_index, source_bank) - - if (master .or. parallel) call file_close(file_id) + if (master .or. parallel) then + file_id = file_open(filename_, 'w', parallel=.true.) + call write_attribute(file_id, "filetype", 'source') end if + call write_source_bank(file_id, work_index, source_bank) + if (master .or. parallel) call file_close(file_id) end subroutine write_source_point From 2ff8eb4696f315f6f47a7d5b7a7e200a6647ea48 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Tue, 7 Aug 2018 17:03:38 -0400 Subject: [PATCH 027/109] Add a C-API based restart test --- src/state_point.F90 | 3 ++- tests/unit_tests/test_capi.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/state_point.F90 b/src/state_point.F90 index 4d66a37aa5..3f1d5b3978 100644 --- a/src/state_point.F90 +++ b/src/state_point.F90 @@ -70,6 +70,7 @@ contains integer(HID_T) :: cmfd_group, tallies_group, tally_group, meshes_group, & filters_group, filter_group, derivs_group, & deriv_group, runtime_group + integer(C_INT) :: ignored_err real(C_DOUBLE) :: k_combined(2) character(MAX_WORD_LEN), allocatable :: str_array(:) character(C_CHAR), pointer :: string(:) @@ -151,7 +152,7 @@ contains call write_dataset(file_id, "k_col_abs", k_col_abs) call write_dataset(file_id, "k_col_tra", k_col_tra) call write_dataset(file_id, "k_abs_tra", k_abs_tra) - err = openmc_get_keff(k_combined) + ignored_err = openmc_get_keff(k_combined) call write_dataset(file_id, "k_combined", k_combined) ! Write out CMFD info diff --git a/tests/unit_tests/test_capi.py b/tests/unit_tests/test_capi.py index af013cbb5b..288676ff7a 100644 --- a/tests/unit_tests/test_capi.py +++ b/tests/unit_tests/test_capi.py @@ -311,3 +311,31 @@ def test_mesh(capi_init): msf = openmc.capi.MeshSurfaceFilter(mesh) assert msf.mesh == mesh + + +def test_restart(pincell_model): + # Run for 7 batches then write a statepoint. + openmc.capi.init() + openmc.capi.simulation_init() + for i in range(7): + openmc.capi.next_batch() + openmc.capi.statepoint_write('restart_test.h5', True) + + # Run 3 more batches and copy the keff. + for i in range(3): + openmc.capi.next_batch() + keff0 = openmc.capi.keff() + openmc.capi.simulation_finalize() + openmc.capi.finalize() + + # Restart the simulation and run all 10 batches. + openmc.capi.init(args=('-r', 'restart_test.h5')) + openmc.capi.simulation_init() + for i in range(10): + openmc.capi.next_batch() + keff1 = openmc.capi.keff() + openmc.capi.simulation_finalize() + openmc.capi.finalize() + + # Compare the keff values. + assert keff0 == pytest.approx(keff1) From 0f4159ca9738f131170f88ce7538f68a4ca719ca Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Tue, 7 Aug 2018 17:06:53 -0400 Subject: [PATCH 028/109] Remove commented-out code --- src/simulation.F90 | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/simulation.F90 b/src/simulation.F90 index cd7e68da46..ecc31dbd06 100644 --- a/src/simulation.F90 +++ b/src/simulation.F90 @@ -368,12 +368,6 @@ contains call write_source_point(filename) end if - ! Write out source point if it's been specified for this batch - !if ((sourcepoint_batch % contains(current_batch) .or. source_latest) .and. & - ! source_write) then - ! call write_source_point() - !end if - end subroutine finalize_batch !=============================================================================== From b5dca6baff9c1433c0f71963250406e4e376c996 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Tue, 7 Aug 2018 18:45:10 -0400 Subject: [PATCH 029/109] Fix writing of "source_present" to statepoint --- src/state_point.F90 | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/state_point.F90 b/src/state_point.F90 index 3f1d5b3978..efe999f8c4 100644 --- a/src/state_point.F90 +++ b/src/state_point.F90 @@ -140,6 +140,17 @@ contains ! Write out current batch number call write_dataset(file_id, "current_batch", current_batch) + ! Indicate whether source bank is stored in statepoint + if (present(write_source)) then + if (write_source /= 0) then + call write_attribute(file_id, "source_present", 1) + else + call write_attribute(file_id, "source_present", 0) + end if + else + call write_attribute(file_id, "source_present", 0) + end if + ! Write out information for eigenvalue run if (run_mode == MODE_EIGENVALUE) then call write_dataset(file_id, "n_inactive", n_inactive) @@ -442,13 +453,8 @@ contains file_id = file_open(filename_, 'a', parallel=.true.) end if call write_source_bank(file_id, work_index, source_bank) - call write_attribute(file_id, "source_present", 1) if (master .or. parallel) call file_close(file_id) - else - call write_attribute(file_id, "source_present", 0) end if - else - call write_attribute(file_id, "source_present", 0) end if end function openmc_statepoint_write From 4b62006d23f679aa0ce7a089c4df1e7a674c619f Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Wed, 8 Aug 2018 10:54:53 -0400 Subject: [PATCH 030/109] Fix capi restart unit test --- tests/unit_tests/test_capi.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/tests/unit_tests/test_capi.py b/tests/unit_tests/test_capi.py index 288676ff7a..4b80ba7eb3 100644 --- a/tests/unit_tests/test_capi.py +++ b/tests/unit_tests/test_capi.py @@ -313,10 +313,14 @@ def test_mesh(capi_init): assert msf.mesh == mesh -def test_restart(pincell_model): - # Run for 7 batches then write a statepoint. +def test_restart(capi_init): + # Finalize and re-init to make internal state consistent with XML. + openmc.capi.hard_reset() + openmc.capi.finalize() openmc.capi.init() openmc.capi.simulation_init() + + # Run for 7 batches then write a statepoint. for i in range(7): openmc.capi.next_batch() openmc.capi.statepoint_write('restart_test.h5', True) @@ -325,17 +329,17 @@ def test_restart(pincell_model): for i in range(3): openmc.capi.next_batch() keff0 = openmc.capi.keff() - openmc.capi.simulation_finalize() - openmc.capi.finalize() - # Restart the simulation and run all 10 batches. + # Restart the simulation from the statepoint and run all 10 batches. + openmc.capi.simulation_finalize() + openmc.capi.hard_reset() + openmc.capi.finalize() openmc.capi.init(args=('-r', 'restart_test.h5')) openmc.capi.simulation_init() for i in range(10): openmc.capi.next_batch() keff1 = openmc.capi.keff() openmc.capi.simulation_finalize() - openmc.capi.finalize() # Compare the keff values. assert keff0 == pytest.approx(keff1) From 5a0fc9eebac7e37fdb34d8cd9b98019336c3732e Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 8 Aug 2018 10:06:00 -0500 Subject: [PATCH 031/109] Convert whitespace to blanks when reading arrays from XML --- src/xml_interface.F90 | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/xml_interface.F90 b/src/xml_interface.F90 index a9dc5224bc..0e08f75d1e 100644 --- a/src/xml_interface.F90 +++ b/src/xml_interface.F90 @@ -261,6 +261,7 @@ contains ! Get value of text node/attribute str = node_value_string(node, name) + call whitespace_to_blanks(str) ! Read numbers into array read(UNIT=str, FMT=*, IOSTAT=stat) array @@ -283,6 +284,7 @@ contains ! Get value of text node/attribute str = node_value_string(node, name) + call whitespace_to_blanks(str) ! Read numbers into array read(UNIT=str, FMT=*, IOSTAT=stat) array @@ -333,4 +335,21 @@ contains end if end subroutine get_node_array_string +!=============================================================================== +! WHITESPACE_TO_BLANKS converts all whitespace to blanks +!=============================================================================== + + subroutine whitespace_to_blanks(str) + character(len=*, kind=C_CHAR), intent(inout) :: str + + integer :: i + + do i = 1, len(str) + select case (str(i:i)) + case (C_NEW_LINE, C_HORIZONTAL_TAB, C_CARRIAGE_RETURN) + str(i:i) = ' ' + end select + end do + end subroutine + end module xml_interface From d5a85164e23d9ca396afbaf6e9d636e860342885 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Wed, 8 Aug 2018 12:19:59 -0400 Subject: [PATCH 032/109] Include source bank in statepoint by default --- openmc/capi/core.py | 10 +++++----- src/simulation.F90 | 4 ++-- src/state_point.F90 | 34 +++++++++++++++++++--------------- 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/openmc/capi/core.py b/openmc/capi/core.py index 903999628a..b5ada7956b 100644 --- a/openmc/capi/core.py +++ b/openmc/capi/core.py @@ -1,6 +1,6 @@ from contextlib import contextmanager -from ctypes import (CDLL, c_int, c_int32, c_int64, c_double, c_char_p, c_char, - POINTER, Structure, c_void_p, create_string_buffer) +from ctypes import (CDLL, c_bool, c_int, c_int32, c_int64, c_double, c_char_p, + c_char, POINTER, Structure, c_void_p, create_string_buffer) from warnings import warn import numpy as np @@ -52,7 +52,7 @@ _dll.openmc_simulation_init.restype = c_int _dll.openmc_simulation_init.errcheck = _error_handler _dll.openmc_simulation_finalize.restype = c_int _dll.openmc_simulation_finalize.errcheck = _error_handler -_dll.openmc_statepoint_write.argtypes = [POINTER(c_char_p), POINTER(c_int)] +_dll.openmc_statepoint_write.argtypes = [POINTER(c_char_p), POINTER(c_bool)] _dll.openmc_statepoint_write.restype = c_int _dll.openmc_statepoint_write.errcheck = _error_handler @@ -269,7 +269,7 @@ def source_bank(): return as_array(ptr, (n.value,)).view(bank_dtype) -def statepoint_write(filename=None, write_source=False): +def statepoint_write(filename=None, write_source=True): """Write a statepoint file. Parameters @@ -283,7 +283,7 @@ def statepoint_write(filename=None, write_source=False): """ if filename is not None: filename = c_char_p(filename.encode()) - _dll.openmc_statepoint_write(filename, c_int(write_source)) + _dll.openmc_statepoint_write(filename, c_bool(write_source)) @contextmanager diff --git a/src/simulation.F90 b/src/simulation.F90 index ecc31dbd06..4ddf54169a 100644 --- a/src/simulation.F90 +++ b/src/simulation.F90 @@ -352,9 +352,9 @@ contains if (statepoint_batch % contains(current_batch)) then if (sourcepoint_batch % contains(current_batch) .and. source_write & .and. .not. source_separate) then - err = openmc_statepoint_write(write_source=1) + err = openmc_statepoint_write(write_source=.true._C_BOOL) else - err = openmc_statepoint_write(write_source=0) + err = openmc_statepoint_write(write_source=.false._C_BOOL) end if end if diff --git a/src/state_point.F90 b/src/state_point.F90 index efe999f8c4..b679e43fd2 100644 --- a/src/state_point.F90 +++ b/src/state_point.F90 @@ -59,10 +59,11 @@ contains !=============================================================================== function openmc_statepoint_write(filename, write_source) result(err) bind(C) - type(C_PTR), intent(in), optional :: filename - integer(C_INT), intent(in), optional :: write_source + type(C_PTR), intent(in), optional :: filename + logical(C_BOOL), intent(in), optional :: write_source integer(C_INT) :: err + logical :: write_source_ integer :: i, j, k integer :: i_xs integer, allocatable :: id_array(:) @@ -79,6 +80,8 @@ contains logical :: parallel err = 0 + + ! Set the filename if (present(filename)) then call c_f_pointer(filename, string, [MAX_FILE_LEN]) filename_ = to_f_string(string) @@ -89,6 +92,13 @@ contains filename_ = trim(filename_) // '.h5' end if + ! Determine whether or not to write the source bank + if (present(write_source)) then + write_source_ = write_source + else + write_source_ = .true. + end if + ! Write message call write_message("Creating state point " // trim(filename_) // "...", 5) @@ -141,12 +151,8 @@ contains call write_dataset(file_id, "current_batch", current_batch) ! Indicate whether source bank is stored in statepoint - if (present(write_source)) then - if (write_source /= 0) then - call write_attribute(file_id, "source_present", 1) - else - call write_attribute(file_id, "source_present", 0) - end if + if (write_source_) then + call write_attribute(file_id, "source_present", 1) else call write_attribute(file_id, "source_present", 0) end if @@ -447,14 +453,12 @@ contains #endif ! Write the source bank if desired - if (present(write_source)) then - if (write_source /= 0) then - if (master .or. parallel) then - file_id = file_open(filename_, 'a', parallel=.true.) - end if - call write_source_bank(file_id, work_index, source_bank) - if (master .or. parallel) call file_close(file_id) + if (write_source_) then + if (master .or. parallel) then + file_id = file_open(filename_, 'a', parallel=.true.) end if + call write_source_bank(file_id, work_index, source_bank) + if (master .or. parallel) call file_close(file_id) end if end function openmc_statepoint_write From 1074da87f8a6277276c0cd5abc34afed5b566cf5 Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Wed, 8 Aug 2018 13:27:41 -0500 Subject: [PATCH 033/109] Made some change accordingly to the suggestions. --- openmc/filter.py | 2 +- src/constants.F90 | 5 +++-- src/math_functions.h | 13 ++++--------- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/openmc/filter.py b/openmc/filter.py index 36053ec46c..e63d72412f 100644 --- a/openmc/filter.py +++ b/openmc/filter.py @@ -22,7 +22,7 @@ _FILTER_TYPES = ( 'universe', 'material', 'cell', 'cellborn', 'surface', 'mesh', 'energy', 'energyout', 'mu', 'polar', 'azimuthal', 'distribcell', 'delayedgroup', 'energyfunction', 'cellfrom', 'legendre', 'spatiallegendre', - 'sphericalharmonics', 'zernike', 'particle', 'zernikeradial' + 'sphericalharmonics', 'zernike', 'zernikeradial', 'particle' ) _CURRENT_NAMES = ( diff --git a/src/constants.F90 b/src/constants.F90 index 1bdcec74fb..4de52322e0 100644 --- a/src/constants.F90 +++ b/src/constants.F90 @@ -379,8 +379,9 @@ module constants FILTER_SPH_HARMONICS = 18, & FILTER_SPTL_LEGENDRE = 19, & FILTER_ZERNIKE = 20, & - FILTER_PARTICLE = 21, & - FILTER_ZERNIKE_RADIAL = 22 + FILTER_ZERNIKE_RADIAL = 21, & + FILTER_PARTICLE = 22 + ! Mesh types integer, parameter :: & diff --git a/src/math_functions.h b/src/math_functions.h index e0ecad60ec..7ef39c4461 100644 --- a/src/math_functions.h +++ b/src/math_functions.h @@ -92,18 +92,13 @@ extern "C" void calc_rn_c(int n, const double uvw[3], double rn[]); extern "C" void calc_zn_c(int n, double rho, double phi, double zn[]); //============================================================================== -//! Calculate only the even radial components of n-th order modified Zernike -//! polynomial moment with azimuthal dependency m = 0 for a given angle -//! (rho, theta) location on the unit disk. +//! Calculate only the even order components of n-th order modified Zernike +//! polynomial moment with azimuthal dependency m = 0 for a given radial (rho) +//! location on the unit disk. //! //! Since m = 0, n could only be even orders. Z_q0 = R_q0 //! -//! This procedure uses the modified Kintner's method for calculating Zernike -//! polynomials as outlined in Chong, C. W., Raveendran, P., & Mukundan, -//! R. (2003). A comparative analysis of algorithms for fast computation of -//! Zernike moments. Pattern Recognition, 36(3), 731-742. -//! The normalization of the polynomials is such that the integral of Z_pq^2 -//! over the unit disk is exactly pi. +//! See calc_zn_c for methodology. //! //! @param n The maximum order requested //! @param rho The radial parameter to specify location on the unit disk From a7ce79c62f0cb9cd9f327126435b68c570547fb2 Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Wed, 8 Aug 2018 13:32:08 -0500 Subject: [PATCH 034/109] ONE instead of 1 --- src/tallies/tally_filter_zernike.F90 | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/tallies/tally_filter_zernike.F90 b/src/tallies/tally_filter_zernike.F90 index d574c542d5..1ece62dbb2 100644 --- a/src/tallies/tally_filter_zernike.F90 +++ b/src/tallies/tally_filter_zernike.F90 @@ -80,7 +80,7 @@ contains x = p % coord(1) % xyz(1) - this % x y = p % coord(1) % xyz(2) - this % y r = sqrt(x*x + y*y)/this % r - if (r <= 1) then + if (r <= ONE) then theta = atan2(y, x) ! Get moments for Zernike polynomial orders 0..n @@ -160,7 +160,7 @@ contains x = p % coord(1) % xyz(1) - this % x y = p % coord(1) % xyz(2) - this % y r = sqrt(x*x + y*y)/this % r - if (r <= 1) then + if (r <= ONE) then ! Get moments for even order Zernike polynomial orders 0..n call calc_zn_rad(this % order, r, zn_rad) @@ -228,11 +228,7 @@ contains err = verify_filter(index) if (err == 0) then select type (f => filters(index) % obj) - type is (ZernikeFilter) - x = f % x - y = f % y - r = f % r - type is (ZernikeRadialFilter) + class is (ZernikeFilter) x = f % x y = f % y r = f % r @@ -278,11 +274,7 @@ contains err = verify_filter(index) if (err == 0) then select type (f => filters(index) % obj) - type is (ZernikeFilter) - if (present(x)) f % x = x - if (present(y)) f % y = y - if (present(r)) f % r = r - type is (ZernikeRadialFilter) + class is (ZernikeFilter) if (present(x)) f % x = x if (present(y)) f % y = y if (present(r)) f % r = r From d9a7db16777eb6239bcefd1fccf01161eb3fda05 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 25 Jun 2018 21:00:59 -0500 Subject: [PATCH 035/109] Introduce Position/Angle types --- CMakeLists.txt | 1 + src/cell.cpp | 34 ++-- src/cell.h | 11 +- src/geometry.cpp | 59 +++++++ src/geometry.h | 62 +++++++ src/surface.cpp | 449 +++++++++++++++++++++++------------------------ src/surface.h | 130 +++++++------- 7 files changed, 421 insertions(+), 325 deletions(-) create mode 100644 src/geometry.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ea9bd5969c..0be9ccb325 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -386,6 +386,7 @@ add_library(libopenmc SHARED src/cell.cpp src/initialize.cpp src/finalize.cpp + src/geometry.cpp src/geometry_aux.cpp src/hdf5_interface.cpp src/lattice.cpp diff --git a/src/cell.cpp b/src/cell.cpp index 263191b316..972540fbd2 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -279,33 +279,31 @@ Cell::Cell(pugi::xml_node cell_node) //============================================================================== bool -Cell::contains(const double xyz[3], const double uvw[3], - int32_t on_surface) const +Cell::contains(Position r, Angle a, int32_t on_surface) const { if (simple) { - return contains_simple(xyz, uvw, on_surface); + return contains_simple(r, a, on_surface); } else { - return contains_complex(xyz, uvw, on_surface); + return contains_complex(r, a, on_surface); } } //============================================================================== std::pair -Cell::distance(const double xyz[3], const double uvw[3], - int32_t on_surface) const +Cell::distance(Position r, Angle a, int32_t on_surface) const { double min_dist {INFTY}; int32_t i_surf {std::numeric_limits::max()}; for (int32_t token : rpn) { // Ignore this token if it corresponds to an operator rather than a region. - if (token >= OP_UNION) {continue;} + if (token >= OP_UNION) continue; // Calculate the distance to this surface. // Note the off-by-one indexing bool coincident {token == on_surface}; - double d {surfaces_c[abs(token)-1]->distance(xyz, uvw, coincident)}; + double d {surfaces_c[abs(token)-1]->distance(r, a, coincident)}; // Check if this distance is the new minimum. if (d < min_dist) { @@ -356,8 +354,7 @@ Cell::to_hdf5(hid_t cell_group) const //============================================================================== bool -Cell::contains_simple(const double xyz[3], const double uvw[3], - int32_t on_surface) const +Cell::contains_simple(Position r, Angle a, int32_t on_surface) const { for (int32_t token : rpn) { if (token < OP_UNION) { @@ -370,7 +367,7 @@ Cell::contains_simple(const double xyz[3], const double uvw[3], return false; } else { // Note the off-by-one indexing - bool sense = surfaces_c[abs(token)-1]->sense(xyz, uvw); + bool sense = surfaces_c[abs(token)-1]->sense(r, a); if (sense != (token > 0)) {return false;} } } @@ -381,8 +378,7 @@ Cell::contains_simple(const double xyz[3], const double uvw[3], //============================================================================== bool -Cell::contains_complex(const double xyz[3], const double uvw[3], - int32_t on_surface) const +Cell::contains_complex(Position r, Angle a, int32_t on_surface) const { // Make a stack of booleans. We don't know how big it needs to be, but we do // know that rpn.size() is an upper-bound. @@ -413,7 +409,7 @@ Cell::contains_complex(const double xyz[3], const double uvw[3], stack[i_stack] = false; } else { // Note the off-by-one indexing - bool sense = surfaces_c[abs(token)-1]->sense(xyz, uvw);; + bool sense = surfaces_c[abs(token)-1]->sense(r, a);; stack[i_stack] = (sense == (token > 0)); } } @@ -494,12 +490,18 @@ extern "C" { bool cell_simple(Cell *c) {return c->simple;} bool cell_contains(Cell *c, double xyz[3], double uvw[3], int32_t on_surface) - {return c->contains(xyz, uvw, on_surface);} + { + Position r {xyz}; + Angle a {uvw}; + return c->contains(r, a, on_surface); + } void cell_distance(Cell *c, double xyz[3], double uvw[3], int32_t on_surface, double *min_dist, int32_t *i_surf) { - std::pair out = c->distance(xyz, uvw, on_surface); + Position r {xyz}; + Angle a {uvw}; + std::pair out = c->distance(r, a, on_surface); *min_dist = out.first; *i_surf = out.second; } diff --git a/src/cell.h b/src/cell.h index 24413b4fd4..08a6abf3f6 100644 --- a/src/cell.h +++ b/src/cell.h @@ -8,6 +8,7 @@ #include "hdf5.h" #include "pugixml.hpp" +#include "geometry.h" namespace openmc { @@ -97,21 +98,19 @@ public: //! known to be on. This index takes precedence over surface sense //! calculations. bool - contains(const double xyz[3], const double uvw[3], int32_t on_surface) const; + contains(Position r, Angle a, int32_t on_surface) const; //! Find the oncoming boundary of this cell. std::pair - distance(const double xyz[3], const double uvw[3], int32_t on_surface) const; + distance(Position r, Angle a, int32_t on_surface) const; //! \brief Write cell information to an HDF5 group. //! @param group_id An HDF5 group id. void to_hdf5(hid_t group_id) const; protected: - bool contains_simple(const double xyz[3], const double uvw[3], - int32_t on_surface) const; - bool contains_complex(const double xyz[3], const double uvw[3], - int32_t on_surface) const; + bool contains_simple(Position r, Angle a, int32_t on_surface) const; + bool contains_complex(Position r, Angle a, int32_t on_surface) const; }; } // namespace openmc diff --git a/src/geometry.cpp b/src/geometry.cpp new file mode 100644 index 0000000000..53bf32b5c1 --- /dev/null +++ b/src/geometry.cpp @@ -0,0 +1,59 @@ +#include "geometry.h" + +namespace openmc { + +Position& +Position::operator+=(Position other) +{ + x += other.x; + y += other.y; + z += other.z; + return *this; +} + +Position& +Position::operator+=(double v) +{ + x += v; + y += v; + z += v; + return *this; +} + +Position& +Position::operator-=(Position other) +{ + x -= other.x; + y -= other.y; + z -= other.z; + return *this; +} + +Position& +Position::operator-=(double v) +{ + x -= v; + y -= v; + z -= v; + return *this; +} + +Position& +Position::operator*=(Position other) +{ + x *= other.x; + y *= other.y; + z *= other.z; + return *this; +} + +Position& +Position::operator*=(double v) +{ + x *= v; + y *= v; + z *= v; + return *this; +} + +} // namespace openmc diff --git a/src/geometry.h b/src/geometry.h index 8837c961a7..792d653aee 100644 --- a/src/geometry.h +++ b/src/geometry.h @@ -1,6 +1,68 @@ #ifndef GEOMETRY_H #define GEOMETRY_H +namespace openmc { + extern "C" int openmc_root_universe; +struct Position { + double x = 0.; + double y = 0.; + double z = 0.; + + Position() = default; + Position(double x_, double y_, double z_) : x{x_}, y{y_}, z{z_} { }; + Position(double xyz[]) : x{xyz[0]}, y{xyz[1]}, z{xyz[2]} { }; + + Position& operator+=(Position); + Position& operator+=(double); + Position& operator-=(Position); + Position& operator-=(double); + Position& operator*=(Position); + Position& operator*=(double); + const double& operator[](int i) const { + switch (i) { + case 0: return x; + case 1: return y; + case 2: return z; + } + } + double& operator[](int i) { + switch (i) { + case 0: return x; + case 1: return y; + case 2: return z; + } + } + + inline double dot(Position other) { + return x*other.x + y*other.y + z*other.z; + } +}; + +inline Position operator+(Position a, Position b) { return a += b; } +inline Position operator+(Position a, double b) { return a += b; } +inline Position operator+(double a, Position b) { return b += a; } + +inline Position operator-(Position a, Position b) { return a -= b; } +inline Position operator-(Position a, double b) { return a -= b; } +inline Position operator-(double a, Position b) { return b -= a; } + +inline Position operator*(Position a, Position b) { return a *= b; } +inline Position operator*(Position a, double b) { return a *= b; } +inline Position operator*(double a, Position b) { return b *= a; } + + +struct Angle : Position { + double& u() { return x; } + double& v() { return y; } + double& w() { return z; } + Angle() = default; + Angle(double u, double v, double w) : Position{u, v, w} { }; + Angle(double uvw[]) : Position{uvw} { }; + Angle(Position r) : Position{r} { }; +}; + +} // namespace openmc + #endif // GEOMETRY_H diff --git a/src/surface.cpp b/src/surface.cpp index 6400da2f77..aec0972b8f 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "error.h" #include "hdf5_interface.h" @@ -177,38 +178,33 @@ Surface::Surface(pugi::xml_node surf_node) } bool -Surface::sense(const double xyz[3], const double uvw[3]) const +Surface::sense(Position r, Angle a) const { // Evaluate the surface equation at the particle's coordinates to determine // which side the particle is on. - const double f = evaluate(xyz); + const double f = evaluate(r); // Check which side of surface the point is on. if (std::abs(f) < FP_COINCIDENT) { // Particle may be coincident with this surface. To determine the sense, we // look at the direction of the particle relative to the surface normal (by // default in the positive direction) via their dot product. - double norm[3]; - normal(xyz, norm); - return uvw[0] * norm[0] + uvw[1] * norm[1] + uvw[2] * norm[2] > 0.0; + return a.dot(normal(r)) > 0.0; } return f > 0.0; } -void -Surface::reflect(const double xyz[3], double uvw[3]) const +Angle +Surface::reflect(Position r, Angle a) const { // Determine projection of direction onto normal and squared magnitude of // normal. - double norm[3]; - normal(xyz, norm); - const double projection = norm[0]*uvw[0] + norm[1]*uvw[1] + norm[2]*uvw[2]; - const double magnitude = norm[0]*norm[0] + norm[1]*norm[1] + norm[2]*norm[2]; + Angle n = normal(r); + const double projection = n.dot(a); + const double magnitude = n.dot(n); // Reflect direction according to normal. - uvw[0] -= 2.0 * projection / magnitude * norm[0]; - uvw[1] -= 2.0 * projection / magnitude * norm[1]; - uvw[2] -= 2.0 * projection / magnitude * norm[2]; + return a -= (2.0 * projection / magnitude) * n; } void @@ -261,33 +257,15 @@ PeriodicSurface::PeriodicSurface(pugi::xml_node surf_node) // The template parameter indicates the axis normal to the plane. template double -axis_aligned_plane_evaluate(const double xyz[3], double offset) +axis_aligned_plane_distance(Position r, Angle a, bool coincident, double offset) { - return xyz[i] - offset; -} - -// The template parameter indicates the axis normal to the plane. -template double -axis_aligned_plane_distance(const double xyz[3], const double uvw[3], - bool coincident, double offset) -{ - const double f = offset - xyz[i]; - if (coincident or std::abs(f) < FP_COINCIDENT or uvw[i] == 0.0) return INFTY; - const double d = f / uvw[i]; + const double f = offset - r[i]; + if (coincident or std::abs(f) < FP_COINCIDENT or a[i] == 0.0) return INFTY; + const double d = f / a[i]; if (d < 0.0) return INFTY; return d; } -// The first template parameter indicates the axis normal to the plane. The -// other two parameters indicate the other two axes. -template void -axis_aligned_plane_normal(const double xyz[3], double uvw[3]) -{ - uvw[i1] = 1.0; - uvw[i2] = 0.0; - uvw[i3] = 0.0; -} - //============================================================================== // SurfaceXPlane implementation //============================================================================== @@ -298,20 +276,19 @@ SurfaceXPlane::SurfaceXPlane(pugi::xml_node surf_node) read_coeffs(surf_node, id, x0); } -inline double SurfaceXPlane::evaluate(const double xyz[3]) const +double SurfaceXPlane::evaluate(Position r) const { - return axis_aligned_plane_evaluate<0>(xyz, x0); + return r.x - x0; } -inline double SurfaceXPlane::distance(const double xyz[3], const double uvw[3], - bool coincident) const +double SurfaceXPlane::distance(Position r, Angle a, bool coincident) const { - return axis_aligned_plane_distance<0>(xyz, uvw, coincident, x0); + return axis_aligned_plane_distance<0>(r, a, coincident, x0); } -inline void SurfaceXPlane::normal(const double xyz[3], double uvw[3]) const +Angle SurfaceXPlane::normal(Position r) const { - axis_aligned_plane_normal<0, 1, 2>(xyz, uvw); + return {1., 0., 0.}; } void SurfaceXPlane::to_hdf5_inner(hid_t group_id) const @@ -321,26 +298,24 @@ void SurfaceXPlane::to_hdf5_inner(hid_t group_id) const write_dataset(group_id, "coefficients", coeffs); } -bool SurfaceXPlane::periodic_translate(PeriodicSurface *other, double xyz[3], - double uvw[3]) const +bool SurfaceXPlane::periodic_translate(const PeriodicSurface *other, Position& r, + Angle& a) const { - double other_norm[3]; - other->normal(xyz, other_norm); - if (other_norm[0] == 1 and other_norm[1] == 0 and other_norm[2] == 0) { - xyz[0] = x0; + Angle other_n = other->normal(r); + if (other_n.u() == 1 and other_n.v() == 0 and other_n.w() == 0) { + r.x = x0; return false; } else { // Assume the partner is an YPlane (the only supported partner). Use the - // evaluate function to find y0, then adjust xyz and uvw for rotational + // evaluate function to find y0, then adjust position/angle for rotational // symmetry. - double xyz_test[3] {0, 0, 0}; - double y0 = -other->evaluate(xyz_test); - xyz[1] = xyz[0] - x0 + y0; - xyz[0] = x0; + double y0 = -other->evaluate({0., 0., 0.}); + r.y = r.x - x0 + y0; + r.x = x0; - double u = uvw[0]; - uvw[0] = -uvw[1]; - uvw[1] = u; + double u = a.u(); + a.u() = -a.v(); + a.v() = u; return true; } @@ -349,8 +324,7 @@ bool SurfaceXPlane::periodic_translate(PeriodicSurface *other, double xyz[3], BoundingBox SurfaceXPlane::bounding_box() const { - BoundingBox out {x0, x0, -INFTY, INFTY, -INFTY, INFTY}; - return out; + return {x0, x0, -INFTY, INFTY, -INFTY, INFTY}; } //============================================================================== @@ -363,20 +337,19 @@ SurfaceYPlane::SurfaceYPlane(pugi::xml_node surf_node) read_coeffs(surf_node, id, y0); } -inline double SurfaceYPlane::evaluate(const double xyz[3]) const +double SurfaceYPlane::evaluate(Position r) const { - return axis_aligned_plane_evaluate<1>(xyz, y0); + return r.y - y0; } -inline double SurfaceYPlane::distance(const double xyz[3], const double uvw[3], - bool coincident) const +double SurfaceYPlane::distance(Position r, Angle a, bool coincident) const { - return axis_aligned_plane_distance<1>(xyz, uvw, coincident, y0); + return axis_aligned_plane_distance<1>(r, a, coincident, y0); } -inline void SurfaceYPlane::normal(const double xyz[3], double uvw[3]) const +Angle SurfaceYPlane::normal(Position r) const { - axis_aligned_plane_normal<1, 0, 2>(xyz, uvw); + return {0., 1., 0.}; } void SurfaceYPlane::to_hdf5_inner(hid_t group_id) const @@ -386,27 +359,25 @@ void SurfaceYPlane::to_hdf5_inner(hid_t group_id) const write_dataset(group_id, "coefficients", coeffs); } -bool SurfaceYPlane::periodic_translate(PeriodicSurface *other, double xyz[3], - double uvw[3]) const +bool SurfaceYPlane::periodic_translate(const PeriodicSurface *other, Position& r, + Angle& a) const { - double other_norm[3]; - other->normal(xyz, other_norm); - if (other_norm[0] == 0 and other_norm[1] == 1 and other_norm[2] == 0) { + Angle other_n = other->normal(r); + if (other_n.u() == 0 and other_n.v() == 1 and other_n.w() == 0) { // The periodic partner is also aligned along y. Just change the y coord. - xyz[1] = y0; + r.y = y0; return false; } else { // Assume the partner is an XPlane (the only supported partner). Use the - // evaluate function to find x0, then adjust xyz and uvw for rotational + // evaluate function to find x0, then adjust position/angle for rotational // symmetry. - double xyz_test[3] {0, 0, 0}; - double x0 = -other->evaluate(xyz_test); - xyz[0] = xyz[1] - y0 + x0; - xyz[1] = y0; + double x0 = -other->evaluate({0., 0., 0.}); + r.x = r.y - y0 + x0; + r.y = y0; - double u = uvw[0]; - uvw[0] = uvw[1]; - uvw[1] = -u; + double u = a.u(); + a.u() = a.v(); + a.v() = -u; return true; } @@ -415,8 +386,7 @@ bool SurfaceYPlane::periodic_translate(PeriodicSurface *other, double xyz[3], BoundingBox SurfaceYPlane::bounding_box() const { - BoundingBox out {-INFTY, INFTY, y0, y0, -INFTY, INFTY}; - return out; + return {-INFTY, INFTY, y0, y0, -INFTY, INFTY}; } //============================================================================== @@ -429,20 +399,19 @@ SurfaceZPlane::SurfaceZPlane(pugi::xml_node surf_node) read_coeffs(surf_node, id, z0); } -inline double SurfaceZPlane::evaluate(const double xyz[3]) const +double SurfaceZPlane::evaluate(Position r) const { - return axis_aligned_plane_evaluate<2>(xyz, z0); + return r.z - z0; } -inline double SurfaceZPlane::distance(const double xyz[3], const double uvw[3], - bool coincident) const +double SurfaceZPlane::distance(Position r, Angle a, bool coincident) const { - return axis_aligned_plane_distance<2>(xyz, uvw, coincident, z0); + return axis_aligned_plane_distance<2>(r, a, coincident, z0); } -inline void SurfaceZPlane::normal(const double xyz[3], double uvw[3]) const +Angle SurfaceZPlane::normal(Position r) const { - axis_aligned_plane_normal<2, 0, 1>(xyz, uvw); + return {0., 0., 1.}; } void SurfaceZPlane::to_hdf5_inner(hid_t group_id) const @@ -452,19 +421,18 @@ void SurfaceZPlane::to_hdf5_inner(hid_t group_id) const write_dataset(group_id, "coefficients", coeffs); } -bool SurfaceZPlane::periodic_translate(PeriodicSurface *other, double xyz[3], - double uvw[3]) const +bool SurfaceZPlane::periodic_translate(const PeriodicSurface *other, Position& r, + Angle& a) const { // Assume the other plane is aligned along z. Just change the z coord. - xyz[2] = z0; + r.z = z0; return false; } BoundingBox SurfaceZPlane::bounding_box() const { - BoundingBox out {-INFTY, INFTY, -INFTY, INFTY, z0, z0}; - return out; + return {-INFTY, INFTY, -INFTY, INFTY, z0, z0}; } //============================================================================== @@ -478,17 +446,16 @@ SurfacePlane::SurfacePlane(pugi::xml_node surf_node) } double -SurfacePlane::evaluate(const double xyz[3]) const +SurfacePlane::evaluate(Position r) const { - return A*xyz[0] + B*xyz[1] + C*xyz[2] - D; + return A*r.x + B*r.y + C*r.z - D; } double -SurfacePlane::distance(const double xyz[3], const double uvw[3], - bool coincident) const +SurfacePlane::distance(Position r, Angle a, bool coincident) const { - const double f = A*xyz[0] + B*xyz[1] + C*xyz[2] - D; - const double projection = A*uvw[0] + B*uvw[1] + C*uvw[2]; + const double f = A*r.x + B*r.y + C*r.z - D; + const double projection = A*a.u() + B*a.v() + C*a.w(); if (coincident or std::abs(f) < FP_COINCIDENT or projection == 0.0) { return INFTY; } else { @@ -498,12 +465,10 @@ SurfacePlane::distance(const double xyz[3], const double uvw[3], } } -void -SurfacePlane::normal(const double xyz[3], double uvw[3]) const +Angle +SurfacePlane::normal(Position r) const { - uvw[0] = A; - uvw[1] = B; - uvw[2] = C; + return {A, B, C}; } void SurfacePlane::to_hdf5_inner(hid_t group_id) const @@ -513,18 +478,18 @@ void SurfacePlane::to_hdf5_inner(hid_t group_id) const write_dataset(group_id, "coefficients", coeffs); } -bool SurfacePlane::periodic_translate(PeriodicSurface *other, double xyz[3], - double uvw[3]) const +bool SurfacePlane::periodic_translate(const PeriodicSurface *other, Position& r, + Angle& a) const { // This function assumes the other plane shares this plane's normal direction. // Determine the distance to intersection. - double d = evaluate(xyz) / (A*A + B*B + C*C); + double d = evaluate(r) / (A*A + B*B + C*C); // Move the particle that distance along the normal vector. - xyz[0] -= d * A; - xyz[1] -= d * B; - xyz[2] -= d * C; + r.x -= d * A; + r.y -= d * B; + r.z -= d * C; return false; } @@ -532,8 +497,7 @@ bool SurfacePlane::periodic_translate(PeriodicSurface *other, double xyz[3], BoundingBox SurfacePlane::bounding_box() const { - BoundingBox out {-INFTY, INFTY, -INFTY, INFTY, -INFTY, INFTY}; - return out; + return {-INFTY, INFTY, -INFTY, INFTY, -INFTY, INFTY}; } //============================================================================== @@ -544,28 +508,28 @@ SurfacePlane::bounding_box() const // cylinder. offset1 and offset2 should correspond with i1 and i2, // respectively. template double -axis_aligned_cylinder_evaluate(const double xyz[3], double offset1, +axis_aligned_cylinder_evaluate(Position r, double offset1, double offset2, double radius) { - const double xyz1 = xyz[i1] - offset1; - const double xyz2 = xyz[i2] - offset2; - return xyz1*xyz1 + xyz2*xyz2 - radius*radius; + const double r1 = r[i1] - offset1; + const double r2 = r[i2] - offset2; + return r1*r1 + r2*r2 - radius*radius; } // The first template parameter indicates which axis the cylinder is aligned to. // The other two parameters indicate the other two axes. offset1 and offset2 // should correspond with i2 and i3, respectively. template double -axis_aligned_cylinder_distance(const double xyz[3], const double uvw[3], +axis_aligned_cylinder_distance(Position r, Angle u, bool coincident, double offset1, double offset2, double radius) { - const double a = 1.0 - uvw[i1]*uvw[i1]; // u^2 + v^2 + const double a = 1.0 - u[i1]*u[i1]; // u^2 + v^2 if (a == 0.0) return INFTY; - const double xyz2 = xyz[i2] - offset1; - const double xyz3 = xyz[i3] - offset2; - const double k = xyz2 * uvw[i2] + xyz3 * uvw[i3]; - const double c = xyz2*xyz2 + xyz3*xyz3 - radius*radius; + const double r2 = r[i2] - offset1; + const double r3 = r[i3] - offset2; + const double k = r2 * u[i2] + r3 * u[i3]; + const double c = r2*r2 + r3*r3 - radius*radius; const double quad = k*k - a*c; if (quad < 0.0) { @@ -601,13 +565,14 @@ axis_aligned_cylinder_distance(const double xyz[3], const double uvw[3], // The first template parameter indicates which axis the cylinder is aligned to. // The other two parameters indicate the other two axes. offset1 and offset2 // should correspond with i2 and i3, respectively. -template void -axis_aligned_cylinder_normal(const double xyz[3], double uvw[3], double offset1, - double offset2) +template Angle +axis_aligned_cylinder_normal(Position r, double offset1, double offset2) { - uvw[i2] = 2.0 * (xyz[i2] - offset1); - uvw[i3] = 2.0 * (xyz[i3] - offset2); - uvw[i1] = 0.0; + Angle a; + a[i2] = 2.0 * (r[i2] - offset1); + a[i3] = 2.0 * (r[i3] - offset2); + a[i1] = 0.0; + return a; } //============================================================================== @@ -620,21 +585,20 @@ SurfaceXCylinder::SurfaceXCylinder(pugi::xml_node surf_node) read_coeffs(surf_node, id, y0, z0, r); } -inline double SurfaceXCylinder::evaluate(const double xyz[3]) const +double SurfaceXCylinder::evaluate(Position r) const { - return axis_aligned_cylinder_evaluate<1, 2>(xyz, y0, z0, r); + return axis_aligned_cylinder_evaluate<1, 2>(r, y0, z0, this->r); } -inline double SurfaceXCylinder::distance(const double xyz[3], - const double uvw[3], bool coincident) const +double SurfaceXCylinder::distance(Position r, Angle a, bool coincident) const { - return axis_aligned_cylinder_distance<0, 1, 2>(xyz, uvw, coincident, y0, z0, - r); + return axis_aligned_cylinder_distance<0, 1, 2>(r, a, coincident, y0, z0, + this->r); } -inline void SurfaceXCylinder::normal(const double xyz[3], double uvw[3]) const +Angle SurfaceXCylinder::normal(Position r) const { - axis_aligned_cylinder_normal<0, 1, 2>(xyz, uvw, y0, z0); + return axis_aligned_cylinder_normal<0, 1, 2>(r, y0, z0); } @@ -655,21 +619,20 @@ SurfaceYCylinder::SurfaceYCylinder(pugi::xml_node surf_node) read_coeffs(surf_node, id, x0, z0, r); } -inline double SurfaceYCylinder::evaluate(const double xyz[3]) const +double SurfaceYCylinder::evaluate(Position r) const { - return axis_aligned_cylinder_evaluate<0, 2>(xyz, x0, z0, r); + return axis_aligned_cylinder_evaluate<0, 2>(r, x0, z0, this->r); } -inline double SurfaceYCylinder::distance(const double xyz[3], - const double uvw[3], bool coincident) const +double SurfaceYCylinder::distance(Position r, Angle a, bool coincident) const { - return axis_aligned_cylinder_distance<1, 0, 2>(xyz, uvw, coincident, x0, z0, - r); + return axis_aligned_cylinder_distance<1, 0, 2>(r, a, coincident, x0, z0, + this->r); } -inline void SurfaceYCylinder::normal(const double xyz[3], double uvw[3]) const +Angle SurfaceYCylinder::normal(Position r) const { - axis_aligned_cylinder_normal<1, 0, 2>(xyz, uvw, x0, z0); + return axis_aligned_cylinder_normal<1, 0, 2>(r, x0, z0); } void SurfaceYCylinder::to_hdf5_inner(hid_t group_id) const @@ -689,21 +652,20 @@ SurfaceZCylinder::SurfaceZCylinder(pugi::xml_node surf_node) read_coeffs(surf_node, id, x0, y0, r); } -inline double SurfaceZCylinder::evaluate(const double xyz[3]) const +double SurfaceZCylinder::evaluate(Position r) const { - return axis_aligned_cylinder_evaluate<0, 1>(xyz, x0, y0, r); + return axis_aligned_cylinder_evaluate<0, 1>(r, x0, y0, this->r); } -inline double SurfaceZCylinder::distance(const double xyz[3], - const double uvw[3], bool coincident) const +double SurfaceZCylinder::distance(Position r, Angle a, bool coincident) const { - return axis_aligned_cylinder_distance<2, 0, 1>(xyz, uvw, coincident, x0, y0, - r); + return axis_aligned_cylinder_distance<2, 0, 1>(r, a, coincident, x0, y0, + this->r); } -inline void SurfaceZCylinder::normal(const double xyz[3], double uvw[3]) const +Angle SurfaceZCylinder::normal(Position r) const { - axis_aligned_cylinder_normal<2, 0, 1>(xyz, uvw, x0, y0); + return axis_aligned_cylinder_normal<2, 0, 1>(r, x0, y0); } void SurfaceZCylinder::to_hdf5_inner(hid_t group_id) const @@ -723,22 +685,21 @@ SurfaceSphere::SurfaceSphere(pugi::xml_node surf_node) read_coeffs(surf_node, id, x0, y0, z0, r); } -double SurfaceSphere::evaluate(const double xyz[3]) const +double SurfaceSphere::evaluate(Position r) const { - const double x = xyz[0] - x0; - const double y = xyz[1] - y0; - const double z = xyz[2] - z0; - return x*x + y*y + z*z - r*r; + const double x = r.x - x0; + const double y = r.y - y0; + const double z = r.z - z0; + return x*x + y*y + z*z - this->r*this->r; } -double SurfaceSphere::distance(const double xyz[3], const double uvw[3], - bool coincident) const +double SurfaceSphere::distance(Position r, Angle a, bool coincident) const { - const double x = xyz[0] - x0; - const double y = xyz[1] - y0; - const double z = xyz[2] - z0; - const double k = x*uvw[0] + y*uvw[1] + z*uvw[2]; - const double c = x*x + y*y + z*z - r*r; + const double x = r.x - x0; + const double y = r.y - y0; + const double z = r.z - z0; + const double k = x*a.u() + y*a.v() + z*a.w(); + const double c = x*x + y*y + z*z - this->r*this->r; const double quad = k*k - c; if (quad < 0.0) { @@ -770,11 +731,9 @@ double SurfaceSphere::distance(const double xyz[3], const double uvw[3], } } -inline void SurfaceSphere::normal(const double xyz[3], double uvw[3]) const +Angle SurfaceSphere::normal(Position r) const { - uvw[0] = 2.0 * (xyz[0] - x0); - uvw[1] = 2.0 * (xyz[1] - y0); - uvw[2] = 2.0 * (xyz[2] - z0); + return {2.0*(r.x - x0), 2.0*(r.y - y0), 2.0*(r.z - z0)}; } void SurfaceSphere::to_hdf5_inner(hid_t group_id) const @@ -792,30 +751,30 @@ void SurfaceSphere::to_hdf5_inner(hid_t group_id) const // The other two parameters indicate the other two axes. offset1, offset2, // and offset3 should correspond with i1, i2, and i3, respectively. template double -axis_aligned_cone_evaluate(const double xyz[3], double offset1, +axis_aligned_cone_evaluate(Position r, double offset1, double offset2, double offset3, double radius_sq) { - const double xyz1 = xyz[i1] - offset1; - const double xyz2 = xyz[i2] - offset2; - const double xyz3 = xyz[i3] - offset3; - return xyz2*xyz2 + xyz3*xyz3 - radius_sq*xyz1*xyz1; + const double r1 = r[i1] - offset1; + const double r2 = r[i2] - offset2; + const double r3 = r[i3] - offset3; + return r2*r2 + r3*r3 - radius_sq*r1*r1; } // The first template parameter indicates which axis the cone is aligned to. // The other two parameters indicate the other two axes. offset1, offset2, // and offset3 should correspond with i1, i2, and i3, respectively. template double -axis_aligned_cone_distance(const double xyz[3], const double uvw[3], +axis_aligned_cone_distance(Position r, Angle u, bool coincident, double offset1, double offset2, double offset3, double radius_sq) { - const double xyz1 = xyz[i1] - offset1; - const double xyz2 = xyz[i2] - offset2; - const double xyz3 = xyz[i3] - offset3; - const double a = uvw[i2]*uvw[i2] + uvw[i3]*uvw[i3] - - radius_sq*uvw[i1]*uvw[i1]; - const double k = xyz2*uvw[i2] + xyz3*uvw[i3] - radius_sq*xyz1*uvw[i1]; - const double c = xyz2*xyz2 + xyz3*xyz3 - radius_sq*xyz1*xyz1; + const double r1 = r[i1] - offset1; + const double r2 = r[i2] - offset2; + const double r3 = r[i3] - offset3; + const double a = u[i2]*u[i2] + u[i3]*u[i3] + - radius_sq*u[i1]*u[i1]; + const double k = r2*u[i2] + r3*u[i3] - radius_sq*r1*u[i1]; + const double c = r2*r2 + r3*r3 - radius_sq*r1*r1; double quad = k*k - a*c; double d; @@ -858,13 +817,15 @@ axis_aligned_cone_distance(const double xyz[3], const double uvw[3], // The first template parameter indicates which axis the cone is aligned to. // The other two parameters indicate the other two axes. offset1, offset2, // and offset3 should correspond with i1, i2, and i3, respectively. -template void -axis_aligned_cone_normal(const double xyz[3], double uvw[3], double offset1, - double offset2, double offset3, double radius_sq) +template Angle +axis_aligned_cone_normal(Position r, double offset1, double offset2, + double offset3, double radius_sq) { - uvw[i1] = -2.0 * radius_sq * (xyz[i1] - offset1); - uvw[i2] = 2.0 * (xyz[i2] - offset2); - uvw[i3] = 2.0 * (xyz[i3] - offset3); + Angle a; + a[i1] = -2.0 * radius_sq * (r[i1] - offset1); + a[i2] = 2.0 * (r[i2] - offset2); + a[i3] = 2.0 * (r[i3] - offset3); + return a; } //============================================================================== @@ -877,21 +838,20 @@ SurfaceXCone::SurfaceXCone(pugi::xml_node surf_node) read_coeffs(surf_node, id, x0, y0, z0, r_sq); } -inline double SurfaceXCone::evaluate(const double xyz[3]) const +double SurfaceXCone::evaluate(Position r) const { - return axis_aligned_cone_evaluate<0, 1, 2>(xyz, x0, y0, z0, r_sq); + return axis_aligned_cone_evaluate<0, 1, 2>(r, x0, y0, z0, r_sq); } -inline double SurfaceXCone::distance(const double xyz[3], - const double uvw[3], bool coincident) const +double SurfaceXCone::distance(Position r, Angle a, bool coincident) const { - return axis_aligned_cone_distance<0, 1, 2>(xyz, uvw, coincident, x0, y0, z0, + return axis_aligned_cone_distance<0, 1, 2>(r, a, coincident, x0, y0, z0, r_sq); } -inline void SurfaceXCone::normal(const double xyz[3], double uvw[3]) const +Angle SurfaceXCone::normal(Position r) const { - axis_aligned_cone_normal<0, 1, 2>(xyz, uvw, x0, y0, z0, r_sq); + return axis_aligned_cone_normal<0, 1, 2>(r, x0, y0, z0, r_sq); } void SurfaceXCone::to_hdf5_inner(hid_t group_id) const @@ -911,21 +871,20 @@ SurfaceYCone::SurfaceYCone(pugi::xml_node surf_node) read_coeffs(surf_node, id, x0, y0, z0, r_sq); } -inline double SurfaceYCone::evaluate(const double xyz[3]) const +double SurfaceYCone::evaluate(Position r) const { - return axis_aligned_cone_evaluate<1, 0, 2>(xyz, y0, x0, z0, r_sq); + return axis_aligned_cone_evaluate<1, 0, 2>(r, y0, x0, z0, r_sq); } -inline double SurfaceYCone::distance(const double xyz[3], - const double uvw[3], bool coincident) const +double SurfaceYCone::distance(Position r, Angle a, bool coincident) const { - return axis_aligned_cone_distance<1, 0, 2>(xyz, uvw, coincident, y0, x0, z0, + return axis_aligned_cone_distance<1, 0, 2>(r, a, coincident, y0, x0, z0, r_sq); } -inline void SurfaceYCone::normal(const double xyz[3], double uvw[3]) const +Angle SurfaceYCone::normal(Position r) const { - axis_aligned_cone_normal<1, 0, 2>(xyz, uvw, y0, x0, z0, r_sq); + return axis_aligned_cone_normal<1, 0, 2>(r, y0, x0, z0, r_sq); } void SurfaceYCone::to_hdf5_inner(hid_t group_id) const @@ -945,21 +904,20 @@ SurfaceZCone::SurfaceZCone(pugi::xml_node surf_node) read_coeffs(surf_node, id, x0, y0, z0, r_sq); } -inline double SurfaceZCone::evaluate(const double xyz[3]) const +double SurfaceZCone::evaluate(Position r) const { - return axis_aligned_cone_evaluate<2, 0, 1>(xyz, z0, x0, y0, r_sq); + return axis_aligned_cone_evaluate<2, 0, 1>(r, z0, x0, y0, r_sq); } -inline double SurfaceZCone::distance(const double xyz[3], - const double uvw[3], bool coincident) const +double SurfaceZCone::distance(Position r, Angle a, bool coincident) const { - return axis_aligned_cone_distance<2, 0, 1>(xyz, uvw, coincident, z0, x0, y0, + return axis_aligned_cone_distance<2, 0, 1>(r, a, coincident, z0, x0, y0, r_sq); } -inline void SurfaceZCone::normal(const double xyz[3], double uvw[3]) const +Angle SurfaceZCone::normal(Position r) const { - axis_aligned_cone_normal<2, 0, 1>(xyz, uvw, z0, x0, y0, r_sq); + return axis_aligned_cone_normal<2, 0, 1>(r, z0, x0, y0, r_sq); } void SurfaceZCone::to_hdf5_inner(hid_t group_id) const @@ -980,26 +938,25 @@ SurfaceQuadric::SurfaceQuadric(pugi::xml_node surf_node) } double -SurfaceQuadric::evaluate(const double xyz[3]) const +SurfaceQuadric::evaluate(Position r) const { - const double &x = xyz[0]; - const double &y = xyz[1]; - const double &z = xyz[2]; + const double x = r.x; + const double y = r.y; + const double z = r.z; return x*(A*x + D*y + G) + y*(B*y + E*z + H) + z*(C*z + F*x + J) + K; } double -SurfaceQuadric::distance(const double xyz[3], - const double uvw[3], bool coincident) const +SurfaceQuadric::distance(Position r, Angle ang, bool coincident) const { - const double &x = xyz[0]; - const double &y = xyz[1]; - const double &z = xyz[2]; - const double &u = uvw[0]; - const double &v = uvw[1]; - const double &w = uvw[2]; + const double &x = r.x; + const double &y = r.y; + const double &z = r.z; + const double &u = ang.u(); + const double &v = ang.v(); + const double &w = ang.w(); const double a = A*u*u + B*v*v + C*w*w + D*u*v + E*v*w + F*u*w; const double k = (A*u*x + B*v*y + C*w*z + 0.5*(D*(u*y + v*x) + @@ -1045,15 +1002,15 @@ SurfaceQuadric::distance(const double xyz[3], return d; } -void -SurfaceQuadric::normal(const double xyz[3], double uvw[3]) const +Angle +SurfaceQuadric::normal(Position r) const { - const double &x = xyz[0]; - const double &y = xyz[1]; - const double &z = xyz[2]; - uvw[0] = 2.0*A*x + D*y + F*z + G; - uvw[1] = 2.0*B*y + D*x + E*z + H; - uvw[2] = 2.0*C*z + E*y + F*x + J; + const double &x = r.x; + const double &y = r.y; + const double &z = r.z; + return {2.0*A*x + D*y + F*z + G, + 2.0*B*y + D*x + E*z + H, + 2.0*C*z + E*y + F*x + J}; } void SurfaceQuadric::to_hdf5_inner(hid_t group_id) const @@ -1263,10 +1220,24 @@ extern "C" { int surface_bc(Surface *surf) {return surf->bc;} void surface_reflect(Surface *surf, double xyz[3], double uvw[3]) - {surf->reflect(xyz, uvw);} + { + Position r {xyz}; + Angle a {uvw}; + a = surf->reflect(r, a); + + uvw[0] = a.u(); + uvw[1] = a.v(); + uvw[2] = a.w(); + } void surface_normal(Surface *surf, double xyz[3], double uvw[3]) - {return surf->normal(xyz, uvw);} + { + Position r {xyz}; + Angle a = surf->normal(r); + uvw[0] = a.u(); + uvw[1] = a.v(); + uvw[2] = a.w(); + } void surface_to_hdf5(Surface *surf, hid_t group) {surf->to_hdf5(group);} @@ -1275,7 +1246,21 @@ extern "C" { bool surface_periodic(PeriodicSurface *surf, PeriodicSurface *other, double xyz[3], double uvw[3]) - {return surf->periodic_translate(other, xyz, uvw);} + { + Position r {xyz}; + Angle a {uvw}; + bool rotational = surf->periodic_translate(other, r, a); + + // Copy back to arrays + xyz[0] = r.x; + xyz[1] = r.y; + xyz[2] = r.z; + uvw[0] = a.u(); + uvw[1] = a.v(); + uvw[2] = a.w(); + + return rotational; + } void free_memory_surfaces_c() { diff --git a/src/surface.h b/src/surface.h index 666fc0dbae..be3ad52ab9 100644 --- a/src/surface.h +++ b/src/surface.h @@ -9,6 +9,7 @@ #include "pugixml.hpp" #include "constants.h" +#include "geometry.h" namespace openmc { @@ -65,39 +66,38 @@ public: virtual ~Surface() {} //! Determine which side of a surface a point lies on. - //! @param xyz[3] The 3D Cartesian coordinate of a point. - //! @param uvw[3] A direction used to "break ties" and pick a sense when the + //! @param r The 3D Cartesian coordinate of a point. + //! @param o A direction used to "break ties" and pick a sense when the //! point is very close to the surface. //! @return true if the point is on the "positive" side of the surface and //! false otherwise. - bool sense(const double xyz[3], const double uvw[3]) const; + bool sense(Position r, Angle a) const; //! Determine the direction of a ray reflected from the surface. - //! @param xyz[3] The point at which the ray is incident. - //! @param uvw[3] A direction. This is both an input and an output parameter. + //! @param r The point at which the ray is incident. + //! @param o A direction. This is both an input and an output parameter. //! It specifies the icident direction on input and the reflected direction //! on output. - void reflect(const double xyz[3], double uvw[3]) const; + Angle reflect(Position r, Angle a) const; //! Evaluate the equation describing the surface. //! //! Surfaces can be described by some function f(x, y, z) = 0. This member //! function evaluates that mathematical function. - //! @param xyz[3] A 3D Cartesian coordinate. - virtual double evaluate(const double xyz[3]) const = 0; + //! @param r A 3D Cartesian coordinate. + virtual double evaluate(Position r) const = 0; //! Compute the distance between a point and the surface along a ray. - //! @param xyz[3] A 3D Cartesian coordinate. - //! @param uvw[3] The direction of the ray. + //! @param r A 3D Cartesian coordinate. + //! @param o The direction of the ray. //! @param coincident A hint to the code that the given point should lie //! exactly on the surface. - virtual double distance(const double xyz[3], const double uvw[3], - bool coincident) const = 0; + virtual double distance(Position r, Angle a, bool coincident) const = 0; //! Compute the local outward normal direction of the surface. - //! @param xyz[3] A 3D Cartesian coordinate. - //! @param uvw[3] This output argument provides the normal. - virtual void normal(const double xyz[3], double uvw[3]) const = 0; + //! @param r A 3D Cartesian coordinate. + //! @return Normal direction + virtual Angle normal(Position r) const = 0; //! Write all information needed to reconstruct the surface to an HDF5 group. //! @param group_id An HDF5 group id. @@ -125,14 +125,14 @@ public: //! Translate a particle onto this surface from a periodic partner surface. //! @param other A pointer to the partner surface in this periodic BC. - //! @param xyz[3] A point on the partner surface that will be translated onto + //! @param r A point on the partner surface that will be translated onto //! this surface. - //! @param uvw[3] A direction that will be rotated for systems with rotational + //! @param a A direction that will be rotated for systems with rotational //! periodicity. //! @return true if this surface and its partner make a rotationally-periodic //! boundary condition. - virtual bool periodic_translate(PeriodicSurface *other, double xyz[3], - double uvw[3]) const = 0; + virtual bool periodic_translate(const PeriodicSurface *other, Position& r, + Angle& a) const = 0; //! Get the bounding box for this surface. virtual BoundingBox bounding_box() const = 0; @@ -149,12 +149,11 @@ class SurfaceXPlane : public PeriodicSurface double x0; public: explicit SurfaceXPlane(pugi::xml_node surf_node); - double evaluate(const double xyz[3]) const; - double distance(const double xyz[3], const double uvw[3], bool coincident) - const; - void normal(const double xyz[3], double uvw[3]) const; + double evaluate(Position r) const; + double distance(Position r, Angle a, bool coincident) const; + Angle normal(Position r) const; void to_hdf5_inner(hid_t group_id) const; - bool periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3]) + bool periodic_translate(const PeriodicSurface *other, Position& r, Angle& a) const; BoundingBox bounding_box() const; }; @@ -170,12 +169,11 @@ class SurfaceYPlane : public PeriodicSurface double y0; public: explicit SurfaceYPlane(pugi::xml_node surf_node); - double evaluate(const double xyz[3]) const; - double distance(const double xyz[3], const double uvw[3], - bool coincident) const; - void normal(const double xyz[3], double uvw[3]) const; + double evaluate(Position r) const; + double distance(Position r, Angle a, bool coincident) const; + Angle normal(Position r) const; void to_hdf5_inner(hid_t group_id) const; - bool periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3]) + bool periodic_translate(const PeriodicSurface *other, Position& r, Angle& a) const; BoundingBox bounding_box() const; }; @@ -191,12 +189,11 @@ class SurfaceZPlane : public PeriodicSurface double z0; public: explicit SurfaceZPlane(pugi::xml_node surf_node); - double evaluate(const double xyz[3]) const; - double distance(const double xyz[3], const double uvw[3], - bool coincident) const; - void normal(const double xyz[3], double uvw[3]) const; + double evaluate(Position r) const; + double distance(Position r, Angle a, bool coincident) const; + Angle normal(Position r) const; void to_hdf5_inner(hid_t group_id) const; - bool periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3]) + bool periodic_translate(const PeriodicSurface *other, Position& r, Angle& a) const; BoundingBox bounding_box() const; }; @@ -212,12 +209,11 @@ class SurfacePlane : public PeriodicSurface double A, B, C, D; public: explicit SurfacePlane(pugi::xml_node surf_node); - double evaluate(const double xyz[3]) const; - double distance(const double xyz[3], const double uvw[3], bool coincident) - const; - void normal(const double xyz[3], double uvw[3]) const; + double evaluate(Position r) const; + double distance(Position r, Angle a, bool coincident) const; + Angle normal(Position r) const; void to_hdf5_inner(hid_t group_id) const; - bool periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3]) + bool periodic_translate(const PeriodicSurface *other, Position& r, Angle& a) const; BoundingBox bounding_box() const; }; @@ -234,10 +230,9 @@ class SurfaceXCylinder : public Surface double y0, z0, r; public: explicit SurfaceXCylinder(pugi::xml_node surf_node); - double evaluate(const double xyz[3]) const; - double distance(const double xyz[3], const double uvw[3], - bool coincident) const; - void normal(const double xyz[3], double uvw[3]) const; + double evaluate(Position r) const; + double distance(Position r, Angle a, bool coincident) const; + Angle normal(Position r) const; void to_hdf5_inner(hid_t group_id) const; }; @@ -253,10 +248,9 @@ class SurfaceYCylinder : public Surface double x0, z0, r; public: explicit SurfaceYCylinder(pugi::xml_node surf_node); - double evaluate(const double xyz[3]) const; - double distance(const double xyz[3], const double uvw[3], - bool coincident) const; - void normal(const double xyz[3], double uvw[3]) const; + double evaluate(Position r) const; + double distance(Position r, Angle a, bool coincident) const; + Angle normal(Position r) const; void to_hdf5_inner(hid_t group_id) const; }; @@ -272,10 +266,9 @@ class SurfaceZCylinder : public Surface double x0, y0, r; public: explicit SurfaceZCylinder(pugi::xml_node surf_node); - double evaluate(const double xyz[3]) const; - double distance(const double xyz[3], const double uvw[3], - bool coincident) const; - void normal(const double xyz[3], double uvw[3]) const; + double evaluate(Position r) const; + double distance(Position r, Angle a, bool coincident) const; + Angle normal(Position r) const; void to_hdf5_inner(hid_t group_id) const; }; @@ -291,10 +284,9 @@ class SurfaceSphere : public Surface double x0, y0, z0, r; public: explicit SurfaceSphere(pugi::xml_node surf_node); - double evaluate(const double xyz[3]) const; - double distance(const double xyz[3], const double uvw[3], - bool coincident) const; - void normal(const double xyz[3], double uvw[3]) const; + double evaluate(Position r) const; + double distance(Position r, Angle a, bool coincident) const; + Angle normal(Position r) const; void to_hdf5_inner(hid_t group_id) const; }; @@ -310,10 +302,9 @@ class SurfaceXCone : public Surface double x0, y0, z0, r_sq; public: explicit SurfaceXCone(pugi::xml_node surf_node); - double evaluate(const double xyz[3]) const; - double distance(const double xyz[3], const double uvw[3], - bool coincident) const; - void normal(const double xyz[3], double uvw[3]) const; + double evaluate(Position r) const; + double distance(Position r, Angle a, bool coincident) const; + Angle normal(Position r) const; void to_hdf5_inner(hid_t group_id) const; }; @@ -329,10 +320,9 @@ class SurfaceYCone : public Surface double x0, y0, z0, r_sq; public: explicit SurfaceYCone(pugi::xml_node surf_node); - double evaluate(const double xyz[3]) const; - double distance(const double xyz[3], const double uvw[3], - bool coincident) const; - void normal(const double xyz[3], double uvw[3]) const; + double evaluate(Position r) const; + double distance(Position r, Angle a, bool coincident) const; + Angle normal(Position r) const; void to_hdf5_inner(hid_t group_id) const; }; @@ -348,10 +338,9 @@ class SurfaceZCone : public Surface double x0, y0, z0, r_sq; public: explicit SurfaceZCone(pugi::xml_node surf_node); - double evaluate(const double xyz[3]) const; - double distance(const double xyz[3], const double uvw[3], - bool coincident) const; - void normal(const double xyz[3], double uvw[3]) const; + double evaluate(Position r) const; + double distance(Position r, Angle a, bool coincident) const; + Angle normal(Position r) const; void to_hdf5_inner(hid_t group_id) const; }; @@ -367,10 +356,9 @@ class SurfaceQuadric : public Surface double A, B, C, D, E, F, G, H, J, K; public: explicit SurfaceQuadric(pugi::xml_node surf_node); - double evaluate(const double xyz[3]) const; - double distance(const double xyz[3], const double uvw[3], - bool coincident) const; - void normal(const double xyz[3], double uvw[3]) const; + double evaluate(Position r) const; + double distance(Position r, Angle a, bool coincident) const; + Angle normal(Position r) const; void to_hdf5_inner(hid_t group_id) const; }; From f7649a61dc0a67d4d4d48b4e544cd0f0c6aca1a7 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 26 Jun 2018 14:03:54 -0500 Subject: [PATCH 036/109] Use Position/Angle in lattice classes --- src/geometry.h | 4 +- src/hdf5_interface.h | 9 +++ src/lattice.cpp | 130 ++++++++++++++++++++----------------------- src/lattice.h | 41 +++++++------- 4 files changed, 93 insertions(+), 91 deletions(-) diff --git a/src/geometry.h b/src/geometry.h index 792d653aee..e069b9315b 100644 --- a/src/geometry.h +++ b/src/geometry.h @@ -12,7 +12,7 @@ struct Position { Position() = default; Position(double x_, double y_, double z_) : x{x_}, y{y_}, z{z_} { }; - Position(double xyz[]) : x{xyz[0]}, y{xyz[1]}, z{xyz[2]} { }; + Position(const double xyz[]) : x{xyz[0]}, y{xyz[1]}, z{xyz[2]} { }; Position& operator+=(Position); Position& operator+=(double); @@ -59,7 +59,7 @@ struct Angle : Position { double& w() { return z; } Angle() = default; Angle(double u, double v, double w) : Position{u, v, w} { }; - Angle(double uvw[]) : Position{uvw} { }; + Angle(const double uvw[]) : Position{uvw} { }; Angle(Position r) : Position{r} { }; }; diff --git a/src/hdf5_interface.h b/src/hdf5_interface.h index b0d2cc2c19..8b1f7a434d 100644 --- a/src/hdf5_interface.h +++ b/src/hdf5_interface.h @@ -11,6 +11,8 @@ #include #include +#include "geometry.h" + namespace openmc { @@ -181,5 +183,12 @@ write_dataset(hid_t obj_id, const char* name, const std::array& buffer) write_dataset(obj_id, 1, dims, name, H5TypeMap::type_id, buffer.data(), false); } +template<> inline void +write_dataset(hid_t obj_id, const char* name, Position r) +{ + std::array buffer {r.x, r.y, r.z}; + write_dataset(obj_id, name, buffer); +} + } // namespace openmc #endif //HDF5_INTERFACE_H diff --git a/src/lattice.cpp b/src/lattice.cpp index c95762a63d..c67fc419f0 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -223,15 +223,14 @@ RectLattice::are_valid_indices(const int i_xyz[3]) const //============================================================================== std::pair> -RectLattice::distance(const double xyz[3], const double uvw[3], - const int i_xyz[3]) const +RectLattice::distance(Position r, Angle a, const int i_xyz[3]) const { // Get short aliases to the coordinates. - double x {xyz[0]}; - double y {xyz[1]}; - double z {xyz[2]}; - double u {uvw[0]}; - double v {uvw[1]}; + double x = r.x; + double y = r.y; + double z = r.z; + double u = a.u(); + double v = a.v(); // Determine the oncoming edge. double x0 {copysign(0.5 * pitch[0], u)}; @@ -264,7 +263,7 @@ RectLattice::distance(const double xyz[3], const double uvw[3], // Top and bottom sides if (is_3d) { - double w {uvw[2]}; + double w {a.w()}; double z0 {copysign(0.5 * pitch[2], w)}; if ((std::abs(z - z0) > FP_PRECISION) && w != 0) { double this_d = (z0 - z) / w; @@ -285,13 +284,13 @@ RectLattice::distance(const double xyz[3], const double uvw[3], //============================================================================== std::array -RectLattice::get_indices(const double xyz[3]) const +RectLattice::get_indices(Position r) const { - int ix {static_cast(std::ceil((xyz[0] - lower_left[0]) / pitch[0]))-1}; - int iy {static_cast(std::ceil((xyz[1] - lower_left[1]) / pitch[1]))-1}; + int ix {static_cast(std::ceil((r.x - lower_left.x) / pitch.x))-1}; + int iy {static_cast(std::ceil((r.y - lower_left.y) / pitch.y))-1}; int iz; if (is_3d) { - iz = static_cast(std::ceil((xyz[2] - lower_left[2]) / pitch[2]))-1; + iz = static_cast(std::ceil((r.z - lower_left.z) / pitch.z))-1; } else { iz = 0; } @@ -300,18 +299,15 @@ RectLattice::get_indices(const double xyz[3]) const //============================================================================== -std::array -RectLattice::get_local_xyz(const double global_xyz[3], const int i_xyz[3]) const +Position +RectLattice::get_local_position(Position r, const int i_xyz[3]) const { - std::array local_xyz; - local_xyz[0] = global_xyz[0] - (lower_left[0] + (i_xyz[0] + 0.5)*pitch[0]); - local_xyz[1] = global_xyz[1] - (lower_left[1] + (i_xyz[1] + 0.5)*pitch[1]); + r.x -= (lower_left.x + (i_xyz[0] + 0.5)*pitch.x); + r.y -= (lower_left.y + (i_xyz[1] + 0.5)*pitch.y); if (is_3d) { - local_xyz[2] = global_xyz[2] - (lower_left[2] + (i_xyz[2] + 0.5)*pitch[2]); - } else { - local_xyz[2] = global_xyz[2]; + r.z -= (lower_left.z + (i_xyz[2] + 0.5)*pitch.z); } - return local_xyz; + return r; } //============================================================================== @@ -583,12 +579,11 @@ HexLattice::are_valid_indices(const int i_xyz[3]) const //============================================================================== std::pair> -HexLattice::distance(const double xyz[3], const double uvw[3], - const int i_xyz[3]) const +HexLattice::distance(Position r, Angle a, const int i_xyz[3]) const { // Compute the direction on the hexagonal basis. - double beta_dir = uvw[0] * std::sqrt(3.0) / 2.0 + uvw[1] / 2.0; - double gamma_dir = uvw[0] * std::sqrt(3.0) / 2.0 - uvw[1] / 2.0; + double beta_dir = a.u() * std::sqrt(3.0) / 2.0 + a.v() / 2.0; + double gamma_dir = a.u() * std::sqrt(3.0) / 2.0 - a.v() / 2.0; // Note that hexagonal lattice distance calculations are performed // using the particle's coordinates relative to the neighbor lattice @@ -600,15 +595,15 @@ HexLattice::distance(const double xyz[3], const double uvw[3], double d {INFTY}; std::array lattice_trans; double edge = -copysign(0.5*pitch[0], beta_dir); // Oncoming edge - std::array xyz_t; + Position r_t; if (beta_dir > 0) { const int i_xyz_t[3] {i_xyz[0]+1, i_xyz[1], i_xyz[2]}; - xyz_t = get_local_xyz(xyz, i_xyz_t); + r_t = get_local_position(r, i_xyz_t); } else { const int i_xyz_t[3] {i_xyz[0]-1, i_xyz[1], i_xyz[2]}; - xyz_t = get_local_xyz(xyz, i_xyz_t); + r_t = get_local_position(r, i_xyz_t); } - double beta = xyz_t[0] * std::sqrt(3.0) / 2.0 + xyz_t[1] / 2.0; + double beta = r_t.x * std::sqrt(3.0) / 2.0 + r_t.y / 2.0; if ((std::abs(beta - edge) > FP_PRECISION) && beta_dir != 0) { d = (edge - beta) / beta_dir; if (beta_dir > 0) { @@ -622,12 +617,12 @@ HexLattice::distance(const double xyz[3], const double uvw[3], edge = -copysign(0.5*pitch[0], gamma_dir); if (gamma_dir > 0) { const int i_xyz_t[3] {i_xyz[0]+1, i_xyz[1]-1, i_xyz[2]}; - xyz_t = get_local_xyz(xyz, i_xyz_t); + r_t = get_local_position(r, i_xyz_t); } else { const int i_xyz_t[3] {i_xyz[0]-1, i_xyz[1]+1, i_xyz[2]}; - xyz_t = get_local_xyz(xyz, i_xyz_t); + r_t = get_local_position(r, i_xyz_t); } - double gamma = xyz_t[0] * std::sqrt(3.0) / 2.0 - xyz_t[1] / 2.0; + double gamma = r_t.x * std::sqrt(3.0) / 2.0 - r_t.y / 2.0; if ((std::abs(gamma - edge) > FP_PRECISION) && gamma_dir != 0) { double this_d = (edge - gamma) / gamma_dir; if (this_d < d) { @@ -641,18 +636,18 @@ HexLattice::distance(const double xyz[3], const double uvw[3], } // Upper and lower sides. - edge = -copysign(0.5*pitch[0], uvw[1]); - if (uvw[1] > 0) { + edge = -copysign(0.5*pitch[0], a.v()); + if (a.v() > 0) { const int i_xyz_t[3] {i_xyz[0], i_xyz[1]+1, i_xyz[2]}; - xyz_t = get_local_xyz(xyz, i_xyz_t); + r_t = get_local_position(r, i_xyz_t); } else { const int i_xyz_t[3] {i_xyz[0], i_xyz[1]-1, i_xyz[2]}; - xyz_t = get_local_xyz(xyz, i_xyz_t); + r_t = get_local_position(r, i_xyz_t); } - if ((std::abs(xyz_t[1] - edge) > FP_PRECISION) && uvw[1] != 0) { - double this_d = (edge - xyz_t[1]) / uvw[1]; + if ((std::abs(r_t.y - edge) > FP_PRECISION) && a.v() != 0) { + double this_d = (edge - r_t.y) / a.v(); if (this_d < d) { - if (uvw[1] > 0) { + if (a.v() > 0) { lattice_trans = {0, 1, 0}; } else { lattice_trans = {0, -1, 0}; @@ -663,8 +658,8 @@ HexLattice::distance(const double xyz[3], const double uvw[3], // Top and bottom sides if (is_3d) { - double z {xyz[2]}; - double w {uvw[2]}; + double z = r.z; + double w = a.w(); double z0 {copysign(0.5 * pitch[1], w)}; if ((std::abs(z - z0) > FP_PRECISION) && w != 0) { double this_d = (z0 - z) / w; @@ -686,24 +681,24 @@ HexLattice::distance(const double xyz[3], const double uvw[3], //============================================================================== std::array -HexLattice::get_indices(const double xyz[3]) const +HexLattice::get_indices(Position r) const { // Offset the xyz by the lattice center. - double xyz_o[3] {xyz[0] - center[0], xyz[1] - center[1], xyz[2]}; - if (is_3d) {xyz_o[2] -= center[2];} + Position r_o {r.x - center.x, r.y - center.y, r.z}; + if (is_3d) {r_o.z -= center.z;} // Index the z direction. std::array out; if (is_3d) { - out[2] = static_cast(std::ceil(xyz_o[2] / pitch[1] + 0.5 * n_axial))-1; + out[2] = static_cast(std::ceil(r_o.z / pitch[1] + 0.5 * n_axial))-1; } else { out[2] = 0; } // Convert coordinates into skewed bases. The (x, alpha) basis is used to // find the index of the global coordinates to within 4 cells. - double alpha = xyz_o[1] - xyz_o[0] / std::sqrt(3.0); - out[0] = static_cast(std::floor(xyz_o[0] + double alpha = r_o.y - r_o.x / std::sqrt(3.0); + out[0] = static_cast(std::floor(r_o.x / (0.5*std::sqrt(3.0) * pitch[0]))); out[1] = static_cast(std::floor(alpha / pitch[0])); @@ -725,8 +720,8 @@ HexLattice::get_indices(const double xyz[3]) const for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { int i_xyz[3] {out[0] + j, out[1] + i, 0}; - std::array xyz_t = get_local_xyz(xyz, i_xyz); - double d = xyz_t[0]*xyz_t[0] + xyz_t[1]*xyz_t[1]; + Position r_t = get_local_position(r, i_xyz); + double d = r_t.x*r_t.x + r_t.y*r_t.y; if (d < d_min) { d_min = d; k_min = k; @@ -751,26 +746,19 @@ HexLattice::get_indices(const double xyz[3]) const //============================================================================== -std::array -HexLattice::get_local_xyz(const double global_xyz[3], const int i_xyz[3]) const +Position +HexLattice::get_local_position(Position r, const int i_xyz[3]) const { - std::array local_xyz; - // x_l = x_g - (center + pitch_x*cos(30)*index_x) - local_xyz[0] = global_xyz[0] - (center[0] - + std::sqrt(3.0)/2.0 * (i_xyz[0] - n_rings + 1) * pitch[0]); + r.x -= (center.x + std::sqrt(3.0)/2.0 * (i_xyz[0] - n_rings + 1) * pitch[0]); // y_l = y_g - (center + pitch_x*index_x + pitch_y*sin(30)*index_y) - local_xyz[1] = global_xyz[1] - (center[1] - + (i_xyz[1] - n_rings + 1) * pitch[0] - + (i_xyz[0] - n_rings + 1) * pitch[0] / 2.0); + r.y -= (center.y + (i_xyz[1] - n_rings + 1) * pitch[0] + + (i_xyz[0] - n_rings + 1) * pitch[0] / 2.0); if (is_3d) { - local_xyz[2] = global_xyz[2] - center[2] - + (0.5 * n_axial - i_xyz[2] - 0.5) * pitch[1]; - } else { - local_xyz[2] = global_xyz[2]; + r.z -= center.z - (0.5 * n_axial - i_xyz[2] - 0.5) * pitch[1]; } - return local_xyz; + return r; } //============================================================================== @@ -908,7 +896,9 @@ extern "C" { void lattice_distance(Lattice *lat, const double xyz[3], const double uvw[3], const int i_xyz[3], double *d, int lattice_trans[3]) { - std::pair> ld {lat->distance(xyz, uvw, i_xyz)}; + Position r {xyz}; + Angle a {uvw}; + std::pair> ld {lat->distance(r, a, i_xyz)}; *d = ld.first; lattice_trans[0] = ld.second[0]; lattice_trans[1] = ld.second[1]; @@ -917,7 +907,8 @@ extern "C" { void lattice_get_indices(Lattice *lat, const double xyz[3], int i_xyz[3]) { - std::array inds = lat->get_indices(xyz); + Position r {xyz}; + std::array inds = lat->get_indices(r); i_xyz[0] = inds[0]; i_xyz[1] = inds[1]; i_xyz[2] = inds[2]; @@ -926,10 +917,11 @@ extern "C" { void lattice_get_local_xyz(Lattice *lat, const double global_xyz[3], const int i_xyz[3], double local_xyz[3]) { - std::array xyz = lat->get_local_xyz(global_xyz, i_xyz); - local_xyz[0] = xyz[0]; - local_xyz[1] = xyz[1]; - local_xyz[2] = xyz[2]; + Position global {global_xyz}; + Position local = lat->get_local_position(global, i_xyz); + local_xyz[0] = local.x; + local_xyz[1] = local.y; + local_xyz[2] = local.z; } int32_t lattice_offset(Lattice *lat, int map, const int i_xyz[3]) diff --git a/src/lattice.h b/src/lattice.h index bc706a5a3f..a6c4496621 100644 --- a/src/lattice.h +++ b/src/lattice.h @@ -8,6 +8,7 @@ #include #include "constants.h" +#include "geometry.h" #include "hdf5.h" #include "pugixml.hpp" @@ -75,26 +76,26 @@ public: virtual bool are_valid_indices(const int i_xyz[3]) const = 0; //! \brief Find the next lattice surface crossing - //! @param xyz[3] A 3D Cartesian coordinate. - //! @param uvw[3] A 3D Cartesian direction. + //! @param r A 3D Cartesian coordinate. + //! @param a A 3D Cartesian direction. //! @param i_xyz[3] The indices for a lattice tile. //! @return The distance to the next crossing and an array indicating how the //! lattice indices would change after crossing that boundary. virtual std::pair> - distance(const double xyz[3], const double uvw[3], const int i_xyz[3]) const + distance(Position r, Angle a, const int i_xyz[3]) const = 0; //! \brief Find the lattice tile indices for a given point. - //! @param xyz[3] A 3D Cartesian coordinate. + //! @param r A 3D Cartesian coordinate. //! @return An array containing the indices of a lattice tile. - virtual std::array get_indices(const double xyz[3]) const = 0; + virtual std::array get_indices(Position r) const = 0; //! \brief Get coordinates local to a lattice tile. - //! @param global_xyz[3] A 3D Cartesian coordinate. + //! @param r A 3D Cartesian coordinate. //! @param i_xyz[3] The indices for a lattice tile. //! @return Local 3D Cartesian coordinates. - virtual std::array - get_local_xyz(const double global_xyz[3], const int i_xyz[3]) const = 0; + virtual Position + get_local_position(Position r, const int i_xyz[3]) const = 0; //! \brief Check flattened lattice index. //! @param indx The index for a lattice tile. @@ -193,12 +194,12 @@ public: bool are_valid_indices(const int i_xyz[3]) const; std::pair> - distance(const double xyz[3], const double uvw[3], const int i_xyz[3]) const; + distance(Position r, Angle a, const int i_xyz[3]) const; - std::array get_indices(const double xyz[3]) const; + std::array get_indices(Position r) const; - std::array - get_local_xyz(const double global_xyz[3], const int i_xyz[3]) const; + Position + get_local_position(Position r, const int i_xyz[3]) const; int32_t& offset(int map, const int i_xyz[3]); @@ -207,9 +208,9 @@ public: void to_hdf5_inner(hid_t group_id) const; private: - std::array n_cells; //!< Number of cells along each axis - std::array lower_left; //!< Global lower-left corner of the lattice - std::array pitch; //!< Lattice tile width along each axis + std::array n_cells; //!< Number of cells along each axis + Position lower_left; //!< Global lower-left corner of the lattice + Position pitch; //!< Lattice tile width along each axis // Convenience aliases int &nx {n_cells[0]}; @@ -233,12 +234,12 @@ public: bool are_valid_indices(const int i_xyz[3]) const; std::pair> - distance(const double xyz[3], const double uvw[3], const int i_xyz[3]) const; + distance(Position r, Angle a, const int i_xyz[3]) const; - std::array get_indices(const double xyz[3]) const; + std::array get_indices(Position r) const; - std::array - get_local_xyz(const double global_xyz[3], const int i_xyz[3]) const; + Position + get_local_position(Position r, const int i_xyz[3]) const; bool is_valid_index(int indx) const; @@ -251,7 +252,7 @@ public: private: int n_rings; //!< Number of radial tile positions int n_axial; //!< Number of axial tile positions - std::array center; //!< Global center of lattice + Position center; //!< Global center of lattice std::array pitch; //!< Lattice tile width and height }; From 0fba0e287c3c75d4c49bc93f9ec2d1b89764cee8 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 8 Aug 2018 13:36:42 -0500 Subject: [PATCH 037/109] Settle on Position/Direction, declared in position.h --- CMakeLists.txt | 2 +- src/cell.cpp | 26 ++-- src/cell.h | 11 +- src/geometry.h | 64 +--------- src/hdf5_interface.h | 2 +- src/lattice.cpp | 58 +++++---- src/lattice.h | 11 +- src/{geometry.cpp => position.cpp} | 6 +- src/position.h | 74 ++++++++++++ src/surface.cpp | 184 ++++++++++++++--------------- src/surface.h | 94 +++++++-------- 11 files changed, 275 insertions(+), 257 deletions(-) rename src/{geometry.cpp => position.cpp} (75%) create mode 100644 src/position.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 0be9ccb325..c94f4df5fd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -386,7 +386,6 @@ add_library(libopenmc SHARED src/cell.cpp src/initialize.cpp src/finalize.cpp - src/geometry.cpp src/geometry_aux.cpp src/hdf5_interface.cpp src/lattice.cpp @@ -396,6 +395,7 @@ add_library(libopenmc SHARED src/mgxs_interface.cpp src/particle.cpp src/plot.cpp + src/position.cpp src/pugixml/pugixml_c.cpp src/random_lcg.cpp src/scattdata.cpp diff --git a/src/cell.cpp b/src/cell.cpp index 972540fbd2..acf1473bb8 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -279,19 +279,19 @@ Cell::Cell(pugi::xml_node cell_node) //============================================================================== bool -Cell::contains(Position r, Angle a, int32_t on_surface) const +Cell::contains(Position r, Direction u, int32_t on_surface) const { if (simple) { - return contains_simple(r, a, on_surface); + return contains_simple(r, u, on_surface); } else { - return contains_complex(r, a, on_surface); + return contains_complex(r, u, on_surface); } } //============================================================================== std::pair -Cell::distance(Position r, Angle a, int32_t on_surface) const +Cell::distance(Position r, Direction u, int32_t on_surface) const { double min_dist {INFTY}; int32_t i_surf {std::numeric_limits::max()}; @@ -303,7 +303,7 @@ Cell::distance(Position r, Angle a, int32_t on_surface) const // Calculate the distance to this surface. // Note the off-by-one indexing bool coincident {token == on_surface}; - double d {surfaces_c[abs(token)-1]->distance(r, a, coincident)}; + double d {surfaces_c[abs(token)-1]->distance(r, u, coincident)}; // Check if this distance is the new minimum. if (d < min_dist) { @@ -354,7 +354,7 @@ Cell::to_hdf5(hid_t cell_group) const //============================================================================== bool -Cell::contains_simple(Position r, Angle a, int32_t on_surface) const +Cell::contains_simple(Position r, Direction u, int32_t on_surface) const { for (int32_t token : rpn) { if (token < OP_UNION) { @@ -367,7 +367,7 @@ Cell::contains_simple(Position r, Angle a, int32_t on_surface) const return false; } else { // Note the off-by-one indexing - bool sense = surfaces_c[abs(token)-1]->sense(r, a); + bool sense = surfaces_c[abs(token)-1]->sense(r, u); if (sense != (token > 0)) {return false;} } } @@ -378,7 +378,7 @@ Cell::contains_simple(Position r, Angle a, int32_t on_surface) const //============================================================================== bool -Cell::contains_complex(Position r, Angle a, int32_t on_surface) const +Cell::contains_complex(Position r, Direction u, int32_t on_surface) const { // Make a stack of booleans. We don't know how big it needs to be, but we do // know that rpn.size() is an upper-bound. @@ -409,7 +409,7 @@ Cell::contains_complex(Position r, Angle a, int32_t on_surface) const stack[i_stack] = false; } else { // Note the off-by-one indexing - bool sense = surfaces_c[abs(token)-1]->sense(r, a);; + bool sense = surfaces_c[abs(token)-1]->sense(r, u);; stack[i_stack] = (sense == (token > 0)); } } @@ -492,16 +492,16 @@ extern "C" { bool cell_contains(Cell *c, double xyz[3], double uvw[3], int32_t on_surface) { Position r {xyz}; - Angle a {uvw}; - return c->contains(r, a, on_surface); + Direction u {uvw}; + return c->contains(r, u, on_surface); } void cell_distance(Cell *c, double xyz[3], double uvw[3], int32_t on_surface, double *min_dist, int32_t *i_surf) { Position r {xyz}; - Angle a {uvw}; - std::pair out = c->distance(r, a, on_surface); + Direction u {uvw}; + std::pair out = c->distance(r, u, on_surface); *min_dist = out.first; *i_surf = out.second; } diff --git a/src/cell.h b/src/cell.h index 08a6abf3f6..10265beb1b 100644 --- a/src/cell.h +++ b/src/cell.h @@ -8,7 +8,8 @@ #include "hdf5.h" #include "pugixml.hpp" -#include "geometry.h" + +#include "position.h" namespace openmc { @@ -98,19 +99,19 @@ public: //! known to be on. This index takes precedence over surface sense //! calculations. bool - contains(Position r, Angle a, int32_t on_surface) const; + contains(Position r, Direction u, int32_t on_surface) const; //! Find the oncoming boundary of this cell. std::pair - distance(Position r, Angle a, int32_t on_surface) const; + distance(Position r, Direction u, int32_t on_surface) const; //! \brief Write cell information to an HDF5 group. //! @param group_id An HDF5 group id. void to_hdf5(hid_t group_id) const; protected: - bool contains_simple(Position r, Angle a, int32_t on_surface) const; - bool contains_complex(Position r, Angle a, int32_t on_surface) const; + bool contains_simple(Position r, Direction u, int32_t on_surface) const; + bool contains_complex(Position r, Direction u, int32_t on_surface) const; }; } // namespace openmc diff --git a/src/geometry.h b/src/geometry.h index e069b9315b..09e7eda8eb 100644 --- a/src/geometry.h +++ b/src/geometry.h @@ -1,68 +1,10 @@ -#ifndef GEOMETRY_H -#define GEOMETRY_H +#ifndef OPENMC_GEOMETRY_H +#define OPENMC_GEOMETRY_H namespace openmc { extern "C" int openmc_root_universe; -struct Position { - double x = 0.; - double y = 0.; - double z = 0.; - - Position() = default; - Position(double x_, double y_, double z_) : x{x_}, y{y_}, z{z_} { }; - Position(const double xyz[]) : x{xyz[0]}, y{xyz[1]}, z{xyz[2]} { }; - - Position& operator+=(Position); - Position& operator+=(double); - Position& operator-=(Position); - Position& operator-=(double); - Position& operator*=(Position); - Position& operator*=(double); - const double& operator[](int i) const { - switch (i) { - case 0: return x; - case 1: return y; - case 2: return z; - } - } - double& operator[](int i) { - switch (i) { - case 0: return x; - case 1: return y; - case 2: return z; - } - } - - inline double dot(Position other) { - return x*other.x + y*other.y + z*other.z; - } -}; - -inline Position operator+(Position a, Position b) { return a += b; } -inline Position operator+(Position a, double b) { return a += b; } -inline Position operator+(double a, Position b) { return b += a; } - -inline Position operator-(Position a, Position b) { return a -= b; } -inline Position operator-(Position a, double b) { return a -= b; } -inline Position operator-(double a, Position b) { return b -= a; } - -inline Position operator*(Position a, Position b) { return a *= b; } -inline Position operator*(Position a, double b) { return a *= b; } -inline Position operator*(double a, Position b) { return b *= a; } - - -struct Angle : Position { - double& u() { return x; } - double& v() { return y; } - double& w() { return z; } - Angle() = default; - Angle(double u, double v, double w) : Position{u, v, w} { }; - Angle(const double uvw[]) : Position{uvw} { }; - Angle(Position r) : Position{r} { }; -}; - } // namespace openmc -#endif // GEOMETRY_H +#endif // OPENMC_GEOMETRY_H diff --git a/src/hdf5_interface.h b/src/hdf5_interface.h index 8b1f7a434d..b0466e613d 100644 --- a/src/hdf5_interface.h +++ b/src/hdf5_interface.h @@ -11,7 +11,7 @@ #include #include -#include "geometry.h" +#include "position.h" namespace openmc { diff --git a/src/lattice.cpp b/src/lattice.cpp index c67fc419f0..73dcb98667 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -223,25 +223,23 @@ RectLattice::are_valid_indices(const int i_xyz[3]) const //============================================================================== std::pair> -RectLattice::distance(Position r, Angle a, const int i_xyz[3]) const +RectLattice::distance(Position r, Direction u, const int i_xyz[3]) const { // Get short aliases to the coordinates. double x = r.x; double y = r.y; double z = r.z; - double u = a.u(); - double v = a.v(); // Determine the oncoming edge. - double x0 {copysign(0.5 * pitch[0], u)}; - double y0 {copysign(0.5 * pitch[1], v)}; + double x0 {copysign(0.5 * pitch[0], u.x)}; + double y0 {copysign(0.5 * pitch[1], u.y)}; // Left and right sides double d {INFTY}; std::array lattice_trans; - if ((std::abs(x - x0) > FP_PRECISION) && u != 0) { - d = (x0 - x) / u; - if (u > 0) { + if ((std::abs(x - x0) > FP_PRECISION) && u.x != 0) { + d = (x0 - x) / u.x; + if (u.x > 0) { lattice_trans = {1, 0, 0}; } else { lattice_trans = {-1, 0, 0}; @@ -249,11 +247,11 @@ RectLattice::distance(Position r, Angle a, const int i_xyz[3]) const } // Front and back sides - if ((std::abs(y - y0) > FP_PRECISION) && v != 0) { - double this_d = (y0 - y) / v; + if ((std::abs(y - y0) > FP_PRECISION) && u.y != 0) { + double this_d = (y0 - y) / u.y; if (this_d < d) { d = this_d; - if (v > 0) { + if (u.y > 0) { lattice_trans = {0, 1, 0}; } else { lattice_trans = {0, -1, 0}; @@ -263,13 +261,12 @@ RectLattice::distance(Position r, Angle a, const int i_xyz[3]) const // Top and bottom sides if (is_3d) { - double w {a.w()}; - double z0 {copysign(0.5 * pitch[2], w)}; - if ((std::abs(z - z0) > FP_PRECISION) && w != 0) { - double this_d = (z0 - z) / w; + double z0 {copysign(0.5 * pitch[2], u.z)}; + if ((std::abs(z - z0) > FP_PRECISION) && u.z != 0) { + double this_d = (z0 - z) / u.z; if (this_d < d) { d = this_d; - if (w > 0) { + if (u.z > 0) { lattice_trans = {0, 0, 1}; } else { lattice_trans = {0, 0, -1}; @@ -579,11 +576,11 @@ HexLattice::are_valid_indices(const int i_xyz[3]) const //============================================================================== std::pair> -HexLattice::distance(Position r, Angle a, const int i_xyz[3]) const +HexLattice::distance(Position r, Direction u, const int i_xyz[3]) const { // Compute the direction on the hexagonal basis. - double beta_dir = a.u() * std::sqrt(3.0) / 2.0 + a.v() / 2.0; - double gamma_dir = a.u() * std::sqrt(3.0) / 2.0 - a.v() / 2.0; + double beta_dir = u.x * std::sqrt(3.0) / 2.0 + u.y / 2.0; + double gamma_dir = u.x * std::sqrt(3.0) / 2.0 - u.y / 2.0; // Note that hexagonal lattice distance calculations are performed // using the particle's coordinates relative to the neighbor lattice @@ -636,18 +633,18 @@ HexLattice::distance(Position r, Angle a, const int i_xyz[3]) const } // Upper and lower sides. - edge = -copysign(0.5*pitch[0], a.v()); - if (a.v() > 0) { + edge = -copysign(0.5*pitch[0], u.y); + if (u.y > 0) { const int i_xyz_t[3] {i_xyz[0], i_xyz[1]+1, i_xyz[2]}; r_t = get_local_position(r, i_xyz_t); } else { const int i_xyz_t[3] {i_xyz[0], i_xyz[1]-1, i_xyz[2]}; r_t = get_local_position(r, i_xyz_t); } - if ((std::abs(r_t.y - edge) > FP_PRECISION) && a.v() != 0) { - double this_d = (edge - r_t.y) / a.v(); + if ((std::abs(r_t.y - edge) > FP_PRECISION) && u.y != 0) { + double this_d = (edge - r_t.y) / u.y; if (this_d < d) { - if (a.v() > 0) { + if (u.y > 0) { lattice_trans = {0, 1, 0}; } else { lattice_trans = {0, -1, 0}; @@ -659,13 +656,12 @@ HexLattice::distance(Position r, Angle a, const int i_xyz[3]) const // Top and bottom sides if (is_3d) { double z = r.z; - double w = a.w(); - double z0 {copysign(0.5 * pitch[1], w)}; - if ((std::abs(z - z0) > FP_PRECISION) && w != 0) { - double this_d = (z0 - z) / w; + double z0 {copysign(0.5 * pitch[1], u.z)}; + if ((std::abs(z - z0) > FP_PRECISION) && u.z != 0) { + double this_d = (z0 - z) / u.z; if (this_d < d) { d = this_d; - if (w > 0) { + if (u.z > 0) { lattice_trans = {0, 0, 1}; } else { lattice_trans = {0, 0, -1}; @@ -897,8 +893,8 @@ extern "C" { const int i_xyz[3], double *d, int lattice_trans[3]) { Position r {xyz}; - Angle a {uvw}; - std::pair> ld {lat->distance(r, a, i_xyz)}; + Direction u {uvw}; + std::pair> ld {lat->distance(r, u, i_xyz)}; *d = ld.first; lattice_trans[0] = ld.second[0]; lattice_trans[1] = ld.second[1]; diff --git a/src/lattice.h b/src/lattice.h index a6c4496621..5bd15a6126 100644 --- a/src/lattice.h +++ b/src/lattice.h @@ -7,11 +7,12 @@ #include #include -#include "constants.h" -#include "geometry.h" #include "hdf5.h" #include "pugixml.hpp" +#include "constants.h" +#include "position.h" + namespace openmc { @@ -82,7 +83,7 @@ public: //! @return The distance to the next crossing and an array indicating how the //! lattice indices would change after crossing that boundary. virtual std::pair> - distance(Position r, Angle a, const int i_xyz[3]) const + distance(Position r, Direction u, const int i_xyz[3]) const = 0; //! \brief Find the lattice tile indices for a given point. @@ -194,7 +195,7 @@ public: bool are_valid_indices(const int i_xyz[3]) const; std::pair> - distance(Position r, Angle a, const int i_xyz[3]) const; + distance(Position r, Direction u, const int i_xyz[3]) const; std::array get_indices(Position r) const; @@ -234,7 +235,7 @@ public: bool are_valid_indices(const int i_xyz[3]) const; std::pair> - distance(Position r, Angle a, const int i_xyz[3]) const; + distance(Position r, Direction u, const int i_xyz[3]) const; std::array get_indices(Position r) const; diff --git a/src/geometry.cpp b/src/position.cpp similarity index 75% rename from src/geometry.cpp rename to src/position.cpp index 53bf32b5c1..85e511041e 100644 --- a/src/geometry.cpp +++ b/src/position.cpp @@ -1,7 +1,11 @@ -#include "geometry.h" +#include "position.h" namespace openmc { +//============================================================================== +// Position implementation +//============================================================================== + Position& Position::operator+=(Position other) { diff --git a/src/position.h b/src/position.h new file mode 100644 index 0000000000..808e0bcf67 --- /dev/null +++ b/src/position.h @@ -0,0 +1,74 @@ +#ifndef OPENMC_POSITION_H +#define OPENMC_POSITION_H + +namespace openmc { + +//============================================================================== +//! Type representing a position in Cartesian coordinates +//============================================================================== + +struct Position { + // Constructors + Position() = default; + Position(double x_, double y_, double z_) : x{x_}, y{y_}, z{z_} { }; + Position(const double xyz[]) : x{xyz[0]}, y{xyz[1]}, z{xyz[2]} { }; + + // Unary operators + Position& operator+=(Position); + Position& operator+=(double); + Position& operator-=(Position); + Position& operator-=(double); + Position& operator*=(Position); + Position& operator*=(double); + const double& operator[](int i) const { + switch (i) { + case 0: return x; + case 1: return y; + case 2: return z; + } + } + double& operator[](int i) { + switch (i) { + case 0: return x; + case 1: return y; + case 2: return z; + } + } + + // Other member functions + + //! Dot product of two vectors + //! \param[in] other Vector to take dot product with + //! \result Resulting dot product + inline double dot(Position other) { + return x*other.x + y*other.y + z*other.z; + } + + // Data members + double x = 0.; + double y = 0.; + double z = 0.; +}; + +// Binary operators +inline Position operator+(Position a, Position b) { return a += b; } +inline Position operator+(Position a, double b) { return a += b; } +inline Position operator+(double a, Position b) { return b += a; } + +inline Position operator-(Position a, Position b) { return a -= b; } +inline Position operator-(Position a, double b) { return a -= b; } +inline Position operator-(double a, Position b) { return b -= a; } + +inline Position operator*(Position a, Position b) { return a *= b; } +inline Position operator*(Position a, double b) { return a *= b; } +inline Position operator*(double a, Position b) { return b *= a; } + +//============================================================================== +//! Type representing a vector direction in Cartesian coordinates +//============================================================================== + +using Direction = Position; + +} // namespace openmc + +#endif // OPENMC_POSITION_H \ No newline at end of file diff --git a/src/surface.cpp b/src/surface.cpp index aec0972b8f..8258861526 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -178,7 +178,7 @@ Surface::Surface(pugi::xml_node surf_node) } bool -Surface::sense(Position r, Angle a) const +Surface::sense(Position r, Direction u) const { // Evaluate the surface equation at the particle's coordinates to determine // which side the particle is on. @@ -189,22 +189,22 @@ Surface::sense(Position r, Angle a) const // Particle may be coincident with this surface. To determine the sense, we // look at the direction of the particle relative to the surface normal (by // default in the positive direction) via their dot product. - return a.dot(normal(r)) > 0.0; + return u.dot(normal(r)) > 0.0; } return f > 0.0; } -Angle -Surface::reflect(Position r, Angle a) const +Direction +Surface::reflect(Position r, Direction u) const { // Determine projection of direction onto normal and squared magnitude of // normal. - Angle n = normal(r); - const double projection = n.dot(a); + Direction n = normal(r); + const double projection = n.dot(u); const double magnitude = n.dot(n); // Reflect direction according to normal. - return a -= (2.0 * projection / magnitude) * n; + return u -= (2.0 * projection / magnitude) * n; } void @@ -257,11 +257,11 @@ PeriodicSurface::PeriodicSurface(pugi::xml_node surf_node) // The template parameter indicates the axis normal to the plane. template double -axis_aligned_plane_distance(Position r, Angle a, bool coincident, double offset) +axis_aligned_plane_distance(Position r, Direction u, bool coincident, double offset) { const double f = offset - r[i]; - if (coincident or std::abs(f) < FP_COINCIDENT or a[i] == 0.0) return INFTY; - const double d = f / a[i]; + if (coincident or std::abs(f) < FP_COINCIDENT or u[i] == 0.0) return INFTY; + const double d = f / u[i]; if (d < 0.0) return INFTY; return d; } @@ -281,12 +281,12 @@ double SurfaceXPlane::evaluate(Position r) const return r.x - x0; } -double SurfaceXPlane::distance(Position r, Angle a, bool coincident) const +double SurfaceXPlane::distance(Position r, Direction u, bool coincident) const { - return axis_aligned_plane_distance<0>(r, a, coincident, x0); + return axis_aligned_plane_distance<0>(r, u, coincident, x0); } -Angle SurfaceXPlane::normal(Position r) const +Direction SurfaceXPlane::normal(Position r) const { return {1., 0., 0.}; } @@ -299,23 +299,23 @@ void SurfaceXPlane::to_hdf5_inner(hid_t group_id) const } bool SurfaceXPlane::periodic_translate(const PeriodicSurface *other, Position& r, - Angle& a) const + Direction& u) const { - Angle other_n = other->normal(r); - if (other_n.u() == 1 and other_n.v() == 0 and other_n.w() == 0) { + Direction other_n = other->normal(r); + if (other_n.x == 1 and other_n.y == 0 and other_n.z == 0) { r.x = x0; return false; } else { // Assume the partner is an YPlane (the only supported partner). Use the - // evaluate function to find y0, then adjust position/angle for rotational + // evaluate function to find y0, then adjust position/Direction for rotational // symmetry. double y0 = -other->evaluate({0., 0., 0.}); r.y = r.x - x0 + y0; r.x = x0; - double u = a.u(); - a.u() = -a.v(); - a.v() = u; + double ux = u.x; + u.x = -u.y; + u.y = ux; return true; } @@ -342,12 +342,12 @@ double SurfaceYPlane::evaluate(Position r) const return r.y - y0; } -double SurfaceYPlane::distance(Position r, Angle a, bool coincident) const +double SurfaceYPlane::distance(Position r, Direction u, bool coincident) const { - return axis_aligned_plane_distance<1>(r, a, coincident, y0); + return axis_aligned_plane_distance<1>(r, u, coincident, y0); } -Angle SurfaceYPlane::normal(Position r) const +Direction SurfaceYPlane::normal(Position r) const { return {0., 1., 0.}; } @@ -360,24 +360,24 @@ void SurfaceYPlane::to_hdf5_inner(hid_t group_id) const } bool SurfaceYPlane::periodic_translate(const PeriodicSurface *other, Position& r, - Angle& a) const + Direction& u) const { - Angle other_n = other->normal(r); - if (other_n.u() == 0 and other_n.v() == 1 and other_n.w() == 0) { + Direction other_n = other->normal(r); + if (other_n.x == 0 and other_n.y == 1 and other_n.z == 0) { // The periodic partner is also aligned along y. Just change the y coord. r.y = y0; return false; } else { // Assume the partner is an XPlane (the only supported partner). Use the - // evaluate function to find x0, then adjust position/angle for rotational + // evaluate function to find x0, then adjust position/Direction for rotational // symmetry. double x0 = -other->evaluate({0., 0., 0.}); r.x = r.y - y0 + x0; r.y = y0; - double u = a.u(); - a.u() = a.v(); - a.v() = -u; + double ux = u.x; + u.x = u.y; + u.y = -ux; return true; } @@ -404,12 +404,12 @@ double SurfaceZPlane::evaluate(Position r) const return r.z - z0; } -double SurfaceZPlane::distance(Position r, Angle a, bool coincident) const +double SurfaceZPlane::distance(Position r, Direction u, bool coincident) const { - return axis_aligned_plane_distance<2>(r, a, coincident, z0); + return axis_aligned_plane_distance<2>(r, u, coincident, z0); } -Angle SurfaceZPlane::normal(Position r) const +Direction SurfaceZPlane::normal(Position r) const { return {0., 0., 1.}; } @@ -422,7 +422,7 @@ void SurfaceZPlane::to_hdf5_inner(hid_t group_id) const } bool SurfaceZPlane::periodic_translate(const PeriodicSurface *other, Position& r, - Angle& a) const + Direction& u) const { // Assume the other plane is aligned along z. Just change the z coord. r.z = z0; @@ -452,10 +452,10 @@ SurfacePlane::evaluate(Position r) const } double -SurfacePlane::distance(Position r, Angle a, bool coincident) const +SurfacePlane::distance(Position r, Direction u, bool coincident) const { const double f = A*r.x + B*r.y + C*r.z - D; - const double projection = A*a.u() + B*a.v() + C*a.w(); + const double projection = A*u.x + B*u.y + C*u.z; if (coincident or std::abs(f) < FP_COINCIDENT or projection == 0.0) { return INFTY; } else { @@ -465,7 +465,7 @@ SurfacePlane::distance(Position r, Angle a, bool coincident) const } } -Angle +Direction SurfacePlane::normal(Position r) const { return {A, B, C}; @@ -479,7 +479,7 @@ void SurfacePlane::to_hdf5_inner(hid_t group_id) const } bool SurfacePlane::periodic_translate(const PeriodicSurface *other, Position& r, - Angle& a) const + Direction& u) const { // This function assumes the other plane shares this plane's normal direction. @@ -520,7 +520,7 @@ axis_aligned_cylinder_evaluate(Position r, double offset1, // The other two parameters indicate the other two axes. offset1 and offset2 // should correspond with i2 and i3, respectively. template double -axis_aligned_cylinder_distance(Position r, Angle u, +axis_aligned_cylinder_distance(Position r, Direction u, bool coincident, double offset1, double offset2, double radius) { const double a = 1.0 - u[i1]*u[i1]; // u^2 + v^2 @@ -565,14 +565,14 @@ axis_aligned_cylinder_distance(Position r, Angle u, // The first template parameter indicates which axis the cylinder is aligned to. // The other two parameters indicate the other two axes. offset1 and offset2 // should correspond with i2 and i3, respectively. -template Angle +template Direction axis_aligned_cylinder_normal(Position r, double offset1, double offset2) { - Angle a; - a[i2] = 2.0 * (r[i2] - offset1); - a[i3] = 2.0 * (r[i3] - offset2); - a[i1] = 0.0; - return a; + Direction u; + u[i2] = 2.0 * (r[i2] - offset1); + u[i3] = 2.0 * (r[i3] - offset2); + u[i1] = 0.0; + return u; } //============================================================================== @@ -590,13 +590,13 @@ double SurfaceXCylinder::evaluate(Position r) const return axis_aligned_cylinder_evaluate<1, 2>(r, y0, z0, this->r); } -double SurfaceXCylinder::distance(Position r, Angle a, bool coincident) const +double SurfaceXCylinder::distance(Position r, Direction u, bool coincident) const { - return axis_aligned_cylinder_distance<0, 1, 2>(r, a, coincident, y0, z0, + return axis_aligned_cylinder_distance<0, 1, 2>(r, u, coincident, y0, z0, this->r); } -Angle SurfaceXCylinder::normal(Position r) const +Direction SurfaceXCylinder::normal(Position r) const { return axis_aligned_cylinder_normal<0, 1, 2>(r, y0, z0); } @@ -624,13 +624,13 @@ double SurfaceYCylinder::evaluate(Position r) const return axis_aligned_cylinder_evaluate<0, 2>(r, x0, z0, this->r); } -double SurfaceYCylinder::distance(Position r, Angle a, bool coincident) const +double SurfaceYCylinder::distance(Position r, Direction u, bool coincident) const { - return axis_aligned_cylinder_distance<1, 0, 2>(r, a, coincident, x0, z0, + return axis_aligned_cylinder_distance<1, 0, 2>(r, u, coincident, x0, z0, this->r); } -Angle SurfaceYCylinder::normal(Position r) const +Direction SurfaceYCylinder::normal(Position r) const { return axis_aligned_cylinder_normal<1, 0, 2>(r, x0, z0); } @@ -657,13 +657,13 @@ double SurfaceZCylinder::evaluate(Position r) const return axis_aligned_cylinder_evaluate<0, 1>(r, x0, y0, this->r); } -double SurfaceZCylinder::distance(Position r, Angle a, bool coincident) const +double SurfaceZCylinder::distance(Position r, Direction u, bool coincident) const { - return axis_aligned_cylinder_distance<2, 0, 1>(r, a, coincident, x0, y0, + return axis_aligned_cylinder_distance<2, 0, 1>(r, u, coincident, x0, y0, this->r); } -Angle SurfaceZCylinder::normal(Position r) const +Direction SurfaceZCylinder::normal(Position r) const { return axis_aligned_cylinder_normal<2, 0, 1>(r, x0, y0); } @@ -693,12 +693,12 @@ double SurfaceSphere::evaluate(Position r) const return x*x + y*y + z*z - this->r*this->r; } -double SurfaceSphere::distance(Position r, Angle a, bool coincident) const +double SurfaceSphere::distance(Position r, Direction u, bool coincident) const { const double x = r.x - x0; const double y = r.y - y0; const double z = r.z - z0; - const double k = x*a.u() + y*a.v() + z*a.w(); + const double k = x*u.x + y*u.y + z*u.z; const double c = x*x + y*y + z*z - this->r*this->r; const double quad = k*k - c; @@ -731,7 +731,7 @@ double SurfaceSphere::distance(Position r, Angle a, bool coincident) const } } -Angle SurfaceSphere::normal(Position r) const +Direction SurfaceSphere::normal(Position r) const { return {2.0*(r.x - x0), 2.0*(r.y - y0), 2.0*(r.z - z0)}; } @@ -764,7 +764,7 @@ axis_aligned_cone_evaluate(Position r, double offset1, // The other two parameters indicate the other two axes. offset1, offset2, // and offset3 should correspond with i1, i2, and i3, respectively. template double -axis_aligned_cone_distance(Position r, Angle u, +axis_aligned_cone_distance(Position r, Direction u, bool coincident, double offset1, double offset2, double offset3, double radius_sq) { @@ -817,15 +817,15 @@ axis_aligned_cone_distance(Position r, Angle u, // The first template parameter indicates which axis the cone is aligned to. // The other two parameters indicate the other two axes. offset1, offset2, // and offset3 should correspond with i1, i2, and i3, respectively. -template Angle +template Direction axis_aligned_cone_normal(Position r, double offset1, double offset2, double offset3, double radius_sq) { - Angle a; - a[i1] = -2.0 * radius_sq * (r[i1] - offset1); - a[i2] = 2.0 * (r[i2] - offset2); - a[i3] = 2.0 * (r[i3] - offset3); - return a; + Direction u; + u[i1] = -2.0 * radius_sq * (r[i1] - offset1); + u[i2] = 2.0 * (r[i2] - offset2); + u[i3] = 2.0 * (r[i3] - offset3); + return u; } //============================================================================== @@ -843,13 +843,13 @@ double SurfaceXCone::evaluate(Position r) const return axis_aligned_cone_evaluate<0, 1, 2>(r, x0, y0, z0, r_sq); } -double SurfaceXCone::distance(Position r, Angle a, bool coincident) const +double SurfaceXCone::distance(Position r, Direction u, bool coincident) const { - return axis_aligned_cone_distance<0, 1, 2>(r, a, coincident, x0, y0, z0, + return axis_aligned_cone_distance<0, 1, 2>(r, u, coincident, x0, y0, z0, r_sq); } -Angle SurfaceXCone::normal(Position r) const +Direction SurfaceXCone::normal(Position r) const { return axis_aligned_cone_normal<0, 1, 2>(r, x0, y0, z0, r_sq); } @@ -876,13 +876,13 @@ double SurfaceYCone::evaluate(Position r) const return axis_aligned_cone_evaluate<1, 0, 2>(r, y0, x0, z0, r_sq); } -double SurfaceYCone::distance(Position r, Angle a, bool coincident) const +double SurfaceYCone::distance(Position r, Direction u, bool coincident) const { - return axis_aligned_cone_distance<1, 0, 2>(r, a, coincident, y0, x0, z0, + return axis_aligned_cone_distance<1, 0, 2>(r, u, coincident, y0, x0, z0, r_sq); } -Angle SurfaceYCone::normal(Position r) const +Direction SurfaceYCone::normal(Position r) const { return axis_aligned_cone_normal<1, 0, 2>(r, y0, x0, z0, r_sq); } @@ -909,13 +909,13 @@ double SurfaceZCone::evaluate(Position r) const return axis_aligned_cone_evaluate<2, 0, 1>(r, z0, x0, y0, r_sq); } -double SurfaceZCone::distance(Position r, Angle a, bool coincident) const +double SurfaceZCone::distance(Position r, Direction u, bool coincident) const { - return axis_aligned_cone_distance<2, 0, 1>(r, a, coincident, z0, x0, y0, + return axis_aligned_cone_distance<2, 0, 1>(r, u, coincident, z0, x0, y0, r_sq); } -Angle SurfaceZCone::normal(Position r) const +Direction SurfaceZCone::normal(Position r) const { return axis_aligned_cone_normal<2, 0, 1>(r, z0, x0, y0, r_sq); } @@ -949,14 +949,14 @@ SurfaceQuadric::evaluate(Position r) const } double -SurfaceQuadric::distance(Position r, Angle ang, bool coincident) const +SurfaceQuadric::distance(Position r, Direction ang, bool coincident) const { const double &x = r.x; const double &y = r.y; const double &z = r.z; - const double &u = ang.u(); - const double &v = ang.v(); - const double &w = ang.w(); + const double &u = ang.x; + const double &v = ang.y; + const double &w = ang.z; const double a = A*u*u + B*v*v + C*w*w + D*u*v + E*v*w + F*u*w; const double k = (A*u*x + B*v*y + C*w*z + 0.5*(D*(u*y + v*x) + @@ -1002,7 +1002,7 @@ SurfaceQuadric::distance(Position r, Angle ang, bool coincident) const return d; } -Angle +Direction SurfaceQuadric::normal(Position r) const { const double &x = r.x; @@ -1222,21 +1222,21 @@ extern "C" { void surface_reflect(Surface *surf, double xyz[3], double uvw[3]) { Position r {xyz}; - Angle a {uvw}; - a = surf->reflect(r, a); + Direction u {uvw}; + u = surf->reflect(r, u); - uvw[0] = a.u(); - uvw[1] = a.v(); - uvw[2] = a.w(); + uvw[0] = u.x; + uvw[1] = u.y; + uvw[2] = u.z; } void surface_normal(Surface *surf, double xyz[3], double uvw[3]) { Position r {xyz}; - Angle a = surf->normal(r); - uvw[0] = a.u(); - uvw[1] = a.v(); - uvw[2] = a.w(); + Direction u = surf->normal(r); + uvw[0] = u.x; + uvw[1] = u.y; + uvw[2] = u.z; } void surface_to_hdf5(Surface *surf, hid_t group) {surf->to_hdf5(group);} @@ -1248,16 +1248,16 @@ extern "C" { double uvw[3]) { Position r {xyz}; - Angle a {uvw}; - bool rotational = surf->periodic_translate(other, r, a); + Direction u {uvw}; + bool rotational = surf->periodic_translate(other, r, u); // Copy back to arrays xyz[0] = r.x; xyz[1] = r.y; xyz[2] = r.z; - uvw[0] = a.u(); - uvw[1] = a.v(); - uvw[2] = a.w(); + uvw[0] = u.x; + uvw[1] = u.y; + uvw[2] = u.z; return rotational; } diff --git a/src/surface.h b/src/surface.h index be3ad52ab9..7d639c57a8 100644 --- a/src/surface.h +++ b/src/surface.h @@ -9,7 +9,7 @@ #include "pugixml.hpp" #include "constants.h" -#include "geometry.h" +#include "position.h" namespace openmc { @@ -71,14 +71,14 @@ public: //! point is very close to the surface. //! @return true if the point is on the "positive" side of the surface and //! false otherwise. - bool sense(Position r, Angle a) const; + bool sense(Position r, Direction u) const; //! Determine the direction of a ray reflected from the surface. //! @param r The point at which the ray is incident. //! @param o A direction. This is both an input and an output parameter. //! It specifies the icident direction on input and the reflected direction //! on output. - Angle reflect(Position r, Angle a) const; + Direction reflect(Position r, Direction u) const; //! Evaluate the equation describing the surface. //! @@ -92,12 +92,12 @@ public: //! @param o The direction of the ray. //! @param coincident A hint to the code that the given point should lie //! exactly on the surface. - virtual double distance(Position r, Angle a, bool coincident) const = 0; + virtual double distance(Position r, Direction u, bool coincident) const = 0; //! Compute the local outward normal direction of the surface. //! @param r A 3D Cartesian coordinate. //! @return Normal direction - virtual Angle normal(Position r) const = 0; + virtual Direction normal(Position r) const = 0; //! Write all information needed to reconstruct the surface to an HDF5 group. //! @param group_id An HDF5 group id. @@ -132,7 +132,7 @@ public: //! @return true if this surface and its partner make a rotationally-periodic //! boundary condition. virtual bool periodic_translate(const PeriodicSurface *other, Position& r, - Angle& a) const = 0; + Direction& u) const = 0; //! Get the bounding box for this surface. virtual BoundingBox bounding_box() const = 0; @@ -150,10 +150,10 @@ class SurfaceXPlane : public PeriodicSurface public: explicit SurfaceXPlane(pugi::xml_node surf_node); double evaluate(Position r) const; - double distance(Position r, Angle a, bool coincident) const; - Angle normal(Position r) const; + double distance(Position r, Direction u, bool coincident) const; + Direction normal(Position r) const; void to_hdf5_inner(hid_t group_id) const; - bool periodic_translate(const PeriodicSurface *other, Position& r, Angle& a) + bool periodic_translate(const PeriodicSurface *other, Position& r, Direction& u) const; BoundingBox bounding_box() const; }; @@ -170,10 +170,10 @@ class SurfaceYPlane : public PeriodicSurface public: explicit SurfaceYPlane(pugi::xml_node surf_node); double evaluate(Position r) const; - double distance(Position r, Angle a, bool coincident) const; - Angle normal(Position r) const; + double distance(Position r, Direction u, bool coincident) const; + Direction normal(Position r) const; void to_hdf5_inner(hid_t group_id) const; - bool periodic_translate(const PeriodicSurface *other, Position& r, Angle& a) + bool periodic_translate(const PeriodicSurface *other, Position& r, Direction& u) const; BoundingBox bounding_box() const; }; @@ -190,10 +190,10 @@ class SurfaceZPlane : public PeriodicSurface public: explicit SurfaceZPlane(pugi::xml_node surf_node); double evaluate(Position r) const; - double distance(Position r, Angle a, bool coincident) const; - Angle normal(Position r) const; + double distance(Position r, Direction u, bool coincident) const; + Direction normal(Position r) const; void to_hdf5_inner(hid_t group_id) const; - bool periodic_translate(const PeriodicSurface *other, Position& r, Angle& a) + bool periodic_translate(const PeriodicSurface *other, Position& r, Direction& u) const; BoundingBox bounding_box() const; }; @@ -210,10 +210,10 @@ class SurfacePlane : public PeriodicSurface public: explicit SurfacePlane(pugi::xml_node surf_node); double evaluate(Position r) const; - double distance(Position r, Angle a, bool coincident) const; - Angle normal(Position r) const; + double distance(Position r, Direction u, bool coincident) const; + Direction normal(Position r) const; void to_hdf5_inner(hid_t group_id) const; - bool periodic_translate(const PeriodicSurface *other, Position& r, Angle& a) + bool periodic_translate(const PeriodicSurface *other, Position& r, Direction& u) const; BoundingBox bounding_box() const; }; @@ -231,8 +231,8 @@ class SurfaceXCylinder : public Surface public: explicit SurfaceXCylinder(pugi::xml_node surf_node); double evaluate(Position r) const; - double distance(Position r, Angle a, bool coincident) const; - Angle normal(Position r) const; + double distance(Position r, Direction u, bool coincident) const; + Direction normal(Position r) const; void to_hdf5_inner(hid_t group_id) const; }; @@ -249,8 +249,8 @@ class SurfaceYCylinder : public Surface public: explicit SurfaceYCylinder(pugi::xml_node surf_node); double evaluate(Position r) const; - double distance(Position r, Angle a, bool coincident) const; - Angle normal(Position r) const; + double distance(Position r, Direction u, bool coincident) const; + Direction normal(Position r) const; void to_hdf5_inner(hid_t group_id) const; }; @@ -267,8 +267,8 @@ class SurfaceZCylinder : public Surface public: explicit SurfaceZCylinder(pugi::xml_node surf_node); double evaluate(Position r) const; - double distance(Position r, Angle a, bool coincident) const; - Angle normal(Position r) const; + double distance(Position r, Direction u, bool coincident) const; + Direction normal(Position r) const; void to_hdf5_inner(hid_t group_id) const; }; @@ -285,8 +285,8 @@ class SurfaceSphere : public Surface public: explicit SurfaceSphere(pugi::xml_node surf_node); double evaluate(Position r) const; - double distance(Position r, Angle a, bool coincident) const; - Angle normal(Position r) const; + double distance(Position r, Direction u, bool coincident) const; + Direction normal(Position r) const; void to_hdf5_inner(hid_t group_id) const; }; @@ -303,8 +303,8 @@ class SurfaceXCone : public Surface public: explicit SurfaceXCone(pugi::xml_node surf_node); double evaluate(Position r) const; - double distance(Position r, Angle a, bool coincident) const; - Angle normal(Position r) const; + double distance(Position r, Direction u, bool coincident) const; + Direction normal(Position r) const; void to_hdf5_inner(hid_t group_id) const; }; @@ -321,8 +321,8 @@ class SurfaceYCone : public Surface public: explicit SurfaceYCone(pugi::xml_node surf_node); double evaluate(Position r) const; - double distance(Position r, Angle a, bool coincident) const; - Angle normal(Position r) const; + double distance(Position r, Direction u, bool coincident) const; + Direction normal(Position r) const; void to_hdf5_inner(hid_t group_id) const; }; @@ -339,8 +339,8 @@ class SurfaceZCone : public Surface public: explicit SurfaceZCone(pugi::xml_node surf_node); double evaluate(Position r) const; - double distance(Position r, Angle a, bool coincident) const; - Angle normal(Position r) const; + double distance(Position r, Direction u, bool coincident) const; + Direction normal(Position r) const; void to_hdf5_inner(hid_t group_id) const; }; @@ -357,8 +357,8 @@ class SurfaceQuadric : public Surface public: explicit SurfaceQuadric(pugi::xml_node surf_node); double evaluate(Position r) const; - double distance(Position r, Angle a, bool coincident) const; - Angle normal(Position r) const; + double distance(Position r, Direction u, bool coincident) const; + Direction normal(Position r) const; void to_hdf5_inner(hid_t group_id) const; }; @@ -367,19 +367,19 @@ public: //============================================================================== extern "C" { - Surface* surface_pointer(int surf_ind); - int surface_id(Surface *surf); - int surface_bc(Surface *surf); - bool surface_sense(Surface *surf, double xyz[3], double uvw[3]); - void surface_reflect(Surface *surf, double xyz[3], double uvw[3]); - double surface_distance(Surface *surf, double xyz[3], double uvw[3], - bool coincident); - void surface_normal(Surface *surf, double xyz[3], double uvw[3]); - void surface_to_hdf5(Surface *surf, hid_t group); - int surface_i_periodic(PeriodicSurface *surf); - bool surface_periodic(PeriodicSurface *surf, PeriodicSurface *other, - double xyz[3], double uvw[3]); - void free_memory_surfaces_c(); + Surface* surface_pointer(int surf_ind); + int surface_id(Surface *surf); + int surface_bc(Surface *surf); + bool surface_sense(Surface *surf, double xyz[3], double uvw[3]); + void surface_reflect(Surface *surf, double xyz[3], double uvw[3]); + double surface_distance(Surface *surf, double xyz[3], double uvw[3], + bool coincident); + void surface_normal(Surface *surf, double xyz[3], double uvw[3]); + void surface_to_hdf5(Surface *surf, hid_t group); + int surface_i_periodic(PeriodicSurface *surf); + bool surface_periodic(PeriodicSurface *surf, PeriodicSurface *other, + double xyz[3], double uvw[3]); + void free_memory_surfaces_c(); } } // namespace openmc From c72ff04afb79219f172c082409e936511eb7d4d0 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 8 Aug 2018 13:46:53 -0500 Subject: [PATCH 038/109] Make write_dataset for Position an overload (not specialization) --- src/hdf5_interface.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hdf5_interface.h b/src/hdf5_interface.h index b0466e613d..6faba4078f 100644 --- a/src/hdf5_interface.h +++ b/src/hdf5_interface.h @@ -183,8 +183,8 @@ write_dataset(hid_t obj_id, const char* name, const std::array& buffer) write_dataset(obj_id, 1, dims, name, H5TypeMap::type_id, buffer.data(), false); } -template<> inline void -write_dataset(hid_t obj_id, const char* name, Position r) +inline void +write_dataset(hid_t obj_id, const char* name, Position r) { std::array buffer {r.x, r.y, r.z}; write_dataset(obj_id, name, buffer); From 134ad969d832525beff391b4f54214b6d3c0d0f1 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 8 Aug 2018 13:54:33 -0500 Subject: [PATCH 039/109] Fix some comments, include guards --- src/cell.h | 14 +++++++------- src/hdf5_interface.h | 6 +++--- src/lattice.h | 44 ++++++++++++++++++++++---------------------- src/surface.h | 38 +++++++++++++++++++------------------- 4 files changed, 51 insertions(+), 51 deletions(-) diff --git a/src/cell.h b/src/cell.h index 10265beb1b..062251b48c 100644 --- a/src/cell.h +++ b/src/cell.h @@ -1,5 +1,5 @@ -#ifndef CELL_H -#define CELL_H +#ifndef OPENMC_CELL_H +#define OPENMC_CELL_H #include #include @@ -92,10 +92,10 @@ public: //! provides a performance benefit for the common case. In //! contains_complex, we evaluate the RPN expression using a stack, similar to //! how a RPN calculator would work. - //! @param xyz[3] The 3D Cartesian coordinate to check. - //! @param uvw[3] A direction used to "break ties" the coordinates are very + //! \param r The 3D Cartesian coordinate to check. + //! \param u A direction used to "break ties" the coordinates are very //! close to a surface. - //! @param on_surface The signed index of a surface that the coordinate is + //! \param on_surface The signed index of a surface that the coordinate is //! known to be on. This index takes precedence over surface sense //! calculations. bool @@ -106,7 +106,7 @@ public: distance(Position r, Direction u, int32_t on_surface) const; //! \brief Write cell information to an HDF5 group. - //! @param group_id An HDF5 group id. + //! \param group_id An HDF5 group id. void to_hdf5(hid_t group_id) const; protected: @@ -115,4 +115,4 @@ protected: }; } // namespace openmc -#endif // CELL_H +#endif // OPENMC_CELL_H diff --git a/src/hdf5_interface.h b/src/hdf5_interface.h index 6faba4078f..152c52c1cd 100644 --- a/src/hdf5_interface.h +++ b/src/hdf5_interface.h @@ -1,5 +1,5 @@ -#ifndef HDF5_INTERFACE_H -#define HDF5_INTERFACE_H +#ifndef OPENMC_HDF5_INTERFACE_H +#define OPENMC_HDF5_INTERFACE_H #include "hdf5.h" #include "hdf5_hl.h" @@ -191,4 +191,4 @@ write_dataset(hid_t obj_id, const char* name, Position r) } } // namespace openmc -#endif //HDF5_INTERFACE_H +#endif // OPENMC_HDF5_INTERFACE_H diff --git a/src/lattice.h b/src/lattice.h index 5bd15a6126..94d7b43878 100644 --- a/src/lattice.h +++ b/src/lattice.h @@ -1,5 +1,5 @@ -#ifndef LATTICE_H -#define LATTICE_H +#ifndef OPENMC_LATTICE_H +#define OPENMC_LATTICE_H #include #include @@ -71,54 +71,54 @@ public: int32_t fill_offset_table(int32_t offset, int32_t target_univ_id, int map); //! \brief Check lattice indices. - //! @param i_xyz[3] The indices for a lattice tile. - //! @return true if the given indices fit within the lattice bounds. False + //! \param i_xyz[3] The indices for a lattice tile. + //! \return true if the given indices fit within the lattice bounds. False //! otherwise. virtual bool are_valid_indices(const int i_xyz[3]) const = 0; //! \brief Find the next lattice surface crossing - //! @param r A 3D Cartesian coordinate. - //! @param a A 3D Cartesian direction. - //! @param i_xyz[3] The indices for a lattice tile. - //! @return The distance to the next crossing and an array indicating how the + //! \param r A 3D Cartesian coordinate. + //! \param u A 3D Cartesian direction. + //! \param i_xyz[3] The indices for a lattice tile. + //! \return The distance to the next crossing and an array indicating how the //! lattice indices would change after crossing that boundary. virtual std::pair> distance(Position r, Direction u, const int i_xyz[3]) const = 0; //! \brief Find the lattice tile indices for a given point. - //! @param r A 3D Cartesian coordinate. - //! @return An array containing the indices of a lattice tile. + //! \param r A 3D Cartesian coordinate. + //! \return An array containing the indices of a lattice tile. virtual std::array get_indices(Position r) const = 0; //! \brief Get coordinates local to a lattice tile. - //! @param r A 3D Cartesian coordinate. - //! @param i_xyz[3] The indices for a lattice tile. - //! @return Local 3D Cartesian coordinates. + //! \param r A 3D Cartesian coordinate. + //! \param i_xyz[3] The indices for a lattice tile. + //! \return Local 3D Cartesian coordinates. virtual Position get_local_position(Position r, const int i_xyz[3]) const = 0; //! \brief Check flattened lattice index. - //! @param indx The index for a lattice tile. - //! @return true if the given index fit within the lattice bounds. False + //! \param indx The index for a lattice tile. + //! \return true if the given index fit within the lattice bounds. False //! otherwise. virtual bool is_valid_index(int indx) const {return (indx >= 0) && (indx < universes.size());} //! \brief Get the distribcell offset for a lattice tile. - //! @param The map index for the target cell. - //! @param i_xyz[3] The indices for a lattice tile. - //! @return Distribcell offset i.e. the largest instance number for the target + //! \param The map index for the target cell. + //! \param i_xyz[3] The indices for a lattice tile. + //! \return Distribcell offset i.e. the largest instance number for the target //! cell found in the geometry tree under this lattice tile. virtual int32_t& offset(int map, const int i_xyz[3]) = 0; //! \brief Convert an array index to a useful human-readable string. - //! @param indx The index for a lattice tile. - //! @return A string representing the lattice tile. + //! \param indx The index for a lattice tile. + //! \return A string representing the lattice tile. virtual std::string index_to_string(int indx) const = 0; //! \brief Write lattice information to an HDF5 group. - //! @param group_id An HDF5 group id. + //! \param group_id An HDF5 group id. void to_hdf5(hid_t group_id) const; protected: @@ -258,4 +258,4 @@ private: }; } // namespace openmc -#endif // LATTICE_H +#endif // OPENMC_LATTICE_H diff --git a/src/surface.h b/src/surface.h index 7d639c57a8..b267af05ca 100644 --- a/src/surface.h +++ b/src/surface.h @@ -1,5 +1,5 @@ -#ifndef SURFACE_H -#define SURFACE_H +#ifndef OPENMC_SURFACE_H +#define OPENMC_SURFACE_H #include #include // For numeric_limits @@ -66,16 +66,16 @@ public: virtual ~Surface() {} //! Determine which side of a surface a point lies on. - //! @param r The 3D Cartesian coordinate of a point. - //! @param o A direction used to "break ties" and pick a sense when the + //! \param r The 3D Cartesian coordinate of a point. + //! \param u A direction used to "break ties" and pick a sense when the //! point is very close to the surface. - //! @return true if the point is on the "positive" side of the surface and + //! \return true if the point is on the "positive" side of the surface and //! false otherwise. bool sense(Position r, Direction u) const; //! Determine the direction of a ray reflected from the surface. - //! @param r The point at which the ray is incident. - //! @param o A direction. This is both an input and an output parameter. + //! \param r The point at which the ray is incident. + //! \param u A direction. This is both an input and an output parameter. //! It specifies the icident direction on input and the reflected direction //! on output. Direction reflect(Position r, Direction u) const; @@ -84,23 +84,23 @@ public: //! //! Surfaces can be described by some function f(x, y, z) = 0. This member //! function evaluates that mathematical function. - //! @param r A 3D Cartesian coordinate. + //! \param r A 3D Cartesian coordinate. virtual double evaluate(Position r) const = 0; //! Compute the distance between a point and the surface along a ray. - //! @param r A 3D Cartesian coordinate. - //! @param o The direction of the ray. - //! @param coincident A hint to the code that the given point should lie + //! \param r A 3D Cartesian coordinate. + //! \param u The direction of the ray. + //! \param coincident A hint to the code that the given point should lie //! exactly on the surface. virtual double distance(Position r, Direction u, bool coincident) const = 0; //! Compute the local outward normal direction of the surface. - //! @param r A 3D Cartesian coordinate. - //! @return Normal direction + //! \param r A 3D Cartesian coordinate. + //! \return Normal direction virtual Direction normal(Position r) const = 0; //! Write all information needed to reconstruct the surface to an HDF5 group. - //! @param group_id An HDF5 group id. + //! \param group_id An HDF5 group id. //TODO: this probably needs to include i_periodic for PeriodicSurface void to_hdf5(hid_t group_id) const; @@ -124,12 +124,12 @@ public: explicit PeriodicSurface(pugi::xml_node surf_node); //! Translate a particle onto this surface from a periodic partner surface. - //! @param other A pointer to the partner surface in this periodic BC. - //! @param r A point on the partner surface that will be translated onto + //! \param other A pointer to the partner surface in this periodic BC. + //! \param r A point on the partner surface that will be translated onto //! this surface. - //! @param a A direction that will be rotated for systems with rotational + //! \param u A direction that will be rotated for systems with rotational //! periodicity. - //! @return true if this surface and its partner make a rotationally-periodic + //! \return true if this surface and its partner make a rotationally-periodic //! boundary condition. virtual bool periodic_translate(const PeriodicSurface *other, Position& r, Direction& u) const = 0; @@ -383,4 +383,4 @@ extern "C" { } } // namespace openmc -#endif // SURFACE_H +#endif // OPENMC_SURFACE_H From 1bd1a1b855fccb26cecf7300032bcc4a5a90a092 Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Wed, 8 Aug 2018 14:52:09 -0500 Subject: [PATCH 040/109] Remove some redundancy --- src/tallies/tally_filter_zernike.F90 | 39 ++++++++++++++++------------ 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/src/tallies/tally_filter_zernike.F90 b/src/tallies/tally_filter_zernike.F90 index 1ece62dbb2..96e016d2ee 100644 --- a/src/tallies/tally_filter_zernike.F90 +++ b/src/tallies/tally_filter_zernike.F90 @@ -13,6 +13,10 @@ module tally_filter_zernike implicit none private + public :: openmc_zernike_filter_get_order + public :: openmc_zernike_filter_get_params + public :: openmc_zernike_filter_set_order + public :: openmc_zernike_filter_set_params !=============================================================================== ! ZERNIKEFILTER gives Zernike polynomial moments of a particle's position @@ -24,6 +28,7 @@ module tally_filter_zernike real(8) :: y real(8) :: r contains + procedure :: calc_n_bins => calc_n_bins_zn procedure :: from_xml => from_xml_zn procedure :: get_all_bins => get_all_bins_zn procedure :: to_statepoint => to_statepoint_zn @@ -37,7 +42,8 @@ module tally_filter_zernike type, public, extends(ZernikeFilter) :: ZernikeRadialFilter contains - procedure :: from_xml => from_xml_zn_rad + procedure :: calc_n_bins => calc_n_bins_zn_rad + ! Inherit from_xml from ZernikeFilter procedure :: get_all_bins => get_all_bins_zn_rad procedure :: to_statepoint => to_statepoint_zn_rad procedure :: text_label => text_label_zn_rad @@ -49,6 +55,15 @@ contains ! ZernikeFilter methods !=============================================================================== + function calc_n_bins_zn(this) result(num_n_bins) + class(ZernikeFilter), intent(in) :: this + integer :: n + integer :: num_n_bins + + n = this % order + num_n_bins = ((n+1) * (n+2))/2 + end function calc_n_bins_zn + subroutine from_xml_zn(this, node) class(ZernikeFilter), intent(inout) :: this type(XMLNode), intent(in) :: node @@ -63,7 +78,7 @@ contains ! Get specified order call get_node_value(node, "order", n) this % order = n - this % n_bins = ((n + 1)*(n + 2))/2 + this % n_bins = this % calc_n_bins() end subroutine from_xml_zn subroutine get_all_bins_zn(this, p, estimator, match) @@ -129,22 +144,14 @@ contains ! ZernikeRadialFilter methods !=============================================================================== - subroutine from_xml_zn_rad(this, node) - class(ZernikeRadialFilter), intent(inout) :: this - type(XMLNode), intent(in) :: node - + function calc_n_bins_zn_rad(this) result(num_n_bins) + class(ZernikeRadialFilter), intent(in) :: this integer :: n + integer :: num_n_bins - ! Get center of cylinder and radius - call get_node_value(node, "x", this % x) - call get_node_value(node, "y", this % y) - call get_node_value(node, "r", this % r) - - ! Get specified order - call get_node_value(node, "order", n) - this % order = n - this % n_bins = n/2 + 1 - end subroutine from_xml_zn_rad + n = this % order + num_n_bins = n/2 + 1 + end function calc_n_bins_zn_rad subroutine get_all_bins_zn_rad(this, p, estimator, match) class(ZernikeRadialFilter), intent(in) :: this From 98916c301725973f7c4f3a06b9cb87d1598572a4 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 8 Aug 2018 17:24:26 -0500 Subject: [PATCH 041/109] Change r -> radius in cylinder/sphere/cone types --- src/surface.cpp | 62 ++++++++++++++++++++++++------------------------- src/surface.h | 21 ++++++++--------- 2 files changed, 41 insertions(+), 42 deletions(-) diff --git a/src/surface.cpp b/src/surface.cpp index 8258861526..94c24c82db 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -582,18 +582,18 @@ axis_aligned_cylinder_normal(Position r, double offset1, double offset2) SurfaceXCylinder::SurfaceXCylinder(pugi::xml_node surf_node) : Surface(surf_node) { - read_coeffs(surf_node, id, y0, z0, r); + read_coeffs(surf_node, id, y0, z0, radius); } double SurfaceXCylinder::evaluate(Position r) const { - return axis_aligned_cylinder_evaluate<1, 2>(r, y0, z0, this->r); + return axis_aligned_cylinder_evaluate<1, 2>(r, y0, z0, radius); } double SurfaceXCylinder::distance(Position r, Direction u, bool coincident) const { return axis_aligned_cylinder_distance<0, 1, 2>(r, u, coincident, y0, z0, - this->r); + radius); } Direction SurfaceXCylinder::normal(Position r) const @@ -605,7 +605,7 @@ Direction SurfaceXCylinder::normal(Position r) const void SurfaceXCylinder::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "x-cylinder", false); - std::array coeffs {{y0, z0, r}}; + std::array coeffs {{y0, z0, radius}}; write_dataset(group_id, "coefficients", coeffs); } @@ -616,18 +616,18 @@ void SurfaceXCylinder::to_hdf5_inner(hid_t group_id) const SurfaceYCylinder::SurfaceYCylinder(pugi::xml_node surf_node) : Surface(surf_node) { - read_coeffs(surf_node, id, x0, z0, r); + read_coeffs(surf_node, id, x0, z0, radius); } double SurfaceYCylinder::evaluate(Position r) const { - return axis_aligned_cylinder_evaluate<0, 2>(r, x0, z0, this->r); + return axis_aligned_cylinder_evaluate<0, 2>(r, x0, z0, radius); } double SurfaceYCylinder::distance(Position r, Direction u, bool coincident) const { return axis_aligned_cylinder_distance<1, 0, 2>(r, u, coincident, x0, z0, - this->r); + radius); } Direction SurfaceYCylinder::normal(Position r) const @@ -638,7 +638,7 @@ Direction SurfaceYCylinder::normal(Position r) const void SurfaceYCylinder::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "y-cylinder", false); - std::array coeffs {{x0, z0, r}}; + std::array coeffs {{x0, z0, radius}}; write_dataset(group_id, "coefficients", coeffs); } @@ -649,18 +649,18 @@ void SurfaceYCylinder::to_hdf5_inner(hid_t group_id) const SurfaceZCylinder::SurfaceZCylinder(pugi::xml_node surf_node) : Surface(surf_node) { - read_coeffs(surf_node, id, x0, y0, r); + read_coeffs(surf_node, id, x0, y0, radius); } double SurfaceZCylinder::evaluate(Position r) const { - return axis_aligned_cylinder_evaluate<0, 1>(r, x0, y0, this->r); + return axis_aligned_cylinder_evaluate<0, 1>(r, x0, y0, radius); } double SurfaceZCylinder::distance(Position r, Direction u, bool coincident) const { return axis_aligned_cylinder_distance<2, 0, 1>(r, u, coincident, x0, y0, - this->r); + radius); } Direction SurfaceZCylinder::normal(Position r) const @@ -671,7 +671,7 @@ Direction SurfaceZCylinder::normal(Position r) const void SurfaceZCylinder::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "z-cylinder", false); - std::array coeffs {{x0, y0, r}}; + std::array coeffs {{x0, y0, radius}}; write_dataset(group_id, "coefficients", coeffs); } @@ -682,7 +682,7 @@ void SurfaceZCylinder::to_hdf5_inner(hid_t group_id) const SurfaceSphere::SurfaceSphere(pugi::xml_node surf_node) : Surface(surf_node) { - read_coeffs(surf_node, id, x0, y0, z0, r); + read_coeffs(surf_node, id, x0, y0, z0, radius); } double SurfaceSphere::evaluate(Position r) const @@ -690,7 +690,7 @@ double SurfaceSphere::evaluate(Position r) const const double x = r.x - x0; const double y = r.y - y0; const double z = r.z - z0; - return x*x + y*y + z*z - this->r*this->r; + return x*x + y*y + z*z - radius*radius; } double SurfaceSphere::distance(Position r, Direction u, bool coincident) const @@ -699,7 +699,7 @@ double SurfaceSphere::distance(Position r, Direction u, bool coincident) const const double y = r.y - y0; const double z = r.z - z0; const double k = x*u.x + y*u.y + z*u.z; - const double c = x*x + y*y + z*z - this->r*this->r; + const double c = x*x + y*y + z*z - radius*radius; const double quad = k*k - c; if (quad < 0.0) { @@ -739,7 +739,7 @@ Direction SurfaceSphere::normal(Position r) const void SurfaceSphere::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "sphere", false); - std::array coeffs {{x0, y0, z0, r}}; + std::array coeffs {{x0, y0, z0, radius}}; write_dataset(group_id, "coefficients", coeffs); } @@ -835,29 +835,29 @@ axis_aligned_cone_normal(Position r, double offset1, double offset2, SurfaceXCone::SurfaceXCone(pugi::xml_node surf_node) : Surface(surf_node) { - read_coeffs(surf_node, id, x0, y0, z0, r_sq); + read_coeffs(surf_node, id, x0, y0, z0, radius_sq); } double SurfaceXCone::evaluate(Position r) const { - return axis_aligned_cone_evaluate<0, 1, 2>(r, x0, y0, z0, r_sq); + return axis_aligned_cone_evaluate<0, 1, 2>(r, x0, y0, z0, radius_sq); } double SurfaceXCone::distance(Position r, Direction u, bool coincident) const { return axis_aligned_cone_distance<0, 1, 2>(r, u, coincident, x0, y0, z0, - r_sq); + radius_sq); } Direction SurfaceXCone::normal(Position r) const { - return axis_aligned_cone_normal<0, 1, 2>(r, x0, y0, z0, r_sq); + return axis_aligned_cone_normal<0, 1, 2>(r, x0, y0, z0, radius_sq); } void SurfaceXCone::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "x-cone", false); - std::array coeffs {{x0, y0, z0, r_sq}}; + std::array coeffs {{x0, y0, z0, radius_sq}}; write_dataset(group_id, "coefficients", coeffs); } @@ -868,29 +868,29 @@ void SurfaceXCone::to_hdf5_inner(hid_t group_id) const SurfaceYCone::SurfaceYCone(pugi::xml_node surf_node) : Surface(surf_node) { - read_coeffs(surf_node, id, x0, y0, z0, r_sq); + read_coeffs(surf_node, id, x0, y0, z0, radius_sq); } double SurfaceYCone::evaluate(Position r) const { - return axis_aligned_cone_evaluate<1, 0, 2>(r, y0, x0, z0, r_sq); + return axis_aligned_cone_evaluate<1, 0, 2>(r, y0, x0, z0, radius_sq); } double SurfaceYCone::distance(Position r, Direction u, bool coincident) const { return axis_aligned_cone_distance<1, 0, 2>(r, u, coincident, y0, x0, z0, - r_sq); + radius_sq); } Direction SurfaceYCone::normal(Position r) const { - return axis_aligned_cone_normal<1, 0, 2>(r, y0, x0, z0, r_sq); + return axis_aligned_cone_normal<1, 0, 2>(r, y0, x0, z0, radius_sq); } void SurfaceYCone::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "y-cone", false); - std::array coeffs {{x0, y0, z0, r_sq}}; + std::array coeffs {{x0, y0, z0, radius_sq}}; write_dataset(group_id, "coefficients", coeffs); } @@ -901,29 +901,29 @@ void SurfaceYCone::to_hdf5_inner(hid_t group_id) const SurfaceZCone::SurfaceZCone(pugi::xml_node surf_node) : Surface(surf_node) { - read_coeffs(surf_node, id, x0, y0, z0, r_sq); + read_coeffs(surf_node, id, x0, y0, z0, radius_sq); } double SurfaceZCone::evaluate(Position r) const { - return axis_aligned_cone_evaluate<2, 0, 1>(r, z0, x0, y0, r_sq); + return axis_aligned_cone_evaluate<2, 0, 1>(r, z0, x0, y0, radius_sq); } double SurfaceZCone::distance(Position r, Direction u, bool coincident) const { return axis_aligned_cone_distance<2, 0, 1>(r, u, coincident, z0, x0, y0, - r_sq); + radius_sq); } Direction SurfaceZCone::normal(Position r) const { - return axis_aligned_cone_normal<2, 0, 1>(r, z0, x0, y0, r_sq); + return axis_aligned_cone_normal<2, 0, 1>(r, z0, x0, y0, radius_sq); } void SurfaceZCone::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "z-cone", false); - std::array coeffs {{x0, y0, z0, r_sq}}; + std::array coeffs {{x0, y0, z0, radius_sq}}; write_dataset(group_id, "coefficients", coeffs); } diff --git a/src/surface.h b/src/surface.h index b267af05ca..62e0111ca0 100644 --- a/src/surface.h +++ b/src/surface.h @@ -74,10 +74,9 @@ public: bool sense(Position r, Direction u) const; //! Determine the direction of a ray reflected from the surface. - //! \param r The point at which the ray is incident. - //! \param u A direction. This is both an input and an output parameter. - //! It specifies the icident direction on input and the reflected direction - //! on output. + //! \param[in] r The point at which the ray is incident. + //! \param[in] u Incident direction of the ray + //! \return Outgoing direction of the ray Direction reflect(Position r, Direction u) const; //! Evaluate the equation describing the surface. @@ -227,7 +226,7 @@ public: class SurfaceXCylinder : public Surface { - double y0, z0, r; + double y0, z0, radius; public: explicit SurfaceXCylinder(pugi::xml_node surf_node); double evaluate(Position r) const; @@ -245,7 +244,7 @@ public: class SurfaceYCylinder : public Surface { - double x0, z0, r; + double x0, z0, radius; public: explicit SurfaceYCylinder(pugi::xml_node surf_node); double evaluate(Position r) const; @@ -263,7 +262,7 @@ public: class SurfaceZCylinder : public Surface { - double x0, y0, r; + double x0, y0, radius; public: explicit SurfaceZCylinder(pugi::xml_node surf_node); double evaluate(Position r) const; @@ -281,7 +280,7 @@ public: class SurfaceSphere : public Surface { - double x0, y0, z0, r; + double x0, y0, z0, radius; public: explicit SurfaceSphere(pugi::xml_node surf_node); double evaluate(Position r) const; @@ -299,7 +298,7 @@ public: class SurfaceXCone : public Surface { - double x0, y0, z0, r_sq; + double x0, y0, z0, radius_sq; public: explicit SurfaceXCone(pugi::xml_node surf_node); double evaluate(Position r) const; @@ -317,7 +316,7 @@ public: class SurfaceYCone : public Surface { - double x0, y0, z0, r_sq; + double x0, y0, z0, radius_sq; public: explicit SurfaceYCone(pugi::xml_node surf_node); double evaluate(Position r) const; @@ -335,7 +334,7 @@ public: class SurfaceZCone : public Surface { - double x0, y0, z0, r_sq; + double x0, y0, z0, radius_sq; public: explicit SurfaceZCone(pugi::xml_node surf_node); double evaluate(Position r) const; From fd6c8906aca1c3cc1600030e71277725757f20f1 Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Thu, 9 Aug 2018 09:42:36 -0500 Subject: [PATCH 042/109] Change order --- src/tallies/tally_header.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tallies/tally_header.F90 b/src/tallies/tally_header.F90 index c6f3772e1f..7793739a49 100644 --- a/src/tallies/tally_header.F90 +++ b/src/tallies/tally_header.F90 @@ -339,11 +339,11 @@ contains type is (ZernikeFilter) j = FILTER_ZERNIKE this % estimator = ESTIMATOR_COLLISION - type is (ParticleFilter) - j = FILTER_PARTICLE type is (ZernikeRadialFilter) j = FILTER_ZERNIKE_RADIAL this % estimator = ESTIMATOR_COLLISION + type is (ParticleFilter) + j = FILTER_PARTICLE end select this % find_filter(j) = i end do From 960211de0cee2a04ce538e8dd87dbdc56f4e67a2 Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Thu, 9 Aug 2018 11:05:16 -0500 Subject: [PATCH 043/109] Add ZernikeRadialFilter in Sphinx --- docs/source/pythonapi/base.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/pythonapi/base.rst b/docs/source/pythonapi/base.rst index b9eb7033f1..752cf417e8 100644 --- a/docs/source/pythonapi/base.rst +++ b/docs/source/pythonapi/base.rst @@ -122,6 +122,7 @@ Constructing Tallies openmc.SpatialLegendreFilter openmc.SphericalHarmonicsFilter openmc.ZernikeFilter + openmc.ZernikeRadialFilter openmc.ParticleFilter openmc.Mesh openmc.Trigger From 11723c8263e17161a11e3d88645d2710f4c6c36a Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Thu, 9 Aug 2018 11:15:22 -0500 Subject: [PATCH 044/109] Fortran index starts from 1. --- src/tallies/tally_filter_zernike.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tallies/tally_filter_zernike.F90 b/src/tallies/tally_filter_zernike.F90 index 96e016d2ee..b680fc06d0 100644 --- a/src/tallies/tally_filter_zernike.F90 +++ b/src/tallies/tally_filter_zernike.F90 @@ -133,7 +133,7 @@ contains if (bin <= last) then first = last - n m = -n + (bin - first)*2 - label = "Zernike expansion, Z" // trim(to_str(n)) // "," & + label = "Zernike expansion, Z" // trim(to_str((n-1))) // "," & // trim(to_str(m)) exit end if From 7f015db3434f909c0d0e62d06d0f543bfc7eb1a8 Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Thu, 9 Aug 2018 12:41:30 -0500 Subject: [PATCH 045/109] Change the description of ZernikeRadialFilter --- openmc/filter_expansion.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/openmc/filter_expansion.py b/openmc/filter_expansion.py index ad761f2ff7..7debebd6b9 100644 --- a/openmc/filter_expansion.py +++ b/openmc/filter_expansion.py @@ -466,32 +466,30 @@ class ZernikeFilter(ExpansionFilter): class ZernikeRadialFilter(ZernikeFilter): - r"""Score radial Zernike expansion moments in space up to specified order. + r"""Score the :math:`m = 0` (radial variation only) Zernike moments up to + specified order. - The Zernike polynomials are defined the same as in ZernikeFilter. + The Zernike polynomials are defined the same as in :class:`ZernikeFilter`. .. math:: - Z_n^m(\rho, \theta) = R_n^m(\rho) \cos (m\theta), \quad m > 0 - Z_n^{m}(\rho, \theta) = R_n^{m}(\rho) \sin (m\theta), \quad m < 0 - - Z_n^{m}(\rho, \theta) = R_n^{m}(\rho), \quad m = 0 + Z_n^{0}(\rho, \theta) = R_n^{0}(\rho) where the radial polynomials are .. math:: - R_n^m(\rho) = \sum\limits_{k=0}^{(n-m)/2} \frac{(-1)^k (n-k)!}{k! ( - \frac{n+m}{2} - k)! (\frac{n-m}{2} - k)!} \rho^{n-2k}. + R_n^{0}(\rho) = \sum\limits_{k=0}^{n/2} \frac{(-1)^k (n-k)!}{k! (( + \frac{n}{2} - k)!)^{2}} \rho^{n-2k}. - With this definition, the integral of :math:`(Z_n^m)^2` over the unit disk - is :math:`\frac{\epsilon_m\pi}{2n+2}` for each polynomial where - :math:`\epsilon_m` is 2 if :math:`m` equals 0 and 1 otherwise. + With this definition, the integral of :math:`(Z_n^0)^2` over the unit disk + is :math:`\frac{\pi}{n+1}`. If there is only radial dependency, the polynomials are integrated over the azimuthal angles. The only terms left are :math:`Z_n^{0}(\rho, \theta) = R_n^{0}(\rho)`. Note that :math:`n` could only be even orders. Therefore, for a radial Zernike polynomials up to order of :math:`n`, - there are :math:`\frac{n}{2} + 1` terms in total. + there are :math:`\frac{n}{2} + 1` terms in total. The indexing is from the + lowest even order (0) to highest even order. Parameters ---------- From e2774801a5f509b30e539cb7f257d583aec1480b Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Fri, 10 Aug 2018 09:22:08 -0500 Subject: [PATCH 046/109] Fixed the typo --- src/tallies/tally_filter_zernike.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tallies/tally_filter_zernike.F90 b/src/tallies/tally_filter_zernike.F90 index b680fc06d0..73fda7fade 100644 --- a/src/tallies/tally_filter_zernike.F90 +++ b/src/tallies/tally_filter_zernike.F90 @@ -133,7 +133,7 @@ contains if (bin <= last) then first = last - n m = -n + (bin - first)*2 - label = "Zernike expansion, Z" // trim(to_str((n-1))) // "," & + label = "Zernike expansion, Z" // trim(to_str(n)) // "," & // trim(to_str(m)) exit end if @@ -196,7 +196,7 @@ contains integer, intent(in) :: bin character(MAX_LINE_LEN) :: label - label = "Zernike expansion, Z" // trim(to_str(2*bin)) // ",0" + label = "Zernike expansion, Z" // trim(to_str(2*(bin-1))) // ",0" end function text_label_zn_rad !=============================================================================== From e65322d3664f5a80f2cf2ca5ae60a93695eb5424 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 2 Jul 2018 22:10:38 -0500 Subject: [PATCH 047/109] Convert univariate probability distributions --- CMakeLists.txt | 1 + src/constants.h | 5 ++ src/distribution.cpp | 137 +++++++++++++++++++++++++++++++++++++++++++ src/distribution.h | 78 ++++++++++++++++++++++++ 4 files changed, 221 insertions(+) create mode 100644 src/distribution.cpp create mode 100644 src/distribution.h diff --git a/CMakeLists.txt b/CMakeLists.txt index c94f4df5fd..10484f161e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -384,6 +384,7 @@ add_library(libopenmc SHARED src/tallies/trigger.F90 src/tallies/trigger_header.F90 src/cell.cpp + src/distribution.cpp src/initialize.cpp src/finalize.cpp src/geometry_aux.cpp diff --git a/src/constants.h b/src/constants.h index 016a6b3484..24a23196c9 100644 --- a/src/constants.h +++ b/src/constants.h @@ -86,6 +86,11 @@ extern "C" double FP_PRECISION; constexpr double INFTY {std::numeric_limits::max()}; constexpr int C_NONE {-1}; +// Interpolation rules +enum class Interpolation { + histogram, lin_lin, lin_log, log_lin, log_log +}; + } // namespace openmc #endif // CONSTANTS_H diff --git a/src/distribution.cpp b/src/distribution.cpp new file mode 100644 index 0000000000..323a03de50 --- /dev/null +++ b/src/distribution.cpp @@ -0,0 +1,137 @@ +#include "distribution.h" + +#include +#include +#include + +#include "error.h" +#include "math_functions.h" +#include "random_lcg.h" + +namespace openmc { + +Discrete::Discrete(const double* x, const double* p, int n) + : x_{x, x+n}, p_{p, p+n} +{ + // 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; +} + + +double Discrete::sample() +{ + 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]; + } +} + + +double Uniform::sample() +{ + return a_ + prn()*(b_ - a_); +} + + +double Maxwell::sample() +{ + return maxwell_spectrum_c(theta_); +} + + +double Watt::sample() +{ + return watt_spectrum_c(a_, b_); +} + + +Tabular::Tabular(const double* x, const double* p, int n, Interpolation interp) + : x_{x, x+n}, p_{p, p+n}, interp_{interp}, c_(n, 0.0) +{ + // 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 + 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() +{ + // Sample value of CDF + double c = prn(); + + // Find first CDF bin which is above the sampled value + double c_i = c_[0]; + int i; + 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; + } + } +} + + +double Equiprobable::sample() +{ + 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); +} + +} // namespace openmc diff --git a/src/distribution.h b/src/distribution.h new file mode 100644 index 0000000000..675acf9761 --- /dev/null +++ b/src/distribution.h @@ -0,0 +1,78 @@ +#ifndef DISTRIBUTION_H +#define DISTRIBUTION_H + +#include + +#include "constants.h" + +namespace openmc { + +class Distribution { +public: + virtual double sample() = 0; + virtual ~Distribution() = default; +}; + + +class Discrete : public Distribution { +public: + Discrete(const double* x, const double* p, int n); + double sample(); +private: + std::vector x_; + std::vector p_; +}; + + +class Uniform : public Distribution { +public: + Uniform(double a, double b) : a_{a}, b_{b} {}; + double sample(); +private: + double a_; + double b_; +}; + + +class Maxwell : public Distribution { +public: + Maxwell(double theta) : theta_{theta} { }; + double sample(); +private: + double theta_; +}; + + +class Watt : public Distribution { +public: + Watt(double a, double b) : a_{a}, b_{b} { }; + double sample(); +private: + double a_; + double b_; +}; + + +class Tabular : public Distribution { +public: + Tabular(const double* x, const double* p, int n, Interpolation interp); + double sample(); +private: + std::vector x_; + std::vector p_; + std::vector c_; + Interpolation interp_; +}; + + +class Equiprobable : public Distribution { +public: + Equiprobable(const double* x, int n) : x_{x, x+n} { }; + double sample(); +private: + std::vector x_; +}; + +} // namespace openmc + +#endif // DISTRIBUTION_H From f8e035d12da289e4820a995f0573b34d3bf167c3 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 5 Jul 2018 07:01:19 -0500 Subject: [PATCH 048/109] Convert multivariate probability distributions --- CMakeLists.txt | 2 + src/distribution.cpp | 177 ++++++++++++++++++++++++++++++----- src/distribution.h | 84 ++++++++++++++--- src/distribution_multi.cpp | 51 ++++++++++ src/distribution_multi.h | 73 +++++++++++++++ src/distribution_spatial.cpp | 97 +++++++++++++++++++ src/distribution_spatial.h | 69 ++++++++++++++ src/math_functions.cpp | 8 ++ src/math_functions.h | 9 +- src/xml_interface.cpp | 12 ++- src/xml_interface.h | 18 ++++ 11 files changed, 557 insertions(+), 43 deletions(-) create mode 100644 src/distribution_multi.cpp create mode 100644 src/distribution_multi.h create mode 100644 src/distribution_spatial.cpp create mode 100644 src/distribution_spatial.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 10484f161e..24b0bef569 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -385,6 +385,8 @@ add_library(libopenmc SHARED src/tallies/trigger_header.F90 src/cell.cpp src/distribution.cpp + src/distribution_multi.cpp + src/distribution_spatial.cpp src/initialize.cpp src/finalize.cpp src/geometry_aux.cpp diff --git a/src/distribution.cpp b/src/distribution.cpp index 323a03de50..01255f2d75 100644 --- a/src/distribution.cpp +++ b/src/distribution.cpp @@ -1,26 +1,40 @@ #include "distribution.h" -#include -#include -#include +#include // for copy +#include // for sqrt, floor, max +#include // for back_inserter +#include // for accumulate +#include // 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(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} { - // 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; + normalize(); } - -double Discrete::sample() +double Discrete::sample() const { int n = x_.size(); if (n > 1) { @@ -36,28 +50,107 @@ double Discrete::sample() } } +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; +} -double Uniform::sample() +//============================================================================== +// Uniform implementation +//============================================================================== + +Uniform::Uniform(pugi::xml_node node) +{ + auto params = get_node_array(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 +//============================================================================== -double Maxwell::sample() +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 +//============================================================================== -double Watt::sample() +Watt::Watt(pugi::xml_node node) +{ + auto params = get_node_array(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(const double* x, const double* p, int n, Interpolation interp) - : x_{x, x+n}, p_{p, p+n}, interp_{interp}, c_(n, 0.0) +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(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) { @@ -66,11 +159,17 @@ Tabular::Tabular(const double* x, const double* p, int n, Interpolation interp) } // Calculate cumulative distribution function - 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]); + 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]); + } } } @@ -81,8 +180,7 @@ Tabular::Tabular(const double* x, const double* p, int n, Interpolation interp) } } - -double Tabular::sample() +double Tabular::sample() const { // Sample value of CDF double c = prn(); @@ -90,7 +188,7 @@ double Tabular::sample() // Find first CDF bin which is above the sampled value double c_i = c_[0]; int i; - size_t n = c_.size(); + std::size_t n = c_.size(); for (i = 0; i < n - 1; ++i) { if (c <= c_[i+1]) break; c_i = c_[i+1]; @@ -121,10 +219,13 @@ double Tabular::sample() } } +//============================================================================== +// Equiprobable implementation +//============================================================================== -double Equiprobable::sample() +double Equiprobable::sample() const { - size_t n = x_.size(); + std::size_t n = x_.size(); double r = prn(); int i = std::floor((n - 1)*r); @@ -134,4 +235,32 @@ double Equiprobable::sample() 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"); + + // 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 diff --git a/src/distribution.h b/src/distribution.h index 675acf9761..705db53dab 100644 --- a/src/distribution.h +++ b/src/distribution.h @@ -1,78 +1,136 @@ #ifndef DISTRIBUTION_H #define DISTRIBUTION_H -#include +#include // for size_t +#include // for unique_ptr +#include // for vector #include "constants.h" +#include "pugixml.hpp" namespace openmc { +//============================================================================== +//! Abstract class representing a univariate probability distribution +//============================================================================== + class Distribution { public: - virtual double sample() = 0; + virtual double sample() const = 0; virtual ~Distribution() = default; }; +//============================================================================== +//! 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); - double sample(); + + //! Sample a value from the distribution + double sample() const; private: std::vector x_; std::vector p_; + + 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} {}; - double sample(); + + //! Sample a value from the distribution + double sample() const; private: double a_; double b_; }; +//============================================================================== +//! Maxwellian distribution of form c*E*exp(-E/a) +//============================================================================== class Maxwell : public Distribution { public: + explicit Maxwell(pugi::xml_node node); Maxwell(double theta) : theta_{theta} { }; - double sample(); + + //! Sample a value from the distribution + double sample() const; private: double theta_; }; +//============================================================================== +//! 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} { }; - double sample(); + + //! Sample a value from the distribution + double sample() const; private: double a_; double b_; }; +//============================================================================== +//! Histogram or linear-linear interpolated tabular distribution +//============================================================================== class Tabular : public Distribution { public: - Tabular(const double* x, const double* p, int n, Interpolation interp); - double sample(); + 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 + double sample() const; private: - std::vector x_; - std::vector p_; - std::vector c_; - Interpolation interp_; + std::vector x_; //!< tabulated independent variable + std::vector p_; //!< tabulated probability density + std::vector 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); }; +//============================================================================== +//! +//============================================================================== class Equiprobable : public Distribution { public: + explicit Equiprobable(pugi::xml_node node); Equiprobable(const double* x, int n) : x_{x, x+n} { }; - double sample(); + + //! Sample a value from the distribution + double sample() const; private: std::vector x_; }; + +using UPtrDist = std::unique_ptr; + +UPtrDist distribution_from_xml(pugi::xml_node node); + } // namespace openmc #endif // DISTRIBUTION_H diff --git a/src/distribution_multi.cpp b/src/distribution_multi.cpp new file mode 100644 index 0000000000..36184f7527 --- /dev/null +++ b/src/distribution_multi.cpp @@ -0,0 +1,51 @@ +#include "distribution_multi.h" + +#include // for move +#include // 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 diff --git a/src/distribution_multi.h b/src/distribution_multi.h new file mode 100644 index 0000000000..2d4dab42c1 --- /dev/null +++ b/src/distribution_multi.h @@ -0,0 +1,73 @@ +#ifndef DISTRIBUTION_MULTI_H +#define DISTRIBUTION_MULTI_H + +#include + +#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 diff --git a/src/distribution_spatial.cpp b/src/distribution_spatial.cpp new file mode 100644 index 0000000000..d870a5f93a --- /dev/null +++ b/src/distribution_spatial.cpp @@ -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(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(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 diff --git a/src/distribution_spatial.h b/src/distribution_spatial.h new file mode 100644 index 0000000000..9b32a6344f --- /dev/null +++ b/src/distribution_spatial.h @@ -0,0 +1,69 @@ +#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 Position sample() const = 0; + virtual ~SpatialDistribution() = default; +}; + +//============================================================================== +//! 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 + 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 + Position sample() const; +private: + Position lower_left_; + Position upper_right_; + bool only_fissionable {false}; +}; + +//============================================================================== +//! Distribution at a single point +//============================================================================== + +class SpatialPoint : public SpatialDistribution { +public: + explicit SpatialPoint(pugi::xml_node node); + + //! Sample a position from the distribution + Position sample() const; +private: + Position r_; +}; + +} // namespace openmc + +#endif // OPENMC_DISTRIBUTION_SPATIAL_H diff --git a/src/math_functions.cpp b/src/math_functions.cpp index 3342e3a912..ddb7506af7 100644 --- a/src/math_functions.cpp +++ b/src/math_functions.cpp @@ -623,6 +623,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(); diff --git a/src/math_functions.h b/src/math_functions.h index 566e68ea60..78aa166b32 100644 --- a/src/math_functions.h +++ b/src/math_functions.h @@ -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 #include #include "constants.h" +#include "position.h" #include "random_lcg.h" @@ -106,6 +107,8 @@ extern "C" void calc_zn_c(int n, double rho, double phi, double zn[]); 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. @@ -202,4 +205,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 diff --git a/src/xml_interface.cpp b/src/xml_interface.cpp index b4fcc524c6..7f3222a524 100644 --- a/src/xml_interface.cpp +++ b/src/xml_interface.cpp @@ -9,7 +9,7 @@ namespace openmc { std::string -get_node_value(pugi::xml_node node, const char *name) +get_node_value_str(pugi::xml_node node, const char* name) { // Search for either an attribute or child tag and get the data as a char*. const pugi::char_t *value_char; @@ -23,9 +23,15 @@ get_node_value(pugi::xml_node node, const char *name) << node.name() << "\" XML node"; fatal_error(err_msg); } + return value_char; +} - // Convert to lowercase string. - std::string value(value_char); + +std::string +get_node_value(pugi::xml_node node, const char *name) +{ + // Get char* and convert to lowercase string. + std::string value {get_node_value_str(node, name)}; std::transform(value.begin(), value.end(), value.begin(), ::tolower); // Remove whitespace. diff --git a/src/xml_interface.h b/src/xml_interface.h index de89018efe..b12e6185b6 100644 --- a/src/xml_interface.h +++ b/src/xml_interface.h @@ -1,6 +1,7 @@ #ifndef XML_INTERFACE_H #define XML_INTERFACE_H +#include // for stringstream #include #include @@ -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_str(pugi::xml_node node, const char *name); std::string get_node_value(pugi::xml_node node, const char *name); +template +std::vector get_node_array(pugi::xml_node node, const char* name) +{ + // Get value of node attribute/child + std::string s {get_node_value_str(node, name)}; + + // Read values one by one into vector + std::stringstream iss {s}; + T value; + std::vector values; + while (iss >> value) + values.push_back(value); + + return values; +} + } // namespace openmc #endif // XML_INTERFACE_H From 1a9f2a27d7214bbed0d6c92a3b9c539a873a58c0 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 6 Jul 2018 10:49:24 -0500 Subject: [PATCH 049/109] Include xtensor as vendored header-only library --- CMakeLists.txt | 12 +- vendor/xtensor/CMakeLists.txt | 191 ++ .../xtensor/include/xtensor/xaccumulator.hpp | 266 ++ vendor/xtensor/include/xtensor/xadapt.hpp | 322 +++ vendor/xtensor/include/xtensor/xarray.hpp | 550 ++++ vendor/xtensor/include/xtensor/xassign.hpp | 783 ++++++ .../include/xtensor/xaxis_iterator.hpp | 197 ++ vendor/xtensor/include/xtensor/xbroadcast.hpp | 412 +++ .../include/xtensor/xbuffer_adaptor.hpp | 623 +++++ vendor/xtensor/include/xtensor/xbuilder.hpp | 918 ++++++ vendor/xtensor/include/xtensor/xcomplex.hpp | 251 ++ vendor/xtensor/include/xtensor/xconcepts.hpp | 113 + vendor/xtensor/include/xtensor/xcontainer.hpp | 1418 ++++++++++ vendor/xtensor/include/xtensor/xcsv.hpp | 169 ++ vendor/xtensor/include/xtensor/xeval.hpp | 57 + vendor/xtensor/include/xtensor/xexception.hpp | 219 ++ .../xtensor/include/xtensor/xexpression.hpp | 307 ++ vendor/xtensor/include/xtensor/xfixed.hpp | 818 ++++++ vendor/xtensor/include/xtensor/xfunction.hpp | 1184 ++++++++ .../xtensor/include/xtensor/xfunctor_view.hpp | 1349 +++++++++ vendor/xtensor/include/xtensor/xgenerator.hpp | 401 +++ .../xtensor/include/xtensor/xindex_view.hpp | 745 +++++ vendor/xtensor/include/xtensor/xinfo.hpp | 139 + vendor/xtensor/include/xtensor/xio.hpp | 634 +++++ vendor/xtensor/include/xtensor/xiterable.hpp | 824 ++++++ vendor/xtensor/include/xtensor/xiterator.hpp | 1123 ++++++++ vendor/xtensor/include/xtensor/xjson.hpp | 183 ++ vendor/xtensor/include/xtensor/xlayout.hpp | 93 + vendor/xtensor/include/xtensor/xmath.hpp | 2146 ++++++++++++++ vendor/xtensor/include/xtensor/xnoalias.hpp | 110 + vendor/xtensor/include/xtensor/xnorm.hpp | 477 ++++ vendor/xtensor/include/xtensor/xnpy.hpp | 702 +++++ .../xtensor/include/xtensor/xoffset_view.hpp | 41 + vendor/xtensor/include/xtensor/xoperation.hpp | 843 ++++++ vendor/xtensor/include/xtensor/xoptional.hpp | 503 ++++ .../include/xtensor/xoptional_assembly.hpp | 661 +++++ .../xtensor/xoptional_assembly_base.hpp | 948 +++++++ .../xtensor/xoptional_assembly_storage.hpp | 551 ++++ vendor/xtensor/include/xtensor/xrandom.hpp | 314 +++ vendor/xtensor/include/xtensor/xreducer.hpp | 1039 +++++++ vendor/xtensor/include/xtensor/xscalar.hpp | 1108 ++++++++ vendor/xtensor/include/xtensor/xsemantic.hpp | 656 +++++ vendor/xtensor/include/xtensor/xshape.hpp | 119 + vendor/xtensor/include/xtensor/xslice.hpp | 970 +++++++ vendor/xtensor/include/xtensor/xsort.hpp | 316 +++ vendor/xtensor/include/xtensor/xstorage.hpp | 1346 +++++++++ .../xtensor/include/xtensor/xstrided_view.hpp | 1307 +++++++++ .../include/xtensor/xstrided_view_base.hpp | 773 ++++++ vendor/xtensor/include/xtensor/xstrides.hpp | 451 +++ vendor/xtensor/include/xtensor/xtensor.hpp | 479 ++++ .../include/xtensor/xtensor_config.hpp | 63 + .../include/xtensor/xtensor_forward.hpp | 216 ++ .../xtensor/include/xtensor/xtensor_simd.hpp | 160 ++ vendor/xtensor/include/xtensor/xutils.hpp | 1040 +++++++ vendor/xtensor/include/xtensor/xvectorize.hpp | 101 + vendor/xtensor/include/xtensor/xview.hpp | 1538 +++++++++++ .../xtensor/include/xtensor/xview_utils.hpp | 274 ++ vendor/xtensor/xtensor.pc.in | 8 + vendor/xtensor/xtensorConfig.cmake.in | 21 + vendor/xtl/CMakeLists.txt | 113 + vendor/xtl/include/xtl/xany.hpp | 453 +++ vendor/xtl/include/xtl/xbase64.hpp | 75 + .../xtl/include/xtl/xbasic_fixed_string.hpp | 2250 +++++++++++++++ vendor/xtl/include/xtl/xclosure.hpp | 387 +++ vendor/xtl/include/xtl/xcomplex.hpp | 1337 +++++++++ vendor/xtl/include/xtl/xcomplex_sequence.hpp | 576 ++++ vendor/xtl/include/xtl/xdynamic_bitset.hpp | 1125 ++++++++ vendor/xtl/include/xtl/xfunctional.hpp | 28 + vendor/xtl/include/xtl/xhash.hpp | 187 ++ .../xtl/include/xtl/xhierarchy_generator.hpp | 72 + vendor/xtl/include/xtl/xiterator_base.hpp | 196 ++ vendor/xtl/include/xtl/xjson.hpp | 40 + vendor/xtl/include/xtl/xmeta_utils.hpp | 482 ++++ vendor/xtl/include/xtl/xoptional.hpp | 1425 ++++++++++ vendor/xtl/include/xtl/xoptional_sequence.hpp | 621 +++++ vendor/xtl/include/xtl/xproxy_wrapper.hpp | 48 + vendor/xtl/include/xtl/xsequence.hpp | 173 ++ vendor/xtl/include/xtl/xtl_config.hpp | 16 + vendor/xtl/include/xtl/xtype_traits.hpp | 141 + vendor/xtl/include/xtl/xvariant.hpp | 155 ++ vendor/xtl/include/xtl/xvariant_impl.hpp | 2457 +++++++++++++++++ vendor/xtl/xtlConfig.cmake.in | 21 + 82 files changed, 45958 insertions(+), 2 deletions(-) create mode 100644 vendor/xtensor/CMakeLists.txt create mode 100644 vendor/xtensor/include/xtensor/xaccumulator.hpp create mode 100644 vendor/xtensor/include/xtensor/xadapt.hpp create mode 100644 vendor/xtensor/include/xtensor/xarray.hpp create mode 100644 vendor/xtensor/include/xtensor/xassign.hpp create mode 100644 vendor/xtensor/include/xtensor/xaxis_iterator.hpp create mode 100644 vendor/xtensor/include/xtensor/xbroadcast.hpp create mode 100644 vendor/xtensor/include/xtensor/xbuffer_adaptor.hpp create mode 100644 vendor/xtensor/include/xtensor/xbuilder.hpp create mode 100644 vendor/xtensor/include/xtensor/xcomplex.hpp create mode 100644 vendor/xtensor/include/xtensor/xconcepts.hpp create mode 100644 vendor/xtensor/include/xtensor/xcontainer.hpp create mode 100644 vendor/xtensor/include/xtensor/xcsv.hpp create mode 100644 vendor/xtensor/include/xtensor/xeval.hpp create mode 100644 vendor/xtensor/include/xtensor/xexception.hpp create mode 100644 vendor/xtensor/include/xtensor/xexpression.hpp create mode 100644 vendor/xtensor/include/xtensor/xfixed.hpp create mode 100644 vendor/xtensor/include/xtensor/xfunction.hpp create mode 100644 vendor/xtensor/include/xtensor/xfunctor_view.hpp create mode 100644 vendor/xtensor/include/xtensor/xgenerator.hpp create mode 100644 vendor/xtensor/include/xtensor/xindex_view.hpp create mode 100644 vendor/xtensor/include/xtensor/xinfo.hpp create mode 100644 vendor/xtensor/include/xtensor/xio.hpp create mode 100644 vendor/xtensor/include/xtensor/xiterable.hpp create mode 100644 vendor/xtensor/include/xtensor/xiterator.hpp create mode 100644 vendor/xtensor/include/xtensor/xjson.hpp create mode 100644 vendor/xtensor/include/xtensor/xlayout.hpp create mode 100644 vendor/xtensor/include/xtensor/xmath.hpp create mode 100644 vendor/xtensor/include/xtensor/xnoalias.hpp create mode 100644 vendor/xtensor/include/xtensor/xnorm.hpp create mode 100644 vendor/xtensor/include/xtensor/xnpy.hpp create mode 100644 vendor/xtensor/include/xtensor/xoffset_view.hpp create mode 100644 vendor/xtensor/include/xtensor/xoperation.hpp create mode 100644 vendor/xtensor/include/xtensor/xoptional.hpp create mode 100644 vendor/xtensor/include/xtensor/xoptional_assembly.hpp create mode 100644 vendor/xtensor/include/xtensor/xoptional_assembly_base.hpp create mode 100644 vendor/xtensor/include/xtensor/xoptional_assembly_storage.hpp create mode 100644 vendor/xtensor/include/xtensor/xrandom.hpp create mode 100644 vendor/xtensor/include/xtensor/xreducer.hpp create mode 100644 vendor/xtensor/include/xtensor/xscalar.hpp create mode 100644 vendor/xtensor/include/xtensor/xsemantic.hpp create mode 100644 vendor/xtensor/include/xtensor/xshape.hpp create mode 100644 vendor/xtensor/include/xtensor/xslice.hpp create mode 100644 vendor/xtensor/include/xtensor/xsort.hpp create mode 100644 vendor/xtensor/include/xtensor/xstorage.hpp create mode 100644 vendor/xtensor/include/xtensor/xstrided_view.hpp create mode 100644 vendor/xtensor/include/xtensor/xstrided_view_base.hpp create mode 100644 vendor/xtensor/include/xtensor/xstrides.hpp create mode 100644 vendor/xtensor/include/xtensor/xtensor.hpp create mode 100644 vendor/xtensor/include/xtensor/xtensor_config.hpp create mode 100644 vendor/xtensor/include/xtensor/xtensor_forward.hpp create mode 100644 vendor/xtensor/include/xtensor/xtensor_simd.hpp create mode 100644 vendor/xtensor/include/xtensor/xutils.hpp create mode 100644 vendor/xtensor/include/xtensor/xvectorize.hpp create mode 100644 vendor/xtensor/include/xtensor/xview.hpp create mode 100644 vendor/xtensor/include/xtensor/xview_utils.hpp create mode 100644 vendor/xtensor/xtensor.pc.in create mode 100644 vendor/xtensor/xtensorConfig.cmake.in create mode 100644 vendor/xtl/CMakeLists.txt create mode 100644 vendor/xtl/include/xtl/xany.hpp create mode 100644 vendor/xtl/include/xtl/xbase64.hpp create mode 100644 vendor/xtl/include/xtl/xbasic_fixed_string.hpp create mode 100644 vendor/xtl/include/xtl/xclosure.hpp create mode 100644 vendor/xtl/include/xtl/xcomplex.hpp create mode 100644 vendor/xtl/include/xtl/xcomplex_sequence.hpp create mode 100644 vendor/xtl/include/xtl/xdynamic_bitset.hpp create mode 100644 vendor/xtl/include/xtl/xfunctional.hpp create mode 100644 vendor/xtl/include/xtl/xhash.hpp create mode 100644 vendor/xtl/include/xtl/xhierarchy_generator.hpp create mode 100644 vendor/xtl/include/xtl/xiterator_base.hpp create mode 100644 vendor/xtl/include/xtl/xjson.hpp create mode 100644 vendor/xtl/include/xtl/xmeta_utils.hpp create mode 100644 vendor/xtl/include/xtl/xoptional.hpp create mode 100644 vendor/xtl/include/xtl/xoptional_sequence.hpp create mode 100644 vendor/xtl/include/xtl/xproxy_wrapper.hpp create mode 100644 vendor/xtl/include/xtl/xsequence.hpp create mode 100644 vendor/xtl/include/xtl/xtl_config.hpp create mode 100644 vendor/xtl/include/xtl/xtype_traits.hpp create mode 100644 vendor/xtl/include/xtl/xvariant.hpp create mode 100644 vendor/xtl/include/xtl/xvariant_impl.hpp create mode 100644 vendor/xtl/xtlConfig.cmake.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 24b0bef569..668e37899e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 #=============================================================================== @@ -453,7 +461,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 diff --git a/vendor/xtensor/CMakeLists.txt b/vendor/xtensor/CMakeLists.txt new file mode 100644 index 0000000000..d4d3b355d6 --- /dev/null +++ b/vendor/xtensor/CMakeLists.txt @@ -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 $ + $) +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/") diff --git a/vendor/xtensor/include/xtensor/xaccumulator.hpp b/vendor/xtensor/include/xtensor/xaccumulator.hpp new file mode 100644 index 0000000000..f2b446ff36 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xaccumulator.hpp @@ -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 +#include +#include +#include + +#include "xexpression.hpp" +#include "xstrides.hpp" +#include "xtensor_forward.hpp" + +namespace xt +{ + +#define DEFAULT_STRATEGY_ACCUMULATORS evaluation_strategy::immediate + + /************** + * accumulate * + **************/ + + template + struct xaccumulator_functor + : public std::tuple + { + using self_type = xaccumulator_functor; + using base_type = std::tuple; + using accumulate_functor_type = ACCUMULATE_FUNC; + using init_functor_type = INIT_FUNC; + + xaccumulator_functor() + : base_type() + { + } + + template + xaccumulator_functor(RF&& accumulate_func) + : base_type(std::forward(accumulate_func), INIT_FUNC()) + { + } + + template + xaccumulator_functor(RF&& accumulate_func, IF&& init_func) + : base_type(std::forward(accumulate_func), std::forward(init_func)) + { + } + }; + + template + auto make_xaccumulator_functor(RF&& accumulate_func) + { + using accumulator_type = xaccumulator_functor>; + return accumulator_type(std::forward(accumulate_func)); + } + + template + auto make_xaccumulator_functor(RF&& accumulate_func, IF&& init_func) + { + using accumulator_type = xaccumulator_functor, std::remove_reference_t>; + return accumulator_type(std::forward(accumulate_func), std::forward(init_func)); + } + + namespace detail + { + template + xarray::value_type> accumulator_impl(F&&, E&&, std::size_t, EVS) + { + static_assert(!std::is_same::value, "Lazy accumulators not yet implemented."); + } + + template + xarray::value_type> accumulator_impl(F&&, E&&, EVS) + { + static_assert(!std::is_same::value, "Lazy accumulators not yet implemented."); + } + + template + struct xaccumulator_return_type + { + using type = xarray; + }; + + template + struct xaccumulator_return_type, R> + { + using type = xtensor; + }; + + template + using xaccumulator_return_type_t = typename xaccumulator_return_type::type; + + template + 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()); + inner_loop_size = std::accumulate(first + ax + 1, last, + std::size_t(1), std::multiplies()); + }; + + 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(axis)); + set_loop_strides(e.strides().begin(), e.strides().end(), static_cast(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 + inline auto accumulator_impl(F&& f, E&& e, std::size_t axis, evaluation_strategy::immediate) + { + using accumulate_functor = std::decay_t(f))>; + using function_return_type = typename accumulate_functor::result_type; + using result_type = xaccumulator_return_type_t, function_return_type>; + + 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()); + + inner_loop_size = std::accumulate(first + ax, + last, + std::size_t(1), std::multiplies()); + }; + + if (result_type::static_layout == layout_type::row_major) + { + set_loop_sizes(result.shape().cbegin(), result.shape().cend(), static_cast(axis)); + } + else + { + set_loop_sizes(result.shape().cbegin(), result.shape().cend(), static_cast(axis + 1)); + std::swap(inner_loop_size, outer_loop_size); + } + + std::size_t pos = 0; + + inner_loop_size = inner_loop_size - inner_stride; + + // activate the init loop if we have an init function other than identity + if (!std::is_same(f)), xtl::identity>::value) + { + accumulator_init_with_f(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 + inline auto accumulator_impl(F&& f, E&& e, evaluation_strategy::immediate) + { + using accumulate_functor = std::decay_t(f))>; + using T = typename accumulate_functor::result_type; + + using result_type = xtensor; + std::size_t sz = e.size(); + auto result = result_type::from_shape({sz}); + + auto it = e.template begin(); + + result.storage()[0] = std::get<1>(f)(*it); + ++it; + + for (std::size_t idx = 0; it != e.template end(); ++it) + { + 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 filled with accumulated values + */ + template ::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), std::forward(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 filled with accumulated values + */ + template + inline auto accumulate(F&& f, E&& e, std::size_t axis, EVS evaluation_strategy = EVS()) + { + return detail::accumulator_impl(std::forward(f), std::forward(e), axis, evaluation_strategy); + } +} + +#endif diff --git a/vendor/xtensor/include/xtensor/xadapt.hpp b/vendor/xtensor/include/xtensor/xadapt.hpp new file mode 100644 index 0000000000..b080bd0b7d --- /dev/null +++ b/vendor/xtensor/include/xtensor/xadapt.hpp @@ -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 +#include +#include +#include + +#include + +#include "xarray.hpp" +#include "xtensor.hpp" + +namespace xt +{ + namespace detail + { + template + struct array_size_impl; + + template + struct array_size_impl> + { + static constexpr std::size_t value = N; + }; + + template + using array_size = array_size_impl>; + } + + /************************** + * 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 >::value, int> = 0> + xarray_adaptor, L, std::decay_t> + 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 >::value, int> = 0, + typename std::enable_if_t>::value, int> = 0> + xarray_adaptor, layout_type::dynamic, std::decay_t> + adapt(C&& container, SC&& shape, SS&& strides); + + /** + * 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 >>>, + typename std::enable_if_t>::value, int> = 0> + xarray_adaptor, O, A>, L, SC> + adapt(P&& pointer, typename A::size_type size, O ownership, const SC& shape, layout_type l = L, const A& alloc = A()); + + /** + * 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 >>>, + typename std::enable_if_t>::value, int> = 0, + typename std::enable_if_t>::value, int> = 0> + xarray_adaptor, O, A>, layout_type::dynamic, std::decay_t> + adapt(P&& pointer, typename A::size_type size, O ownership, SC&& shape, SS&& strides, const A& alloc = A()); + + /*************************** + * 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 + xtensor_adaptor + 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 >::value, int> = 0> + xtensor_adaptor::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 >::value, int> = 0, + typename std::enable_if_t>::value, int> = 0> + xtensor_adaptor::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 >>>> + xtensor_adaptor, O, A>, 1, L> + adapt(P&& pointer, typename A::size_type size, O ownership, layout_type l = L, const A& alloc = A()); + + /** + * Constructs an xtensor_adaptor of the given dynamically allocated C array, + * with the specified shape and layout. + * @param pointer the pointer to the beginning of the dynamic array + * @param size the size of the dynamic array + * @param ownership indicates whether the adaptor takes ownership of the array. + * Possible values are ``no_ownerhsip()`` or ``acquire_ownership()`` + * @param shape the shape of the xtensor_adaptor + * @param l the layout_type of the xtensor_adaptor + * @param alloc the allocator used for allocating / deallocating the dynamic array + */ + template >>>, + typename std::enable_if_t>::value, int> = 0> + xtensor_adaptor, O, A>, detail::array_size::value, L> + adapt(P&& pointer, typename A::size_type size, O ownership, const SC& shape, layout_type l = L, const A& alloc = A()); + + /** + * Constructs an xtensor_adaptor of the given dynamically allocated C array, + * with the specified shape and strides. + * @param pointer the pointer to the beginning of the dynamic array + * @param size the size of the dynamic array + * @param ownership indicates whether the adaptor takes ownership of the array. + * Possible values are ``no_ownerhsip()`` or ``acquire_ownership()`` + * @param shape the shape of the xtensor_adaptor + * @param strides the strides of the xtensor_adaptor + * @param alloc the allocator used for allocating / deallocating the dynamic array + */ + template >>>, + typename std::enable_if_t>::value, int> = 0, + typename std::enable_if_t>::value, int> = 0> + xtensor_adaptor, O, A>, detail::array_size::value, layout_type::dynamic> + adapt(P&& pointer, typename A::size_type size, O ownership, SC&& shape, SS&& strides, const A& alloc = A()); + + /***************************************** + * xarray_adaptor builder implementation * + *****************************************/ + + // shape only - container version + template >::value, int>> + inline xarray_adaptor, L, std::decay_t> + adapt(C&& container, const SC& shape, layout_type l) + { + using return_type = xarray_adaptor, L, std::decay_t>; + return return_type(std::forward(container), shape, l); + } + + // shape and strides - container version + template >::value, int>, + typename std::enable_if_t>::value, int>> + inline xarray_adaptor, layout_type::dynamic, std::decay_t> + adapt(C&& container, SC&& shape, SS&& strides) + { + using return_type = xarray_adaptor, layout_type::dynamic, std::decay_t>; + return return_type(std::forward(container), + xtl::forward_sequence(shape), + xtl::forward_sequence(strides)); + } + + // shape only - buffer version + template >::value, int>> + inline xarray_adaptor, O, A>, L, SC> + adapt(P&& pointer, typename A::size_type size, O, const SC& shape, layout_type l, const A& alloc) + { + using buffer_type = xbuffer_adaptor, O, A>; + using return_type = xarray_adaptor; + buffer_type buf(std::forward

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

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

(pointer), size, alloc); + const std::array shape{size}; + return return_type(std::move(buf), shape, l); + } + + // shape only - buffer version + template >::value, int>> + inline xtensor_adaptor, O, A>, detail::array_size::value, L> + adapt(P&& pointer, typename A::size_type size, O, const SC& shape, layout_type l, const A& alloc) + { + using buffer_type = xbuffer_adaptor, O, A>; + constexpr std::size_t N = detail::array_size::value; + using return_type = xtensor_adaptor; + buffer_type buf(std::forward

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

(pointer), size, alloc); + return return_type(std::move(buf), + xtl::forward_sequence(shape), + xtl::forward_sequence(strides)); + } +} + +#endif diff --git a/vendor/xtensor/include/xtensor/xarray.hpp b/vendor/xtensor/include/xtensor/xarray.hpp new file mode 100644 index 0000000000..7c51f28124 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xarray.hpp @@ -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 +#include +#include + +#include + +#include "xbuffer_adaptor.hpp" +#include "xcontainer.hpp" +#include "xsemantic.hpp" + +namespace xt +{ + + /******************************** + * xarray_container declaration * + ********************************/ + + template + struct xcontainer_inner_types> + { + 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; + static constexpr layout_type layout = L; + }; + + template + struct xiterable_inner_types> + : xcontainer_iterable_types> + { + }; + + /** + * @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 xarray_container : public xstrided_container>, + public xcontainer_semantic> + { + public: + + using self_type = xarray_container; + using base_type = xstrided_container; + using semantic_base = xcontainer_semantic; + 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 t); + xarray_container(nested_initializer_list_t t); + xarray_container(nested_initializer_list_t t); + xarray_container(nested_initializer_list_t t); + xarray_container(nested_initializer_list_t t); + + template + 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 + xarray_container(const xexpression& e); + + template + xarray_container& operator=(const xexpression& e); + + private: + + storage_type m_storage; + + storage_type& storage_impl() noexcept; + const storage_type& storage_impl() const noexcept; + + friend class xcontainer>; + }; + + /****************************** + * xarray_adaptor declaration * + ******************************/ + + template + struct xcontainer_inner_types> + { + using storage_type = std::remove_reference_t; + 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, L, SC, Tag>; + static constexpr layout_type layout = L; + }; + + template + struct xiterable_inner_types> + : xcontainer_iterable_types> + { + }; + + /** + * @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 xarray_adaptor : public xstrided_container>, + public xcontainer_semantic> + { + public: + + using container_closure_type = EC; + + using self_type = xarray_adaptor; + using base_type = xstrided_container; + using semantic_base = xcontainer_semantic; + 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 + xarray_adaptor(D&& storage, const shape_type& shape, layout_type l = L); + + template + 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 + xarray_adaptor& operator=(const xexpression& e); + + private: + + container_closure_type m_storage; + + storage_type& storage_impl() noexcept; + const storage_type& storage_impl() const noexcept; + + + friend class xcontainer>; + }; + + /*********************************** + * xarray_container implementation * + ***********************************/ + + /** + * @name Constructors + */ + //@{ + /** + * Allocates an uninitialized xarray_container that holds 0 element. + */ + template + inline xarray_container::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 + inline xarray_container::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 + inline xarray_container::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 + inline xarray_container::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 + inline xarray_container::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 + inline xarray_container::xarray_container(const value_type& t) + : base_type() + { + base_type::resize(xt::shape(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 + inline xarray_container::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 + inline xarray_container::xarray_container(nested_initializer_list_t t) + : base_type() + { + base_type::resize(xt::shape(t)); + L == layout_type::row_major ? nested_copy(m_storage.begin(), t) : nested_copy(this->template begin(), t); + } + + /** + * Allocates a two-dimensional xarray_container. + * @param t the elements of the xarray_container + */ + template + inline xarray_container::xarray_container(nested_initializer_list_t t) + : base_type() + { + base_type::resize(xt::shape(t)); + L == layout_type::row_major ? nested_copy(m_storage.begin(), t) : nested_copy(this->template begin(), t); + } + + /** + * Allocates a three-dimensional xarray_container. + * @param t the elements of the xarray_container + */ + template + inline xarray_container::xarray_container(nested_initializer_list_t t) + : base_type() + { + base_type::resize(xt::shape(t)); + L == layout_type::row_major ? nested_copy(m_storage.begin(), t) : nested_copy(this->template begin(), t); + } + + /** + * Allocates a four-dimensional xarray_container. + * @param t the elements of the xarray_container + */ + template + inline xarray_container::xarray_container(nested_initializer_list_t t) + : base_type() + { + base_type::resize(xt::shape(t)); + L == layout_type::row_major ? nested_copy(m_storage.begin(), t) : nested_copy(this->template begin(), t); + } + + /** + * Allocates a five-dimensional xarray_container. + * @param t the elements of the xarray_container + */ + template + inline xarray_container::xarray_container(nested_initializer_list_t t) + : base_type() + { + base_type::resize(xt::shape(t)); + L == layout_type::row_major ? nested_copy(m_storage.begin(), t) : nested_copy(this->template begin(), t); + } + //@} + + /** + * Allocates and returns an xarray_container with the specified shape. + * @param s the shape of the xarray_container + */ + template + template + inline xarray_container xarray_container::from_shape(S&& s) + { + shape_type shape = xtl::forward_sequence(s); + return self_type(shape); + } + + /** + * @name Extended copy semantic + */ + //@{ + /** + * The extended copy constructor. + */ + template + template + inline xarray_container::xarray_container(const xexpression& 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 + template + inline auto xarray_container::operator=(const xexpression& e) -> self_type& + { + return semantic_base::operator=(e); + } + //@} + + template + inline auto xarray_container::storage_impl() noexcept -> storage_type& + { + return m_storage; + } + + template + inline auto xarray_container::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 + inline xarray_adaptor::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 + inline xarray_adaptor::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 + template + inline xarray_adaptor::xarray_adaptor(D&& storage, const shape_type& shape, layout_type l) + : base_type(), m_storage(std::forward(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 + template + inline xarray_adaptor::xarray_adaptor(D&& storage, const shape_type& shape, const strides_type& strides) + : base_type(), m_storage(std::forward(storage)) + { + base_type::resize(shape, strides); + } + //@} + + template + inline auto xarray_adaptor::operator=(const xarray_adaptor& rhs) -> self_type& + { + base_type::operator=(rhs); + m_storage = rhs.m_storage; + return *this; + } + + template + inline auto xarray_adaptor::operator=(xarray_adaptor&& rhs) -> self_type& + { + base_type::operator=(std::move(rhs)); + m_storage = rhs.m_storage; + return *this; + } + + template + inline auto xarray_adaptor::operator=(temporary_type&& rhs) -> self_type& + { + base_type::shape_impl() = std::move(const_cast(rhs.shape())); + base_type::strides_impl() = std::move(const_cast(rhs.strides())); + base_type::backstrides_impl() = std::move(const_cast(rhs.backstrides())); + m_storage = std::move(rhs.storage()); + return *this; + } + + /** + * @name Extended copy semantic + */ + //@{ + /** + * The extended assignment operator. + */ + template + template + inline auto xarray_adaptor::operator=(const xexpression& e) -> self_type& + { + return semantic_base::operator=(e); + } + //@} + + template + inline auto xarray_adaptor::storage_impl() noexcept -> storage_type& + { + return m_storage; + } + + template + inline auto xarray_adaptor::storage_impl() const noexcept -> const storage_type& + { + return m_storage; + } +} + +#endif diff --git a/vendor/xtensor/include/xtensor/xassign.hpp b/vendor/xtensor/include/xtensor/xassign.hpp new file mode 100644 index 0000000000..1b2f4c00d2 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xassign.hpp @@ -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 +#include +#include + +#include + +#include "xconcepts.hpp" +#include "xexpression.hpp" +#include "xiterator.hpp" +#include "xstrides.hpp" +#include "xtensor_forward.hpp" +#include "xutils.hpp" + +namespace xt +{ + + /******************** + * Assign functions * + ********************/ + + template + void assign_data(xexpression& e1, const xexpression& e2, bool trivial); + + template + void assign_xexpression(xexpression& e1, const xexpression& e2); + + template + void computed_assign(xexpression& e1, const xexpression& e2); + + template + void scalar_computed_assign(xexpression& e1, const E2& e2, F&& f); + + template + void assert_compatible_shape(const xexpression& e1, const xexpression& e2); + + template + void strided_assign(E1& e1, const E2& e2, std::false_type /*disable*/); + + template + void strided_assign(E1& e1, const E2& e2, std::true_type /*enable*/); + + /************************ + * xexpression_assigner * + ************************/ + + template + class xexpression_assigner_base; + + template <> + class xexpression_assigner_base + { + public: + + template + static void assign_data(xexpression& e1, const xexpression& e2, bool trivial); + }; + + template + class xexpression_assigner : public xexpression_assigner_base + { + public: + + using base_type = xexpression_assigner_base; + + template + static void assign_xexpression(xexpression& e1, const xexpression& e2); + + template + static void computed_assign(xexpression& e1, const xexpression& e2); + + template + static void scalar_computed_assign(xexpression& e1, const E2& e2, F&& f); + + template + static void assert_compatible_shape(const xexpression& e1, const xexpression& e2); + + private: + + template + static bool resize(xexpression& e1, const xexpression& e2); + }; + + /***************** + * data_assigner * + *****************/ + + template + 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; + 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 + struct trivial_assigner + { + template + static void run(E1& e1, const E2& e2); + }; + + /*********************************** + * Assign functions implementation * + ***********************************/ + + template + inline void assign_data(xexpression& e1, const xexpression& e2, bool trivial) + { + using tag = xexpression_tag_t; + xexpression_assigner::assign_data(e1, e2, trivial); + } + + template + inline void assign_xexpression(xexpression& e1, const xexpression& e2) + { + xtl::mpl::static_if::value>([&](auto self) + { + self(e2).derived_cast().assign_to(e1); + }, /*else*/ [&](auto /*self*/) + { + using tag = xexpression_tag_t; + xexpression_assigner::assign_xexpression(e1, e2); + }); + } + + template + inline void computed_assign(xexpression& e1, const xexpression& e2) + { + using tag = xexpression_tag_t; + xexpression_assigner::computed_assign(e1, e2); + } + + template + inline void scalar_computed_assign(xexpression& e1, const E2& e2, F&& f) + { + using tag = xexpression_tag_t; + xexpression_assigner::scalar_computed_assign(e1, e2, std::forward(f)); + } + + template + inline void assert_compatible_shape(const xexpression& e1, const xexpression& e2) + { + using tag = xexpression_tag_t; + xexpression_assigner::assert_compatible_shape(e1, e2); + } + + /*************************************** + * xexpression_assigner implementation * + ***************************************/ + + namespace detail + { + template + 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 + inline bool is_trivial_broadcast(const xview&, const E2&) + { + return false; + } + + template > + struct forbid_simd_assign + { + static constexpr bool value = true; + }; + + // Double steps check for xfunction because the default + // parameter void_t of forbid_simd_assign prevents additional + // specializations. + template + struct xfunction_forbid_simd; + + template + struct forbid_simd_assign().template load_simd(typename E::size_type(0)))>> + { + static constexpr bool value = false || xfunction_forbid_simd::value; + }; + + template + struct xfunction_forbid_simd + { + static constexpr bool value = false; + }; + + template + struct xfunction_forbid_simd> + { + static constexpr bool value = xtl::disjunction< + std::integral_constant::type>::value>...>::value; + }; + + template + struct has_simd_apply : std::false_type {}; + + template + struct has_simd_apply)>> + : std::true_type + { + }; + + template + struct has_step_leading : std::false_type + { + }; + + template + struct has_step_leading().step_leading())>> + : std::true_type + { + }; + + template + struct use_strided_loop + { + static constexpr bool stepper_deref() { return std::is_reference::value; } + static constexpr bool value = has_strides::value && has_step_leading::value && stepper_deref(); + }; + + template + struct use_strided_loop> + { + static constexpr bool value = true; + }; + + template + struct use_strided_loop> + { + static constexpr bool value = xtl::conjunction>...>::value && + has_simd_apply>::value; + }; + } + + template + 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::value; } + static constexpr bool simd_size() { return xsimd::simd_traits::size > 1; } + static constexpr bool forbid_simd() { return detail::forbid_simd_assign::value; } + static constexpr bool simd_assign() { return contiguous_layout() && same_type() && simd_size() && !forbid_simd(); } + static constexpr bool simd_strided_loop() { return same_type() && simd_size() && detail::use_strided_loop::value && detail::use_strided_loop::value; } + }; + + template + inline void xexpression_assigner_base::assign_data(xexpression& e1, const xexpression& 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::simd_assign(); + trivial_assigner::run(de1, de2); + } + else if (xassign_traits::simd_strided_loop()) + { + strided_assign(de1, de2, std::integral_constant::simd_strided_loop()>{}); + } + else + { + data_assigner assigner(de1, de2); + assigner.run(); + } + } + + template + template + inline void xexpression_assigner::assign_xexpression(xexpression& e1, const xexpression& e2) + { + bool trivial_broadcast = resize(e1, e2); + base_type::assign_data(e1, e2, trivial_broadcast); + } + + template + template + inline void xexpression_assigner::computed_assign(xexpression& e1, const xexpression& 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(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 + template + inline void xexpression_assigner::scalar_computed_assign(xexpression& 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 + template + inline void xexpression_assigner::assert_compatible_shape(const xexpression& e1, const xexpression& 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 + template + inline bool xexpression_assigner::resize(xexpression& e1, const xexpression& 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(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 + inline data_assigner::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(e1.shape().size(), size_type(0))) + { + } + + template + inline void data_assigner::run() + { + using size_type = typename E1::size_type; + using argument_type = std::decay_t; + using result_type = std::decay_t; + constexpr bool is_narrowing = is_narrowing_conversion::value; + + size_type s = m_e1.size(); + for (size_type i = 0; i < s; ++i) + { + *m_lhs = conditional_cast(*m_rhs); + stepper_tools::increment_stepper(*this, m_index, m_e1.shape()); + } + } + + template + inline void data_assigner::step(size_type i) + { + m_lhs.step(i); + m_rhs.step(i); + } + + template + inline void data_assigner::step(size_type i, size_type n) + { + m_lhs.step(i, n); + m_rhs.step(i, n); + } + + template + inline void data_assigner::reset(size_type i) + { + m_lhs.reset(i); + m_rhs.reset(i); + } + + template + inline void data_assigner::to_end(layout_type l) + { + m_lhs.to_end(l); + m_rhs.to_end(l); + } + + /*********************************** + * trivial_assigner implementation * + ***********************************/ + + template + template + inline void trivial_assigner::run(E1& e1, const E2& e2) + { + using lhs_align_mode = xsimd::container_alignment_t; + constexpr bool is_aligned = std::is_same::value; + using rhs_align_mode = std::conditional_t; + using value_type = std::common_type_t; + using simd_type = xsimd::simd_type; + using 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(i, e2.template load_simd(i)); + } + for (size_type i = align_end; i < size; ++i) + { + e1.data_element(i) = e2.data_element(i); + } + } + + namespace assigner_detail + { + template + inline void assign_loop(It src, Ot dst, std::size_t n) + { + for(; n > 0; --n) + { + *dst = static_cast(*src); + ++src; + ++dst; + } + } + + template + inline void trivial_assigner_run_impl(E1& e1, const E2& e2, std::true_type) + { + using size_type = typename E1::size_type; + auto src = e2.storage_cbegin(); + auto dst = e1.storage_begin(); + assign_loop(src, dst, e1.size()); + } + + template + inline void trivial_assigner_run_impl(E1&, const E2&, std::false_type) + { + XTENSOR_PRECONDITION(false, + "Internal error: trivial_assigner called with unrelated types."); + } + } + + template <> + template + inline void trivial_assigner::run(E1& e1, const E2& e2) + { + using is_convertible = std::is_convertible::value_type, + typename std::decay_t::value_type>; + // If the types are not compatible, this function is still instantiated but never called. + // To avoid compilation problems in effectively unused code trivial_assigner_run_impl is + // empty in this case. + assigner_detail::trivial_assigner_run_impl(e1, e2, is_convertible()); + } + + /*********************** + * Strided assign loop * + ***********************/ + + namespace strided_assign_detail + { + template + struct idx_tools; + + template <> + struct idx_tools + { + template + 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 + { + template + 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 + 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 + std::enable_if_t + operator()(const T& el) + { + auto var = check_strides_overlap::get(m_strides, el.strides()); + if (var > m_cut) + { + m_cut = var; + } + return m_cut; + } + + template + std::enable_if_t + operator()(const T& el) + { + auto var = check_strides_overlap::get(m_strides, el.strides()); + if (var < m_cut) + { + m_cut = var; + } + return m_cut; + } + + template + std::size_t operator()(const xt::xscalar& /*el*/) + { + return m_cut; + } + + template + std::size_t operator()(const xt::xfunction& xf) + { + xt::for_each(*this, xf.arguments()); + return m_cut; + } + + private: + + std::size_t m_cut; + const strides_type& m_strides; + }; + + template + 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(e1.strides()); + cut = csf(e2); + } + else if (e1.strides().front() == 1) + { + auto csf = check_strides_functor(e1.strides()); + cut = csf(e2); + } + + using shape_value_type = typename E1::shape_type::value_type; + std::size_t outer_loop_size = static_cast( + std::accumulate(e1.shape().begin(), e1.shape().begin() + static_cast(cut), + shape_value_type(1), std::multiplies{})); + std::size_t inner_loop_size = static_cast( + std::accumulate(e1.shape().begin() + static_cast(cut), e1.shape().end(), + shape_value_type(1), std::multiplies{})); + + if (e1.strides().back() != 1) // column major mode + { + std::swap(outer_loop_size, inner_loop_size); + } + + return std::make_tuple(inner_loop_size, outer_loop_size, cut); + } + } + + template + 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 assigner(e1, e2); + assigner.run(); + return; + } + + // TODO can we get rid of this and use `shape_type`? + dynamic_shape 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(cut); + } + else + { + xt::resize_container(idx, e1.shape().size() - cut); + max_shape_begin = e1.shape().begin() + static_cast(cut); + max_shape_end = e1.shape().end(); + } + + // add this when we have std::array index! + // std::fill(idx.begin(), idx.end(), 0); + + dynamic_shape max(max_shape_begin, max_shape_end); + + using simd_type = xsimd::simd_type; + + 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(fct_stepper.template step_simd()); + } + 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::next_idx(idx, max) : + strided_assign_detail::idx_tools::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 + inline void strided_assign(E1& /*e1*/, const E2& /*e2*/, std::false_type /*disable*/) + { + } +} + +#endif diff --git a/vendor/xtensor/include/xtensor/xaxis_iterator.hpp b/vendor/xtensor/include/xtensor/xaxis_iterator.hpp new file mode 100644 index 0000000000..e544791b82 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xaxis_iterator.hpp @@ -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 + +#include "xview.hpp" + +namespace xt +{ + + /****************** + * xaxis_iterator * + ******************/ + + template + class xaxis_iterator + { + public: + + using self_type = xaxis_iterator; + + using xexpression_type = std::decay_t; + using size_type = typename xexpression_type::size_type; + using difference_type = typename xexpression_type::difference_type; + using value_type = xview; + using reference = std::remove_reference_t>; + using pointer = xtl::xclosure_pointer>>; + + using iterator_category = std::forward_iterator_tag; + + xaxis_iterator(); + template + 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; + mutable storing_type p_expression; + size_type m_index; + + template + std::enable_if_t::value, std::add_lvalue_reference_t>> + deref(T val) const; + + template + std::enable_if_t::value, T> + deref(T& val) const; + + template + std::enable_if_t::value, T> + get_storage_init(CTA&& e) const; + + template + std::enable_if_t::value, T> + get_storage_init(CTA&& e) const; + }; + + template + bool operator==(const xaxis_iterator& lhs, const xaxis_iterator& rhs); + + template + bool operator!=(const xaxis_iterator& lhs, const xaxis_iterator& rhs); + + template + auto axis_begin(E&& e); + + template + auto axis_end(E&& e); + + /********************************* + * xaxis_iterator implementation * + *********************************/ + + template + template + inline std::enable_if_t::value, std::add_lvalue_reference_t>> + xaxis_iterator::deref(T val) const + { + return *val; + } + + template + template + inline std::enable_if_t::value, T> + xaxis_iterator::deref(T& val) const + { + return val; + } + + template + template + inline std::enable_if_t::value, T> + xaxis_iterator::get_storage_init(CTA&& e) const + { + return &e; + } + + template + template + inline std::enable_if_t::value, T> + xaxis_iterator::get_storage_init(CTA&& e) const + { + return e; + } + + template + inline xaxis_iterator::xaxis_iterator() + : p_expression(nullptr), m_index(0) + { + } + + template + template + inline xaxis_iterator::xaxis_iterator(CTA&& e, size_type index) + : p_expression(get_storage_init(std::forward(e))), m_index(index) + { + } + + template + inline auto xaxis_iterator::operator++() -> self_type& + { + ++m_index; + return *this; + } + + template + inline auto xaxis_iterator::operator++(int) -> self_type + { + self_type tmp(*this); + ++(*this); + return tmp; + } + + template + inline auto xaxis_iterator::operator*() const -> reference + { + return view(deref(p_expression), size_type(m_index)); + } + + template + inline auto xaxis_iterator::operator->() const -> pointer + { + return xtl::closure_pointer(operator*()); + } + + template + inline bool xaxis_iterator::equal(const self_type& rhs) const + { + return p_expression == rhs.p_expression && m_index == rhs.m_index; + } + + template + inline bool operator==(const xaxis_iterator& lhs, const xaxis_iterator& rhs) + { + return lhs.equal(rhs); + } + + template + inline bool operator!=(const xaxis_iterator& lhs, const xaxis_iterator& rhs) + { + return !(lhs == rhs); + } + + template + inline auto axis_begin(E&& e) + { + using return_type = xaxis_iterator>; + using size_type = typename std::decay_t::size_type; + return return_type(std::forward(e), size_type(0)); + } + + template + inline auto axis_end(E&& e) + { + using return_type = xaxis_iterator>; + using size_type = typename std::decay_t::size_type; + return return_type(std::forward(e), size_type(e.shape()[0])); + } +} + +#endif diff --git a/vendor/xtensor/include/xtensor/xbroadcast.hpp b/vendor/xtensor/include/xtensor/xbroadcast.hpp new file mode 100644 index 0000000000..77c04f0416 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xbroadcast.hpp @@ -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 +#include +#include +#include +#include +#include +#include + +#include + +#include "xexpression.hpp" +#include "xiterable.hpp" +#include "xscalar.hpp" +#include "xstrides.hpp" +#include "xutils.hpp" + +namespace xt +{ + + /************* + * broadcast * + *************/ + + template + auto broadcast(E&& e, const S& s); + +#ifdef X_OLD_CLANG + template + auto broadcast(E&& e, std::initializer_list s); +#else + template + auto broadcast(E&& e, const I (&s)[L]); +#endif + + /************** + * xbroadcast * + **************/ + + template + class xbroadcast; + + template + struct xiterable_inner_types> + { + using xexpression_type = std::decay_t; + using inner_shape_type = promote_shape_t; + 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 xbroadcast : public xexpression>, + public xconst_iterable> + { + public: + + using self_type = xbroadcast; + using xexpression_type = std::decay_t; + + 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; + 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 + 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 + const_reference operator()(Args... args) const; + + template + const_reference at(Args... args) const; + + template + const_reference unchecked(Args... args) const; + + template + disable_integral_t operator[](const S& index) const; + template + const_reference operator[](std::initializer_list index) const; + const_reference operator[](size_type i) const; + + template + const_reference element(It first, It last) const; + + template + bool broadcast_shape(S& shape, bool reuse_cache = false) const; + + template + bool is_trivial_broadcast(const S& strides) const noexcept; + + template + const_stepper stepper_begin(const S& shape) const noexcept; + template + const_stepper stepper_end(const S& shape, layout_type l) const noexcept; + + template ::value>> + void assign_to(xexpression& 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 + inline auto broadcast(E&& e, const S& s) + { + using broadcast_type = xbroadcast, S>; + using shape_type = typename broadcast_type::shape_type; + return broadcast_type(std::forward(e), xtl::forward_sequence(s)); + } + +#ifdef X_OLD_CLANG + template + inline auto broadcast(E&& e, std::initializer_list s) + { + using broadcast_type = xbroadcast, std::vector>; + using shape_type = typename broadcast_type::shape_type; + return broadcast_type(std::forward(e), xtl::forward_sequence(s)); + } +#else + template + inline auto broadcast(E&& e, const I (&s)[L]) + { + using broadcast_type = xbroadcast, std::array>; + using shape_type = typename broadcast_type::shape_type; + return broadcast_type(std::forward(e), xtl::forward_sequence(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 + template + inline xbroadcast::xbroadcast(CTA&& e, S&& s) + : m_e(std::forward(e)), m_shape(std::forward(s)) + { + xt::broadcast_shape(m_e.shape(), m_shape); + } + //@} + + /** + * @name Size and shape + */ + /** + * Returns the size of the expression. + */ + template + inline auto xbroadcast::size() const noexcept -> size_type + { + return compute_size(shape()); + } + + /** + * Returns the number of dimensions of the expression. + */ + template + inline auto xbroadcast::dimension() const noexcept -> size_type + { + return m_shape.size(); + } + + /** + * Returns the shape of the expression. + */ + template + inline auto xbroadcast::shape() const noexcept -> const inner_shape_type& + { + return m_shape; + } + + /** + * Returns the layout_type of the expression. + */ + template + inline layout_type xbroadcast::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 + template + inline auto xbroadcast::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 + template + inline auto xbroadcast::at(Args... args) const -> const_reference + { + check_access(shape(), static_cast(args)...); + return this->operator()(args...); + } + + /** + * Returns a constant reference to the element at the specified position in the expression. + * @param args a list of indices specifying the position in the expression. Indices + * 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 a = {{0, 1}, {2, 3}}; + * xt::xarray b = {0, 1}; + * auto fd = a + b; + * double res = fd.uncheked(0, 1); + * \endcode + */ + template + template + inline auto xbroadcast::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 + template + inline auto xbroadcast::operator[](const S& index) const + -> disable_integral_t + { + return element(index.cbegin(), index.cend()); + } + + template + template + inline auto xbroadcast::operator[](std::initializer_list index) const -> const_reference + { + return element(index.begin(), index.end()); + } + + template + inline auto xbroadcast::operator[](size_type i) const -> const_reference + { + return operator()(i); + } + + /** + * Returns a constant reference to the element at the specified position in the expression. + * @param first iterator starting the sequence of indices + * @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 + template + inline auto xbroadcast::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 + template + inline bool xbroadcast::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 + template + inline bool xbroadcast::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 + template + inline auto xbroadcast::stepper_begin(const S& shape) const noexcept -> const_stepper + { + // Could check if (broadcastable(shape, m_shape) + return m_e.stepper_begin(shape); + } + + template + template + inline auto xbroadcast::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 + template + inline void xbroadcast::assign_to(xexpression& e) const + { + auto& ed = e.derived_cast(); + ed.resize(m_shape); + std::fill(ed.begin(), ed.end(), m_e()); + } +} + +#endif diff --git a/vendor/xtensor/include/xtensor/xbuffer_adaptor.hpp b/vendor/xtensor/include/xtensor/xbuffer_adaptor.hpp new file mode 100644 index 0000000000..d8d3316859 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xbuffer_adaptor.hpp @@ -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 +#include +#include +#include +#include + +#include + +#include "xstorage.hpp" + +namespace xt +{ + /****************************** + * xbuffer_adator declaration * + ******************************/ + + struct no_ownership + { + }; + + struct acquire_ownership + { + }; + + template >>> + class xbuffer_adaptor; + + /********************************* + * xbuffer_adator implementation * + *********************************/ + + namespace detail + { + template + class xbuffer_storage + { + public: + + using self_type = xbuffer_storage; + using allocator_type = A; + using value_type = typename allocator_type::value_type; + using reference = std::conditional_t>>::value, + typename allocator_type::const_reference, + typename allocator_type::reference>; + using const_reference = typename allocator_type::const_reference; + using pointer = std::conditional_t>>::value, + typename allocator_type::const_pointer, + typename allocator_type::pointer>; + using const_pointer = typename allocator_type::const_pointer; + using size_type = typename allocator_type::size_type; + using difference_type = typename allocator_type::difference_type; + + xbuffer_storage(); + + template + 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 xbuffer_owner_storage + { + public: + + using self_type = xbuffer_owner_storage; + using allocator_type = A; + using value_type = typename allocator_type::value_type; + using reference = std::conditional_t>>::value, + typename allocator_type::const_reference, + typename allocator_type::reference>; + using const_reference = typename allocator_type::const_reference; + using pointer = std::conditional_t>>::value, + typename allocator_type::const_pointer, + typename allocator_type::pointer>; + using const_pointer = typename allocator_type::const_pointer; + using size_type = typename allocator_type::size_type; + using difference_type = typename allocator_type::difference_type; + + xbuffer_owner_storage() = default; + + template + 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 m_data; + size_type m_size; + bool m_moved_from; + allocator_type m_allocator; + }; + + template + struct get_buffer_storage + { + using type = xbuffer_storage; + }; + + template + struct get_buffer_storage + { + using type = xbuffer_owner_storage; + }; + + template + using buffer_storage_t = typename get_buffer_storage::type; + } + + template + class xbuffer_adaptor : private detail::buffer_storage_t + { + public: + + using base_type = detail::buffer_storage_t; + using self_type = xbuffer_adaptor; + using allocator_type = typename base_type::allocator_type; + using value_type = typename base_type::value_type; + using reference = typename base_type::reference; + using const_reference = typename base_type::const_reference; + using pointer = typename base_type::pointer; + using const_pointer = typename base_type::const_pointer; + using temporary_type = uvector; + + using size_type = typename base_type::size_type; + using difference_type = typename base_type::difference_type; + + using iterator = pointer; + using const_iterator = const_pointer; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + xbuffer_adaptor() = default; + + template + 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 + bool operator==(const xbuffer_adaptor& lhs, + const xbuffer_adaptor& rhs); + + template + bool operator!=(const xbuffer_adaptor& lhs, + const xbuffer_adaptor& rhs); + + template + bool operator<(const xbuffer_adaptor& lhs, + const xbuffer_adaptor& rhs); + + template + bool operator<=(const xbuffer_adaptor& lhs, + const xbuffer_adaptor& rhs); + + template + bool operator>(const xbuffer_adaptor& lhs, + const xbuffer_adaptor& rhs); + + template + bool operator>=(const xbuffer_adaptor& lhs, + const xbuffer_adaptor& rhs); + + template + void swap(xbuffer_adaptor& lhs, + xbuffer_adaptor& rhs) noexcept; + + /************************************ + * temporary_container metafunction * + ************************************/ + + template + struct temporary_container + { + using type = C; + }; + + template + struct temporary_container> + { + using type = typename xbuffer_adaptor::temporary_type; + }; + + template + using temporary_container_t = typename temporary_container::type; + + /********************************** + * xbuffer_storage implementation * + **********************************/ + + namespace detail + { + template + inline xbuffer_storage::xbuffer_storage() + : p_data(nullptr), m_size(0) + { + } + + template + template + inline xbuffer_storage::xbuffer_storage(P&& data, size_type size, const allocator_type&) + : p_data(std::forward

(data)), m_size(size) + { + } + + template + inline auto xbuffer_storage::size() const noexcept -> size_type + { + return m_size; + } + + template + inline void xbuffer_storage::resize(size_type size) + { + if (size != m_size) + { + throw std::runtime_error("xbuffer_storage not resizable"); + } + } + + template + inline auto xbuffer_storage::data() noexcept -> pointer + { + return p_data; + } + + template + inline auto xbuffer_storage::data() const noexcept -> const_pointer + { + return p_data; + } + + template + inline void xbuffer_storage::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 + template + inline xbuffer_owner_storage::xbuffer_owner_storage(P&& data, size_type size, const allocator_type& alloc) + : m_data(std::forward

(data)), m_size(size), m_moved_from(false), m_allocator(alloc) + { + } + + template + inline xbuffer_owner_storage::~xbuffer_owner_storage() + { + if (!m_moved_from) + { + safe_destroy_deallocate(m_allocator, m_data.get(), m_size); + m_size = 0; + } + } + + template + inline auto xbuffer_owner_storage::operator=(const self_type& rhs) -> self_type& + { + using std::swap; + if (this != &rhs) + { + allocator_type al = std::allocator_traits::select_on_container_copy_construction(rhs.get_allocator()); + pointer tmp = safe_init_allocate(al, rhs.m_size); + if (xtrivially_default_constructible::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 + inline xbuffer_owner_storage::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 + inline auto xbuffer_owner_storage::operator=(self_type&& rhs) -> self_type& + { + swap(rhs); + rhs.m_moved_from = true; + return *this; + } + + template + inline auto xbuffer_owner_storage::size() const noexcept -> size_type + { + return m_size; + } + + template + void xbuffer_owner_storage::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 + inline auto xbuffer_owner_storage::data() noexcept -> pointer + { + return m_data.get(); + } + + template + inline auto xbuffer_owner_storage::data() const noexcept -> const_pointer + { + return m_data.get(); + } + + template + inline auto xbuffer_owner_storage::get_allocator() const noexcept -> allocator_type + { + return allocator_type(m_allocator); + } + + template + inline void xbuffer_owner_storage::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 + template + inline xbuffer_adaptor::xbuffer_adaptor(P&& data, size_type size, const allocator_type& alloc) + : base_type(std::forward

(data), size, alloc) + { + } + + template + inline auto xbuffer_adaptor::operator=(temporary_type&& tmp) -> self_type& + { + base_type::resize(tmp.size()); + std::copy(tmp.cbegin(), tmp.cend(), begin()); + return *this; + } + + template + bool xbuffer_adaptor::empty() const noexcept + { + return size() == 0; + } + + template + inline auto xbuffer_adaptor::operator[](size_type i) -> reference + { + return data()[i]; + } + + template + inline auto xbuffer_adaptor::operator[](size_type i) const -> const_reference + { + return data()[i]; + } + + template + inline auto xbuffer_adaptor::front() -> reference + { + return data()[0]; + } + + template + inline auto xbuffer_adaptor::front() const -> const_reference + { + return data()[0]; + } + + template + inline auto xbuffer_adaptor::back() -> reference + { + return data()[size() - 1]; + } + + template + inline auto xbuffer_adaptor::back() const -> const_reference + { + return data()[size() - 1]; + } + + template + inline auto xbuffer_adaptor::begin() -> iterator + { + return data(); + } + + template + inline auto xbuffer_adaptor::end() -> iterator + { + return data() + size(); + } + + template + inline auto xbuffer_adaptor::begin() const -> const_iterator + { + return data(); + } + + template + inline auto xbuffer_adaptor::end() const -> const_iterator + { + return data() + size(); + } + + template + inline auto xbuffer_adaptor::cbegin() const -> const_iterator + { + return begin(); + } + + template + inline auto xbuffer_adaptor::cend() const -> const_iterator + { + return end(); + } + + template + inline auto xbuffer_adaptor::rbegin() -> reverse_iterator + { + return reverse_iterator(end()); + } + + template + inline auto xbuffer_adaptor::rend() -> reverse_iterator + { + return reverse_iterator(begin()); + } + + template + inline auto xbuffer_adaptor::rbegin() const -> const_reverse_iterator + { + return const_reverse_iterator(end()); + } + + template + inline auto xbuffer_adaptor::rend() const -> const_reverse_iterator + { + return const_reverse_iterator(begin()); + } + + template + inline auto xbuffer_adaptor::crbegin() const -> const_reverse_iterator + { + return rbegin(); + } + + template + inline auto xbuffer_adaptor::crend() const -> const_reverse_iterator + { + return rend(); + } + + template + inline bool operator==(const xbuffer_adaptor& lhs, + const xbuffer_adaptor& rhs) + { + return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + + template + inline bool operator!=(const xbuffer_adaptor& lhs, + const xbuffer_adaptor& rhs) + { + return !(lhs == rhs); + } + + template + inline bool operator<(const xbuffer_adaptor& lhs, + const xbuffer_adaptor& rhs) + { + return std::lexicographical_compare(lhs.begin(), lhs.end(), + rhs.begin(), rhs.end(), + std::less()); + } + + template + inline bool operator<=(const xbuffer_adaptor& lhs, + const xbuffer_adaptor& rhs) + { + return std::lexicographical_compare(lhs.begin(), lhs.end(), + rhs.begin(), rhs.end(), + std::less_equal()); + } + + template + inline bool operator>(const xbuffer_adaptor& lhs, + const xbuffer_adaptor& rhs) + { + return std::lexicographical_compare(lhs.begin(), lhs.end(), + rhs.begin(), rhs.end(), + std::greater()); + } + + template + inline bool operator>=(const xbuffer_adaptor& lhs, + const xbuffer_adaptor& rhs) + { + return std::lexicographical_compare(lhs.begin(), lhs.end(), + rhs.begin(), rhs.end(), + std::greater_equal()); + } + + template + inline void swap(xbuffer_adaptor& lhs, + xbuffer_adaptor& rhs) noexcept + { + lhs.swap(rhs); + } +} + +#endif diff --git a/vendor/xtensor/include/xtensor/xbuilder.hpp b/vendor/xtensor/include/xtensor/xbuilder.hpp new file mode 100644 index 0000000000..c3e34b8ac3 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xbuilder.hpp @@ -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 +#include +#include +#include +#include +#include +#ifdef X_OLD_CLANG + #include +#endif + +#include +#include + +#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 + inline auto ones(S shape) noexcept + { + return broadcast(T(1), std::forward(shape)); + } + +#ifdef X_OLD_CLANG + template + inline auto ones(std::initializer_list shape) noexcept + { + return broadcast(T(1), shape); + } +#else + template + 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 + inline auto zeros(S shape) noexcept + { + return broadcast(T(0), std::forward(shape)); + } + +#ifdef X_OLD_CLANG + template + inline auto zeros(std::initializer_list shape) noexcept + { + return broadcast(T(0), shape); + } +#else + template + 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`` + * - ``std::array`` or ``initializer_list`` → ``xtensor`` + * - ``xshape`` → ``xtensor_fixed>`` + * + * @param shape shape of the new xcontainer + */ + template + inline xarray empty(const S& shape) + { + return xarray::from_shape(shape); + } + + template + inline xtensor empty(const std::array& shape) + { + using shape_type = typename xtensor::shape_type; + return xtensor(xtl::forward_sequence(shape)); + } + +#ifndef X_OLD_CLANG + template + inline xtensor empty(const I(&shape)[N]) + { + using shape_type = typename xtensor::shape_type; + return xtensor(xtl::forward_sequence(shape)); + } +#endif + + template + inline xtensor_fixed, L> empty(const fixed_shape& /*shape*/) + { + return xtensor_fixed, 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 + inline typename E::temporary_type empty_like(const xexpression& 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 + inline typename E::temporary_type full_like(const xexpression& 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(e.shape());` for a lazy version. + * + * @param e the xexpression from which to extract shape, value type and layout. + */ + template + inline typename E::temporary_type zeros_like(const xexpression& 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(e.shape());`` for a lazy version. + * + * @param e the xexpression from which to extract shape, value type and layout. + */ + template + inline typename E::temporary_type ones_like(const xexpression& e) + { + return full_like(e, typename E::value_type(1)); + } + + namespace detail + { + template + 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 + inline T operator()(Args... args) const + { + return access_impl(args...); + } + + template + inline T element(It first, It) const + { + return m_start + m_step * T(*first); + } + + template + inline void assign_to(xexpression& e) const noexcept + { + auto& de = e.derived_cast(); + value_type value = m_start; + + for (auto& el : de.storage()) + { + el = value; + value += m_step; + } + } + + private: + + value_type m_start; + value_type m_stop; + value_type m_step; + + template + 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 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 + inline value_type operator()(Args... args) const + { + size_type idx[sizeof...(Args)] = {static_cast(args)...}; + return access_impl(std::begin(idx), std::end(idx)); + } + + template + inline value_type element(It first, It last) const + { + return access_impl(first, last); + } + + private: + + F m_ft; + template + inline value_type access_impl(const It& begin, const It& end) const + { + return m_ft(begin, end); + } + }; + + template + class eye_fn + { + public: + + using value_type = T; + + eye_fn(int k) + : m_k(k) + { + } + + template + inline T operator()(const It& /*begin*/, const It& end) const + { + using lvalue_type = typename std::iterator_traits::value_type; + return *(end - 1) == *(end - 2) + static_cast(static_cast(m_k)) ? T(1) : T(0); + } + + 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 + inline auto eye(const std::vector& shape, int k = 0) + { + return detail::make_xgenerator(detail::fn_impl>(detail::eye_fn(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 + inline auto eye(std::size_t n, int k = 0) + { + return eye({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 + inline auto arange(T start, T stop, T step = 1) noexcept + { + std::size_t shape = static_cast(std::ceil((stop - start) / step)); + return detail::make_xgenerator(detail::arange_impl(start, stop, step), {shape}); + } + + /** + * 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 + inline auto arange(T stop) noexcept + { + return arange(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 + inline auto linspace(T start, T stop, std::size_t num_samples = 50, bool endpoint = true) noexcept + { + using fp_type = std::common_type_t; + fp_type step = fp_type(stop - start) / fp_type(num_samples - (endpoint ? 1 : 0)); + return cast(detail::make_xgenerator(detail::arange_impl(fp_type(start), fp_type(stop), step), {num_samples})); + } + + /** + * 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 + inline auto logspace(T start, T stop, std::size_t num_samples, T base = 10, bool endpoint = true) noexcept + { + return cast(pow(std::move(base), linspace(start, stop, num_samples, endpoint))); + } + + namespace detail + { + template + class concatenate_impl + { + public: + + using size_type = std::size_t; + using value_type = promote_type_t::value_type...>; + + inline concatenate_impl(std::tuple&& t, size_type axis) + : m_t(t), m_axis(axis) + { + } + + template + inline value_type operator()(Args... args) const + { + // TODO: avoid memory allocation + return access_impl(xindex({static_cast(args)...})); + } + + template + 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(i, match, m_t)) + { + break; + } + } + return apply(i, get, m_t); + } + + std::tuple m_t; + size_type m_axis; + }; + + template + class stack_impl + { + public: + + using size_type = std::size_t; + using value_type = promote_type_t::value_type...>; + + inline stack_impl(std::tuple&& t, size_type axis) + : m_t(t), m_axis(axis) + { + } + + template + inline value_type operator()(Args... args) const + { + // TODO: avoid memory allocation + return access_impl(xindex({static_cast(args)...})); + } + + template + 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(i, get_item, m_t); + } + + const std::tuple m_t; + const size_type m_axis; + }; + + template + class repeat_impl + { + public: + + using xexpression_type = std::decay_t; + using size_type = typename xexpression_type::size_type; + using value_type = typename xexpression_type::value_type; + + template + repeat_impl(CTA&& source, size_type axis) + : m_source(std::forward(source)), m_axis(axis) + { + } + + template + value_type operator()(Args... args) const + { + std::array args_arr = {static_cast(args)...}; + return m_source(args_arr[m_axis]); + } + + template + inline value_type element(It first, It) const + { + return m_source(*(first + static_cast(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 + inline auto xtuple(Types&&... args) + { + return std::tuple...>(std::forward(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 a = {{1, 2, 3}}; + * xt::xarray b = {{2, 3, 4}}; + * xt::xarray c = xt::concatenate(xt::xtuple(a, b)); // => {{1, 2, 3}, + * {2, 3, 4}} + * xt::xarray d = xt::concatenate(xt::xtuple(a, b), 1); // => {{1, 2, 3, 2, 3, 4}} + * \endcode + */ + template + inline auto concatenate(std::tuple&& t, std::size_t axis = 0) + { + using shape_type = promote_shape_t::shape_type...>; + shape_type new_shape = xtl::forward_sequence(std::get<0>(t).shape()); + auto shape_at_axis = [&axis](std::size_t prev, auto& arr) -> std::size_t { + return prev + arr.shape()[axis]; + }; + new_shape[axis] += accumulate(shape_at_axis, std::size_t(0), t) - new_shape[axis]; + return detail::make_xgenerator(detail::concatenate_impl(std::forward>(t), axis), new_shape); + } + + namespace detail + { + template + inline std::array add_axis(std::array arr, std::size_t axis, std::size_t value) + { + std::array 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 + 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 a = {1, 2, 3}; + * xt::xarray b = {5, 6, 7}; + * xt::xarray s = xt::stack(xt::xtuple(a, b)); // => {{1, 2, 3}, + * {5, 6, 7}} + * xt::xarray t = xt::stack(xt::xtuple(a, b), 1); // => {{1, 5}, + * {2, 6}, + * {3, 7}} + * \endcode + */ + template + inline auto stack(std::tuple&& t, std::size_t axis = 0) + { + using shape_type = promote_shape_t::shape_type...>; + auto new_shape = detail::add_axis(xtl::forward_sequence(std::get<0>(t).shape()), axis, sizeof...(CT)); + return detail::make_xgenerator(detail::stack_impl(std::forward>(t), axis), new_shape); + } + + namespace detail + { + + template + inline auto meshgrid_impl(std::index_sequence, E&&... e) noexcept + { +#if defined X_OLD_CLANG || defined _MSC_VER + const std::array shape = {e.shape()[0]...}; + return std::make_tuple( + detail::make_xgenerator( + detail::repeat_impl>(std::forward(e), I), + shape + )... + ); +#else + return std::make_tuple( + detail::make_xgenerator( + detail::repeat_impl>(std::forward(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 + inline auto meshgrid(E&&... e) noexcept + { + return detail::meshgrid_impl(std::make_index_sequence(), std::forward(e)...); + } + + namespace detail + { + template + class diagonal_fn + { + public: + + using xexpression_type = std::decay_t; + using value_type = typename xexpression_type::value_type; + + template + diagonal_fn(CTA&& source, int offset, std::size_t axis_1, std::size_t axis_2) + : m_source(std::forward(source)), m_offset(offset), m_axis_1(axis_1), m_axis_2(axis_2) + { + } + + template + 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::value_type; + it_vtype uoffset = static_cast(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 diag_fn + { + public: + + using xexpression_type = std::decay_t; + using value_type = typename xexpression_type::value_type; + + template + diag_fn(CTA&& source, int k) + : m_source(std::forward(source)), m_k(k) + { + } + + template + inline value_type operator()(It begin, It) const + { + using it_vtype = typename std::iterator_traits::value_type; + it_vtype umk = static_cast(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 trilu_fn + { + public: + + using xexpression_type = std::decay_t; + using value_type = typename xexpression_type::value_type; + using signed_idx_type = long int; + + template + trilu_fn(CTA&& source, int k, Comp comp) + : m_source(std::forward(source)), m_k(k), m_comp(comp) + { + } + + template + 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 + struct diagonal_shape_type + { + using type = ST; + }; + + template + struct diagonal_shape_type> + { + using type = std::array; + }; + } + + /** + * @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 a = {{1, 2, 3}, + * {4, 5, 6} + * {7, 8, 9}}; + * auto b = xt::diagonal(a); // => {1, 5, 9} + * \endcode + */ + template + inline auto diagonal(E&& arr, int offset = 0, std::size_t axis_1 = 0, std::size_t axis_2 = 1) + { + using CT = xclosure_t; + using shape_type = typename detail::diagonal_shape_type::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(dimension - 1, 0); + int dim_1 = static_cast(shape[axis_1]); + int dim_2 = static_cast(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(std::forward(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 a = {1, 5, 9}; + * auto b = xt::diag(a); // => {{1, 0, 0}, + * // {0, 5, 0}, + * // {0, 0, 9}} + * \endcode + */ + template + inline auto diag(E&& arr, int k = 0) + { + using CT = xclosure_t; + 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(std::forward(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 + inline auto tril(E&& arr, int k = 0) + { + using CT = xclosure_t; + auto shape = arr.shape(); + return detail::make_xgenerator(detail::fn_impl>>( + detail::trilu_fn>(std::forward(arr), k, std::greater_equal())), + 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 + inline auto triu(E&& arr, int k = 0) + { + using CT = xclosure_t; + auto shape = arr.shape(); + return detail::make_xgenerator(detail::fn_impl>>( + detail::trilu_fn>(std::forward(arr), k, std::less_equal())), + shape); + } +} +#endif diff --git a/vendor/xtensor/include/xtensor/xcomplex.hpp b/vendor/xtensor/include/xtensor/xcomplex.hpp new file mode 100644 index 0000000000..e47842aa11 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xcomplex.hpp @@ -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 +#include + +#include + +#include "xtensor/xbuilder.hpp" +#include "xtensor/xexpression.hpp" +#include "xtensor/xoffset_view.hpp" + +namespace xt +{ + + /****************************** + * real and imag declarations * + ******************************/ + + template + decltype(auto) real(E&& e) noexcept; + + template + decltype(auto) imag(E&& e) noexcept; + + /******************************** + * real and imag implementation * + ********************************/ + + namespace detail + { + template + struct complex_helper + { + template + static inline auto real(E&& e) noexcept + { + using real_type = typename std::decay_t::value_type::value_type; + return xoffset_view, real_type, 0>(std::forward(e)); + } + + template + static inline auto imag(E&& e) noexcept + { + using real_type = typename std::decay_t::value_type::value_type; + return xoffset_view, real_type, sizeof(real_type)>(std::forward(e)); + } + }; + + template <> + struct complex_helper + { + template + static inline decltype(auto) real(E&& e) noexcept + { + return e; + } + + template + static inline auto imag(E&& e) noexcept + { + return zeros::value_type>(e.shape()); + } + }; + + template + struct complex_expression_helper + { + template + static inline auto real(E&& e) noexcept + { + return detail::complex_helper::value_type>::value>::real(e); + } + + template + static inline auto imag(E&& e) noexcept + { + return detail::complex_helper::value_type>::value>::imag(e); + } + }; + + template <> + struct complex_expression_helper + { + template + static inline decltype(auto) real(E&& e) noexcept + { + return xtl::forward_real(std::forward(e)); + } + + template + static inline decltype(auto) imag(E&& e) noexcept + { + return xtl::forward_imag(std::forward(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 + inline decltype(auto) real(E&& e) noexcept + { + return detail::complex_expression_helper>::value>::real(std::forward(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 + inline decltype(auto) imag(E&& e) noexcept + { + return detail::complex_expression_helper>::value>::imag(std::forward(e)); + } + +#define UNARY_COMPLEX_FUNCTOR(NAME) \ + template \ + struct NAME##_fun \ + { \ + using argument_type = T; \ + using result_type = decltype(std::NAME(std::declval())); \ + 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 instead of T. + template + constexpr T conj(const T& c) + { + return c; + } + + template + constexpr std::complex conj(const std::complex& c) + { + return std::complex(c.real(), -c.imag()); + } + } + + template + struct conj_fun + { + using argument_type = T; + using result_type = decltype(detail::conj(std::declval())); + using simd_value_type = xsimd::simd_type; + constexpr result_type operator()(const T& t) const + { + return detail::conj(t); + } + constexpr simd_value_type simd_apply(const simd_value_type& t) const + { + return detail::conj(t); + } + }; + } + +#undef UNARY_COMPLEX_FUNCTOR + + /** + * @brief Returns an \ref xfunction evaluating to the complex conjugate of the given expression. + * + * @param e the \ref xexpression + */ + template + inline auto conj(E&& e) noexcept + { + using value_type = typename std::decay_t::value_type; + using functor = math::conj_fun; + using result_type = typename functor::result_type; + using type = xfunction>; + return type(functor(), std::forward(e)); + } + + /** + * @brief Calculates the phase angle (in radians) elementwise for the complex numbers in e. + * @param e the \ref xexpression + */ + template + inline auto arg(E&& e) noexcept + { + using value_type = typename std::decay_t::value_type; + using functor = math::arg_fun; + using result_type = typename functor::result_type; + using type = xfunction>; + return type(functor(), std::forward(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 + inline auto angle(E&& e, bool deg = false) noexcept + { + using value_type = xtl::complex_value_type_t::value_type>; + value_type multiplier = 1.0; + if (deg) + { + multiplier = value_type(180) / numeric_constants::PI; + } + return arg(std::forward(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 + inline auto norm(E&& e) noexcept + { + using value_type = typename std::decay_t::value_type; + using functor = math::norm_fun; + using result_type = typename functor::result_type; + using type = xfunction>; + return type(functor(), std::forward(e)); + } +} +#endif diff --git a/vendor/xtensor/include/xtensor/xconcepts.hpp b/vendor/xtensor/include/xtensor/xconcepts.hpp new file mode 100644 index 0000000000..1845c6b033 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xconcepts.hpp @@ -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 + +/***************************************************** + * concept checking and type inference functionality * + *****************************************************/ + +namespace xt +{ + + /****************************************** + * XTENSOR_REQUIRE concept checking macro * + ******************************************/ + + struct concept_check_successful + { + }; + + template + using concept_check = typename std::enable_if::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 ::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' value member + is true: + \code + template ::value>> + T foo(T t) + {...} + \endcode + */ + template + struct iterator_concept + { + using V = std::decay_t; + + static char test(...); + + template + static int test(U*, typename U::iterator_category* = 0); + + static const bool value = + std::is_array::value || + std::is_pointer::value || + std::is_same())), 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. int64_t or double) + to a smaller type (e.g. int32_t), 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 is_narrowing_conversion::value is true. Currently, + the check is only implemented for built-in types, i.e. types where std::is_arithmetic + is true. + */ + template + struct is_narrowing_conversion + { + using argument_type = std::decay_t; + using result_type = std::decay_t; + + static const bool value = std::is_arithmetic::value && + (sizeof(result_type) < sizeof(argument_type) || + (std::is_integral::value && std::is_floating_point::value)); + }; +} // namespace xt + +#endif // XCONCEPTS_HPP diff --git a/vendor/xtensor/include/xtensor/xcontainer.hpp b/vendor/xtensor/include/xtensor/xcontainer.hpp new file mode 100644 index 0000000000..80df1907f9 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xcontainer.hpp @@ -0,0 +1,1418 @@ +/*************************************************************************** +* 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_CONTAINER_HPP +#define XTENSOR_CONTAINER_HPP + +#include +#include +#include +#include +#include + +#include +#include + +#include "xiterable.hpp" +#include "xiterator.hpp" +#include "xmath.hpp" +#include "xoperation.hpp" +#include "xstrides.hpp" +#include "xtensor_forward.hpp" + +namespace xt +{ + template + struct xcontainer_iterable_types + { + using inner_shape_type = typename xcontainer_inner_types::inner_shape_type; + using storage_type = typename xcontainer_inner_types::storage_type; + using stepper = xstepper; + using const_stepper = xstepper; + }; + +#define DL XTENSOR_DEFAULT_LAYOUT + + namespace detail + { + template + struct allocator_type_impl + { + using type = typename T::allocator_type; + }; + + template + struct allocator_type_impl> + { + using type = std::allocator; // fake allocator for testing + }; + } + + template + using allocator_type_t = typename detail::allocator_type_impl::type; + + + /** + * @class xcontainer + * @brief Base class for dense multidimensional containers. + * + * The xcontainer class defines the interface for dense multidimensional + * container classes. It does not embed any data container, this responsibility + * is delegated to the inheriting classes. + * + * @tparam D The derived type, i.e. the inheriting class for which xcontainer + * provides the interface. + */ + template + class xcontainer : private xiterable + { + public: + + using derived_type = D; + + using inner_types = xcontainer_inner_types; + using storage_type = typename inner_types::storage_type; + using allocator_type = allocator_type_t>; + using value_type = typename storage_type::value_type; + using reference = std::conditional_t::value, + typename storage_type::const_reference, + typename storage_type::reference>; + using const_reference = typename storage_type::const_reference; + using pointer = typename storage_type::pointer; + using const_pointer = typename storage_type::const_pointer; + using size_type = typename storage_type::size_type; + using difference_type = typename storage_type::difference_type; + using simd_value_type = xsimd::simd_type; + + using shape_type = typename inner_types::shape_type; + using strides_type = typename inner_types::strides_type; + using backstrides_type = typename inner_types::backstrides_type; + + using inner_shape_type = typename inner_types::inner_shape_type; + using inner_strides_type = typename inner_types::inner_strides_type; + using inner_backstrides_type = typename inner_types::inner_backstrides_type; + + using iterable_base = xiterable; + using stepper = typename iterable_base::stepper; + using const_stepper = typename iterable_base::const_stepper; + + static constexpr layout_type static_layout = inner_types::layout; + static constexpr bool contiguous_layout = static_layout != layout_type::dynamic; + using data_alignment = xsimd::container_alignment_t; + using simd_type = xsimd::simd_type; + + static_assert(static_layout != layout_type::any, "Container layout can never be layout_type::any!"); + + size_type size() const noexcept; + + constexpr size_type dimension() const noexcept; + + constexpr const inner_shape_type& shape() const noexcept; + constexpr const inner_strides_type& strides() const noexcept; + constexpr const inner_backstrides_type& backstrides() const noexcept; + + template + void fill(const T& value); + + template + reference operator()(Args... args); + + template + const_reference operator()(Args... args) const; + + template + reference at(Args... args); + + template + const_reference at(Args... args) const; + + template + reference unchecked(Args... args); + + template + const_reference unchecked(Args... args) const; + + template + disable_integral_t operator[](const S& index); + template + reference operator[](std::initializer_list index); + reference operator[](size_type i); + + template + disable_integral_t operator[](const S& index) const; + template + const_reference operator[](std::initializer_list index) const; + const_reference operator[](size_type i) const; + + template + reference element(It first, It last); + template + const_reference element(It first, It last) const; + + storage_type& storage() noexcept; + const storage_type& storage() const noexcept; + + value_type* data() noexcept; + const value_type* data() const noexcept; + const size_type data_offset() const noexcept; + + template + bool broadcast_shape(S& shape, bool reuse_cache = false) const; + + template + bool is_trivial_broadcast(const S& strides) const noexcept; + + template + stepper stepper_begin(const S& shape) noexcept; + template + stepper stepper_end(const S& shape, layout_type l) noexcept; + + template + const_stepper stepper_begin(const S& shape) const noexcept; + template + const_stepper stepper_end(const S& shape, layout_type l) const noexcept; + + reference data_element(size_type i); + const_reference data_element(size_type i) const; + + template + using simd_return_type = xsimd::simd_return_type; + + template + void store_simd(size_type i, const simd& e); + template + simd_return_type load_simd(size_type i) const; + +#if defined(_MSC_VER) && _MSC_VER >= 1910 + // Workaround for compiler bug in Visual Studio 2017 with respect to alias templates with non-type parameters. + template + using layout_iterator = xiterator; + template + using const_layout_iterator = xiterator; + template + using reverse_layout_iterator = std::reverse_iterator>; + template + using const_reverse_layout_iterator = std::reverse_iterator>; +#else + template + using layout_iterator = typename iterable_base::template layout_iterator; + template + using const_layout_iterator = typename iterable_base::template const_layout_iterator; + template + using reverse_layout_iterator = typename iterable_base::template reverse_layout_iterator; + template + using const_reverse_layout_iterator = typename iterable_base::template const_reverse_layout_iterator; +#endif + + template + using broadcast_iterator = typename iterable_base::template broadcast_iterator; + template + using const_broadcast_iterator = typename iterable_base::template const_broadcast_iterator; + template + using reverse_broadcast_iterator = typename iterable_base::template reverse_broadcast_iterator; + template + using const_reverse_broadcast_iterator = typename iterable_base::template const_reverse_broadcast_iterator; + + using storage_iterator = typename storage_type::iterator; + using const_storage_iterator = typename storage_type::const_iterator; + using reverse_storage_iterator = typename storage_type::reverse_iterator; + using const_reverse_storage_iterator = typename storage_type::const_reverse_iterator; + + template + using select_iterator_impl = std::conditional_t; + + template + using select_iterator = select_iterator_impl>; + template + using select_const_iterator = select_iterator_impl>; + template + using select_reverse_iterator = select_iterator_impl>; + template + using select_const_reverse_iterator = select_iterator_impl>; + + using iterator = select_iterator

; + using const_iterator = select_const_iterator
; + using reverse_iterator = select_reverse_iterator
; + using const_reverse_iterator = select_const_reverse_iterator
; + + template + select_iterator begin() noexcept; + template + select_iterator end() noexcept; + + template + select_const_iterator begin() const noexcept; + template + select_const_iterator end() const noexcept; + template + select_const_iterator cbegin() const noexcept; + template + select_const_iterator cend() const noexcept; + + template + select_reverse_iterator rbegin() noexcept; + template + select_reverse_iterator rend() noexcept; + + template + select_const_reverse_iterator rbegin() const noexcept; + template + select_const_reverse_iterator rend() const noexcept; + template + select_const_reverse_iterator crbegin() const noexcept; + template + select_const_reverse_iterator crend() const noexcept; + + template + broadcast_iterator begin(const S& shape) noexcept; + template + broadcast_iterator end(const S& shape) noexcept; + + template + const_broadcast_iterator begin(const S& shape) const noexcept; + template + const_broadcast_iterator end(const S& shape) const noexcept; + template + const_broadcast_iterator cbegin(const S& shape) const noexcept; + template + const_broadcast_iterator cend(const S& shape) const noexcept; + + + template + reverse_broadcast_iterator rbegin(const S& shape) noexcept; + template + reverse_broadcast_iterator rend(const S& shape) noexcept; + + template + const_reverse_broadcast_iterator rbegin(const S& shape) const noexcept; + template + const_reverse_broadcast_iterator rend(const S& shape) const noexcept; + template + const_reverse_broadcast_iterator crbegin(const S& shape) const noexcept; + template + const_reverse_broadcast_iterator crend(const S& shape) const noexcept; + + template + storage_iterator storage_begin() noexcept; + template + storage_iterator storage_end() noexcept; + + template + const_storage_iterator storage_begin() const noexcept; + template + const_storage_iterator storage_end() const noexcept; + template + const_storage_iterator storage_cbegin() const noexcept; + template + const_storage_iterator storage_cend() const noexcept; + + template + reverse_storage_iterator storage_rbegin() noexcept; + template + reverse_storage_iterator storage_rend() noexcept; + + template + const_reverse_storage_iterator storage_rbegin() const noexcept; + template + const_reverse_storage_iterator storage_rend() const noexcept; + template + const_reverse_storage_iterator storage_crbegin() const noexcept; + template + const_reverse_storage_iterator storage_crend() const noexcept; + + using container_iterator = storage_iterator; + using const_container_iterator = const_storage_iterator; + + protected: + + xcontainer() = default; + ~xcontainer() = default; + + xcontainer(const xcontainer&) = default; + xcontainer& operator=(const xcontainer&) = default; + + xcontainer(xcontainer&&) = default; + xcontainer& operator=(xcontainer&&) = default; + + container_iterator data_xbegin() noexcept; + const_container_iterator data_xbegin() const noexcept; + container_iterator data_xend(layout_type l) noexcept; + const_container_iterator data_xend(layout_type l) const noexcept; + + protected: + + derived_type& derived_cast() & noexcept; + const derived_type& derived_cast() const & noexcept; + derived_type derived_cast() && noexcept; + + private: + + friend class xiterable; + friend class xconst_iterable; + + template + friend class xstepper; + + template + It data_xend_impl(It end, layout_type l) const noexcept; + + inner_shape_type& mutable_shape(); + inner_strides_type& mutable_strides(); + inner_backstrides_type& mutable_backstrides(); + }; + +#undef DL + + /** + * @class xstrided_container + * @brief Partial implementation of xcontainer that embeds the strides and the shape + * + * The xstrided_container class is a partial implementation of the xcontainer interface + * that embed the strides and the shape of the multidimensional container. It does + * not embed the data container, this responsibility is delegated to the inheriting + * classes. + * + * @tparam D The derived type, i.e. the inheriting class for which xstrided_container + * provides the partial imlpementation of xcontainer. + */ + template + class xstrided_container : public xcontainer + { + public: + + using base_type = xcontainer; + 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 size_type = typename base_type::size_type; + using shape_type = typename base_type::shape_type; + using strides_type = typename base_type::strides_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; + + template + void resize(S&& shape, bool force = false); + template + void resize(S&& shape, layout_type l); + template + void resize(S&& shape, const strides_type& strides); + + template + void reshape(S&& shape, layout_type layout = base_type::static_layout); + + layout_type layout() const noexcept; + + protected: + + xstrided_container() noexcept; + ~xstrided_container() = default; + + xstrided_container(const xstrided_container&) = default; + xstrided_container& operator=(const xstrided_container&) = default; + + xstrided_container(xstrided_container&&) = default; + xstrided_container& operator=(xstrided_container&&) = default; + + explicit xstrided_container(inner_shape_type&&, inner_strides_type&&) noexcept; + + inner_shape_type& shape_impl() noexcept; + const inner_shape_type& shape_impl() const noexcept; + + inner_strides_type& strides_impl() noexcept; + const inner_strides_type& strides_impl() const noexcept; + + inner_backstrides_type& backstrides_impl() noexcept; + const inner_backstrides_type& backstrides_impl() const noexcept; + + private: + + inner_shape_type m_shape; + inner_strides_type m_strides; + inner_backstrides_type m_backstrides; + layout_type m_layout = base_type::static_layout; + }; + + /****************************** + * xcontainer implementation * + ******************************/ + + template + template + inline It xcontainer::data_xend_impl(It end, layout_type l) const noexcept + { + return strided_data_end(*this, end, l); + } + + template + inline auto xcontainer::mutable_shape() -> inner_shape_type& + { + return derived_cast().shape_impl(); + } + + template + inline auto xcontainer::mutable_strides() -> inner_strides_type& + { + return derived_cast().strides_impl(); + } + + template + inline auto xcontainer::mutable_backstrides() -> inner_backstrides_type& + { + return derived_cast().backstrides_impl(); + } + + /** + * @name Size and shape + */ + //@{ + /** + * Returns the number of element in the container. + */ + template + inline auto xcontainer::size() const noexcept -> size_type + { + return contiguous_layout ? storage().size() : compute_size(shape()); + } + + /** + * Returns the number of dimensions of the container. + */ + template + inline constexpr auto xcontainer::dimension() const noexcept -> size_type + { + return shape().size(); + } + + /** + * Returns the shape of the container. + */ + template + constexpr inline auto xcontainer::shape() const noexcept -> const inner_shape_type& + { + return derived_cast().shape_impl(); + } + + /** + * Returns the strides of the container. + */ + template + constexpr inline auto xcontainer::strides() const noexcept -> const inner_strides_type& + { + return derived_cast().strides_impl(); + } + + /** + * Returns the backstrides of the container. + */ + template + constexpr inline auto xcontainer::backstrides() const noexcept -> const inner_backstrides_type& + { + return derived_cast().backstrides_impl(); + } + //@} + + /** + * @name Data + */ + //@{ + + /** + * Fills the container with the given value. + * @param value the value to fill the container with. + */ + template + template + inline void xcontainer::fill(const T& value) + { + std::fill(storage_begin(), storage_end(), value); + } + + /** + * Returns a reference to the element at the specified position in the container. + * @param args a list of indices specifying the position in the container. Indices + * must be unsigned integers, the number of indices should be equal or greater than + * the number of dimensions of the container. + */ + template + template + inline auto xcontainer::operator()(Args... args) -> reference + { + XTENSOR_TRY(check_index(shape(), args...)); + XTENSOR_CHECK_DIMENSION(shape(), args...); + size_type index = xt::data_offset(strides(), static_cast(args)...); + return storage()[index]; + } + + /** + * Returns a constant reference to the element at the specified position in the container. + * @param args a list of indices specifying the position in the container. Indices + * must be unsigned integers, the number of indices should be equal or greater than + * the number of dimensions of the container. + */ + template + template + inline auto xcontainer::operator()(Args... args) const -> const_reference + { + XTENSOR_TRY(check_index(shape(), args...)); + XTENSOR_CHECK_DIMENSION(shape(), args...); + size_type index = xt::data_offset(strides(), static_cast(args)...); + return storage()[index]; + } + + /** + * Returns a reference to the element at the specified position in the container, + * after dimension and bounds checking. + * @param args a list of indices specifying the position in the container. Indices + * must be unsigned integers, the number of indices should be equal to the number of dimensions + * of the container. + * @exception std::out_of_range if the number of argument is greater than the number of dimensions + * or if indices are out of bounds. + */ + template + template + inline auto xcontainer::at(Args... args) -> reference + { + check_access(shape(), static_cast(args)...); + return this->operator()(args...); + } + + /** + * Returns a constant reference to the element at the specified position in the container, + * after dimension and bounds checking. + * @param args a list of indices specifying the position in the container. Indices + * must be unsigned integers, the number of indices should be equal to the number of dimensions + * of the container. + * @exception std::out_of_range if the number of argument is greater than the number of dimensions + * or if indices are out of bounds. + */ + template + template + inline auto xcontainer::at(Args... args) const -> const_reference + { + check_access(shape(), static_cast(args)...); + return this->operator()(args...); + } + + /** + * Returns a reference to the element at the specified position in the container. + * @param args a list of indices specifying the position in the container. Indices + * must be unsigned integers, the number of indices must be equal to the number of + * dimensions of the container, 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 a = {{0, 1}, {2, 3}}; + * xt::xarray b = {0, 1}; + * auto fd = a + b; + * double res = fd.uncheked(0, 1); + * \endcode + */ + template + template + inline auto xcontainer::unchecked(Args... args) -> reference + { + size_type index = xt::unchecked_data_offset(strides(), static_cast(args)...); + return storage()[index]; + } + + /** + * Returns a constant reference to the element at the specified position in the container. + * @param args a list of indices specifying the position in the container. Indices + * must be unsigned integers, the number of indices must be equal to the number of + * dimensions of the container, 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 a = {{0, 1}, {2, 3}}; + * xt::xarray b = {0, 1}; + * auto fd = a + b; + * double res = fd.uncheked(0, 1); + * \endcode + */ + template + template + inline auto xcontainer::unchecked(Args... args) const -> const_reference + { + size_type index = xt::unchecked_data_offset(strides(), static_cast(args)...); + return storage()[index]; + } + + /** + * Returns a reference to the element at the specified position in the container. + * @param index a sequence of indices specifying the position in the container. Indices + * must be unsigned integers, the number of indices in the list should be equal or greater + * than the number of dimensions of the container. + */ + template + template + inline auto xcontainer::operator[](const S& index) + -> disable_integral_t + { + return element(index.cbegin(), index.cend()); + } + + template + template + inline auto xcontainer::operator[](std::initializer_list index) -> reference + { + return element(index.begin(), index.end()); + } + + template + inline auto xcontainer::operator[](size_type i) -> reference + { + return operator()(i); + } + + /** + * Returns a constant reference to the element at the specified position in the container. + * @param index a sequence of indices specifying the position in the container. Indices + * must be unsigned integers, the number of indices in the list should be equal or greater + * than the number of dimensions of the container. + */ + template + template + inline auto xcontainer::operator[](const S& index) const + -> disable_integral_t + { + return element(index.cbegin(), index.cend()); + } + + template + template + inline auto xcontainer::operator[](std::initializer_list index) const -> const_reference + { + return element(index.begin(), index.end()); + } + + template + inline auto xcontainer::operator[](size_type i) const -> const_reference + { + return operator()(i); + } + + /** + * Returns a reference to the element at the specified position in the container. + * @param first iterator starting the sequence of indices + * @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 + template + inline auto xcontainer::element(It first, It last) -> reference + { + XTENSOR_TRY(check_element_index(shape(), first, last)); + return storage()[element_offset(strides(), first, last)]; + } + + /** + * Returns a reference to the element at the specified position in the container. + * @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 + template + inline auto xcontainer::element(It first, It last) const -> const_reference + { + XTENSOR_TRY(check_element_index(shape(), first, last)); + return storage()[element_offset(strides(), first, last)]; + } + + /** + * Returns a reference to the buffer containing the elements of the container. + */ + template + inline auto xcontainer::storage() noexcept -> storage_type& + { + return derived_cast().storage_impl(); + } + + /** + * Returns a constant reference to the buffer containing the elements of the + * container. + */ + template + inline auto xcontainer::storage() const noexcept -> const storage_type& + { + return derived_cast().storage_impl(); + } + + /** + * Returns a pointer to the underlying array serving as element storage. The pointer + * is such that range [data(); data() + size()] is always a valid range, even if the + * container is empty (data() is not is not dereferenceable in that case) + */ + template + inline auto xcontainer::data() noexcept -> value_type* + { + return storage().data(); + } + + /** + * Returns a constant pointer to the underlying array serving as element storage. The pointer + * is such that range [data(); data() + size()] is always a valid range, even if the + * container is empty (data() is not is not dereferenceable in that case) + */ + template + inline auto xcontainer::data() const noexcept -> const value_type* + { + return storage().data(); + } + + /** + * Returns the offset to the first element in the container. + */ + template + inline auto xcontainer::data_offset() const noexcept -> const size_type + { + return size_type(0); + } + //@} + + /** + * @name Broadcasting + */ + //@{ + /** + * Broadcast the shape of the container 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 + template + inline bool xcontainer::broadcast_shape(S& shape, bool) const + { + return xt::broadcast_shape(this->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 + template + inline bool xcontainer::is_trivial_broadcast(const S& str) const noexcept + { + return str.size() == strides().size() && + std::equal(str.cbegin(), str.cend(), strides().begin()); + } + //@} + + /**************** + * Iterator api * + ****************/ + + template + template + inline auto xcontainer::begin() noexcept -> select_iterator + { + return xtl::mpl::static_if([&](auto self) + { + return self(*this).template storage_begin(); + }, /*else*/ [&](auto self) + { + return self(*this).iterable_base::template begin(); + }); + } + + template + template + inline auto xcontainer::end() noexcept -> select_iterator + { + return xtl::mpl::static_if([&](auto self) + { + return self(*this).template storage_end(); + }, /*else*/ [&](auto self) + { + return self(*this).iterable_base::template end(); + }); + } + + template + template + inline auto xcontainer::begin() const noexcept -> select_const_iterator + { + return this->template cbegin(); + } + + template + template + inline auto xcontainer::end() const noexcept -> select_const_iterator + { + return this->template cend(); + } + + template + template + inline auto xcontainer::cbegin() const noexcept -> select_const_iterator + { + return xtl::mpl::static_if([&](auto self) + { + return self(*this).template storage_cbegin(); + }, /*else*/ [&](auto self) + { + return self(*this).iterable_base::template cbegin(); + }); + } + + template + template + inline auto xcontainer::cend() const noexcept -> select_const_iterator + { + return xtl::mpl::static_if([&](auto self) + { + return self(*this).template storage_cend(); + }, /*else*/ [&](auto self) + { + return self(*this).iterable_base::template cend(); + }); + } + + template + template + inline auto xcontainer::rbegin() noexcept -> select_reverse_iterator + { + return xtl::mpl::static_if([&](auto self) + { + return self(*this).template storage_rbegin(); + }, /*else*/ [&](auto self) + { + return self(*this).iterable_base::template rbegin(); + }); + } + + template + template + inline auto xcontainer::rend() noexcept -> select_reverse_iterator + { + return xtl::mpl::static_if([&](auto self) + { + return self(*this).template storage_rend(); + }, /*else*/ [&](auto self) + { + return self(*this).iterable_base::template rend(); + }); + } + + template + template + inline auto xcontainer::rbegin() const noexcept -> select_const_reverse_iterator + { + return this->template crbegin(); + } + + template + template + inline auto xcontainer::rend() const noexcept -> select_const_reverse_iterator + { + return this->template crend(); + } + + template + template + inline auto xcontainer::crbegin() const noexcept -> select_const_reverse_iterator + { + return xtl::mpl::static_if([&](auto self) + { + return self(*this).template storage_crbegin(); + }, /*else*/ [&](auto self) + { + return self(*this).iterable_base::template crbegin(); + }); + } + + template + template + inline auto xcontainer::crend() const noexcept -> select_const_reverse_iterator + { + return xtl::mpl::static_if([&](auto self) + { + return self(*this).template storage_crend(); + }, /*else*/ [&](auto self) + { + return self(*this).iterable_base::template crend(); + }); + } + + /***************************** + * Broadcasting iterator api * + *****************************/ + + template + template + inline auto xcontainer::begin(const S& shape) noexcept -> broadcast_iterator + { + return iterable_base::template begin(shape); + } + + template + template + inline auto xcontainer::end(const S& shape) noexcept -> broadcast_iterator + { + return iterable_base::template end(shape); + } + + template + template + inline auto xcontainer::begin(const S& shape) const noexcept -> const_broadcast_iterator + { + return iterable_base::template begin(shape); + } + + template + template + inline auto xcontainer::end(const S& shape) const noexcept -> const_broadcast_iterator + { + return iterable_base::template end(shape); + } + + template + template + inline auto xcontainer::cbegin(const S& shape) const noexcept -> const_broadcast_iterator + { + return iterable_base::template cbegin(shape); + } + + template + template + inline auto xcontainer::cend(const S& shape) const noexcept -> const_broadcast_iterator + { + return iterable_base::template cend(shape); + } + + template + template + inline auto xcontainer::rbegin(const S& shape) noexcept -> reverse_broadcast_iterator + { + return iterable_base::template rbegin(shape); + } + + template + template + inline auto xcontainer::rend(const S& shape) noexcept -> reverse_broadcast_iterator + { + return iterable_base::template rend(shape); + } + + template + template + inline auto xcontainer::rbegin(const S& shape) const noexcept -> const_reverse_broadcast_iterator + { + return iterable_base::template rbegin(shape); + } + + template + template + inline auto xcontainer::rend(const S& shape) const noexcept -> const_reverse_broadcast_iterator + { + return iterable_base::template rend(shape); + } + + template + template + inline auto xcontainer::crbegin(const S& shape) const noexcept -> const_reverse_broadcast_iterator + { + return iterable_base::template crbegin(shape); + } + + template + template + inline auto xcontainer::crend(const S& shape) const noexcept -> const_reverse_broadcast_iterator + { + return iterable_base::template crend(shape); + } + + /*********************** + * Linear iterator api * + ***********************/ + + template + template + inline auto xcontainer::storage_begin() noexcept -> storage_iterator + { + return storage().begin(); + } + + template + template + inline auto xcontainer::storage_end() noexcept -> storage_iterator + { + return storage().end(); + } + + template + template + inline auto xcontainer::storage_begin() const noexcept -> const_storage_iterator + { + return storage().begin(); + } + + template + template + inline auto xcontainer::storage_end() const noexcept -> const_storage_iterator + { + return storage().end(); + } + + template + template + inline auto xcontainer::storage_cbegin() const noexcept -> const_storage_iterator + { + return storage().cbegin(); + } + + template + template + inline auto xcontainer::storage_cend() const noexcept -> const_storage_iterator + { + return storage().cend(); + } + + template + template + inline auto xcontainer::storage_rbegin() noexcept -> reverse_storage_iterator + { + return storage().rbegin(); + } + + template + template + inline auto xcontainer::storage_rend() noexcept -> reverse_storage_iterator + { + return storage().rend(); + } + + template + template + inline auto xcontainer::storage_rbegin() const noexcept -> const_reverse_storage_iterator + { + return storage().rbegin(); + } + + template + template + inline auto xcontainer::storage_rend() const noexcept -> const_reverse_storage_iterator + { + return storage().rend(); + } + + template + template + inline auto xcontainer::storage_crbegin() const noexcept -> const_reverse_storage_iterator + { + return storage().crbegin(); + } + + template + template + inline auto xcontainer::storage_crend() const noexcept -> const_reverse_storage_iterator + { + return storage().crend(); + } + + /*************** + * stepper api * + ***************/ + + template + template + inline auto xcontainer::stepper_begin(const S& shape) noexcept -> stepper + { + size_type offset = shape.size() - dimension(); + return stepper(static_cast(this), data_xbegin(), offset); + } + + template + template + inline auto xcontainer::stepper_end(const S& shape, layout_type l) noexcept -> stepper + { + size_type offset = shape.size() - dimension(); + return stepper(static_cast(this), data_xend(l), offset); + } + + template + template + inline auto xcontainer::stepper_begin(const S& shape) const noexcept -> const_stepper + { + size_type offset = shape.size() - dimension(); + return const_stepper(static_cast(this), data_xbegin(), offset); + } + + template + template + inline auto xcontainer::stepper_end(const S& shape, layout_type l) const noexcept -> const_stepper + { + size_type offset = shape.size() - dimension(); + return const_stepper(static_cast(this), data_xend(l), offset); + } + + template + inline auto xcontainer::data_xbegin() noexcept -> container_iterator + { + return storage().begin(); + } + + template + inline auto xcontainer::data_xbegin() const noexcept -> const_container_iterator + { + return storage().begin(); + } + + template + inline auto xcontainer::data_xend(layout_type l) noexcept -> container_iterator + { + return data_xend_impl(storage().end(), l); + } + + template + inline auto xcontainer::data_xend(layout_type l) const noexcept -> const_container_iterator + { + return data_xend_impl(storage().end(), l); + } + + template + inline auto xcontainer::derived_cast() & noexcept -> derived_type& + { + return *static_cast(this); + } + + template + inline auto xcontainer::derived_cast() const & noexcept -> const derived_type& + { + return *static_cast(this); + } + + template + inline auto xcontainer::derived_cast() && noexcept -> derived_type + { + return *static_cast(this); + } + + template + inline auto xcontainer::data_element(size_type i) -> reference + { + return storage()[i]; + } + + template + inline auto xcontainer::data_element(size_type i) const -> const_reference + { + return storage()[i]; + } + + template + template + inline void xcontainer::store_simd(size_type i, const simd& e) + { + using align_mode = driven_align_mode_t; + xsimd::store_simd(&(storage()[i]), e, align_mode()); + } + + template + template + inline auto xcontainer::load_simd(size_type i) const -> simd_return_type + { + using align_mode = driven_align_mode_t; + return xsimd::load_simd(&(storage()[i]), align_mode()); + } + + /************************************* + * xstrided_container implementation * + *************************************/ + + template + inline xstrided_container::xstrided_container() noexcept + : base_type() + { + m_shape = xtl::make_sequence(base_type::dimension(), 1); + m_strides = xtl::make_sequence(base_type::dimension(), 0); + m_backstrides = xtl::make_sequence(base_type::dimension(), 0); + } + + template + inline xstrided_container::xstrided_container(inner_shape_type&& shape, inner_strides_type&& strides) noexcept + : base_type(), m_shape(std::move(shape)), m_strides(std::move(strides)) + { + m_backstrides = xtl::make_sequence(m_shape.size(), 0); + adapt_strides(m_shape, m_strides, m_backstrides); + } + + template + inline auto xstrided_container::shape_impl() noexcept -> inner_shape_type& + { + return m_shape; + } + + template + inline auto xstrided_container::shape_impl() const noexcept -> const inner_shape_type& + { + return m_shape; + } + + template + inline auto xstrided_container::strides_impl() noexcept -> inner_strides_type& + { + return m_strides; + } + + template + inline auto xstrided_container::strides_impl() const noexcept -> const inner_strides_type& + { + return m_strides; + } + + template + inline auto xstrided_container::backstrides_impl() noexcept -> inner_backstrides_type& + { + return m_backstrides; + } + + template + inline auto xstrided_container::backstrides_impl() const noexcept -> const inner_backstrides_type& + { + return m_backstrides; + } + + /** + * Return the layout_type of the container + * @return layout_type of the container + */ + template + layout_type xstrided_container::layout() const noexcept + { + return m_layout; + } + + namespace detail + { + template + inline void resize_data_container(C& c, S size) + { + xt::resize_container(c, size); + } + + template + inline void resize_data_container(const C& c, S size) + { + (void) c; // remove unused parameter warning + (void) size; + XTENSOR_ASSERT_MSG(c.size() == size, "Trying to resize const data container with wrong size."); + } + } + + /** + * resizes the container. + * @param shape the new shape + * @param force force reshaping, even if the shape stays the same (default: false) + */ + template + template + inline void xstrided_container::resize(S&& shape, bool force) + { + if (m_shape.size() != shape.size() || !std::equal(std::begin(shape), std::end(shape), std::begin(m_shape)) || force) + { + if (m_layout == layout_type::dynamic || m_layout == layout_type::any) + { + m_layout = XTENSOR_DEFAULT_LAYOUT; // fall back to default layout + } + m_shape = xtl::forward_sequence(shape); + resize_container(m_strides, m_shape.size()); + resize_container(m_backstrides, m_shape.size()); + size_type data_size = compute_strides(m_shape, m_layout, m_strides, m_backstrides); + detail::resize_data_container(this->storage(), data_size); + } + } + + /** + * resizes the container. + * @param shape the new shape + * @param l the new layout_type + */ + template + template + inline void xstrided_container::resize(S&& shape, layout_type l) + { + if (base_type::static_layout != layout_type::dynamic && l != base_type::static_layout) + { + throw std::runtime_error("Cannot change layout_type if template parameter not layout_type::dynamic."); + } + m_layout = l; + resize(std::forward(shape), true); + } + + /** + * Resizes the container. + * @param shape the new shape + * @param strides the new strides + */ + template + template + inline void xstrided_container::resize(S&& shape, const strides_type& strides) + { + if (base_type::static_layout != layout_type::dynamic) + { + throw std::runtime_error("Cannot resize with custom strides when layout() is != layout_type::dynamic."); + } + m_shape = xtl::forward_sequence(shape); + m_strides = strides; + resize_container(m_backstrides, m_strides.size()); + adapt_strides(m_shape, m_strides, m_backstrides); + m_layout = layout_type::dynamic; + detail::resize_data_container(this->storage(), compute_size(m_shape)); + } + + /** + * Reshapes the container and keeps old elements + * @param shape the new shape (has to have same number of elements as the original container) + * @param layout the layout to compute the strides (defaults to static layout of the container, + * or for a container with dynamic layout to XTENSOR_DEFAULT_LAYOUT) + */ + template + template + inline void xstrided_container::reshape(S&& shape, layout_type layout) + { + if (compute_size(shape) != this->size()) + { + throw std::runtime_error("Cannot reshape with incorrect number of elements. Do you mean to resize?"); + } + if (layout == layout_type::dynamic || layout == layout_type::any) + { + layout = XTENSOR_DEFAULT_LAYOUT; // fall back to default layout + } + if (layout != base_type::static_layout && base_type::static_layout != layout_type::dynamic) + { + throw std::runtime_error("Cannot reshape with different layout if static layout != dynamic."); + } + m_layout = layout; + m_shape = xtl::forward_sequence(shape); + resize_container(m_strides, m_shape.size()); + resize_container(m_backstrides, m_shape.size()); + compute_strides(m_shape, m_layout, m_strides, m_backstrides); + } +} + +#endif diff --git a/vendor/xtensor/include/xtensor/xcsv.hpp b/vendor/xtensor/include/xtensor/xcsv.hpp new file mode 100644 index 0000000000..4a2716d400 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xcsv.hpp @@ -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 +#include +#include +#include +#include +#include + +#include "xtensor.hpp" + +namespace xt +{ + + /************************************** + * load_csv and dump_csv declarations * + **************************************/ + + template > + using xcsv_tensor = xtensor_container, 2, layout_type::row_major>; + + template > + xcsv_tensor load_csv(std::istream& stream); + + template + void dump_csv(std::ostream& stream, const xexpression& e); + + /***************************************** + * load_csv and dump_csv implementations * + *****************************************/ + + namespace detail + { + template + inline T lexical_cast(const std::string& cell) + { + T res; + std::istringstream iss(cell); + iss >> res; + return res; + } + + template <> + inline float lexical_cast(const std::string& cell) { return std::stof(cell); } + + template <> + inline double lexical_cast(const std::string& cell) { return std::stod(cell); } + + template <> + inline long double lexical_cast(const std::string& cell) { return std::stold(cell); } + + template <> + inline int lexical_cast(const std::string& cell) { return std::stoi(cell); } + + template <> + inline long lexical_cast(const std::string& cell) { return std::stol(cell); } + + template <> + inline long long lexical_cast(const std::string& cell) { return std::stoll(cell); } + + template <> + inline unsigned int lexical_cast(const std::string& cell) { return static_cast(std::stoul(cell)); } + + template <> + inline unsigned long lexical_cast(const std::string& cell) { return std::stoul(cell); } + + template <> + inline unsigned long long lexical_cast(const std::string& cell) { return std::stoull(cell); } + + template + ST load_csv_row(std::istream& row_stream, OI output, std::string cell) + { + ST length = 0; + while (std::getline(row_stream, cell, ',')) + { + *output++ = lexical_cast(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 + xcsv_tensor load_csv(std::istream& stream) + { + using tensor_type = xcsv_tensor; + 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 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(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 + void dump_csv(std::ostream& stream, const xexpression& 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 diff --git a/vendor/xtensor/include/xtensor/xeval.hpp b/vendor/xtensor/include/xtensor/xeval.hpp new file mode 100644 index 0000000000..18d53beea6 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xeval.hpp @@ -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 + using is_container = std::is_base_of>, T>; + } + + /** + * Force evaluation of xexpression. + * @return xarray or xtensor depending on shape type + * + * \code{.cpp} + * xarray 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, not an xexpression + * \endcode + */ + template + inline auto eval(T&& t) + -> std::enable_if_t>::value, T&&> + { + return std::forward(t); + } + + /// @cond DOXYGEN_INCLUDE_SFINAE + template > + inline auto eval(T&& t) + -> std::enable_if_t::value && detail::is_array::value, xtensor::value>> + { + return xtensor::value>(std::forward(t)); + } + + template > + inline auto eval(T&& t) + -> std::enable_if_t::value && !detail::is_array::value, xt::xarray> + { + return xarray(std::forward(t)); + } + /// @endcond +} + +#endif diff --git a/vendor/xtensor/include/xtensor/xexception.hpp b/vendor/xtensor/include/xtensor/xexception.hpp new file mode 100644 index 0000000000..689ce31e09 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xexception.hpp @@ -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 +#include +#include +#include + +namespace xt +{ + + /******************* + * broadcast_error * + *******************/ + + class broadcast_error : public std::runtime_error + { + public: + + explicit broadcast_error(const char* msg) + : std::runtime_error(msg) + { + } + }; + + template + [[noreturn]] void throw_broadcast_error(const S1& lhs, const S2& rhs); + + /********************************** + * broadcast_error implementation * + **********************************/ + +#ifdef NDEBUG + // Do not inline this function + template + [[noreturn]] void throw_broadcast_error(const S1&, const S2&) + { + throw broadcast_error("Incompatible dimension of arrays, compile in DEBUG for more info"); + } +#else + template + [[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 iter1(buf, ", "); + std::copy(lhs.cbegin(), lhs.cend(), iter1); + + buf << ")\n RHS shape = ("; + using size_type2 = typename S2::value_type; + std::ostream_iterator iter2(buf, ", "); + std::copy(rhs.cbegin(), rhs.cend(), iter2); + buf << ")"; + + 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 + void check_index(const S& shape, Args... args); + + template + void check_element_index(const S& shape, It first, It last); + + namespace detail + { + template + inline void check_index_impl(const S&) + { + } + + template + inline void check_index_impl(const S& shape, std::size_t arg, Args... args) + { + if (sizeof...(Args) + 1 > shape.size()) + { + check_index_impl(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(shape, args...); + } + } + } + + template + inline void check_index(const S& shape, Args... args) + { + using value_type = typename S::value_type; + detail::check_index_impl(shape, static_cast(args)...); + } + + template + inline void check_element_index(const S& shape, It first, It last) + { + using value_type = typename std::iterator_traits::value_type; + auto dst = static_cast(last - first); + It efirst = last - static_cast((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 + 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 + 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 diff --git a/vendor/xtensor/include/xtensor/xexpression.hpp b/vendor/xtensor/include/xtensor/xexpression.hpp new file mode 100644 index 0000000000..a83ea0c582 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xexpression.hpp @@ -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 +#include +#include + +#include +#include + +#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 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 + inline auto xexpression::derived_cast() & noexcept -> derived_type& + { + return *static_cast(this); + } + + /** + * Returns a constant reference to the actual derived type of the xexpression. + */ + template + inline auto xexpression::derived_cast() const & noexcept -> const derived_type& + { + return *static_cast(this); + } + + /** + * Returns a constant reference to the actual derived type of the xexpression. + */ + template + inline auto xexpression::derived_cast() && noexcept -> derived_type + { + return *static_cast(this); + } + //@} + + namespace detail + { + template + struct is_xexpression_impl : std::is_base_of>, std::decay_t> + { + }; + + template + struct is_xexpression_impl> : std::true_type + { + }; + } + + template + using is_xexpression = detail::is_xexpression_impl; + + template + using enable_xexpression = typename std::enable_if::value, R>::type; + + template + using disable_xexpression = typename std::enable_if::value, R>::type; + + template + using has_xexpression = xtl::disjunction...>; + + /************ + * xclosure * + ************/ + + template + class xscalar; + + template + struct xclosure + { + using type = xtl::closure_type_t; + }; + + template + struct xclosure>> + { + using type = xscalar>; + }; + + template + using xclosure_t = typename xclosure::type; + + template + struct const_xclosure + { + using type = xtl::const_closure_type_t; + }; + + template + struct const_xclosure>> + { + using type = xscalar>; + }; + + template + using const_xclosure_t = typename const_xclosure::type; + + /*************** + * xvalue_type * + ***************/ + + namespace detail + { + template + struct xvalue_type_impl + { + using type = E; + }; + + template + struct xvalue_type_impl::value>> + { + using type = typename E::value_type; + }; + } + + template + using xvalue_type = detail::xvalue_type_impl; + + template + using xvalue_type_t = typename xvalue_type::type; + + /************************* + * expression tag system * + *************************/ + + struct xscalar_expression_tag + { + }; + + struct xtensor_expression_tag + { + }; + + struct xoptional_expression_tag + { + }; + + namespace detail + { + template > + struct get_expression_tag + { + using type = xtensor_expression_tag; + }; + + template + struct get_expression_tag::expression_tag>> + { + using type = typename std::decay_t::expression_tag; + }; + + template + using get_expression_tag_t = typename get_expression_tag::type; + + template + struct expression_tag_and; + + template + struct expression_tag_and + { + using type = T; + }; + + template + struct expression_tag_and + { + using type = T; + }; + + template <> + struct expression_tag_and + { + using type = xscalar_expression_tag; + }; + + template + struct expression_tag_and + { + using type = T; + }; + + template + struct expression_tag_and + : expression_tag_and + { + }; + + template <> + struct expression_tag_and + { + using type = xoptional_expression_tag; + }; + + template <> + struct expression_tag_and + : expression_tag_and + { + }; + + template + struct expression_tag_and + : expression_tag_and::type> + { + }; + + template + using expression_tag_and_t = typename expression_tag_and::type; + } + + template + struct xexpression_tag + { + using type = detail::expression_tag_and_t>>...>; + }; + + template + using xexpression_tag_t = typename xexpression_tag::type; + + template + struct is_xtensor_expression : std::is_same, xtensor_expression_tag> + { + }; + + template + struct is_xoptional_expression : std::is_same, xoptional_expression_tag> + { + }; + + /******************************** + * xoptional_comparable concept * + ********************************/ + + template + struct xoptional_comparable : xtl::conjunction, + is_xoptional_expression + >... + > + { + }; +} + +#endif diff --git a/vendor/xtensor/include/xtensor/xfixed.hpp b/vendor/xtensor/include/xtensor/xfixed.hpp new file mode 100644 index 0000000000..4438825975 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xfixed.hpp @@ -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 +#include +#include +#include +#include + +#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 + class fixed_shape + { + public: + + using cast_type = const_array; + + constexpr static std::size_t size() + { + return sizeof...(X); + } + + constexpr fixed_shape() + { + } + + constexpr operator cast_type() const + { + return {{X...}}; + } + }; +} + +namespace std +{ + template + class tuple_size> : + public integral_constant + { + }; +} + +namespace xtl +{ + namespace detail + { + template + struct sequence_builder> + { + using sequence_type = xt::const_array; + 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 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 + 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 + struct at + { + constexpr static std::size_t arr[sizeof...(X)] = {X...}; + constexpr static std::size_t value = arr[IDX]; + }; + + template + struct calculate_stride; + + template + struct calculate_stride + { + constexpr static std::size_t value = Y * calculate_stride::value; + }; + + template + struct calculate_stride + { + constexpr static std::size_t value = 1; + }; + + template + struct calculate_stride_row_major + { + constexpr static std::size_t value = at::value * calculate_stride_row_major::value; + }; + + template + struct calculate_stride_row_major<0, X...> + { + constexpr static std::size_t value = 1; + }; + + template + struct calculate_stride + { + constexpr static std::size_t value = calculate_stride_row_major::value; + }; + + template + constexpr const_array + get_strides_impl(const xt::fixed_shape& /*shape*/, std::index_sequence) + { + static_assert((L == layout_type::row_major) || (L == layout_type::column_major), + "Layout not supported for fixed array"); + return {{at::value == 1 ? 0 : calculate_stride::value...}}; + } + + template + constexpr T get_backstrides_impl(const T& shape, const T& strides, std::index_sequence) + { + return {{(strides[I] * (shape[I] - 1))...}}; + } + + template + struct compute_size_impl; + + template + struct compute_size_impl + { + constexpr static std::size_t value = Y * compute_size_impl::value; + }; + + template + struct compute_size_impl + { + 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 + struct fixed_compute_size; + + template + struct fixed_compute_size> + { + constexpr static std::size_t value = compute_size_impl::value; + }; + + template + struct get_init_type_impl; + + template + struct get_init_type_impl + { + using type = V[Y]; + }; + + template + struct get_init_type_impl + { + using type = V[1]; + }; + + template + struct get_init_type_impl + { + using tmp_type = typename get_init_type_impl::type; + using type = tmp_type[Y]; + }; + } + + template + constexpr const_array get_strides(const fixed_shape& shape) noexcept + { + return detail::get_strides_impl(shape, std::make_index_sequence{}); + } + + template + constexpr T get_backstrides(const T& shape, const T& strides) noexcept + { + return detail::get_backstrides_impl(shape, strides, + std::make_index_sequence::value>{}); + } + + template + struct get_init_type; + + template + struct get_init_type> + { + using type = typename detail::get_init_type_impl::type; + }; + + template + using get_init_type_t = typename get_init_type::type; + + template + struct xcontainer_inner_types> + { + 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::value>; + using strides_type = shape_type; + using storage_type = aligned_array::value>; + using temporary_type = xfixed_container; + static constexpr layout_type layout = L; + }; + + template + struct xiterable_inner_types> + : xcontainer_iterable_types> + { + }; + + /** + * @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 xfixed_container : public xcontainer>, + public xcontainer_semantic> + { + public: + + using self_type = xfixed_container; + using base_type = xcontainer; + using semantic_base = xcontainer_semantic; + + 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::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& init); +#else + // remove this enable_if when removing the other value_type constructor + template , class EN = std::enable_if_t> + xfixed_container(nested_initializer_list_t 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 + xfixed_container(const xexpression& e); + + template + xfixed_container& operator=(const xexpression& e); + + template + void resize(ST&& shape, bool force = false) const; + + template + void reshape(ST&& shape, layout_type layout = L) const; + + template + 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(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>; + }; + +#ifdef XTENSOR_HAS_CONSTEXPR_ENHANCED + // Out of line definitions to prevent linker errors prior to C++17 + template + constexpr typename xfixed_container::inner_shape_type xfixed_container::m_shape; + + template + constexpr typename xfixed_container::inner_strides_type xfixed_container::m_strides; + + template + constexpr typename xfixed_container::inner_backstrides_type xfixed_container::m_backstrides; +#endif + + /**************************************** + * xfixed_container_adaptor declaration * + ****************************************/ + + template + class xfixed_adaptor; + + template + struct xcontainer_inner_types> + { + using storage_type = std::remove_reference_t; + 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::value>; + using strides_type = shape_type; + using temporary_type = xfixed_container; + static constexpr layout_type layout = L; + }; + + template + struct xiterable_inner_types> + : xcontainer_iterable_types> + { + }; + + /** + * @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 xfixed_adaptor : public xcontainer>, + public xcontainer_semantic> + { + public: + + using container_closure_type = EC; + + using self_type = xfixed_adaptor; + using base_type = xcontainer; + using semantic_base = xcontainer_semantic; + 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 + 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 + xfixed_adaptor& operator=(const xexpression& 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(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>; + }; + +#ifdef XTENSOR_HAS_CONSTEXPR_ENHANCED + // Out of line definitions to prevent linker errors prior to C++17 + template + constexpr typename xfixed_adaptor::inner_shape_type xfixed_adaptor::m_shape; + + template + constexpr typename xfixed_adaptor::inner_strides_type xfixed_adaptor::m_strides; + + template + constexpr typename xfixed_adaptor::inner_backstrides_type xfixed_adaptor::m_backstrides; +#endif + + /************************************ + * xfixed_container implementation * + ************************************/ + + /** + * @name Constructors + */ + //@{ + /** + * Create an uninitialized xfixed_container according to the shape template parameter. + */ + template + inline xfixed_container::xfixed_container() + { + } + + /** + * Create an xfixed_container, and initialize with the value of v. + * + * @param v the fill value + */ + template + inline xfixed_container::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 + inline xfixed_container::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 + inline xfixed_container::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``. + * 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 + inline xfixed_container::xfixed_container(const get_init_type_t& init) + { + std::copy(reinterpret_cast(&init), reinterpret_cast(&init) + this->size(), + this->template begin()); + } +#else + template + template + inline xfixed_container::xfixed_container(nested_initializer_list_t t) + { + L == layout_type::row_major ? nested_copy(m_storage.begin(), t) : nested_copy(this->template begin(), t); + } +#endif + //@} + + /** + * @name Extended copy semantic + */ + //@{ + /** + * The extended copy constructor. + */ + template + template + inline xfixed_container::xfixed_container(const xexpression& e) + { + semantic_base::assign(e); + } + + /** + * The extended assignment operator. + */ + template + template + inline auto xfixed_container::operator=(const xexpression& 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 + template + inline void xfixed_container::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 + template + inline void xfixed_container::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 + template + inline bool xfixed_container::broadcast_shape(ST& shape, bool) const + { + return xt::broadcast_shape(m_shape, shape); + } + + template + constexpr layout_type xfixed_container::layout() const noexcept + { + return base_type::static_layout; + } + + template + inline auto xfixed_container::storage_impl() noexcept -> storage_type& + { + return m_storage; + } + + template + inline auto xfixed_container::storage_impl() const noexcept -> const storage_type& + { + return m_storage; + } + + template + XTENSOR_CONSTEXPR_RETURN auto xfixed_container::shape_impl() const noexcept -> const inner_shape_type& + { + return m_shape; + } + + template + XTENSOR_CONSTEXPR_RETURN auto xfixed_container::strides_impl() const noexcept -> const inner_strides_type& + { + return m_strides; + } + + template + XTENSOR_CONSTEXPR_RETURN auto xfixed_container::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 + inline xfixed_adaptor::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 + inline xfixed_adaptor::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 + template + inline xfixed_adaptor::xfixed_adaptor(D&& data) + : base_type(), m_storage(std::forward(data)) + { + } + //@} + + template + inline auto xfixed_adaptor::operator=(const xfixed_adaptor& rhs) -> self_type& + { + base_type::operator=(rhs); + m_storage = rhs.m_storage; + return *this; + } + + template + inline auto xfixed_adaptor::operator=(xfixed_adaptor&& rhs) -> self_type& + { + base_type::operator=(std::move(rhs)); + m_storage = rhs.m_storage; + return *this; + } + + template + inline auto xfixed_adaptor::operator=(temporary_type&& rhs) -> self_type& + { + m_storage = xtl::forward_sequence(std::move(rhs.storage())); + return *this; + } + + /** + * @name Extended copy semantic + */ + //@{ + /** + * The extended assignment operator. + */ + template + template + inline auto xfixed_adaptor::operator=(const xexpression& e) -> self_type& + { + return semantic_base::operator=(e); + } + //@} + + template + inline auto xfixed_adaptor::storage_impl() noexcept -> storage_type& + { + return m_storage; + } + + template + inline auto xfixed_adaptor::storage_impl() const noexcept -> const storage_type& + { + return m_storage; + } + + template + constexpr layout_type xfixed_adaptor::layout() const noexcept + { + return base_type::static_layout; + } + + template + XTENSOR_CONSTEXPR_RETURN auto xfixed_adaptor::shape_impl() const noexcept -> const inner_shape_type& + { + return m_shape; + } + + template + XTENSOR_CONSTEXPR_RETURN auto xfixed_adaptor::strides_impl() const noexcept -> const inner_strides_type& + { + return m_strides; + } + + template + XTENSOR_CONSTEXPR_RETURN auto xfixed_adaptor::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 diff --git a/vendor/xtensor/include/xtensor/xfunction.hpp b/vendor/xtensor/include/xtensor/xfunction.hpp new file mode 100644 index 0000000000..91fe86f365 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xfunction.hpp @@ -0,0 +1,1184 @@ +/*************************************************************************** +* 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_FUNCTION_HPP +#define XTENSOR_FUNCTION_HPP + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "xexpression.hpp" +#include "xiterable.hpp" +#include "xlayout.hpp" +#include "xscalar.hpp" +#include "xstrides.hpp" +#include "xtensor_simd.hpp" +#include "xutils.hpp" + +namespace xt +{ + + namespace detail + { + + /******************** + * common_size_type * + ********************/ + + template + struct common_size_type + { + using type = std::common_type_t; + }; + + template <> + struct common_size_type<> + { + using type = std::size_t; + }; + + template + using common_size_type_t = typename common_size_type::type; + + template + using conjunction_c = xtl::conjunction...>; + + /************************** + * common_difference type * + **************************/ + + template + struct common_difference_type + { + using type = std::common_type_t; + }; + + template <> + struct common_difference_type<> + { + using type = std::ptrdiff_t; + }; + + template + using common_difference_type_t = typename common_difference_type::type; + + /********************* + * common_value_type * + *********************/ + + template + struct common_value_type + { + using type = promote_type_t...>; + }; + + template + using common_value_type_t = typename common_value_type::type; + + template > + struct simd_return_type + { + }; + + template + struct simd_return_type)>> + { + using type = xsimd::simd_type>; + }; + + template + using simd_return_type_t = typename simd_return_type::type; + + template + struct functor_return_type + { + using type = R; + using simd_type = xsimd::simd_type; + }; + + template + struct functor_return_type> + { + using type = std::complex; + using simd_type = xsimd::simd_type>; + }; + + template + struct functor_return_type + { + using type = bool; + using simd_type = xsimd::simd_bool_type; + }; + + template <> + struct functor_return_type + { + using type = bool; + using simd_type = bool; + }; + } + + template + class xfunction_iterator; + + template + class xfunction_stepper; + + template + class xfunction_base; + + template + struct xiterable_inner_types> + { + using inner_shape_type = promote_shape_t::shape_type...>; + using const_stepper = xfunction_stepper; + using stepper = const_stepper; + }; + + /****************** + * xfunction_base * + ******************/ + +#define DL XTENSOR_DEFAULT_LAYOUT + + /** + * @class xfunction_base + * @brief Base class for multidimensional function operating on + * xexpression. + * + * The xfunction_base class implements a multidimensional function + * operating on xexpression. Inheriting classes specify which + * kind of xexpression the xfunction_base operates on. + * + * @tparam F the function type + * @tparam R the return type of the function + * @tparam CT the closure types for arguments of the function + */ + template + class xfunction_base : private xconst_iterable> + { + public: + + using self_type = xfunction_base; + using only_scalar = all_xscalar; + using functor_type = typename std::remove_reference::type; + using tuple_type = std::tuple; + + 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 = detail::common_size_type_t...>; + using difference_type = detail::common_difference_type_t...>; + using simd_value_type = typename detail::functor_return_type...>, R>::simd_type; + using simd_argument_type = xsimd::simd_type...>>; + using iterable_base = xconst_iterable>; + 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 = compute_layout(std::decay_t::static_layout...); + static constexpr bool contiguous_layout = detail::conjunction_c::contiguous_layout...>::value; + + template + using layout_iterator = typename iterable_base::template layout_iterator; + template + using const_layout_iterator = typename iterable_base::template const_layout_iterator; + template + using reverse_layout_iterator = typename iterable_base::template reverse_layout_iterator; + template + using const_reverse_layout_iterator = typename iterable_base::template const_reverse_layout_iterator; + + template + using broadcast_iterator = typename iterable_base::template broadcast_iterator; + template + using const_broadcast_iterator = typename iterable_base::template const_broadcast_iterator; + template + using reverse_broadcast_iterator = typename iterable_base::template reverse_broadcast_iterator; + template + using const_reverse_broadcast_iterator = typename iterable_base::template const_reverse_broadcast_iterator; + + using const_storage_iterator = xfunction_iterator; + using storage_iterator = const_storage_iterator; + using const_reverse_storage_iterator = std::reverse_iterator; + using reverse_storage_iterator = std::reverse_iterator; + + using iterator = typename iterable_base::iterator; + using const_iterator = typename iterable_base::const_iterator; + using reverse_iterator = typename iterable_base::reverse_iterator; + using const_reverse_iterator = typename iterable_base::const_reverse_iterator; + + size_type size() const noexcept; + size_type dimension() const noexcept; + const shape_type& shape() const; + layout_type layout() const noexcept; + + template + const_reference operator()(Args... args) const; + + template + const_reference at(Args... args) const; + + template + const_reference unchecked(Args... args) const; + + template + disable_integral_t operator[](const S& index) const; + template + const_reference operator[](std::initializer_list index) const; + const_reference operator[](size_type i) const; + + template + const_reference element(It first, It last) const; + + template + bool broadcast_shape(S& shape, bool reuse_cache = false) const; + + template + bool is_trivial_broadcast(const S& strides) const noexcept; + + using iterable_base::begin; + using iterable_base::end; + using iterable_base::cbegin; + using iterable_base::cend; + using iterable_base::rbegin; + using iterable_base::rend; + using iterable_base::crbegin; + using iterable_base::crend; + + template + const_storage_iterator storage_begin() const noexcept; + template + const_storage_iterator storage_end() const noexcept; + template + const_storage_iterator storage_cbegin() const noexcept; + template + const_storage_iterator storage_cend() const noexcept; + + template + const_reverse_storage_iterator storage_rbegin() const noexcept; + template + const_reverse_storage_iterator storage_rend() const noexcept; + template + const_reverse_storage_iterator storage_crbegin() const noexcept; + template + const_reverse_storage_iterator storage_crend() const noexcept; + + template + const_stepper stepper_begin(const S& shape) const noexcept; + template + const_stepper stepper_end(const S& shape, layout_type l) const noexcept; + + const_reference data_element(size_type i) const; + + template ::type> + operator value_type() const; + + template + detail::simd_return_type_t load_simd(size_type i) const; + + const tuple_type& arguments() const noexcept; + + protected: + + template , self_type>::value>> + xfunction_base(Func&& f, CTA&&... e) noexcept; + + ~xfunction_base() = default; + + xfunction_base(const xfunction_base&) = default; + xfunction_base& operator=(const xfunction_base&) = default; + + xfunction_base(xfunction_base&&) = default; + xfunction_base& operator=(xfunction_base&&) = default; + + private: + + template + layout_type layout_impl(std::index_sequence) const noexcept; + + template + const_reference access_impl(std::index_sequence, Args... args) const; + + template + const_reference unchecked_impl(std::index_sequence, Args... args) const; + + template + const_reference element_access_impl(std::index_sequence, It first, It last) const; + + template + const_reference data_element_impl(std::index_sequence, size_type i) const; + + template + auto load_simd_impl(std::index_sequence, size_type i) const; + + template + const_stepper build_stepper(Func&& f, std::index_sequence) const noexcept; + + template + const_storage_iterator build_iterator(Func&& f, std::index_sequence) const noexcept; + + size_type compute_dimension() const noexcept; + + tuple_type m_e; + functor_type m_f; + mutable shape_type m_shape; + mutable bool m_shape_trivial; + mutable bool m_shape_computed; + + friend class xfunction_iterator; + friend class xfunction_stepper; + friend class xconst_iterable; + }; + +#undef DL + + /********************** + * xfunction_iterator * + **********************/ + + template + class xscalar; + + namespace detail + { + template + struct get_iterator_impl + { + using type = typename C::storage_iterator; + }; + + template + struct get_iterator_impl + { + using type = typename C::const_storage_iterator; + }; + + template + struct get_iterator_impl> + { + using type = typename xscalar::dummy_iterator; + }; + + template + struct get_iterator_impl> + { + using type = typename xscalar::const_dummy_iterator; + }; + } + + template + using get_iterator = typename detail::get_iterator_impl::type; + + template + class xfunction_iterator : public xtl::xrandom_access_iterator_base, + typename xfunction_base::value_type, + typename xfunction_base::difference_type, + typename xfunction_base::pointer, + typename xfunction_base::reference> + { + public: + + using self_type = xfunction_iterator; + using functor_type = typename std::remove_reference::type; + using xfunction_type = xfunction_base; + + using value_type = typename xfunction_type::value_type; + using reference = typename xfunction_type::value_type; + using pointer = typename xfunction_type::const_pointer; + using difference_type = typename xfunction_type::difference_type; + using iterator_category = std::random_access_iterator_tag; + + template + xfunction_iterator(const xfunction_type* func, It&&... it) noexcept; + + self_type& operator++(); + self_type& operator--(); + + self_type& operator+=(difference_type n); + self_type& operator-=(difference_type n); + + difference_type operator-(const self_type& rhs) const; + + reference operator*() const; + + bool equal(const self_type& rhs) const; + bool less_than(const self_type& rhs) const; + + private: + + using data_type = std::tuple>...>; + + template + reference deref_impl(std::index_sequence) const; + + template + difference_type tuple_max_diff(std::index_sequence, + const data_type& lhs, + const data_type& rhs) const; + + const xfunction_type* p_f; + data_type m_it; + }; + + template + bool operator==(const xfunction_iterator& it1, + const xfunction_iterator& it2); + + template + bool operator<(const xfunction_iterator& it1, + const xfunction_iterator& it2); + + /********************* + * xfunction_stepper * + *********************/ + + template + class xfunction_stepper + { + public: + + using self_type = xfunction_stepper; + using functor_type = typename std::remove_reference::type; + using xfunction_type = xfunction_base; + + using value_type = typename xfunction_type::value_type; + using reference = typename xfunction_type::value_type; + using pointer = typename xfunction_type::const_pointer; + using size_type = typename xfunction_type::size_type; + using difference_type = typename xfunction_type::difference_type; + + using shape_type = typename xfunction_type::shape_type; + + template + xfunction_stepper(const xfunction_type* func, It&&... it) noexcept; + + void step(size_type dim); + void step_back(size_type dim); + void step(size_type dim, size_type n); + void step_back(size_type dim, size_type n); + void reset(size_type dim); + void reset_back(size_type dim); + + void to_begin(); + void to_end(layout_type l); + + reference operator*() const; + + template + ST step_simd(); + + value_type step_leading(); + + private: + + template + reference deref_impl(std::index_sequence) const; + + template + ST step_simd_impl(std::index_sequence); + + template + value_type step_leading_impl(std::index_sequence); + + const xfunction_type* p_f; + std::tuple::const_stepper...> m_it; + }; + + /************* + * xfunction * + *************/ + + /** + * @class xfunction + * @brief Multidimensional function operating on + * xtensor expressions. + * + * The xfunction class implements a multidimensional function + * operating on xtensor expressions. + * + * @tparam F the function type + * @tparam R the return type of the function + * @tparam CT the closure types for arguments of the function + */ + template + class xfunction : public xfunction_base, + public xexpression> + { + public: + + using self_type = xfunction; + using base_type = xfunction_base; + + template , self_type>::value>> + xfunction(Func&& f, CTA&&... e) noexcept; + + ~xfunction() = default; + + xfunction(const xfunction&) = default; + xfunction& operator=(const xfunction&) = default; + + xfunction(xfunction&&) = default; + xfunction& operator=(xfunction&&) = default; + }; + + /********************************* + * xfunction_base implementation * + *********************************/ + + /** + * @name Constructor + */ + //@{ + /** + * Constructs an xfunction_base applying the specified function to the given + * arguments. + * @param f the function to apply + * @param e the \ref xexpression arguments + */ + template + template + inline xfunction_base::xfunction_base(Func&& f, CTA&&... e) noexcept + : m_e(std::forward(e)...), m_f(std::forward(f)), m_shape(xtl::make_sequence(0, size_type(0))), + m_shape_computed(false) + { + } + //@} + + /** + * @name Size and shape + */ + //@{ + /** + * Returns the size of the expression. + */ + template + inline auto xfunction_base::size() const noexcept -> size_type + { + return compute_size(shape()); + } + + /** + * Returns the number of dimensions of the function. + */ + template + inline auto xfunction_base::dimension() const noexcept -> size_type + { + size_type dimension = m_shape_computed ? m_shape.size() : compute_dimension(); + return dimension; + } + + /** + * Returns the shape of the xfunction. + */ + template + inline auto xfunction_base::shape() const -> const shape_type& + { + if (!m_shape_computed) + { + m_shape = xtl::make_sequence(compute_dimension(), size_type(0)); + m_shape_trivial = broadcast_shape(m_shape, false); + m_shape_computed = true; + } + return m_shape; + } + + /** + * Returns the layout_type of the xfunction. + */ + template + inline layout_type xfunction_base::layout() const noexcept + { + return layout_impl(std::make_index_sequence()); + } + //@} + + /** + * @name Data + */ + /** + * Returns a constant reference to the 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 + template + inline auto xfunction_base::operator()(Args... args) const -> const_reference + { + // The static cast prevents the compiler from instantiating the template methods with signed integers, + // leading to warning about signed/unsigned conversions in the deeper layers of the access methods + return access_impl(std::make_index_sequence(), static_cast(args)...); + } + + /** + * Returns a constant reference to the element at the specified position in the expression, + * after dimension and bounds checking. + * @param args a list of indices specifying the position in the function. Indices + * must be unsigned integers, the number of indices should be equal to the number of dimensions + * of the expression. + * @exception std::out_of_range if the number of argument is greater than the number of dimensions + * or if indices are out of bounds. + */ + template + template + inline auto xfunction_base::at(Args... args) const -> const_reference + { + check_access(shape(), static_cast(args)...); + return this->operator()(args...); + } + + /** + * Returns a constant reference to the element at the specified position in the expression. + * @param args a list of indices specifying the position in the expression. Indices + * 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 a = {{0, 1}, {2, 3}}; + * xt::xarray b = {0, 1}; + * auto fd = a + b; + * double res = fd.uncheked(0, 1); + * \endcode + */ + template + template + inline auto xfunction_base::unchecked(Args... args) const -> const_reference + { + // The static cast prevents the compiler from instantiating the template methods with signed integers, + // leading to warning about signed/unsigned conversions in the deeper layers of the access methods + return unchecked_impl(std::make_index_sequence(), static_cast(args)...); + } + + template + template + inline auto xfunction_base::operator[](const S& index) const + -> disable_integral_t + { + return element(index.cbegin(), index.cend()); + } + + template + template + inline auto xfunction_base::operator[](std::initializer_list index) const -> const_reference + { + return element(index.begin(), index.end()); + } + + template + inline auto xfunction_base::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 + template + inline auto xfunction_base::element(It first, It last) const -> const_reference + { + return element_access_impl(std::make_index_sequence(), first, last); + } + //@} + + /** + * @name Broadcasting + */ + //@{ + /** + * Broadcast the shape of the function to the specified parameter. + * @param shape the result shape + * @param reuse_cache boolean for reusing a previously computed shape + * @return a boolean indicating whether the broadcasting is trivial + */ + template + template + inline bool xfunction_base::broadcast_shape(S& shape, bool reuse_cache) const + { + if (reuse_cache && m_shape_computed) + { + std::copy(m_shape.cbegin(), m_shape.cend(), shape.begin()); + return m_shape_trivial; + } + else + { + // e.broadcast_shape must be evaluated even if b is false + auto func = [&shape](bool b, auto&& e) { return e.broadcast_shape(shape) && b; }; + return accumulate(func, true, m_e); + } + } + + /** + * 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 + template + inline bool xfunction_base::is_trivial_broadcast(const S& strides) const noexcept + { + auto func = [&strides](bool b, auto&& e) { return b && e.is_trivial_broadcast(strides); }; + return accumulate(func, true, m_e); + } + //@} + + template + template + inline auto xfunction_base::storage_begin() const noexcept -> const_storage_iterator + { + return storage_cbegin(); + } + + template + template + inline auto xfunction_base::storage_end() const noexcept -> const_storage_iterator + { + return storage_cend(); + } + + template + template + inline auto xfunction_base::storage_cbegin() const noexcept -> const_storage_iterator + { + auto f = [](const auto& e) noexcept { return detail::trivial_begin(e); }; + return build_iterator(f, std::make_index_sequence()); + } + + template + template + inline auto xfunction_base::storage_cend() const noexcept -> const_storage_iterator + { + auto f = [](const auto& e) noexcept { return detail::trivial_end(e); }; + return build_iterator(f, std::make_index_sequence()); + } + + template + template + inline auto xfunction_base::storage_rbegin() const noexcept -> const_reverse_storage_iterator + { + return storage_crbegin(); + } + + template + template + inline auto xfunction_base::storage_rend() const noexcept -> const_reverse_storage_iterator + { + return storage_crend(); + } + + template + template + inline auto xfunction_base::storage_crbegin() const noexcept -> const_reverse_storage_iterator + { + return const_reverse_storage_iterator(storage_cend()); + } + + template + template + inline auto xfunction_base::storage_crend() const noexcept -> const_reverse_storage_iterator + { + return const_reverse_storage_iterator(storage_cbegin()); + } + + template + template + inline auto xfunction_base::stepper_begin(const S& shape) const noexcept -> const_stepper + { + auto f = [&shape](const auto& e) noexcept { return e.stepper_begin(shape); }; + return build_stepper(f, std::make_index_sequence()); + } + + template + template + inline auto xfunction_base::stepper_end(const S& shape, layout_type l) const noexcept -> const_stepper + { + auto f = [&shape, l](const auto& e) noexcept { return e.stepper_end(shape, l); }; + return build_stepper(f, std::make_index_sequence()); + } + + template + inline auto xfunction_base::data_element(size_type i) const -> const_reference + { + return data_element_impl(std::make_index_sequence(), i); + } + + template + template + inline xfunction_base::operator value_type() const + { + return operator()(); + } + + template + template + inline auto xfunction_base::load_simd(size_type i) const -> detail::simd_return_type_t + { + return load_simd_impl(std::make_index_sequence(), i); + } + + template + inline auto xfunction_base::arguments() const noexcept -> const tuple_type& + { + return m_e; + } + + template + template + inline layout_type xfunction_base::layout_impl(std::index_sequence) const noexcept + { + return compute_layout(std::get(m_e).layout()...); + } + + template + template + inline auto xfunction_base::access_impl(std::index_sequence, Args... args) const -> const_reference + { + XTENSOR_TRY(check_index(shape(), args...)); + XTENSOR_CHECK_DIMENSION(shape(), args...); + return m_f(std::get(m_e)(args...)...); + } + + template + template + inline auto xfunction_base::unchecked_impl(std::index_sequence, Args... args) const -> const_reference + { + return m_f(std::get(m_e).unchecked(args...)...); + } + + template + template + inline auto xfunction_base::element_access_impl(std::index_sequence, It first, It last) const -> const_reference + { + XTENSOR_TRY(check_element_index(shape(), first, last)); + return m_f((std::get(m_e).element(first, last))...); + } + + template + template + inline auto xfunction_base::data_element_impl(std::index_sequence, size_type i) const -> const_reference + { + return m_f((std::get(m_e).data_element(i))...); + } + + namespace detail + { +// TODO: add traits for batch_bool in xsimd and remove this ugly hack + + template + struct is_batch_bool + { + static constexpr bool value = false; + }; + +#ifdef XTENSOR_USE_XSIMD + template + struct is_batch_bool> + { + static constexpr bool value = true; + }; +#endif + + // This metafunction avoids loading boolean values as batches of floating points and + // reciprocally. However, we cannot always load data as batches of their scalar type + // since this prevents mixed arithmetic. + template + struct get_simd_type + { + using simd_value_type = typename std::decay_t::simd_value_type; + static constexpr bool is_arg_bool = is_batch_bool::value; + static constexpr bool is_res_bool = is_batch_bool::value; + using type = std::conditional_t>; + }; + + template + using get_simd_type_t = typename get_simd_type::type; + } + + template + template + inline auto xfunction_base::load_simd_impl(std::index_sequence, size_type i) const + { + return m_f.simd_apply((std::get(m_e) + .template load_simd, simd, simd_argument_type>>(i))...); + } + + template + template + inline auto xfunction_base::build_stepper(Func&& f, std::index_sequence) const noexcept -> const_stepper + { + return const_stepper(this, f(std::get(m_e))...); + } + + template + template + inline auto xfunction_base::build_iterator(Func&& f, std::index_sequence) const noexcept -> const_storage_iterator + { + return const_storage_iterator(this, f(std::get(m_e))...); + } + + template + inline auto xfunction_base::compute_dimension() const noexcept -> size_type + { + auto func = [](size_type d, auto&& e) noexcept { return (std::max)(d, e.dimension()); }; + return accumulate(func, size_type(0), m_e); + } + + /************************************* + * xfunction_iterator implementation * + *************************************/ + + template + template + inline xfunction_iterator::xfunction_iterator(const xfunction_type* func, It&&... it) noexcept + : p_f(func), m_it(std::forward(it)...) + { + } + + template + inline auto xfunction_iterator::operator++() -> self_type& + { + auto f = [](auto& it) { ++it; }; + for_each(f, m_it); + return *this; + } + + template + inline auto xfunction_iterator::operator--() -> self_type& + { + auto f = [](auto& it) { return --it; }; + for_each(f, m_it); + return *this; + } + + template + inline auto xfunction_iterator::operator+=(difference_type n) -> self_type& + { + auto f = [n](auto& it) { it += n; }; + for_each(f, m_it); + return *this; + } + + template + inline auto xfunction_iterator::operator-=(difference_type n) -> self_type& + { + auto f = [n](auto& it) { it -= n; }; + for_each(f, m_it); + return *this; + } + + template + inline auto xfunction_iterator::operator-(const self_type& rhs) const -> difference_type + { + return tuple_max_diff(std::make_index_sequence(), m_it, rhs.m_it); + } + + template + inline auto xfunction_iterator::operator*() const -> reference + { + return deref_impl(std::make_index_sequence()); + } + + template + inline bool xfunction_iterator::equal(const self_type& rhs) const + { + return p_f == rhs.p_f && m_it == rhs.m_it; + } + + template + inline bool xfunction_iterator::less_than(const self_type& rhs) const + { + return p_f == rhs.p_f && m_it < rhs.m_it; + } + + template + template + inline auto xfunction_iterator::deref_impl(std::index_sequence) const -> reference + { + return (p_f->m_f)(*std::get(m_it)...); + } + + template + template + inline auto xfunction_iterator::tuple_max_diff(std::index_sequence, + const data_type& lhs, + const data_type& rhs) const -> difference_type + { + auto diff = std::make_tuple((std::get(lhs) - std::get(rhs))...); + auto func = [](difference_type n, auto&& v) { return (std::max)(n, v); }; + return accumulate(func, difference_type(0), diff); + } + + template + inline bool operator==(const xfunction_iterator& it1, + const xfunction_iterator& it2) + { + return it1.equal(it2); + } + + template + inline bool operator<(const xfunction_iterator& it1, + const xfunction_iterator& it2) + { + return it1.less_than(it2); + } + + /************************************ + * xfunction_stepper implementation * + ************************************/ + + template + template + inline xfunction_stepper::xfunction_stepper(const xfunction_type* func, It&&... it) noexcept + : p_f(func), m_it(std::forward(it)...) + { + } + + template + inline void xfunction_stepper::step(size_type dim) + { + auto f = [dim](auto& it) { it.step(dim); }; + for_each(f, m_it); + } + + template + inline void xfunction_stepper::step_back(size_type dim) + { + auto f = [dim](auto& it) { it.step_back(dim); }; + for_each(f, m_it); + } + + template + inline void xfunction_stepper::step(size_type dim, size_type n) + { + auto f = [dim, n](auto& it) { it.step(dim, n); }; + for_each(f, m_it); + } + + template + inline void xfunction_stepper::step_back(size_type dim, size_type n) + { + auto f = [dim, n](auto& it) { it.step_back(dim, n); }; + for_each(f, m_it); + } + + template + inline void xfunction_stepper::reset(size_type dim) + { + auto f = [dim](auto& it) { it.reset(dim); }; + for_each(f, m_it); + } + + template + inline void xfunction_stepper::reset_back(size_type dim) + { + auto f = [dim](auto& it) { it.reset_back(dim); }; + for_each(f, m_it); + } + + template + inline void xfunction_stepper::to_begin() + { + auto f = [](auto& it) { it.to_begin(); }; + for_each(f, m_it); + } + + template + inline void xfunction_stepper::to_end(layout_type l) + { + auto f = [l](auto& it) { it.to_end(l); }; + for_each(f, m_it); + } + + template + inline auto xfunction_stepper::operator*() const -> reference + { + return deref_impl(std::make_index_sequence()); + } + + template + template + inline auto xfunction_stepper::deref_impl(std::index_sequence) const -> reference + { + return (p_f->m_f)(*std::get(m_it)...); + } + + template + template + inline ST xfunction_stepper::step_simd_impl(std::index_sequence) + { + return (p_f->m_f.simd_apply)(std::get(m_it).template + step_simd, ST, typename xfunction_type::simd_argument_type>>()...); + } + + template + template + inline ST xfunction_stepper::step_simd() + { + return step_simd_impl(std::make_index_sequence()); + } + + template + template + inline auto xfunction_stepper::step_leading_impl(std::index_sequence) + -> value_type + { + return (p_f->m_f)(std::get(m_it).step_leading()...); + } + + template + inline auto xfunction_stepper::step_leading() + -> value_type + { + return step_leading_impl(std::make_index_sequence()); + } + + /**************************** + * xfunction implementation * + ****************************/ + + /** + * Constructs an xfunction applying the specified function to the given + * arguments. + * @param f the function to apply + * @param e the \ref xexpression arguments + */ + template + template + xfunction::xfunction(Func&& f, CTA&&... e) noexcept + : base_type(std::forward(f), std::forward(e)...) + { + } +} + +#endif diff --git a/vendor/xtensor/include/xtensor/xfunctor_view.hpp b/vendor/xtensor/include/xtensor/xfunctor_view.hpp new file mode 100644 index 0000000000..6cba79575a --- /dev/null +++ b/vendor/xtensor/include/xtensor/xfunctor_view.hpp @@ -0,0 +1,1349 @@ +/*************************************************************************** +* 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_FUNCTOR_VIEW_HPP +#define XTENSOR_FUNCTOR_VIEW_HPP + +#include +#include +#include +#include +#include + +#include + +#include "xtensor/xexpression.hpp" +#include "xtensor/xiterator.hpp" +#include "xtensor/xsemantic.hpp" +#include "xtensor/xutils.hpp" + +#include "xtensor/xarray.hpp" +#include "xtensor/xtensor.hpp" + +namespace xt +{ + + /***************************** + * xfunctor_view declaration * + *****************************/ + + template + class xfunctor_iterator; + + template + class xfunctor_stepper; + + template + class xfunctor_view; + + /******************************** + * xfunctor_view_temporary_type * + ********************************/ + + namespace detail + { + template + struct functorview_temporary_type_impl + { + using type = xarray; + }; + + template + struct functorview_temporary_type_impl, L> + { + using type = xtensor; + }; + } + + template + struct xfunctor_view_temporary_type + { + using type = typename detail::functorview_temporary_type_impl::type; + }; + + template + struct xcontainer_inner_types> + { + using xexpression_type = std::decay_t; + using temporary_type = typename xfunctor_view_temporary_type::type; + }; + +#define DL XTENSOR_DEFAULT_LAYOUT + /** + * @class xfunctor_view + * @brief View of an xexpression . + * + * The xfunctor_view class is an expression addressing its elements by applying a functor to the + * corresponding element of an underlying expression. Unlike e.g. xgenerator, an xfunctor_view is + * an lvalue. It is used e.g. to access real and imaginary parts of complex expressions. + * + * xfunctor_view is not meant to be used directly, but through helper functions such + * as \ref real or \ref imag. + * + * @tparam F the functor type to be applied to the elements of specified expression. + * @tparam CT the closure type of the \ref xexpression type underlying this view + * + * @sa real, imag + */ + template + class xfunctor_view : public xview_semantic> + { + public: + + using self_type = xfunctor_view; + using xexpression_type = std::decay_t; + using semantic_base = xview_semantic; + using functor_type = typename std::decay_t; + + using value_type = typename functor_type::value_type; + using reference = typename functor_type::reference; + using const_reference = typename functor_type::const_reference; + using pointer = typename functor_type::pointer; + using const_pointer = typename functor_type::const_pointer; + using size_type = typename xexpression_type::size_type; + using difference_type = typename xexpression_type::difference_type; + + using shape_type = typename xexpression_type::shape_type; + + static constexpr layout_type static_layout = xexpression_type::static_layout; + static constexpr bool contiguous_layout = false; + + using stepper = xfunctor_stepper; + using const_stepper = xfunctor_stepper; + + template + using layout_iterator = xfunctor_iterator>; + template + using const_layout_iterator = xfunctor_iterator>; + + template + using reverse_layout_iterator = xfunctor_iterator>; + template + using const_reverse_layout_iterator = xfunctor_iterator>; + + template + using broadcast_iterator = xfunctor_iterator>; + template + using const_broadcast_iterator = xfunctor_iterator>; + + template + using reverse_broadcast_iterator = xfunctor_iterator>; + template + using const_reverse_broadcast_iterator = xfunctor_iterator>; + + using storage_iterator = xfunctor_iterator; + using const_storage_iterator = xfunctor_iterator; + using reverse_storage_iterator = xfunctor_iterator; + using const_reverse_storage_iterator = xfunctor_iterator; + + using iterator = xfunctor_iterator; + using const_iterator = xfunctor_iterator; + using reverse_iterator = xfunctor_iterator; + using const_reverse_iterator = xfunctor_iterator; + + explicit xfunctor_view(CT) noexcept; + + template + xfunctor_view(Func&&, E&&) noexcept; + + template + self_type& operator=(const xexpression& e); + + template + disable_xexpression& operator=(const E& e); + + size_type size() const noexcept; + size_type dimension() const noexcept; + const shape_type& shape() const noexcept; + layout_type layout() const noexcept; + + template + reference operator()(Args... args); + + template + reference at(Args... args); + + template + reference unchecked(Args... args); + + template + disable_integral_t operator[](const S& index); + template + reference operator[](std::initializer_list index); + reference operator[](size_type i); + + template + reference element(IT first, IT last); + + template + const_reference operator()(Args... args) const; + + template + const_reference unchecked(Args... args) const; + + template + const_reference at(Args... args) const; + + template + disable_integral_t operator[](const S& index) const; + template + const_reference operator[](std::initializer_list index) const; + const_reference operator[](size_type i) const; + + template + const_reference element(IT first, IT last) const; + + template + bool broadcast_shape(S& shape, bool reuse_cache = false) const; + + template + bool is_trivial_broadcast(const S& strides) const; + + template + auto begin() noexcept; + template + auto end() noexcept; + + template + auto begin() const noexcept; + template + auto end() const noexcept; + template + auto cbegin() const noexcept; + template + auto cend() const noexcept; + + template + auto rbegin() noexcept; + template + auto rend() noexcept; + + template + auto rbegin() const noexcept; + template + auto rend() const noexcept; + template + auto crbegin() const noexcept; + template + auto crend() const noexcept; + + template + broadcast_iterator begin(const S& shape) noexcept; + template + broadcast_iterator end(const S& shape) noexcept; + + template + const_broadcast_iterator begin(const S& shape) const noexcept; + template + const_broadcast_iterator end(const S& shape) const noexcept; + template + const_broadcast_iterator cbegin(const S& shape) const noexcept; + template + const_broadcast_iterator cend(const S& shape) const noexcept; + + template + reverse_broadcast_iterator rbegin(const S& shape) noexcept; + template + reverse_broadcast_iterator rend(const S& shape) noexcept; + + template + const_reverse_broadcast_iterator rbegin(const S& shape) const noexcept; + template + const_reverse_broadcast_iterator rend(const S& shape) const noexcept; + template + const_reverse_broadcast_iterator crbegin(const S& shape) const noexcept; + template + const_reverse_broadcast_iterator crend(const S& shape) const noexcept; + + template + storage_iterator storage_begin() noexcept; + template + storage_iterator storage_end() noexcept; + + template + const_storage_iterator storage_begin() const noexcept; + template + const_storage_iterator storage_end() const noexcept; + template + const_storage_iterator storage_cbegin() const noexcept; + template + const_storage_iterator storage_cend() const noexcept; + + template + reverse_storage_iterator storage_rbegin() noexcept; + template + reverse_storage_iterator storage_rend() noexcept; + + template + const_reverse_storage_iterator storage_rbegin() const noexcept; + template + const_reverse_storage_iterator storage_rend() const noexcept; + template + const_reverse_storage_iterator storage_crbegin() const noexcept; + template + const_reverse_storage_iterator storage_crend() const noexcept; + + template + stepper stepper_begin(const S& shape) noexcept; + template + stepper stepper_end(const S& shape, layout_type l) noexcept; + template + const_stepper stepper_begin(const S& shape) const noexcept; + template + const_stepper stepper_end(const S& shape, layout_type l) const noexcept; + + private: + + CT m_e; + functor_type m_functor; + + using temporary_type = typename xcontainer_inner_types::temporary_type; + void assign_temporary_impl(temporary_type&& tmp); + friend class xview_semantic>; + }; + +#undef DL + + /********************************* + * xfunctor_iterator declaration * + *********************************/ + + template + class xfunctor_iterator : public xtl::xrandom_access_iterator_base, + typename F::value_type, + typename std::iterator_traits::difference_type, + typename xtl::xproxy_wrapper()(*(IT())))>::pointer, + xtl::xproxy_wrapper()(*(IT())))>> + { + public: + + using functor_type = std::decay_t; + using subiterator_traits = std::iterator_traits; + + using value_type = typename functor_type::value_type; + using reference = xtl::xproxy_wrapper()(*(IT())))>; + using pointer = typename reference::pointer; + using difference_type = typename subiterator_traits::difference_type; + using iterator_category = typename subiterator_traits::iterator_category; + + using self_type = xfunctor_iterator; + + xfunctor_iterator(const IT&, const functor_type*); + + self_type& operator++(); + self_type& operator--(); + + self_type& operator+=(difference_type n); + self_type& operator-=(difference_type n); + + difference_type operator-(xfunctor_iterator rhs) const; + + reference operator*() const; + pointer operator->() const; + + bool equal(const xfunctor_iterator& rhs) const; + bool less_than(const xfunctor_iterator& rhs) const; + + private: + + IT m_it; + const functor_type* p_functor; + }; + + template + bool operator==(const xfunctor_iterator& lhs, + const xfunctor_iterator& rhs); + + template + bool operator<(const xfunctor_iterator& lhs, + const xfunctor_iterator& rhs); + + /******************************** + * xfunctor_stepper declaration * + ********************************/ + + template + class xfunctor_stepper + { + public: + + using functor_type = std::decay_t; + + using value_type = typename functor_type::value_type; + using reference = apply_cv_t; + using pointer = std::remove_reference_t*; + using size_type = typename ST::size_type; + using difference_type = typename ST::difference_type; + + xfunctor_stepper() = default; + xfunctor_stepper(const ST&, const functor_type*); + + reference operator*() const; + + void step(size_type dim); + void step_back(size_type dim); + void step(size_type dim, size_type n); + void step_back(size_type dim, size_type n); + void reset(size_type dim); + void reset_back(size_type dim); + + void to_begin(); + void to_end(layout_type); + + private: + + ST m_stepper; + const functor_type* p_functor; + }; + + /******************************** + * xfunctor_view implementation * + ********************************/ + + /** + * @name Constructors + */ + //@{ + + /** + * Constructs an xfunctor_view expression wrappering the specified \ref xexpression. + * + * @param e the underlying expression + */ + template + inline xfunctor_view::xfunctor_view(CT e) noexcept + : m_e(e), m_functor(functor_type()) + { + } + + /** + * Constructs an xfunctor_view expression wrappering the specified \ref xexpression. + * + * @param func the functor to be applied to the elements of the underlying expression. + * @param e the underlying expression + */ + template + template + inline xfunctor_view::xfunctor_view(Func&& func, E&& e) noexcept + : m_e(std::forward(e)), m_functor(std::forward(func)) + { + } + //@} + + /** + * @name Extended copy semantic + */ + //@{ + /** + * The extended assignment operator. + */ + template + template + inline auto xfunctor_view::operator=(const xexpression& e) -> self_type& + { + bool cond = (e.derived_cast().shape().size() == dimension()) && std::equal(shape().begin(), shape().end(), e.derived_cast().shape().begin()); + if (!cond) + { + semantic_base::operator=(broadcast(e.derived_cast(), shape())); + } + else + { + semantic_base::operator=(e); + } + return *this; + } + //@} + + template + template + inline auto xfunctor_view::operator=(const E& e) -> disable_xexpression& + { + std::fill(begin(), end(), e); + return *this; + } + + template + inline void xfunctor_view::assign_temporary_impl(temporary_type&& tmp) + { + std::copy(tmp.cbegin(), tmp.cend(), begin()); + } + + /** + * @name Size and shape + */ + /** + * Returns the size of the expression. + */ + template + inline auto xfunctor_view::size() const noexcept -> size_type + { + return m_e.size(); + } + + /** + * Returns the number of dimensions of the expression. + */ + template + inline auto xfunctor_view::dimension() const noexcept -> size_type + { + return m_e.dimension(); + } + + /** + * Returns the shape of the expression. + */ + template + inline auto xfunctor_view::shape() const noexcept -> const shape_type& + { + return m_e.shape(); + } + + /** + * Returns the layout_type of the expression. + */ + template + inline layout_type xfunctor_view::layout() const noexcept + { + return m_e.layout(); + } + //@} + + /** + * @name Data + */ + /** + * Returns a 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 + template + inline auto xfunctor_view::operator()(Args... args) -> reference + { + XTENSOR_TRY(check_index(shape(), args...)); + XTENSOR_CHECK_DIMENSION(shape(), args...); + return m_functor(m_e(args...)); + } + + /** + * Returns a reference to the element at the specified position in the expression, + * after dimension and bounds checking. + * @param args a list of indices specifying the position in the function. Indices + * must be unsigned integers, the number of indices should be equal to the number of dimensions + * of the expression. + * @exception std::out_of_range if the number of argument is greater than the number of dimensions + * or if indices are out of bounds. + */ + template + template + inline auto xfunctor_view::at(Args... args) -> reference + { + check_access(shape(), args...); + return this->operator()(args...); + } + + /** + * Returns a 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 a = {{0, 1}, {2, 3}}; + * xt::xarray b = {0, 1}; + * auto fd = a + b; + * double res = fd.uncheked(0, 1); + * \endcode + */ + template + template + inline auto xfunctor_view::unchecked(Args... args) -> reference + { + return m_functor(m_e.unchecked(args...)); + } + + /** + * Returns a reference to the element at the specified position in the expression. + * @param index a sequence of indices specifying the position in the function. Indices + * must be unsigned integers, the number of indices in the sequence should be equal or greater + * than the number of dimensions of the container. + */ + template + template + inline auto xfunctor_view::operator[](const S& index) + -> disable_integral_t + { + return m_functor(m_e[index]); + } + + template + template + inline auto xfunctor_view::operator[](std::initializer_list index) + -> reference + { + return m_functor(m_e[index]); + } + + template + inline auto xfunctor_view::operator[](size_type i) -> reference + { + return operator()(i); + } + + /** + * Returns a 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 + template + inline auto xfunctor_view::element(IT first, IT last) -> reference + { + XTENSOR_TRY(check_element_index(shape(), first, last)); + return m_functor(m_e.element(first, last)); + } + + /** + * 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 + template + inline auto xfunctor_view::operator()(Args... args) const -> const_reference + { + XTENSOR_TRY(check_index(shape(), args...)); + XTENSOR_CHECK_DIMENSION(shape(), args...); + return m_functor(m_e(args...)); + } + + /** + * Returns a constant reference to the element at the specified position in the expression, + * after dimension and bounds checking. + * @param args a list of indices specifying the position in the function. Indices + * must be unsigned integers, the number of indices should be equal to the number of dimensions + * of the expression. + * @exception std::out_of_range if the number of argument is greater than the number of dimensions + * or if indices are out of bounds. + */ + template + template + inline auto xfunctor_view::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 a = {{0, 1}, {2, 3}}; + * xt::xarray b = {0, 1}; + * auto fd = a + b; + * double res = fd.uncheked(0, 1); + * \endcode + */ + template + template + inline auto xfunctor_view::unchecked(Args... args) const -> const_reference + { + return m_functor(m_e.unchecked(args...)); + } + + /** + * Returns a constant reference to the element at the specified position in the expression. + * @param index a sequence of indices specifying the position in the function. Indices + * must be unsigned integers, the number of indices in the sequence should be equal or greater + * than the number of dimensions of the container. + */ + template + template + inline auto xfunctor_view::operator[](const S& index) const + -> disable_integral_t + { + return m_functor(m_e[index]); + } + + template + template + inline auto xfunctor_view::operator[](std::initializer_list index) const + -> const_reference + { + return m_functor(m_e[index]); + } + + template + inline auto xfunctor_view::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 + template + inline auto xfunctor_view::element(IT first, IT last) const -> const_reference + { + XTENSOR_TRY(check_element_index(shape(), first, last)); + return m_functor(m_e.element(first, last)); + } + //@} + + /** + * @name Broadcasting + */ + //@{ + /** + * Broadcast the shape of the function to the specified parameter. + * @param shape the result shape + * @param reuse_cache boolean for reusing a previously computed shape + * @return a boolean indicating whether the broadcasting is trivial + */ + template + template + inline bool xfunctor_view::broadcast_shape(S& shape, bool reuse_cache) const + { + return m_e.broadcast_shape(shape, reuse_cache); + } + + /** + * 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 + template + inline bool xfunctor_view::is_trivial_broadcast(const S& strides) const + { + return m_e.is_trivial_broadcast(strides); + } + //@} + + /** + * @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 + template + inline auto xfunctor_view::begin() noexcept + { + return xfunctor_iterator())> + (m_e.template begin(), &m_functor); + } + + /** + * 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 + template + inline auto xfunctor_view::end() noexcept + { + return xfunctor_iterator())> + (m_e.template end(), &m_functor); + } + + /** + * 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 + template + inline auto xfunctor_view::begin() const noexcept + { + return this->template cbegin(); + } + + /** + * 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 + template + inline auto xfunctor_view::end() const noexcept + { + return this->template cend(); + } + + /** + * 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 + template + inline auto xfunctor_view::cbegin() const noexcept + { + return xfunctor_iterator())> + (m_e.template cbegin(), &m_functor); + } + + /** + * 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 + template + inline auto xfunctor_view::cend() const noexcept + { + return xfunctor_iterator())> + (m_e.template cend(), &m_functor); + } + //@} + + /** + * @name 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 + template + inline auto xfunctor_view::begin(const S& shape) noexcept -> broadcast_iterator + { + return broadcast_iterator(m_e.template begin(shape), &m_functor); + } + + /** + * 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 + template + inline auto xfunctor_view::end(const S& shape) noexcept -> broadcast_iterator + { + return broadcast_iterator(m_e.template end(shape), &m_functor); + } + + /** + * 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 + template + inline auto xfunctor_view::begin(const S& shape) const noexcept -> const_broadcast_iterator + { + return cbegin(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 + template + inline auto xfunctor_view::end(const S& shape) const noexcept -> const_broadcast_iterator + { + return cend(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 + template + inline auto xfunctor_view::cbegin(const S& shape) const noexcept -> const_broadcast_iterator + { + return const_broadcast_iterator(m_e.template cbegin(shape), &m_functor); + } + + /** + * 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 + template + inline auto xfunctor_view::cend(const S& shape) const noexcept -> const_broadcast_iterator + { + return const_broadcast_iterator(m_e.template cend(shape), &m_functor); + } + //@} + + /** + * @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 + template + inline auto xfunctor_view::rbegin() noexcept + { + return xfunctor_iterator())> + (m_e.template rbegin(), &m_functor); + } + + /** + * 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 + template + inline auto xfunctor_view::rend() noexcept + { + return xfunctor_iterator())> + (m_e.template rend(), &m_functor); + } + + /** + * 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 + template + inline auto xfunctor_view::rbegin() const noexcept + { + return this->template crbegin(); + } + + /** + * 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 + template + inline auto xfunctor_view::rend() const noexcept + { + return this->template crend(); + } + + /** + * 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 + template + inline auto xfunctor_view::crbegin() const noexcept + { + return xfunctor_iterator())> + (m_e.template rbegin(), &m_functor); + } + + /** + * 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 + template + inline auto xfunctor_view::crend() const noexcept + { + return xfunctor_iterator())> + (m_e.template rend(), &m_functor); + } + //@} + + /** + * @name Reverse 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 + template + inline auto xfunctor_view::rbegin(const S& shape) noexcept -> reverse_broadcast_iterator + { + return reverse_broadcast_iterator(m_e.template rbegin(shape), &m_functor); + } + + /** + * 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 + template + inline auto xfunctor_view::rend(const S& shape) noexcept -> reverse_broadcast_iterator + { + return reverse_broadcast_iterator(m_e.template rend(shape), &m_functor); + } + + /** + * 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 + template + inline auto xfunctor_view::rbegin(const S& shape) const noexcept -> const_reverse_broadcast_iterator + { + return crbegin(shape); + } + + /** + * Returns a constant iterator to the element following the last element + * of the reversed expression. + * @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 + template + inline auto xfunctor_view::rend(const S& /*shape*/) const noexcept -> const_reverse_broadcast_iterator + { + return crend(); + } + + /** + * 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 + template + inline auto xfunctor_view::crbegin(const S& /*shape*/) const noexcept -> const_reverse_broadcast_iterator + { + return const_reverse_broadcast_iterator(m_e.template crbegin(), &m_functor); + } + + /** + * Returns a constant iterator to the element following the last element + * of the reversed expression. + * @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 + template + inline auto xfunctor_view::crend(const S& shape) const noexcept -> const_reverse_broadcast_iterator + { + return const_reverse_broadcast_iterator(m_e.template crend(shape), &m_functor); + } + //@} + + template + template + inline auto xfunctor_view::storage_begin() noexcept -> storage_iterator + { + return storage_iterator(m_e.template storage_begin(), &m_functor); + } + + template + template + inline auto xfunctor_view::storage_end() noexcept -> storage_iterator + { + return storage_iterator(m_e.template storage_end(), &m_functor); + } + + template + template + inline auto xfunctor_view::storage_begin() const noexcept -> const_storage_iterator + { + return const_storage_iterator(m_e.template storage_begin(), &m_functor); + } + + template + template + inline auto xfunctor_view::storage_end() const noexcept -> const_storage_iterator + { + return const_storage_iterator(m_e.template storage_end(), &m_functor); + } + + template + template + inline auto xfunctor_view::storage_cbegin() const noexcept -> const_storage_iterator + { + return const_storage_iterator(m_e.template storage_cbegin(), &m_functor); + } + + template + template + inline auto xfunctor_view::storage_cend() const noexcept -> const_storage_iterator + { + return const_storage_iterator(m_e.template storage_cend(), &m_functor); + } + + template + template + inline auto xfunctor_view::storage_rbegin() noexcept -> reverse_storage_iterator + { + return reverse_storage_iterator(m_e.template storage_rbegin(), &m_functor); + } + + template + template + inline auto xfunctor_view::storage_rend() noexcept -> reverse_storage_iterator + { + return reverse_storage_iterator(m_e.template storage_rend(), &m_functor); + } + + template + template + inline auto xfunctor_view::storage_rbegin() const noexcept -> const_reverse_storage_iterator + { + return const_reverse_storage_iterator(m_e.template storage_rbegin(), &m_functor); + } + + template + template + inline auto xfunctor_view::storage_rend() const noexcept -> const_reverse_storage_iterator + { + return const_reverse_storage_iterator(m_e.template storage_rend(), &m_functor); + } + + template + template + inline auto xfunctor_view::storage_crbegin() const noexcept -> const_reverse_storage_iterator + { + return const_reverse_storage_iterator(m_e.template storage_crbegin(), &m_functor); + } + + template + template + inline auto xfunctor_view::storage_crend() const noexcept -> const_reverse_storage_iterator + { + return const_reverse_storage_iterator(m_e.template storage_crend(), &m_functor); + } + + /*************** + * stepper api * + ***************/ + + template + template + inline auto xfunctor_view::stepper_begin(const S& shape) noexcept -> stepper + { + return stepper(m_e.stepper_begin(shape), &m_functor); + } + + template + template + inline auto xfunctor_view::stepper_end(const S& shape, layout_type l) noexcept -> stepper + { + return stepper(m_e.stepper_end(shape, l), &m_functor); + } + + template + template + inline auto xfunctor_view::stepper_begin(const S& shape) const noexcept -> const_stepper + { + const xexpression_type& const_m_e = m_e; + return const_stepper(const_m_e.stepper_begin(shape), &m_functor); + } + + template + template + inline auto xfunctor_view::stepper_end(const S& shape, layout_type l) const noexcept -> const_stepper + { + const xexpression_type& const_m_e = m_e; + return const_stepper(const_m_e.stepper_end(shape, l), &m_functor); + } + + /************************************ + * xfunctor_iterator implementation * + ************************************/ + + template + xfunctor_iterator::xfunctor_iterator(const IT& it, const functor_type* pf) + : m_it(it), p_functor(pf) + { + } + + template + inline auto xfunctor_iterator::operator++() -> self_type& + { + ++m_it; + return *this; + } + + template + inline auto xfunctor_iterator::operator--() -> self_type& + { + --m_it; + return *this; + } + + template + inline auto xfunctor_iterator::operator+=(difference_type n) -> self_type& + { + m_it += n; + return *this; + } + + template + inline auto xfunctor_iterator::operator-=(difference_type n) -> self_type& + { + m_it -= n; + return *this; + } + + template + inline auto xfunctor_iterator::operator-(xfunctor_iterator rhs) const -> difference_type + { + return m_it - rhs.m_it; + } + + template + auto xfunctor_iterator::operator*() const -> reference + { + return xtl::proxy_wrapper((*p_functor)(*m_it)); + } + + template + auto xfunctor_iterator::operator->() const -> pointer + { + return &(operator*()); + } + + template + auto xfunctor_iterator::equal(const xfunctor_iterator& rhs) const -> bool + { + return m_it == rhs.m_it; + } + + template + auto xfunctor_iterator::less_than(const xfunctor_iterator& rhs) const -> bool + { + return m_it < rhs.m_it; + } + + template + bool operator==(const xfunctor_iterator& lhs, + const xfunctor_iterator& rhs) + { + return lhs.equal(rhs); + } + + template + bool operator<(const xfunctor_iterator& lhs, + const xfunctor_iterator& rhs) + { + return !lhs.less_than(rhs); + } + + /*********************************** + * xfunctor_stepper implementation * + ***********************************/ + + template + xfunctor_stepper::xfunctor_stepper(const ST& stepper, const functor_type* pf) + : m_stepper(stepper), p_functor(pf) + { + } + + template + auto xfunctor_stepper::operator*() const -> reference + { + return (*p_functor)(*m_stepper); + } + + template + void xfunctor_stepper::step(size_type dim) + { + m_stepper.step(dim); + } + + template + void xfunctor_stepper::step_back(size_type dim) + { + m_stepper.step_back(dim); + } + + template + void xfunctor_stepper::step(size_type dim, size_type n) + { + m_stepper.step(dim, n); + } + + template + void xfunctor_stepper::step_back(size_type dim, size_type n) + { + m_stepper.step_back(dim, n); + } + + template + void xfunctor_stepper::reset(size_type dim) + { + m_stepper.reset(dim); + } + + template + void xfunctor_stepper::reset_back(size_type dim) + { + m_stepper.reset_back(dim); + } + + template + void xfunctor_stepper::to_begin() + { + m_stepper.to_begin(); + } + + template + void xfunctor_stepper::to_end(layout_type l) + { + m_stepper.to_end(l); + } +} +#endif diff --git a/vendor/xtensor/include/xtensor/xgenerator.hpp b/vendor/xtensor/include/xtensor/xgenerator.hpp new file mode 100644 index 0000000000..f1118fe439 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xgenerator.hpp @@ -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 +#include +#include +#include +#include +#include + +#include + +#include "xexpression.hpp" +#include "xiterable.hpp" +#include "xstrides.hpp" +#include "xutils.hpp" + +namespace xt +{ + + /************** + * xgenerator * + **************/ + + template + class xgenerator; + + template + struct xiterable_inner_types> + { + using inner_shape_type = S; + using const_stepper = xindexed_stepper, 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 xgenerator : public xexpression>, + public xconst_iterable> + { + public: + + using self_type = xgenerator; + using functor_type = typename std::remove_reference::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; + 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 + 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 + const_reference operator()(Args... args) const; + template + const_reference at(Args... args) const; + template + const_reference unchecked(Args... args) const; + template + disable_integral_t operator[](const OS& index) const; + template + const_reference operator[](std::initializer_list index) const; + const_reference operator[](size_type i) const; + + template + const_reference element(It first, It last) const; + + template + bool broadcast_shape(O& shape, bool reuse_cache = false) const; + + template + bool is_trivial_broadcast(const O& /*strides*/) const noexcept; + + template + const_stepper stepper_begin(const O& shape) const noexcept; + template + const_stepper stepper_end(const O& shape, layout_type) const noexcept; + + template ::value>> + void assign_to(xexpression& e) const noexcept; + + private: + + template + void adapt_index() const; + + template + 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 + template + inline xgenerator::xgenerator(Func&& f, const S& shape) noexcept + : m_f(std::forward(f)), m_shape(shape) + { + } + //@} + + /** + * @name Size and shape + */ + //@{ + /** + * Returns the size of the expression. + */ + template + inline auto xgenerator::size() const noexcept -> size_type + { + return compute_size(shape()); + } + + /** + * Returns the number of dimensions of the function. + */ + template + inline auto xgenerator::dimension() const noexcept -> size_type + { + return m_shape.size(); + } + + /** + * Returns the shape of the xgenerator. + */ + template + inline auto xgenerator::shape() const noexcept -> const inner_shape_type& + { + return m_shape; + } + + template + inline layout_type xgenerator::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 + template + inline auto xgenerator::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 + template + inline auto xgenerator::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 a = {{0, 1}, {2, 3}}; + * xt::xarray b = {0, 1}; + * auto fd = a + b; + * double res = fd.uncheked(0, 1); + * \endcode + */ + template + template + inline auto xgenerator::unchecked(Args... args) const -> const_reference + { + return m_f(args...); + } + + template + template + inline auto xgenerator::operator[](const OS& index) const + -> disable_integral_t + { + return element(index.cbegin(), index.cend()); + } + + template + template + inline auto xgenerator::operator[](std::initializer_list index) const + -> const_reference + { + return element(index.begin(), index.end()); + } + + template + inline auto xgenerator::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 + template + inline auto xgenerator::element(It first, It last) const -> const_reference + { + using bounded_iterator = xbounded_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 + template + inline bool xgenerator::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 + template + inline bool xgenerator::is_trivial_broadcast(const O& /*strides*/) const noexcept + { + return false; + } + //@} + + template + template + inline auto xgenerator::stepper_begin(const O& shape) const noexcept -> const_stepper + { + size_type offset = shape.size() - dimension(); + return const_stepper(this, offset); + } + + template + template + inline auto xgenerator::stepper_end(const O& shape, layout_type) const noexcept -> const_stepper + { + size_type offset = shape.size() - dimension(); + return const_stepper(this, offset, true); + } + + template + template + inline void xgenerator::assign_to(xexpression& e) const noexcept + { + e.derived_cast().resize(m_shape); + m_f.assign_to(e); + } + + template + template + inline void xgenerator::adapt_index() const + { + } + + template + template + inline void xgenerator::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(args...); + } + else + { + if (static_cast(arg) >= m_shape[dim] && m_shape[dim] == 1) + { + arg = 0; + } + adapt_index(args...); + } + } + + namespace detail + { +#ifdef X_OLD_CLANG + template + inline auto make_xgenerator(Functor&& f, std::initializer_list shape) noexcept + { + using shape_type = std::vector; + using type = xgenerator; + return type(std::forward(f), xtl::forward_sequence(shape)); + } +#else + template + inline auto make_xgenerator(Functor&& f, const I (&shape)[L]) noexcept + { + using shape_type = std::array; + using type = xgenerator; + return type(std::forward(f), xtl::forward_sequence(shape)); + } +#endif + + template + inline auto make_xgenerator(Functor&& f, S&& shape) noexcept + { + using type = xgenerator>; + return type(std::forward(f), std::forward(shape)); + } + } +} + +#endif diff --git a/vendor/xtensor/include/xtensor/xindex_view.hpp b/vendor/xtensor/include/xtensor/xindex_view.hpp new file mode 100644 index 0000000000..ef46c1bbbd --- /dev/null +++ b/vendor/xtensor/include/xtensor/xindex_view.hpp @@ -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 +#include +#include +#include +#include + +#include "xexpression.hpp" +#include "xiterable.hpp" +#include "xstrides.hpp" +#include "xutils.hpp" + +namespace xt +{ + + template + class xindex_view; + + template + struct xcontainer_inner_types> + { + using xexpression_type = std::decay_t; + using temporary_type = xarray; + }; + + template + struct xiterable_inner_types> + { + using inner_shape_type = std::array; + using const_stepper = xindexed_stepper, true>; + using stepper = xindexed_stepper, 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 xindex_view : public xview_semantic>, + public xiterable> + { + public: + + using self_type = xindex_view; + using xexpression_type = std::decay_t; + using semantic_base = xview_semantic; + + 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; + 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::temporary_type; + using base_index_type = xindex_type_t; + + static constexpr layout_type static_layout = layout_type::dynamic; + static constexpr bool contiguous_layout = false; + + template + xindex_view(CTA&& e, I2&& indices) noexcept; + + template + self_type& operator=(const xexpression& e); + + template + disable_xexpression& 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 + void fill(const T& value); + + reference operator()(size_type idx = size_type(0)); + template + reference operator()(size_type idx0, size_type idx1, Args... args); + reference unchecked(size_type idx); + template + disable_integral_t operator[](const S& index); + template + reference operator[](std::initializer_list index); + reference operator[](size_type i); + + template + reference element(It first, It last); + + const_reference operator()(size_type idx = size_type(0)) const; + template + const_reference operator()(size_type idx0, size_type idx1, Args... args) const; + const_reference unchecked(size_type idx) const; + template + disable_integral_t operator[](const S& index) const; + template + const_reference operator[](std::initializer_list index) const; + const_reference operator[](size_type i) const; + + template + const_reference element(It first, It last) const; + + template + bool broadcast_shape(O& shape, bool reuse_cache = false) const; + + template + bool is_trivial_broadcast(const O& /*strides*/) const noexcept; + + template + stepper stepper_begin(const ST& shape); + template + stepper stepper_end(const ST& shape, layout_type); + + template + const_stepper stepper_begin(const ST& shape) const; + template + 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>; + }; + + /*************** + * 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 xfiltration + { + public: + + using self_type = xfiltration; + using xexpression_type = std::decay_t; + using const_reference = typename xexpression_type::const_reference; + + template + xfiltration(ECTA&& e, CCTA&& condition); + + template + disable_xexpression operator=(const E&); + + template + disable_xexpression operator+=(const E&); + + template + disable_xexpression operator-=(const E&); + + template + disable_xexpression operator*=(const E&); + + template + disable_xexpression operator/=(const E&); + + template + disable_xexpression operator%=(const E&); + + private: + + template + 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 + template + inline xindex_view::xindex_view(CTA&& e, I2&& indices) noexcept + : m_e(std::forward(e)), m_indices(std::forward(indices)), m_shape({ m_indices.size() }) + { + } + //@} + + /** + * @name Extended copy semantic + */ + //@{ + /** + * The extended assignment operator. + */ + template + template + inline auto xindex_view::operator=(const xexpression& e) -> self_type& + { + return semantic_base::operator=(e); + } + //@} + + template + template + inline auto xindex_view::operator=(const E& e) -> disable_xexpression& + { + std::fill(this->begin(), this->end(), e); + return *this; + } + + template + inline void xindex_view::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 + inline auto xindex_view::size() const noexcept -> size_type + { + return compute_size(shape()); + } + + /** + * Returns the number of dimensions of the xindex_view. + */ + template + inline auto xindex_view::dimension() const noexcept -> size_type + { + return 1; + } + + /** + * Returns the shape of the xindex_view. + */ + template + inline auto xindex_view::shape() const noexcept -> const inner_shape_type& + { + return m_shape; + } + + template + inline layout_type xindex_view::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 + template + inline void xindex_view::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 + inline auto xindex_view::operator()(size_type idx) -> reference + { + return m_e[m_indices[idx]]; + } + + template + template + inline auto xindex_view::operator()(size_type, size_type idx1, Args... args) -> reference + { + return this->operator()(idx1, static_cast(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 + inline auto xindex_view::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 + inline auto xindex_view::operator()(size_type idx) const -> const_reference + { + return m_e[m_indices[idx]]; + } + + template + template + inline auto xindex_view::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 + inline auto xindex_view::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 + template + inline auto xindex_view::operator[](const S& index) + -> disable_integral_t + { + return m_e[m_indices[index[0]]]; + } + + template + template + inline auto xindex_view::operator[](std::initializer_list index) + -> reference + { + return m_e[m_indices[*(index.begin())]]; + } + + template + inline auto xindex_view::operator[](size_type i) -> reference + { + return operator()(i); + } + + /** + * Returns a constant reference to the element at the specified position in the container. + * @param index a sequence of indices specifying the position in the container. Indices + * must be unsigned integers, the number of indices in the list should be equal or greater + * than the number of dimensions of the container. + */ + template + template + inline auto xindex_view::operator[](const S& index) const + -> disable_integral_t + { + return m_e[m_indices[index[0]]]; + } + + template + template + inline auto xindex_view::operator[](std::initializer_list index) const + -> const_reference + { + return m_e[m_indices[*(index.begin())]]; + } + + template + inline auto xindex_view::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 + template + inline auto xindex_view::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 + template + inline auto xindex_view::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 + template + inline bool xindex_view::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 + template + inline bool xindex_view::is_trivial_broadcast(const O& /*strides*/) const noexcept + { + return false; + } + //@} + + /*************** + * stepper api * + ***************/ + + template + template + inline auto xindex_view::stepper_begin(const ST& shape) -> stepper + { + size_type offset = shape.size() - dimension(); + return stepper(this, offset); + } + + template + template + inline auto xindex_view::stepper_end(const ST& shape, layout_type) -> stepper + { + size_type offset = shape.size() - dimension(); + return stepper(this, offset, true); + } + + template + template + inline auto xindex_view::stepper_begin(const ST& shape) const -> const_stepper + { + size_type offset = shape.size() - dimension(); + return const_stepper(this, offset); + } + + template + template + inline auto xindex_view::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 + template + inline xfiltration::xfiltration(ECTA&& e, CCTA&& condition) + : m_e(std::forward(e)), m_condition(std::forward(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 + template + inline auto xfiltration::operator=(const E& e) -> disable_xexpression + { + 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 + template + inline auto xfiltration::operator+=(const E& e) -> disable_xexpression + { + 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 + template + inline auto xfiltration::operator-=(const E& e) -> disable_xexpression + { + 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 + template + inline auto xfiltration::operator*=(const E& e) -> disable_xexpression + { + 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 + template + inline auto xfiltration::operator/=(const E& e) -> disable_xexpression + { + 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 + template + inline auto xfiltration::operator%=(const E& e) -> disable_xexpression + { + return apply([this, &e](const_reference v, bool cond) { return cond ? v % e : v; }); + } + + template + template + inline auto xfiltration::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 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 + inline auto index_view(E&& e, I&& indices) noexcept + { + using view_type = xindex_view, std::decay_t>; + return view_type(std::forward(e), std::forward(indices)); + } +#ifdef X_OLD_CLANG + template + inline auto index_view(E&& e, std::initializer_list> indices) noexcept + { + std::vector idx; + for (auto it = indices.begin(); it != indices.end(); ++it) + { + idx.emplace_back(xindex(it->begin(), it->end())); + } + using view_type = xindex_view, std::vector>; + return view_type(std::forward(e), std::move(idx)); + } +#else + template + inline auto index_view(E&& e, const xindex (&indices)[L]) noexcept + { + using view_type = xindex_view, std::array>; + return view_type(std::forward(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 a = {{1,5,3}, {4,5,6}}; + * b = filter(a, a >= 5); + * std::cout << b << std::endl; // {5, 5, 6} + * \endcode + * + * \sa filtration + */ + template + inline auto filter(E&& e, O&& condition) noexcept + { + auto indices = where(std::forward(condition)); + using view_type = xindex_view, decltype(indices)>; + return view_type(std::forward(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 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 + inline auto filtration(E&& e, C&& condition) noexcept + { + using filtration_type = xfiltration, xclosure_t>; + return filtration_type(std::forward(e), std::forward(condition)); + } +} + +#endif diff --git a/vendor/xtensor/include/xtensor/xinfo.hpp b/vendor/xtensor/include/xtensor/xinfo.hpp new file mode 100644 index 0000000000..50da4f6cd4 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xinfo.hpp @@ -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 + +#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 + 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 + 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 + std::string type_to_string() + { + static_string static_name = type_name(); + return std::string(static_name.data, static_name.size); + } + + template + std::string info(const T& t) + { + std::string s; + s += "\nValue type: " + type_to_string(); + 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 diff --git a/vendor/xtensor/include/xtensor/xio.hpp b/vendor/xtensor/include/xtensor/xio.hpp new file mode 100644 index 0000000000..fa778996da --- /dev/null +++ b/vendor/xtensor/include/xtensor/xio.hpp @@ -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 +#include +#include +#include +#include +#include +#include + +#include "xexpression.hpp" +#include "xmath.hpp" +#include "xstrided_view.hpp" + +namespace xt +{ + + template + inline std::ostream& operator<<(std::ostream& out, const xexpression& 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 + 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(element_width) + size_type(2); + size_type line_lim = static_cast(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(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(i)); + xoutput(out, e, slices, printer, blanks + 1, element_width, edgeitems, line_width) << '}'; + slices.pop_back(); + } + return out; + } + + template + 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(view.shape()[0] - 1); ++i) + { + if (lim && size_type(view.shape()[0]) > (lim * 2) && i == lim) + { + i = static_cast(view.shape()[0]) - lim; + } + slices.push_back(static_cast(i)); + recurser_run(fn, e, slices, lim); + slices.pop_back(); + } + slices.push_back(static_cast(i)); + recurser_run(fn, e, slices, lim); + slices.pop_back(); + } + } + + template + struct printer; + + template + struct printer::value>> + { + using value_type = std::decay_t; + using cache_type = std::vector; + 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 + struct printer::value && !std::is_same::value>> + { + using value_type = std::decay_t; + using cache_type = std::vector; + 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 && 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 + struct printer::value>> + { + using value_type = bool; + using cache_type = std::vector; + 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 + struct printer::value>> + { + using value_type = std::decay_t; + using cache_type = std::vector; + 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 real_printer, imag_printer; + cache_type m_signs; + cache_iterator m_it; + }; + + template + struct printer::value && !xtl::is_complex::value>> + { + using value_type = std::decay_t; + using cache_type = std::vector; + 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 + struct custom_formatter + { + using value_type = std::decay_t; + + template + custom_formatter(F&& func) + : m_func(func) + { + } + + std::string operator()(const value_type& val) const + { + return m_func(val); + } + + private: + + std::function m_func; + }; + } + + template + std::ostream& pretty_print(const xexpression& e, F&& func, std::ostream& out = std::cout) + { + xfunction, std::string, const_xclosure_t> print_fun(detail::custom_formatter(std::forward(func)), e); + return pretty_print(print_fun, out); + } + + template + std::ostream& pretty_print(const xexpression& 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 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 + inline std::ostream& operator<<(std::ostream& out, const xexpression& e) + { + return pretty_print(e, out); + } +} + +#endif diff --git a/vendor/xtensor/include/xtensor/xiterable.hpp b/vendor/xtensor/include/xtensor/xiterable.hpp new file mode 100644 index 0000000000..9eb4a55f28 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xiterable.hpp @@ -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 + 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 xconst_iterable + { + public: + + using derived_type = D; + + using iterable_types = xiterable_inner_types; + 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 + using layout_iterator = xiterator; + template + using const_layout_iterator = xiterator; + template + using reverse_layout_iterator = std::reverse_iterator>; + template + using const_reverse_layout_iterator = std::reverse_iterator>; + + template + using broadcast_iterator = xiterator; + template + using const_broadcast_iterator = xiterator; + template + using reverse_broadcast_iterator = std::reverse_iterator>; + template + using const_reverse_broadcast_iterator = std::reverse_iterator>; + + using storage_iterator = layout_iterator
; + using const_storage_iterator = const_layout_iterator
; + using reverse_storage_iterator = reverse_layout_iterator
; + using const_reverse_storage_iterator = const_reverse_layout_iterator
; + + using iterator = layout_iterator
; + using const_iterator = const_layout_iterator
; + using reverse_iterator = reverse_layout_iterator
; + using const_reverse_iterator = const_reverse_layout_iterator
; + + template + const_layout_iterator begin() const noexcept; + template + const_layout_iterator end() const noexcept; + template + const_layout_iterator cbegin() const noexcept; + template + const_layout_iterator cend() const noexcept; + + template + const_reverse_layout_iterator rbegin() const noexcept; + template + const_reverse_layout_iterator rend() const noexcept; + template + const_reverse_layout_iterator crbegin() const noexcept; + template + const_reverse_layout_iterator crend() const noexcept; + + template + const_broadcast_iterator begin(const S& shape) const noexcept; + template + const_broadcast_iterator end(const S& shape) const noexcept; + template + const_broadcast_iterator cbegin(const S& shape) const noexcept; + template + const_broadcast_iterator cend(const S& shape) const noexcept; + + template + const_reverse_broadcast_iterator rbegin(const S& shape) const noexcept; + template + const_reverse_broadcast_iterator rend(const S& shape) const noexcept; + template + const_reverse_broadcast_iterator crbegin(const S& shape) const noexcept; + template + const_reverse_broadcast_iterator crend(const S& shape) const noexcept; + + template + const_layout_iterator storage_begin() const noexcept; + template + const_layout_iterator storage_end() const noexcept; + template + const_layout_iterator storage_cbegin() const noexcept; + template + const_layout_iterator storage_cend() const noexcept; + + template + const_reverse_layout_iterator storage_rbegin() const noexcept; + template + const_reverse_layout_iterator storage_rend() const noexcept; + template + const_reverse_layout_iterator storage_crbegin() const noexcept; + template + const_reverse_layout_iterator storage_crend() const noexcept; + + protected: + + const inner_shape_type& get_shape() const; + + private: + + template + const_layout_iterator get_cbegin(bool end_index) const noexcept; + template + const_layout_iterator get_cend(bool end_index) const noexcept; + + template + const_broadcast_iterator get_cbegin(const S& shape, bool end_index) const noexcept; + template + const_broadcast_iterator get_cend(const S& shape, bool end_index) const noexcept; + + template + const_stepper get_stepper_begin(const S& shape) const noexcept; + template + 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 xiterable : public xconst_iterable + { + public: + + using derived_type = D; + + using base_type = xconst_iterable; + 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 + using layout_iterator = typename base_type::template layout_iterator; + template + using const_layout_iterator = typename base_type::template const_layout_iterator; + template + using reverse_layout_iterator = typename base_type::template reverse_layout_iterator; + template + using const_reverse_layout_iterator = typename base_type::template const_reverse_layout_iterator; + + template + using broadcast_iterator = typename base_type::template broadcast_iterator; + template + using const_broadcast_iterator = typename base_type::template const_broadcast_iterator; + template + using reverse_broadcast_iterator = typename base_type::template reverse_broadcast_iterator; + template + using const_reverse_broadcast_iterator = typename base_type::template const_reverse_broadcast_iterator; + + 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_iterator begin() noexcept; + template + layout_iterator end() noexcept; + + template + reverse_layout_iterator rbegin() noexcept; + template + reverse_layout_iterator rend() noexcept; + + template + broadcast_iterator begin(const S& shape) noexcept; + template + broadcast_iterator end(const S& shape) noexcept; + + template + reverse_broadcast_iterator rbegin(const S& shape) noexcept; + template + reverse_broadcast_iterator rend(const S& shape) noexcept; + + template + layout_iterator storage_begin() noexcept; + template + layout_iterator storage_end() noexcept; + + template + reverse_layout_iterator storage_rbegin() noexcept; + template + reverse_layout_iterator storage_rend() noexcept; + + private: + + template + layout_iterator get_begin(bool end_index) noexcept; + template + layout_iterator get_end(bool end_index) noexcept; + + template + broadcast_iterator get_begin(const S& shape, bool end_index) noexcept; + template + broadcast_iterator get_end(const S& shape, bool end_index) noexcept; + + template + stepper get_stepper_begin(const S& shape) noexcept; + template + stepper get_stepper_end(const S& shape, layout_type l) noexcept; + + template + const_stepper get_stepper_begin(const S& shape) const noexcept; + template + 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 + template + inline auto xconst_iterable::begin() const noexcept -> const_layout_iterator + { + return this->template cbegin(); + } + + /** + * 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 + template + inline auto xconst_iterable::end() const noexcept -> const_layout_iterator + { + return this->template cend(); + } + + /** + * 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 + template + inline auto xconst_iterable::cbegin() const noexcept -> const_layout_iterator + { + return this->template get_cbegin(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 + template + inline auto xconst_iterable::cend() const noexcept -> const_layout_iterator + { + return this->template get_cend(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 + template + inline auto xconst_iterable::rbegin() const noexcept -> const_reverse_layout_iterator + { + return this->template crbegin(); + } + + /** + * 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 + template + inline auto xconst_iterable::rend() const noexcept -> const_reverse_layout_iterator + { + return this->template crend(); + } + + /** + * 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 + template + inline auto xconst_iterable::crbegin() const noexcept -> const_reverse_layout_iterator + { + return const_reverse_layout_iterator(get_cend(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 + template + inline auto xconst_iterable::crend() const noexcept -> const_reverse_layout_iterator + { + return const_reverse_layout_iterator(get_cbegin(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 + template + inline auto xconst_iterable::begin(const S& shape) const noexcept -> const_broadcast_iterator + { + return cbegin(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 + template + inline auto xconst_iterable::end(const S& shape) const noexcept -> const_broadcast_iterator + { + return cend(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 + template + inline auto xconst_iterable::cbegin(const S& shape) const noexcept -> const_broadcast_iterator + { + return get_cbegin(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 + template + inline auto xconst_iterable::cend(const S& shape) const noexcept -> const_broadcast_iterator + { + return get_cend(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 + template + inline auto xconst_iterable::rbegin(const S& shape) const noexcept -> const_reverse_broadcast_iterator + { + return crbegin(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 + template + inline auto xconst_iterable::rend(const S& shape) const noexcept -> const_reverse_broadcast_iterator + { + return crend(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 + template + inline auto xconst_iterable::crbegin(const S& shape) const noexcept -> const_reverse_broadcast_iterator + { + return const_reverse_broadcast_iterator(get_cend(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 + template + inline auto xconst_iterable::crend(const S& shape) const noexcept -> const_reverse_broadcast_iterator + { + return const_reverse_broadcast_iterator(get_cbegin(shape, false)); + } + //@} + + template + template + inline auto xconst_iterable::storage_begin() const noexcept -> const_layout_iterator + { + return this->template cbegin(); + } + + template + template + inline auto xconst_iterable::storage_end() const noexcept -> const_layout_iterator + { + return this->template cend(); + } + + template + template + inline auto xconst_iterable::storage_cbegin() const noexcept -> const_layout_iterator + { + return this->template cbegin(); + } + + template + template + inline auto xconst_iterable::storage_cend() const noexcept -> const_layout_iterator + { + return this->template cend(); + } + + template + template + inline auto xconst_iterable::storage_rbegin() const noexcept -> const_reverse_layout_iterator + { + return this->template crbegin(); + } + + template + template + inline auto xconst_iterable::storage_rend() const noexcept -> const_reverse_layout_iterator + { + return this->template crend(); + } + + template + template + inline auto xconst_iterable::storage_crbegin() const noexcept -> const_reverse_layout_iterator + { + return this->template crbegin(); + } + + template + template + inline auto xconst_iterable::storage_crend() const noexcept -> const_reverse_layout_iterator + { + return this->template crend(); + } + + template + template + inline auto xconst_iterable::get_cbegin(bool end_index) const noexcept -> const_layout_iterator + { + return const_layout_iterator(get_stepper_begin(get_shape()), &get_shape(), end_index); + } + + template + template + inline auto xconst_iterable::get_cend(bool end_index) const noexcept -> const_layout_iterator + { + return const_layout_iterator(get_stepper_end(get_shape(), L), &get_shape(), end_index); + } + + template + template + inline auto xconst_iterable::get_cbegin(const S& shape, bool end_index) const noexcept -> const_broadcast_iterator + { + return const_broadcast_iterator(get_stepper_begin(shape), shape, end_index); + } + + template + template + inline auto xconst_iterable::get_cend(const S& shape, bool end_index) const noexcept -> const_broadcast_iterator + { + return const_broadcast_iterator(get_stepper_end(shape, L), shape, end_index); + } + + template + template + inline auto xconst_iterable::get_stepper_begin(const S& shape) const noexcept -> const_stepper + { + return derived_cast().stepper_begin(shape); + } + + template + template + inline auto xconst_iterable::get_stepper_end(const S& shape, layout_type l) const noexcept -> const_stepper + { + return derived_cast().stepper_end(shape, l); + } + + template + inline auto xconst_iterable::get_shape() const -> const inner_shape_type& + { + return derived_cast().shape(); + } + + template + inline auto xconst_iterable::derived_cast() const -> const derived_type& + { + return *static_cast(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 + template + inline auto xiterable::begin() noexcept -> layout_iterator + { + return get_begin(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 + template + inline auto xiterable::end() noexcept -> layout_iterator + { + return get_end(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 + template + inline auto xiterable::rbegin() noexcept -> reverse_layout_iterator + { + return reverse_layout_iterator(get_end(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 + template + inline auto xiterable::rend() noexcept -> reverse_layout_iterator + { + return reverse_layout_iterator(get_begin(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 + template + inline auto xiterable::begin(const S& shape) noexcept -> broadcast_iterator + { + return get_begin(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 + template + inline auto xiterable::end(const S& shape) noexcept -> broadcast_iterator + { + return get_end(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 + template + inline auto xiterable::rbegin(const S& shape) noexcept -> reverse_broadcast_iterator + { + return reverse_broadcast_iterator(get_end(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 + template + inline auto xiterable::rend(const S& shape) noexcept -> reverse_broadcast_iterator + { + return reverse_broadcast_iterator(get_begin(shape, false)); + } + //@} + + template + template + inline auto xiterable::storage_begin() noexcept -> layout_iterator + { + return this->template begin(); + } + + template + template + inline auto xiterable::storage_end() noexcept -> layout_iterator + { + return this->template end(); + } + + template + template + inline auto xiterable::storage_rbegin() noexcept -> reverse_layout_iterator + { + return this->template rbegin(); + } + + template + template + inline auto xiterable::storage_rend() noexcept -> reverse_layout_iterator + { + return this->template rend(); + } + + template + template + inline auto xiterable::get_begin(bool end_index) noexcept -> layout_iterator + { + return layout_iterator(get_stepper_begin(this->get_shape()), &(this->get_shape()), end_index); + } + + template + template + inline auto xiterable::get_end(bool end_index) noexcept -> layout_iterator + { + return layout_iterator(get_stepper_end(this->get_shape(), L), &(this->get_shape()), end_index); + } + + template + template + inline auto xiterable::get_begin(const S& shape, bool end_index) noexcept -> broadcast_iterator + { + return broadcast_iterator(get_stepper_begin(shape), shape, end_index); + } + + template + template + inline auto xiterable::get_end(const S& shape, bool end_index) noexcept -> broadcast_iterator + { + return broadcast_iterator(get_stepper_end(shape, L), shape, end_index); + } + + template + template + inline auto xiterable::get_stepper_begin(const S& shape) noexcept -> stepper + { + return derived_cast().stepper_begin(shape); + } + + template + template + inline auto xiterable::get_stepper_end(const S& shape, layout_type l) noexcept -> stepper + { + return derived_cast().stepper_end(shape, l); + } + + template + template + inline auto xiterable::get_stepper_begin(const S& shape) const noexcept -> const_stepper + { + return derived_cast().stepper_begin(shape); + } + + template + template + inline auto xiterable::get_stepper_end(const S& shape, layout_type l) const noexcept -> const_stepper + { + return derived_cast().stepper_end(shape, l); + } + + template + inline auto xiterable::derived_cast() -> derived_type& + { + return *static_cast(this); + } +} + +#endif diff --git a/vendor/xtensor/include/xtensor/xiterator.hpp b/vendor/xtensor/include/xtensor/xiterator.hpp new file mode 100644 index 0000000000..01b7950515 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xiterator.hpp @@ -0,0 +1,1123 @@ +/*************************************************************************** +* 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_ITERATOR_HPP +#define XTENSOR_ITERATOR_HPP + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "xexception.hpp" +#include "xlayout.hpp" +#include "xshape.hpp" +#include "xutils.hpp" + +namespace xt +{ + + /*********************** + * iterator meta utils * + ***********************/ + + template + class xscalar; + + namespace detail + { + template + struct get_stepper_iterator_impl + { + using type = typename C::container_iterator; + }; + + template + struct get_stepper_iterator_impl + { + using type = typename C::const_container_iterator; + }; + + template + struct get_stepper_iterator_impl> + { + using type = typename xscalar::dummy_iterator; + }; + + template + struct get_stepper_iterator_impl> + { + using type = typename xscalar::const_dummy_iterator; + }; + } + + template + using get_stepper_iterator = typename detail::get_stepper_iterator_impl::type; + + namespace detail + { + template + struct index_type_impl + { + using type = dynamic_shape; + }; + + template + struct index_type_impl> + { + using type = std::array; + }; + } + + template + using xindex_type_t = typename detail::index_type_impl::type; + + /************ + * xstepper * + ************/ + + template + class xstepper + { + public: + + using storage_type = C; + using subiterator_type = get_stepper_iterator; + using subiterator_traits = std::iterator_traits; + using value_type = typename subiterator_traits::value_type; + using reference = typename subiterator_traits::reference; + using pointer = typename subiterator_traits::pointer; + using difference_type = typename subiterator_traits::difference_type; + using size_type = typename storage_type::size_type; + using shape_type = typename storage_type::shape_type; + using simd_type = xsimd::simd_type; + + xstepper() = default; + xstepper(storage_type* c, subiterator_type it, size_type offset) noexcept; + + reference operator*() const; + + void step(size_type dim, size_type n = 1); + void step_back(size_type dim, size_type n = 1); + void reset(size_type dim); + void reset_back(size_type dim); + + void to_begin(); + void to_end(layout_type l); + + template + R step_simd(); + + value_type step_leading(); + + template + void store_simd(const R& vec); + + private: + + storage_type* p_c; + subiterator_type m_it; + size_type m_offset; + }; + + template + struct stepper_tools + { + // For performance reasons, increment_stepper and decrement_stepper are + // specialized for the case where n=1, which underlies operator++ and + // operator-- on xiterators. + + template + static void increment_stepper(S& stepper, + IT& index, + const ST& shape); + + template + static void decrement_stepper(S& stepper, + IT& index, + const ST& shape); + + template + static void increment_stepper(S& stepper, + IT& index, + const ST& shape, + typename S::size_type n); + + template + static void decrement_stepper(S& stepper, + IT& index, + const ST& shape, + typename S::size_type n); + }; + + /******************** + * xindexed_stepper * + ********************/ + + template + class xindexed_stepper + { + public: + + using self_type = xindexed_stepper; + using xexpression_type = std::conditional_t; + + using value_type = typename xexpression_type::value_type; + using reference = std::conditional_t; + using pointer = std::conditional_t; + using size_type = typename xexpression_type::size_type; + using difference_type = typename xexpression_type::difference_type; + + using shape_type = typename xexpression_type::shape_type; + using index_type = xindex_type_t; + + xindexed_stepper() = default; + xindexed_stepper(xexpression_type* e, size_type offset, bool end = false) noexcept; + + reference operator*() const; + + void step(size_type dim, size_type n = 1); + void step_back(size_type dim, size_type n = 1); + void reset(size_type dim); + void reset_back(size_type dim); + + void to_begin(); + void to_end(layout_type l); + + private: + + xexpression_type* p_e; + index_type m_index; + size_type m_offset; + }; + + template + struct is_indexed_stepper + { + static const bool value = false; + }; + + template + struct is_indexed_stepper> + { + static const bool value = true; + }; + + /************* + * xiterator * + *************/ + + namespace detail + { + template + class shape_storage + { + public: + + using shape_type = S; + using param_type = const S&; + + shape_storage() = default; + shape_storage(param_type shape); + const S& shape() const; + + private: + + S m_shape; + }; + + template + class shape_storage + { + public: + + using shape_type = S; + using param_type = const S*; + + shape_storage(param_type shape = 0); + const S& shape() const; + + private: + + const S* p_shape; + }; + + template + struct LAYOUT_FORBIDEN_FOR_XITERATOR; + } + + template + class xiterator : public xtl::xrandom_access_iterator_base, + typename It::value_type, + typename It::difference_type, + typename It::pointer, + typename It::reference>, + private detail::shape_storage + { + public: + + using self_type = xiterator; + + using subiterator_type = It; + using value_type = typename subiterator_type::value_type; + using reference = typename subiterator_type::reference; + using pointer = typename subiterator_type::pointer; + using difference_type = typename subiterator_type::difference_type; + using size_type = typename subiterator_type::size_type; + using iterator_category = std::random_access_iterator_tag; + + using private_base = detail::shape_storage; + using shape_type = typename private_base::shape_type; + using shape_param_type = typename private_base::param_type; + using index_type = xindex_type_t; + + xiterator() = default; + // end_index means either reverse_iterator && !end or !reverse_iterator && end + xiterator(It it, shape_param_type shape, bool end_index); + + self_type& operator++(); + self_type& operator--(); + + self_type& operator+=(difference_type n); + self_type& operator-=(difference_type n); + + difference_type operator-(const self_type& rhs) const; + + reference operator*() const; + pointer operator->() const; + + bool equal(const xiterator& rhs) const; + bool less_than(const xiterator& rhs) const; + + private: + + subiterator_type m_it; + index_type m_index; + difference_type m_linear_index; + + using checking_type = typename detail::LAYOUT_FORBIDEN_FOR_XITERATOR::type; + }; + + template + bool operator==(const xiterator& lhs, + const xiterator& rhs); + + template + bool operator<(const xiterator& lhs, + const xiterator& rhs); + + /********************* + * xbounded_iterator * + *********************/ + + template + class xbounded_iterator : public xtl::xrandom_access_iterator_base, + typename std::iterator_traits::value_type, + typename std::iterator_traits::difference_type, + typename std::iterator_traits::pointer, + typename std::iterator_traits::reference> + { + public: + + using self_type = xbounded_iterator; + + using subiterator_type = It; + using bound_iterator_type = BIt; + using value_type = typename std::iterator_traits::value_type; + using reference = typename std::iterator_traits::reference; + using pointer = typename std::iterator_traits::pointer; + using difference_type = typename std::iterator_traits::difference_type; + using iterator_category = std::random_access_iterator_tag; + + xbounded_iterator() = default; + xbounded_iterator(It it, BIt bound_it); + + self_type& operator++(); + self_type& operator--(); + + self_type& operator+=(difference_type n); + self_type& operator-=(difference_type n); + + difference_type operator-(const self_type& rhs) const; + + value_type operator*() const; + + bool equal(const self_type& rhs) const; + bool less_than(const self_type& rhs) const; + + private: + + subiterator_type m_it; + bound_iterator_type m_bound_it; + }; + + template + bool operator==(const xbounded_iterator& lhs, + const xbounded_iterator& rhs); + + template + bool operator<(const xbounded_iterator& lhs, + const xbounded_iterator& rhs); + + /******************************* + * trivial_begin / trivial_end * + *******************************/ + + namespace detail + { + template + constexpr auto trivial_begin(C& c) noexcept + { + return c.storage_begin(); + } + + template + constexpr auto trivial_end(C& c) noexcept + { + return c.storage_end(); + } + + template + constexpr auto trivial_begin(const C& c) noexcept + { + return c.storage_begin(); + } + + template + constexpr auto trivial_end(const C& c) noexcept + { + return c.storage_end(); + } + } + + /*************************** + * xstepper implementation * + ***************************/ + + template + inline xstepper::xstepper(storage_type* c, subiterator_type it, size_type offset) noexcept + : p_c(c), m_it(it), m_offset(offset) + { + } + + template + inline auto xstepper::operator*() const -> reference + { + return *m_it; + } + + template + inline void xstepper::step(size_type dim, size_type n) + { + if (dim >= m_offset) + { + using strides_value_type = decltype(p_c->strides()[0]); + m_it += difference_type(static_cast(n) * p_c->strides()[dim - m_offset]); + } + } + + template + inline void xstepper::step_back(size_type dim, size_type n) + { + if (dim >= m_offset) + { + using strides_value_type = decltype(p_c->strides()[0]); + m_it -= difference_type(static_cast(n) * p_c->strides()[dim - m_offset]); + } + } + + template + inline void xstepper::reset(size_type dim) + { + if (dim >= m_offset) + { + m_it -= difference_type(p_c->backstrides()[dim - m_offset]); + } + } + + template + inline void xstepper::reset_back(size_type dim) + { + if (dim >= m_offset) + { + m_it += difference_type(p_c->backstrides()[dim - m_offset]); + } + } + + template + inline void xstepper::to_begin() + { + m_it = p_c->data_xbegin(); + } + + template + inline void xstepper::to_end(layout_type l) + { + m_it = p_c->data_xend(l); + } + + template + template + inline R xstepper::step_simd() + { + R reg; + reg.load_unaligned(&(*m_it)); + m_it += xsimd::revert_simd_traits::size; + return reg; + } + + template + template + inline void xstepper::store_simd(const R& vec) + { + vec.store_unaligned(&(*m_it)); + m_it += xsimd::revert_simd_traits::size;; + } + + template + auto xstepper::step_leading() -> value_type + { + ++m_it; + return *m_it; + } + + template <> + template + void stepper_tools::increment_stepper(S& stepper, + IT& index, + const ST& shape) + { + using size_type = typename S::size_type; + size_type i = index.size(); + while (i != 0) + { + --i; + if (index[i] != shape[i] - 1) + { + ++index[i]; + stepper.step(i); + return; + } + else + { + index[i] = 0; + if (i != 0) + { + stepper.reset(i); + } + } + } + if (i == 0) + { + std::copy(shape.cbegin(), shape.cend(), index.begin()); + stepper.to_end(layout_type::row_major); + } + } + + template <> + template + void stepper_tools::increment_stepper(S& stepper, + IT& index, + const ST& shape, + typename S::size_type n) + { + using size_type = typename S::size_type; + size_type i = index.size(); + size_type leading_i = index.size() - 1; + while (i != 0 && n != 0) + { + --i; + size_type inc = (i == leading_i) ? n : 1; + if (index[i] + inc < shape[i]) + { + index[i] += inc; + stepper.step(i, inc); + n -= inc; + if (i != leading_i || index.size() == 1) + { + i = index.size(); + } + } + else + { + if (i == leading_i) + { + size_type off = shape[i] - index[i] - 1; + stepper.step(i, off); + n -= off; + } + index[i] = 0; + if (i != 0) + { + stepper.reset(i); + } + } + } + if (i == 0) + { + std::copy(shape.cbegin(), shape.cend(), index.begin()); + stepper.to_end(layout_type::row_major); + } + } + + template <> + template + void stepper_tools::decrement_stepper(S& stepper, + IT& index, + const ST& shape) + { + using size_type = typename S::size_type; + size_type i = index.size(); + while (i != 0) + { + --i; + if (index[i] != 0) + { + --index[i]; + stepper.step_back(i); + return; + } + else + { + index[i] = shape[i] - 1; + if (i != 0) + { + stepper.reset_back(i); + } + } + } + if (i == 0) + { + stepper.to_begin(); + } + } + + template <> + template + void stepper_tools::decrement_stepper(S& stepper, + IT& index, + const ST& shape, + typename S::size_type n) + { + using size_type = typename S::size_type; + size_type i = index.size(); + size_type leading_i = index.size() - 1; + while (i != 0 && n != 0) + { + --i; + size_type inc = (i == leading_i) ? n : 1; + if (index[i] >= inc) + { + index[i] -= inc; + stepper.step_back(i, inc); + n -= inc; + if (i != leading_i || index.size() == 1) + { + i = index.size(); + } + } + else + { + if (i == leading_i) + { + size_type off = index[i]; + stepper.step_back(i, off); + n -= off; + } + index[i] = shape[i] - 1; + if (i != 0) + { + stepper.reset_back(i); + } + } + } + if (i == 0) + { + stepper.to_begin(); + } + } + + template <> + template + void stepper_tools::increment_stepper(S& stepper, + IT& index, + const ST& shape) + { + using size_type = typename S::size_type; + size_type size = index.size(); + size_type i = 0; + while (i != size) + { + if (index[i] != shape[i] - 1) + { + ++index[i]; + stepper.step(i); + return; + } + else + { + index[i] = 0; + if (i != size - 1) + { + stepper.reset(i); + } + } + ++i; + } + if (i == size) + { + std::copy(shape.cbegin(), shape.cend(), index.begin()); + stepper.to_end(layout_type::column_major); + } + } + + template <> + template + void stepper_tools::increment_stepper(S& stepper, + IT& index, + const ST& shape, + typename S::size_type n) + { + using size_type = typename S::size_type; + size_type size = index.size(); + size_type i = 0; + size_type leading_i = 0; + while (i != size && n != 0) + { + size_type inc = (i == leading_i) ? n : 1; + if (index[i] + inc < shape[i]) + { + index[i] += inc; + stepper.step(i, inc); + n -= inc; + if (i != leading_i || index.size() == 1) + { + i = 0; + continue; + } + } + else + { + if (i == leading_i) + { + size_type off = shape[i] - index[i] - 1; + stepper.step(i, off); + n -= off; + } + index[i] = 0; + if (i != size - 1) + { + stepper.reset(i); + } + } + ++i; + } + if (i == size) + { + std::copy(shape.cbegin(), shape.cend(), index.begin()); + stepper.to_end(layout_type::column_major); + } + } + + template <> + template + void stepper_tools::decrement_stepper(S& stepper, + IT& index, + const ST& shape) + { + using size_type = typename S::size_type; + size_type size = index.size(); + size_type i = 0; + while (i != size) + { + if (index[i] != 0) + { + --index[i]; + stepper.step_back(i); + return; + } + else + { + index[i] = shape[i] - 1; + if (i != size - 1) + { + stepper.reset_back(i); + } + } + ++i; + } + if (i == size) + { + stepper.to_begin(); + } + } + + template <> + template + void stepper_tools::decrement_stepper(S& stepper, + IT& index, + const ST& shape, + typename S::size_type n) + { + using size_type = typename S::size_type; + size_type size = index.size(); + size_type i = 0; + size_type leading_i = 0; + while (i != size && n != 0) + { + size_type inc = (i == leading_i) ? n : 1; + if (index[i] >= inc) + { + index[i] -= inc; + stepper.step_back(i, inc); + n -= inc; + if (i != leading_i || index.size() == 1) + { + i = 0; + continue; + } + } + else + { + if (i == leading_i) + { + size_type off = index[i]; + stepper.step_back(i, off); + n -= off; + } + index[i] = shape[i] - 1; + if (i != size - 1) + { + stepper.reset_back(i); + } + } + ++i; + } + if (i == size) + { + stepper.to_begin(); + } + } + + /*********************************** + * xindexed_stepper implementation * + ***********************************/ + + template + inline xindexed_stepper::xindexed_stepper(xexpression_type* e, size_type offset, bool end) noexcept + : p_e(e), m_index(xtl::make_sequence(e->shape().size(), size_type(0))), m_offset(offset) + { + if (end) + { + // Note: the layout here doesn't matter (unused) but using default layout looks more "correct" + to_end(XTENSOR_DEFAULT_LAYOUT); + } + } + + template + inline auto xindexed_stepper::operator*() const -> reference + { + return p_e->element(m_index.cbegin(), m_index.cend()); + } + + template + inline void xindexed_stepper::step(size_type dim, size_type n) + { + if (dim >= m_offset) + { + m_index[dim - m_offset] += static_cast(n); + } + } + + template + inline void xindexed_stepper::step_back(size_type dim, size_type n) + { + if (dim >= m_offset) + { + m_index[dim - m_offset] -= static_cast(n); + } + } + + template + inline void xindexed_stepper::reset(size_type dim) + { + if (dim >= m_offset) + { + m_index[dim - m_offset] = 0; + } + } + + template + inline void xindexed_stepper::reset_back(size_type dim) + { + if (dim >= m_offset) + { + m_index[dim - m_offset] = p_e->shape()[dim - m_offset] - 1; + } + } + + template + inline void xindexed_stepper::to_begin() + { + std::fill(m_index.begin(), m_index.end(), size_type(0)); + } + + template + inline void xindexed_stepper::to_end(layout_type) + { + std::copy(p_e->shape().begin(), p_e->shape().end(), m_index.begin()); + } + + /**************************** + * xiterator implementation * + ****************************/ + + namespace detail + { + template + inline shape_storage::shape_storage(param_type shape) + : m_shape(shape) + { + } + + template + inline const S& shape_storage::shape() const + { + return m_shape; + } + + template + inline shape_storage::shape_storage(param_type shape) + : p_shape(shape) + { + } + + template + inline const S& shape_storage::shape() const + { + return *p_shape; + } + + template <> + struct LAYOUT_FORBIDEN_FOR_XITERATOR + { + using type = int; + }; + + template <> + struct LAYOUT_FORBIDEN_FOR_XITERATOR + { + using type = int; + }; + } + + template + inline xiterator::xiterator(It it, shape_param_type shape, bool end_index) + : private_base(shape), m_it(it), + m_index(end_index ? xtl::forward_sequence(this->shape()) + : xtl::make_sequence(this->shape().size(), size_type(0))), + m_linear_index(0) + { + // end_index means either reverse_iterator && !end or !reverse_iterator && end + if (end_index) + { + if (m_index.size() != size_type(0)) + { + auto iter_begin = (L == layout_type::row_major) ? m_index.begin() : m_index.begin() + 1; + auto iter_end = (L == layout_type::row_major) ? m_index.end() - 1 : m_index.end(); + std::transform(iter_begin, iter_end, iter_begin, [](const auto& v) { return v - 1; }); + } + m_linear_index = difference_type(std::accumulate(this->shape().cbegin(), this->shape().cend(), + size_type(1), std::multiplies())); + } + } + + template + inline auto xiterator::operator++() -> self_type& + { + stepper_tools::increment_stepper(m_it, m_index, this->shape()); + ++m_linear_index; + return *this; + } + + template + inline auto xiterator::operator--() -> self_type& + { + stepper_tools::decrement_stepper(m_it, m_index, this->shape()); + --m_linear_index; + return *this; + } + + template + inline auto xiterator::operator+=(difference_type n) -> self_type& + { + if (n >= 0) + { + stepper_tools::increment_stepper(m_it, m_index, this->shape(), static_cast(n)); + } + else + { + stepper_tools::decrement_stepper(m_it, m_index, this->shape(), static_cast(-n)); + } + m_linear_index += n; + return *this; + } + + template + inline auto xiterator::operator-=(difference_type n) -> self_type& + { + if (n >= 0) + { + stepper_tools::decrement_stepper(m_it, m_index, this->shape(), static_cast(n)); + } + else + { + stepper_tools::increment_stepper(m_it, m_index, this->shape(), static_cast(-n)); + } + m_linear_index -= n; + return *this; + } + + template + inline auto xiterator::operator-(const self_type& rhs) const -> difference_type + { + return m_linear_index - rhs.m_linear_index; + } + + template + inline auto xiterator::operator*() const -> reference + { + return *m_it; + } + + template + inline auto xiterator::operator->() const -> pointer + { + return &(*m_it); + } + + template + inline bool xiterator::equal(const xiterator& rhs) const + { + XTENSOR_ASSERT(this->shape() == rhs.shape()); + return m_linear_index == rhs.m_linear_index; + } + + template + inline bool xiterator::less_than(const xiterator& rhs) const + { + XTENSOR_ASSERT(this->shape() == rhs.shape()); + return m_linear_index < rhs.m_linear_index; + } + + template + inline bool operator==(const xiterator& lhs, + const xiterator& rhs) + { + return lhs.equal(rhs); + } + + template + bool operator<(const xiterator& lhs, + const xiterator& rhs) + { + return lhs.less_than(rhs); + } + + /************************************ + * xbounded_iterator implementation * + ************************************/ + + template + xbounded_iterator::xbounded_iterator(It it, BIt bound_it) + : m_it(it), m_bound_it(bound_it) + { + } + + template + inline auto xbounded_iterator::operator++() -> self_type& + { + ++m_it; + ++m_bound_it; + return *this; + } + + template + inline auto xbounded_iterator::operator--() -> self_type& + { + --m_it; + --m_bound_it; + return *this; + } + + template + inline auto xbounded_iterator::operator+=(difference_type n) -> self_type& + { + m_it += n; + m_bound_it += n; + return *this; + } + + template + inline auto xbounded_iterator::operator-=(difference_type n) -> self_type& + { + m_it -= n; + m_bound_it -= n; + return *this; + } + + template + inline auto xbounded_iterator::operator-(const self_type& rhs) const -> difference_type + { + return m_it - rhs.m_it; + } + + template + inline auto xbounded_iterator::operator*() const -> value_type + { + using type = decltype(*m_bound_it); + return (static_cast(*m_it) < *m_bound_it) ? *m_it : static_cast((*m_bound_it) - 1); + } + + template + inline bool xbounded_iterator::equal(const self_type& rhs) const + { + return m_it == rhs.m_it && m_bound_it == rhs.m_bound_it; + } + + template + inline bool xbounded_iterator::less_than(const self_type& rhs) const + { + return m_it < rhs.m_it; + } + + template + inline bool operator==(const xbounded_iterator& lhs, + const xbounded_iterator& rhs) + { + return lhs.equal(rhs); + } + + template + inline bool operator<(const xbounded_iterator& lhs, + const xbounded_iterator& rhs) + { + return lhs.less_than(rhs); + } +} + +#endif diff --git a/vendor/xtensor/include/xtensor/xjson.hpp b/vendor/xtensor/include/xtensor/xjson.hpp new file mode 100644 index 0000000000..b0d33ed8a8 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xjson.hpp @@ -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 +#include +#include + +#include + +#include "xstrided_view.hpp" + +namespace xt +{ + /************************************* + * to_json and from_json declaration * + *************************************/ + + template + enable_xexpression to_json(nlohmann::json&, const E&); + + template + enable_xcontainer_semantics from_json(const nlohmann::json&, E&); + + /// @cond DOXYGEN_INCLUDE_SFINAE + template + enable_xview_semantics from_json(const nlohmann::json&, E&); + /// @endcond + + /**************************************** + * to_json and from_json implementation * + ****************************************/ + + namespace detail + { + template + void to_json_impl(nlohmann::json& j, const xexpression& 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 + inline void from_json_impl(const nlohmann::json& j, xexpression& 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 + 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 + inline enable_xexpression 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 + inline enable_xcontainer_semantics from_json(const nlohmann::json& j, E& e) + { + auto dimension = detail::json_dimension(j); + auto s = xtl::make_sequence(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 + inline enable_xview_semantics 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 diff --git a/vendor/xtensor/include/xtensor/xlayout.hpp b/vendor/xtensor/include/xtensor/xlayout.hpp new file mode 100644 index 0000000000..5ec8a340c5 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xlayout.hpp @@ -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 + 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; + return layout_type(static_cast(lhs) & static_cast(rhs)); + } + + template + constexpr layout_type compute_layout_impl(layout_type lhs, Args... args) noexcept + { + return compute_layout_impl(lhs, compute_layout_impl(args...)); + } + } + + template + 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 diff --git a/vendor/xtensor/include/xtensor/xmath.hpp b/vendor/xtensor/include/xtensor/xmath.hpp new file mode 100644 index 0000000000..41332b180b --- /dev/null +++ b/vendor/xtensor/include/xtensor/xmath.hpp @@ -0,0 +1,2146 @@ +/*************************************************************************** +* 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_MATH_HPP +#define XTENSOR_MATH_HPP + +#include +#include +#include +#include + +#include + +#include "xaccumulator.hpp" +#include "xoperation.hpp" +#include "xreducer.hpp" +#include "xslice.hpp" +#include "xstrided_view.hpp" +#include "xeval.hpp" + +namespace xt +{ + template + struct numeric_constants + { + static constexpr T PI = 3.141592653589793238463; + static constexpr T PI_2 = 1.57079632679489661923; + static constexpr T PI_4 = 0.785398163397448309616; + static constexpr T D_1_PI = 0.318309886183790671538; + static constexpr T D_2_PI = 0.636619772367581343076; + static constexpr T D_2_SQRTPI = 1.12837916709551257390; + static constexpr T SQRT2 = 1.41421356237309504880; + static constexpr T SQRT1_2 = 0.707106781186547524401; + static constexpr T E = 2.71828182845904523536; + static constexpr T LOG2E = 1.44269504088896340736; + static constexpr T LOG10E = 0.434294481903251827651; + static constexpr T LN2 = 0.693147180559945309417; + }; + + /*********** + * Helpers * + ***********/ + +#define XTENSOR_UNSIGNED_ABS_FUNC(T) \ +constexpr inline T abs(const T& x) \ +{ \ + return x; \ +} \ + +#define XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, T) \ +constexpr inline bool FUNC_NAME(const T& /*x*/) noexcept \ +{ \ + return RETURN_VAL; \ +} \ + +#define XTENSOR_INT_SPECIALIZATION(FUNC_NAME, RETURN_VAL) \ +XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, char); \ +XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, short); \ +XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, int); \ +XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, long); \ +XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, long long); \ +XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, unsigned char); \ +XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, unsigned short); \ +XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, unsigned int); \ +XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, unsigned long); \ +XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, unsigned long long); \ + + +#define XTENSOR_UNARY_MATH_FUNCTOR_IMPL(NAME, R) \ + template \ + struct NAME##_fun \ + { \ + static auto exec(const T& arg) \ + { \ + using math::NAME; \ + return NAME(arg); \ + } \ + template \ + using frt = xt::detail::functor_return_type; \ + using return_type = frt; \ + using argument_type = T; \ + using result_type = decltype(exec(std::declval())); \ + using simd_value_type = xsimd::simd_type; \ + using simd_result_type = typename return_type::simd_type; \ + constexpr result_type operator()(const T& arg) const \ + { \ + using math::NAME; \ + return NAME(arg); \ + } \ + template \ + constexpr typename frt, R>::simd_type \ + simd_apply(const B& arg) const \ + { \ + using math::NAME; \ + return NAME(arg); \ + } \ + template \ + struct rebind \ + { \ + using type = NAME##_fun; \ + }; \ + } + +#define XTENSOR_UNARY_MATH_FUNCTOR(NAME) XTENSOR_UNARY_MATH_FUNCTOR_IMPL(NAME, T) +#define XTENSOR_UNARY_BOOL_FUNCTOR(NAME) XTENSOR_UNARY_MATH_FUNCTOR_IMPL(NAME, bool) + +#define XTENSOR_UNARY_MATH_FUNCTOR_COMPLEX_REDUCING(NAME) \ + template \ + struct NAME##_fun \ + { \ + static auto exec(const T& arg) \ + { \ + using math::NAME; \ + return NAME(arg); \ + } \ + using argument_type = T; \ + using result_type = decltype(exec(std::declval())); \ + using simd_value_type = argument_type; \ + using simd_result_type = result_type; \ + constexpr result_type operator()(const T& arg) const \ + { \ + using math::NAME; \ + return NAME(arg); \ + } \ + template \ + constexpr simd_result_type simd_apply(const B& arg) const \ + { \ + using math::NAME; \ + return NAME(arg); \ + } \ + template \ + struct rebind \ + { \ + using type = NAME##_fun; \ + }; \ + } + +#define XTENSOR_BINARY_MATH_FUNCTOR_IMPL(NAME, R) \ + template \ + struct NAME##_fun \ + { \ + static auto exec(const T& arg1, const T& arg2) \ + { \ + using math::NAME; \ + return NAME(arg1, arg2); \ + } \ + template \ + using frt = xt::detail::functor_return_type; \ + using return_type = xt::detail::functor_return_type; \ + using first_argument_type = T; \ + using second_argument_type = T; \ + using result_type = decltype(exec(std::declval(), std::declval())); \ + using simd_value_type = xsimd::simd_type; \ + using simd_result_type = typename return_type::simd_type; \ + constexpr result_type operator()(const T& arg1, const T& arg2) const \ + { \ + using math::NAME; \ + return NAME(arg1, arg2); \ + } \ + template \ + constexpr typename frt, R>::simd_type \ + simd_apply(const B& arg1, const B& arg2) const \ + { \ + using math::NAME; \ + return NAME(arg1, arg2); \ + } \ + template \ + struct rebind \ + { \ + using type = NAME##_fun; \ + }; \ + } + +#define XTENSOR_BINARY_MATH_FUNCTOR(NAME) XTENSOR_BINARY_MATH_FUNCTOR_IMPL(NAME, T) +#define XTENSOR_BINARY_BOOL_FUNCTOR(NAME) XTENSOR_BINARY_MATH_FUNCTOR_IMPL(NAME, bool) + +#define XTENSOR_TERNARY_MATH_FUNCTOR_IMPL(NAME, R) \ + template \ + struct NAME##_fun \ + { \ + static auto exec(const T& arg1, const T& arg2, const T& arg3) \ + { \ + using math::NAME; \ + return NAME(arg1, arg2, arg3); \ + } \ + template \ + using frt = xt::detail::functor_return_type; \ + using return_type = xt::detail::functor_return_type; \ + using first_argument_type = T; \ + using second_argument_type = T; \ + using third_argument_type = T; \ + using result_type = decltype(exec(std::declval(), std::declval(), \ + std::declval())); \ + using simd_value_type = xsimd::simd_type; \ + using simd_result_type = typename return_type::simd_type; \ + constexpr result_type operator()(const T& arg1, \ + const T& arg2, \ + const T& arg3) const \ + { \ + using math::NAME; \ + return NAME(arg1, arg2, arg3); \ + } \ + template \ + constexpr typename frt, R>::simd_type \ + simd_apply(const B& arg1, const B& arg2, const B& arg3) const \ + { \ + using math::NAME; \ + return NAME(arg1, arg2, arg3); \ + } \ + template \ + struct rebind \ + { \ + using type = NAME##_fun; \ + }; \ + } + +#define XTENSOR_TERNARY_MATH_FUNCTOR(NAME) XTENSOR_TERNARY_MATH_FUNCTOR_IMPL(NAME, T) +#define XTENSOR_TERNARY_BOOL_FUNCTOR(NAME) XTENSOR_TERNARY_MATH_FUNCTOR_IMPL(NAME, bool) + + namespace math + { + using std::abs; + using std::fabs; + + using std::cos; + using std::sin; + using std::tan; + using std::acos; + using std::asin; + using std::atan; + + using std::cosh; + using std::sinh; + using std::tanh; + using std::acosh; + using std::asinh; + using std::atanh; + + using std::sqrt; + using std::cbrt; + + using std::exp; + using std::exp2; + using std::expm1; + using std::log; + using std::log2; + using std::log10; + using std::log1p; + using std::logb; + using std::ilogb; + + using std::floor; + using std::ceil; + using std::trunc; + using std::round; + using std::lround; + using std::llround; + using std::rint; + using std::nearbyint; + using std::remainder; + + using std::erf; + using std::erfc; + using std::erfc; + using std::tgamma; + using std::lgamma; + + using std::conj; + using std::real; + using std::imag; + using std::arg; + + using std::atan2; + using std::copysign; + using std::fdim; + using std::fmax; + using std::fmin; + using std::fmod; + using std::hypot; + using std::pow; + + using std::fma; + + using std::isnan; + using std::isinf; + using std::isfinite; + using std::fpclassify; + + // Overload isinf, isnan and isfinite for complex datatypes, + // following the Python specification: + template + inline bool isinf(const std::complex& c) + { + return std::isinf(std::real(c)) || std::isinf(std::imag(c)); + } + + template + inline bool isnan(const std::complex& c) + { + return std::isnan(std::real(c)) || std::isnan(std::imag(c)); + } + + template + inline bool isfinite(const std::complex& c) + { + return !isinf(c) && !isnan(c); + } + + // The following specializations are needed to avoid 'ambiguous overload' errors, + // whereas 'unsigned char' and 'unsigned short' are automatically converted to 'int'. + // we're still adding those functions to silence warnings + XTENSOR_UNSIGNED_ABS_FUNC(unsigned char); + XTENSOR_UNSIGNED_ABS_FUNC(unsigned short); + XTENSOR_UNSIGNED_ABS_FUNC(unsigned int); + XTENSOR_UNSIGNED_ABS_FUNC(unsigned long); + XTENSOR_UNSIGNED_ABS_FUNC(unsigned long long); + +#ifdef _WIN32 + XTENSOR_INT_SPECIALIZATION(isinf, false); + XTENSOR_INT_SPECIALIZATION(isnan, false); + XTENSOR_INT_SPECIALIZATION(isfinite, true); +#endif + + XTENSOR_UNARY_MATH_FUNCTOR_COMPLEX_REDUCING(abs); + + XTENSOR_UNARY_MATH_FUNCTOR(fabs); + XTENSOR_BINARY_MATH_FUNCTOR(fmod); + XTENSOR_BINARY_MATH_FUNCTOR(remainder); + XTENSOR_TERNARY_MATH_FUNCTOR(fma); + XTENSOR_BINARY_MATH_FUNCTOR(fmax); + XTENSOR_BINARY_MATH_FUNCTOR(fmin); + XTENSOR_BINARY_MATH_FUNCTOR(fdim); + XTENSOR_UNARY_MATH_FUNCTOR(exp); + XTENSOR_UNARY_MATH_FUNCTOR(exp2); + XTENSOR_UNARY_MATH_FUNCTOR(expm1); + XTENSOR_UNARY_MATH_FUNCTOR(log); + XTENSOR_UNARY_MATH_FUNCTOR(log10); + XTENSOR_UNARY_MATH_FUNCTOR(log2); + XTENSOR_UNARY_MATH_FUNCTOR(log1p); + XTENSOR_BINARY_MATH_FUNCTOR(pow); + XTENSOR_UNARY_MATH_FUNCTOR(sqrt); + XTENSOR_UNARY_MATH_FUNCTOR(cbrt); + XTENSOR_BINARY_MATH_FUNCTOR(hypot); + XTENSOR_UNARY_MATH_FUNCTOR(sin); + XTENSOR_UNARY_MATH_FUNCTOR(cos); + XTENSOR_UNARY_MATH_FUNCTOR(tan); + XTENSOR_UNARY_MATH_FUNCTOR(asin); + XTENSOR_UNARY_MATH_FUNCTOR(acos); + XTENSOR_UNARY_MATH_FUNCTOR(atan); + XTENSOR_BINARY_MATH_FUNCTOR(atan2); + XTENSOR_UNARY_MATH_FUNCTOR(sinh); + XTENSOR_UNARY_MATH_FUNCTOR(cosh); + XTENSOR_UNARY_MATH_FUNCTOR(tanh); + XTENSOR_UNARY_MATH_FUNCTOR(asinh); + XTENSOR_UNARY_MATH_FUNCTOR(acosh); + XTENSOR_UNARY_MATH_FUNCTOR(atanh); + XTENSOR_UNARY_MATH_FUNCTOR(erf); + XTENSOR_UNARY_MATH_FUNCTOR(erfc); + XTENSOR_UNARY_MATH_FUNCTOR(tgamma); + XTENSOR_UNARY_MATH_FUNCTOR(lgamma); + XTENSOR_UNARY_MATH_FUNCTOR(ceil); + XTENSOR_UNARY_MATH_FUNCTOR(floor); + XTENSOR_UNARY_MATH_FUNCTOR(trunc); + XTENSOR_UNARY_MATH_FUNCTOR(round); + XTENSOR_UNARY_MATH_FUNCTOR(nearbyint); + XTENSOR_UNARY_MATH_FUNCTOR(rint); + XTENSOR_UNARY_BOOL_FUNCTOR(isfinite); + XTENSOR_UNARY_BOOL_FUNCTOR(isinf); + XTENSOR_UNARY_BOOL_FUNCTOR(isnan); + } + +#undef XTENSOR_UNARY_MATH_FUNCTOR +#undef XTENSOR_UNARY_BOOL_FUNCTOR +#undef XTENSOR_UNARY_MATH_FUNCTOR_IMPL +#undef XTENSOR_BINARY_MATH_FUNCTOR +#undef XTENSOR_BINARY_BOOL_FUNCTOR +#undef XTENSOR_BINARY_MATH_FUNCTOR_IMPL +#undef XTENSOR_TERNARY_MATH_FUNCTOR +#undef XTENSOR_TERNARY_BOOL_FUNCTOR +#undef XTENSOR_TERNARY_MATH_FUNCTOR_IMPL +#undef XTENSOR_UNARY_MATH_FUNCTOR_COMPLEX_REDUCING +#undef XTENSOR_UNSIGNED_ABS_FUNC + +#define XTENSOR_REDUCER_FUNCTION(NAME, FUNCTOR, RESULT_TYPE) \ + template >::value, int>> \ + inline auto NAME(E&& e, X&& axes, EVS es = EVS()) \ + { \ + using result_type = RESULT_TYPE; \ + using functor_type = FUNCTOR; \ + return reduce(make_xreducer_functor(functor_type()), std::forward(e), \ + std::forward(axes), es); \ + } \ + \ + template ::value, int>> \ + inline auto NAME(E&& e, EVS es = EVS()) \ + { \ + using result_type = RESULT_TYPE; \ + using functor_type = FUNCTOR; \ + return reduce(make_xreducer_functor(functor_type()), std::forward(e), es); \ + } + +#define XTENSOR_OLD_CLANG_REDUCER(NAME, FUNCTOR, RESULT_TYPE) \ + template \ + inline auto NAME(E&& e, std::initializer_list axes, EVS es = EVS()) \ + { \ + using result_type = RESULT_TYPE; \ + using functor_type = FUNCTOR; \ + return reduce(make_xreducer_functor(functor_type()), std::forward(e), axes, es); \ + } \ + +#define XTENSOR_MODERN_CLANG_REDUCER(NAME, FUNCTOR, RESULT_TYPE) \ + template \ + inline auto NAME(E&& e, const I (&axes)[N], EVS es = EVS()) \ + { \ + using result_type = RESULT_TYPE; \ + using functor_type = FUNCTOR; \ + return reduce(make_xreducer_functor(functor_type()), std::forward(e), axes, es); \ + } + + /******************* + * basic functions * + *******************/ + + /** + * @defgroup basic_functions Basic functions + */ + + /** + * @ingroup basic_functions + * @brief Absolute value function. + * + * Returns an \ref xfunction for the element-wise absolute value + * of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto abs(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup basic_functions + * @brief Absolute value function. + * + * Returns an \ref xfunction for the element-wise absolute value + * of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto fabs(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup basic_functions + * @brief Remainder of the floating point division operation. + * + * Returns an \ref xfunction for the element-wise remainder of + * the floating point division operation e1 / e2. + * @param e1 an \ref xexpression or a scalar + * @param e2 an \ref xexpression or a scalar + * @return an \ref xfunction + * @note e1 and e2 can't be both scalars. + */ + template + inline auto fmod(E1&& e1, E2&& e2) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e1), std::forward(e2)); + } + + /** + * @ingroup basic_functions + * @brief Signed remainder of the division operation. + * + * Returns an \ref xfunction for the element-wise signed remainder + * of the floating point division operation e1 / e2. + * @param e1 an \ref xexpression or a scalar + * @param e2 an \ref xexpression or a scalar + * @return an \ref xfunction + * @note e1 and e2 can't be both scalars. + */ + template + inline auto remainder(E1&& e1, E2&& e2) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e1), std::forward(e2)); + } + + /** + * @ingroup basic_functions + * @brief Fused multiply-add operation. + * + * Returns an \ref xfunction for e1 * e2 + e3 as if + * to infinite precision and rounded only once to fit the result type. + * @param e1 an \ref xfunction or a scalar + * @param e2 an \ref xfunction or a scalar + * @param e3 an \ref xfunction or a scalar + * @return an \ref xfunction + * @note e1, e2 and e3 can't be scalars every three. + */ + template + inline auto fma(E1&& e1, E2&& e2, E3&& e3) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e1), std::forward(e2), std::forward(e3)); + } + + /** + * @ingroup basic_functions + * @brief Maximum function. + * + * Returns an \ref xfunction for the element-wise maximum + * of \a e1 and \a e2. + * @param e1 an \ref xexpression or a scalar + * @param e2 an \ref xexpression or a scalar + * @return an \ref xfunction + * @note e1 and e2 can't be both scalars. + */ + template + inline auto fmax(E1&& e1, E2&& e2) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e1), std::forward(e2)); + } + + /** + * @ingroup basic_functions + * @brief Minimum function. + * + * Returns an \ref xfunction for the element-wise minimum + * of \a e1 and \a e2. + * @param e1 an \ref xexpression or a scalar + * @param e2 an \ref xexpression or a scalar + * @return an \ref xfunction + * @note e1 and e2 can't be both scalars. + */ + template + inline auto fmin(E1&& e1, E2&& e2) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e1), std::forward(e2)); + } + + /** + * @ingroup basic_functions + * @brief Positive difference function. + * + * Returns an \ref xfunction for the element-wise positive + * difference of \a e1 and \a e2. + * @param e1 an \ref xexpression or a scalar + * @param e2 an \ref xexpression or a scalar + * @return an \ref xfunction + * @note e1 and e2 can't be both scalars. + */ + template + inline auto fdim(E1&& e1, E2&& e2) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e1), std::forward(e2)); + } + + namespace math + { + template + struct minimum + { + using result_type = T; + using simd_value_type = xsimd::simd_type; + + constexpr result_type operator()(const T& t1, const T& t2) const noexcept + { + return (t1 < t2) ? t1 : t2; + } + + constexpr simd_value_type simd_apply(const simd_value_type& t1, const simd_value_type& t2) const noexcept + { + return xsimd::select(t1 < t2, t1, t2); + } + }; + + template + struct maximum + { + using result_type = T; + using simd_value_type = xsimd::simd_type; + + constexpr result_type operator()(const T& t1, const T& t2) const noexcept + { + return (t1 > t2) ? t1 : t2; + } + + constexpr simd_value_type simd_apply(const simd_value_type& t1, const simd_value_type& t2) const noexcept + { + return xsimd::select(t1 > t2, t1, t2); + } + }; + + template + struct clamp_fun + { + using first_argument_type = T; + using second_argument_type = T; + using third_argument_type = T; + using result_type = T; + using simd_value_type = xsimd::simd_type; + + constexpr T operator()(const T& v, const T& lo, const T& hi) const + { + return v < lo ? lo : hi < v ? hi : v; + } + + constexpr simd_value_type simd_apply(const simd_value_type& v, + const simd_value_type& lo, + const simd_value_type& hi) const + { + return xsimd::select(v < lo, lo, xsimd::select(hi < v, hi, v)); + } + }; + } + + /** + * @ingroup basic_functions + * @brief Elementwise maximum + * + * Returns an \ref xfunction for the element-wise + * maximum between e1 and e2. + * @param e1 an \ref xexpression + * @param e2 an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto maximum(E1&& e1, E2&& e2) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e1), std::forward(e2)); + } + + /** + * @ingroup basic_functions + * @brief Elementwise minimum + * + * Returns an \ref xfunction for the element-wise + * minimum between e1 and e2. + * @param e1 an \ref xexpression + * @param e2 an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto minimum(E1&& e1, E2&& e2) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e1), std::forward(e2)); + } + + /** + * @ingroup basic_functions + * @brief Maximum element along given axis. + * + * Returns an \ref xreducer for the maximum of elements over given + * \em axes. + * @param e an \ref xexpression + * @param axes the axes along which the maximum is found (optional) + * @param es evaluation strategy of the reducer + * @return an \ref xreducer + */ + XTENSOR_REDUCER_FUNCTION(amax, math::maximum, typename std::decay_t::value_type); +#ifdef X_OLD_CLANG + XTENSOR_OLD_CLANG_REDUCER(amax, math::maximum, typename std::decay_t::value_type); +#else + XTENSOR_MODERN_CLANG_REDUCER(amax, math::maximum, typename std::decay_t::value_type); +#endif + + /** + * @ingroup basic_functions + * @brief Minimum element along given axis. + * + * Returns an \ref xreducer for the minimum of elements over given + * \em axes. + * @param e an \ref xexpression + * @param axes the axes along which the minimum is found (optional) + * @param es evaluation strategy of the reducer + * @return an \ref xreducer + */ + XTENSOR_REDUCER_FUNCTION(amin, math::minimum, typename std::decay_t::value_type); +#ifdef X_OLD_CLANG + XTENSOR_OLD_CLANG_REDUCER(amin, math::minimum, typename std::decay_t::value_type); +#else + XTENSOR_MODERN_CLANG_REDUCER(amin, math::minimum, typename std::decay_t::value_type); +#endif + + /** + * @ingroup basic_functions + * @brief Clip values between hi and lo + * + * Returns an \ref xfunction for the element-wise clipped + * values between lo and hi + * @param e1 an \ref xexpression or a scalar + * @param lo a scalar + * @param hi a scalar + * + * @return a \ref xfunction + */ + template + inline auto clip(E1&& e1, E2&& lo, E3&& hi) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e1), std::forward(lo), std::forward(hi)); + } + + namespace math + { + namespace detail + { + template + constexpr std::enable_if_t::value, T> + sign_impl(T x) + { + return std::isnan(x) ? std::numeric_limits::quiet_NaN() : x == 0 ? T(copysign(T(0), x)) : T(copysign(T(1), x)); + } + + template + inline std::enable_if_t::value, T> + sign_impl(T x) + { + typename T::value_type e = (x.real() != T(0)) ? x.real() : x.imag(); + return T(sign_impl(e), 0); + } + + template + constexpr std::enable_if_t::value, T> + sign_impl(T x) + { + return T(x > T(0)); + } + } + + template + struct sign_fun + { + using argument_type = T; + using result_type = T; + + constexpr T operator()(const T& x) const + { + return detail::sign_impl(x); + } + }; + } + + /** + * @ingroup basic_functions + * @brief Returns an element-wise indication of the sign of a number + * + * If the number is positive, returns +1. If negative, -1. If the number + * is zero, returns 0. + * + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto sign(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /************************* + * exponential functions * + *************************/ + + /** + * @defgroup exp_functions Exponential functions + */ + + /** + * @ingroup exp_functions + * @brief Natural exponential function. + * + * Returns an \ref xfunction for the element-wise natural + * exponential of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto exp(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup exp_functions + * @brief Base 2 exponential function. + * + * Returns an \ref xfunction for the element-wise base 2 + * exponential of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto exp2(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup exp_functions + * @brief Natural exponential minus one function. + * + * Returns an \ref xfunction for the element-wise natural + * exponential of \em e, minus 1. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto expm1(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup exp_functions + * @brief Natural logarithm function. + * + * Returns an \ref xfunction for the element-wise natural + * logarithm of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto log(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup exp_functions + * @brief Base 10 logarithm function. + * + * Returns an \ref xfunction for the element-wise base 10 + * logarithm of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto log10(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup exp_functions + * @brief Base 2 logarithm function. + * + * Returns an \ref xfunction for the element-wise base 2 + * logarithm of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto log2(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup exp_functions + * @brief Natural logarithm of one plus function. + * + * Returns an \ref xfunction for the element-wise natural + * logarithm of \em e, plus 1. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto log1p(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /******************* + * power functions * + *******************/ + + /** + * @defgroup pow_functions Power functions + */ + + /** + * @ingroup pow_functions + * @brief Power function. + * + * Returns an \ref xfunction for the element-wise value of + * of \em e1 raised to the power \em e2. + * @param e1 an \ref xexpression or a scalar + * @param e2 an \ref xexpression or a scalar + * @return an \ref xfunction + * @note e1 and e2 can't be both scalars. + */ + template + inline auto pow(E1&& e1, E2&& e2) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e1), std::forward(e2)); + } + + /** + * @ingroup pow_functions + * @brief Square root function. + * + * Returns an \ref xfunction for the element-wise square + * root of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto sqrt(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup pow_functions + * @brief Cubic root function. + * + * Returns an \ref xfunction for the element-wise cubic + * root of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto cbrt(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup pow_functions + * @brief Hypotenuse function. + * + * Returns an \ref xfunction for the element-wise square + * root of the sum of the square of \em e1 and \em e2, avoiding + * overflow and underflow at intermediate stages of computation. + * @param e1 an \ref xexpression or a scalar + * @param e2 an \ref xexpression or a scalar + * @return an \ref xfunction + * @note e1 and e2 can't be both scalars. + */ + template + inline auto hypot(E1&& e1, E2&& e2) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e1), std::forward(e2)); + } + + /*************************** + * trigonometric functions * + ***************************/ + + /** + * @defgroup trigo_functions Trigonometric function + */ + + /** + * @ingroup trigo_functions + * @brief Sine function. + * + * Returns an \ref xfunction for the element-wise sine + * of \em e (measured in radians). + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto sin(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup trigo_functions + * @brief Cosine function. + * + * Returns an \ref xfunction for the element-wise cosine + * of \em e (measured in radians). + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto cos(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup trigo_functions + * @brief Tangent function. + * + * Returns an \ref xfunction for the element-wise tangent + * of \em e (measured in radians). + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto tan(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup trigo_functions + * @brief Arcsine function. + * + * Returns an \ref xfunction for the element-wise arcsine + * of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto asin(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup trigo_functions + * @brief Arccosine function. + * + * Returns an \ref xfunction for the element-wise arccosine + * of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto acos(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup trigo_functions + * @brief Arctangent function. + * + * Returns an \ref xfunction for the element-wise arctangent + * of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto atan(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup trigo_functions + * @brief Artangent function, using signs to determine quadrants. + * + * Returns an \ref xfunction for the element-wise arctangent + * of e1 / e2, using the signs of arguments to determine the + * correct quadrant. + * @param e1 an \ref xexpression or a scalar + * @param e2 an \ref xexpression or a scalar + * @return an \ref xfunction + * @note e1 and e2 can't be both scalars. + */ + template + inline auto atan2(E1&& e1, E2&& e2) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e1), std::forward(e2)); + } + + /************************ + * hyperbolic functions * + ************************/ + + /** + * @defgroup hyper_functions Hyperbolic functions + */ + + /** + * @ingroup hyper_functions + * @brief Hyperbolic sine function. + * + * Returns an \ref xfunction for the element-wise hyperbolic + * sine of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto sinh(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup hyper_functions + * @brief Hyperbolic cosine function. + * + * Returns an \ref xfunction for the element-wise hyperbolic + * cosine of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto cosh(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup hyper_functions + * @brief Hyperbolic tangent function. + * + * Returns an \ref xfunction for the element-wise hyperbolic + * tangent of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto tanh(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup hyper_functions + * @brief Inverse hyperbolic sine function. + * + * Returns an \ref xfunction for the element-wise inverse hyperbolic + * sine of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto asinh(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup hyper_functions + * @brief Inverse hyperbolic cosine function. + * + * Returns an \ref xfunction for the element-wise inverse hyperbolic + * cosine of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto acosh(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup hyper_functions + * @brief Inverse hyperbolic tangent function. + * + * Returns an \ref xfunction for the element-wise inverse hyperbolic + * tangent of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto atanh(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /***************************** + * error and gamma functions * + *****************************/ + + /** + * @defgroup err_functions Error and gamma functions + */ + + /** + * @ingroup err_functions + * @brief Error function. + * + * Returns an \ref xfunction for the element-wise error function + * of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto erf(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup err_functions + * @brief Complementary error function. + * + * Returns an \ref xfunction for the element-wise complementary + * error function of \em e, whithout loss of precision for large argument. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto erfc(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup err_functions + * @brief Gamma function. + * + * Returns an \ref xfunction for the element-wise gamma function + * of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto tgamma(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup err_functions + * @brief Natural logarithm of the gamma function. + * + * Returns an \ref xfunction for the element-wise logarithm of + * the asbolute value fo the gamma function of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto lgamma(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /********************************************* + * nearest integer floating point operations * + *********************************************/ + + /** + * @defgroup nearint_functions Nearest integer floating point operations + */ + + /** + * @ingroup nearint_functions + * @brief ceil function. + * + * Returns an \ref xfunction for the element-wise smallest integer value + * not less than \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto ceil(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup nearint_functions + * @brief floor function. + * + * Returns an \ref xfunction for the element-wise smallest integer value + * not greater than \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto floor(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup nearint_functions + * @brief trunc function. + * + * Returns an \ref xfunction for the element-wise nearest integer not greater + * in magnitude than \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto trunc(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup nearint_functions + * @brief round function. + * + * Returns an \ref xfunction for the element-wise nearest integer value + * to \em e, rounding halfway cases away from zero, regardless of the + * current rounding mode. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto round(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup nearint_functions + * @brief nearbyint function. + * + * Returns an \ref xfunction for the element-wise rounding of \em e to integer + * values in floating point format, using the current rounding mode. nearbyint + * never raises FE_INEXACT error. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto nearbyint(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup nearint_functions + * @brief rint function. + * + * Returns an \ref xfunction for the element-wise rounding of \em e to integer + * values in floating point format, using the current rounding mode. Contrary + * to nearbyint, rint may raise FE_INEXACT error. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto rint(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /**************************** + * classification functions * + ****************************/ + + /** + * @defgroup classif_functions Classification functions + */ + + /** + * @ingroup classif_functions + * @brief finite value check + * + * Returns an \ref xfunction for the element-wise finite value check + * tangent of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto isfinite(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup classif_functions + * @brief infinity check + * + * Returns an \ref xfunction for the element-wise infinity check + * tangent of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto isinf(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup classif_functions + * @brief NaN check + * + * Returns an \ref xfunction for the element-wise NaN check + * tangent of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto isnan(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + namespace detail + { + template + inline auto get_functor(T&& args, std::index_sequence) + { + return FUNCTOR(std::get(args)...); + } + + template