SIRIUS 7.5.0
Electronic structure library and applications
radial_functions_index.hpp
Go to the documentation of this file.
1// Copyright (c) 2013-2018 Anton Kozhevnikov, Thomas Schulthess
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without modification, are permitted provided that
5// the following conditions are met:
6//
7// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
8// following disclaimer.
9// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions
10// and the following disclaimer in the documentation and/or other materials provided with the distribution.
11//
12// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
13// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
14// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
15// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
16// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
17// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
18// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
19
20/** \file radial_functions_index.hpp
21 *
22 * \brief Contains definition and implementation of sirius::radial_functions_index class.
23 */
24
25#ifndef __RADIAL_FUNCTIONS_INDEX_HPP__
26#define __RADIAL_FUNCTIONS_INDEX_HPP__
27
28#include "core/rte/rte.hpp"
29#include "core/strong_type.hpp"
30
31namespace sirius {
32
33/// Radial function index.
35/// Augmented wave radial function index.
37/// Local orbital radial function index.
39/// Basis function index.
41/// Augmented wave basis function index.
43/// Local orbital basis function index.
45
46/// Angular momentum quantum number.
47/** This class handles orbital or total angluar momentum quantum number. */
49{
50 private:
51
52 /// Orbital quantum number l.
53 int l_;
54
55 /// Spin quantum number in the units of 1/2.
56 /** This variable can have only three values: -1,0,1. It is used to consruct the total angular
57 * momentum j = l + s/2. In case s = 0 total agular momentum j = l (no level splitting). */
58 int s_{0};
59
60 public:
61
62 /// Constructor.
63 explicit angular_momentum(int l__)
64 : l_(l__)
65 {
66 if (l__ < 0) {
67 RTE_THROW("l can't be negative");
68 }
69 }
70
71 /// Constructor.
72 explicit angular_momentum(int l__, int s__)
73 : l_(l__)
74 , s_(s__)
75 {
76 if (l__ < 0) {
77 RTE_THROW("l can't be negative");
78 }
79 if (s__ != -1 && s__ != 0 && s__ != 1) {
80 RTE_THROW("wrong value of s");
81 }
82 if (l__ == 0 && s__ == -1) {
83 RTE_THROW("incompatible combination of l and s quantum numbers");
84 }
85 }
86
87 /// Get orbital quantum number l.
88 inline auto l() const
89 {
90 return l_;
91 }
92
93 /// Get total angular momentum j = l +/- 1/2
94 inline auto j() const
95 {
96 return l_ + s_ / 2.0;
97 }
98
99 /// Get twice the total angular momentum 2j = 2l +/- 1
100 inline auto two_j() const
101 {
102 return 2 * l_ + s_;
103 }
104
105 /// The size of the subshell for the angular momentum l or j.
106 /** This is the number of m_l values in the range [-l, l] or the number of
107 * m_j values in the range [-j, j] */
108 inline auto subshell_size() const
109 {
110 return two_j() + 1;
111 }
112
113 /// Get spin quantum number s.
114 inline auto s() const
115 {
116 return s_;
117 }
118};
119
120inline bool operator==(angular_momentum lhs__, angular_momentum rhs__)
121{
122 return (lhs__.l() == rhs__.l()) && (lhs__.s() == rhs__.s());
123}
124
125inline bool operator!=(angular_momentum lhs__, angular_momentum rhs__)
126{
127 return !(lhs__ == rhs__);
128}
129
130/// Output angular momentum to a stream.
131inline std::ostream& operator<<(std::ostream& out, angular_momentum am)
132{
133 if (am.s() == 0) {
134 out << "{l: " << am.l() << "}";
135 } else {
136 out << "{l: " << am.l() << ", j: " << am.j() << "}";
137 }
138 return out;
139}
140
141/// Descriptor for the atomic radial functions.
142/** The radial functions \f$ f_{\ell \nu}(r) \f$ are labeled by two indices: orbital quantum number \f$ \ell \f$ and
143 * an order \f$ \nu \f$ for a given \f$ \ell \f$. Radial functions can be any of augmented waves or local orbitals
144 * (in case of FP-LAPW) or beta projectors, atomic or Hubbard wave functions in case of PP-PW.
145 */
147{
148 /// Total angular momentum
150
151 /// Order of a function for a given \f$ \ell \f$.
152 int order;
153
154 /// If this is a local orbital radial function, idxlo is it's index in the list of local orbital descriptors.
156
157 rf_index idxrf{-1};
158
160 rf_lo_index idxlo__ = rf_lo_index(-1))
161 : am{am__}
162 , order{order__}
163 , idxlo{idxlo__}
164 , idxrf{idxrf__}
165 {
166 RTE_ASSERT(order >= 0);
167 }
168};
169
170/// Radial basis function index.
171/** Radial functions can have a repeating orbital quantum number, for example {2s, 2s, 3p, 3p, 4d} configuration
172 * corresponds to {l=0, l=0, l=1, l=1, l=2} radial functions index. */
174{
175 private:
176 /// Store index of the radial function by angular momentum j and order of the function for a given j. */
177 std::vector<std::vector<std::array<int, 2>>> index_by_j_order_;
178
179 /// List of radial function index descriptors.
180 /** This list establishes a mapping \f$ f_{\mu}(r) \leftrightarrow f_{j \nu}(r) \f$ between a
181 * composite index \f$ \mu \f$ of radial functions and
182 * corresponding \f$ j \nu \f$ indices, where \f$ j \f$ is the total orbital quantum number and
183 * \f$ \nu \f$ is the order of radial function for a given \f$ j \f$. */
184 std::vector<radial_function_index_descriptor> vrd_;
185
186 /// Starting index of local orbitals (if added in LAPW case).
187 int offset_lo_{-1};
188 public:
189 /// Default constructor.
191 {
192 }
193
194 /// Add a single radial function with a given angular momentum.
196 {
197 /* current l */
198 auto l = am__.l();
199 /* current s */
200 auto s = am__.s();
201
202 if (s != 0 && l > 0) {
203 RTE_THROW("for l > 0 full-j radial functions are added in pairs");
204 }
205
206 /* make sure that the space is available */
207 if (static_cast<int>(index_by_j_order_.size()) < l + 1) {
208 index_by_j_order_.resize(l + 1);
209 }
210
211 /* size of array is equal to current index */
212 auto size = this->size();
213
214 std::array<int, 2> idx({-1, -1});
215 /* std::max(s, 0) maps s = -1 -> 0, s = 0 -> 0, s = 1 -> 1 */
216 idx[std::max(s, 0)] = size;
217 /* current order */
218 auto o = static_cast<int>(index_by_j_order_[l].size());
219 /* for the reverse mapping */
220 index_by_j_order_[l].push_back(idx);
221 /* add descriptor to the list */
223 }
224
225 /// Add local-orbital type of radial function.
226 /** Local orbitals are only used in FP-LAPW, where the distinction between APW and local orbitals
227 * must be made. For PP-PW this is not used. */
229 {
230 /* mark the start of the local orbital block of radial functions */
231 if (offset_lo_ < 0) {
232 offset_lo_ = this->size();
233 }
234 /* add current index of radial function for reverese mapping from local orbital index */
235 this->add(am__);
236 /* set index of the local orbital */
237 vrd_.back().idxlo = rf_lo_index(this->size() - offset_lo_ - 1);
238 }
239
240 /// Add two component of the spinor radial function.
242 {
243 /* current l */
244 auto l = am1__.l();
245 /* check second l */
246 if (l != am2__.l()) {
247 RTE_THROW("orbital quantum numbers are different");
248 }
249
250 /* current s */
251 auto s1 = am1__.s();
252 /* current s */
253 auto s2 = am2__.s();
254
255 if (s1 == s2) {
256 RTE_THROW("spin quantum numbers are the same");
257 }
258
259 if (s1 * s2 == 0) {
260 RTE_THROW("spin quantum numbers can't be zero in case of full orbital momentum");
261 }
262
263 /* make sure that the space is available */
264 if (static_cast<int>(index_by_j_order_.size()) < l + 1) {
265 index_by_j_order_.resize(l + 1);
266 }
267
268 /* for the total angular momantum, the radial functions are stored in pairs and
269 * have a contiguous index from s=-1 to s=1, for example:
270 * | l = 0 | l = 1 |
271 * +-----------+--------+-------+-------+---
272 * | | s = -1 | n/a | idx=1 |
273 * | order = 0 +--------+-------+-------+---
274 * | ! s = 1 | idx=0 | idx=2 |
275 * +-----------+--------+-------+-------+---
276 * | | s = -1 | n/a | idx=4 |
277 * | order = 1 +--------+-------+-------+---
278 * | ! s = 1 | idx=3 | idx=5 |
279 * +-----------+--------+-------+-------+---
280 * |........................................
281 * |
282 */
283
284 /* current order */
285 auto o = static_cast<int>(index_by_j_order_[l].size());
286
287 auto size = this->size();
288
289 std::array<int, 2> idx({-1, -1});
290 /* std::max(s, 0) maps s = -1 -> 0, s = 0 -> 0, s = 1 -> 1 */
291 idx[std::max(s1, 0)] = size;
292 idx[std::max(s2, 0)] = size + 1;
293
294 vrd_.push_back(radial_function_index_descriptor(am1__, o, rf_index(size)));
295 vrd_.push_back(radial_function_index_descriptor(am2__, o, rf_index(size + 1)));
296
297 index_by_j_order_[l].push_back(idx);
298 }
299
300 /// Return angular momentum of the radial function.
301 inline auto am(rf_index idx__) const
302 {
303 return vrd_[idx__].am;
304 }
305
306 /// Return order of the radial function.
307 inline auto order(rf_index idx__) const
308 {
309 return vrd_[idx__].order;
310 }
311
312 /// Return maximum angular momentum quantum number.
313 inline auto lmax() const
314 {
315 return static_cast<int>(index_by_j_order_.size()) - 1;
316 }
317
318 /// Maximum angular momentum quantum number for local orbitals.
319 inline auto lmax_lo() const
320 {
321 int result{-1};
322 if (offset_lo_ >= 0) {
323 for (int i = offset_lo_; i < this->size(); i++) {
324 result = std::max(result, vrd_[i].am.l());
325 }
326 }
327 return result;
328 }
329
330 /// Number of local orbitals for a given l.
331 inline auto num_lo(int l__) const
332 {
333 int result{-1};
334 if (offset_lo_ >= 0) {
335 for (int i = offset_lo_; i < this->size(); i++) {
336 if (vrd_[i].am.l() == l__) {
337 result++;
338 }
339 }
340 }
341 return result;
342 }
343
344 /// Return maximum order of the radial functions for a given angular momentum.
345 inline auto max_order(int l__) const
346 {
347 return static_cast<int>(index_by_j_order_[l__].size());
348 }
349
350 /// Return maximum order of the radial functions across all angular momentums.
351 inline auto max_order() const
352 {
353 int result{0};
354 for (int l = 0; l <= this->lmax(); l++) {
355 result = std::max(result, this->max_order(l));
356 }
357 return result;
358 }
359
360 /// Return index of radial function.
361 inline auto index_of(angular_momentum am__, int order__) const
362 {
363 /* std::max(s, 0) maps s = -1 -> 0, s = 0 -> 0, s = 1 -> 1 */
364 return rf_index(index_by_j_order_[am__.l()][order__][std::max(am__.s(), 0)]);
365 }
366
367 /// Return index of local orbital.
368 inline auto index_of(rf_lo_index idxlo__) const
369 {
370 RTE_ASSERT(idxlo__ >= 0 && idxlo__ + offset_lo_ < this->size());
371 return rf_index(offset_lo_ + idxlo__);
372 }
373
374 /// Check if the angular momentum is treated as full (j = l +/- 1/2).
375 auto full_j(int l__, int o__) const
376 {
377 /* look at index of l + s */
378 if (index_by_j_order_[l__][o__][1] >= 0) {
379 return true;
380 } else {
381 return false;
382 }
383 }
384
385 /// Return the angular mementum(s) of the subshell with given l and order.
386 auto subshell(int l__, int o__) const
387 {
388 if (full_j(l__, o__)) {
389 if (l__ == 0) {
390 return std::vector<angular_momentum>({angular_momentum(l__, 1)});
391 } else {
392 return std::vector<angular_momentum>({angular_momentum(l__, -1), angular_momentum(l__, 1)});
393 }
394 } else {
395 return std::vector<angular_momentum>({angular_momentum(l__)});
396 }
397 }
398
399 /// Return total number of radial functions.
400 inline int size() const
401 {
402 return static_cast<int>(vrd_.size());
403 }
404
405 /// Return the subshell size for a given l and order.
406 /** In case of orbital quantum number l the size is 2l+1; in case of full
407 * angular momentum j the size is 2*(2l+1) and consists of 2j_{+} + 1 and 2j_{-} + 1
408 * contributions */
409 inline auto subshell_size(int l__, int o__) const
410 {
411 int size{0};
412 for (auto j: subshell(l__, o__)) {
413 size += j.subshell_size();
414 }
415 return size;
416 }
417
418 /// Return radial function descriptor for a given index.
419 inline auto const& operator[](rf_index i__) const
420 {
421 return vrd_[i__];
422 }
423
424 /// Begin iterator of radial function descriptor list.
425 auto begin() const
426 {
427 return vrd_.begin();
428 }
429
430 /// End iterator of radial function descriptor list.
431 auto end() const
432 {
433 return vrd_.end();
434 }
435};
436
437inline auto begin(radial_functions_index const& idx__)
438{
439 return idx__.begin();
440}
441
442inline auto end(radial_functions_index const& idx__)
443{
444 return idx__.end();
445}
446
447}
448
449#endif
Angular momentum quantum number.
int s_
Spin quantum number in the units of 1/2.
auto l() const
Get orbital quantum number l.
angular_momentum(int l__)
Constructor.
auto subshell_size() const
The size of the subshell for the angular momentum l or j.
int l_
Orbital quantum number l.
auto two_j() const
Get twice the total angular momentum 2j = 2l +/- 1.
auto s() const
Get spin quantum number s.
angular_momentum(int l__, int s__)
Constructor.
auto j() const
Get total angular momentum j = l +/- 1/2.
Radial basis function index.
auto const & operator[](rf_index i__) const
Return radial function descriptor for a given index.
void add_lo(angular_momentum am__)
Add local-orbital type of radial function.
std::vector< radial_function_index_descriptor > vrd_
List of radial function index descriptors.
auto num_lo(int l__) const
Number of local orbitals for a given l.
auto full_j(int l__, int o__) const
Check if the angular momentum is treated as full (j = l +/- 1/2).
auto index_of(angular_momentum am__, int order__) const
Return index of radial function.
auto subshell_size(int l__, int o__) const
Return the subshell size for a given l and order.
auto max_order() const
Return maximum order of the radial functions across all angular momentums.
int size() const
Return total number of radial functions.
auto index_of(rf_lo_index idxlo__) const
Return index of local orbital.
auto subshell(int l__, int o__) const
Return the angular mementum(s) of the subshell with given l and order.
auto order(rf_index idx__) const
Return order of the radial function.
auto lmax_lo() const
Maximum angular momentum quantum number for local orbitals.
auto am(rf_index idx__) const
Return angular momentum of the radial function.
int offset_lo_
Starting index of local orbitals (if added in LAPW case).
void add(angular_momentum am1__, angular_momentum am2__)
Add two component of the spinor radial function.
auto end() const
End iterator of radial function descriptor list.
auto lmax() const
Return maximum angular momentum quantum number.
auto begin() const
Begin iterator of radial function descriptor list.
auto max_order(int l__) const
Return maximum order of the radial functions for a given angular momentum.
std::vector< std::vector< std::array< int, 2 > > > index_by_j_order_
Store index of the radial function by angular momentum j and order of the function for a given j....
radial_functions_index()
Default constructor.
void add(angular_momentum am__)
Add a single radial function with a given angular momentum.
Namespace of the SIRIUS library.
Definition: sirius.f90:5
std::ostream & operator<<(std::ostream &out, hbar &&b)
Inject horisontal bar to ostream.
strong_type< int, struct __rf_lo_index_tag > rf_lo_index
Local orbital radial function index.
strong_type< int, struct __rf_index_tag > rf_index
Radial function index.
Eror and warning handling during run-time execution.
A wrapper class to create strong types.
Descriptor for the atomic radial functions.
int order
Order of a function for a given .
angular_momentum am
Total angular momentum.
rf_lo_index idxlo
If this is a local orbital radial function, idxlo is it's index in the list of local orbital descript...