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/SorterType.hpp"
11 : #include "pairinteraction/ket/KetAtom.hpp"
12 : #include "pairinteraction/ket/KetAtomCreator.hpp"
13 : #include "pairinteraction/system/SystemAtom.hpp"
14 :
15 : #include <cmath>
16 : #include <doctest/doctest.h>
17 : #include <stdexcept>
18 : #include <vector>
19 :
20 : namespace pairinteraction {
21 :
22 : constexpr double VOLT_PER_CM_IN_ATOMIC_UNITS = 1 / 5.14220675112e9;
23 :
24 1 : DOCTEST_TEST_CASE("create a basis for strontium 88") {
25 1 : Database &database = Database::get_global_instance();
26 1 : auto basis = BasisAtomCreator<double>(database)
27 2 : .set_species("Sr88_sqdt")
28 2 : .restrict_quantum_number("n", 60, 60)
29 2 : .restrict_quantum_number("l", 0, 2)
30 2 : .restrict_quantum_number("s", 0, 0)
31 1 : .create();
32 19 : for (const auto &ket : *basis) {
33 9 : DOCTEST_CHECK(ket->get_species() == "Sr88_sqdt");
34 9 : }
35 1 : }
36 :
37 1 : DOCTEST_TEST_CASE("create a basis for strontium 87") {
38 1 : Database &database = Database::get_global_instance();
39 1 : auto basis = BasisAtomCreator<double>(database)
40 2 : .set_species("Sr87_mqdt")
41 2 : .restrict_quantum_number("nu", 59, 61)
42 2 : .restrict_quantum_number("l", 0, 0)
43 1 : .create();
44 161 : for (const auto &ket : *basis) {
45 80 : DOCTEST_CHECK(ket->get_species() == "Sr87_mqdt");
46 80 : }
47 1 : }
48 :
49 1 : DOCTEST_TEST_CASE("create a basis from kets") {
50 1 : Database &database = Database::get_global_instance();
51 1 : auto ket1 = KetAtomCreator(database)
52 2 : .set_species("Sr88_sqdt")
53 2 : .set_quantum_number("n", 59)
54 2 : .set_quantum_number("l", 0)
55 2 : .set_quantum_number("j", 0)
56 2 : .set_quantum_number("m", 0)
57 1 : .create();
58 1 : auto ket2 = KetAtomCreator(database)
59 2 : .set_species("Sr88_sqdt")
60 2 : .set_quantum_number("n", 60)
61 2 : .set_quantum_number("l", 0)
62 2 : .set_quantum_number("j", 0)
63 2 : .set_quantum_number("m", 0)
64 1 : .create();
65 1 : auto ket3 = KetAtomCreator(database)
66 2 : .set_species("Sr88_sqdt")
67 2 : .set_quantum_number("n", 61)
68 2 : .set_quantum_number("l", 0)
69 2 : .set_quantum_number("j", 0)
70 2 : .set_quantum_number("m", 0)
71 1 : .create();
72 : auto basis =
73 1 : BasisAtomCreator<double>(database).add_ket(ket1).add_ket(ket2).add_ket(ket3).create();
74 7 : for (const auto &ket : *basis) {
75 3 : DOCTEST_CHECK(ket->get_species() == "Sr88_sqdt");
76 3 : }
77 1 : }
78 :
79 1 : DOCTEST_TEST_CASE("create a basis and sort it according to parity and m") {
80 1 : Database &database = Database::get_global_instance();
81 1 : auto basis_unsorted = BasisAtomCreator<double>(database)
82 2 : .set_species("Rb")
83 2 : .restrict_quantum_number("n", 60, 60)
84 2 : .restrict_quantum_number("l", 0, 3)
85 2 : .restrict_quantum_number("m", -0.5, 0.5)
86 1 : .create();
87 :
88 : // Sort the basis by parity and the m quantum number
89 1 : auto sorter = basis_unsorted->get_sorter({SorterType::PARITY, SorterType::QUANTUM_NUMBER_M});
90 1 : auto basis = basis_unsorted->transformed(sorter);
91 :
92 : // Check if the basis is properly sorted
93 1 : double parity = -1;
94 1 : auto quantum_number_m = std::numeric_limits<double>::lowest();
95 15 : for (size_t i = 0; i < basis->get_number_of_states(); ++i) {
96 14 : DOCTEST_MESSAGE("State ", i, ": Parity = ", basis->get_quantum_number("parity", i),
97 : ", M = ", basis->get_quantum_number("m", i));
98 14 : DOCTEST_CHECK(basis->get_quantum_number("parity", i) >= parity);
99 14 : if (basis->get_quantum_number("parity", i) != parity) {
100 1 : parity = basis->get_quantum_number("parity", i);
101 1 : quantum_number_m = std::numeric_limits<double>::lowest();
102 : }
103 14 : DOCTEST_CHECK(basis->get_quantum_number("m", i) >= quantum_number_m);
104 14 : quantum_number_m = basis->get_quantum_number("m", i);
105 : }
106 :
107 : // Check that the blocks are correctly determined
108 1 : auto blocks = basis->get_indices_of_blocks({SorterType::PARITY, SorterType::QUANTUM_NUMBER_M});
109 1 : std::vector<size_t> expected_start = {0, 4, 8, 11};
110 :
111 1 : DOCTEST_CHECK(blocks.size() == expected_start.size());
112 :
113 1 : size_t idx = 0;
114 5 : for (const auto &block : blocks) {
115 4 : DOCTEST_MESSAGE("Block ", idx, " starts at ", block.start);
116 4 : DOCTEST_CHECK(block.start == expected_start[idx]);
117 4 : idx++;
118 : }
119 :
120 : // Transforming by the identity matrix leaves the coefficients unchanged
121 1 : size_t dim = basis->get_number_of_states();
122 : Eigen::SparseMatrix<double, Eigen::RowMajor> matrix(static_cast<long>(dim),
123 1 : static_cast<long>(dim));
124 1 : matrix.setIdentity();
125 1 : auto transformed = basis->transformed(matrix);
126 1 : DOCTEST_CHECK(transformed->get_coefficients().isApprox(basis->get_coefficients()));
127 1 : }
128 :
129 1 : DOCTEST_TEST_CASE("a basis is canonical if its coefficients are the identity matrix") {
130 1 : auto &database = Database::get_global_instance();
131 :
132 1 : auto basis = BasisAtomCreator<double>(database)
133 2 : .set_species("Rb")
134 2 : .restrict_quantum_number("n", 60, 60)
135 2 : .restrict_quantum_number("l", 0, 1)
136 1 : .create();
137 :
138 1 : DOCTEST_CHECK(basis->is_canonical());
139 :
140 1 : auto dim = static_cast<long>(basis->get_number_of_states());
141 :
142 : // Explicitly stored zeros must not affect the result
143 1 : Eigen::SparseMatrix<double, Eigen::RowMajor> identity_with_zeros(dim, dim);
144 1 : identity_with_zeros.reserve(Eigen::VectorXi::Constant(dim, 2));
145 9 : for (long i = 0; i < dim; ++i) {
146 8 : identity_with_zeros.insert(i, i) = 1;
147 8 : identity_with_zeros.insert(i, (i + 1) % dim) = 0;
148 : }
149 1 : identity_with_zeros.makeCompressed();
150 1 : DOCTEST_CHECK(identity_with_zeros.nonZeros() > dim);
151 1 : DOCTEST_CHECK(basis->copy_with_coefficients(identity_with_zeros)->is_canonical());
152 :
153 : // A basis whose states are a non-trivial superposition of kets is not canonical
154 1 : Eigen::SparseMatrix<double, Eigen::RowMajor> non_identity(dim, dim);
155 1 : non_identity.setIdentity();
156 1 : non_identity.coeffRef(0, 0) = 0.5;
157 1 : DOCTEST_CHECK_FALSE(basis->copy_with_coefficients(non_identity)->is_canonical());
158 :
159 : // Sorting the basis makes it non-canonical
160 1 : auto sorted = basis->transformed(basis->get_sorter({SorterType::PARITY}));
161 1 : DOCTEST_CHECK_FALSE(sorted->is_canonical());
162 1 : }
163 :
164 1 : DOCTEST_TEST_CASE("blocks can only be obtained if the states are sorted") {
165 1 : Database &database = Database::get_global_instance();
166 1 : auto basis_unsorted = BasisAtomCreator<double>(database)
167 2 : .set_species("Rb")
168 2 : .restrict_quantum_number("n", 60, 60)
169 2 : .restrict_quantum_number("l", 0, 3)
170 2 : .restrict_quantum_number("m", -0.5, 0.5)
171 1 : .create();
172 :
173 : // In the unsorted basis, states that share the same labels are scattered over the basis. They
174 : // would end up in several blocks and couplings between them would be lost.
175 3 : DOCTEST_CHECK_THROWS_AS(
176 : basis_unsorted->get_indices_of_blocks({SorterType::PARITY, SorterType::QUANTUM_NUMBER_M}),
177 : std::invalid_argument);
178 :
179 1 : auto basis = basis_unsorted->transformed(
180 1 : basis_unsorted->get_sorter({SorterType::PARITY, SorterType::QUANTUM_NUMBER_M}));
181 :
182 : // After sorting, the states of equal parity and m are contiguous ...
183 1 : DOCTEST_CHECK_NOTHROW(
184 : basis->get_indices_of_blocks({SorterType::PARITY, SorterType::QUANTUM_NUMBER_M}));
185 :
186 : // ... and so are the states of equal parity because the parity is the primary criterion
187 1 : DOCTEST_CHECK_NOTHROW(basis->get_indices_of_blocks({SorterType::PARITY}));
188 :
189 : // The states of equal m are not contiguous, however, because m only breaks ties between states
190 : // of equal parity
191 3 : DOCTEST_CHECK_THROWS_AS(basis->get_indices_of_blocks({SorterType::QUANTUM_NUMBER_M}),
192 : std::invalid_argument);
193 :
194 : // If the states are not labeled at all, no blocks can be obtained either
195 1 : auto dim = static_cast<long>(basis->get_number_of_states());
196 1 : Eigen::SparseMatrix<double, Eigen::RowMajor> identity(dim, dim);
197 1 : identity.setIdentity();
198 1 : auto unlabeled = basis->copy_with_coefficients(identity);
199 3 : DOCTEST_CHECK_THROWS_AS(unlabeled->get_indices_of_blocks({SorterType::PARITY}),
200 : std::invalid_argument);
201 3 : DOCTEST_CHECK_THROWS_AS(unlabeled->get_indices_of_blocks({SorterType::QUANTUM_NUMBER_F}),
202 : std::invalid_argument);
203 1 : }
204 :
205 3 : DOCTEST_TEST_CASE("calculation of matrix elements") {
206 3 : auto &database = Database::get_global_instance();
207 :
208 3 : auto ket_s = KetAtomCreator(database)
209 6 : .set_species("Rb")
210 6 : .set_quantum_number("n", 60)
211 6 : .set_quantum_number("l", 0)
212 6 : .set_quantum_number("j", 0.5)
213 6 : .set_quantum_number("m", 0.5)
214 3 : .create();
215 :
216 3 : auto ket_p = KetAtomCreator(database)
217 6 : .set_species("Rb")
218 6 : .set_quantum_number("n", 60)
219 6 : .set_quantum_number("l", 1)
220 6 : .set_quantum_number("j", 0.5)
221 6 : .set_quantum_number("m", 0.5)
222 3 : .create();
223 :
224 3 : auto basis = BasisAtomCreator<double>(database)
225 6 : .set_species("Rb")
226 6 : .restrict_quantum_number("n", 59, 61)
227 6 : .restrict_quantum_number("l", 0, 1)
228 6 : .restrict_quantum_number("m", 0.5, 0.5)
229 3 : .create();
230 :
231 3 : SystemAtom<double> system(basis);
232 :
233 4 : auto get_corresponding_state_index = [&database](const auto &b,
234 4 : const std::shared_ptr<const KetAtom> &ket) {
235 4 : auto basis_ket = BasisAtomCreator<double>(database).add_ket(ket).create();
236 4 : Eigen::MatrixXd overlaps =
237 8 : Eigen::MatrixXd(b->get_matrix_elements(basis_ket, OperatorType::IDENTITY, 0))
238 : .cwiseAbs();
239 4 : Eigen::Index idx = 0;
240 4 : overlaps.row(0).maxCoeff(&idx);
241 4 : return idx;
242 4 : };
243 :
244 3 : DOCTEST_SUBCASE("calculate energy") {
245 1 : auto basis_ket_s = BasisAtomCreator<double>(database).add_ket(ket_s).create();
246 :
247 1 : auto m1 = basis_ket_s->get_matrix_elements(basis_ket_s, OperatorType::ENERGY, 0);
248 1 : DOCTEST_CHECK(m1.rows() == 1);
249 1 : DOCTEST_CHECK(m1.cols() == 1);
250 1 : double energy1 = m1.coeff(0, 0);
251 :
252 1 : auto m2 = basis->get_matrix_elements(basis_ket_s, OperatorType::ENERGY, 0);
253 1 : DOCTEST_CHECK(m2.rows() == 1);
254 1 : DOCTEST_CHECK(m2.cols() == basis->get_number_of_states());
255 1 : double energy2 = m2.coeff(0, static_cast<int>(get_corresponding_state_index(basis, ket_s)));
256 :
257 1 : double reference = ket_s->get_energy();
258 1 : DOCTEST_CHECK(std::abs(energy1 - reference) < 1e-11);
259 1 : DOCTEST_CHECK(std::abs(energy2 - reference) < 1e-11);
260 4 : }
261 :
262 3 : DOCTEST_SUBCASE("calculate electric dipole matrix element") {
263 1 : auto basis_ket_p = BasisAtomCreator<double>(database).add_ket(ket_p).create();
264 :
265 1 : auto m = basis->get_matrix_elements(basis_ket_p, OperatorType::ELECTRIC_DIPOLE, 0);
266 1 : DOCTEST_CHECK(m.rows() == 1);
267 1 : DOCTEST_CHECK(m.cols() == basis->get_number_of_states());
268 1 : double dipole = m.coeff(0, static_cast<int>(get_corresponding_state_index(basis, ket_s)));
269 :
270 1 : DOCTEST_CHECK(std::abs(dipole - 1247.60438) < 1e-3);
271 4 : }
272 :
273 3 : DOCTEST_SUBCASE("calculate electric dipole matrix element with and without an induced dipole") {
274 : {
275 1 : auto state = basis->get_state(get_corresponding_state_index(basis, ket_s));
276 :
277 1 : auto m = state->get_matrix_elements(state, OperatorType::ELECTRIC_DIPOLE, 0);
278 1 : DOCTEST_CHECK(m.rows() == 1);
279 1 : DOCTEST_CHECK(m.cols() == 1);
280 1 : double dipole = m.coeff(0, 0);
281 :
282 1 : DOCTEST_CHECK(std::abs(dipole - 0) < 1e-6);
283 1 : }
284 :
285 : {
286 1 : system.set_electric_field({0, 0, VOLT_PER_CM_IN_ATOMIC_UNITS});
287 1 : system.diagonalize(DiagonalizerEigen<double>());
288 1 : auto eigenbasis = system.get_eigenbasis();
289 1 : auto state = eigenbasis->get_state(get_corresponding_state_index(eigenbasis, ket_s));
290 :
291 1 : auto m = state->get_matrix_elements(state, OperatorType::ELECTRIC_DIPOLE, 0);
292 1 : DOCTEST_CHECK(m.rows() == 1);
293 1 : DOCTEST_CHECK(m.cols() == 1);
294 1 : double dipole = m.coeff(0, 0);
295 :
296 1 : DOCTEST_CHECK(std::abs(dipole - 135.04130) < 1e-3);
297 1 : }
298 3 : }
299 3 : }
300 :
301 1 : DOCTEST_TEST_CASE("conserved quantum numbers are detected despite non-normalized coefficients") {
302 : // The diagonalizers prune small entries of the eigenvectors so that the columns of the
303 : // resulting transformation matrix are normalized only up to a defect of the order of rtol^2.
304 : // The detection of conserved quantum numbers must not be spoiled by this defect. Otherwise,
305 : // the detection would fail for a large rtol or a low floating point precision.
306 1 : Database &database = Database::get_global_instance();
307 1 : auto unsorted_basis = BasisAtomCreator<double>(database)
308 2 : .set_species("Rb")
309 2 : .restrict_quantum_number("n", 60, 60)
310 2 : .restrict_quantum_number("l", 0, 3)
311 1 : .create();
312 : auto basis =
313 1 : unsorted_basis->transformed(unsorted_basis->get_sorter({SorterType::QUANTUM_NUMBER_M}));
314 1 : DOCTEST_REQUIRE(basis->has_quantum_number("m"));
315 :
316 1 : auto dim = static_cast<Eigen::Index>(basis->get_number_of_states());
317 1 : constexpr double defect = 1e-2; // the squared norm of each column is 1 - defect
318 1 : const double scale = std::sqrt(1 - defect);
319 1 : const double sqrt_half = std::sqrt(0.5);
320 :
321 : // Superimpose pairs of states that have the same m, mimicking eigenvectors that are confined
322 : // to a block of constant m, and scale the columns so that they are not exactly normalized
323 1 : std::vector<Eigen::Triplet<double>> triplets;
324 21 : for (Eigen::Index i = 0; i < dim;) {
325 20 : auto idx = static_cast<size_t>(i);
326 39 : if (i + 1 < dim &&
327 39 : basis->get_quantum_number("m", idx) == basis->get_quantum_number("m", idx + 1)) {
328 12 : triplets.emplace_back(i, i, scale * sqrt_half);
329 12 : triplets.emplace_back(i + 1, i, scale * sqrt_half);
330 12 : triplets.emplace_back(i, i + 1, scale * sqrt_half);
331 12 : triplets.emplace_back(i + 1, i + 1, -scale * sqrt_half);
332 12 : i += 2;
333 : } else {
334 8 : triplets.emplace_back(i, i, scale);
335 8 : i += 1;
336 : }
337 : }
338 1 : Eigen::SparseMatrix<double, Eigen::RowMajor> transformation(dim, dim);
339 1 : transformation.setFromTriplets(triplets.begin(), triplets.end());
340 :
341 : // Because the transformation does not mix different m, m is still well-defined
342 1 : auto transformed = basis->transformed(transformation);
343 1 : DOCTEST_CHECK(transformed->has_quantum_number("m"));
344 33 : for (size_t i = 0; i < transformed->get_number_of_states(); ++i) {
345 32 : DOCTEST_CHECK(transformed->get_quantum_number("m", i) == basis->get_quantum_number("m", i));
346 : }
347 :
348 : // If, in contrast, states of different m are superimposed, m is not well-defined anymore
349 1 : Eigen::Index other = 0;
350 4 : while (other < dim &&
351 4 : basis->get_quantum_number("m", 0) ==
352 4 : basis->get_quantum_number("m", static_cast<size_t>(other))) {
353 1 : ++other;
354 : }
355 1 : DOCTEST_REQUIRE(other < dim);
356 1 : triplets.clear();
357 33 : for (Eigen::Index i = 0; i < dim; ++i) {
358 32 : if (i != 0 && i != other) {
359 30 : triplets.emplace_back(i, i, scale);
360 : }
361 : }
362 1 : triplets.emplace_back(0, 0, scale * sqrt_half);
363 1 : triplets.emplace_back(other, 0, scale * sqrt_half);
364 1 : triplets.emplace_back(0, other, scale * sqrt_half);
365 1 : triplets.emplace_back(other, other, -scale * sqrt_half);
366 1 : Eigen::SparseMatrix<double, Eigen::RowMajor> mixing_transformation(dim, dim);
367 1 : mixing_transformation.setFromTriplets(triplets.begin(), triplets.end());
368 :
369 1 : auto mixed = basis->transformed(mixing_transformation);
370 1 : DOCTEST_CHECK_FALSE(mixed->has_quantum_number("m"));
371 3 : DOCTEST_CHECK_THROWS_AS(mixed->get_quantum_number("m", 0), std::invalid_argument);
372 :
373 : // An explicitly stored zero that couples a state to a state without a well-defined m must not
374 : // spoil the m of the state
375 1 : Eigen::Index target = 0;
376 3 : while (target == 0 || target == other) {
377 2 : ++target;
378 : }
379 1 : DOCTEST_REQUIRE(target < dim);
380 1 : triplets.clear();
381 33 : for (Eigen::Index i = 0; i < dim; ++i) {
382 32 : triplets.emplace_back(i, i, 1);
383 : }
384 1 : triplets.emplace_back(0, target, 0);
385 1 : Eigen::SparseMatrix<double, Eigen::RowMajor> transformation_with_zero(dim, dim);
386 1 : transformation_with_zero.setFromTriplets(triplets.begin(), triplets.end());
387 1 : DOCTEST_REQUIRE(transformation_with_zero.nonZeros() == dim + 1);
388 :
389 1 : auto transformed_with_zero = mixed->transformed(transformation_with_zero);
390 1 : DOCTEST_CHECK(transformed_with_zero->get_quantum_number("m", static_cast<size_t>(target)) ==
391 : basis->get_quantum_number("m", static_cast<size_t>(target)));
392 1 : }
393 :
394 1 : DOCTEST_TEST_CASE("energies of the states of a basis") {
395 1 : Database &database = Database::get_global_instance();
396 1 : auto basis = BasisAtomCreator<double>(database)
397 2 : .set_species("Rb")
398 2 : .restrict_quantum_number("n", 60, 60)
399 2 : .restrict_quantum_number("l", 0, 1)
400 1 : .create();
401 1 : auto dim = static_cast<Eigen::Index>(basis->get_number_of_states());
402 :
403 : // The states of a canonical basis have the energies of the kets, by which they are sorted
404 1 : DOCTEST_CHECK(basis->has_energy());
405 1 : DOCTEST_CHECK(basis->is_sorted_by_energy());
406 9 : for (size_t i = 0; i < basis->get_number_of_states(); ++i) {
407 8 : DOCTEST_CHECK(basis->get_energy(i) == basis->get_ket(i)->get_energy());
408 8 : DOCTEST_CHECK(basis->get_state(i)->get_energy(0) == basis->get_ket(i)->get_energy());
409 : }
410 :
411 : // Sorting permutes the energies along with the states
412 1 : auto sorter = basis->get_sorter({SorterType::QUANTUM_NUMBER_M});
413 1 : auto sorted = basis->transformed(sorter);
414 1 : DOCTEST_CHECK(sorted->has_energy());
415 1 : DOCTEST_CHECK_FALSE(sorted->is_sorted_by_energy());
416 9 : for (Eigen::Index i = 0; i < dim; ++i) {
417 8 : DOCTEST_CHECK(sorted->get_energy(static_cast<size_t>(i)) ==
418 : basis->get_energy(static_cast<size_t>(sorter.indices()[i])));
419 : }
420 :
421 : // In general, transformed states do not have well-defined energies
422 1 : Eigen::SparseMatrix<double, Eigen::RowMajor> identity(dim, dim);
423 1 : identity.setIdentity();
424 1 : auto transformed = basis->transformed(identity);
425 1 : DOCTEST_CHECK_FALSE(transformed->has_energy());
426 1 : DOCTEST_CHECK_FALSE(transformed->is_sorted_by_energy());
427 1 : DOCTEST_CHECK_THROWS_AS(transformed->get_energy(0), std::invalid_argument);
428 :
429 : // Unless the energies of the transformed states are explicitly specified
430 1 : std::vector<double> energies(basis->get_number_of_states());
431 9 : for (size_t i = 0; i < energies.size(); ++i) {
432 8 : energies[i] = basis->get_energy(i);
433 : }
434 1 : auto transformed_with_energies = basis->transformed(identity, energies);
435 1 : DOCTEST_CHECK(transformed_with_energies->is_sorted_by_energy());
436 9 : for (size_t i = 0; i < energies.size(); ++i) {
437 8 : DOCTEST_CHECK(transformed_with_energies->get_energy(i) == energies[i]);
438 : }
439 3 : DOCTEST_CHECK_THROWS_AS(basis->transformed(identity, {energies[0]}), std::invalid_argument);
440 :
441 : // Arbitrary coefficients do not have a well-defined energy
442 1 : auto copied = basis->copy_with_coefficients(basis->get_coefficients());
443 1 : DOCTEST_CHECK_THROWS_AS(copied->get_energy(0), std::invalid_argument);
444 1 : DOCTEST_CHECK_FALSE(copied->has_energy());
445 1 : }
446 :
447 : } // namespace pairinteraction
|