LCOV - code coverage report
Current view: top level - src/basis - BasisAtomCreator.test.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 133 133 100.0 %
Date: 2025-05-02 21:49:55 Functions: 5 5 100.0 %

          Line data    Source code
       1             : // SPDX-FileCopyrightText: 2024 Pairinteraction Developers
       2             : // SPDX-License-Identifier: LGPL-3.0-or-later
       3             : 
       4             : #include "pairinteraction/basis/BasisAtomCreator.hpp"
       5             : 
       6             : #include "pairinteraction/basis/BasisAtom.hpp"
       7             : #include "pairinteraction/database/Database.hpp"
       8             : #include "pairinteraction/diagonalize/DiagonalizerEigen.hpp"
       9             : #include "pairinteraction/enums/OperatorType.hpp"
      10             : #include "pairinteraction/enums/Parity.hpp"
      11             : #include "pairinteraction/enums/TransformationType.hpp"
      12             : #include "pairinteraction/ket/KetAtom.hpp"
      13             : #include "pairinteraction/ket/KetAtomCreator.hpp"
      14             : #include "pairinteraction/system/SystemAtom.hpp"
      15             : 
      16             : #include <doctest/doctest.h>
      17             : 
      18             : namespace pairinteraction {
      19             : 
      20             : constexpr double VOLT_PER_CM_IN_ATOMIC_UNITS = 1 / 5.14220675112e9;
      21             : 
      22           1 : DOCTEST_TEST_CASE("create a basis for strontium 88") {
      23           1 :     Database &database = Database::get_global_instance();
      24           1 :     auto basis = BasisAtomCreator<double>()
      25           2 :                      .set_species("Sr88_singlet")
      26           1 :                      .restrict_quantum_number_n(60, 60)
      27           1 :                      .restrict_quantum_number_l(0, 2)
      28           1 :                      .create(database);
      29          19 :     for (const auto &ket : *basis) {
      30           9 :         DOCTEST_CHECK(ket->get_species() == "Sr88_singlet");
      31           9 :         DOCTEST_MESSAGE("Ket: ", *ket);
      32           9 :     }
      33           1 : }
      34             : 
      35           1 : DOCTEST_TEST_CASE("create a basis for strontium 87") {
      36           1 :     Database &database = Database::get_global_instance();
      37           1 :     auto basis = BasisAtomCreator<double>()
      38           2 :                      .set_species("Sr87_mqdt")
      39           1 :                      .restrict_quantum_number_nu(59, 61)
      40           1 :                      .restrict_quantum_number_l(0, 0)
      41           1 :                      .create(database);
      42         113 :     for (const auto &ket : *basis) {
      43          56 :         DOCTEST_CHECK(ket->get_species() == "Sr87_mqdt");
      44          56 :         DOCTEST_MESSAGE("Ket: ", *ket);
      45          56 :     }
      46           1 : }
      47             : 
      48           1 : DOCTEST_TEST_CASE("create a basis from kets") {
      49           1 :     Database &database = Database::get_global_instance();
      50           1 :     auto ket1 = KetAtomCreator("Sr88_singlet", 59, 0, 0, 0).create(database);
      51           1 :     auto ket2 = KetAtomCreator("Sr88_singlet", 60, 0, 0, 0).create(database);
      52           1 :     auto ket3 = KetAtomCreator("Sr88_singlet", 61, 0, 0, 0).create(database);
      53             :     auto basis =
      54           2 :         BasisAtomCreator<double>().append_ket(ket1).append_ket(ket2).append_ket(ket3).create(
      55           1 :             database);
      56           7 :     for (const auto &ket : *basis) {
      57           3 :         DOCTEST_CHECK(ket->get_species() == "Sr88_singlet");
      58           3 :         DOCTEST_MESSAGE("Ket: ", *ket);
      59           3 :     }
      60           1 : }
      61             : 
      62           1 : DOCTEST_TEST_CASE("create a basis and sort it according to parity and m") {
      63           1 :     Database &database = Database::get_global_instance();
      64           1 :     auto basis_unsorted = BasisAtomCreator<double>()
      65           2 :                               .set_species("Rb")
      66           1 :                               .restrict_quantum_number_n(60, 60)
      67           1 :                               .restrict_quantum_number_l(0, 3)
      68           1 :                               .restrict_quantum_number_m(-0.5, 0.5)
      69           1 :                               .create(database);
      70             : 
      71             :     // Sort the basis by parity and the m quantum number
      72           1 :     auto sorter = basis_unsorted->get_sorter(
      73           1 :         {TransformationType::SORT_BY_PARITY, TransformationType::SORT_BY_QUANTUM_NUMBER_M});
      74           1 :     auto basis = basis_unsorted->transformed(sorter);
      75             : 
      76             :     // Check if the basis is properly sorted
      77           1 :     auto parity = Parity::ODD;
      78           1 :     auto quantum_number_m = std::numeric_limits<double>::lowest();
      79          15 :     for (size_t i = 0; i < basis->get_number_of_states(); ++i) {
      80          14 :         DOCTEST_MESSAGE("State ", i, ": Parity = ", basis->get_parity(i),
      81             :                         ", M = ", basis->get_quantum_number_m(i));
      82          14 :         DOCTEST_CHECK(basis->get_parity(i) >= parity);
      83          14 :         if (basis->get_parity(i) != parity) {
      84           1 :             parity = basis->get_parity(i);
      85           1 :             quantum_number_m = std::numeric_limits<double>::lowest();
      86             :         }
      87          14 :         DOCTEST_CHECK(basis->get_quantum_number_m(i) >= quantum_number_m);
      88          14 :         quantum_number_m = basis->get_quantum_number_m(i);
      89             :     }
      90             : 
      91             :     // Check that the blocks are correctly determined
      92           1 :     auto blocks = basis->get_indices_of_blocks(
      93           1 :         {TransformationType::SORT_BY_PARITY, TransformationType::SORT_BY_QUANTUM_NUMBER_M});
      94           1 :     std::vector<size_t> expected_start = {0, 4, 8, 11};
      95             : 
      96           1 :     DOCTEST_CHECK(blocks.size() == expected_start.size());
      97             : 
      98           1 :     size_t idx = 0;
      99           5 :     for (const auto &block : blocks) {
     100           4 :         DOCTEST_MESSAGE("Block ", idx, " starts at ", block.start);
     101           4 :         DOCTEST_CHECK(block.start == expected_start[idx]);
     102           4 :         idx++;
     103             :     }
     104             : 
     105             :     // Test implicit conversion of an eigen matrix to a transformator
     106           1 :     size_t dim = basis->get_number_of_states();
     107             :     Eigen::SparseMatrix<double, Eigen::RowMajor> matrix(static_cast<long>(dim),
     108           1 :                                                         static_cast<long>(dim));
     109           1 :     matrix.setIdentity();
     110           1 :     auto transformed = basis->transformed(matrix);
     111           1 :     auto transformation = transformed->get_transformation();
     112           1 :     DOCTEST_CHECK(transformation.transformation_type.back() == TransformationType::ARBITRARY);
     113           1 : }
     114             : 
     115           3 : DOCTEST_TEST_CASE("calculation of matrix elements") {
     116           3 :     auto &database = Database::get_global_instance();
     117             : 
     118           3 :     auto ket_s = KetAtomCreator()
     119           6 :                      .set_species("Rb")
     120           3 :                      .set_quantum_number_n(60)
     121           3 :                      .set_quantum_number_l(0)
     122           3 :                      .set_quantum_number_j(0.5)
     123           3 :                      .set_quantum_number_m(0.5)
     124           3 :                      .create(database);
     125             : 
     126           3 :     auto ket_p = KetAtomCreator()
     127           6 :                      .set_species("Rb")
     128           3 :                      .set_quantum_number_n(60)
     129           3 :                      .set_quantum_number_l(1)
     130           3 :                      .set_quantum_number_j(0.5)
     131           3 :                      .set_quantum_number_m(0.5)
     132           3 :                      .create(database);
     133             : 
     134           3 :     auto basis = BasisAtomCreator<double>()
     135           6 :                      .set_species("Rb")
     136           3 :                      .restrict_quantum_number_n(59, 61)
     137           3 :                      .restrict_quantum_number_l(0, 1)
     138           3 :                      .restrict_quantum_number_m(0.5, 0.5)
     139           3 :                      .create(database);
     140             : 
     141           3 :     SystemAtom<double> system(basis);
     142             : 
     143           3 :     DOCTEST_SUBCASE("calculate energy") {
     144           2 :         auto m1 = basis->get_canonical_state_from_ket(ket_s)->get_matrix_elements(
     145           1 :             ket_s, OperatorType::ENERGY, 0);
     146           1 :         DOCTEST_CHECK(m1.size() == 1);
     147           1 :         double energy1 = m1[0];
     148             : 
     149           1 :         auto m2 = basis->get_matrix_elements(ket_s, OperatorType::ENERGY, 0);
     150           1 :         DOCTEST_CHECK(m2.size() == basis->get_number_of_states());
     151           1 :         double energy2 = m2[static_cast<int>(basis->get_corresponding_state_index(ket_s))];
     152             : 
     153           1 :         double reference = ket_s->get_energy();
     154           1 :         DOCTEST_CHECK(std::abs(energy1 - reference) < 1e-11);
     155           1 :         DOCTEST_CHECK(std::abs(energy2 - reference) < 1e-11);
     156           4 :     }
     157             : 
     158           3 :     DOCTEST_SUBCASE("calculate electric dipole matrix element") {
     159           1 :         auto m = basis->get_matrix_elements(ket_p, OperatorType::ELECTRIC_DIPOLE, 0);
     160           1 :         DOCTEST_CHECK(m.size() == basis->get_number_of_states());
     161           1 :         double dipole = m[static_cast<int>(basis->get_corresponding_state_index(ket_s))];
     162             : 
     163           1 :         DOCTEST_CHECK(std::abs(dipole - 1247.5985544327215848) < 1e-6);
     164           4 :     }
     165             : 
     166           3 :     DOCTEST_SUBCASE("calculate electric dipole matrix element with and without an induced dipole") {
     167             :         {
     168           1 :             auto state = basis->get_corresponding_state(ket_s);
     169             : 
     170           1 :             auto m = state->get_matrix_elements(state, OperatorType::ELECTRIC_DIPOLE, 0);
     171           1 :             DOCTEST_CHECK(m.rows() == 1);
     172           1 :             DOCTEST_CHECK(m.cols() == 1);
     173           1 :             double dipole = m.coeff(0, 0);
     174             : 
     175           1 :             DOCTEST_CHECK(std::abs(dipole - 0) < 1e-6);
     176           1 :         }
     177             : 
     178             :         {
     179           1 :             system.set_electric_field({0, 0, VOLT_PER_CM_IN_ATOMIC_UNITS});
     180           1 :             system.diagonalize(DiagonalizerEigen<double>());
     181           1 :             auto state = system.get_eigenbasis()->get_corresponding_state(ket_s);
     182             : 
     183           1 :             auto m = state->get_matrix_elements(state, OperatorType::ELECTRIC_DIPOLE, 0);
     184           1 :             DOCTEST_CHECK(m.rows() == 1);
     185           1 :             DOCTEST_CHECK(m.cols() == 1);
     186           1 :             double dipole = m.coeff(0, 0);
     187             : 
     188           1 :             DOCTEST_CHECK(std::abs(dipole - 135.01903532588247003) < 1e-6);
     189           1 :         }
     190           3 :     }
     191           3 : }
     192             : 
     193             : } // namespace pairinteraction

Generated by: LCOV version 1.16