Chi-Tech
cylindrical_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 chi_math::Quadrature& quad_azimu,
15 const bool verbose)
17{
18 const auto np = quad_polar.weights_.size();
19 std::vector<chi_math::Quadrature> quad_azimu_vec(np, quad_azimu);
20 Initialize(quad_polar, quad_azimu_vec, verbose);
21}
22
23
26 const chi_math::Quadrature& quad_polar,
27 const std::vector<chi_math::Quadrature>& quad_azimu_vec,
28 const bool verbose)
30{
31 Initialize(quad_polar, quad_azimu_vec, verbose);
32}
33
34
35void
37 Initialize(const chi_math::Quadrature& quad_polar,
38 const std::vector<chi_math::Quadrature>& quad_azimu_vec,
39 const bool verbose)
40{
41 // copies of input quadratures
42 auto polar_quad(quad_polar);
43 auto azimu_quad_vec(quad_azimu_vec);
44
45 // --------------------------------------------------------------------------
46 // verifications and corrections (if possible)
47 // --------------------------------------------------------------------------
48 const auto eps = std::numeric_limits<double>::epsilon();
49
50 // consistency among polar quadrature and azimuthal quadratures
51 if (polar_quad.weights_.size() != azimu_quad_vec.size())
52 throw std::invalid_argument("chi_math::CylindricalAngularQuadrature::Initialize : "
53 "number of azimuthal quadratures does not correspond "
54 "to number of polar points of the polar quadrature.");
55
56 // at present, this class does not handle correctly reduced geometries
57 if (polar_quad.weights_.size() == 0)
58 throw std::invalid_argument("chi_math::CylindricalAngularQuadrature::Initialize : "
59 "invalid polar quadrature size = "
60 +std::to_string(polar_quad.weights_.size()));
61
62 for (const auto& azimu_quad : azimu_quad_vec)
63 if (azimu_quad.weights_.size() == 0)
64 throw std::invalid_argument("chi_math::CylindricalAngularQuadrature::Initialize : "
65 "invalid azimuthal quadrature size = "
66 +std::to_string(azimu_quad.weights_.size()));
67
68 // --------------------------------------------------------------------------
69 // verifications on polar quadrature
70 // --------------------------------------------------------------------------
71 const double polar_quad_sum_weights = 2;
72 const auto polar_quad_span = std::pair<double, double>(-1, +1);
73
74 // weights sum to 2
75 const auto integral_weights =
76 std::accumulate(polar_quad.weights_.begin(), polar_quad.weights_.end(), 0.0);
77 if (std::abs(integral_weights) > 0)
78 {
79 const auto fac = polar_quad_sum_weights / integral_weights;
80 if (std::abs(fac - 1) > eps)
81 for (auto& w : polar_quad.weights_)
82 w *= fac;
83 }
84 else
85 throw std::invalid_argument("chi_math::CylindricalAngularQuadrature::Initialize : "
86 "polar quadrature weights sum to zero.");
87
88 // defined on range [-1;+1]
89 if (std::abs(polar_quad.GetRange().first - polar_quad_span.first) > eps ||
90 std::abs(polar_quad.GetRange().second- polar_quad_span.second) > eps)
91 polar_quad.SetRange(polar_quad_span);
92
93 // --------------------------------------------------------------------------
94 // verifications on azimuthal quadrature
95 // --------------------------------------------------------------------------
96 const double azimu_quad_sum_weights = M_PI;
97 const auto azimu_quad_span = std::pair<double, double>(-1, +1);
98
99 for (auto& azimu_quad : azimu_quad_vec)
100 {
101 // weights sum to $\pi$
102 const auto integral_weights =
103 std::accumulate(azimu_quad.weights_.begin(), azimu_quad.weights_.end(), 0.0);
104 if (std::abs(integral_weights) > 0)
105 {
106 const auto fac = azimu_quad_sum_weights / integral_weights;
107 if (std::abs(fac - 1) > eps)
108 for (auto& w : azimu_quad.weights_)
109 w *= fac;
110 }
111 else
112 throw std::invalid_argument("chi_math::CylindricalAngularQuadrature::Initialize : "
113 "azimuthal quadrature weights sum to zero.");
114
115 // defined on range [-1;+1]
116 if (std::abs(azimu_quad.GetRange().first - azimu_quad_span.first) > eps ||
117 std::abs(azimu_quad.GetRange().second- azimu_quad_span.second) > eps)
118 azimu_quad.SetRange(azimu_quad_span);
119
120 // abscissae sorted in ascending order
121 auto lt_qp = [](const chi_math::QuadraturePointXYZ& qp0,
123 { return qp0[0] < qp1[0]; };
124 if (!std::is_sorted(azimu_quad.qpoints_.begin(), azimu_quad.qpoints_.end(), lt_qp))
125 throw std::invalid_argument("chi_math::CylindricalAngularQuadrature::Initialize : "
126 "azimuthal quadrature abscissae not in ascending order.");
127
128 // existence of zero-weight abscissae at the start and at the end of the interval
129 if (std::abs(azimu_quad.weights_.front()) > eps &&
130 std::abs(azimu_quad.qpoints_.front()[0] - azimu_quad_span.first) > eps)
131 {
132 azimu_quad.weights_.emplace(azimu_quad.weights_.begin(), 0);
133 azimu_quad.qpoints_.emplace(azimu_quad.qpoints_.begin(), azimu_quad_span.first);
134 }
135 if (std::abs(azimu_quad.weights_.back()) > eps &&
136 std::abs(azimu_quad.qpoints_.back()[0] - azimu_quad_span.second) > eps)
137 {
138 azimu_quad.weights_.emplace(azimu_quad.weights_.end(), 0);
139 azimu_quad.qpoints_.emplace(azimu_quad.qpoints_.end(), azimu_quad_span.second);
140 }
141 }
142
143 // --------------------------------------------------------------------------
144 // product quadrature : initialisation
145 // --------------------------------------------------------------------------
146
147 // compute weights, abscissae $(\varphi, \vartheta)$ and direction vectors
148 // $\omega_{pq} := (\mu_{pq}, \xi_{p}, \eta_{pq})$
149 weights_.clear();
150 abscissae_.clear();
151 omegas_.clear();
152 for (size_t p = 0; p < azimu_quad_vec.size(); ++p)
153 {
154 const auto pol_wei = polar_quad.weights_[p];
155 const auto pol_abs = polar_quad.qpoints_[p][0];
156 const auto pol_com = std::sqrt(1 - pol_abs * pol_abs);
157
158 for (size_t q = 0; q < azimu_quad_vec[p].weights_.size(); ++q)
159 {
160 const auto& azimu_quad = azimu_quad_vec[p];
161
162 const auto azi_wei = azimu_quad.weights_[q];
163 const auto azi_abs = azimu_quad.qpoints_[q][0];
164 const auto azi_com = std::sqrt(1 - azi_abs * azi_abs);
165
166 const auto weight = pol_wei * azi_wei;
167 const auto abscissa =
168 QuadraturePointPhiTheta(std::acos(azi_abs), std::acos(pol_abs));
169 const auto omega =
170 chi_mesh::Vector3(pol_com * azi_abs, pol_abs, pol_com * azi_com);
171
172 weights_.emplace_back(weight);
173 abscissae_.emplace_back(abscissa);
174 omegas_.emplace_back(omega);
175 }
176 }
177 weights_.shrink_to_fit();
178 abscissae_.shrink_to_fit();
179 omegas_.shrink_to_fit();
180
181 // map of direction indices
182 unsigned int ind0 = 0;
183 map_directions_.clear();
184 for (size_t p = 0; p < azimu_quad_vec.size(); ++p)
185 {
186 std::vector<unsigned int> vec_directions_p;
187 for (size_t q = 0; q < azimu_quad_vec[p].weights_.size(); ++q)
188 vec_directions_p.emplace_back(ind0 + q);
189 map_directions_.emplace(p, vec_directions_p);
190 ind0 += azimu_quad_vec[p].weights_.size();
191 }
192
193 // --------------------------------------------------------------------------
194 // curvilinear product quadrature : compute additional parametrising factors
195 // --------------------------------------------------------------------------
196 InitializeParameters();
197
198 // --------------------------------------------------------------------------
199 // print
200 // --------------------------------------------------------------------------
201 if (verbose)
202 {
203 Chi::log.Log() << "map_directions" << std::endl;
204 for (const auto& dir : map_directions_)
205 {
206 Chi::log.Log() << "polar level " << dir.first << " : ";
207 for (const auto& q : dir.second)
208 Chi::log.Log() << q << ", ";
209 Chi::log.Log() << std::endl;
210 }
211 Chi::log.Log() << "curvilinear product quadrature : cylindrical" << std::endl;
212 for (size_t k = 0; k < weights_.size(); ++k)
213 Chi::log.Log()
214 << "angle index " << k << ": weight = " << weights_[k]
215 << ", (phi, theta) = (" << abscissae_[k].phi << ", " << abscissae_[k].theta << ")"
216 << ", omega = " << omegas_[k].PrintStr()
217 << ", fac_diamond_difference = " << fac_diamond_difference_[k]
218 << ", fac_streaming_operator = " << fac_streaming_operator_[k]
219 << std::endl;
220 const auto sum_weights =
221 std::accumulate(weights_.begin(), weights_.end(), 0.0);
222 Chi::log.Log() << "sum(weights) = " << sum_weights << std::endl;
223 }
224}
225
226
227void
229{
230 fac_diamond_difference_.resize(weights_.size(), 1);
231 fac_streaming_operator_.resize(weights_.size(), 0);
232 for (size_t p = 0; p < map_directions_.size(); ++p)
233 {
234 double sum_q_weights = 0;
235 for (size_t q = 0; q < map_directions_[p].size(); ++q)
236 sum_q_weights += weights_[map_directions_[p][q]];
237 const auto pi_sum_q_weights = M_PI / sum_q_weights;
238
239 // interface quantities initialised to starting direction values
240 double alpha_interface = 0;
241 double phi_interface = abscissae_[map_directions_[p].front()].phi;
242 std::vector<double> mu_interface(2, std::cos(phi_interface));
243
244 // initialisation permits to forego start direction and final direction
245 for (size_t q = 1; q < map_directions_[p].size() - 1; ++q)
246 {
247 const auto k = map_directions_[p][q];
248 const auto w_pq = weights_[k];
249 const auto mu_pq = omegas_[k].x;
250 const auto phi_pq = abscissae_[k].phi;
251
252 alpha_interface -= w_pq * mu_pq;
253
254 phi_interface -= w_pq * pi_sum_q_weights;
255 mu_interface[0] = mu_interface[1];
256 mu_interface[1] = std::cos(phi_interface);
257
258 const auto mu = std::cos(phi_pq);
259 const auto tau = (mu - mu_interface[0]) / (mu_interface[1] - mu_interface[0]);
260
261 fac_diamond_difference_[k] = tau;
262 fac_streaming_operator_[k] = alpha_interface / (w_pq * tau) + mu_pq;
263 }
264 }
265}
266
267
268void
269chi_math::CylindricalAngularQuadrature::MakeHarmonicIndices(unsigned int scattering_order, int dimension)
270{
271 if (m_to_ell_em_map_.empty())
272 {
273 if (dimension == 1)
274 {
275 for (unsigned int l = 0; l <= scattering_order; ++l)
276 for (int m = 0; m <= l; ++m)
277 if ((l + m) % 2 == 0)
278 m_to_ell_em_map_.emplace_back(l, m);
279 }
280 else if (dimension == 2)
281 for (unsigned int l = 0; l <= scattering_order; ++l)
282 for (int m = 0; m <= l; ++m)
283 m_to_ell_em_map_.emplace_back(l, m);
284 else
285 throw std::invalid_argument("chi_math::CylindricalAngularQuadrature::MakeHarmonicIndices : "
286 "invalid dimension.");
287 }
288}
static chi::ChiLog & log
Definition: chi_runtime.h:81
LogStream Log(LOG_LVL level=LOG_0)
Definition: chi_log.cc:35
CylindricalAngularQuadrature(const chi_math::Quadrature &quad_polar, const chi_math::Quadrature &quad_azimu, const bool verbose=false)
void MakeHarmonicIndices(unsigned int scattering_order, int dimension) override
void Initialize(const chi_math::Quadrature &quad_polar, const std::vector< chi_math::Quadrature > &quad_azimu_vec, const bool verbose=false)
std::vector< double > weights_
Definition: quadrature.h:38
VectorN< 3 > Vector3