https://mooseframework.inl.gov
RayTracingAngularQuadrature.C
Go to the documentation of this file.
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 
11 
12 // MOOSE includes
13 #include "MooseUtils.h"
14 
15 // libMesh includes
16 #include "libmesh/dense_vector.h"
17 
19  const unsigned int polar_order,
20  const unsigned int azimuthal_order,
21  const Real mu_min,
22  const Real mu_max)
23  : _dim(dim),
24  _polar_order(polar_order),
25  _azimuthal_order(azimuthal_order),
26  _mu_min(mu_min),
27  _mu_max(mu_max)
28 {
29  if (_polar_order == 0)
30  mooseError("polar_order must be positive in RayTracingAngularQuadrature");
31  if (_azimuthal_order == 0)
32  mooseError("azimuthal_order must be positive in RayTracingAngularQuadrature");
33  if (_mu_min >= _mu_max)
34  mooseError("mu_min must be < mu_max in RayTracingAngularQuadrature");
35  if (_mu_min < -1)
36  mooseError("mu_min must be >= -1 in RayTracingAngularQuadrature");
37  if (_mu_max > 1)
38  mooseError("mu_max must be <= 1 in RayTracingAngularQuadrature");
39  if (dim != 2 && dim != 3)
40  mooseError("RayTracingAngularQuadrature only supports dimensions 2 and 3");
41 
42  // Build the quadrature
43  build();
44 
45  // Default rotation is up
46  rotate(libMesh::Point(0, 0, 1));
47 }
48 
49 void
51 {
52  // Chebyshev quadrature on [0, 2\pi]
53  std::vector<Real> chebyshev_x(_azimuthal_order);
54  std::vector<Real> chebyshev_w(_azimuthal_order);
55  chebyshev(_azimuthal_order, chebyshev_x, chebyshev_w);
56 
57  // Gauss-Legendre quadrature on [0, 1]
58  std::vector<Real> gauss_legendre_x;
59  std::vector<Real> gauss_legendre_w;
60  gaussLegendre(_polar_order, gauss_legendre_x, gauss_legendre_w);
61 
62  _phi.resize(0);
63  _mu.resize(0);
64  _w.resize(0);
65 
66  // Build the product quadrature
67  for (std::size_t i = 0; i < chebyshev_x.size(); ++i)
68  for (std::size_t j = 0; j < gauss_legendre_x.size(); ++j)
69  {
70  // If 2D, throw away the downward mu
71  if (_dim == 2 && gauss_legendre_x[j] < 0.5 - TOLERANCE * TOLERANCE)
72  continue;
73 
74  _phi.push_back(chebyshev_x[i]);
75  _mu.push_back(gauss_legendre_x[j] * (_mu_max - _mu_min) + _mu_min);
76  _polar_sin.push_back(std::sin(std::acos(_mu.back())));
77 
78  const Real weight_factor =
79  (_dim == 2 && !MooseUtils::absoluteFuzzyEqual(gauss_legendre_x[j], 0.5)) ? 2.0 : 1.0;
80  _w.push_back(weight_factor * chebyshev_w[i] * gauss_legendre_w[j]);
81  }
82 }
83 
84 void
86  std::vector<Real> & x,
87  std::vector<Real> & w)
88 {
89  if (order == 0)
90  mooseError("Order must be positive in gaussLegendre()");
91 
92  x.resize(order);
93  w.resize(order);
94  libMesh::DenseMatrix<Real> mat(order, order);
95  libMesh::DenseVector<Real> lambda(order);
96  libMesh::DenseVector<Real> lambdai(order);
97  libMesh::DenseMatrix<Real> vec(order, order);
98 
99  for (unsigned int i = 1; i < order; ++i)
100  {
101  Real ri = i;
102  mat(i, i - 1) = ri / std::sqrt(((2. * ri - 1.) * (2. * ri + 1.)));
103  mat(i - 1, i) = mat(i, i - 1);
104  }
105  mat.evd_right(lambda, lambdai, vec);
106 
107  for (unsigned int i = 0; i < order; ++i)
108  {
109  x[i] = 0.5 * (lambda(i) + 1.0);
110  w[i] = vec(0, i) * vec(0, i);
111  }
112 
113  // Sort based on the points
114  std::vector<std::size_t> sorted_indices(x.size());
115  std::iota(sorted_indices.begin(), sorted_indices.end(), 0);
116  std::stable_sort(sorted_indices.begin(),
117  sorted_indices.end(),
118  [&x](size_t i1, size_t i2) { return x[i1] < x[i2]; });
119  const auto x_copy = x;
120  const auto w_copy = w;
121  for (std::size_t i = 0; i < x.size(); ++i)
122  {
123  x[i] = x_copy[sorted_indices[i]];
124  w[i] = w_copy[sorted_indices[i]];
125  }
126 }
127 
128 void
130 {
131  _current_rotation_direction = rotation_direction;
132 
133  libMesh::DenseMatrix<Real> rotation_matrix;
134  rotationMatrix(rotation_direction.unit(), rotation_matrix);
135 
136  _current_directions.clear();
137  _current_directions.reserve(_phi.size());
138 
139  _current_weights.clear();
140  _current_weights.reserve(_w.size());
141 
142  _current_polar_sins.clear();
143  _current_polar_sins.reserve(_polar_sin.size());
144 
146  libMesh::DenseVector<Real> omega_p(3);
147  Point direction;
148 
149  for (std::size_t q = 0; q < _phi.size(); ++q)
150  {
151  // Get direction as a DenseVector for rotation
152  omega(0) = sqrt(1 - _mu[q] * _mu[q]) * cos(_phi[q]);
153  omega(1) = sqrt(1 - _mu[q] * _mu[q]) * sin(_phi[q]);
154  omega(2) = _mu[q];
155 
156  // Rotate and create the direction
157  rotation_matrix.vector_mult(omega_p, omega);
158  direction(0) = omega_p(0);
159  direction(1) = omega_p(1);
160  direction(2) = omega_p(2);
161 
162  // The index for the new direction in the "current" data
163  // structures. By default - we add a new one. However,
164  // in 2D we may have a duplicate projected direction
165  // so we need to keep track of this in the case
166  // that we are adding information to an already
167  // existant direction
168  std::size_t l = _current_directions.size();
169 
170  // If 2D, project to the xy plane and see if any other
171  // projected directions are a duplicate
172  if (_dim == 2)
173  {
174  direction(2) = 0;
175  direction /= direction.norm();
176 
177  // If we loop through all current directions and find
178  // no duplicates, this will set l back to _current_directions.size()
179  for (l = 0; l < _current_directions.size(); ++l)
180  if (_current_directions[l].absolute_fuzzy_equals(direction))
181  break;
182  }
183 
184  // If l is the current size of _current_directions, it means
185  // that no duplicates were found and that we are inserting
186  // a new direction
187  if (l == _current_directions.size())
188  {
189  _current_directions.push_back(direction);
190  _current_weights.resize(l + 1);
191  _current_polar_sins.resize(l + 1);
192  }
193  else
194  mooseAssert(_dim == 2, "Should only have duplicates in 2D");
195 
196  // Add to weights and sins for this direction
197  _current_weights[l].push_back(_w[q]);
198  _current_polar_sins[l].push_back(_polar_sin[q]);
199  }
200 }
201 
202 const libMesh::Point &
203 RayTracingAngularQuadrature::getDirection(const unsigned int l) const
204 {
205  checkDirection(l);
206  return _current_directions[l];
207 }
208 
209 const std::vector<Real> &
210 RayTracingAngularQuadrature::getWeights(const unsigned int l) const
211 {
212  checkDirection(l);
213  return _current_weights[l];
214 }
215 
216 Real
218 {
219  checkDirection(l);
220  return std::accumulate(_current_weights[l].begin(), _current_weights[l].end(), (Real)0);
221 }
222 
223 const std::vector<Real> &
224 RayTracingAngularQuadrature::getPolarSins(const unsigned int l) const
225 {
226  checkDirection(l);
227  return _current_polar_sins[l];
228 }
229 
230 std::size_t
231 RayTracingAngularQuadrature::numPolar(const unsigned int l) const
232 {
233  checkDirection(l);
234  if (_dim == 3)
235  mooseAssert(_current_weights[l].size() == 1, "Should be 1 polar in 3D");
236  return _current_polar_sins[l].size();
237 }
238 
239 void
241 {
242  if (!hasDirection(l))
243  mooseError("RayTracingAngularQuadrature does not have direction ", l);
244 }
245 
246 void
247 RayTracingAngularQuadrature::chebyshev(const unsigned int order,
248  std::vector<Real> & x,
249  std::vector<Real> & w)
250 {
251  x.resize(order);
252  w.resize(order);
253 
254  for (std::size_t i = 0; i < order; ++i)
255  {
256  x[i] = 2 * (Real)i * M_PI / (Real)order;
257  w[i] = 2 * M_PI / (Real)order;
258  }
259 }
260 
261 void
264 {
265  matrix.resize(3, 3);
266  matrix.zero();
267 
268  // Create a local coordinate system around direction
269  const libMesh::Point tx = orthonormalVector(direction);
270  const libMesh::Point ty = direction.cross(tx);
271 
272  // Create the rotation matrix
273  for (unsigned int j = 0; j < 3; ++j)
274  {
275  matrix(j, 0) = tx(j);
276  matrix(j, 1) = ty(j);
277  matrix(j, 2) = direction(j);
278  }
279 }
280 
283 {
284  if (MooseUtils::absoluteFuzzyLessEqual(v.norm(), 0))
285  ::mooseError("Vector v has norm close to 0 in orthonormalVector()");
286 
288  return libMesh::Point(1, 0, 0);
290  return libMesh::Point(0, 1, 0);
292  return libMesh::Point(0, 0, 1);
293 
294  return libMesh::Point(-v(1), v(0), 0).unit();
295 }
static void gaussLegendre(const unsigned int order, std::vector< Real > &x, std::vector< Real > &w)
Builds Gauss-Legendre quadrature on 0, 1, with weights that sum to 1.
CTSub CT_OPERATOR_BINARY CTMul CTCompareLess CTCompareGreater CTCompareEqual _arg template * sin(_arg) *_arg.template D< dtag >()) CT_SIMPLE_UNARY_FUNCTION(tan
bool absoluteFuzzyEqual(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
void mooseError(Args &&... args)
virtual void zero() override final
unsigned int dim
std::vector< std::vector< Real > > _current_polar_sins
const unsigned int _polar_order
The polar order.
static void chebyshev(const unsigned int order, std::vector< Real > &x, std::vector< Real > &w)
Builds Chebyshev quadrature on [0, 2] with weights that sum to 2.
std::vector< Real > _phi
Quadrature phi.
std::vector< Real > _mu
Quadrature mu.
const libMesh::Point & getDirection(const unsigned int l) const
Get the direction associated with direction l.
const Real _mu_min
The minimum mu.
std::vector< Real > _w
Quadrature combined weights.
TypeVector< Real > unit() const
CTSub CT_OPERATOR_BINARY CTMul CTCompareLess CTCompareGreater CTCompareEqual _arg template cos(_arg) *_arg.template D< dtag >()) CT_SIMPLE_UNARY_FUNCTION(cos
void build()
Build the quadrature.
const std::vector< double > x
std::vector< libMesh::Point > _current_directions
The current quadrature information.
libMesh::Point _current_rotation_direction
The current rotation direction.
void evd_right(DenseVector< T > &lambda_real, DenseVector< T > &lambda_imag, DenseMatrix< T > &VR)
std::vector< std::vector< Real > > _current_weights
std::size_t numPolar(const unsigned int l) const
The number of polar directions associated with the given direction.
const unsigned int _azimuthal_order
The azimuthal order.
TypeVector< typename CompareTypes< Real, T2 >::supertype > cross(const TypeVector< T2 > &v) const
static void rotationMatrix(const libMesh::Point &direction, libMesh::DenseMatrix< Real > &matrix)
Builds the rotation matrix for direction direction into matrix.
const Real _mu_max
The maximum mu.
unsigned int dim() const
Get the quadrature dimension.
bool hasDirection(const unsigned int l) const
Whether or not the angular quadrature has direction l.
Real getTotalWeight(const unsigned int l) const
Gets the total of the weights associated with the direction l.
bool absolute_fuzzy_equals(const T &var1, const T2 &var2, const Real tol=TOLERANCE *TOLERANCE)
void rotate(const libMesh::Point &rotation_direction)
Rotates the quadrature to a given direction.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
static const std::string v
Definition: NS.h:84
const std::vector< Real > & getPolarSins(const unsigned int l) const
Gets the polar sins for the direction l.
CTSub CT_OPERATOR_BINARY CTMul CTCompareLess CTCompareGreater CTCompareEqual _arg template * sqrt(_arg)) *_arg.template D< dtag >()) CT_SIMPLE_UNARY_FUNCTION(tanh
bool absoluteFuzzyLessEqual(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
void resize(const unsigned int new_m, const unsigned int new_n)
static libMesh::Point orthonormalVector(const libMesh::Point &v)
Gets the vector that is orthonormal to v.
void checkDirection(const unsigned int l) const
Throws a MooseError if the angular quadrature does not have direction l.
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
const std::vector< Real > & getWeights(const unsigned int l) const
Get the weights associated with the direction l.
RayTracingAngularQuadrature(const unsigned int dim, const unsigned int polar_order, const unsigned int azimuthal_order, const Real mu_min, const Real mu_max)
Constructor.
const unsigned int _dim
The dimension.
std::vector< Real > _polar_sin
Quadrature polar sin.
void vector_mult(DenseVector< T > &dest, const DenseVector< T > &arg) const