1 //
2 // BAGEL - Brilliantly Advanced General Electronic Structure Library
3 // Filename: orthogonal.cc
4 // Copyright (C) 2018 Toru Shiozaki
5 //
6 // Author: Jae Woo Park <jwpk1201@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 #include <bagel_config.h>
26 #ifdef COMPILE_SMITH
27 
28 #include <numeric>
29 #include <src/smith/moint.h>
30 #include <src/smith/orthogonal.h>
31 
32 using namespace std;
33 using namespace bagel;
34 using namespace bagel::SMITH;
35 
Orthogonal_Basis(shared_ptr<const SMITH_Info<double>> info,const IndexRange c,const IndexRange a,const IndexRange v,vector<double> f,vector<double> e0,shared_ptr<const Matrix> fact,shared_ptr<const Denom<double>> d,const bool residual)36 Orthogonal_Basis::Orthogonal_Basis(shared_ptr<const SMITH_Info<double>> info, const IndexRange c, const IndexRange a, const IndexRange v,
37 vector<double> f, vector<double> e0, shared_ptr<const Matrix> fact, shared_ptr<const Denom<double>> d, const bool residual) : closed_(c), active_(a), virt_(v), eig_(f), e0all_(e0) {
38   nact_ = info->nact();
39   nclosed_ = info->nclosed();
40   nvirt_ = info->nvirt();
41   nocc_ = nact_ + nclosed_;
42   ncore_ = info->ncore();
43   nclo_ = nclosed_ - ncore_;
44   norb_ = nocc_ + nvirt_;
45   nstates_ = info->ciwfn()->nstates();
46 
47   d_ = d;
48 
49   fockact_ = fact->copy();
50   sssr_ = info->sssr();
51   imag_ = info->shift_imag();
52   shift_ = info->shift();
53 
54   to_denom_[Excitations::arbs] = "xx";
55   to_denom_[Excitations::arbi] = "x";
56   to_denom_[Excitations::airj] = "h";
57   to_denom_[Excitations::risj] = "hh";
58   to_denom_[Excitations::airs] = "xh";
59   to_denom_[Excitations::arst] = "xxh";
60   to_denom_[Excitations::rist] = "xhh";
61   to_denom_[Excitations::aibj] = "";
62 
63   int keyoffset = closed_.nblock() + active_.nblock() + virt_.nblock();
64 
65   // Now we have interms
66   // sssr ---- state 0   0 1 2 3 4 5 6 7
67   //           state 1   0 1 2 3 4 5 6 7
68   //           state 2   0 1 2 3 4 5 6 7 ...
69   // msmr ----           0 1 2 3 4 5 6 7(0) 7(1) 7(2)
70   if (sssr_) {
71     for (int istate = 0; istate != nstates_; ++istate) {
72       for (int iext = Excitations::arbs; iext != Excitations::aibj; ++iext) {
73         const size_t ndim = d->shalf(to_denom_.at(iext), istate).ndim();
74         const int maxtile = max(((int)(ndim / 255) + 1), info->maxtile());
75         interm_.push_back(IndexRange(ndim, maxtile, keyoffset));
76         keyoffset += interm_[iext].nblock();
77       }
78       interm_.push_back(IndexRange(0));
79     }
80   } else {
81     for (int iext = Excitations::arbs; iext != Excitations::aibj; ++iext) {
82       const size_t ndim = d->shalf(to_denom_.at(iext), 0).ndim();
83       const int maxtile = max(((int)(ndim / 255) + 1), info->maxtile());
84       interm_.push_back(IndexRange(ndim, maxtile, keyoffset));
85       keyoffset += interm_[iext].nblock();
86     }
87     interm_.push_back(IndexRange(0));
88   }
89 
90   for (int istate = 0; istate != nstates_; ++istate) {
91     auto tmp = make_shared<MultiTensor_<double>>(Excitations::total + (sssr_ ? 0 : nstates_-1));
92     for (int iext = Excitations::arbs; iext != Excitations::aibj; ++iext) {
93       (*tmp)[iext] = init_data(iext, istate);
94     }
95     // aibj depends on whether sssr or msmr
96     if (sssr_) {
97       const int pos = Excitations::aibj;
98       (*tmp)[pos] = init_data(Excitations::aibj, istate);
99     } else {
100       for (int ist = 0; ist != nstates_; ++ist) {
101         const int pos = Excitations::aibj + ist;
102         (*tmp)[pos] = init_data(Excitations::aibj, istate);
103       }
104     }
105 
106     data_.push_back(tmp);
107     denom_.push_back(tmp->clone());
108   }
109 
110   set_denom(d);
111 
112   if (residual) basis_type_ = Basis_Type::residual;
113   else basis_type_ = Basis_Type::amplitude;
114 
115   zero();
116 }
117 
118 
Orthogonal_Basis(const Orthogonal_Basis & o,const bool clone,const bool residual)119 Orthogonal_Basis::Orthogonal_Basis(const Orthogonal_Basis& o, const bool clone, const bool residual) {
120   to_denom_ = o.to_denom_;
121 
122   closed_ = o.closed_;
123   active_ = o.active_;
124   virt_ = o.virt_;
125   eig_ = o.eig_;
126   e0all_ = o.e0all_;
127   fockact_ = o.fockact_;
128 
129   nact_ = o.nact_;
130   nclosed_ = o.nclosed_;
131   nvirt_ = o.nvirt_;
132   nocc_ = o.nocc_;
133   ncore_ = o.ncore_;
134   nclo_ = o.nclo_;
135   norb_ = o.norb_;
136   nstates_ = o.nstates_;
137 
138   d_ = o.d_;
139 
140   sssr_ = o.sssr_;
141   imag_ = o.imag_;
142   shift_ = o.shift_;
143 
144   interm_ = o.interm_;
145 
146   data_.resize(nstates_);
147   for (int i = 0; i != nstates_; ++i) {
148     if (clone) {
149       data_[i] = o.data_[i]->clone();
150     } else {
151       data_[i] = o.data_[i]->copy();
152     }
153   }
154 
155   denom_.resize(nstates_);
156   for (int i = 0; i != nstates_; ++i)
157     denom_[i] = o.denom_[i]->copy();
158 
159   if (residual) basis_type_ = Basis_Type::residual;
160   else basis_type_ = Basis_Type::amplitude;
161 }
162 
163 
init_data(const int iext,const int istate)164 shared_ptr<Tensor_<double>> Orthogonal_Basis::init_data(const int iext, const int istate) {
165   // Now we use intermediate indices instead of orbital, and is somewhat complicated...
166   // Interm always runs faster.
167   unordered_set<size_t> sparse;
168   shared_ptr<Tensor_<double>> out;
169   const int dataindex = sssr_ ? iext + istate * Excitations::total : iext;
170   switch(iext) {
171     case Excitations::arbs:
172       for (auto& i3 : virt_)
173         for (auto& i1 : virt_)
174           for (auto& i0o : interm_[dataindex])
175             sparse.insert(generate_hash_key(i0o, i1, i3));
176       out = make_shared<Tensor_<double>>(vector<IndexRange>{interm_[dataindex], virt_, virt_}, /*kramers=*/false, sparse, /*alloc=*/true);
177       break;
178     case Excitations::arbi:
179       for (auto& i3 : virt_)
180         for (auto& i2 : closed_)
181           for (auto& i1 : virt_)
182             for (auto& i0o : interm_[dataindex])
183               sparse.insert(generate_hash_key(i0o, i1, i2, i3));
184       out = make_shared<Tensor_<double>>(vector<IndexRange>{interm_[dataindex], virt_, closed_, virt_}, /*kramers=*/false, sparse, /*alloc=*/true);
185       break;
186     case Excitations::airj:
187       for (auto& i2 : closed_)
188         for (auto& i1 : virt_)
189           for (auto& i0 : closed_)
190             for (auto& i0o : interm_[dataindex])
191               sparse.insert(generate_hash_key(i0o, i0, i1, i2));
192       out = make_shared<Tensor_<double>>(vector<IndexRange>{interm_[dataindex], closed_, virt_, closed_}, /*kramers=*/false, sparse, /*alloc=*/true);
193       break;
194     case Excitations::risj:
195       for (auto& i2 : closed_)
196         for (auto& i0 : closed_)
197           for (auto& i0o : interm_[dataindex])
198             sparse.insert(generate_hash_key(i0o, i0, i2));
199       out = make_shared<Tensor_<double>>(vector<IndexRange>{interm_[dataindex], closed_, closed_}, /*kramers=*/false, sparse, /*alloc=*/true);
200       break;
201     case Excitations::airs:
202       for (auto& i1 : virt_)
203         for (auto& i0 : closed_)
204           for (auto& i0o : interm_[dataindex])
205             sparse.insert(generate_hash_key(i0o, i0, i1));
206       out = make_shared<Tensor_<double>>(vector<IndexRange>{interm_[dataindex], closed_, virt_}, /*kramers=*/false, sparse, /*alloc=*/true);
207       break;
208     case Excitations::arst:
209       for (auto& i1 : virt_)
210         for (auto& i0o : interm_[dataindex])
211           sparse.insert(generate_hash_key(i0o, i1));
212       out = make_shared<Tensor_<double>>(vector<IndexRange>{interm_[dataindex], virt_}, /*kramers=*/false, sparse, /*alloc=*/true);
213       break;
214     case Excitations::rist:
215       for (auto& i0 : closed_)
216         for (auto& i0o : interm_[dataindex])
217           sparse.insert(generate_hash_key(i0o, i0));
218       out = make_shared<Tensor_<double>>(vector<IndexRange>{interm_[dataindex], closed_}, /*kramers=*/false, sparse, /*alloc=*/true);
219       break;
220     case Excitations::aibj:
221       for (auto& i3 : virt_)
222         for (auto& i2 : closed_)
223           for (auto& i1 : virt_)
224             for (auto& i0 : closed_)
225               sparse.insert(generate_hash_key(i0, i1, i2, i3));
226       out = make_shared<Tensor_<double>>(vector<IndexRange>{closed_, virt_, closed_, virt_}, /*kramers=*/false, sparse, /*alloc=*/true);
227       break;
228   }
229   return out;
230 }
231 
232 
weight_by_denom(const int istate,shared_ptr<const MultiTensor_<double>> original) const233 shared_ptr<MultiTensor_<double>> Orthogonal_Basis::weight_by_denom(const int istate, shared_ptr<const MultiTensor_<double>> original) const {
234   auto out = make_shared<MultiTensor_<double>>(Excitations::total + (sssr_ ? 0 : nstates_-1));
235   for (int iext = Excitations::arbs; iext != Excitations::total; ++iext) {
236     const int dataindex = sssr_ ? iext + istate * Excitations::total : iext;
237     const shared_ptr<Tensor_<double>> dtensor = denom_[istate]->at(iext);
238     shared_ptr<const Tensor_<double>> ttensor = original->at(iext);
239     switch(iext) {
240       case Excitations::arbs:
241         out->at(iext) = ttensor->clone();
242         for (auto& i3 : virt_)
243           for (auto& i1 : virt_)
244             for (auto& i0o : interm_[dataindex]) {
245               if (!dtensor->is_local(i0o, i1, i3)) continue;
246               const unique_ptr<double[]> ddata = dtensor->get_block(i0o, i1, i3);
247               unique_ptr<double[]> tdata = ttensor->get_block(i0o, i1, i3);
248               const size_t intermsize = dtensor->get_size(i0o, i1, i3);
249               for (size_t i = 0; i != intermsize; ++i) {
250                 tdata[i] *= ddata[i];
251               }
252               out->at(iext)->add_block(tdata, i0o, i1, i3);
253             }
254         break;
255       case Excitations::arbi:
256         out->at(iext) = ttensor->clone();
257         for (auto& i3 : virt_)
258           for (auto& i2 : closed_)
259             for (auto& i1 : virt_)
260               for (auto& i0o : interm_[dataindex]) {
261                 if (!dtensor->is_local(i0o, i1, i2, i3)) continue;
262                 const unique_ptr<double[]> ddata = dtensor->get_block(i0o, i1, i2, i3);
263                 unique_ptr<double[]> tdata = ttensor->get_block(i0o, i1, i2, i3);
264                 const size_t intermsize = dtensor->get_size(i0o, i1, i2, i3);
265                 for (size_t i = 0; i != intermsize; ++i) {
266                   tdata[i] *= ddata[i];
267                 }
268                 out->at(iext)->add_block(tdata, i0o, i1, i2, i3);
269               }
270         break;
271       case Excitations::airj:
272         out->at(iext) = ttensor->clone();
273         for (auto& i2 : closed_)
274           for (auto& i1 : virt_)
275             for (auto& i0 : closed_)
276               for (auto& i0o : interm_[dataindex]) {
277                 if (!dtensor->is_local(i0o, i0, i1, i2)) continue;
278                 const unique_ptr<double[]> ddata = dtensor->get_block(i0o, i0, i1, i2);
279                 unique_ptr<double[]> tdata = ttensor->get_block(i0o, i0, i1, i2);
280                 const size_t intermsize = dtensor->get_size(i0o, i0, i1, i2);
281                 for (size_t i = 0; i != intermsize; ++i) {
282                   tdata[i] *= ddata[i];
283                 }
284                 out->at(iext)->add_block(tdata, i0o, i0, i1, i2);
285               }
286         break;
287       case Excitations::risj:
288         out->at(iext) = ttensor->clone();
289         for (auto& i2 : closed_)
290           for (auto& i0 : closed_)
291             for (auto& i0o : interm_[dataindex]) {
292               if (!dtensor->is_local(i0o, i0, i2)) continue;
293               const unique_ptr<double[]> ddata = dtensor->get_block(i0o, i0, i2);
294               unique_ptr<double[]> tdata = ttensor->get_block(i0o, i0, i2);
295               const size_t intermsize = dtensor->get_size(i0o, i0, i2);
296               for (size_t i = 0; i != intermsize; ++i) {
297                 tdata[i] *= ddata[i];
298               }
299               out->at(iext)->add_block(tdata, i0o, i0, i2);
300             }
301         break;
302       case Excitations::airs:
303         out->at(iext) = ttensor->clone();
304         for (auto& i1 : virt_)
305           for (auto& i0 : closed_)
306             for (auto& i0o : interm_[dataindex]) {
307               if (!dtensor->is_local(i0o, i0, i1)) continue;
308               const unique_ptr<double[]> ddata = dtensor->get_block(i0o, i0, i1);
309               unique_ptr<double[]> tdata = ttensor->get_block(i0o, i0, i1);
310               const size_t intermsize = dtensor->get_size(i0o, i0, i1);
311               for (size_t i = 0; i != intermsize; ++i) {
312                 tdata[i] *= ddata[i];
313               }
314               out->at(iext)->add_block(tdata, i0o, i0, i1);
315             }
316         break;
317       case Excitations::arst:
318         out->at(iext) = ttensor->clone();
319         for (auto& i1 : virt_)
320           for (auto& i0o : interm_[dataindex]) {
321             if (!dtensor->is_local(i0o, i1)) continue;
322             const unique_ptr<double[]> ddata = dtensor->get_block(i0o, i1);
323             unique_ptr<double[]> tdata = ttensor->get_block(i0o, i1);
324             const size_t intermsize = dtensor->get_size(i0o, i1);
325             for (size_t i = 0; i != intermsize; ++i) {
326               tdata[i] *= ddata[i];
327             }
328             out->at(iext)->add_block(tdata, i0o, i1);
329           }
330         break;
331       case Excitations::rist:
332         out->at(iext) = ttensor->clone();
333         for (auto& i0 : closed_)
334           for (auto& i0o : interm_[dataindex]) {
335             if (!dtensor->is_local(i0o, i0)) continue;
336             const unique_ptr<double[]> ddata = dtensor->get_block(i0o, i0);
337             unique_ptr<double[]> tdata = ttensor->get_block(i0o, i0);
338             const size_t intermsize = dtensor->get_size(i0o, i0);
339             for (size_t i = 0; i != intermsize; ++i) {
340               tdata[i] *= ddata[i];
341             }
342             out->at(iext)->add_block(tdata, i0o, i0);
343           }
344        break;
345       case Excitations::aibj:
346         for (int ist = 0; ist != nstates_; ++ist) {
347           if (!sssr_ || ist == istate) {
348             const int pos = iext + (sssr_ ? 0 : ist);
349             out->at(pos) = original->at(pos)->clone();
350             for (auto& i3 : virt_)
351               for (auto& i2 : closed_)
352                 for (auto& i1 : virt_)
353                   for (auto& i0 : closed_) {
354                     if (!denom_[istate]->at(pos)->is_local(i0, i1, i2, i3)) continue;
355                       const unique_ptr<double[]> ddata = denom_[istate]->at(pos)->get_block(i0, i1, i2, i3);
356                       unique_ptr<double[]> tdata = original->at(pos)->get_block(i0, i1, i2, i3);
357                       const size_t intermsize = denom_[istate]->at(pos)->get_size(i0, i1, i2, i3);
358                       for (size_t i = 0; i != intermsize; ++i) {
359                         tdata[i] *= ddata[i];
360                       }
361                       out->at(pos)->add_block(tdata, i0, i1, i2, i3);
362                   }
363           }
364         }
365       break;
366     }
367   }
368   mpi__->barrier();
369   return out;
370 }
371 
372 
get_contravariant(const int istate,const bool weight) const373 shared_ptr<MultiTensor_<double>> Orthogonal_Basis::get_contravariant(const int istate, const bool weight) const {
374   auto out = make_shared<MultiTensor_<double>>(Excitations::total + (sssr_ ? 0 : nstates_-1));
375   for (int iext = Excitations::arbs; iext != Excitations::total; ++iext) {
376     const int dataindex = sssr_ ? iext + istate * Excitations::total : iext;
377     const shared_ptr<Tensor_<double>> dtensor = data_[istate]->at(iext);
378     switch(iext) {
379       case Excitations::arbs:
380         out->at(iext) = dtensor->copy();
381         break;
382       case Excitations::arbi:
383         out->at(iext) = dtensor->clone();
384         for (auto& i3 : virt_)
385           for (auto& i2 : closed_)
386             for (auto& i1 : virt_)
387               for (auto& i0o : interm_[dataindex]) {
388                 if (!dtensor->is_local(i0o, i1, i2, i3)) continue;
389                 unique_ptr<double[]> data0 = dtensor->get_block(i0o, i1, i2, i3);
390                 unique_ptr<double[]> data1 = dtensor->get_block(i0o, i3, i2, i1);
391                 sort_indices<0,3,2,1,2,1,-1,1>(data1, data0, i0o.size(), i3.size(), i2.size(), i1.size());
392                 out->at(iext)->add_block(data0, i0o, i1, i2, i3);
393               }
394         break;
395       case Excitations::airj:
396         out->at(iext) = dtensor->clone();
397         for (auto& i2 : closed_)
398           for (auto& i1 : virt_)
399             for (auto& i0 : closed_)
400               for (auto& i0o : interm_[dataindex]) {
401                 if (!dtensor->is_local(i0o, i0, i1, i2)) continue;
402                 unique_ptr<double[]> data0 = dtensor->get_block(i0o, i0, i1, i2);
403                 unique_ptr<double[]> data1 = dtensor->get_block(i0o, i2, i1, i0);
404                 sort_indices<0,3,2,1,2,1,-1,1>(data1, data0, i0o.size(), i2.size(), i1.size(), i0.size());
405                 out->at(iext)->add_block(data0, i0o, i0, i1, i2);
406               }
407         break;
408       case Excitations::risj:
409         out->at(iext) = dtensor->copy();
410         break;
411       case Excitations::airs:
412         out->at(iext) = dtensor->copy();
413         break;
414       case Excitations::arst:
415         out->at(iext) = dtensor->copy();
416         break;
417       case Excitations::rist:
418         out->at(iext) = dtensor->copy();
419         break;
420       case Excitations::aibj:
421         for (int ist = 0; ist != nstates_; ++ist) {
422           if (!sssr_ || ist == istate) {
423             const int pos = iext + (sssr_ ? 0 : ist);
424             out->at(pos) = data_[istate]->at(pos)->clone();
425             for (auto& i3 : virt_)
426               for (auto& i2 : closed_)
427                 for (auto& i1 : virt_)
428                   for (auto& i0 : closed_) {
429                     if (!data_[istate]->at(pos)->is_local(i0, i1, i2, i3)) continue;
430                     unique_ptr<double[]> data0 = data_[istate]->at(pos)->get_block(i0, i1, i2, i3);
431                     unique_ptr<double[]> data1 = data_[istate]->at(pos)->get_block(i0, i3, i2, i1);
432                     sort_indices<0,3,2,1,8,1,-4,1>(data1, data0, i0.size(), i3.size(), i2.size(), i1.size());
433                     out->at(pos)->add_block(data0, i0, i1, i2, i3);
434                   }
435           }
436         }
437         break;
438     }
439   }
440   mpi__->barrier();
441 
442   if (weight && imag_) {
443     // weight by denominator, so that we can get the correct energy
444     out = weight_by_denom(istate, out);
445   }
446   return out;
447 }
448 
449 
set_denom(shared_ptr<const Denom<double>> d)450 void Orthogonal_Basis::set_denom(shared_ptr<const Denom<double>> d) {
451   for (int istate = 0; istate != nstates_; ++istate) {
452     e0_ = e0all_[istate];
453     for (int iext = Excitations::arbs; iext != Excitations::total; ++iext) {
454       const int dataindex = sssr_ ? iext + istate * Excitations::total : iext;
455       const shared_ptr<Tensor_<double>> dtensor = denom_[istate]->at(iext);
456       switch(iext) {
457         case Excitations::arbs:
458           for (auto& i3 : virt_)
459             for (auto& i1 : virt_)
460               for (auto& i0o : interm_[dataindex]) {
461                 if (!dtensor->is_local(i0o, i1, i3)) continue;
462                 unique_ptr<double[]> data0(new double[dtensor->get_size(i0o, i1, i3)]);
463                 size_t iall = 0;
464                 for (int j3 = i3.offset(); j3 != i3.offset()+i3.size(); ++j3)
465                   for (int j1 = i1.offset(); j1 != i1.offset()+i1.size(); ++j1)
466                     for (int j0o = i0o.offset(); j0o != i0o.offset()+i0o.size(); ++j0o, ++iall)
467                       data0[iall] = eig_[j3] + eig_[j1] + d->denom(to_denom_.at(iext), istate, j0o) - e0_;
468                 denom_[istate]->at(iext)->put_block(data0, i0o, i1, i3);
469               }
470           break;
471         case Excitations::arbi:
472           for (auto& i3 : virt_)
473             for (auto& i2 : closed_)
474               for (auto& i1 : virt_)
475                 for (auto& i0o : interm_[dataindex]) {
476                   if (!dtensor->is_local(i0o, i1, i2, i3)) continue;
477                   unique_ptr<double[]> data0(new double[dtensor->get_size(i0o, i1, i2, i3)]);
478                   size_t iall = 0;
479                   for (int j3 = i3.offset(); j3 != i3.offset()+i3.size(); ++j3)
480                     for (int j2 = i2.offset(); j2 != i2.offset()+i2.size(); ++j2)
481                       for (int j1 = i1.offset(); j1 != i1.offset()+i1.size(); ++j1)
482                         for (int j0o = i0o.offset(); j0o != i0o.offset()+i0o.size(); ++j0o, ++iall)
483                           data0[iall] = eig_[j3] - eig_[j2] + eig_[j1] + d->denom(to_denom_.at(iext), istate, j0o) - e0_;
484                   denom_[istate]->at(iext)->put_block(data0, i0o, i1, i2, i3);
485                 }
486           break;
487         case Excitations::airj:
488           for (auto& i2 : closed_)
489             for (auto& i1 : virt_)
490               for (auto& i0 : closed_)
491                 for (auto& i0o : interm_[dataindex]) {
492                   if (!dtensor->is_local(i0o, i0, i1, i2)) continue;
493                   unique_ptr<double[]> data0(new double[dtensor->get_size(i0o, i0, i1, i2)]);
494                   size_t iall = 0;
495                   for (int j2 = i2.offset(); j2 != i2.offset()+i2.size(); ++j2)
496                     for (int j1 = i1.offset(); j1 != i1.offset()+i1.size(); ++j1)
497                       for (int j0 = i0.offset(); j0 != i0.offset()+i0.size(); ++j0)
498                         for (int j0o = i0o.offset(); j0o != i0o.offset()+i0o.size(); ++j0o, ++iall)
499                           data0[iall] = - eig_[j2] + eig_[j1] - eig_[j0] + d->denom(to_denom_.at(iext), istate, j0o) - e0_;
500                   denom_[istate]->at(iext)->put_block(data0, i0o, i0, i1, i2);
501                 }
502           break;
503         case Excitations::risj:
504           for (auto& i2 : closed_)
505             for (auto& i0 : closed_)
506               for (auto& i0o : interm_[dataindex]) {
507                 if (!dtensor->is_local(i0o, i0, i2)) continue;
508                 unique_ptr<double[]> data0(new double[dtensor->get_size(i0o, i0, i2)]);
509                 size_t iall = 0;
510                 for (int j2 = i2.offset(); j2 != i2.offset()+i2.size(); ++j2)
511                   for (int j0 = i0.offset(); j0 != i0.offset()+i0.size(); ++j0)
512                     for (int j0o = i0o.offset(); j0o != i0o.offset()+i0o.size(); ++j0o, ++iall)
513                       data0[iall] = - eig_[j2] - eig_[j0] + d->denom(to_denom_.at(iext), istate, j0o) - e0_;
514                 denom_[istate]->at(iext)->put_block(data0, i0o, i0, i2);
515               }
516           break;
517         case Excitations::airs:
518           for (auto& i1 : virt_)
519             for (auto& i0 : closed_)
520               for (auto& i0o : interm_[dataindex]) {
521                 if (!dtensor->is_local(i0o, i0, i1)) continue;
522                 unique_ptr<double[]> data0(new double[dtensor->get_size(i0o, i0, i1)]);
523                 size_t iall = 0;
524                 for (int j1 = i1.offset(); j1 != i1.offset()+i1.size(); ++j1)
525                   for (int j0 = i0.offset(); j0 != i0.offset()+i0.size(); ++j0)
526                     for (int j0o = i0o.offset(); j0o != i0o.offset()+i0o.size(); ++j0o, ++iall)
527                       data0[iall] = eig_[j1] - eig_[j0] + d->denom(to_denom_.at(iext), istate, j0o) - e0_;
528                 denom_[istate]->at(iext)->put_block(data0, i0o, i0, i1);
529               }
530           break;
531         case Excitations::arst:
532           for (auto& i1 : virt_)
533             for (auto& i0o : interm_[dataindex]) {
534               if (!dtensor->is_local(i0o, i1)) continue;
535               unique_ptr<double[]> data0(new double[dtensor->get_size(i0o, i1)]);
536               size_t iall = 0;
537               for (int j1 = i1.offset(); j1 != i1.offset()+i1.size(); ++j1)
538                 for (int j0o = i0o.offset(); j0o != i0o.offset()+i0o.size(); ++j0o, ++iall)
539                   data0[iall] = eig_[j1] + d->denom(to_denom_.at(iext), istate, j0o) - e0_;
540               denom_[istate]->at(iext)->put_block(data0, i0o, i1);
541             }
542           break;
543         case Excitations::rist:
544           for (auto& i0 : closed_)
545             for (auto& i0o : interm_[dataindex]) {
546               if (!dtensor->is_local(i0o, i0)) continue;
547               unique_ptr<double[]> data0(new double[dtensor->get_size(i0o, i0)]);
548               size_t iall = 0;
549               for (int j0 = i0.offset(); j0 != i0.offset()+i0.size(); ++j0)
550                 for (int j0o = i0o.offset(); j0o != i0o.offset()+i0o.size(); ++j0o, ++iall)
551                   data0[iall] = - eig_[j0] + d->denom(to_denom_.at(iext), istate, j0o) - e0_;
552               denom_[istate]->at(iext)->put_block(data0, i0o, i0);
553             }
554          break;
555         case Excitations::aibj:
556           for (int ist = 0; ist != nstates_; ++ist) {
557             double e0loc = e0_ - e0all_[ist];
558             if (!sssr_ || ist == istate) {
559               const int pos = iext + (sssr_ ? 0 : ist);
560               for (auto& i3 : virt_)
561                 for (auto& i2 : closed_)
562                   for (auto& i1 : virt_)
563                     for (auto& i0 : closed_) {
564                       if (!denom_[istate]->at(pos)->is_local(i0, i1, i2, i3)) continue;
565                       unique_ptr<double[]> data0(new double[denom_[istate]->at(pos)->get_size(i0, i1, i2, i3)]);
566                       size_t iall = 0;
567                       for (int j3 = i3.offset(); j3 != i3.offset()+i3.size(); ++j3)
568                         for (int j2 = i2.offset(); j2 != i2.offset()+i2.size(); ++j2)
569                           for (int j1 = i1.offset(); j1 != i1.offset()+i1.size(); ++j1)
570                             for (int j0 = i0.offset(); j0 != i0.offset()+i0.size(); ++j0, ++iall)
571                               data0[iall] = - eig_[j0] - eig_[j2] + eig_[j1] + eig_[j3] + e0loc;
572                       denom_[istate]->at(pos)->put_block(data0, i0, i1, i2, i3);
573                     }
574               }
575             }
576             break;
577       }
578     }
579   }
580   mpi__->barrier();
581 }
582 
583 
transform_to_orthogonal(shared_ptr<const MultiTensor_<double>> t,int istate)584 void Orthogonal_Basis::transform_to_orthogonal(shared_ptr<const MultiTensor_<double>> t, int istate) {
585   // we put the transformed data in data_[istate].
586   data_[istate]->zero();
587   for (int ist = 0; ist != nstates_; ++ist) {
588     if (!t->at(ist)) continue;
589     for (int iext = Excitations::arbs; iext != Excitations::total; ++iext) {
590       const int dataindex = sssr_ ? iext + istate * Excitations::total : iext;
591       shared_ptr<const Tensor_<double>> tensor = t->at(ist);
592       const MatView ishalf = (iext != Excitations::aibj) ? shalf(iext, ist) : shalf(0, ist);
593       switch(iext) {
594         case Excitations::arbs:
595           for (auto& i2 : active_)
596             for (auto& i0 : active_) {
597               auto create_transp = [this](const MatView shalf, const Index& I0, const Index& I2, const Index& I0o) {
598                 unique_ptr<double[]> out(new double[I0.size()*I2.size()*I0o.size()]);
599                 for (int j2 = I2.offset(), k = 0; j2 != I2.offset()+I2.size(); ++j2)
600                   for (int j0 = I0.offset(); j0 != I0.offset()+I0.size(); ++j0, ++k)
601                     copy_n(shalf.element_ptr(I0o.offset(),(j0-nclosed_)+(j2-nclosed_)*nact_),
602                            I0o.size(), out.get()+I0o.size()*k);
603                 return move(out);
604               };
605               for (auto& i0o : interm_[dataindex]) {
606                 unique_ptr<double[]> transp = create_transp(ishalf, i0, i2, i0o);
607                 for (auto& i3 : virt_)
608                   for (auto& i1 : virt_) {
609                     if (!data_[istate]->at(iext)->is_local(i0o, i1, i3)) continue;
610                     const size_t blocksize = tensor->get_size(i0, i1, i2, i3);
611                     const unique_ptr<double[]> data0 = tensor->get_block(i0, i1, i2, i3);
612                     unique_ptr<double[]> data1(new double[blocksize]);
613                     // i0 i2 to be contracted
614                     sort_indices<0,2,1,3,0,1,1,1>(data0, data1, i0.size(), i1.size(), i2.size(), i3.size());
615                     unique_ptr<double[]> interm(new double[i1.size()*i3.size()*i0o.size()]);
616                     btas::gemm_impl<true>::call(CblasColMajor, CblasNoTrans, CblasNoTrans, i0o.size(), i1.size()*i3.size(), i0.size()*i2.size(),
617                                                 sqrt(0.5), transp.get(), i0o.size(), data1.get(), i0.size()*i2.size(), 0.0, interm.get(), i0o.size());
618                     data_[istate]->at(iext)->add_block(interm, i0o, i1, i3);
619                   }
620               }
621             }
622           break;
623         case Excitations::arbi:
624           for (auto& i0 : active_) {
625             auto create_transp = [this](const MatView shalf, const Index& I0, const Index& I0o) {
626               unique_ptr<double[]> out(new double[I0.size()*I0o.size()]);
627               for (int j0 = I0.offset(), k = 0; j0 != I0.offset()+I0.size(); ++j0, ++k)
628                 copy_n(shalf.element_ptr(I0o.offset(), j0-nclosed_), I0o.size(), out.get()+I0o.size()*k);
629               return move(out);
630             };
631             for (auto& i0o : interm_[dataindex]) {
632               unique_ptr<double[]> transp = create_transp(ishalf, i0, i0o);
633               for (auto& i3 : virt_)
634                 for (auto& i2 : closed_)
635                   for (auto& i1 : virt_) {
636                     if (!data_[istate]->at(iext)->is_local(i0o, i1, i2, i3)) continue;
637                     const size_t blocksize = tensor->get_size(i2, i3, i0, i1);
638                     const unique_ptr<double[]> data0 = tensor->get_block(i2, i3, i0, i1);
639                     unique_ptr<double[]> data2(new double[blocksize]);
640                     // i0 to be contracted
641                     sort_indices<2,3,0,1,0,1,1,1>(data0, data2, i2.size(), i3.size(), i0.size(), i1.size());
642                     const unique_ptr<double[]> data1 = tensor->get_block(i2, i1, i0, i3);
643                     sort_indices<2,1,0,3,2,3,1,3>(data1, data2, i2.size(), i1.size(), i0.size(), i3.size());
644                     unique_ptr<double[]> interm(new double[i1.size()*i2.size()*i3.size()*i0o.size()]);
645                     btas::gemm_impl<true>::call(CblasColMajor, CblasNoTrans, CblasNoTrans, i0o.size(), i1.size()*i2.size()*i3.size(), i0.size(),
646                                                 1.0, transp.get(), i0o.size(), data2.get(), i0.size(), 0.0, interm.get(), i0o.size());
647                     data_[istate]->at(iext)->add_block(interm, i0o, i1, i2, i3);
648                   }
649             }
650           }
651           break;
652         case Excitations::airj:
653           for (auto& i3 : active_) {
654             auto create_transp = [this](const MatView shalf, const Index& I3, const Index& I0o) {
655               unique_ptr<double[]> out(new double[I3.size()*I0o.size()]);
656               for (int j3 = I3.offset(), k = 0; j3 != I3.offset()+I3.size(); ++j3, ++k)
657                 copy_n(shalf.element_ptr(I0o.offset(),j3-nclosed_), I0o.size(), out.get()+I0o.size()*k);
658               return move(out);
659             };
660             for (auto& i0o : interm_[dataindex]) {
661               unique_ptr<double[]> transp = create_transp(ishalf, i3, i0o);
662               for (auto& i2 : closed_)
663                 for (auto& i1 : virt_)
664                   for (auto& i0 : closed_) {
665                     if (!data_[istate]->at(iext)->is_local(i0o, i0, i1, i2)) continue;
666                     const size_t blocksize = tensor->get_size(i2, i3, i0, i1);
667                     const unique_ptr<double[]> data0 = tensor->get_block(i2, i3, i0, i1);
668                     unique_ptr<double[]> data2(new double[blocksize]);
669                     // i3 to be contracted
670                     sort_indices<1,2,3,0,0,1,1,1>(data0, data2, i2.size(), i3.size(), i0.size(), i1.size());
671                     const unique_ptr<double[]> data1 = tensor->get_block(i0, i3, i2, i1);
672                     sort_indices<1,0,3,2,2,3,1,3>(data1, data2, i0.size(), i3.size(), i2.size(), i1.size());
673                     unique_ptr<double[]> interm(new double[i0.size()*i1.size()*i2.size()*i0o.size()]);
674                     btas::gemm_impl<true>::call(CblasColMajor, CblasNoTrans, CblasNoTrans, i0o.size(), i0.size()*i1.size()*i2.size(), i3.size(),
675                                                 1.0, transp.get(), i0o.size(), data2.get(), i3.size(), 0.0, interm.get(), i0o.size());
676                     data_[istate]->at(iext)->add_block(interm, i0o, i0, i1, i2);
677                   }
678             }
679           }
680           break;
681         case Excitations::risj:
682           for (auto& i3 : active_)
683             for (auto& i1 : active_) {
684               auto create_transp = [this](const MatView shalf, const Index& I1, const Index& I3, const Index& I0o) {
685                 unique_ptr<double[]> out(new double[I1.size()*I3.size()*I0o.size()]);
686                 for (int j3 = I3.offset(), k = 0; j3 != I3.offset()+I3.size(); ++j3)
687                   for (int j1 = I1.offset(); j1 != I1.offset()+I1.size(); ++j1, ++k)
688                     copy_n(shalf.element_ptr(I0o.offset(),(j1-nclosed_)+(j3-nclosed_)*nact_),
689                            I0o.size(), out.get()+I0o.size()*k);
690                 return move(out);
691               };
692               for (auto& i0o : interm_[dataindex]) {
693                 unique_ptr<double[]> transp = create_transp(ishalf, i1, i3, i0o);
694                 for (auto& i2 : closed_)
695                   for (auto& i0 : closed_) {
696                     if (!data_[istate]->at(iext)->is_local(i0o, i0, i2)) continue;
697                     const size_t blocksize = tensor->get_size(i0, i1, i2, i3);
698                     const unique_ptr<double[]> data0 = tensor->get_block(i0, i1, i2, i3);
699                     unique_ptr<double[]> data1(new double[blocksize]);
700                     // i1 i3 to be contracted
701                     sort_indices<1,3,0,2,0,1,1,1>(data0, data1, i0.size(), i1.size(), i2.size(), i3.size());
702                     unique_ptr<double[]> interm(new double[i0.size()*i2.size()*i0o.size()]);
703                     btas::gemm_impl<true>::call(CblasColMajor, CblasNoTrans, CblasNoTrans, i0o.size(), i0.size()*i2.size(), i1.size()*i3.size(),
704                                                 sqrt(0.5), transp.get(), i0o.size(), data1.get(), i1.size()*i3.size(), 0.0, interm.get(), i0o.size());
705                     data_[istate]->at(iext)->add_block(interm, i0o, i0, i2);
706                   }
707               }
708             }
709           break;
710         case Excitations::airs:
711           for (auto& i3 : active_)
712             for (auto& i2 : active_) {
713               auto create_transp = [this](const MatView shalf, const Index& I2, const Index& I3, const Index& I0o) {
714                 unique_ptr<double[]> out(new double[I2.size()*I3.size()*I0o.size()*2]);
715                 for (int j3 = I3.offset(), k = 0; j3 != I3.offset()+I3.size(); ++j3)
716                   for (int j2 = I2.offset(); j2 != I2.offset()+I2.size(); ++j2, ++k) {
717                     copy_n(shalf.element_ptr(I0o.offset(), (j2-nclosed_)+(j3-nclosed_)*nact_),
718                            I0o.size(), out.get()+I0o.size()*k);
719                     copy_n(shalf.element_ptr(I0o.offset(), (j2-nclosed_)+(j3-nclosed_)*nact_ + nact_*nact_),
720                            I0o.size(), out.get()+I0o.size()*(k+I2.size()*I3.size()));
721                   }
722                 return move(out);
723               };
724               for (auto& i0o : interm_[dataindex]) {
725                 unique_ptr<double[]> transp = create_transp(ishalf, i2, i3, i0o);
726                 for (auto& i1 : virt_)
727                   for (auto& i0 : closed_) {
728                     if (!data_[istate]->at(iext)->is_local(i0o, i0, i1)) continue;
729                     const size_t blocksize = tensor->get_size(i2, i3, i0, i1);
730                     const unique_ptr<double[]> data0 = tensor->get_block(i2, i3, i0, i1);
731                     const unique_ptr<double[]> data1 = tensor->get_block(i0, i3, i2, i1);
732                     unique_ptr<double[]> data2(new double[blocksize*2]);
733                     // i2 i3 to be contracted
734                     sort_indices<2,3,0,1,0,1,1,1>(data0.get(), data2.get()          , i2.size(), i3.size(), i0.size(), i1.size());
735                     sort_indices<0,3,2,1,0,1,1,1>(data1.get(), data2.get()+blocksize, i0.size(), i3.size(), i2.size(), i1.size());
736                     unique_ptr<double[]> interm(new double[i0.size()*i1.size()*i0o.size()]);
737                     unique_ptr<double[]> interm2(new double[i0.size()*i1.size()*i0o.size()]);
738                     btas::gemm_impl<true>::call(CblasColMajor, CblasNoTrans, CblasTrans, i0.size()*i1.size(), i0o.size(), i2.size()*i3.size()*2,
739                                                 1.0, data2.get(), i0.size()*i1.size(), transp.get(), i0o.size(), 0.0, interm.get(), i0.size()*i1.size());
740                     sort_indices<2,0,1,0,1,1,1>(interm.get(), interm2.get(), i0.size(), i1.size(), i0o.size());
741                     data_[istate]->at(iext)->add_block(interm2, i0o, i0, i1);
742                   }
743               }
744             }
745           break;
746         case Excitations::arst:
747           for (auto& i3 : active_)
748             for (auto& i2 : active_)
749               for (auto& i0 : active_) {
750                 auto create_transp = [this](const MatView shalf, const Index& I0, const Index& I2, const Index& I3, const Index& I0o) {
751                   unique_ptr<double[]> out(new double[I0.size()*I2.size()*I3.size()*I0o.size()]);
752                   for (int j3 = I3.offset(), k = 0; j3 != I3.offset()+I3.size(); ++j3)
753                     for (int j2 = I2.offset(); j2 != I2.offset()+I2.size(); ++j2)
754                       for (int j0 = I0.offset(); j0 != I0.offset()+I0.size(); ++j0, ++k)
755                         copy_n(shalf.element_ptr(I0o.offset(),j0-nclosed_+nact_*(j2-nclosed_+nact_*(j3-nclosed_))),
756                                I0o.size(), out.get()+I0o.size()*k);
757                   return move(out);
758                 };
759                 for (auto& i0o : interm_[dataindex]) {
760                   unique_ptr<double[]> transp = create_transp(ishalf, i0, i2, i3, i0o);
761                   for (auto& i1 : virt_) {
762                     if (!data_[istate]->at(iext)->is_local(i0o, i1)) continue;
763                     const size_t blocksize = tensor->get_size(i2, i3, i0, i1);
764                     const unique_ptr<double[]> data0 = tensor->get_block(i2, i3, i0, i1);
765                     unique_ptr<double[]> data1(new double[blocksize]);
766                     // i3 i2 i0 to be contracted
767                     sort_indices<2,0,1,3,0,1,1,1>(data0, data1, i2.size(), i3.size(), i0.size(), i1.size());
768                     unique_ptr<double[]> interm(new double[i1.size()*i0o.size()]);
769                     btas::gemm_impl<true>::call(CblasColMajor, CblasNoTrans, CblasNoTrans, i0o.size(), i1.size(), i0.size()*i2.size()*i3.size(),
770                                                 1.0, transp.get(), i0o.size(), data1.get(), i0.size()*i2.size()*i3.size(), 0.0, interm.get(), i0o.size());
771                     data_[istate]->at(iext)->add_block(interm, i0o, i1);
772                   }
773                 }
774               }
775           break;
776         case Excitations::rist:
777           for (auto& i3 : active_)
778             for (auto& i1 : active_)
779               for (auto& i0 : active_) {
780                 auto create_transp = [this](const MatView shalf, const Index& I0, const Index& I1, const Index& I3, const Index& I0o) {
781                   unique_ptr<double[]> out(new double[I0.size()*I1.size()*I3.size()*I0o.size()]);
782                   for (int j3 = I3.offset(), k = 0; j3 != I3.offset()+I3.size(); ++j3)
783                     for (int j1 = I1.offset(); j1 != I1.offset()+I1.size(); ++j1)
784                       for (int j0 = I0.offset(); j0 != I0.offset()+I0.size(); ++j0, ++k)
785                         copy_n(shalf.element_ptr(I0o.offset(),j0-nclosed_+nact_*(j1-nclosed_+nact_*(j3-nclosed_))),
786                                I0o.size(), out.get()+I0o.size()*k);
787                   return move(out);
788                 };
789                 for (auto& i0o : interm_[dataindex]) {
790                   unique_ptr<double[]> transp = create_transp(ishalf, i0, i1, i3, i0o);
791                   for (auto& i2 : closed_) {
792                     if (!data_[istate]->at(iext)->is_local(i0o, i2)) continue;
793                     const size_t blocksize = tensor->get_size(i2, i3, i0, i1);
794                     const unique_ptr<double[]> data0 = tensor->get_block(i2, i3, i0, i1);
795                     unique_ptr<double[]> data1(new double[blocksize]);
796                     // i3 i1 i0 to be contracted
797                     sort_indices<2,3,1,0,0,1,1,1>(data0, data1, i2.size(), i3.size(), i0.size(), i1.size());
798                     unique_ptr<double[]> interm(new double[i2.size()*i0o.size()]);
799                     btas::gemm_impl<true>::call(CblasColMajor, CblasNoTrans, CblasNoTrans, i0o.size(), i2.size(), i0.size()*i1.size()*i3.size(),
800                                                 1.0, transp.get(), i0o.size(), data1.get(), i0.size()*i1.size()*i3.size(), 0.0, interm.get(), i0o.size());
801                     data_[istate]->at(iext)->add_block(interm, i0o, i2);
802                   }
803                 }
804               }
805           break;
806         case Excitations::aibj:
807           if (!sssr_ || ist == istate) {
808             const int pos = iext + (sssr_ ? 0 : ist);
809             for (auto& i3 : virt_)
810               for (auto& i2 : closed_)
811                 for (auto& i1 : virt_)
812                   for (auto& i0 : closed_) {
813                     if (!data_[istate]->at(pos)->is_local(i0, i1, i2, i3)) continue;
814                     unique_ptr<double[]> data0 = t->at(ist)->get_block(i0, i1, i2, i3);
815                     const unique_ptr<double[]> data1 = t->at(ist)->get_block(i0, i3, i2, i1);
816                     sort_indices<0,3,2,1,2,12,1,12>(data1, data0, i0.size(), i3.size(), i2.size(), i1.size());
817                     data_[istate]->at(pos)->add_block(data0, i0, i1, i2, i3);
818                   }
819           }
820           break;
821       }
822     }
823   }
824   mpi__->barrier();
825 }
826 
827 
transform_to_redundant(const int istate) const828 shared_ptr<MultiTensor_<double>> Orthogonal_Basis::transform_to_redundant(const int istate) const {
829   // we put the transformed data in out.
830   auto out = make_shared<MultiTensor_<double>>(nstates_);
831   for (int ist = 0; ist != nstates_; ++ist) {
832     if (sssr_ && istate != ist) continue;
833     (*out)[ist] = init_amplitude();
834     for (int iext = Excitations::arbs; iext != Excitations::total; ++iext) {
835       const int dataindex = sssr_ ? iext + istate * Excitations::total : iext;
836       shared_ptr<Tensor_<double>> tensor = out->at(ist);
837       shared_ptr<const Tensor_<double>> dtensor = data_[istate]->at(iext);
838       const MatView ishalf = (iext != Excitations::aibj) ? shalf(iext, ist) : shalf(0, ist);
839       switch(iext) {
840         case Excitations::arbs:
841           for (auto& i2 : active_)
842             for (auto& i0 : active_) {
843               auto create_transp = [this](const MatView shalf, const Index& I0, const Index& I2, const Index& I0o) {
844                 unique_ptr<double[]> out(new double[I0.size()*I2.size()*I0o.size()]);
845                 for (int j2 = I2.offset(), k = 0; j2 != I2.offset()+I2.size(); ++j2)
846                   for (int j0 = I0.offset(); j0 != I0.offset()+I0.size(); ++j0, ++k)
847                     copy_n(shalf.element_ptr(I0o.offset(),(j0-nclosed_)+(j2-nclosed_)*nact_),
848                            I0o.size(), out.get()+I0o.size()*k);
849                 return move(out);
850               };
851               for (auto& i0o : interm_[dataindex]) {
852                 unique_ptr<double[]> transp = create_transp(ishalf, i0, i2, i0o);
853                 for (auto& i3 : virt_)
854                   for (auto& i1 : virt_) {
855                     if (!tensor->is_local(i0, i1, i2, i3)) continue;
856                     const size_t blocksize = tensor->get_size(i0, i1, i2, i3);
857                     unique_ptr<double[]> interm = dtensor->get_block(i0o, i1, i3);
858                     const size_t interm_size = dtensor->get_size(i0o, i1, i3);
859                     if (imag_) {
860                       const unique_ptr<double[]> denom = denom_[istate]->at(iext)->get_block(i0o, i1, i3);
861                       for (size_t i = 0; i != interm_size; ++i) {
862                         interm[i] *= denom[i];
863                       }
864                     }
865                     unique_ptr<double[]> data0(new double[blocksize]);
866                     btas::gemm_impl<true>::call(CblasColMajor, CblasConjTrans, CblasNoTrans, i0.size()*i2.size(), i1.size()*i3.size(), i0o.size(),
867                                                 sqrt(0.5), transp.get(), i0o.size(), interm.get(), i0o.size(), 0.0, data0.get(), i0.size()*i2.size());
868                     unique_ptr<double[]> data1(new double[blocksize]);
869                     sort_indices<0,2,1,3,0,1,1,1>(data0.get(), data1.get(), i0.size(), i2.size(), i1.size(), i3.size());
870                     tensor->add_block(data1, i0, i1, i2, i3);
871                   }
872               }
873             }
874           break;
875         case Excitations::arbi:
876           for (auto& i0 : active_) {
877             auto create_transp = [this](const MatView shalf, const Index& I0, const Index& I0o) {
878               unique_ptr<double[]> out(new double[I0.size()*I0o.size()]);
879               for (int j0 = I0.offset(), k = 0; j0 != I0.offset()+I0.size(); ++j0, ++k)
880                 copy_n(shalf.element_ptr(I0o.offset(), j0-nclosed_), I0o.size(), out.get()+I0o.size()*k);
881               return move(out);
882             };
883             for (auto& i0o : interm_[dataindex]) {
884               unique_ptr<double[]> transp = create_transp(ishalf, i0, i0o);
885               for (auto& i3 : virt_)
886                 for (auto& i2 : closed_)
887                   for (auto& i1 : virt_) {
888                     if (!tensor->is_local(i0, i1, i2, i3)) continue;
889                     const size_t blocksize = tensor->get_size(i0, i1, i2, i3);
890                     unique_ptr<double[]> interm = dtensor->get_block(i0o, i1, i2, i3);
891                     const size_t interm_size = dtensor->get_size(i0o, i1, i2, i3);
892                     if (imag_) {
893                       const unique_ptr<double[]> denom = denom_[istate]->at(iext)->get_block(i0o, i1, i2, i3);
894                       for (size_t i = 0; i != interm_size; ++i) {
895                         interm[i] *= denom[i];
896                       }
897                     }
898                     unique_ptr<double[]> data0(new double[blocksize]);
899                     btas::gemm_impl<true>::call(CblasColMajor, CblasConjTrans, CblasNoTrans, i0.size(), i1.size()*i2.size()*i3.size(), i0o.size(),
900                                                 1.0, transp.get(), i0o.size(), interm.get(), i0o.size(), 0.0, data0.get(), i0.size());
901                     tensor->add_block(data0, i0, i1, i2, i3);
902                   }
903             }
904           }
905           break;
906         case Excitations::airj:
907           for (auto& i3 : active_) {
908             auto create_transp = [this](const MatView shalf, const Index& I3, const Index& I0o) {
909               unique_ptr<double[]> out(new double[I3.size()*I0o.size()]);
910               for (int j3 = I3.offset(), k = 0; j3 != I3.offset()+I3.size(); ++j3, ++k)
911                 copy_n(shalf.element_ptr(I0o.offset(),j3-nclosed_), I0o.size(), out.get()+I0o.size()*k);
912               return move(out);
913             };
914             for (auto& i0o : interm_[dataindex]) {
915               unique_ptr<double[]> transp = create_transp(ishalf, i3, i0o);
916               for (auto& i2 : closed_)
917                 for (auto& i1 : virt_)
918                   for (auto& i0 : closed_) {
919                     if (!dtensor->is_local(i0o, i0, i1, i2)) continue;
920                     const size_t blocksize = tensor->get_size(i0, i1, i2, i3);
921                     unique_ptr<double[]> interm = dtensor->get_block(i0o, i0, i1, i2);
922                     const size_t interm_size = dtensor->get_size(i0o, i0, i1, i2);
923                     if (imag_) {
924                       const unique_ptr<double[]> denom = denom_[istate]->at(iext)->get_block(i0o,i0, i1, i2);
925                       for (size_t i = 0; i != interm_size; ++i) {
926                         interm[i] *= denom[i];
927                       }
928                     }
929                     unique_ptr<double[]> interm2(new double[interm_size]);
930                     sort_indices<1,2,3,0,0,1,1,1>(interm.get(), interm2.get(), i0o.size(), i0.size(), i1.size(), i2.size());
931                     unique_ptr<double[]> data0(new double[blocksize]);
932                     btas::gemm_impl<true>::call(CblasColMajor, CblasNoTrans, CblasNoTrans, i0.size()*i1.size()*i2.size(), i3.size(), i0o.size(),
933                                                 1.0, interm2.get(), i0.size()*i1.size()*i2.size(), transp.get(), i0o.size(), 0.0, data0.get(), i0.size()*i1.size()*i2.size());
934                     tensor->add_block(data0, i0, i1, i2, i3);
935                   }
936             }
937           }
938           break;
939         case Excitations::risj:
940           for (auto& i3 : active_)
941             for (auto& i1 : active_) {
942               auto create_transp = [this](const MatView shalf, const Index& I1, const Index& I3, const Index& I0o) {
943                 unique_ptr<double[]> out(new double[I1.size()*I3.size()*I0o.size()]);
944                 for (int j3 = I3.offset(), k = 0; j3 != I3.offset()+I3.size(); ++j3)
945                   for (int j1 = I1.offset(); j1 != I1.offset()+I1.size(); ++j1, ++k)
946                     copy_n(shalf.element_ptr(I0o.offset(),(j1-nclosed_)+(j3-nclosed_)*nact_),
947                            I0o.size(), out.get()+I0o.size()*k);
948                 return move(out);
949               };
950               for (auto& i0o : interm_[dataindex]) {
951                 unique_ptr<double[]> transp = create_transp(ishalf, i1, i3, i0o);
952                 for (auto& i2 : closed_)
953                   for (auto& i0 : closed_) {
954                     if (!tensor->is_local(i0, i1, i2, i3)) continue;
955                     const size_t blocksize = tensor->get_size(i0, i1, i2, i3);
956                     unique_ptr<double[]> interm = dtensor->get_block(i0o, i0, i2);
957                     const size_t interm_size = dtensor->get_size(i0o, i0, i2);
958                     if (imag_) {
959                       const unique_ptr<double[]> denom = denom_[istate]->at(iext)->get_block(i0o, i0, i2);
960                       for (size_t i = 0; i != interm_size; ++i) {
961                         interm[i] *= denom[i];
962                       }
963                     }
964                     unique_ptr<double[]> interm2(new double[interm_size]);
965                     sort_indices<1,2,0,0,1,1,1>(interm.get(), interm2.get(), i0o.size(), i0.size(), i2.size());
966                     unique_ptr<double[]> data0(new double[blocksize]);
967                     btas::gemm_impl<true>::call(CblasColMajor, CblasNoTrans, CblasNoTrans, i0.size()*i2.size(), i1.size()*i3.size(), i0o.size(),
968                                                 sqrt(0.5), interm2.get(), i0.size()*i2.size(), transp.get(), i0o.size(), 0.0, data0.get(), i0.size()*i2.size());
969                     unique_ptr<double[]> data1(new double[blocksize]);
970                     sort_indices<0,2,1,3,0,1,1,1>(data0, data1, i0.size(), i2.size(), i1.size(), i3.size());
971                     tensor->add_block(data1, i0, i1, i2, i3);
972                   }
973               }
974             }
975           break;
976         case Excitations::airs:
977           for (auto& i3 : active_)
978             for (auto& i2 : active_) {
979               auto create_transp = [this](const MatView shalf, const Index& I2, const Index& I3, const Index& I0o) {
980                 unique_ptr<double[]> out(new double[I2.size()*I3.size()*I0o.size()*2]);
981                 for (int j3 = I3.offset(), k = 0; j3 != I3.offset()+I3.size(); ++j3)
982                   for (int j2 = I2.offset(); j2 != I2.offset()+I2.size(); ++j2, ++k) {
983                     copy_n(shalf.element_ptr(I0o.offset(), (j2-nclosed_)+(j3-nclosed_)*nact_),
984                            I0o.size(), out.get()+I0o.size()*k);
985                     copy_n(shalf.element_ptr(I0o.offset(), (j2-nclosed_)+(j3-nclosed_)*nact_ + nact_*nact_),
986                            I0o.size(), out.get()+I0o.size()*(k+I2.size()*I3.size()));
987                   }
988                 return move(out);
989               };
990               for (auto& i0o : interm_[dataindex]) {
991                 unique_ptr<double[]> transp = create_transp(ishalf, i2, i3, i0o);
992                 for (auto& i1 : virt_)
993                   for (auto& i0 : closed_) {
994                     if (!tensor->is_local(i0, i1, i2, i3)) continue;
995                     const size_t blocksize = tensor->get_size(i0, i1, i2, i3);
996                     unique_ptr<double[]> interm = dtensor->get_block(i0o, i0, i1);
997                     const size_t interm_size = dtensor->get_size(i0o, i0, i1);
998                     if (imag_) {
999                       const unique_ptr<double[]> denom = denom_[istate]->at(iext)->get_block(i0o, i0, i1);
1000                       for (size_t i = 0; i != interm_size; ++i) {
1001                         interm[i] *= denom[i];
1002                       }
1003                     }
1004                     unique_ptr<double[]> interm2(new double[dtensor->get_size(i0o, i0, i1)]);
1005                     sort_indices<1,2,0,0,1,1,1>(interm.get(), interm2.get(), i0o.size(), i0.size(), i1.size());
1006                     unique_ptr<double[]> data0(new double[blocksize*2]);
1007                     btas::gemm_impl<true>::call(CblasColMajor, CblasNoTrans, CblasNoTrans, i0.size()*i1.size(), i2.size()*i3.size()*2, i0o.size(),
1008                                                 1.0, interm2.get(), i0.size()*i1.size(), transp.get(), i0o.size(), 0.0, data0.get(), i0.size()*i1.size());
1009                     unique_ptr<double[]> data1(new double[blocksize]);
1010                     unique_ptr<double[]> data2(new double[blocksize]);
1011                     copy_n(data0.get(), blocksize, data1.get());
1012                     sort_indices<2,1,0,3,0,1,1,1>(data0.get()+blocksize, data2.get(), i0.size(), i1.size(), i2.size(), i3.size());
1013                     tensor->add_block(data1, i0, i1, i2, i3);
1014                     tensor->add_block(data2, i2, i1, i0, i3);
1015                   }
1016               }
1017             }
1018           break;
1019         case Excitations::arst:
1020           for (auto& i3 : active_)
1021             for (auto& i2 : active_)
1022               for (auto& i0 : active_) {
1023                 auto create_transp = [this](const MatView shalf, const Index& I0, const Index& I2, const Index& I3, const Index& I0o) {
1024                   unique_ptr<double[]> out(new double[I0.size()*I2.size()*I3.size()*I0o.size()]);
1025                   for (int j3 = I3.offset(), k = 0; j3 != I3.offset()+I3.size(); ++j3)
1026                     for (int j2 = I2.offset(); j2 != I2.offset()+I2.size(); ++j2)
1027                       for (int j0 = I0.offset(); j0 != I0.offset()+I0.size(); ++j0, ++k)
1028                         copy_n(shalf.element_ptr(I0o.offset(),j0-nclosed_+nact_*(j2-nclosed_+nact_*(j3-nclosed_))),
1029                                I0o.size(), out.get()+I0o.size()*k);
1030                   return move(out);
1031                 };
1032                 for (auto& i0o : interm_[dataindex]) {
1033                   unique_ptr<double[]> transp = create_transp(ishalf, i0, i2, i3, i0o);
1034                   for (auto& i1 : virt_) {
1035                     if (!tensor->is_local(i0, i1, i2, i3)) continue;
1036                     const size_t blocksize = tensor->get_size(i0, i1, i2, i3);
1037                     unique_ptr<double[]> interm = dtensor->get_block(i0o, i1);
1038                     const size_t interm_size = dtensor->get_size(i0o, i1);
1039                     if (imag_) {
1040                       const unique_ptr<double[]> denom = denom_[istate]->at(iext)->get_block(i0o, i1);
1041                       for (size_t i = 0; i != interm_size; ++i) {
1042                         interm[i] *= denom[i];
1043                       }
1044                     }
1045                     unique_ptr<double[]> data0(new double[blocksize]);
1046                     btas::gemm_impl<true>::call(CblasColMajor, CblasConjTrans, CblasNoTrans, i0.size()*i2.size()*i3.size(), i1.size(), i0o.size(),
1047                                                 1.0, transp.get(), i0o.size(), interm.get(), i0o.size(), 0.0, data0.get(), i0.size()*i2.size()*i3.size());
1048                     unique_ptr<double[]> data1(new double[blocksize]);
1049                     sort_indices<0,3,1,2,0,1,1,1>(data0.get(), data1.get(), i0.size(), i2.size(), i3.size(), i1.size());
1050                     tensor->add_block(data1, i0, i1, i2, i3);
1051                   }
1052                 }
1053               }
1054           break;
1055         case Excitations::rist:
1056           for (auto& i3 : active_)
1057             for (auto& i1 : active_)
1058               for (auto& i0 : active_) {
1059                 auto create_transp = [this](const MatView shalf, const Index& I0, const Index& I1, const Index& I3, const Index& I0o) {
1060                   unique_ptr<double[]> out(new double[I0.size()*I1.size()*I3.size()*I0o.size()]);
1061                   for (int j3 = I3.offset(), k = 0; j3 != I3.offset()+I3.size(); ++j3)
1062                     for (int j1 = I1.offset(); j1 != I1.offset()+I1.size(); ++j1)
1063                       for (int j0 = I0.offset(); j0 != I0.offset()+I0.size(); ++j0, ++k)
1064                         copy_n(shalf.element_ptr(I0o.offset(),j0-nclosed_+nact_*(j1-nclosed_+nact_*(j3-nclosed_))),
1065                                I0o.size(), out.get()+I0o.size()*k);
1066                   return move(out);
1067                 };
1068                 for (auto& i0o : interm_[dataindex]) {
1069                   unique_ptr<double[]> transp = create_transp(ishalf, i0, i1, i3, i0o);
1070                   for (auto& i2 : closed_) {
1071                     if (!tensor->is_local(i0, i1, i2, i3)) continue;
1072                     const size_t blocksize = tensor->get_size(i0, i1, i2, i3);
1073                     unique_ptr<double[]> interm = dtensor->get_block(i0o, i2);
1074                     const size_t interm_size = dtensor->get_size(i0o, i2);
1075                     if (imag_) {
1076                       const unique_ptr<double[]> denom = denom_[istate]->at(iext)->get_block(i0o, i2);
1077                       for (size_t i = 0; i != interm_size; ++i) {
1078                         interm[i] *= denom[i];
1079                       }
1080                     }
1081                     unique_ptr<double[]> data0(new double[blocksize]);
1082                     btas::gemm_impl<true>::call(CblasColMajor, CblasConjTrans, CblasNoTrans, i0.size()*i1.size()*i3.size(), i2.size(), i0o.size(),
1083                                                 1.0, transp.get(), i0o.size(), interm.get(), i0o.size(), 0.0, data0.get(), i0.size()*i1.size()*i3.size());
1084                     unique_ptr<double[]> data1(new double[blocksize]);
1085                     sort_indices<0,1,3,2,0,1,1,1>(data0.get(), data1.get(), i0.size(), i1.size(), i3.size(), i2.size());
1086                     tensor->add_block(data1, i0, i1, i2, i3);
1087                   }
1088                 }
1089               }
1090           break;
1091         case Excitations::aibj:
1092           const int pos = sssr_ ? iext : iext + ist;
1093           for (auto& i3 : virt_)
1094             for (auto& i2 : closed_)
1095               for (auto& i1 : virt_)
1096                 for (auto& i0 : closed_) {
1097                   if (!tensor->is_local(i0, i1, i2, i3)) continue;
1098                   unique_ptr<double[]> data0 = data_[istate]->at(pos)->get_block(i0, i1, i2, i3);
1099                   if (imag_) {
1100                     const unique_ptr<double[]> denom = denom_[istate]->at(pos)->get_block(i0, i1, i2, i3);
1101                     const size_t blocksize = data_[istate]->at(pos)->get_size(i0, i1, i2, i3);
1102                     for (size_t i = 0; i != blocksize; ++i) {
1103                       data0[i] *= denom[i];
1104                     }
1105                   }
1106                   out->at(ist)->add_block(data0, i0, i1, i2, i3);
1107                 }
1108           break;
1109       }
1110     }
1111   }
1112   mpi__->barrier();
1113 
1114   return out;
1115 }
1116 
1117 
update(shared_ptr<const Orthogonal_Basis> r,const int istate)1118 void Orthogonal_Basis::update(shared_ptr<const Orthogonal_Basis> r, const int istate) {
1119   const double shift2 = shift_ * shift_;
1120 
1121   for (int iext = Excitations::arbs; iext != Excitations::total; ++iext) {
1122     const shared_ptr<Tensor_<double>> rtensor = r->data(istate)->at(iext);
1123     const shared_ptr<Tensor_<double>> dtensor = denom_[istate]->at(iext);
1124     const int dataindex = sssr_ ? iext + istate * Excitations::total : iext;
1125     switch(iext) {
1126       case Excitations::arbs:
1127         for (auto& i3 : virt_)
1128           for (auto& i1 : virt_)
1129             for (auto& i0o : interm_[dataindex]) {
1130               if (!dtensor->is_local(i0o, i1, i3)) continue;
1131               unique_ptr<double[]> residual = rtensor->get_block(i0o, i1, i3);
1132               unique_ptr<double[]> denom    = dtensor->get_block(i0o, i1, i3);
1133               const size_t blocksize = rtensor->get_size(i0o, i1, i3);
1134               if (imag_) {
1135                 for (size_t j = 0; j != blocksize; ++j) {
1136                   residual[j] *= -(1.0 / (denom[j] * denom[j] + shift2));
1137                 }
1138               } else {
1139                 for (size_t j = 0; j != blocksize; ++j) {
1140                   residual[j] *= -(1.0 / (denom[j] + shift_));
1141                 }
1142               }
1143               data_[istate]->at(iext)->add_block(residual, i0o, i1, i3);
1144             }
1145         break;
1146       case Excitations::arbi:
1147         for (auto& i3 : virt_)
1148           for (auto& i2 : closed_)
1149             for (auto& i1 : virt_)
1150               for (auto& i0o : interm_[dataindex]) {
1151                 if (!dtensor->is_local(i0o, i1, i2, i3)) continue;
1152                 unique_ptr<double[]> residual = rtensor->get_block(i0o, i1, i2, i3);
1153                 unique_ptr<double[]> denom    = dtensor->get_block(i0o, i1, i2, i3);
1154                 const size_t blocksize = rtensor->get_size(i0o, i1, i2, i3);
1155                 if (imag_) {
1156                   for (size_t j = 0; j != blocksize; ++j) {
1157                     residual[j] *= -(1.0 / (denom[j] * denom[j] + shift2));
1158                   }
1159                 } else {
1160                   for (size_t j = 0; j != blocksize; ++j) {
1161                     residual[j] *= -(1.0 / (denom[j] + shift_));
1162                   }
1163                 }
1164                 data_[istate]->at(iext)->add_block(residual, i0o, i1, i2, i3);
1165               }
1166         break;
1167       case Excitations::airj:
1168         for (auto& i2 : closed_)
1169           for (auto& i1 : virt_)
1170             for (auto& i0 : closed_)
1171               for (auto& i0o : interm_[dataindex]) {
1172                 if (!dtensor->is_local(i0o, i0, i1, i2)) continue;
1173                 unique_ptr<double[]> residual = rtensor->get_block(i0o, i0, i1, i2);
1174                 unique_ptr<double[]> denom    = dtensor->get_block(i0o, i0, i1, i2);
1175                 const size_t blocksize = rtensor->get_size(i0o, i0, i1, i2);
1176                 if (imag_) {
1177                   for (size_t j = 0; j != blocksize; ++j) {
1178                     residual[j] *= -(1.0 / (denom[j] * denom[j] + shift2));
1179                   }
1180                 } else {
1181                   for (size_t j = 0; j != blocksize; ++j) {
1182                     residual[j] *= -(1.0 / (denom[j] + shift_));
1183                   }
1184                 }
1185                 data_[istate]->at(iext)->add_block(residual, i0o, i0, i1, i2);
1186               }
1187         break;
1188       case Excitations::risj:
1189         for (auto& i2 : closed_)
1190           for (auto& i0 : closed_)
1191             for (auto& i0o : interm_[dataindex]) {
1192               if (!dtensor->is_local(i0o, i0, i2)) continue;
1193               unique_ptr<double[]> residual = rtensor->get_block(i0o, i0, i2);
1194               unique_ptr<double[]> denom    = dtensor->get_block(i0o, i0, i2);
1195               const size_t blocksize = rtensor->get_size(i0o, i0, i2);
1196               if (imag_) {
1197                 for (size_t j = 0; j != blocksize; ++j) {
1198                   residual[j] *= -(1.0 / (denom[j] * denom[j] + shift2));
1199                 }
1200               } else {
1201                 for (size_t j = 0; j != blocksize; ++j) {
1202                   residual[j] *= -(1.0 / (denom[j] + shift_));
1203                 }
1204               }
1205               data_[istate]->at(iext)->add_block(residual, i0o, i0, i2);
1206             }
1207         break;
1208       case Excitations::airs:
1209         for (auto& i1 : virt_)
1210           for (auto& i0 : closed_)
1211             for (auto& i0o : interm_[dataindex]) {
1212               if (!dtensor->is_local(i0o, i0, i1)) continue;
1213               unique_ptr<double[]> residual = rtensor->get_block(i0o, i0, i1);
1214               unique_ptr<double[]> denom    = dtensor->get_block(i0o, i0, i1);
1215               const size_t blocksize = rtensor->get_size(i0o, i0, i1);
1216               if (imag_) {
1217                 for (size_t j = 0; j != blocksize; ++j) {
1218                   residual[j] *= -(1.0 / (denom[j] * denom[j] + shift2));
1219                 }
1220               } else {
1221                 for (size_t j = 0; j != blocksize; ++j) {
1222                   residual[j] *= -(1.0 / (denom[j] + shift_));
1223                 }
1224               }
1225               data_[istate]->at(iext)->add_block(residual, i0o, i0, i1);
1226             }
1227         break;
1228       case Excitations::arst:
1229         for (auto& i1 : virt_)
1230           for (auto& i0o : interm_[dataindex]) {
1231             if (!dtensor->is_local(i0o, i1)) continue;
1232             unique_ptr<double[]> residual = rtensor->get_block(i0o, i1);
1233             unique_ptr<double[]> denom    = dtensor->get_block(i0o, i1);
1234             const size_t blocksize = rtensor->get_size(i0o, i1);
1235             if (imag_) {
1236               for (size_t j = 0; j != blocksize; ++j) {
1237                 residual[j] *= -(1.0 / (denom[j] * denom[j] + shift2));
1238               }
1239             } else {
1240               for (size_t j = 0; j != blocksize; ++j) {
1241                 residual[j] *= -(1.0 / (denom[j] + shift_));
1242               }
1243             }
1244             data_[istate]->at(iext)->add_block(residual, i0o, i1);
1245           }
1246         break;
1247       case Excitations::rist:
1248         for (auto& i0 : closed_)
1249           for (auto& i0o : interm_[dataindex]) {
1250             if (!dtensor->is_local(i0o, i0)) continue;
1251             unique_ptr<double[]> residual = rtensor->get_block(i0o, i0);
1252             unique_ptr<double[]> denom    = dtensor->get_block(i0o, i0);
1253             const size_t blocksize = rtensor->get_size(i0o, i0);
1254             if (imag_) {
1255               for (size_t j = 0; j != blocksize; ++j) {
1256                 residual[j] *= -(1.0 / (denom[j] * denom[j] + shift2));
1257               }
1258             } else {
1259               for (size_t j = 0; j != blocksize; ++j) {
1260                 residual[j] *= -(1.0 / (denom[j] + shift_));
1261               }
1262             }
1263             data_[istate]->at(iext)->add_block(residual, i0o, i0);
1264           }
1265         break;
1266       case Excitations::aibj:
1267         for (int ist = 0; ist != nstates_; ++ist) {
1268           if (!sssr_ || ist == istate) {
1269             const int pos = iext + (sssr_ ? 0 : ist);
1270             for (auto& i3 : virt_)
1271               for (auto& i2 : closed_)
1272                 for (auto& i1 : virt_)
1273                   for (auto& i0 : closed_) {
1274                     if (!denom_[istate]->at(pos)->is_local(i0, i1, i2, i3)) continue;
1275                     unique_ptr<double[]> residual = r->data(istate)->at(pos)->get_block(i0, i1, i2, i3);
1276                     unique_ptr<double[]> denom    = denom_[istate]->at(pos)->get_block(i0, i1, i2, i3);
1277                     const size_t blocksize = r->data(istate)->at(pos)->get_size(i0, i1, i2, i3);
1278                     if (imag_) {
1279                       for (size_t j = 0; j != blocksize; ++j) {
1280                         residual[j] *= -(1.0 / (denom[j] * denom[j] + shift2));
1281                       }
1282                     } else {
1283                       for (size_t j = 0; j != blocksize; ++j) {
1284                         residual[j] *= -(1.0 / (denom[j] + shift_));
1285                       }
1286                     }
1287                     data_[istate]->at(pos)->add_block(residual, i0, i1, i2, i3);
1288                   }
1289           }
1290         }
1291         break;
1292     }
1293   }
1294   mpi__->barrier();
1295 }
1296 
1297 
print_convergence(shared_ptr<const Orthogonal_Basis> s,shared_ptr<const Orthogonal_Basis> r,const int istate,const int iter,const double error,const double timing) const1298 double Orthogonal_Basis::print_convergence(shared_ptr<const Orthogonal_Basis> s, shared_ptr<const Orthogonal_Basis> r, const int istate, const int iter, const double error, const double timing) const {
1299   shared_ptr<MultiTensor_<double>> tcovar = get_contravariant(istate, true);
1300   double etot = 0.0;
1301   vector<double> esector(Excitations::total);
1302 
1303   cout << setw(8) << iter;
1304   for (int ist = 0; ist != nstates_; ++ist) {
1305     if (!sssr_ || istate == ist) {
1306       const int pos = Excitations::aibj + (sssr_ ? 0 : ist);
1307       esector[Excitations::aibj] += tcovar->at(pos)->dot_product(s->data(istate)->at(pos)) + tcovar->at(pos)->dot_product(r->data(istate)->at(pos));
1308     }
1309   }
1310   etot += esector[Excitations::aibj];
1311   cout << setprecision(5) << setw(10) << esector[Excitations::aibj];
1312   for (int iext = Excitations::arbs; iext != Excitations::aibj; ++iext) {
1313     esector[iext] = tcovar->at(iext)->dot_product(s->data(istate)->at(iext)) + tcovar->at(iext)->dot_product(r->data(istate)->at(iext));
1314     cout << setprecision(5) << setw(10) << esector[iext];
1315     etot += esector[iext];
1316   }
1317 
1318   cout << setw(13) << setprecision(7) << etot << setw(11) << error << setw(7) << setprecision(2) << timing << endl;
1319 
1320   return etot;
1321 }
1322 
1323 
1324 // copy of the functions in SpinFreeMethod to initialize transformed tensors
loop_over(function<void (const Index &,const Index &,const Index &,const Index &)> func) const1325 void Orthogonal_Basis::loop_over(function<void(const Index&, const Index&, const Index&, const Index&)> func) const {
1326   for (auto& i3 : virt_)
1327     for (auto& i2 : closed_)
1328       for (auto& i1 : virt_)
1329         for (auto& i0 : closed_)
1330           func(i0, i1, i2, i3);
1331   for (auto& i2 : active_)
1332     for (auto& i0 : active_)
1333       for (auto& i3 : virt_)
1334         for (auto& i1 : virt_)
1335           func(i0, i1, i2, i3);
1336   for (auto& i0 : active_)
1337     for (auto& i3 : virt_)
1338       for (auto& i2 : closed_)
1339         for (auto& i1 : virt_)
1340           func(i0, i1, i2, i3);
1341   for (auto& i3 : active_)
1342     for (auto& i2 : closed_)
1343       for (auto& i1 : virt_)
1344         for (auto& i0 : closed_)
1345           func(i0, i1, i2, i3);
1346   for (auto& i3 : active_)
1347     for (auto& i1 : active_)
1348       for (auto& i2 : closed_)
1349         for (auto& i0 : closed_)
1350           func(i0, i1, i2, i3);
1351   for (auto& i3 : active_)
1352     for (auto& i2 : active_)
1353       for (auto& i1 : virt_)
1354         for (auto& i0 : closed_) {
1355           func(i0, i1, i2, i3);
1356           func(i2, i1, i0, i3);
1357         }
1358   for (auto& i3 : active_)
1359     for (auto& i2 : active_)
1360       for (auto& i0 : active_)
1361         for (auto& i1 : virt_)
1362           func(i0, i1, i2, i3);
1363   for (auto& i3 : active_)
1364     for (auto& i1 : active_)
1365       for (auto& i0 : active_)
1366         for (auto& i2 : closed_)
1367           func(i0, i1, i2, i3);
1368 }
1369 
1370 
init_amplitude() const1371 shared_ptr<Tensor_<double>> Orthogonal_Basis::init_amplitude() const {
1372   unordered_set<size_t> sparse;
1373   auto put = [&sparse](const Index& i0, const Index& i1, const Index& i2, const Index& i3) {
1374     sparse.insert(generate_hash_key(i0, i1, i2, i3));
1375   };
1376   loop_over(put);
1377 
1378   IndexRange occ(closed_);   occ.merge(active_);
1379   IndexRange virt(active_);  virt.merge(virt_);
1380 
1381   return make_shared<Tensor_<double>>(vector<IndexRange>{occ, virt, occ, virt}, /*kramers*/false, sparse, /*alloc*/true);
1382 }
1383 
1384 
1385 #endif
1386