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