Chi-Tech
angular_quadrature_base.cc
Go to the documentation of this file.
2
4
5#include "chi_runtime.h"
6#include "chi_log.h"
7
8#include <iomanip>
9#include <numeric>
10
11//###################################################################
12/**Optimizes the angular quadrature for polar symmetry by removing
13 * all the direction with downward pointing polar angles.
14 *
15 * \param normalization float. (Optional) The default is a negative number
16 * which does not apply any normalization. If a
17 * positive number is provided, the weights will be
18 * normalized to sum to this number.*/
20 OptimizeForPolarSymmetry(const double normalization)
21{
22 std::vector<chi_math::QuadraturePointPhiTheta> new_abscissae;
23 std::vector<double> new_weights;
24 std::vector<chi_mesh::Vector3> new_omegas;
25
26 const size_t num_dirs = omegas_.size();
27 double weight_sum = 0.0;
28 for (size_t d=0; d<num_dirs; ++d)
29 if (omegas_[d].z > 0.0)
30 {
31 new_abscissae.emplace_back(abscissae_[d]);
32 new_weights.emplace_back(weights_[d]);
33 new_omegas.emplace_back(omegas_[d]);
34 weight_sum += weights_[d];
35 }
36
37 if (normalization > 0.0)
38 for (double& w : new_weights)
39 w *= normalization/weight_sum;
40
41 abscissae_ = std::move(new_abscissae);
42 weights_ = std::move(new_weights);
43 omegas_ = std::move(new_omegas);
44}
45
46//###################################################################
47/**Populates a map of moment m to the Spherical Harmonic indices
48 * required.*/
50 MakeHarmonicIndices(unsigned int scattering_order, int dimension)
51{
52 m_to_ell_em_map_.clear();
53
54 if (dimension == 1)
55 for (int ell=0; ell<=scattering_order; ell++)
56 m_to_ell_em_map_.emplace_back(ell, 0);
57 else if (dimension == 2)
58 for (int ell=0; ell<=scattering_order; ell++)
59 for (int m=-ell; m<=ell; m+=2)
60 m_to_ell_em_map_.emplace_back(ell, m);
61 else if (dimension == 3)
62 for (int ell=0; ell<=scattering_order; ell++)
63 for (int m=-ell; m<=ell; m++)
64 m_to_ell_em_map_.emplace_back(ell, m);
65}
66
67//###################################################################
68/**Computes the discrete to moment operator.*/
70 BuildDiscreteToMomentOperator(unsigned int scattering_order, int dimension)
71{
72 if (d2m_op_built_) return;
73
74 d2m_op_.clear();
75 MakeHarmonicIndices(scattering_order,dimension);
76
77 const size_t num_angles = abscissae_.size();
78 const size_t num_moms = m_to_ell_em_map_.size();
79
80 for (const auto& ell_em : m_to_ell_em_map_)
81 {
82 std::vector<double> cur_mom;
83 cur_mom.reserve(num_angles);
84
85 for (int n=0; n<num_angles; n++)
86 {
87 const auto& cur_angle = abscissae_[n];
88 double value = chi_math::Ylm(ell_em.ell,ell_em.m,
89 cur_angle.phi,
90 cur_angle.theta);
91 double w = weights_[n];
92 cur_mom.push_back(value*w);
93 }
94
95 d2m_op_.push_back(cur_mom);
96 }
97 d2m_op_built_ = true;
98
99 //=================================== Verbose printout
100 std::stringstream outs;
101 outs
102 << "\nQuadrature d2m operator:\n";
103 for (int n=0; n<num_angles; n++)
104 {
105 outs << std::setw(5) << n;
106 for (int m=0; m<num_moms; m++)
107 {
108 outs
109 << std::setw(15) << std::left << std::fixed
110 << std::setprecision(10) << d2m_op_[m][n] << " ";
111 }
112 outs << "\n";
113 }
114
115 Chi::log.Log0Verbose1() << outs.str();
116}
117
118//###################################################################
119/**Computes the moment to discrete operator.*/
121 BuildMomentToDiscreteOperator(unsigned int scattering_order, int dimension)
122{
123 if (m2d_op_built_) return;
124
125 m2d_op_.clear();
126 MakeHarmonicIndices(scattering_order,dimension);
127
128 const size_t num_angles = abscissae_.size();
129 const size_t num_moms = m_to_ell_em_map_.size();
130
131 const auto normalization =
132 std::accumulate(weights_.begin(), weights_.end(), 0.0);
133
134 for (const auto& ell_em : m_to_ell_em_map_)
135 {
136 std::vector<double> cur_mom;
137 cur_mom.reserve(num_angles);
138
139 for (int n=0; n<num_angles; n++)
140 {
141 const auto& cur_angle = abscissae_[n];
142 double value = ((2.0*ell_em.ell+1.0)/normalization)*
143 chi_math::Ylm(ell_em.ell,ell_em.m,
144 cur_angle.phi,
145 cur_angle.theta);
146 cur_mom.push_back(value);
147 }
148
149 m2d_op_.push_back(cur_mom);
150 }//for m
151 m2d_op_built_ = true;
152
153 //=================================== Verbose printout
154 std::stringstream outs;
155
156 outs
157 << "\nQuadrature m2d operator:\n";
158 for (int n=0; n<num_angles; n++)
159 {
160 outs << std::setw(5) << n;
161 for (int m=0; m<num_moms; m++)
162 {
163 outs
164 << std::setw(15) << std::left << std::fixed
165 << std::setprecision(10) << m2d_op_[m][n] << " ";
166 }
167 outs << "\n";
168 }
169
170 Chi::log.Log0Verbose1() << outs.str();
171}
172
173//###################################################################
174/**Returns a reference to the precomputed d2m operator. This will
175 * throw a std::logic_error if the operator has not been built yet.
176 * The operator is accessed as [m][d], where m is the moment index
177 * and d is the direction index.*/
178std::vector<std::vector<double>> const&
180{
181 const std::string fname = __FUNCTION__;
182 if (not d2m_op_built_)
183 throw std::logic_error(fname + ": Called but D2M operator not yet built. "
184 "Make a call to BuildDiscreteToMomentOperator before using this.");
185 return d2m_op_;
186}
187
188//###################################################################
189/**Returns a reference to the precomputed m2d operator. This will
190 * throw a std::logic_error if the operator has not been built yet.
191 * The operator is accessed as [m][d], where m is the moment index
192 * and d is the direction index.*/
193std::vector<std::vector<double>> const&
195{
196 const std::string fname = __FUNCTION__;
197 if (not m2d_op_built_)
198 throw std::logic_error(fname + ": Called but M2D operator not yet built. "
199 "Make a call to BuildMomentToDiscreteOperator before using this.");
200 return m2d_op_;
201}
202
203//###################################################################
204/**Returns a reference to the precomputed harmonic index map. This will
205 * throw a std::logic_error if the map has not been built yet.*/
206const std::vector<chi_math::AngularQuadrature::HarmonicIndices>&
208{
209 const std::string fname = __FUNCTION__;
210 if (not (d2m_op_built_ or m2d_op_built_))
211 throw std::logic_error(fname + ": Called but map not yet built. "
212 "Make a call to either BuildDiscreteToMomentOperator or"
213 "BuildMomentToDiscreteOperator before using this.");
214 return m_to_ell_em_map_;
215}
216
217//###################################################################
218/**Constructor using custom directions.*/
220 AngularQuadratureCustom(std::vector<double> &azimuthal,
221 std::vector<double> &polar,
222 std::vector<double> &in_weights, bool verbose)
223{
224 size_t Na = azimuthal.size();
225 size_t Np = polar.size();
226 size_t Nw = in_weights.size();
227
228 if ((Na-Np != 0) or (Na-Nw != 0))
229 {
231 << "chi_math::AngularQuadrature::InitializeWithCustom: supplied"
232 " vectors need to be of equal length.";
233 Chi::Exit(EXIT_FAILURE);
234 }
235
236 //================================================== Create angle pairs
237 std::stringstream ostr;
238 double weight_sum = 0.0;
239
240 for (unsigned int i=0; i<Na; i++)
241 {
242 const auto abscissa =
243 chi_math::QuadraturePointPhiTheta(azimuthal[i], polar[i]);
244
245 abscissae_.push_back(abscissa);
246
247 const double weight = in_weights[i];
248 weights_.push_back(weight);
249 weight_sum += weight;
250
251 if (verbose)
252 {
253 char buf[200];
254 snprintf(buf,200,"Varphi=%.2f Theta=%.2f Weight=%.3e\n",
255 abscissa.phi*180.0/M_PI,
256 abscissa.theta*180.0/M_PI,
257 weight);
258 ostr << buf;
259 }
260 }
261
262 //================================================== Create omega list
263 for (const auto& qpoint : abscissae_)
264 {
265 chi_mesh::Vector3 new_omega;
266 new_omega.x = sin(qpoint.theta)*cos(qpoint.phi);
267 new_omega.y = sin(qpoint.theta)*sin(qpoint.phi);
268 new_omega.z = cos(qpoint.theta);
269
270 omegas_.push_back(new_omega);
271 }
272
273 if (verbose)
274 {
275 Chi::log.Log()
276 << ostr.str() << "\n"
277 << "Weight sum=" << weight_sum;
278 }
279}
static void Exit(int error_code)
Definition: chi_runtime.cc:342
static chi::ChiLog & log
Definition: chi_runtime.h:81
LogStream LogAllError()
Definition: chi_log.h:239
LogStream Log(LOG_LVL level=LOG_0)
Definition: chi_log.cc:35
LogStream Log0Verbose1()
Definition: chi_log.h:234
AngularQuadratureCustom(std::vector< double > &azimuthal, std::vector< double > &polar, std::vector< double > &in_weights, bool verbose)
std::vector< std::vector< double > > const & GetMomentToDiscreteOperator() const
const std::vector< HarmonicIndices > & GetMomentToHarmonicsIndexMap() const
virtual void MakeHarmonicIndices(unsigned int scattering_order, int dimension)
std::vector< chi_math::QuadraturePointPhiTheta > abscissae_
virtual void OptimizeForPolarSymmetry(double normalization)
std::vector< std::vector< double > > const & GetDiscreteToMomentOperator() const
virtual void BuildDiscreteToMomentOperator(unsigned int scattering_order, int dimension)
virtual void BuildMomentToDiscreteOperator(unsigned int scattering_order, int dimension)
std::vector< chi_mesh::Vector3 > omegas_
double Ylm(unsigned int ell, int m, double varphi, double theta)
double x
Element-0.
double y
Element-1.
double z
Element-2.