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