1 //
2 // BAGEL - Brilliantly Advanced General Electronic Structure Library
3 // Filename: reldfhalf.cc
4 // Copyright (C) 2012 Toru Shiozaki
5 //
6 // Author: Toru Shiozaki <shiozaki@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/df/reldfhalf.h>
27
28 using namespace std;
29 using namespace bagel;
30
RelDFHalf(shared_ptr<const RelDF> df,vector<shared_ptr<const SpinorInfo>> bas,array<shared_ptr<const Matrix>,4> rcoeff,array<shared_ptr<const Matrix>,4> icoeff)31 RelDFHalf::RelDFHalf(shared_ptr<const RelDF> df, vector<shared_ptr<const SpinorInfo>> bas, array<shared_ptr<const Matrix>,4> rcoeff, array<shared_ptr<const Matrix>,4> icoeff)
32 : RelDFBase(*df) {
33
34 basis_ = bas;
35 const int index = basis_.front()->basis(0);
36 for (auto& i : basis_)
37 if (i->basis(0) != index) throw logic_error("basis should have the same first index");
38
39 // -1 due to dagger (We are transforming the bra.)
40 auto icoeff_scaled = make_shared<const Matrix>(*icoeff[index] * (-1.0));
41
42 // Real RelDF (standard)
43 if (!df->get_imag()) {
44 if (df->swapped()) {
45 dfhalf_[0] = df->get_real()->compute_half_transform_swap(rcoeff[index]);
46 dfhalf_[1] = df->get_real()->compute_half_transform_swap(icoeff_scaled);
47 } else {
48 dfhalf_[0] = df->get_real()->compute_half_transform(rcoeff[index]);
49 dfhalf_[1] = df->get_real()->compute_half_transform(icoeff_scaled);
50 }
51
52 // Complex RelDF (GIAO)
53 } else {
54
55 // For 3-multiplication
56 auto ricoeff = make_shared<const Matrix>(*rcoeff[index] + *icoeff_scaled);
57 auto dfri = make_shared<DFDist>(df->get_imag());
58 const int n = df->get_real()->block().size();
59 const double scale = df->swapped() ? -1.0 : 1.0;
60 for (int i=0; i!=n; ++i) {
61 dfri->add_block(df->get_real()->block(i)->copy());
62 dfri->block(i)->ax_plus_y(scale, df->get_imag()->block(i));
63 }
64
65 if (df->swapped()) {
66 dfhalf_[0] = df->get_real()->compute_half_transform_swap(rcoeff[index]);
67 auto tmp = df->get_imag()->compute_half_transform_swap(icoeff_scaled);
68 dfhalf_[1] = dfri->compute_half_transform_swap(ricoeff);
69
70 dfhalf_[1]->ax_plus_y(-1.0, dfhalf_[0]);
71 dfhalf_[1]->ax_plus_y( 1.0, tmp);
72 dfhalf_[0]->ax_plus_y( 1.0, tmp);
73 } else {
74 dfhalf_[0] = df->get_real()->compute_half_transform(rcoeff[index]);
75 auto tmp = df->get_imag()->compute_half_transform(icoeff_scaled);
76 dfhalf_[1] = dfri->compute_half_transform(ricoeff);
77
78 dfhalf_[1]->ax_plus_y(-1.0, dfhalf_[0]);
79 dfhalf_[1]->ax_plus_y(-1.0, tmp);
80 dfhalf_[0]->ax_plus_y(-1.0, tmp);
81 }
82 }
83 }
84
85
RelDFHalf(array<shared_ptr<DFHalfDist>,2> data,pair<int,int> cartesian,vector<shared_ptr<const SpinorInfo>> bas)86 RelDFHalf::RelDFHalf(array<shared_ptr<DFHalfDist>,2> data, pair<int, int> cartesian, vector<shared_ptr<const SpinorInfo>> bas) : RelDFBase(cartesian), dfhalf_(data) {
87 basis_ = bas;
88 }
89
90
RelDFHalf(const RelDFHalf & o)91 RelDFHalf::RelDFHalf(const RelDFHalf& o) : RelDFBase(o.cartesian_) {
92 basis_ = o.basis_;
93 dfhalf_[0] = o.dfhalf_[0]->copy();
94 dfhalf_[1] = o.dfhalf_[1]->copy();
95 }
96
97
apply_J() const98 shared_ptr<RelDFHalf> RelDFHalf::apply_J() const {
99 return make_shared<RelDFHalf>(array<shared_ptr<DFHalfDist>,2>{{dfhalf_[0]->apply_J(), dfhalf_[1]->apply_J()}}, cartesian_, basis_);
100 }
101
102
apply_JJ() const103 shared_ptr<RelDFHalf> RelDFHalf::apply_JJ() const {
104 return make_shared<RelDFHalf>(array<shared_ptr<DFHalfDist>,2>{{dfhalf_[0]->apply_JJ(), dfhalf_[1]->apply_JJ()}}, cartesian_, basis_);
105 }
106
107
merge_b1(shared_ptr<RelDFHalf> o) const108 shared_ptr<RelDFHalf> RelDFHalf::merge_b1(shared_ptr<RelDFHalf> o) const {
109 assert(cartesian() == o->cartesian() && basis().size() == o->basis().size());
110 for (int i = 0; i != basis().size(); ++i)
111 assert(*basis_[i] == *o->basis_[i]);
112 return make_shared<RelDFHalf>(array<shared_ptr<DFHalfDist>,2>{{get_real()->merge_b1(o->get_real()), get_imag()->merge_b1(o->get_imag())}}, cartesian_, basis_);
113 }
114
115
slice_b1(const int slice_start,const int slice_size) const116 shared_ptr<RelDFHalf> RelDFHalf::slice_b1(const int slice_start, const int slice_size) const {
117 return make_shared<RelDFHalf>(array<shared_ptr<DFHalfDist>,2>{{get_real()->slice_b1(slice_start, slice_size),
118 get_imag()->slice_b1(slice_start, slice_size)}}, cartesian_, basis_);
119 }
120
121
set_sum_diff() const122 void RelDFHalf::set_sum_diff() const {
123 df2_[0] = dfhalf_[0]->copy();
124 df2_[0]->ax_plus_y(1.0, dfhalf_[1]);
125 df2_[1] = dfhalf_[0]->copy();
126 df2_[1]->ax_plus_y(-1.0, dfhalf_[1]);
127 }
128
129
ax_plus_y(complex<double> a,shared_ptr<const RelDFHalf> o)130 void RelDFHalf::ax_plus_y(complex<double> a, shared_ptr<const RelDFHalf> o) {
131 if (imag(a) == 0.0) {
132 const double fac = real(a);
133 dfhalf_[0]->ax_plus_y(fac, o->dfhalf_[0]);
134 dfhalf_[1]->ax_plus_y(fac, o->dfhalf_[1]);
135 } else if (real(a) == 0.0) {
136 const double fac = imag(a);
137 dfhalf_[0]->ax_plus_y(-fac, o->dfhalf_[1]);
138 dfhalf_[1]->ax_plus_y( fac, o->dfhalf_[0]);
139 } else {
140 const double rfac = real(a);
141 dfhalf_[0]->ax_plus_y(rfac, o->dfhalf_[0]);
142 dfhalf_[1]->ax_plus_y(rfac, o->dfhalf_[1]);
143 const double ifac = imag(a);
144 dfhalf_[0]->ax_plus_y(-ifac, o->dfhalf_[1]);
145 dfhalf_[1]->ax_plus_y( ifac, o->dfhalf_[0]);
146 }
147 }
148
149
transform_occ(shared_ptr<const ZMatrix> rdm1) const150 shared_ptr<RelDFHalf> RelDFHalf::transform_occ(shared_ptr<const ZMatrix> rdm1) const {
151 shared_ptr<const Matrix> rdm1r = rdm1->get_real_part();
152 shared_ptr<const Matrix> rdm1i = rdm1->get_imag_part();
153
154 auto dfhalf0 = dfhalf_[0]->transform_occ(rdm1r);
155 auto dfhalf1 = dfhalf_[1]->transform_occ(rdm1r);
156 dfhalf0->ax_plus_y(-1.0, dfhalf_[1]->transform_occ(rdm1i));
157 dfhalf1->ax_plus_y( 1.0, dfhalf_[0]->transform_occ(rdm1i));
158 return make_shared<RelDFHalf>(array<shared_ptr<DFHalfDist>,2>{{dfhalf0, dfhalf1}}, cartesian_, basis_);
159 }
160
161
matches(shared_ptr<const RelDFHalf> o) const162 bool RelDFHalf::matches(shared_ptr<const RelDFHalf> o) const {
163 return cartesian_.second == o->cartesian().second && basis_[0]->basis(1) == o->basis_[0]->basis(1) && alpha_matches(o);
164 }
165
166
alpha_matches(shared_ptr<const Breit2Index> o) const167 bool RelDFHalf::alpha_matches(shared_ptr<const Breit2Index> o) const {
168 assert(basis_.size() == 1);
169 return basis_[0]->alpha_comp() == o->index().second;
170 }
171
172
alpha_matches(shared_ptr<const RelDFHalf> o) const173 bool RelDFHalf::alpha_matches(shared_ptr<const RelDFHalf> o) const {
174 assert(basis_.size() == 1);
175 return basis_[0]->alpha_comp() == o->basis()[0]->alpha_comp();
176 }
177
178
179 // assumes you are multiplying breit2index by 2nd integral, not first (see alpha_matches)
multiply_breit2index(shared_ptr<const Breit2Index> bt) const180 shared_ptr<RelDFHalf> RelDFHalf::multiply_breit2index(shared_ptr<const Breit2Index> bt) const {
181 assert(basis_.size() == 1);
182 array<shared_ptr<DFHalfDist>,2> d = {{ dfhalf_[0]->apply_J(bt->data()), dfhalf_[1]->apply_J(bt->data())}};
183
184 vector<shared_ptr<const SpinorInfo>> spinor = { make_shared<const SpinorInfo>(basis_[0]->basis(), bt->index().first, bt->index().second) };
185 return make_shared<RelDFHalf>(d, cartesian_, spinor);
186 }
187
188
split(const bool docopy)189 list<shared_ptr<RelDFHalf>> RelDFHalf::split(const bool docopy) {
190 list<shared_ptr<RelDFHalf>> out;
191 for (auto i = basis().begin(); i != basis().end(); ++i) {
192 if (i == basis().begin() && docopy) {
193 out.push_back(make_shared<RelDFHalf>(dfhalf_, cartesian_, vector<shared_ptr<const SpinorInfo>>{*i}));
194 } else {
195 // TODO Any way to avoid copying?
196 array<shared_ptr<DFHalfDist>,2> d = {{ dfhalf_[0]->copy(), dfhalf_[1]->copy() }};
197 out.push_back(make_shared<RelDFHalf>(d, cartesian_, vector<shared_ptr<const SpinorInfo>>{*i}));
198 }
199 }
200 return out;
201 }
202
203
back_transform(shared_ptr<const Matrix> r,shared_ptr<const Matrix> i,const bool imag) const204 shared_ptr<DFDist> RelDFHalfB::back_transform(shared_ptr<const Matrix> r, shared_ptr<const Matrix> i, const bool imag) const {
205 shared_ptr<DFDist> out;
206 if (!imag) {
207 out = dfhalf_[0]->back_transform(r);
208 out->ax_plus_y(-1.0, dfhalf_[1]->back_transform(i));
209 } else {
210 out = dfhalf_[0]->back_transform(i);
211 out->ax_plus_y(1.0, dfhalf_[1]->back_transform(r));
212 }
213 return out;
214 }
215