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);
27 const std::vector<chi_math::Quadrature>& quad_azimu_vec,
31 Initialize(quad_polar, quad_azimu_vec, verbose);
38 const std::vector<chi_math::Quadrature>& quad_azimu_vec,
42 auto polar_quad(quad_polar);
43 auto azimu_quad_vec(quad_azimu_vec);
48 const auto eps = std::numeric_limits<double>::epsilon();
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.");
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()));
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()));
71 const double polar_quad_sum_weights = 2;
72 const auto polar_quad_span = std::pair<double, double>(-1, +1);
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)
79 const auto fac = polar_quad_sum_weights / integral_weights;
80 if (std::abs(fac - 1) > eps)
81 for (
auto& w : polar_quad.weights_)
85 throw std::invalid_argument(
"chi_math::CylindricalAngularQuadrature::Initialize : "
86 "polar quadrature weights sum to zero.");
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);
96 const double azimu_quad_sum_weights = M_PI;
97 const auto azimu_quad_span = std::pair<double, double>(-1, +1);
99 for (
auto& azimu_quad : azimu_quad_vec)
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)
106 const auto fac = azimu_quad_sum_weights / integral_weights;
107 if (std::abs(fac - 1) > eps)
108 for (
auto& w : azimu_quad.weights_)
112 throw std::invalid_argument(
"chi_math::CylindricalAngularQuadrature::Initialize : "
113 "azimuthal quadrature weights sum to zero.");
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);
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.");
129 if (std::abs(azimu_quad.weights_.front()) > eps &&
130 std::abs(azimu_quad.qpoints_.front()[0] - azimu_quad_span.first) > eps)
132 azimu_quad.weights_.emplace(azimu_quad.weights_.begin(), 0);
133 azimu_quad.qpoints_.emplace(azimu_quad.qpoints_.begin(), azimu_quad_span.first);
135 if (std::abs(azimu_quad.weights_.back()) > eps &&
136 std::abs(azimu_quad.qpoints_.back()[0] - azimu_quad_span.second) > eps)
138 azimu_quad.weights_.emplace(azimu_quad.weights_.end(), 0);
139 azimu_quad.qpoints_.emplace(azimu_quad.qpoints_.end(), azimu_quad_span.second);
152 for (
size_t p = 0; p < azimu_quad_vec.size(); ++p)
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);
158 for (
size_t q = 0; q < azimu_quad_vec[p].weights_.size(); ++q)
160 const auto& azimu_quad = azimu_quad_vec[p];
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);
166 const auto weight = pol_wei * azi_wei;
167 const auto abscissa =
172 weights_.emplace_back(weight);
173 abscissae_.emplace_back(abscissa);
174 omegas_.emplace_back(omega);
177 weights_.shrink_to_fit();
178 abscissae_.shrink_to_fit();
179 omegas_.shrink_to_fit();
182 unsigned int ind0 = 0;
183 map_directions_.clear();
184 for (
size_t p = 0; p < azimu_quad_vec.size(); ++p)
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();
196 InitializeParameters();
204 for (
const auto& dir : map_directions_)
206 Chi::log.
Log() <<
"polar level " << dir.first <<
" : ";
207 for (
const auto& q : dir.second)
211 Chi::log.
Log() <<
"curvilinear product quadrature : cylindrical" << std::endl;
212 for (
size_t k = 0; k < weights_.size(); ++k)
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]
220 const auto sum_weights =
221 std::accumulate(weights_.begin(), weights_.end(), 0.0);
222 Chi::log.
Log() <<
"sum(weights) = " << sum_weights << std::endl;
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)
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;
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));
245 for (
size_t q = 1; q < map_directions_[p].size() - 1; ++q)
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;
252 alpha_interface -= w_pq * mu_pq;
254 phi_interface -= w_pq * pi_sum_q_weights;
255 mu_interface[0] = mu_interface[1];
256 mu_interface[1] = std::cos(phi_interface);
258 const auto mu = std::cos(phi_pq);
259 const auto tau = (mu - mu_interface[0]) / (mu_interface[1] - mu_interface[0]);
261 fac_diamond_difference_[k] = tau;
262 fac_streaming_operator_[k] = alpha_interface / (w_pq * tau) + mu_pq;
271 if (m_to_ell_em_map_.empty())
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);
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);
285 throw std::invalid_argument(
"chi_math::CylindricalAngularQuadrature::MakeHarmonicIndices : "
286 "invalid dimension.");
LogStream Log(LOG_LVL level=LOG_0)
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)
void InitializeParameters()
std::vector< double > weights_