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