1 //
2 // BAGEL - Brilliantly Advanced General Electronic Structure Library
3 // Filename: dkhcore.cc
4 // Copyright (C) 2016 Toru Shiozaki
5 //
6 // Author: Raymond Wang <raymondwang@u.northwestern.edu>
7 // Maintainer: Shiozaki group
8 //
9 // This file is part of the BAGEL package.
10 //
11 // This program is free software: you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation, either version 3 of the License, or
14 // (at your option) any later version.
15 //
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 //
24 
25 
26 #include <src/mat1e/dkhcore.h>
27 #include <src/mat1e/kinetic.h>
28 #include <src/mat1e/nai.h>
29 #include <src/mat1e/rel/small1e.h>
30 #include <src/mat1e/overlap.h>
31 #include <src/integral/os/overlapbatch.h>
32 #include <src/mat1e/mixedbasis.h>
33 #include <src/util/math/algo.h>
34 
35 using namespace std;
36 using namespace bagel;
37 
BOOST_CLASS_EXPORT_IMPLEMENT(DKHcore)38 BOOST_CLASS_EXPORT_IMPLEMENT(DKHcore)
39 
40 
41 DKHcore::DKHcore(shared_ptr<const Molecule> mol) : Matrix(mol->nbasis(), mol->nbasis()) {
42   init(mol);
43 }
44 
45 
init(shared_ptr<const Molecule> mol0)46 void DKHcore::init(shared_ptr<const Molecule> mol0) {
47 
48   auto pre_scale = [](const VectorB& vec, const Matrix& mat) {
49     assert(mat.ndim() == vec.size());
50     shared_ptr<Matrix> out = mat.clone();
51     for (int i = 0; i != mat.mdim(); ++i)
52       for (int j = 0; j != mat.ndim(); ++j)
53         (*out)(j, i) = mat(j, i) * vec(j);
54     return out;
55   };
56 
57   auto post_scale = [](const Matrix& mat, const VectorB& vec) {
58     assert(mat.mdim() == vec.size());
59     shared_ptr<Matrix> out = mat.copy();
60     for (int i = 0; i != mat.mdim(); ++i)
61       blas::scale_n(vec(i), out->element_ptr(0, i), mat.ndim());
62     return out;
63   };
64 
65   auto mol = make_shared<Molecule>(*mol0);
66   mol = mol->uncontract();
67 
68   // build DKH Hamiltonian in uncontracted basis
69   shared_ptr<const Matrix> transfer;
70   VectorB eig;
71   {
72     const Overlap overlap(mol);
73     shared_ptr<const Matrix> tildex = overlap.tildex();
74     const Kinetic kinetic(mol);
75     auto tmp = make_shared<Matrix>(*tildex % kinetic * *tildex);
76     eig = VectorB(tmp->ndim());
77     tmp->diagonalize(eig);
78     transfer = make_shared<Matrix>(*tildex * *tmp);
79   }
80 
81   const double c2 = c__ * c__;
82   const int nunc = eig.size();
83   VectorB Ep(nunc);
84   VectorB A(nunc);
85   VectorB B(nunc);
86   VectorB RI(nunc);
87   VectorB RI_inv(nunc);
88   for (int i = 0; i != nunc; ++i) {
89     Ep(i) = c__ * std::sqrt(2.0 * eig(i) + c2);
90     A(i) = std::sqrt(0.5 * (Ep(i) + c2) / Ep(i));
91     B(i) = A(i) * c__ / (Ep(i) + c2);
92     RI(i) = 2.0 * eig(i) * pow((c__ / (Ep(i) + c2)), 2);
93     RI_inv(i) = 1.0 / RI(i);
94   }
95 
96   const NAI nai(mol);
97   const Matrix V(*transfer % nai * *transfer);
98   const Small1e<NAIBatch> small1e(mol);
99   const Matrix smallnai(*transfer % small1e[0] * *transfer);
100 
101   Matrix AVA(nunc, nunc);
102   Matrix BVB(nunc, nunc);
103   for (int i = 0; i != nunc; ++i)
104     for (int j = 0; j != nunc; ++j) {
105       const double denom = 1.0 / (Ep(j) + Ep(i));
106       AVA(j, i) = V(j, i) * A(j) * A(i) * denom ;
107       BVB(j, i) = smallnai(j, i) * B(j) * B(i) * denom;
108     }
109 
110   Matrix dkh(nunc, nunc);
111   for (int i = 0; i != nunc; ++i)
112     dkh(i, i) = c2 * 2.0 * eig(i) / (Ep(i) + c2);
113 
114   const Matrix EAVA(*pre_scale(Ep, AVA));
115   const Matrix AVARI(*post_scale(AVA, RI));
116   const Matrix AVAE(*post_scale(AVA, Ep));
117   const Matrix BVBE(*post_scale(BVB, Ep));
118   const Matrix EBVB(*pre_scale(Ep, BVB));
119 
120   dkh += *post_scale(*pre_scale(A, V), A)           + *post_scale(*pre_scale(B, smallnai), B) // Free Particle Projection
121        - BVB * (EAVA - 0.5 * (*pre_scale(RI_inv, BVBE)- AVAE))
122        - (AVAE + 0.5 * EAVA) * BVB                  + 0.5 * (*post_scale(EAVA, RI) - EBVB) * AVA
123        + 0.5 * EBVB * *pre_scale(RI_inv, BVB)       + AVARI * (EAVA + 0.5 * AVAE)
124        + BVBE * *pre_scale(RI_inv, BVB)             - 0.5 * AVA * BVBE;                   // DKH2
125 
126   const MixedBasis<OverlapBatch> mix(mol0, mol);
127   const Matrix transfer2 = *transfer % mix;
128   Matrix_base<double>::operator=(transfer2 % dkh * transfer2);
129 }
130 
131 
132 /*
133    dkh += post_scale(pre_scale(A,V),A) + post_scale(pre_scale(B,smallnai),B)
134        - BVB * EAVA                     - AVAE * BVB                         + AVARI * EAVA
135        + BVBE * pre_scale(RI_inv,BVB)   - 0.5 * BVB * AVAE                   - 0.5 * AVA * BVBE
136        + 0.5 * AVARI * AVAE             + 0.5 * BVB * pre_scale(RI_inv,BVBE) - 0.5 * EBVB * AVA
137        - 0.5 * EAVA * BVB               + 0.5 * EAVA * pre_scale(RI,AVA)     + 0.5 * EBVB * pre_scale(RI_inv,BVB);
138 */
139 
140 // Leave it here if we want do DKH2FULL in the future
141 /*
142   Matrix smallx(transfer % small1e[2] * transfer);
143   Matrix smally(transfer % small1e[3] * transfer);
144   Matrix smallz(transfer % small1e[1] * transfer);
145   for (int i = 0; i != ndim; ++i) {
146     for (int j = 0; j != ndim; ++j) {
147       const int denom = Ep(i) + Ep(j);
148       smallx(i,j) /= denom;
149       smally(i,j) /= denom;
150       smallz(i,j) /= denom;
151     }
152   }
153 
154   const Matrix Xc(B * smallx * B);
155   const Matrix Yc(B * smally * B);
156   const Matrix Zc(B * smallz * B);
157 
158      - Xc * Ep * RI_inv * Xc        - Yc * Ep * RI_inv * Yc          - Zc * Ep * RI_inv * Zc
159      - 0.5 * Xc * RI_inv * Xc * Ep  - 0.5 * Yc * RI_inv * Yc * Ep    - 0.5 * Zc * RI_inv * Zc * Ep
160      - 0.5 * Ep * Xc * RI_inv * Xc  - 0.5 * Ep * Yc * RI_inv * Yc    - 0.5 * Ep * Zc * RI_inv * Zc; // DKH2FULL
161 */
162