Line data Source code
1 : // SPDX-FileCopyrightText: 2024 PairInteraction Developers 2 : // SPDX-License-Identifier: LGPL-3.0-or-later 3 : 4 : #include "pairinteraction/ket/KetPair.hpp" 5 : 6 : #include "pairinteraction/basis/BasisAtom.hpp" 7 : #include "pairinteraction/enums/Parity.hpp" 8 : #include "pairinteraction/ket/KetAtom.hpp" 9 : #include "pairinteraction/utils/hash.hpp" 10 : 11 : #include <limits> 12 : #include <string> 13 : 14 : namespace pairinteraction { 15 : template <typename Scalar> 16 74467 : KetPair<Scalar>::KetPair( 17 : Private /*unused*/, std::initializer_list<size_t> atomic_indices, 18 : std::initializer_list<std::shared_ptr<const BasisAtom<Scalar>>> atomic_bases, real_t energy) 19 : : Ket(energy, calculate_quantum_number_f(atomic_indices, atomic_bases), 20 : calculate_quantum_number_m(atomic_indices, atomic_bases), 21 : calculate_parity(atomic_indices, atomic_bases)), 22 74467 : atomic_indices(atomic_indices), atomic_bases(atomic_bases) { 23 74467 : if (atomic_indices.size() != atomic_bases.size()) { 24 0 : throw std::invalid_argument( 25 : "The number of atomic indices, and atomic bases must be the same."); 26 : } 27 74467 : } 28 : 29 : template <typename Scalar> 30 34 : std::string KetPair<Scalar>::get_label() const { 31 34 : constexpr real_t numerical_precision = 100 * std::numeric_limits<real_t>::epsilon(); 32 : 33 34 : std::string label; 34 34 : std::string separator; 35 102 : for (size_t atom_index = 0; atom_index < atomic_indices.size(); ++atom_index) { 36 68 : const auto &basis = atomic_bases[atom_index]; 37 68 : size_t idx = atomic_indices[atom_index]; 38 : Scalar coefficient = 39 68 : basis->get_coefficients().coeff(idx, basis->get_corresponding_ket_index(idx)); 40 68 : std::string optional_tilde = (std::abs(coefficient - 1.0) > numerical_precision) ? "~" : ""; 41 68 : label += separator + optional_tilde + basis->get_corresponding_ket(idx)->get_label(); 42 68 : separator = "; "; 43 : } 44 68 : return label; 45 34 : } 46 : 47 : template <typename Scalar> 48 : std::shared_ptr<KetPair<Scalar>> 49 0 : KetPair<Scalar>::get_ket_for_different_quantum_number_m(real_t /*new_quantum_number_m*/) const { 50 : // If we use symmetrized states so that the quantum_number_f is the total 51 : // angular quantum number, the quantum_number_m is the magnetic quantum number 52 : // corresponding to the total angular quantum number and we can implement this 53 : // method. 54 0 : throw std::runtime_error("Not implemented."); 55 : } 56 : 57 : template <typename Scalar> 58 1 : std::vector<std::shared_ptr<const BasisAtom<Scalar>>> KetPair<Scalar>::get_atomic_states() const { 59 1 : std::vector<std::shared_ptr<const BasisAtom<Scalar>>> atomic_states; 60 1 : atomic_states.reserve(atomic_indices.size()); 61 3 : for (size_t atom_index = 0; atom_index < atomic_indices.size(); ++atom_index) { 62 2 : atomic_states.push_back(atomic_bases[atom_index]->get_state(atomic_indices[atom_index])); 63 : } 64 1 : return atomic_states; 65 0 : } 66 : 67 : template <typename Scalar> 68 8 : bool KetPair<Scalar>::operator==(const KetPair<Scalar> &other) const { 69 14 : return Ket::operator==(other) && atomic_indices == other.atomic_indices && 70 14 : atomic_bases == other.atomic_bases; 71 : } 72 : 73 : template <typename Scalar> 74 4 : bool KetPair<Scalar>::operator!=(const KetPair<Scalar> &other) const { 75 4 : return !(*this == other); 76 : } 77 : 78 : template <typename Scalar> 79 69649 : size_t KetPair<Scalar>::hash::operator()(const KetPair<Scalar> &k) const { 80 69649 : size_t seed = typename Ket::hash()(k); 81 208947 : for (const auto &index : k.atomic_indices) { 82 139298 : utils::hash_combine(seed, index); 83 : } 84 208947 : for (const auto &basis : k.atomic_bases) { 85 139298 : utils::hash_combine(seed, reinterpret_cast<std::uintptr_t>(basis.get())); 86 : } 87 69649 : return seed; 88 : } 89 : 90 : template <typename Scalar> 91 74467 : typename KetPair<Scalar>::real_t KetPair<Scalar>::calculate_quantum_number_f( 92 : const std::vector<size_t> & /*indices*/, 93 : const std::vector<std::shared_ptr<const BasisAtom<Scalar>>> & /*bases*/) { 94 : // Because this ket state is not symmetrized, the quantum_number_f is not well-defined. 95 74467 : return std::numeric_limits<real_t>::max(); 96 : } 97 : 98 : template <typename Scalar> 99 74467 : typename KetPair<Scalar>::real_t KetPair<Scalar>::calculate_quantum_number_m( 100 : const std::vector<size_t> &indices, 101 : const std::vector<std::shared_ptr<const BasisAtom<Scalar>>> &bases) { 102 223401 : for (const auto &basis : bases) { 103 148934 : if (!basis->has_quantum_number_m()) { 104 0 : return std::numeric_limits<real_t>::max(); 105 : } 106 : } 107 74467 : real_t total_quantum_number_m = 0; 108 223401 : for (size_t i = 0; i < indices.size(); ++i) { 109 148934 : total_quantum_number_m += bases[i]->get_quantum_number_m(indices[i]); 110 : } 111 74467 : return total_quantum_number_m; 112 : } 113 : 114 : template <typename Scalar> 115 74467 : Parity KetPair<Scalar>::calculate_parity( 116 : const std::vector<size_t> & /*indices*/, 117 : const std::vector<std::shared_ptr<const BasisAtom<Scalar>>> & /*bases*/) { 118 : // Because this ket state is not symmetrized, the parity is not well-defined. 119 74467 : return Parity::UNKNOWN; 120 : } 121 : 122 : // Explicit instantiations 123 : template class KetPair<double>; 124 : template class KetPair<std::complex<double>>; 125 : } // namespace pairinteraction