Line data Source code
1 : //* This file is part of the MOOSE framework
2 : //* https://mooseframework.inl.gov
3 : //*
4 : //* All rights reserved, see COPYRIGHT for full restrictions
5 : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 : //*
7 : //* Licensed under LGPL 2.1, please see LICENSE for details
8 : //* https://www.gnu.org/licenses/lgpl-2.1.html
9 : // Bootstrap CI
10 :
11 : #include "BootstrapCalculators.h"
12 :
13 : namespace StochasticTools
14 : {
15 :
16 : MooseEnum
17 2112 : makeBootstrapCalculatorEnum()
18 : {
19 4224 : return MooseEnum("percentile=0 bca=1");
20 : }
21 :
22 : // PERCENTILE //////////////////////////////////////////////////////////////////////////////////////
23 : template <typename InType, typename OutType>
24 : std::vector<OutType>
25 3222 : Percentile<InType, OutType>::compute(const InType & data, const bool is_distributed)
26 : {
27 : // Bootstrap estimates
28 3222 : const std::vector<OutType> values = this->computeBootstrapEstimates(data, is_distributed);
29 :
30 : // Extract percentiles
31 : std::vector<OutType> output;
32 3222 : if (this->processor_id() == 0)
33 13634 : for (const Real & level : this->_levels)
34 : {
35 11112 : long unsigned int index = std::lrint(level * (this->_replicates - 1));
36 11112 : output.push_back(values[index]);
37 : }
38 :
39 3222 : return output;
40 : }
41 :
42 : // BIASCORRECTEDACCELERATED ////////////////////////////////////////////////////////////////////////
43 : template <typename InType, typename OutType>
44 : std::vector<OutType>
45 92 : BiasCorrectedAccelerated<InType, OutType>::compute(const InType & data, const bool is_distributed)
46 : {
47 : // Bootstrap estimates
48 92 : const std::vector<OutType> values = this->computeBootstrapEstimates(data, is_distributed);
49 :
50 : // Compute bias-correction, Efron and Tibshirani (2003), Eq. 14.14, p. 186
51 92 : const OutType value = this->_calc.compute(data, is_distributed);
52 92 : const Real count = std::count_if(
53 : values.begin(),
54 : values.end(),
55 : [&value](Real v) { return v < value; }); // use Real for non-integer division below
56 92 : const Real bias = NormalDistribution::quantile(count / this->_replicates, 0, 1);
57 :
58 : // Compute Acceleration, Efron and Tibshirani (2003), Eq. 14.15, p. 186
59 92 : const OutType acc = data.empty() ? OutType() : acceleration(data, is_distributed);
60 :
61 : // Compute intervals, Efron and Tibshirani (2003), Eq. 14.10, p. 185
62 : std::vector<OutType> output;
63 914 : for (const Real & level : this->_levels)
64 : {
65 822 : const Real z = NormalDistribution::quantile(level, 0, 1);
66 822 : const Real x = bias + (bias + (bias + z) / (1 - acc * (bias + z)));
67 822 : const Real alpha = NormalDistribution::cdf(x, 0, 1);
68 :
69 822 : long unsigned int index = std::lrint(alpha * (this->_replicates - 1));
70 822 : output.push_back(values[index]);
71 : }
72 92 : return output;
73 : }
74 :
75 : template <typename InType, typename OutType>
76 : OutType
77 92 : BiasCorrectedAccelerated<InType, OutType>::acceleration(const InType & data,
78 : const bool is_distributed)
79 : {
80 : const std::size_t local_size = data.size();
81 92 : std::vector<std::size_t> local_sizes = {local_size};
82 92 : if (is_distributed)
83 30 : this->_communicator.allgather(local_sizes);
84 92 : const std::size_t count = std::accumulate(local_sizes.begin(), local_sizes.end(), 0);
85 92 : const processor_id_type rank = is_distributed ? this->processor_id() : 0;
86 :
87 : // Jackknife statistics
88 92 : std::vector<OutType> theta_i(local_size);
89 :
90 : // Compute jackknife estimates, Ch. 11, Eq. 11.2, p. 141
91 244 : for (processor_id_type r = 0; r < local_sizes.size(); ++r)
92 4692 : for (std::size_t i = 0; i < local_sizes[r]; ++i)
93 : {
94 4540 : this->_calc.initializeCalculator();
95 2058580 : for (std::size_t il = 0; il < local_size; ++il)
96 2054040 : if (i != il || r != rank)
97 2050100 : this->_calc.updateCalculator(data[il]);
98 4540 : this->_calc.finalizeCalculator(is_distributed);
99 4540 : if (r == rank)
100 3940 : theta_i[i] = this->_calc.getValue();
101 : }
102 :
103 : // Compute jackknife sum, Ch. 11, Eq. 11.4, p. 141
104 92 : OutType theta_dot = std::accumulate(theta_i.begin(), theta_i.end(), OutType());
105 92 : if (is_distributed)
106 30 : this->_communicator.sum(theta_dot);
107 92 : theta_dot /= count;
108 :
109 : // Acceleration, Ch. 14, Eq. 14.15, p. 185
110 92 : std::vector<OutType> num_den(2);
111 4032 : for (const auto & jk : theta_i)
112 : {
113 3940 : num_den[0] += MathUtils::pow(theta_dot - jk, 3);
114 3940 : num_den[1] += MathUtils::pow(theta_dot - jk, 2);
115 : }
116 92 : if (is_distributed)
117 30 : this->_communicator.sum(num_den);
118 :
119 : mooseAssert(num_den[1] != OutType(), "The acceleration denomenator must not be zero.");
120 184 : return num_den[0] / (6 * std::pow(num_den[1], 3. / 2.));
121 : }
122 :
123 : template <typename InType, typename OutType>
124 : std::unique_ptr<BootstrapCalculator<InType, OutType>>
125 2538 : BootstrapCalculatorBuilder<InType, OutType>::build(
126 : const MooseEnum & item,
127 : const libMesh::ParallelObject & other,
128 : const std::vector<Real> & levels,
129 : unsigned int replicates,
130 : unsigned int seed,
131 : StochasticTools::Calculator<InType, OutType> & calc)
132 : {
133 : std::unique_ptr<BootstrapCalculator<InType, OutType>> ptr = nullptr;
134 2538 : if (item == "percentile")
135 2414 : ptr =
136 : std::make_unique<Percentile<InType, OutType>>(other, item, levels, replicates, seed, calc);
137 124 : else if (item == "bca")
138 124 : ptr = std::make_unique<BiasCorrectedAccelerated<InType, OutType>>(
139 : other, item, levels, replicates, seed, calc);
140 :
141 2538 : if (!ptr)
142 0 : ::mooseError("Failed to create Statistics::BootstrapCalculator object for ", item);
143 :
144 2538 : return ptr;
145 0 : }
146 :
147 : #define createBootstrapCalculators(InType, OutType) \
148 : template class Percentile<InType, OutType>; \
149 : template class BiasCorrectedAccelerated<InType, OutType>; \
150 : template struct BootstrapCalculatorBuilder<InType, OutType>
151 :
152 : createBootstrapCalculators(std::vector<Real>, Real);
153 : createBootstrapCalculators(std::vector<int>, Real);
154 :
155 : } // namespace
|