pairinteraction
A Rydberg Interaction Calculator
BasisPairCreator.test.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2024 Pairinteraction Developers
2// SPDX-License-Identifier: LGPL-3.0-or-later
3
5
20
21#include <doctest/doctest.h>
22
23namespace pairinteraction {
24
25constexpr double HARTREE_IN_GHZ = 6579683.920501762;
26constexpr double VOLT_PER_CM_IN_ATOMIC_UNITS = 1 / 5.14220675112e9;
27constexpr double UM_IN_ATOMIC_UNITS = 1 / 5.29177210544e-5;
28
29DOCTEST_TEST_CASE("create a BasisPair") {
30 // Create single-atom system
32 auto basis = BasisAtomCreator<double>()
33 .set_species("Rb")
34 .restrict_quantum_number_n(58, 62)
35 .restrict_quantum_number_l(0, 2)
36 .create(database);
37 SystemAtom<double> system(basis);
39
40 DiagonalizerEigen<double> diagonalizer;
41 system.diagonalize(diagonalizer);
42
43 // Get energy window for a two-atom basis
44 auto ket = KetAtomCreator()
45 .set_species("Rb")
49 .create(database);
50 double min_energy = 2 * ket->get_energy() - 3 / HARTREE_IN_GHZ;
51 double max_energy = 2 * ket->get_energy() + 3 / HARTREE_IN_GHZ;
52
53 // Create two-atom bases
55 .add(system)
56 .add(system)
57 .restrict_energy(min_energy, max_energy)
58 .restrict_quantum_number_m(1, 1)
59 .create();
61 .add(system)
62 .add(system)
63 .restrict_energy(min_energy, max_energy)
64 .restrict_quantum_number_m(1, 1)
65 .create();
66
67 DOCTEST_SUBCASE("check equality of kets") {
68 // Obtain kets from the two-atom bases and check for equality
69 auto ket1a = basis_pair_a->get_kets()[0];
70 auto ket1b = basis_pair_b->get_kets()[0];
71 auto ket2a = basis_pair_a->get_kets()[1];
72 auto ket2b = basis_pair_b->get_kets()[1];
73 DOCTEST_CHECK(*ket1a == *ket1a);
74 DOCTEST_CHECK(*ket2a == *ket2a);
75 DOCTEST_CHECK(*ket1a != *ket2b);
76 DOCTEST_CHECK(*ket2a != *ket1b);
77
78 // Currently, kets from different BasisPair are never equal
79 DOCTEST_CHECK(*ket1a != *ket1b);
80 DOCTEST_CHECK(*ket2a != *ket2b);
81 }
82
83 DOCTEST_SUBCASE("check overlap") {
84 auto overlaps = basis_pair_a->get_overlaps(ket, ket);
85
86 // The total overlap is less than 1 because of the restricted energy window
87 DOCTEST_CHECK(overlaps.sum() == doctest::Approx(0.9107819201));
88 }
89
90 DOCTEST_SUBCASE("get the atomic states constituting a ket of the basis_pair") {
91 auto atomic_states = basis_pair_a->get_kets()[0]->get_atomic_states();
92 DOCTEST_CHECK(atomic_states.size() == 2);
93 DOCTEST_CHECK(atomic_states[0]->get_number_of_states() == 1);
94 DOCTEST_CHECK(atomic_states[0]->get_number_of_kets() == basis->get_number_of_kets());
95 }
96}
97
98DOCTEST_TEST_CASE("get matrix elements in the pair basis") {
99 DiagonalizerEigen<double> diagonalizer;
100
101 // Create single-atom system
103 auto basis = BasisAtomCreator<double>()
104 .set_species("Rb")
105 .restrict_quantum_number_n(58, 62)
106 .restrict_quantum_number_l(0, 2)
107 .create(database);
108 SystemAtom<double> system(basis);
110 system.diagonalize(diagonalizer);
111
112 // Get energy window for a two-atom basis
113 auto ket = KetAtomCreator()
114 .set_species("Rb")
118 .create(database);
119 double min_energy = 2 * ket->get_energy() - 3 / HARTREE_IN_GHZ;
120 double max_energy = 2 * ket->get_energy() + 3 / HARTREE_IN_GHZ;
121
122 // Create two-atom system
123 auto basis_pair_unperturbed = pairinteraction::BasisPairCreator<double>()
124 .add(system)
125 .add(system)
126 .restrict_energy(min_energy, max_energy)
127 .restrict_quantum_number_m(1, 1)
128 .create();
129 auto system_pair = SystemPair<double>(basis_pair_unperturbed)
131 system_pair.diagonalize(diagonalizer);
132
133 auto basis_pair = system_pair.get_eigenbasis();
134
135 DOCTEST_SUBCASE("check dimensions") {
136 // <basis_pair_unperturbed|d0d0|basis_pair_unperturbed>
137 auto matrix_elements_all = basis_pair_unperturbed->get_matrix_elements(
139 0);
140 DOCTEST_CHECK(matrix_elements_all.rows() == basis_pair_unperturbed->get_number_of_states());
141 DOCTEST_CHECK(matrix_elements_all.cols() == basis_pair_unperturbed->get_number_of_states());
142
143 // <ket_pair|d0d0|basis_pair_unperturbed>
144 auto ket_pair = basis_pair_unperturbed->get_kets()[0];
145 auto matrix_elements_ket_pair = basis_pair_unperturbed->get_matrix_elements(
147 DOCTEST_CHECK(matrix_elements_ket_pair.size() ==
148 basis_pair_unperturbed->get_number_of_states());
149
150 {
151 Eigen::VectorX<double> ref = matrix_elements_all.row(0);
152 DOCTEST_CHECK(ref.isApprox(matrix_elements_ket_pair, 1e-11));
153 }
154
155 // <basis x basis|d0d0|basis_pair>
156 auto matrix_elements_product = basis_pair->get_matrix_elements(
158 DOCTEST_CHECK(matrix_elements_product.rows() ==
159 basis->get_number_of_states() * basis->get_number_of_states());
160 DOCTEST_CHECK(matrix_elements_product.cols() == basis_pair->get_number_of_states());
161
162 // <ket,ket|d0d0|basis_pair>
163 auto matrix_elements_ket = basis_pair->get_matrix_elements(
165 DOCTEST_CHECK(matrix_elements_ket.size() == basis_pair->get_number_of_states());
166 }
167
168 DOCTEST_SUBCASE("check matrix elements") {
169 // energy
170 auto hamiltonian = basis_pair->get_matrix_elements(basis_pair, OperatorType::ENERGY,
172 hamiltonian += basis_pair->get_matrix_elements(basis_pair, OperatorType::IDENTITY,
174
175 // interaction with electric field
176 {
177 Eigen::SparseMatrix<double, Eigen::RowMajor> tmp = -basis_pair->get_matrix_elements(
179 tmp += -basis_pair->get_matrix_elements(basis_pair, OperatorType::IDENTITY,
181 hamiltonian += 10 * VOLT_PER_CM_IN_ATOMIC_UNITS * tmp;
182 }
183
184 // dipole-dipole interaction
185 {
186 Eigen::SparseMatrix<double, Eigen::RowMajor> tmp = -2 *
187 basis_pair->get_matrix_elements(basis_pair, OperatorType::ELECTRIC_DIPOLE,
189 tmp += -basis_pair->get_matrix_elements(basis_pair, OperatorType::ELECTRIC_DIPOLE,
191 tmp += -basis_pair->get_matrix_elements(basis_pair, OperatorType::ELECTRIC_DIPOLE,
193 hamiltonian += std::pow(UM_IN_ATOMIC_UNITS, -3) * tmp;
194 }
195
196 // compare to reference
197 const auto &ref = system_pair.get_matrix();
198 DOCTEST_CHECK(ref.isApprox(hamiltonian, 1e-11));
199 }
200}
201
202} // namespace pairinteraction
Builder class for creating BasisAtom objects.
BasisAtomCreator< Scalar > & set_species(const std::string &value)
BasisPairCreator< Scalar > & add(const SystemAtom< Scalar > &system_atom)
static Database & get_global_instance()
Definition: Database.cpp:1068
Builder class for creating KetAtom objects.
KetAtomCreator & set_quantum_number_n(int value)
std::shared_ptr< const KetAtom > create(Database &database) const
KetAtomCreator & set_quantum_number_l(double value)
KetAtomCreator & set_species(const std::string &value)
KetAtomCreator & set_quantum_number_m(double value)
Type & set_electric_field(const std::array< real_t, 3 > &field)
Definition: SystemAtom.cpp:26
Type & set_distance_vector(const std::array< real_t, 3 > &vector)
Definition: SystemPair.cpp:255
System< Derived > & diagonalize(const DiagonalizerInterface< scalar_t > &diagonalizer, std::optional< real_t > min_eigenenergy={}, std::optional< real_t > max_eigenenergy={}, double rtol=1e-6)
Definition: System.cpp:184
std::shared_ptr< const basis_t > get_eigenbasis() const
Definition: System.cpp:85
Matrix< Type, Dynamic, 1 > VectorX
constexpr double UM_IN_ATOMIC_UNITS
constexpr double HARTREE_IN_GHZ
DOCTEST_TEST_CASE("create a basis for strontium 88")
constexpr double VOLT_PER_CM_IN_ATOMIC_UNITS