LCOV - code coverage report
Current view: top level - pairinteraction - MatrixElements.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 320 608 52.6 %
Date: 2024-04-29 00:41:50 Functions: 16 24 66.7 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2016 Sebastian Weber, Henri Menke. All rights reserved.
       3             :  *
       4             :  * This file is part of the pairinteraction library.
       5             :  *
       6             :  * The pairinteraction library is free software: you can redistribute it and/or modify
       7             :  * it under the terms of the GNU Lesser General Public License as published by
       8             :  * the Free Software Foundation, either version 3 of the License, or
       9             :  * (at your option) any later version.
      10             :  *
      11             :  * The pairinteraction library is distributed in the hope that it will be useful,
      12             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :  * GNU Lesser General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU Lesser General Public License
      17             :  * along with the pairinteraction library. If not, see <http://www.gnu.org/licenses/>.
      18             :  */
      19             : 
      20             : #include "MatrixElements.hpp"
      21             : 
      22             : #include "Constants.hpp"
      23             : #include "QuantumDefect.hpp"
      24             : #include "SQLite.hpp"
      25             : 
      26             : #include <fmt/format.h>
      27             : 
      28             : #include <cctype>
      29             : #include <iostream>
      30             : #include <limits>
      31             : #include <sstream>
      32             : #include <stdexcept>
      33             : #include <string>
      34             : #include <utility>
      35             : 
      36       65178 : bool selectionRulesMomentum(StateOneOld const &state1, StateOneOld const &state2, int q) {
      37       65178 :     bool validL = state1.l == state2.l;
      38       65178 :     bool validJ = std::fabs(state1.j - state2.j) <= 1;
      39       65178 :     bool validM = state1.m == state2.m + q;
      40       65178 :     bool validQ = abs(q) <= 1;
      41       65178 :     return validL && validJ && validM && validQ;
      42             : }
      43             : 
      44        8604 : bool selectionRulesMomentum(StateOneOld const &state1, StateOneOld const &state2) {
      45        8604 :     bool validL = state1.l == state2.l;
      46        8604 :     bool validJ = std::fabs(state1.j - state2.j) <= 1;
      47        8604 :     bool validM = (std::fabs(state1.m - state2.m) <= 1);
      48        8604 :     return validL && validJ && validM;
      49             : }
      50             : 
      51      187080 : bool selectionRulesMultipole(StateOneOld const &state1, StateOneOld const &state2, int kappa,
      52             :                              int q) {
      53      187080 :     bool validL =
      54      187080 :         (abs(state1.l - state2.l) <= kappa) && (kappa % 2 == abs(state1.l - state2.l) % 2);
      55      187080 :     bool validJ = (std::fabs(state1.j - state2.j) <= kappa) && (state1.j + state2.j >= kappa);
      56      187080 :     bool validM = state1.m == state2.m + q;
      57      187080 :     bool validQ = abs(q) <= kappa;
      58      189360 :     bool noZero = !(kappa == 2 && state1.j == state2.j && state2.j == 1.5 &&
      59        2280 :                     state1.m == -state2.m && std::fabs(state1.m - state2.m) == 1);
      60      187080 :     return validL && validJ && validM && validQ && noZero;
      61             : }
      62             : 
      63      141090 : bool selectionRulesMultipole(StateOneOld const &state1, StateOneOld const &state2, int kappa) {
      64      141090 :     bool validL =
      65      141090 :         (abs(state1.l - state2.l) <= kappa) && (kappa % 2 == abs(state1.l - state2.l) % 2);
      66      141090 :     bool validJ = (std::fabs(state1.j - state2.j) <= kappa) && (state1.j + state2.j >= kappa);
      67      141090 :     bool validM = (std::fabs(state1.m - state2.m) <= kappa);
      68      141594 :     bool noZero = !(kappa == 2 && state1.j == state2.j && state2.j == 1.5 &&
      69         504 :                     state1.m == -state2.m && std::fabs(state1.m - state2.m) == 1);
      70      141090 :     return validL && validJ && validM && noZero;
      71             : }
      72             : 
      73           7 : MatrixElements::MatrixElements(std::string const &species, std::string dbname)
      74           7 :     : species(species), dbname(std::move(dbname)) {
      75           7 :     method = "Modelpotentials";
      76           7 :     muB = 0.5;
      77           7 :     gS = 2.0023192;
      78           7 :     gL = 1;
      79             : 
      80           7 :     s = 0.5;
      81           7 :     if (std::isdigit(species.back()) != 0) {
      82           0 :         s = ((species.back() - '0') - 1) / 2.; // TODO think of a better solution
      83             :     }
      84           7 : }
      85             : 
      86           7 : MatrixElements::MatrixElements(const Configuration &config, std::string const &species,
      87           7 :                                std::string const &dbname)
      88           7 :     : MatrixElements(species, dbname) {
      89           7 :     if (config["missingCalc"].str() == "true") {
      90           7 :         method = "Modelpotentials";
      91           0 :     } else if (config["missingWhittaker"].str() == "true") {
      92           0 :         method = "Whittaker";
      93             :     } else {
      94           0 :         method = "Error";
      95             :     }
      96           7 : }
      97             : 
      98           4 : void MatrixElements::precalculateMultipole(std::shared_ptr<const BasisnamesOne> const &basis_one,
      99             :                                            int k) {
     100           4 :     int q = std::numeric_limits<int>::max();
     101           4 :     precalculate(basis_one, k, q, k, true, false, false);
     102           4 : }
     103             : 
     104           0 : void MatrixElements::precalculateRadial(std::shared_ptr<const BasisnamesOne> const &basis_one,
     105             :                                         int k) {
     106           0 :     int q = std::numeric_limits<int>::max();
     107           0 :     precalculate(basis_one, k, q, k, false, false, true);
     108           0 : }
     109             : 
     110           3 : void MatrixElements::precalculateElectricMomentum(
     111             :     std::shared_ptr<const BasisnamesOne> const &basis_one, int q) {
     112           3 :     precalculate(basis_one, 1, q, 1, true, false, false);
     113           3 : }
     114             : 
     115           3 : void MatrixElements::precalculateMagneticMomentum(
     116             :     std::shared_ptr<const BasisnamesOne> const &basis_one, int q) {
     117           3 :     precalculate(basis_one, 1, q, 0, false, true, false);
     118           3 : }
     119             : 
     120           6 : void MatrixElements::precalculateDiamagnetism(std::shared_ptr<const BasisnamesOne> const &basis_one,
     121             :                                               int k, int q) {
     122           6 :     precalculate(basis_one, k, q, 2, true, false, false);
     123           6 : }
     124             : 
     125        1332 : double MatrixElements::getElectricMomentum(
     126             :     StateOneOld const &state_row,
     127             :     StateOneOld const &
     128             :         state_col) { // TODO remove this method and use directly getMultipole(state_row,state_col,1)
     129        1332 :     return getMultipole(state_row, state_col, 1);
     130             : }
     131             : 
     132        1209 : double MatrixElements::getMagneticMomentum(StateOneOld const &state_row,
     133             :                                            StateOneOld const &state_col) {
     134        2418 :     double val = au2GHz / au2G * muB *
     135        1209 :         cache_radial[0][StateTwoOld({{state_row.n, state_col.n}}, {{state_row.l, state_col.l}},
     136        1209 :                                     {{state_row.j, state_col.j}}, {{0, 0}})
     137        2418 :                             .order()] *
     138        2418 :         cache_angular[1][StateTwoOld({{0, 0}}, {{0, 0}}, {{state_row.j, state_col.j}},
     139        1209 :                                      {{state_row.m, state_col.m}})] *
     140        2418 :         (gL *
     141        2418 :              cache_reduced_commutes_s[1][StateTwoOld({{0, 0}}, {{state_row.l, state_col.l}},
     142        1209 :                                                      {{state_row.j, state_col.j}}, {{0, 0}})] *
     143        1209 :              std::sqrt(state_row.l * (state_row.l + 1) * (2 * state_row.l + 1)) +
     144        2418 :          gS *
     145        2418 :              cache_reduced_commutes_l[1][StateTwoOld({{0, 0}}, {{state_row.l, state_col.l}},
     146        1209 :                                                      {{state_row.j, state_col.j}}, {{0, 0}})] *
     147             :              std::sqrt(
     148             :                  0.5 * (0.5 + 1) *
     149             :                  (2 * 0.5 +
     150        1209 :                   1))); // TODO give the radial matrix element the unit au2GHz / au2G * muB (for the
     151             :                         // electric momentum, the radial matrix element already carries the unit)
     152        1209 :     return val;
     153             : }
     154             : 
     155        3045 : double MatrixElements::getDiamagnetism(StateOneOld const &state_row, StateOneOld const &state_col,
     156             :                                        int k) {
     157        3045 :     double val = elementary_charge * inverse_electron_rest_mass * 1. / 12. *
     158        3045 :         cache_radial[2][StateTwoOld({{state_row.n, state_col.n}}, {{state_row.l, state_col.l}},
     159        3045 :                                     {{state_row.j, state_col.j}}, {{0, 0}})
     160        6090 :                             .order()] *
     161        6090 :         cache_angular[k][StateTwoOld({{0, 0}}, {{0, 0}}, {{state_row.j, state_col.j}},
     162        3045 :                                      {{state_row.m, state_col.m}})] *
     163        6090 :         cache_reduced_commutes_s[k][StateTwoOld({{0, 0}}, {{state_row.l, state_col.l}},
     164        3045 :                                                 {{state_row.j, state_col.j}}, {{0, 0}})] *
     165        6090 :         cache_reduced_multipole[k][StateTwoOld(
     166        3045 :             {{0, 0}}, {{state_row.l, state_col.l}}, {{0, 0}},
     167        3045 :             {{0, 0}})]; // TODO do the multiplication with inverse_electron_rest_mass outside this
     168             :                         // class // TODO remove this method and use directly
     169             :                         // getMultipole(state_row,state_col,kappa_angular = ..., kappa_radial = 2)
     170        3045 :     return val;
     171             : }
     172             : 
     173        1588 : double MatrixElements::getMultipole(StateOneOld const &state_row, StateOneOld const &state_col,
     174             :                                     int k) {
     175             :     double val =
     176        1588 :         cache_radial[k][StateTwoOld({{state_row.n, state_col.n}}, {{state_row.l, state_col.l}},
     177        1588 :                                     {{state_row.j, state_col.j}}, {{0, 0}})
     178        3176 :                             .order()] *
     179        3176 :         cache_angular[k][StateTwoOld({{0, 0}}, {{0, 0}}, {{state_row.j, state_col.j}},
     180        1588 :                                      {{state_row.m, state_col.m}})] *
     181        3176 :         cache_reduced_commutes_s[k][StateTwoOld({{0, 0}}, {{state_row.l, state_col.l}},
     182        1588 :                                                 {{state_row.j, state_col.j}}, {{0, 0}})] *
     183        3176 :         cache_reduced_multipole[k][StateTwoOld({{0, 0}}, {{state_row.l, state_col.l}}, {{0, 0}},
     184        1588 :                                                {{0, 0}})];
     185        1588 :     return val;
     186             : }
     187             : 
     188           0 : double MatrixElements::getRadial(StateOneOld const &state_row, StateOneOld const &state_col,
     189             :                                  int k) {
     190             :     double val =
     191           0 :         cache_radial[k][StateTwoOld({{state_row.n, state_col.n}}, {{state_row.l, state_col.l}},
     192           0 :                                     {{state_row.j, state_col.j}}, {{0, 0}})
     193           0 :                             .order()];
     194           0 :     return val;
     195             : }
     196             : 
     197          16 : void MatrixElements::precalculate(const std::shared_ptr<const BasisnamesOne> &basis_one, int kappa,
     198             :                                   int q, int kappar, bool calcElectricMultipole,
     199             :                                   bool calcMagneticMomentum, bool calcRadial) {
     200          32 :     sqlite::handle db(dbname);
     201          32 :     sqlite::statement stmt(db);
     202             : 
     203             :     // --- create cache tables if necessary (reduced_moemntumS and reduced_moemntumL need not to be
     204             :     // cached since they are trivial) ---
     205             : 
     206          16 :     if (calcElectricMultipole || calcMagneticMomentum || calcRadial) {
     207          16 :         stmt.exec("CREATE TABLE IF NOT EXISTS cache_radial ("
     208             :                   "method text, species text, k integer, n1 integer, l1 integer, j1 double,"
     209             :                   "n2 integer, l2 integer, j2 double, value double, UNIQUE (method, species, k, "
     210          32 :                   "n1, l1, j1, n2, l2, j2));");
     211          16 :         stmt.exec("CREATE TEMPORARY TABLE tmp_radial ("
     212             :                   "n1 integer, l1 integer, j1 double,"
     213          32 :                   "n2 integer, l2 integer, j2 double);");
     214             :     }
     215             : 
     216          16 :     if (calcElectricMultipole || calcMagneticMomentum) {
     217          16 :         stmt.exec("CREATE TABLE IF NOT EXISTS cache_angular ("
     218             :                   "k integer, j1 double, m1 double,"
     219          32 :                   "j2 double, m2 double, value double, UNIQUE (k, j1, m1, j2, m2));");
     220          16 :         stmt.exec("CREATE TEMPORARY TABLE tmp_angular ("
     221             :                   "j1 double, m1 double,"
     222          32 :                   "j2 double, m2 double);");
     223             :     }
     224             : 
     225          16 :     if (calcElectricMultipole || calcMagneticMomentum) {
     226          16 :         stmt.exec("CREATE TABLE IF NOT EXISTS cache_reduced_commutes_s ("
     227             :                   "k integer, l1 integer, j1 double,"
     228          32 :                   "l2 integer, j2 double, value double, UNIQUE (k, l1, j1, l2, j2));");
     229          16 :         stmt.exec("CREATE TEMPORARY TABLE tmp_reduced_commutes_s ("
     230             :                   "l1 integer, j1 double,"
     231          32 :                   "l2 integer, j2 double);");
     232             :     }
     233             : 
     234          16 :     if (calcMagneticMomentum) {
     235           3 :         stmt.exec("CREATE TABLE IF NOT EXISTS cache_reduced_commutes_l ("
     236             :                   "k integer, l1 integer, j1 double,"
     237           6 :                   "l2 integer, j2 double, value double, UNIQUE (k, l1, j1, l2, j2));");
     238           3 :         stmt.exec("CREATE TEMPORARY TABLE tmp_reduced_commutes_l ("
     239             :                   "l1 integer, j1 double,"
     240           6 :                   "l2 integer, j2 double);");
     241             :     }
     242             : 
     243          16 :     if (calcElectricMultipole) {
     244          13 :         stmt.exec("CREATE TABLE IF NOT EXISTS cache_reduced_multipole ("
     245             :                   "k integer, l1 integer,"
     246          26 :                   "l2 integer, value double, UNIQUE (k, l1, l2));");
     247          13 :         stmt.exec("CREATE TEMPORARY TABLE tmp_reduced_multipole ("
     248             :                   "l1 integer,"
     249          26 :                   "l2 integer);");
     250             :     }
     251             : 
     252             :     // --- determine elements ---
     253             : 
     254          32 :     std::stringstream ss;
     255             : 
     256          16 :     stmt.exec("begin transaction;");
     257             : 
     258        2264 :     for (const auto &state_col : *basis_one) {
     259      372600 :         for (const auto &state_row : *basis_one) {
     260      370352 :             if (q != std::numeric_limits<int>::max() && state_row.m - state_col.m != q) {
     261      236394 :                 continue;
     262             :             }
     263             : 
     264             :             // if (state_row.idx < state_col.idx) { // TODO
     265             :             //    continue;
     266             :             //}
     267             : 
     268      133958 :             if ((calcElectricMultipole && selectionRulesMultipole(state_row, state_col, kappa)) ||
     269      267916 :                 (calcMagneticMomentum && selectionRulesMomentum(state_row, state_col)) ||
     270             :                 calcRadial) {
     271       23622 :                 if (calcElectricMultipole || calcMagneticMomentum || calcRadial) {
     272             :                     StateTwoOld state_nlj =
     273           0 :                         StateTwoOld({{state_row.n, state_col.n}}, {{state_row.l, state_col.l}},
     274       23622 :                                     {{state_row.j, state_col.j}}, {{0, 0}})
     275       47244 :                             .order();
     276       23622 :                     auto missing_cache_radial = cache_radial[kappar].insert(
     277       23622 :                         {state_nlj, std::numeric_limits<double>::max()});
     278       23622 :                     if (missing_cache_radial.second) {
     279         867 :                         ss.str(std::string());
     280         867 :                         ss << "insert into tmp_radial (n1,l1,j1,n2,l2,j2) values ("
     281         867 :                            << state_nlj.n[0] << "," << state_nlj.l[0] << "," << state_nlj.j[0]
     282         867 :                            << "," << state_nlj.n[1] << "," << state_nlj.l[1] << ","
     283         867 :                            << state_nlj.j[1] << ");";
     284         867 :                         stmt.exec(ss.str());
     285             :                     }
     286             :                 }
     287             : 
     288       23622 :                 if (calcElectricMultipole || calcMagneticMomentum) {
     289             :                     StateTwoOld state_jm =
     290       23622 :                         StateTwoOld({{0, 0}}, {{0, 0}}, {{state_row.j, state_col.j}},
     291       47244 :                                     {{state_row.m, state_col.m}});
     292             :                     auto missing_cache_angular =
     293       23622 :                         cache_angular[kappa].insert({state_jm, std::numeric_limits<double>::max()});
     294       23622 :                     if (missing_cache_angular.second) {
     295         992 :                         ss.str(std::string());
     296         992 :                         ss << "insert into tmp_angular (j1,m1,j2,m2) values (" << state_jm.j[0]
     297         992 :                            << "," << state_jm.m[0] << "," << state_jm.j[1] << "," << state_jm.m[1]
     298         992 :                            << ");";
     299         992 :                         stmt.exec(ss.str());
     300             :                     }
     301             :                 }
     302             : 
     303       23622 :                 if (calcElectricMultipole || calcMagneticMomentum) {
     304       23622 :                     StateTwoOld state_lj = StateTwoOld({{0, 0}}, {{state_row.l, state_col.l}},
     305       47244 :                                                        {{state_row.j, state_col.j}}, {{0, 0}});
     306       23622 :                     auto missing_cache_reduced_commutes_s = cache_reduced_commutes_s[kappa].insert(
     307       23622 :                         {state_lj, std::numeric_limits<double>::max()});
     308       23622 :                     if (missing_cache_reduced_commutes_s.second) {
     309         123 :                         ss.str(std::string());
     310         123 :                         ss << "insert into tmp_reduced_commutes_s (l1,j1,l2,j2) values ("
     311         123 :                            << state_lj.l[0] << "," << state_lj.j[0] << "," << state_lj.l[1] << ","
     312         123 :                            << state_lj.j[1] << ");";
     313         123 :                         stmt.exec(ss.str());
     314             :                     }
     315             :                 }
     316             : 
     317       23622 :                 if (calcMagneticMomentum) {
     318        2268 :                     StateTwoOld state_lj = StateTwoOld({{0, 0}}, {{state_row.l, state_col.l}},
     319        4536 :                                                        {{state_row.j, state_col.j}}, {{0, 0}});
     320        2268 :                     auto missing_cache_reduced_commutes_l = cache_reduced_commutes_l[kappa].insert(
     321        2268 :                         {state_lj, std::numeric_limits<double>::max()});
     322        2268 :                     if (missing_cache_reduced_commutes_l.second) {
     323          17 :                         ss.str(std::string());
     324          17 :                         ss << "insert into tmp_reduced_commutes_l (l1,j1,l2,j2) values ("
     325          17 :                            << state_lj.l[0] << "," << state_lj.j[0] << "," << state_lj.l[1] << ","
     326          17 :                            << state_lj.j[1] << ");";
     327          17 :                         stmt.exec(ss.str());
     328             :                     }
     329             :                 }
     330             : 
     331       23622 :                 if (calcElectricMultipole) {
     332             :                     StateTwoOld state_l =
     333       42708 :                         StateTwoOld({{0, 0}}, {{state_row.l, state_col.l}}, {{0, 0}}, {{0, 0}});
     334       21354 :                     auto missing_cache_reduced_multipole = cache_reduced_multipole[kappa].insert(
     335       21354 :                         {state_l, std::numeric_limits<double>::max()});
     336       21354 :                     if (missing_cache_reduced_multipole.second) {
     337          39 :                         ss.str(std::string());
     338          39 :                         ss << "insert into tmp_reduced_multipole (l1,l2) values (" << state_l.l[0]
     339          39 :                            << "," << state_l.l[1] << ");";
     340          39 :                         stmt.exec(ss.str());
     341             :                     }
     342             :                 }
     343             :             }
     344             :         }
     345             :     }
     346             : 
     347          16 :     stmt.exec("end transaction;");
     348             : 
     349             :     // --- load from database ---
     350             : 
     351             :     int n1, n2, l1, l2;
     352             :     float j1, j2, m1, m2;
     353             :     double value;
     354             : 
     355          16 :     if (calcElectricMultipole || calcMagneticMomentum || calcRadial) {
     356          16 :         ss.str(std::string());
     357             :         ss << "SELECT c.n1, c.l1, c.j1, c.n2, c.l2, c.j2, c.value FROM cache_radial c INNER JOIN "
     358             :               "tmp_radial t ON ("
     359             :            << "c.n1 = t.n1 AND c.l1 = t.l1 AND c.j1 = t.j1 AND c.n2 = t.n2 AND c.l2 = t.l2 AND "
     360             :               "c.j2 = t.j2) "
     361          32 :            << "WHERE c.method= '" << method << "' AND c.species = '" << species
     362          16 :            << "' AND c.k = " << kappar << ";";
     363          32 :         sqlite::statement stmt(db, ss.str());
     364          16 :         stmt.prepare();
     365         274 :         while (stmt.step()) {
     366         258 :             n1 = stmt.get<decltype(n1)>(0);
     367         258 :             l1 = stmt.get<decltype(l1)>(1);
     368         258 :             j1 = stmt.get<decltype(j1)>(2);
     369         258 :             n2 = stmt.get<decltype(n2)>(3);
     370         258 :             l2 = stmt.get<decltype(l2)>(4);
     371         258 :             j2 = stmt.get<decltype(j2)>(5);
     372         258 :             value = stmt.get<decltype(value)>(6);
     373         258 :             cache_radial[kappar][StateTwoOld({{n1, n2}}, {{l1, l2}}, {{j1, j2}}, {{0, 0}})] = value;
     374             :         }
     375             :     }
     376             : 
     377          16 :     if (calcElectricMultipole || calcMagneticMomentum) {
     378          16 :         ss.str(std::string());
     379             :         ss << "SELECT c.j1, c.m1, c.j2, c.m2, c.value FROM cache_angular c INNER JOIN tmp_angular "
     380             :               "t ON ("
     381             :            << "c.j1 = t.j1 AND c.m1 = t.m1 AND c.j2 = t.j2 AND c.m2 = t.m2) "
     382          16 :            << "WHERE c.k = " << kappa << ";";
     383          32 :         sqlite::statement stmt(db, ss.str());
     384          16 :         stmt.prepare();
     385         188 :         while (stmt.step()) {
     386         172 :             j1 = stmt.get<decltype(j1)>(0);
     387         172 :             m1 = stmt.get<decltype(m1)>(1);
     388         172 :             j2 = stmt.get<decltype(j2)>(2);
     389         172 :             m2 = stmt.get<decltype(m2)>(3);
     390         172 :             value = stmt.get<decltype(value)>(4);
     391         172 :             cache_angular[kappa][StateTwoOld({{0, 0}}, {{0, 0}}, {{j1, j2}}, {{m1, m2}})] = value;
     392             :         }
     393             :     }
     394             : 
     395          16 :     if (calcElectricMultipole || calcMagneticMomentum) {
     396          16 :         ss.str(std::string());
     397             :         ss << "SELECT c.l1, c.j1, c.l2, c.j2, c.value FROM cache_reduced_commutes_s c INNER JOIN "
     398             :               "tmp_reduced_commutes_s t ON ("
     399             :            << "c.l1 = t.l1 AND c.j1 = t.j1 AND c.l2 = t.l2 AND c.j2 = t.j2) "
     400          16 :            << "WHERE c.k = " << kappa << ";";
     401          32 :         sqlite::statement stmt(db, ss.str());
     402          16 :         stmt.prepare();
     403          38 :         while (stmt.step()) {
     404          22 :             l1 = stmt.get<decltype(l1)>(0);
     405          22 :             j1 = stmt.get<decltype(j1)>(1);
     406          22 :             l2 = stmt.get<decltype(l2)>(2);
     407          22 :             j2 = stmt.get<decltype(j2)>(3);
     408          22 :             value = stmt.get<decltype(value)>(4);
     409          22 :             cache_reduced_commutes_s[kappa][StateTwoOld({{0, 0}}, {{l1, l2}}, {{j1, j2}},
     410          22 :                                                         {{0, 0}})] = value;
     411             :         }
     412             :     }
     413             : 
     414          16 :     if (calcMagneticMomentum) {
     415           3 :         ss.str(std::string());
     416             :         ss << "SELECT c.l1, c.j1, c.l2, c.j2, c.value FROM cache_reduced_commutes_l c INNER JOIN "
     417             :               "tmp_reduced_commutes_l t ON ("
     418             :            << "c.l1 = t.l1 AND c.j1 = t.j1 AND c.l2 = t.l2 AND c.j2 = t.j2) "
     419           3 :            << "WHERE c.k = " << kappa << ";";
     420           6 :         sqlite::statement stmt(db, ss.str());
     421           3 :         stmt.prepare();
     422           3 :         while (stmt.step()) {
     423           0 :             l1 = stmt.get<decltype(l1)>(0);
     424           0 :             j1 = stmt.get<decltype(j1)>(1);
     425           0 :             l2 = stmt.get<decltype(l2)>(2);
     426           0 :             j2 = stmt.get<decltype(j2)>(3);
     427           0 :             value = stmt.get<decltype(value)>(4);
     428           0 :             cache_reduced_commutes_l[kappa][StateTwoOld({{0, 0}}, {{l1, l2}}, {{j1, j2}},
     429           0 :                                                         {{0, 0}})] = value;
     430             :         }
     431             :     }
     432             : 
     433          16 :     if (calcElectricMultipole) {
     434          13 :         ss.str(std::string());
     435             :         ss << "SELECT c.l1, c.l2, c.value FROM cache_reduced_multipole c INNER JOIN "
     436             :               "tmp_reduced_multipole t ON ("
     437             :            << "c.l1 = t.l1 AND c.l2 = t.l2) "
     438          13 :            << "WHERE c.k = " << kappa << ";";
     439          26 :         sqlite::statement stmt(db, ss.str());
     440          13 :         stmt.prepare();
     441          21 :         while (stmt.step()) {
     442           8 :             l1 = stmt.get<decltype(l1)>(0);
     443           8 :             l2 = stmt.get<decltype(l2)>(1);
     444           8 :             value = stmt.get<decltype(value)>(2);
     445           8 :             cache_reduced_multipole[kappa][StateTwoOld({{0, 0}}, {{l1, l2}}, {{0, 0}}, {{0, 0}})] =
     446             :                 value;
     447             :         }
     448             :     }
     449             : 
     450             :     // --- calculate missing elements and write them to the database ---
     451             : 
     452          16 :     stmt.exec("begin transaction;");
     453             : 
     454          16 :     if (calcElectricMultipole || calcMagneticMomentum || calcRadial) {
     455        1963 :         for (auto &cache : cache_radial[kappar]) {
     456        1947 :             if (cache.second == std::numeric_limits<double>::max()) {
     457        1218 :                 auto state = cache.first;
     458             : 
     459        1218 :                 QuantumDefect qd1(species, state.n[0], state.l[0], state.j[0]);
     460         609 :                 QuantumDefect qd2(species, state.n[1], state.l[1], state.j[1]);
     461         609 :                 cache.second = calcRadialElement(qd1, kappar, qd2);
     462             : 
     463         609 :                 ss.str(std::string());
     464             :                 ss << "insert into cache_radial (method, species, k, n1, l1, j1, n2, l2, j2, "
     465             :                       "value) values ("
     466         609 :                    << "'" << method << "'"
     467             :                    << ","
     468         609 :                    << "'" << species << "'"
     469         609 :                    << "," << kappar << "," << state.n[0] << "," << state.l[0] << "," << state.j[0]
     470         609 :                    << "," << state.n[1] << "," << state.l[1] << "," << state.j[1] << ","
     471         609 :                    << cache.second << ");";
     472         609 :                 stmt.exec(ss.str());
     473             :             }
     474             :         }
     475             :     }
     476             : 
     477          16 :     if (calcElectricMultipole || calcMagneticMomentum) {
     478        2608 :         for (auto &cache : cache_angular[kappa]) {
     479        2592 :             if (cache.second == std::numeric_limits<double>::max()) {
     480         820 :                 auto state = cache.first;
     481         820 :                 float q = state.m[0] - state.m[1];
     482             : 
     483         820 :                 cache.second = std::pow(-1, state.j[0] - state.m[0]) *
     484         820 :                     WignerSymbols::wigner3j(state.j[0], kappa, state.j[1], -state.m[0], q,
     485         820 :                                             state.m[1]);
     486             : 
     487         820 :                 ss.str(std::string());
     488         820 :                 ss << "insert into cache_angular (k, j1, m1, j2, m2, value) values (" << kappa
     489         820 :                    << "," << state.j[0] << "," << state.m[0] << "," << state.j[1] << ","
     490         820 :                    << state.m[1] << "," << cache.second << ");";
     491         820 :                 stmt.exec(ss.str());
     492             :             }
     493             :         }
     494             :     }
     495             : 
     496          16 :     if (calcElectricMultipole || calcMagneticMomentum) {
     497         407 :         for (auto &cache : cache_reduced_commutes_s[kappa]) {
     498         391 :             if (cache.second == std::numeric_limits<double>::max()) {
     499         101 :                 auto state = cache.first;
     500             : 
     501             :                 // Check triangle conditions (violated e.g. for WignerSymbols::wigner6j(0, 0.5, 0.5,
     502             :                 // 0.5, 0, 1))
     503         202 :                 if (state.l[0] >= std::abs(state.j[0] - 0.5) && state.l[0] <= state.j[0] + 0.5 &&
     504         101 :                     state.l[0] >= std::abs(state.l[1] - kappa) &&
     505         200 :                     state.l[0] <= state.l[1] + kappa &&
     506         100 :                     state.j[1] >= std::abs(state.j[0] - kappa) &&
     507         302 :                     state.j[1] <= state.j[0] + kappa && state.j[1] >= std::abs(state.l[1] - 0.5) &&
     508         100 :                     state.j[1] <= state.l[1] + 0.5) {
     509         100 :                     cache.second = std::pow(-1, state.l[0] + 0.5 + state.j[1] + kappa) *
     510         100 :                         std::sqrt((2 * state.j[0] + 1) * (2 * state.j[1] + 1)) *
     511         100 :                         WignerSymbols::wigner6j(state.l[0], state.j[0], 0.5, state.j[1], state.l[1],
     512             :                                                 kappa);
     513             :                 } else {
     514           1 :                     cache.second = 0;
     515             :                 }
     516             : 
     517         101 :                 ss.str(std::string());
     518         101 :                 ss << "insert into cache_reduced_commutes_s (k, l1, j1, l2, j2, value) values ("
     519         101 :                    << kappa << "," << state.l[0] << "," << state.j[0] << "," << state.l[1] << ","
     520         101 :                    << state.j[1] << "," << cache.second << ");";
     521         101 :                 stmt.exec(ss.str());
     522             :             }
     523             :         }
     524             :     }
     525             : 
     526          16 :     if (calcMagneticMomentum) {
     527          54 :         for (auto &cache : cache_reduced_commutes_l[kappa]) {
     528          51 :             if (cache.second == std::numeric_limits<double>::max()) {
     529          17 :                 auto state = cache.first;
     530             : 
     531          17 :                 cache.second = std::pow(-1, state.l[0] + 0.5 + state.j[0] + kappa) *
     532          17 :                     std::sqrt((2 * state.j[0] + 1) * (2 * state.j[1] + 1)) *
     533          17 :                     WignerSymbols::wigner6j(0.5, state.j[0], state.l[0], state.j[1], 0.5, kappa);
     534             : 
     535          17 :                 ss.str(std::string());
     536          17 :                 ss << "insert into cache_reduced_commutes_l (k, l1, j1, l2, j2, value) values ("
     537          17 :                    << kappa << "," << state.l[0] << "," << state.j[0] << "," << state.l[1] << ","
     538          17 :                    << state.j[1] << "," << cache.second << ");";
     539          17 :                 stmt.exec(ss.str());
     540             :             }
     541             :         }
     542             :     }
     543             : 
     544          16 :     if (calcElectricMultipole) {
     545         108 :         for (auto &cache : cache_reduced_multipole[kappa]) {
     546          95 :             if (cache.second == std::numeric_limits<double>::max()) {
     547          31 :                 auto state = cache.first;
     548             : 
     549          31 :                 cache.second = std::pow(-1, state.l[0]) *
     550          31 :                     std::sqrt((2 * state.l[0] + 1) * (2 * state.l[1] + 1)) *
     551          31 :                     WignerSymbols::wigner3j(state.l[0], kappa, state.l[1], 0, 0, 0);
     552             : 
     553          31 :                 ss.str(std::string());
     554          31 :                 ss << "insert into cache_reduced_multipole (k, l1, l2, value) values (" << kappa
     555          31 :                    << "," << state.l[0] << "," << state.l[1] << "," << cache.second << ");";
     556          31 :                 stmt.exec(ss.str());
     557             :             }
     558             :         }
     559             :     }
     560             : 
     561          16 :     stmt.exec("end transaction;");
     562          16 : }
     563             : 
     564         609 : double MatrixElements::calcRadialElement(const QuantumDefect &qd1, int power,
     565             :                                          const QuantumDefect &qd2) {
     566             : 
     567         609 :     double converter = (power == 0) ? 1 : au2GHz / au2Vcm * std::pow(au2um, power - 1);
     568             : 
     569         609 :     if (method == "Modelpotentials") {
     570         609 :         return converter * IntegrateRadialElement<Numerov>(qd1, power, qd2);
     571             :     }
     572           0 :     if (method == "Whittaker") {
     573           0 :         return converter * IntegrateRadialElement<Whittaker>(qd1, power, qd2);
     574             :     }
     575             :     std::string msg("You have to provide all radial matrix elements on your own because you have "
     576           0 :                     "deactivated the calculation of missing radial matrix elements!");
     577           0 :     std::cout << msg << std::endl;
     578           0 :     throw std::runtime_error(msg);
     579             : }
     580             : 
     581           0 : void MatrixElements::precalculateMultipole(const std::vector<StateOneOld> &basis_one, int k) {
     582           0 :     int q = std::numeric_limits<int>::max();
     583           0 :     precalculate(basis_one, k, q, k, true, false, false);
     584           0 : }
     585             : 
     586           0 : void MatrixElements::precalculateRadial(const std::vector<StateOneOld> &basis_one, int k) {
     587           0 :     int q = std::numeric_limits<int>::max();
     588           0 :     precalculate(basis_one, k, q, k, false, false, true);
     589           0 : }
     590             : 
     591           0 : void MatrixElements::precalculateElectricMomentum(const std::vector<StateOneOld> &basis_one,
     592             :                                                   int q) {
     593           0 :     precalculate(basis_one, 1, q, 1, true, false, false);
     594           0 : }
     595             : 
     596           0 : void MatrixElements::precalculateMagneticMomentum(const std::vector<StateOneOld> &basis_one,
     597             :                                                   int q) {
     598           0 :     precalculate(basis_one, 1, q, 0, false, true, false);
     599           0 : }
     600             : 
     601           0 : void MatrixElements::precalculateDiamagnetism(const std::vector<StateOneOld> &basis_one, int k,
     602             :                                               int q) {
     603           0 :     precalculate(basis_one, k, q, 2, true, false, false);
     604           0 : }
     605             : 
     606           0 : void MatrixElements::precalculate(const std::vector<StateOneOld> &basis_one, int kappa, int q,
     607             :                                   int kappar, bool calcElectricMultipole, bool calcMagneticMomentum,
     608             :                                   bool calcRadial) {
     609           0 :     sqlite::handle db(dbname);
     610           0 :     sqlite::statement stmt(db);
     611             : 
     612             :     // --- Speed up database access ---
     613             : 
     614           0 :     stmt.exec("PRAGMA synchronous = OFF");     // do not wait on write, hand off to OS and carry on
     615           0 :     stmt.exec("PRAGMA journal_mode = MEMORY"); // keep rollback journal in memory during transaction
     616             : 
     617             :     // --- Create cache tables if necessary (reduced_moemntum_s and reduced_moemntum_l need not to
     618             :     // be cached since they are trivial) --- // TODO put this into the constructor of the
     619             :     // prospective cache object
     620             : 
     621           0 :     if (calcElectricMultipole || calcMagneticMomentum || calcRadial) {
     622           0 :         stmt.exec("create table if not exists cache_radial ("
     623             :                   "method text, species text, k integer, n1 integer, l1 integer, j1 double,"
     624             :                   "n2 integer, l2 integer, j2 double, value double, primary key (method, species, "
     625           0 :                   "k, n1, l1, j1, n2, l2, j2)) without rowid;");
     626             :     }
     627             : 
     628           0 :     if (calcElectricMultipole || calcMagneticMomentum) {
     629           0 :         stmt.exec(
     630             :             "create table if not exists cache_angular ("
     631             :             "k integer, j1 double, m1 double,"
     632           0 :             "j2 double, m2 double, value double, primary key (k, j1, m1, j2, m2)) without rowid;");
     633             :     }
     634             : 
     635           0 :     if (calcElectricMultipole || calcMagneticMomentum) {
     636           0 :         stmt.exec("create table if not exists cache_reduced_commutes_s ("
     637             :                   "s double, k integer, l1 integer, j1 double,"
     638             :                   "l2 integer, j2 double, value double, primary key (s, k, l1, j1, l2, j2)) "
     639           0 :                   "without rowid;");
     640             :     }
     641             : 
     642           0 :     if (calcMagneticMomentum) {
     643           0 :         stmt.exec("create table if not exists cache_reduced_commutes_l ("
     644             :                   "s double, k integer, l1 integer, j1 double,"
     645             :                   "l2 integer, j2 double, value double, primary key (s, k, l1, j1, l2, j2)) "
     646           0 :                   "without rowid;");
     647             :     }
     648             : 
     649           0 :     if (calcElectricMultipole) {
     650           0 :         stmt.exec("create table if not exists cache_reduced_multipole ("
     651             :                   "k integer, l1 integer,"
     652           0 :                   "l2 integer, value double, primary key (k, l1, l2)) without rowid;");
     653             :     }
     654             : 
     655             :     // --- Determine elements ---
     656             : 
     657           0 :     for (const auto &state_col : basis_one) {
     658           0 :         for (const auto &state_row : basis_one) {
     659           0 :             if (q != std::numeric_limits<int>::max() && state_row.m - state_col.m != q) {
     660           0 :                 continue;
     661             :             }
     662             : 
     663           0 :             if (state_row.species.empty() || state_col.species.empty()) {
     664           0 :                 continue; // TODO artifical states !!!
     665             :             }
     666             : 
     667             :             // if (state_row.idx < state_col.idx) { // TODO
     668             :             //    continue;
     669             :             //}
     670             : 
     671           0 :             if ((calcElectricMultipole && selectionRulesMultipole(state_row, state_col, kappa)) ||
     672           0 :                 (calcMagneticMomentum && selectionRulesMomentum(state_row, state_col)) ||
     673             :                 calcRadial) {
     674           0 :                 if (calcElectricMultipole || calcMagneticMomentum || calcRadial) {
     675             :                     StateTwoOld state_nlj =
     676           0 :                         StateTwoOld({{state_row.n, state_col.n}}, {{state_row.l, state_col.l}},
     677           0 :                                     {{state_row.j, state_col.j}}, {{0, 0}})
     678           0 :                             .order();
     679           0 :                     cache_radial[kappar].insert(
     680             :                         {state_nlj,
     681           0 :                          std::numeric_limits<double>::max()}); // TODO can this be speed up?
     682             :                 }
     683             : 
     684           0 :                 if (calcElectricMultipole || calcMagneticMomentum) {
     685             :                     StateTwoOld state_jm =
     686           0 :                         StateTwoOld({{0, 0}}, {{0, 0}}, {{state_row.j, state_col.j}},
     687           0 :                                     {{state_row.m, state_col.m}});
     688           0 :                     cache_angular[kappa].insert({state_jm, std::numeric_limits<double>::max()});
     689             :                 }
     690             : 
     691           0 :                 if (calcElectricMultipole || calcMagneticMomentum) {
     692           0 :                     StateTwoOld state_lj = StateTwoOld({{0, 0}}, {{state_row.l, state_col.l}},
     693           0 :                                                        {{state_row.j, state_col.j}}, {{0, 0}});
     694           0 :                     cache_reduced_commutes_s[kappa].insert(
     695           0 :                         {state_lj, std::numeric_limits<double>::max()});
     696             :                 }
     697             : 
     698           0 :                 if (calcMagneticMomentum) {
     699           0 :                     StateTwoOld state_lj = StateTwoOld({{0, 0}}, {{state_row.l, state_col.l}},
     700           0 :                                                        {{state_row.j, state_col.j}}, {{0, 0}});
     701           0 :                     cache_reduced_commutes_l[kappa].insert(
     702           0 :                         {state_lj, std::numeric_limits<double>::max()});
     703             :                 }
     704             : 
     705           0 :                 if (calcElectricMultipole) {
     706             :                     StateTwoOld state_l =
     707           0 :                         StateTwoOld({{0, 0}}, {{state_row.l, state_col.l}}, {{0, 0}}, {{0, 0}});
     708           0 :                     cache_reduced_multipole[kappa].insert(
     709           0 :                         {state_l, std::numeric_limits<double>::max()});
     710             :                 }
     711             :             }
     712             :         }
     713             :     }
     714             : 
     715             :     // --- Load from database ---
     716             : 
     717           0 :     if (calcElectricMultipole || calcMagneticMomentum || calcRadial) {
     718           0 :         stmt.set(
     719             :             "select value from cache_radial where `method` = ?1 and `species` = ?2 and `k` = ?3 "
     720           0 :             "and `n1` = ?4 and `l1` = ?5 and `j1` = ?6 and `n2` = ?7 and `l2` = ?8 and `j2` = ?9;");
     721             : 
     722           0 :         stmt.prepare();
     723           0 :         for (auto &cache : cache_radial[kappar]) {
     724           0 :             auto state = cache.first;
     725           0 :             stmt.bind(1, method);
     726           0 :             stmt.bind(2, species);
     727           0 :             stmt.bind(3, kappar);
     728           0 :             stmt.bind(4, state.n[0]);
     729           0 :             stmt.bind(5, state.l[0]);
     730           0 :             stmt.bind(6, state.j[0]);
     731           0 :             stmt.bind(7, state.n[1]);
     732           0 :             stmt.bind(8, state.l[1]);
     733           0 :             stmt.bind(9, state.j[1]);
     734           0 :             if (stmt.step()) {
     735           0 :                 cache.second = stmt.get<double>(0);
     736             :             }
     737           0 :             stmt.reset();
     738             :         }
     739             :     }
     740             : 
     741           0 :     if (calcElectricMultipole || calcMagneticMomentum) {
     742           0 :         stmt.set("select value from cache_angular where `k` = ?1 and `j1` = ?2 and `m1` = ?3 and "
     743           0 :                  "`j2` = ?4 and `m2` = ?5;");
     744             : 
     745           0 :         stmt.prepare();
     746           0 :         for (auto &cache : cache_angular[kappa]) {
     747           0 :             auto state = cache.first;
     748           0 :             stmt.bind(1, kappa);
     749           0 :             stmt.bind(2, state.j[0]);
     750           0 :             stmt.bind(3, state.m[0]);
     751           0 :             stmt.bind(4, state.j[1]);
     752           0 :             stmt.bind(5, state.m[1]);
     753           0 :             if (stmt.step()) {
     754           0 :                 cache.second = stmt.get<double>(0);
     755             :             }
     756           0 :             stmt.reset();
     757             :         }
     758             :     }
     759             : 
     760           0 :     if (calcElectricMultipole || calcMagneticMomentum) {
     761           0 :         stmt.set("select value from cache_reduced_commutes_s where `s` = ?1 and `k` = ?2 and `l1` "
     762           0 :                  "= ?3 and `j1` = ?4 and `l2` = ?5 and `j2` = ?6;");
     763             : 
     764           0 :         stmt.prepare();
     765           0 :         for (auto &cache : cache_reduced_commutes_s[kappa]) {
     766           0 :             auto state = cache.first;
     767           0 :             stmt.bind(1, s);
     768           0 :             stmt.bind(2, kappa);
     769           0 :             stmt.bind(3, state.l[0]);
     770           0 :             stmt.bind(4, state.j[0]);
     771           0 :             stmt.bind(5, state.l[1]);
     772           0 :             stmt.bind(6, state.j[1]);
     773           0 :             if (stmt.step()) {
     774           0 :                 cache.second = stmt.get<double>(0);
     775             :             }
     776           0 :             stmt.reset();
     777             :         }
     778             :     }
     779             : 
     780           0 :     if (calcMagneticMomentum) {
     781           0 :         stmt.set("select value from cache_reduced_commutes_l where `s` = ?1 and `k` = ?2 and `l1` "
     782           0 :                  "= ?3 and `j1` = ?4 and `l2` = ?5 and `j2` = ?6;");
     783             : 
     784           0 :         stmt.prepare();
     785           0 :         for (auto &cache : cache_reduced_commutes_l[kappa]) {
     786           0 :             auto state = cache.first;
     787           0 :             stmt.bind(1, kappa);
     788           0 :             stmt.bind(2, s);
     789           0 :             stmt.bind(3, state.l[0]);
     790           0 :             stmt.bind(4, state.j[0]);
     791           0 :             stmt.bind(5, state.l[1]);
     792           0 :             stmt.bind(6, state.j[1]);
     793           0 :             if (stmt.step()) {
     794           0 :                 cache.second = stmt.get<double>(0);
     795             :             }
     796           0 :             stmt.reset();
     797             :         }
     798             :     }
     799             : 
     800           0 :     if (calcElectricMultipole) {
     801           0 :         stmt.set("select value from cache_reduced_multipole where `k` = ?1 and `l1` = ?2 and `l2` "
     802           0 :                  "= ?3;");
     803             : 
     804           0 :         stmt.prepare();
     805           0 :         for (auto &cache : cache_reduced_multipole[kappa]) {
     806           0 :             auto state = cache.first;
     807           0 :             stmt.bind(1, kappa);
     808           0 :             stmt.bind(2, state.l[0]);
     809           0 :             stmt.bind(3, state.l[1]);
     810           0 :             if (stmt.step()) {
     811           0 :                 cache.second = stmt.get<double>(0);
     812             :             }
     813           0 :             stmt.reset();
     814             :         }
     815             :     }
     816             : 
     817             :     // --- Calculate missing elements and write them to the database ---
     818             : 
     819           0 :     stmt.exec("begin transaction;");
     820             : 
     821           0 :     if (calcElectricMultipole || calcMagneticMomentum || calcRadial) {
     822           0 :         stmt.set("insert or ignore into cache_radial (method, species, k, n1, l1, j1, n2, l2, j2, "
     823           0 :                  "value) values (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10);");
     824             : 
     825           0 :         stmt.prepare();
     826           0 :         for (auto &cache : cache_radial[kappar]) {
     827           0 :             if (cache.second == std::numeric_limits<double>::max()) {
     828           0 :                 auto state = cache.first;
     829             : 
     830           0 :                 QuantumDefect qd1(species, state.n[0], state.l[0], state.j[0]);
     831           0 :                 QuantumDefect qd2(species, state.n[1], state.l[1], state.j[1]);
     832           0 :                 cache.second = calcRadialElement(qd1, kappar, qd2);
     833             : 
     834           0 :                 stmt.bind(1, method);
     835           0 :                 stmt.bind(2, species);
     836           0 :                 stmt.bind(3, kappar);
     837           0 :                 stmt.bind(4, state.n[0]);
     838           0 :                 stmt.bind(5, state.l[0]);
     839           0 :                 stmt.bind(6, state.j[0]);
     840           0 :                 stmt.bind(7, state.n[1]);
     841           0 :                 stmt.bind(8, state.l[1]);
     842           0 :                 stmt.bind(9, state.j[1]);
     843           0 :                 stmt.bind(10, cache.second);
     844             : 
     845           0 :                 stmt.step();
     846           0 :                 stmt.reset();
     847             :             }
     848             :         }
     849             :     }
     850             : 
     851           0 :     if (calcElectricMultipole || calcMagneticMomentum) {
     852           0 :         stmt.set("insert or ignore into cache_angular (k, j1, m1, j2, m2, value) values (?1, ?2, "
     853           0 :                  "?3, ?4, ?5, ?6);");
     854             : 
     855           0 :         for (auto &cache : cache_angular[kappa]) {
     856           0 :             if (cache.second == std::numeric_limits<double>::max()) {
     857           0 :                 auto state = cache.first;
     858           0 :                 float q = state.m[0] - state.m[1];
     859             : 
     860           0 :                 cache.second = std::pow(-1, state.j[0] - state.m[0]) *
     861           0 :                     WignerSymbols::wigner3j(state.j[0], kappa, state.j[1], -state.m[0], q,
     862           0 :                                             state.m[1]);
     863             : 
     864           0 :                 if (cache.second > 1e9) {
     865             :                     std::cout << "Warning: Error in the calculation of the Wigner-3j-symbol "
     866           0 :                                  "detected and resolved."
     867           0 :                               << std::endl;
     868           0 :                     cache.second = 0;
     869             :                 }
     870             : 
     871           0 :                 stmt.prepare(); // @henri: can this be moved outside the loop?
     872           0 :                 stmt.bind(1, kappa);
     873           0 :                 stmt.bind(2, state.j[0]);
     874           0 :                 stmt.bind(3, state.m[0]);
     875           0 :                 stmt.bind(4, state.j[1]);
     876           0 :                 stmt.bind(5, state.m[1]);
     877           0 :                 stmt.bind(6, cache.second);
     878           0 :                 stmt.step();
     879           0 :                 stmt.reset(); // @henri: can this be moved outside the loop?
     880             :             }
     881             :         }
     882             :     }
     883             : 
     884           0 :     if (calcElectricMultipole || calcMagneticMomentum) {
     885           0 :         stmt.set("insert or ignore into cache_reduced_commutes_s (s, k, l1, j1, l2, j2, value) "
     886           0 :                  "values (?1, ?2, ?3, ?4, ?5, ?6, ?7);");
     887             : 
     888           0 :         stmt.prepare();
     889           0 :         for (auto &cache : cache_reduced_commutes_s[kappa]) {
     890           0 :             if (cache.second == std::numeric_limits<double>::max()) {
     891           0 :                 auto state = cache.first;
     892             : 
     893             :                 // Check triangle conditions (violated e.g. for WignerSymbols::wigner6j(0, 0.5, 0.5,
     894             :                 // 0.5, 0, 1))
     895           0 :                 if (state.l[0] >= std::abs(state.j[0] - s) && state.l[0] <= state.j[0] + s &&
     896           0 :                     state.l[0] >= std::abs(state.l[1] - kappa) &&
     897           0 :                     state.l[0] <= state.l[1] + kappa &&
     898           0 :                     state.j[1] >= std::abs(state.j[0] - kappa) &&
     899           0 :                     state.j[1] <= state.j[0] + kappa && state.j[1] >= std::abs(state.l[1] - s) &&
     900           0 :                     state.j[1] <= state.l[1] + s) {
     901           0 :                     cache.second = std::pow(-1, state.l[0] + s + state.j[1] + kappa) *
     902           0 :                         std::sqrt((2 * state.j[0] + 1) * (2 * state.j[1] + 1)) *
     903           0 :                         WignerSymbols::wigner6j(state.l[0], state.j[0], s, state.j[1], state.l[1],
     904             :                                                 kappa);
     905             :                 } else {
     906           0 :                     cache.second = 0;
     907             :                 }
     908             : 
     909           0 :                 stmt.bind(1, s);
     910           0 :                 stmt.bind(2, kappa);
     911           0 :                 stmt.bind(3, state.l[0]);
     912           0 :                 stmt.bind(4, state.j[0]);
     913           0 :                 stmt.bind(5, state.l[1]);
     914           0 :                 stmt.bind(6, state.j[1]);
     915           0 :                 stmt.bind(7, cache.second);
     916           0 :                 stmt.step();
     917           0 :                 stmt.reset();
     918             :             }
     919             :         }
     920             :     }
     921             : 
     922           0 :     if (calcMagneticMomentum) {
     923           0 :         stmt.set("insert or ignore into cache_reduced_commutes_l (s, k, l1, j1, l2, j2, value) "
     924           0 :                  "values (?1, ?2, ?3, ?4, ?5, ?6, ?7);");
     925             : 
     926           0 :         stmt.prepare();
     927           0 :         for (auto &cache : cache_reduced_commutes_l[kappa]) {
     928           0 :             if (cache.second == std::numeric_limits<double>::max()) {
     929           0 :                 auto state = cache.first;
     930             : 
     931             :                 // Check triangle conditions (violated e.g. for WignerSymbols::wigner6j(0, 0.5, 0.5,
     932             :                 // 0.5, 0, 1))
     933           0 :                 if (s >= std::abs(state.j[0] - state.l[0]) && s <= state.j[0] + state.l[0] &&
     934           0 :                     s >= std::abs(s - kappa) && s <= s + kappa &&
     935           0 :                     state.j[1] >= std::abs(state.j[0] - kappa) &&
     936           0 :                     state.j[1] <= state.j[0] + kappa && state.j[1] >= std::abs(s - state.l[0]) &&
     937           0 :                     state.j[1] <= s + state.l[0]) {
     938           0 :                     cache.second = std::pow(-1, state.l[0] + s + state.j[0] + kappa) *
     939           0 :                         std::sqrt((2 * state.j[0] + 1) * (2 * state.j[1] + 1)) *
     940           0 :                         WignerSymbols::wigner6j(s, state.j[0], state.l[0], state.j[1], s, kappa);
     941             :                 } else {
     942           0 :                     cache.second = 0;
     943             :                 }
     944             : 
     945           0 :                 stmt.bind(1, s);
     946           0 :                 stmt.bind(2, kappa);
     947           0 :                 stmt.bind(3, state.l[0]);
     948           0 :                 stmt.bind(4, state.j[0]);
     949           0 :                 stmt.bind(5, state.l[1]);
     950           0 :                 stmt.bind(6, state.j[1]);
     951           0 :                 stmt.bind(7, cache.second);
     952           0 :                 stmt.step();
     953           0 :                 stmt.reset();
     954             :             }
     955             :         }
     956             :     }
     957             : 
     958           0 :     if (calcElectricMultipole) {
     959           0 :         stmt.set("insert or ignore into cache_reduced_multipole (k, l1, l2, value) values (?1, ?2, "
     960           0 :                  "?3, ?4);");
     961             : 
     962           0 :         stmt.prepare();
     963           0 :         for (auto &cache : cache_reduced_multipole[kappa]) {
     964           0 :             if (cache.second == std::numeric_limits<double>::max()) {
     965           0 :                 auto state = cache.first;
     966             : 
     967           0 :                 cache.second = std::pow(-1, state.l[0]) *
     968           0 :                     std::sqrt((2 * state.l[0] + 1) * (2 * state.l[1] + 1)) *
     969           0 :                     WignerSymbols::wigner3j(state.l[0], kappa, state.l[1], 0, 0, 0);
     970             : 
     971           0 :                 if (cache.second > 1e9) {
     972             :                     std::cout << "Warning: Error in the calculation of the Wigner-3j-symbol "
     973           0 :                                  "detected and resolved."
     974           0 :                               << std::endl;
     975           0 :                     cache.second = 0;
     976             :                 }
     977             : 
     978           0 :                 stmt.bind(1, kappa);
     979           0 :                 stmt.bind(2, state.l[0]);
     980           0 :                 stmt.bind(3, state.l[1]);
     981           0 :                 stmt.bind(4, cache.second);
     982           0 :                 stmt.step();
     983           0 :                 stmt.reset();
     984             :             }
     985             :         }
     986             :     }
     987             : 
     988           0 :     stmt.exec("commit transaction;");
     989           0 : }

Generated by: LCOV version 1.14