LCOV - code coverage report
Current view: top level - src/ket - KetAtom.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 66 77 85.7 %
Date: 2026-06-19 12:50:25 Functions: 10 11 90.9 %

          Line data    Source code
       1             : // SPDX-FileCopyrightText: 2024 PairInteraction Developers
       2             : // SPDX-License-Identifier: LGPL-3.0-or-later
       3             : 
       4             : #include "pairinteraction/ket/KetAtom.hpp"
       5             : 
       6             : #include "pairinteraction/utils/hash.hpp"
       7             : 
       8             : #include <array>
       9             : #include <cctype>
      10             : #include <cmath>
      11             : #include <fmt/core.h>
      12             : #include <fmt/format.h>
      13             : #include <string>
      14             : #include <string_view>
      15             : #include <vector>
      16             : 
      17             : namespace pairinteraction {
      18             : 
      19             : constexpr std::array<std::string_view, 6> quantum_number_l_labels = {"S", "P", "D", "F", "G", "H"};
      20             : 
      21       40225 : KetAtom::KetAtom(Private /*unused*/, double energy, std::string species,
      22             :                  std::unordered_map<std::string, double> quantum_numbers,
      23             :                  std::unordered_map<std::string, double> quantum_numbers_std, Database &database,
      24       40225 :                  size_t id_in_database)
      25       40225 :     : Ket(energy), species(std::move(species)), quantum_numbers(std::move(quantum_numbers)),
      26       40225 :       quantum_numbers_std(std::move(quantum_numbers_std)), database(database),
      27       40225 :       id_in_database(id_in_database) {}
      28             : 
      29         263 : Database &KetAtom::get_database() const { return database; }
      30             : 
      31       41459 : size_t KetAtom::get_id_in_database() const { return id_in_database; }
      32             : 
      33      170826 : double KetAtom::get_quantum_number(const std::string &name) const {
      34      170826 :     return quantum_numbers.at(name);
      35             : }
      36             : 
      37           5 : double KetAtom::get_quantum_number_std(const std::string &name) const {
      38           5 :     auto it = quantum_numbers_std.find(name);
      39           5 :     return it != quantum_numbers_std.end() ? it->second : 0;
      40             : }
      41             : 
      42        1232 : std::string KetAtom::get_label() const {
      43        1232 :     double s = get_quantum_number("s");
      44        1232 :     double l = get_quantum_number("l");
      45        1232 :     double f = get_quantum_number("f");
      46        1232 :     double m = get_quantum_number("m");
      47        1232 :     bool is_calculated_with_mqdt = get_quantum_number("is_calculated_with_mqdt") != 0;
      48             : 
      49        1232 :     size_t pos = species.find('_');
      50        1232 :     std::string label = (pos != std::string::npos) ? species.substr(0, pos) : species;
      51        1232 :     label[0] = static_cast<char>(std::toupper(label[0]));
      52             : 
      53        1232 :     if (!is_calculated_with_mqdt) {
      54        1191 :         if (s == 0) {
      55          13 :             label += "_singlet";
      56        1178 :         } else if (s == 1) {
      57          16 :             label += "_triplet";
      58        1162 :         } else if (s != 0.5) {
      59           0 :             throw std::runtime_error(
      60           0 :                 "Invalid value for quantum number s in the single-channel description.");
      61             :         }
      62             :     }
      63             : 
      64        1232 :     label += ":";
      65             : 
      66        1232 :     if (is_calculated_with_mqdt) {
      67          82 :         label += fmt::format("S={:.1f},nu={:.1f},L={:.1f},", s, get_quantum_number("nu"), l);
      68          41 :         label += get_quantum_number("is_j_total_momentum") != 0 ? "J=" : "F=";
      69             :     } else {
      70        2382 :         label += fmt::format("{:.0f},", get_quantum_number("n"));
      71        1191 :         if (l == std::rint(l) && l < quantum_number_l_labels.size()) {
      72        1191 :             label += quantum_number_l_labels.at(static_cast<size_t>(l));
      73             :         } else {
      74           0 :             label += fmt::format("{:.0f}", l);
      75             :         }
      76        1191 :         label += "_";
      77             :     }
      78             : 
      79        1232 :     if (f == std::rint(f)) {
      80          28 :         label += fmt::format("{:.0f}", f);
      81        1218 :     } else if (2 * f == std::rint(2 * f)) {
      82        2436 :         label += fmt::format("{:.0f}/2", 2 * f);
      83             :     } else {
      84           0 :         std::abort(); // can't happen because the total momentum is validated to be an integer
      85             :                       // or half-integer
      86             :     }
      87             : 
      88        1232 :     if (m == std::rint(m)) {
      89          28 :         label += fmt::format(",{:.0f}", m);
      90        1218 :     } else if (2 * m == std::rint(2 * m)) {
      91        2436 :         label += fmt::format(",{:.0f}/2", 2 * m);
      92             :     } else {
      93           0 :         std::abort(); // can't happen because the quantum number m is validated to be an integer
      94             :                       // or half-integer
      95             :     }
      96             : 
      97        2464 :     return label;
      98           0 : }
      99             : 
     100             : std::shared_ptr<KetAtom>
     101           0 : KetAtom::get_ket_for_different_quantum_number_m(double new_quantum_number_m) const {
     102           0 :     auto ket = *this;
     103           0 :     ket.quantum_numbers.at("m") = new_quantum_number_m;
     104           0 :     return std::make_shared<KetAtom>(ket);
     105           0 : }
     106             : 
     107       11989 : const std::string &KetAtom::get_species() const { return species; }
     108             : 
     109       39325 : bool KetAtom::operator==(const KetAtom &other) const {
     110       41275 :     return Ket::operator==(other) && species == other.species &&
     111       42418 :         quantum_numbers == other.quantum_numbers &&
     112       40468 :         quantum_numbers_std == other.quantum_numbers_std;
     113             : }
     114             : 
     115           1 : bool KetAtom::operator!=(const KetAtom &other) const { return !(*this == other); }
     116             : 
     117       40304 : size_t KetAtom::hash::operator()(const KetAtom &k) const {
     118       40304 :     size_t seed = typename Ket::hash()(k);
     119       40304 :     utils::hash_combine(seed, k.species);
     120             :     // The quantum numbers are stored in an unordered map, so we combine the per-entry hashes in an
     121             :     // order-independent way (via xor) to obtain a deterministic result.
     122       40304 :     size_t quantum_numbers_hash = 0;
     123      604560 :     for (const auto &[key, value] : k.quantum_numbers) {
     124      564256 :         size_t entry_seed = 0;
     125      564256 :         utils::hash_combine(entry_seed, key);
     126      564256 :         utils::hash_combine(entry_seed, value);
     127      564256 :         quantum_numbers_hash ^= entry_seed;
     128             :     }
     129      282128 :     for (const auto &[key, value] : k.quantum_numbers_std) {
     130      241824 :         size_t entry_seed = 0;
     131      241824 :         utils::hash_combine(entry_seed, key);
     132      241824 :         utils::hash_combine(entry_seed, value);
     133      241824 :         quantum_numbers_hash ^= entry_seed;
     134             :     }
     135       40304 :     utils::hash_combine(seed, quantum_numbers_hash);
     136       40304 :     return seed;
     137             : }
     138             : 
     139             : } // namespace pairinteraction

Generated by: LCOV version 1.16