LIBINT 2.9.0
multipole.h
1/*
2 * Copyright (C) 2004-2024 Edward F. Valeev
3 *
4 * This file is part of Libint compiler.
5 *
6 * Libint compiler is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU 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 compiler 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 General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Libint compiler. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#ifndef _libint2_src_bin_libint_multipole_h_
22#define _libint2_src_bin_libint_multipole_h_
23
24#include <global_macros.h>
25#include <hashable.h>
26#include <polyconstr.h>
27#include <smart_ptr.h>
28#include <util_types.h>
29
30#include <array>
31#include <cassert>
32#include <iostream>
33#include <numeric>
34#include <sstream>
35#include <string>
36
37namespace libint2 {
38
41template <unsigned NDIM = 3>
43 : public Hashable<LIBINT2_UINT_LEAST64, ReferToKey> {
44 static_assert(
45 NDIM == 1 || NDIM == 3,
46 "CartesianMultipoleQuanta<NDIM>: only NDIM=1 or NDIM=3 are supported");
47
48 public:
49 CartesianMultipoleQuanta() : valid_(true) {
50 for (auto d = 0u; d != NDIM; ++d) n_[d] = 0u;
51 }
53 : valid_(true) {
54 std::copy(other.n_, other.n_ + NDIM, n_);
55 }
56 CartesianMultipoleQuanta& operator=(const CartesianMultipoleQuanta& other) {
57 valid_ = other.valid_;
58 std::copy(other.n_, other.n_ + NDIM, n_);
59 return *this;
60 }
61 CartesianMultipoleQuanta& operator+=(const CartesianMultipoleQuanta& other) {
62 assert(valid_);
63 for (auto d = 0u; d != NDIM; ++d) n_[d] += other.n_[d];
64 return *this;
65 }
66 CartesianMultipoleQuanta& operator-=(const CartesianMultipoleQuanta& other) {
67 assert(valid_);
68 for (auto d = 0u; d != NDIM; ++d) n_[d] -= other.n_[d];
69 return *this;
70 }
71 ~CartesianMultipoleQuanta() = default;
72
74 unsigned int operator[](unsigned int xyz) const {
75 assert(xyz < NDIM);
76 return n_[xyz];
77 }
79 void inc(unsigned int xyz, unsigned int c = 1u) {
80 assert(xyz < NDIM);
81 assert(valid_);
82 n_[xyz] += c;
83 }
86 void dec(unsigned int xyz, unsigned int c = 1u) {
87 assert(xyz < NDIM);
88 // assert(valid_);
89 if (n_[xyz] >= c)
90 n_[xyz] -= c;
91 else
92 valid_ = false;
93 }
95 unsigned int norm() const { return std::accumulate(n_, n_ + NDIM, 0u); }
97 bool zero() const { return norm() == 0; }
99 bool valid() const { return valid_; }
101 LIBINT2_UINT_LEAST64 key() const {
102 if (NDIM == 3u) {
103 unsigned nxy = n_[1] + n_[2];
104 unsigned l = nxy + n_[0];
105 LIBINT2_UINT_LEAST64 key = nxy * (nxy + 1) / 2 + n_[2];
106 const auto result = key + key_l_offset.at(l);
107 assert(result < max_key);
108 return result;
109 }
110 if (NDIM == 1u) {
111 const auto result = n_[0];
112 assert(result < max_key);
113 return result;
114 }
115 assert(false);
116 }
118 std::string label() const {
119 char result[NDIM + 1];
120 for (auto xyz = 0u; xyz < NDIM; ++xyz) result[xyz] = '0' + n_[xyz];
121 result[NDIM] = '\0';
122 return std::string(result);
123 }
124
125 /* ---------------
126 * key computation
127 * --------------- */
128 constexpr static unsigned max_qn = LIBINT_CARTGAUSS_MAX_AM;
129
130 // nkeys[L] is the number of possible CartesianMultipoleQuanta with \c norm()
131 // == L \note for NDIM=1 nkeys[L] = 1 \note for NDIM=3 nkeys[L] = (L+1)(L+2)/2
132
136 const static unsigned max_key =
137 NDIM == 3 ? (1 + max_qn) * (2 + max_qn) * (3 + max_qn) / 6 : (1 + max_qn);
138
140 void print(std::ostream& os = std::cout) const;
141
142 protected:
144 void invalidate() { valid_ = false; }
145
146 private:
147 unsigned int n_[NDIM];
148 bool valid_; // indicates valid/invalid state
151 static std::array<LIBINT2_UINT_LEAST64, CartesianMultipoleQuanta::max_qn + 1>
152 key_l_offset;
153};
154
155// explicit instantiation declaration, definitions are multipole.cc
156template <>
157std::array<LIBINT2_UINT_LEAST64, CartesianMultipoleQuanta<1u>::max_qn + 1>
158 CartesianMultipoleQuanta<1u>::key_l_offset;
159template <>
160std::array<LIBINT2_UINT_LEAST64, CartesianMultipoleQuanta<3u>::max_qn + 1>
161 CartesianMultipoleQuanta<3u>::key_l_offset;
162
163template <unsigned NDIM>
164CartesianMultipoleQuanta<NDIM> operator-(
165 const CartesianMultipoleQuanta<NDIM>& A,
166 const CartesianMultipoleQuanta<NDIM>& B) {
167 CartesianMultipoleQuanta<NDIM> Diff(A);
168 for (unsigned int xyz = 0; xyz < 3; ++xyz) Diff.dec(xyz, B[xyz]);
169 return Diff;
170}
171
172template <unsigned NDIM>
173bool operator==(const CartesianMultipoleQuanta<NDIM>& A,
174 const CartesianMultipoleQuanta<NDIM>& B) {
175 for (unsigned d = 0; d != NDIM; ++d)
176 if (A[d] != B[d]) return false;
177 return true;
178}
179
181template <unsigned NDIM>
183 return A.valid();
184}
185
187
197 : public Hashable<LIBINT2_UINT_LEAST64, ReferToKey> {
198 public:
199 enum Sign { plus, minus };
200 constexpr static unsigned max_qn = LIBINT_CARTGAUSS_MAX_AM;
201
207 : SphericalMultipoleQuanta(l, m, m < 0 ? Sign::minus : Sign::plus) {}
209 SphericalMultipoleQuanta(int l, int m, Sign sign)
210 : l_(l),
211 m_(std::abs(m)),
212 sign_(sign),
213 valid_(true),
214 phase_(sign == Sign::plus && m < 0 ? -1 : 1) {
215 if (l < 0) valid_ = false;
216 if (m_ > l_) valid_ = false;
217 // N^-_{0,0} = 0
218 if (sign_ == Sign::minus && m_ == 0) valid_ = false;
219 }
220
221 int l() const {
222 assert(valid_);
223 return static_cast<int>(l_);
224 }
225 int m() const {
226 assert(valid_);
227 return static_cast<int>(m_);
228 }
229 Sign sign() const {
230 assert(valid_);
231 return sign_;
232 }
233 bool valid() const { return valid_; }
234 int phase() const {
235 assert(valid_);
236 return phase_;
237 }
239 bool is_precomputed() const {
240 assert(valid_);
241 return sign_ == Sign::plus && l_ == 0 && m_ == 0;
242 }
243 int value() const {
244 assert(is_precomputed());
245 return 1;
246 }
247
248 const static unsigned max_key = (1 + max_qn) * (1 + max_qn);
249
251 LIBINT2_UINT_LEAST64 key() const {
252 assert(valid_);
253 const auto result = l_ * l_ + (sign_ == Sign::plus ? (l_ + m_) : (l_ - m_));
254 assert(result < max_key);
255 return result;
256 }
257
258 private:
259 // N^-_{l,m} is symmetric is stored as N^-_{l,|m|}
260 int l_;
261 int m_;
262 Sign sign_;
263 bool valid_;
264 int phase_;
265};
266
268inline bool exists(const SphericalMultipoleQuanta& A) { return A.valid(); }
269
271inline SphericalMultipoleQuanta::Sign flip(
272 const SphericalMultipoleQuanta::Sign& s) {
273 return s == SphericalMultipoleQuanta::Sign::minus
274 ? SphericalMultipoleQuanta::Sign::plus
275 : SphericalMultipoleQuanta::Sign::minus;
276}
277
278} // namespace libint2
279
280#endif
Represents quantum numbers of cartesian multipole operator.
Definition multipole.h:43
static const unsigned max_key
The range of keys is [0,max_key).
Definition multipole.h:136
unsigned int operator[](unsigned int xyz) const
returns the number of quanta along xyz
Definition multipole.h:74
unsigned int norm() const
Returns the sum of quantum numbers.
Definition multipole.h:95
bool valid() const
Return false if this object is invalid.
Definition multipole.h:99
void dec(unsigned int xyz, unsigned int c=1u)
Subtract c quanta along xyz.
Definition multipole.h:86
void inc(unsigned int xyz, unsigned int c=1u)
Add c quanta along xyz.
Definition multipole.h:79
void print(std::ostream &os=std::cout) const
Print out the content.
bool zero() const
norm() == 0
Definition multipole.h:97
std::string label() const
Return a compact label.
Definition multipole.h:118
void invalidate()
make this object invalid
Definition multipole.h:144
LIBINT2_UINT_LEAST64 key() const
Implements Hashable<unsigned>::key()
Definition multipole.h:101
Objects of Hashable<T> class provide hashing function key() which computes keys of type KeyType.
Definition hashable.h:79
Represents quantum numbers of real spherical multipole operator defined in Eqs.
Definition multipole.h:197
bool is_precomputed() const
Definition multipole.h:239
SphericalMultipoleQuanta(int l, int m)
constructs if , otherwise constructs
Definition multipole.h:206
SphericalMultipoleQuanta()
constructs an object in default (unusable) state
Definition multipole.h:203
SphericalMultipoleQuanta(int l, int m, Sign sign)
constructs
Definition multipole.h:209
LIBINT2_UINT_LEAST64 key() const
Implements Hashable<unsigned>::key()
Definition multipole.h:251
Defaults definitions for various parameters assumed by Libint.
Definition algebra.cc:24
bool exists(const IncableBFSet &A)
Return true if A is valid.
Definition bfset.h:96
SphericalMultipoleQuanta::Sign flip(const SphericalMultipoleQuanta::Sign &s)
plus <-> minus
Definition multipole.h:271