77 std::vector<std::vector<Real>>& inverse,
80 inverse.resize(dimension, std::vector<Real>(dimension, 0.0));
81 for (
int row_index = 0; row_index < dimension; row_index++) {
82 inverse[row_index][row_index] = 1.0;
86 for (
int column_index = 0; column_index < dimension; column_index++) {
88 int pivot_row = column_index;
89 Real max_value = std::abs(matrix[column_index][column_index]);
90 for (
int row_index = column_index + 1; row_index < dimension; row_index++) {
91 if (std::abs(matrix[row_index][column_index]) > max_value) {
92 max_value = std::abs(matrix[row_index][column_index]);
93 pivot_row = row_index;
98 if (pivot_row != column_index) {
99 std::swap(matrix[column_index], matrix[pivot_row]);
100 std::swap(inverse[column_index], inverse[pivot_row]);
103 Real pivot_value = matrix[column_index][column_index];
104 if (std::abs(pivot_value) < 1e-15) {
109 for (
int element_index = 0; element_index < dimension; element_index++) {
110 matrix[column_index][element_index] /= pivot_value;
111 inverse[column_index][element_index] /= pivot_value;
115 for (
int row_index = 0; row_index < dimension; row_index++) {
116 if (row_index == column_index)
118 Real factor = matrix[row_index][column_index];
119 for (
int element_index = 0; element_index < dimension; element_index++) {
120 matrix[row_index][element_index] -= factor * matrix[column_index][element_index];
121 inverse[row_index][element_index] -= factor * inverse[column_index][element_index];
135 std::vector<Vector3D> directions(number_of_points);
138 for (
int point_index = 0; point_index < number_of_points; point_index++) {
139 Real theta = std::acos(1.0 - 2.0 * (point_index + 0.5) / number_of_points);
140 Real phi = golden_ratio * point_index;
142 std::sin(theta) * std::cos(phi), std::sin(theta) * std::sin(phi), std::cos(theta));
170 int nlm_projector = (max_degree + 1) * (max_degree + 1);
171 int max_product_degree = 2 * max_degree;
172 int nlm_product = (max_product_degree + 1) * (max_product_degree + 1);
188 constexpr int highest_implemented_harmonic_degree = 4;
189 if (max_product_degree > highest_implemented_harmonic_degree) {
190 throw std::invalid_argument(
191 "generate_gaunt_coefficients: a projector degree of " + std::to_string(max_degree) +
192 " needs harmonics up to degree " + std::to_string(max_product_degree) +
193 ", above the highest implemented (" +
194 std::to_string(highest_implemented_harmonic_degree) +
195 "). The collocation matrix would be singular in the missing rows and the "
196 "table silently wrong, so no table is built. Q3 supports projector "
197 "channels up to d.");
202 ap_row.resize(nlm_projector);
203 for (
auto& ap_element : ap_row)
204 ap_element.resize(nlm_projector, 0.0);
208 for (
int lm1 = 0; lm1 < nlm_projector; lm1++) {
224 int llx = nlm_product;
231 std::vector<std::vector<Real>> ylm_at_points(llx, std::vector<Real>(nlm_product, 0.0));
232 for (
int point_index = 0; point_index < llx; point_index++) {
233 for (
int degree = 0; degree <= max_product_degree; degree++) {
236 ylm_at_points[point_index][lm_index] =
248 std::vector<std::vector<Real>> ylm_matrix(nlm_product, std::vector<Real>(nlm_product, 0.0));
249 for (
int point_index = 0; point_index < llx; point_index++) {
250 for (
int lm_index = 0; lm_index < nlm_product; lm_index++) {
251 ylm_matrix[point_index][lm_index] = ylm_at_points[point_index][lm_index];
259 std::vector<std::vector<Real>> mly;
273 for (
int lm1 = 0; lm1 < nlm_projector; lm1++) {
274 for (
int lm2 = 0; lm2 < nlm_projector; lm2++) {
275 for (
int lp = 0; lp < nlm_product; lp++) {
277 for (
int point_index = 0; point_index < llx; point_index++) {
278 sum += mly[lp][point_index] * ylm_at_points[point_index][lm1] *
279 ylm_at_points[point_index][lm2];
287 for (
int lm1 = 0; lm1 < nlm_projector; lm1++) {
288 for (
int lm2 = 0; lm2 < nlm_projector; lm2++) {
289 for (
int lp = 0; lp < nlm_product; lp++) {