LIBINT 2.9.0
solidharmonics.h
1/*
2 * Copyright (C) 2004-2024 Edward F. Valeev
3 *
4 * This file is part of Libint library.
5 *
6 * Libint library is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Libint library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with Libint library. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#ifndef _libint2_include_solidharmonics_h_
22#define _libint2_include_solidharmonics_h_
23
24#include <libint2/util/cxxstd.h>
25#if LIBINT2_CPLUSPLUS_STD < 2011
26#error "The simple Libint API requires C++11 support"
27#endif
28
29#include <algorithm>
30#include <array>
31#include <vector>
32
33// if using from the Libint compiler, need to define real type with which will
34// be computing
35#ifndef LIBINT2_REALTYPE
36#define LIBINT2_REALTYPE double
37#endif
38#include <libint2/cgshell_ordering.h>
39#include <libint2/initialize.h>
40#include <libint2/shell.h>
41
42namespace {
43template <typename Int>
44signed char parity(Int i) {
45 return i % 2 ? -1 : 1;
46}
47} // namespace
48
49namespace libint2 {
50
51namespace solidharmonics {
52
53// to avoid overhead of Eigen::SparseMatrix will roll our own
54
58template <typename Real>
60 public:
61 typedef ::libint2::value_type real_t;
62
63 SolidHarmonicsCoefficients() : l_(-1) {}
64 SolidHarmonicsCoefficients(unsigned char l) : l_(l) {
65 assert(l <= std::numeric_limits<signed char>::max());
66 init();
67 }
68 // intel does not support "move ctor = default"
70 : values_(std::move(other.values_)),
71 row_offset_(std::move(other.row_offset_)),
72 colidx_(std::move(other.colidx_)),
73 l_(other.l_) {}
74
76
77 void init(unsigned char l) {
78 assert(l <= std::numeric_limits<signed char>::max());
79 l_ = l;
80 init();
81 }
82
83 static const SolidHarmonicsCoefficients& instance(unsigned int l) {
84 static std::vector<SolidHarmonicsCoefficients> shg_coefs(
85 SolidHarmonicsCoefficients::CtorHelperIter(0),
86 SolidHarmonicsCoefficients::CtorHelperIter(LIBINT_HARD_MAX_AM + 1));
87 assert(l < shg_coefs.size());
88 return shg_coefs[l];
89 }
90
91 static SolidHarmonicsCoefficients make_instance(unsigned int l) {
93 }
94
96 const Real* row_values(size_t r) const {
97 return &values_[0] + row_offset_[r];
98 }
100 const unsigned int* row_idx(size_t r) const {
101 return &colidx_[0] + row_offset_[r];
102 }
104 unsigned int nnz(size_t r) const {
105 return row_offset_[r + 1] - row_offset_[r];
106 }
107
114 static Real coeff(int l, int m, int lx, int ly, int lz) {
115 using libint2::math::bc_real;
116 using libint2::math::df_Kminus1_real;
117 using libint2::math::fac_real;
118
119 auto abs_m = std::abs(m);
120 if ((lx + ly - abs_m) % 2) return 0.0;
121
122 auto j = (lx + ly - abs_m) / 2;
123 if (j < 0) return 0.0;
124
125 /*----------------------------------------------------------------------------------------
126 Checking whether the cartesian polynomial contributes to the requested
127 component of Ylm
128 ----------------------------------------------------------------------------------------*/
129 auto comp = (m >= 0) ? 1 : -1;
130 /* if (comp != ((abs_m-lx)%2 ? -1 : 1))*/
131 auto i = abs_m - lx;
132 if (comp != parity(abs(i))) return 0.0;
133
134 Real pfac;
135 pfac = sqrt(((fac_real<Real>(2 * lx) * fac_real<Real>(2 * ly) *
136 fac_real<Real>(2 * lz)) /
137 fac_real<Real>(2 * l)) *
138 ((fac_real<Real>(l - abs_m)) / (fac_real<Real>(l))) *
139 (Real(1) / fac_real<Real>(l + abs_m)) *
140 (Real(1) / (fac_real<Real>(lx) * fac_real<Real>(ly) *
141 fac_real<Real>(lz))));
142
143 /* pfac =
144 * sqrt(fac_real<Real>(l-abs_m)/(fac_real<Real>(l)*fac_real<Real>(l)*fac[l+abs_m]));*/
145 pfac /= (1L << l);
146 if (m < 0)
147 pfac *= parity((i - 1) / 2);
148 else
149 pfac *= parity(i / 2);
150
151 auto i_min = j;
152 auto i_max = (l - abs_m) / 2;
153 Real sum = 0;
154 for (auto i = i_min; i <= i_max; i++) {
155 Real pfac1 = bc_real<Real>(l, i) * bc_real<Real>(i, j);
156 pfac1 *= (Real(parity(i) * fac_real<Real>(2 * (l - i))) /
157 fac_real<Real>(l - abs_m - 2 * i));
158 Real sum1 = 0.0;
159 const int k_min = std::max((lx - abs_m) / 2, 0);
160 const int k_max = std::min(j, lx / 2);
161 for (int k = k_min; k <= k_max; k++) {
162 if (lx - 2 * k <= abs_m)
163 sum1 += bc_real<Real>(j, k) * bc_real<Real>(abs_m, lx - 2 * k) *
164 parity(k);
165 }
166 sum += pfac1 * sum1;
167 }
168 sum *= sqrt(df_Kminus1_real<Real>(2 * l) /
169 (df_Kminus1_real<Real>(2 * lx) * df_Kminus1_real<Real>(2 * ly) *
170 df_Kminus1_real<Real>(2 * lz)));
171
172 Real result = (m == 0) ? pfac * sum : M_SQRT2 * pfac * sum;
173 return result;
174 }
175
176 private:
177 std::vector<Real> values_; // elements
178 std::vector<unsigned int>
179 row_offset_; // "pointer" to the beginning of each row
180 std::vector<unsigned int> colidx_; // column indices
181 int l_; // the angular momentum quantum number
182
183 void init() {
184 const unsigned int npure = 2 * l_ + 1;
185 const unsigned int ncart = (l_ + 1) * (l_ + 2) / 2;
186 std::vector<Real> full_coeff(npure * ncart);
187
188 std::vector<int> shg_indices;
190 libint2::SHGShellOrdering_Standard) {
191 for (signed int pure_idx = 0, m = -l_; pure_idx != npure; ++pure_idx, ++m)
192 shg_indices.push_back(m);
194 libint2::SHGShellOrdering_Gaussian) {
195 for (signed int pure_idx = 0, m = 0; pure_idx != npure;
196 ++pure_idx, m = (m > 0 ? -m : 1 - m))
197 shg_indices.push_back(m);
198 } else {
199 throw std::invalid_argument(std::string(
200 "libint2::solid_harmonics_ordering() value not recognized."));
201 }
202
203 for (signed int pure_idx = 0; pure_idx != npure; ++pure_idx) {
204 int m = shg_indices[pure_idx];
205 int cart_idx = 0;
206 int lx, ly, lz;
207 FOR_CART(lx, ly, lz, l_)
208 full_coeff[pure_idx * ncart + cart_idx] = coeff(l_, m, lx, ly, lz);
209 // std::cout << "Solid(" << (int)l_ << "," << (int)m << ") += Cartesian("
210 // << (int)lx << "," << (int)ly << "," << (int)lz << ") * " <<
211 // full_coeff[pure_idx * ncart + cart_idx] << std::endl;
212 ++cart_idx;
213 END_FOR_CART
214 }
215
216 // compress rows
217 // 1) count nonzeroes
218 size_t nnz = 0;
219 for (size_t i = 0; i != full_coeff.size(); ++i)
220 nnz += full_coeff[i] == 0.0 ? 0 : 1;
221 // 2) allocate
222 values_.resize(nnz);
223 colidx_.resize(nnz);
224 row_offset_.resize(npure + 1);
225 // 3) copy
226 {
227 unsigned int pc = 0;
228 unsigned int cnt = 0;
229 for (unsigned int p = 0; p != npure; ++p) {
230 row_offset_[p] = cnt;
231 for (unsigned int c = 0; c != ncart; ++c, ++pc) {
232 if (full_coeff[pc] != 0.0) {
233 values_[cnt] = full_coeff[pc];
234 colidx_[cnt] = c;
235 ++cnt;
236 }
237 }
238 }
239 row_offset_[npure] = cnt;
240 }
241 // done
242 }
243
244 struct CtorHelperIter {
245 using iterator_category = std::input_iterator_tag;
246 using value_type = SolidHarmonicsCoefficients;
247 using difference_type = std::ptrdiff_t;
248 using pointer = value_type*;
249 using reference = value_type&;
250
251 unsigned int l_;
252
253 CtorHelperIter() = default;
254 CtorHelperIter(unsigned int l) : l_(l) {}
255 CtorHelperIter(const CtorHelperIter&) = default;
256 CtorHelperIter& operator=(const CtorHelperIter& rhs) {
257 l_ = rhs.l_;
258 return *this;
259 }
260
261 CtorHelperIter& operator++() {
262 ++l_;
263 return *this;
264 }
265 CtorHelperIter& operator--() {
266 assert(l_ > 0);
267 --l_;
268 return *this;
269 }
270
271 value_type operator*() const { return value_type(l_); }
272 bool operator==(const CtorHelperIter& rhs) const { return l_ == rhs.l_; }
273 bool operator!=(const CtorHelperIter& rhs) const {
274 return not(*this == rhs);
275 }
276 };
277};
278
279// generic transforms
280
281template <typename Real>
282void transform_first(size_t l, size_t n2, const Real* src, Real* tgt) {
283 const auto& coefs = SolidHarmonicsCoefficients<Real>::instance(l);
284
285 const auto n = 2 * l + 1;
286 std::fill(tgt, tgt + n * n2, 0);
287
288 // loop over shg
289 for (size_t s = 0; s != n; ++s) {
290 const auto nc_s = coefs.nnz(s); // # of cartesians contributing to shg s
291 const auto* c_idxs =
292 coefs.row_idx(s); // indices of cartesians contributing to shg s
293 const auto* c_vals = coefs.row_values(
294 s); // coefficients of cartesians contributing to shg s
295
296 const auto tgt_blk_s_offset = s * n2;
297
298 for (size_t ic = 0; ic != nc_s;
299 ++ic) { // loop over contributing cartesians
300 const auto c = c_idxs[ic];
301 const auto s_c_coeff = c_vals[ic];
302
303 auto src_blk_s = src + c * n2;
304 auto tgt_blk_s = tgt + tgt_blk_s_offset;
305
306 // loop over other dims
307 for (size_t i2 = 0; i2 != n2; ++i2, ++src_blk_s, ++tgt_blk_s) {
308 *tgt_blk_s += s_c_coeff * *src_blk_s;
309 }
310 }
311 }
312}
313
316template <typename Real>
317void transform_first2(int l1, int l2, size_t inner_dim, const Real* source_blk,
318 Real* target_blk) {
319 const auto& coefs1 = SolidHarmonicsCoefficients<Real>::instance(l1);
320 const auto& coefs2 = SolidHarmonicsCoefficients<Real>::instance(l2);
321
322 const auto ncart2 = (l2 + 1) * (l2 + 2) / 2;
323 const auto npure1 = 2 * l1 + 1;
324 const auto npure2 = 2 * l2 + 1;
325 const auto ncart2inner = ncart2 * inner_dim;
326 const auto npure2inner = npure2 * inner_dim;
327 std::fill(target_blk, target_blk + npure1 * npure2inner, 0);
328
329 // loop over blocks of inner dimension
330 const size_t inner_blk_size = 8;
331 const size_t nblks = (inner_dim + inner_blk_size - 1) / inner_blk_size;
332 for (size_t blk = 0; blk != nblks; ++blk) {
333 const auto blk_begin = blk * inner_blk_size;
334 const auto blk_end = std::min(blk_begin + inner_blk_size, inner_dim);
335 const auto blk_size = blk_end - blk_begin;
336
337 // loop over first shg
338 for (size_t s1 = 0; s1 != npure1; ++s1) {
339 const auto nc1 =
340 coefs1.nnz(s1); // # of cartesians contributing to shg s1
341 const auto* c1_idxs =
342 coefs1.row_idx(s1); // indices of cartesians contributing to shg s1
343 const auto* c1_vals = coefs1.row_values(
344 s1); // coefficients of cartesians contributing to shg s1
345
346 auto target_blk_s1 = target_blk + s1 * npure2inner + blk_begin;
347
348 // loop over second shg
349 for (size_t s2 = 0; s2 != npure2; ++s2) {
350 const auto nc2 =
351 coefs2.nnz(s2); // # of cartesians contributing to shg s2
352 const auto* c2_idxs =
353 coefs2.row_idx(s2); // indices of cartesians contributing to shg s2
354 const auto* c2_vals = coefs2.row_values(
355 s2); // coefficients of cartesians contributing to shg s2
356 const auto s2inner = s2 * inner_dim;
357 const auto target_blk_s1_blk_begin = target_blk_s1 + s2inner;
358
359 for (size_t ic1 = 0; ic1 != nc1;
360 ++ic1) { // loop over contributing cartesians
361 auto c1 = c1_idxs[ic1];
362 auto s1_c1_coeff = c1_vals[ic1];
363
364 auto source_blk_c1 = source_blk + c1 * ncart2inner + blk_begin;
365
366 for (size_t ic2 = 0; ic2 != nc2;
367 ++ic2) { // loop over contributing cartesians
368 auto c2 = c2_idxs[ic2];
369 auto s2_c2_coeff = c2_vals[ic2];
370 const auto c2inner = c2 * inner_dim;
371
372 const auto coeff = s1_c1_coeff * s2_c2_coeff;
373 const auto source_blk_c1_blk_begin = source_blk_c1 + c2inner;
374 for (auto b = 0; b < blk_size; ++b)
375 target_blk_s1_blk_begin[b] += source_blk_c1_blk_begin[b] * coeff;
376
377 } // cart2
378
379 } // cart1
380
381 } // shg2
382
383 } // shg1
384
385 } // blk
386
387} // transform_first2()
388
389template <typename Real>
390void transform_inner(size_t n1, size_t l, size_t n2, const Real* src,
391 Real* tgt) {
392 const auto& coefs = SolidHarmonicsCoefficients<Real>::instance(l);
393
394 const auto nc = (l + 1) * (l + 2) / 2;
395 const auto n = 2 * l + 1;
396 const auto nc_n2 = nc * n2;
397 const auto n_n2 = n * n2;
398 std::fill(tgt, tgt + n1 * n_n2, 0);
399
400 // loop over shg
401 for (size_t s = 0; s != n; ++s) {
402 const auto nc_s = coefs.nnz(s); // # of cartesians contributing to shg s
403 const auto* c_idxs =
404 coefs.row_idx(s); // indices of cartesians contributing to shg s
405 const auto* c_vals = coefs.row_values(
406 s); // coefficients of cartesians contributing to shg s
407
408 const auto tgt_blk_s_offset = s * n2;
409
410 for (size_t ic = 0; ic != nc_s;
411 ++ic) { // loop over contributing cartesians
412 const auto c = c_idxs[ic];
413 const auto s_c_coeff = c_vals[ic];
414
415 auto src_blk_s = src + c * n2;
416 auto tgt_blk_s = tgt + tgt_blk_s_offset;
417
418 // loop over other dims
419 for (size_t i1 = 0; i1 != n1;
420 ++i1, src_blk_s += nc_n2, tgt_blk_s += n_n2) {
421 for (size_t i2 = 0; i2 != n2; ++i2) {
422 tgt_blk_s[i2] += s_c_coeff * src_blk_s[i2];
423 }
424 }
425 }
426 }
427}
428
431template <typename Real>
432void transform_last(size_t n1, size_t l, const Real* src, Real* tgt) {
433 const auto& coefs = SolidHarmonicsCoefficients<Real>::instance(l);
434
435 const auto nc = (l + 1) * (l + 2) / 2;
436 const auto n = 2 * l + 1;
437 std::fill(tgt, tgt + n1 * n, 0);
438
439 // loop over shg
440 for (size_t s = 0; s != n; ++s) {
441 const auto nc_s = coefs.nnz(s); // # of cartesians contributing to shg s
442 const auto* c_idxs =
443 coefs.row_idx(s); // indices of cartesians contributing to shg s
444 const auto* c_vals = coefs.row_values(
445 s); // coefficients of cartesians contributing to shg s
446
447 const auto tgt_blk_s_offset = s;
448
449 for (size_t ic = 0; ic != nc_s;
450 ++ic) { // loop over contributing cartesians
451 const auto c = c_idxs[ic];
452 const auto s_c_coeff = c_vals[ic];
453
454 auto src_blk_s = src + c;
455 auto tgt_blk_s = tgt + tgt_blk_s_offset;
456
457 // loop over other dims
458 for (size_t i1 = 0; i1 != n1; ++i1, src_blk_s += nc, tgt_blk_s += n) {
459 *tgt_blk_s += s_c_coeff * *src_blk_s;
460 }
461 }
462 }
463}
464
467template <typename Real>
468void tform_last2(size_t n1, int l_row, int l_col, const Real* source_blk,
469 Real* target_blk) {
470 const auto& coefs_row = SolidHarmonicsCoefficients<Real>::instance(l_row);
471 const auto& coefs_col = SolidHarmonicsCoefficients<Real>::instance(l_col);
472
473 const auto ncart_row = (l_row + 1) * (l_row + 2) / 2;
474 const auto ncart_col = (l_col + 1) * (l_col + 2) / 2;
475 const auto ncart = ncart_row * ncart_col;
476 const auto npure_row = 2 * l_row + 1;
477 const auto npure_col = 2 * l_col + 1;
478 const auto npure = npure_row * npure_col;
479 std::fill(target_blk, target_blk + n1 * npure, 0);
480
481 for (size_t i1 = 0; i1 != n1;
482 ++i1, source_blk += ncart, target_blk += npure) {
483 // loop over row shg
484 for (size_t s1 = 0; s1 != npure_row; ++s1) {
485 const auto nc1 =
486 coefs_row.nnz(s1); // # of cartesians contributing to shg s1
487 const auto* c1_idxs = coefs_row.row_idx(
488 s1); // indices of cartesians contributing to shg s1
489 const auto* c1_vals = coefs_row.row_values(
490 s1); // coefficients of cartesians contributing to shg s1
491
492 auto target_blk_s1 = target_blk + s1 * npure_col;
493
494 // loop over col shg
495 for (size_t s2 = 0; s2 != npure_col; ++s2) {
496 const auto nc2 =
497 coefs_col.nnz(s2); // # of cartesians contributing to shg s2
498 const auto* c2_idxs = coefs_col.row_idx(
499 s2); // indices of cartesians contributing to shg s2
500 const auto* c2_vals = coefs_col.row_values(
501 s2); // coefficients of cartesians contributing to shg s2
502
503 for (size_t ic1 = 0; ic1 != nc1;
504 ++ic1) { // loop over contributing cartesians
505 auto c1 = c1_idxs[ic1];
506 auto s1_c1_coeff = c1_vals[ic1];
507
508 auto source_blk_c1 = source_blk + c1 * ncart_col;
509
510 for (size_t ic2 = 0; ic2 != nc2;
511 ++ic2) { // loop over contributing cartesians
512 auto c2 = c2_idxs[ic2];
513 auto s2_c2_coeff = c2_vals[ic2];
514
515 target_blk_s1[s2] += source_blk_c1[c2] * s1_c1_coeff * s2_c2_coeff;
516 } // cart2
517
518 } // cart1
519
520 } // shg2
521
522 } // shg1
523 }
524} // tform()
525
528template <typename Real>
529void tform(int l_row, int l_col, const Real* source_blk, Real* target_blk) {
530 const auto& coefs_row = SolidHarmonicsCoefficients<Real>::instance(l_row);
531 const auto& coefs_col = SolidHarmonicsCoefficients<Real>::instance(l_col);
532
533 const auto ncart_col = (l_col + 1) * (l_col + 2) / 2;
534 const auto npure_row = 2 * l_row + 1;
535 const auto npure_col = 2 * l_col + 1;
536 std::fill(target_blk, target_blk + npure_row * npure_col, 0);
537
538 // loop over row shg
539 for (auto s1 = 0; s1 != npure_row; ++s1) {
540 const auto nc1 =
541 coefs_row.nnz(s1); // # of cartesians contributing to shg s1
542 const auto* c1_idxs =
543 coefs_row.row_idx(s1); // indices of cartesians contributing to shg s1
544 const auto* c1_vals = coefs_row.row_values(
545 s1); // coefficients of cartesians contributing to shg s1
546
547 auto target_blk_s1 = target_blk + s1 * npure_col;
548
549 // loop over col shg
550 for (auto s2 = 0; s2 != npure_col; ++s2) {
551 const auto nc2 =
552 coefs_col.nnz(s2); // # of cartesians contributing to shg s2
553 const auto* c2_idxs = coefs_col.row_idx(
554 s2); // indices of cartesians contributing to shg s2
555 const auto* c2_vals = coefs_col.row_values(
556 s2); // coefficients of cartesians contributing to shg s2
557
558 for (size_t ic1 = 0; ic1 != nc1;
559 ++ic1) { // loop over contributing cartesians
560 auto c1 = c1_idxs[ic1];
561 auto s1_c1_coeff = c1_vals[ic1];
562
563 auto source_blk_c1 = source_blk + c1 * ncart_col;
564
565 for (size_t ic2 = 0; ic2 != nc2;
566 ++ic2) { // loop over contributing cartesians
567 auto c2 = c2_idxs[ic2];
568 auto s2_c2_coeff = c2_vals[ic2];
569
570 target_blk_s1[s2] += source_blk_c1[c2] * s1_c1_coeff * s2_c2_coeff;
571 } // cart2
572
573 } // cart1
574
575 } // shg2
576
577 } // shg1
578} // transform_last2()
579
581template <typename Real>
582void tform_cols(size_t nrow, int l_col, const Real* source_blk,
583 Real* target_blk) {
584 return transform_last(nrow, l_col, source_blk, target_blk);
585 const auto& coefs_col = SolidHarmonicsCoefficients<Real>::instance(l_col);
586
587 const auto ncart_col = (l_col + 1) * (l_col + 2) / 2;
588 const auto npure_col = 2 * l_col + 1;
589
590 // loop over rows
591 for (auto r1 = 0ul; r1 != nrow; ++r1) {
592 auto source_blk_r1 = source_blk + r1 * ncart_col;
593 auto target_blk_r1 = target_blk + r1 * npure_col;
594
595 // loop over col shg
596 for (auto s2 = 0; s2 != npure_col; ++s2) {
597 const auto nc2 =
598 coefs_col.nnz(s2); // # of cartesians contributing to shg s2
599 const auto* c2_idxs = coefs_col.row_idx(
600 s2); // indices of cartesians contributing to shg s2
601 const auto* c2_vals = coefs_col.row_values(
602 s2); // coefficients of cartesians contributing to shg s2
603
604 Real r1_s2_value = 0.0;
605
606 for (size_t ic2 = 0; ic2 != nc2;
607 ++ic2) { // loop over contributing cartesians
608 auto c2 = c2_idxs[ic2];
609 auto s2_c2_coeff = c2_vals[ic2];
610
611 r1_s2_value += source_blk_r1[c2] * s2_c2_coeff;
612
613 } // cart2
614
615 target_blk_r1[s2] = r1_s2_value;
616
617 } // shg1
618
619 } // rows
620
621} // tform_cols()
622
624template <typename Real>
625void tform_rows(int l_row, size_t ncol, const Real* source_blk,
626 Real* target_blk) {
627 return transform_first(l_row, ncol, source_blk, target_blk);
628 const auto& coefs_row = SolidHarmonicsCoefficients<Real>::instance(l_row);
629
630 const auto npure_row = 2 * l_row + 1;
631
632 // loop over row shg
633 for (auto s1 = 0; s1 != npure_row; ++s1) {
634 const auto nc1 =
635 coefs_row.nnz(s1); // # of cartesians contributing to shg s1
636 const auto* c1_idxs =
637 coefs_row.row_idx(s1); // indices of cartesians contributing to shg s1
638 const auto* c1_vals = coefs_row.row_values(
639 s1); // coefficients of cartesians contributing to shg s1
640
641 auto target_blk_s1 = target_blk + s1 * ncol;
642
643 // loop over cols
644 for (decltype(ncol) c2 = 0; c2 != ncol; ++c2) {
645 Real s1_c2_value = 0.0;
646 auto source_blk_c2_offset = source_blk + c2;
647
648 for (std::size_t ic1 = 0; ic1 != nc1;
649 ++ic1) { // loop over contributing cartesians
650 auto c1 = c1_idxs[ic1];
651 auto s1_c1_coeff = c1_vals[ic1];
652
653 s1_c2_value += source_blk_c2_offset[c1 * ncol] * s1_c1_coeff;
654
655 } // cart1
656
657 target_blk_s1[c2] = s1_c2_value;
658
659 } // shg2
660
661 } // shg1
662} // tform_rows();
663
665template <typename Real, typename Shell> // Shell = libint2::Shell::Contraction
666void tform(const Shell& shell_row, const Shell& shell_col,
667 const Real* source_blk, Real* target_blk) {
668 const auto trow = shell_row.pure;
669 const auto tcol = shell_col.pure;
670 if (trow) {
671 if (tcol) {
672 // tform(shell_row.l, shell_col.l, source_blk, target_blk);
673 Real localscratch[500];
674 tform_cols(shell_row.cartesian_size(), shell_col.l, source_blk,
675 &localscratch[0]);
676 tform_rows(shell_row.l, shell_col.size(), &localscratch[0], target_blk);
677 } else
678 tform_rows(shell_row.l, shell_col.cartesian_size(), source_blk,
679 target_blk);
680 } else
681 tform_cols(shell_row.cartesian_size(), shell_col.l, source_blk, target_blk);
682}
683
684} // namespace solidharmonics
685
686} // namespace libint2
687
688#endif /* _libint2_include_solidharmonics_h_ */
Transformation coefficients from unnormalized Cartesian Gaussians (rows) to unit-normalized real Soli...
Definition solidharmonics.h:59
const Real * row_values(size_t r) const
returns ptr to row values
Definition solidharmonics.h:96
const unsigned int * row_idx(size_t r) const
returns ptr to row indices
Definition solidharmonics.h:100
unsigned int nnz(size_t r) const
number of nonzero elements in row r
Definition solidharmonics.h:104
static Real coeff(int l, int m, int lx, int ly, int lz)
Definition solidharmonics.h:114
Defaults definitions for various parameters assumed by Libint.
Definition algebra.cc:24
SHGShellOrdering solid_harmonics_ordering()
Accessor for the SHGShellOrdering.
Definition initialize.h:122