Chi-Tech
spherical_angular_quadrature.cc
Go to the documentation of this file.
2
3#include <algorithm>
4#include <limits>
5#include <numeric>
6
7#include "chi_runtime.h"
8#include "chi_log.h"
9
10
13 const chi_math::Quadrature& quad_polar,
14 const bool verbose)
16{
17 Initialize(quad_polar, verbose);
18}
19
20
21void
23 Initialize(const chi_math::Quadrature& quad_polar,
24 const bool verbose)
25{
26 // copies of input quadratures
27 auto polar_quad(quad_polar);
28
29 // --------------------------------------------------------------------------
30 // verifications and corrections (if possible)
31 // --------------------------------------------------------------------------
32 const auto eps = std::numeric_limits<double>::epsilon();
33
34 if (polar_quad.weights_.size() == 0)
35 throw std::invalid_argument("chi_math::SphericalAngularQuadrature::Initialize : "
36 "invalid polar quadrature size = "
37 +std::to_string(polar_quad.weights_.size()));
38
39 // --------------------------------------------------------------------------
40 // verifications on polar quadrature
41 // --------------------------------------------------------------------------
42 const double polar_quad_sum_weights = 2;
43 const auto polar_quad_span = std::pair<double, double>(-1, +1);
44
45 // weights sum to 2
46 const auto integral_weights =
47 std::accumulate(polar_quad.weights_.begin(), polar_quad.weights_.end(), 0.0);
48 if (std::abs(integral_weights) > 0)
49 {
50 const auto fac = polar_quad_sum_weights / integral_weights;
51 if (std::abs(fac - 1) > eps)
52 for (auto& w : polar_quad.weights_)
53 w *= fac;
54 }
55 else
56 throw std::invalid_argument("chi_math::SphericalAngularQuadrature::Initialize : "
57 "polar quadrature weights sum to zero.");
58
59 // defined on range [-1;+1]
60 if (std::abs(polar_quad.GetRange().first - polar_quad_span.first) > eps ||
61 std::abs(polar_quad.GetRange().second- polar_quad_span.second) > eps)
62 polar_quad.SetRange(polar_quad_span);
63
64 // abscissae sorted in ascending order
65 auto lt_qp = [](const chi_math::QuadraturePointXYZ& qp0,
67 { return qp0[0] < qp1[0]; };
68 if (!std::is_sorted(polar_quad.qpoints_.begin(), polar_quad.qpoints_.end(), lt_qp))
69 throw std::invalid_argument("chi_math::SphericalAngularQuadrature::Initialize : "
70 "polar quadrature abscissae not in ascending order.");
71
72 // existence of zero-weight abscissae at the start and at the end of the interval
73 if (std::abs(polar_quad.weights_.front()) > eps &&
74 std::abs(polar_quad.qpoints_.front()[0] - polar_quad_span.first) > eps)
75 {
76 polar_quad.weights_.emplace(polar_quad.weights_.begin(), 0);
77 polar_quad.qpoints_.emplace(polar_quad.qpoints_.begin(), polar_quad_span.first);
78 }
79 if (std::abs(polar_quad.weights_.back()) > eps &&
80 std::abs(polar_quad.qpoints_.back()[0] - polar_quad_span.second) > eps)
81 {
82 polar_quad.weights_.emplace(polar_quad.weights_.end(), 0);
83 polar_quad.qpoints_.emplace(polar_quad.qpoints_.end(), polar_quad_span.second);
84 }
85
86 // --------------------------------------------------------------------------
87 // product quadrature : initialisation
88 // --------------------------------------------------------------------------
89
90 // compute weights, abscissae $(0, \vartheta_{p})$ and direction vectors
91 // $\omega_{p} := ((1-\mu_{p}^{2})^{1/2}, 0, \mu_{p})$
92 weights_.clear();
93 abscissae_.clear();
94 omegas_.clear();
95 for (size_t p = 0; p < polar_quad.weights_.size(); ++p)
96 {
97 const auto pol_wei = polar_quad.weights_[p];
98 const auto pol_abs = polar_quad.qpoints_[p][0];
99 const auto pol_com = std::sqrt(1 - pol_abs * pol_abs);
100
101 const auto weight = pol_wei;
102 const auto abscissa = QuadraturePointPhiTheta(0, std::acos(pol_abs));
103 const auto omega = chi_mesh::Vector3(pol_com, 0, pol_abs);
104
105 weights_.emplace_back(weight);
106 abscissae_.emplace_back(abscissa);
107 omegas_.emplace_back(omega);
108 }
109 weights_.shrink_to_fit();
110 abscissae_.shrink_to_fit();
111 omegas_.shrink_to_fit();
112
113 // map of direction indices
114 map_directions_.clear();
115 for (size_t p = 0; p < polar_quad.weights_.size(); ++p)
116 {
117 std::vector<unsigned int> vec_directions_p;
118 vec_directions_p.emplace_back(p);
119 map_directions_.emplace(p, vec_directions_p);
120 }
121
122 // --------------------------------------------------------------------------
123 // curvilinear product quadrature : compute additional parametrising factors
124 // --------------------------------------------------------------------------
125 InitializeParameters();
126
127 // --------------------------------------------------------------------------
128 // print
129 // --------------------------------------------------------------------------
130 if (verbose)
131 {
132 Chi::log.Log() << "map_directions" << std::endl;
133 for (const auto& dir : map_directions_)
134 {
135 Chi::log.Log() << "polar level " << dir.first << " : ";
136 for (const auto& q : dir.second)
137 Chi::log.Log() << q << ", ";
138 Chi::log.Log() << std::endl;
139 }
140 Chi::log.Log() << "curvilinear product quadrature : spherical" << std::endl;
141 for (size_t k = 0; k < weights_.size(); ++k)
142 Chi::log.Log()
143 << "angle index " << k << ": weight = " << weights_[k]
144 << ", (phi, theta) = (" << abscissae_[k].phi << ", " << abscissae_[k].theta << ")"
145 << ", omega = " << omegas_[k].PrintStr()
146 << ", fac_diamond_difference = " << fac_diamond_difference_[k]
147 << ", fac_streaming_operator = " << fac_streaming_operator_[k]
148 << std::endl;
149 const auto sum_weights =
150 std::accumulate(weights_.begin(), weights_.end(), 0.0);
151 Chi::log.Log() << "sum(weights) = " << sum_weights << std::endl;
152 }
153}
154
155
156void
158{
159 fac_diamond_difference_.resize(weights_.size(), 1);
160 fac_streaming_operator_.resize(weights_.size(), 0);
161
162 // interface quantities initialised to starting direction values
163 double alpha_interface = 0;
164 std::vector<double> mu_interface(2, omegas_[map_directions_[0].front()].z);
165
166 // initialisation permits to forego start direction and final direction
167 for (size_t p = 1; p < map_directions_.size() - 1; ++p)
168 {
169 const auto k = map_directions_[p][0];
170 const auto w_p = weights_[k];
171 const auto mu_p = omegas_[k].z;
172
173 alpha_interface -= w_p * mu_p;
174
175 mu_interface[0] = mu_interface[1];
176 mu_interface[1] += w_p;
177
178 const auto tau = (mu_p - mu_interface[0]) / (mu_interface[1] - mu_interface[0]);
179
180 fac_diamond_difference_[k] = tau;
181 fac_streaming_operator_[k] = alpha_interface / (w_p * tau) + mu_p;
182 fac_streaming_operator_[k] *= 2;
183 }
184}
185
186
187void
188chi_math::SphericalAngularQuadrature::MakeHarmonicIndices(unsigned int scattering_order, int dimension)
189{
190 if (m_to_ell_em_map_.empty())
191 {
192 if (dimension == 1)
193 for (unsigned int l = 0; l <= scattering_order; ++l)
194 m_to_ell_em_map_.emplace_back(l, 0);
195 else
196 throw std::invalid_argument("chi_math::SphericalAngularQuadrature::MakeHarmonicIndices : "
197 "invalid dimension.");
198 }
199}
static chi::ChiLog & log
Definition: chi_runtime.h:81
LogStream Log(LOG_LVL level=LOG_0)
Definition: chi_log.cc:35
void Initialize(const chi_math::Quadrature &quad_polar, const bool verbose=false)
SphericalAngularQuadrature(const chi_math::Quadrature &quad_polar, const bool verbose=false)
void MakeHarmonicIndices(unsigned int scattering_order, int dimension) override
VectorN< 3 > Vector3