MPQC 3.0.0-alpha
Loading...
Searching...
No Matches
compute_tbint_tensor.h
1//
2// compute_tbint_tensor.h
3//
4// Copyright (C) 2005 Edward Valeev
5//
6// Author: Edward Valeev <evaleev@vt.edu>
7// Maintainer: EV
8//
9// This file is part of the SC Toolkit.
10//
11// The SC Toolkit is free software; you can redistribute it and/or modify
12// it under the terms of the GNU Library General Public License as published by
13// the Free Software Foundation; either version 2, or (at your option)
14// any later version.
15//
16// The SC Toolkit 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 Library General Public License for more details.
20//
21// You should have received a copy of the GNU Library General Public License
22// along with the SC Toolkit; see the file COPYING.LIB. If not, write to
23// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
24//
25// The U.S. Government is granted a limited license as per AL 91-7.
26//
27
28#include <cmath>
29#include <util/misc/regtime.h>
30#include <math/mmisc/pairiter.h>
31#include <chemistry/qc/lcao/utils.h>
32#include <chemistry/qc/lcao/utils.impl.h>
33#include <chemistry/qc/mbptr12/r12int_eval.h>
34#include <util/misc/print.h>
35
36#ifndef _chemistry_qc_mbptr12_computetbinttensor_h
37#define _chemistry_qc_mbptr12_computetbinttensor_h
38
39namespace sc {
40
41 template <typename DataProcess,
42 bool CorrFactorInBra,
43 bool CorrFactorInKet>
44 void
46 TwoBodyOper::type tbint_type,
47 const Ref<OrbitalSpace>& space1_bra,
48 const Ref<OrbitalSpace>& space1_ket,
49 const Ref<OrbitalSpace>& space2_bra,
50 const Ref<OrbitalSpace>& space2_ket,
51 bool antisymmetrize,
52 const std::vector<std::string>& transform_keys)
53 {
54 // are particles 1 and 2 equivalent?
55 const bool part1_strong_equiv_part2 = (space1_bra==space2_bra && space1_ket==space2_ket);
56 const bool part1_weak_equiv_part2 = (space1_bra->rank()==space2_bra->rank() && space1_ket->rank()==space2_ket->rank());
57 // Check correct semantics of this call : if antisymmetrize then particles must be equivalent
58 const bool correct_semantics = (antisymmetrize && part1_weak_equiv_part2) ||
60 if (!correct_semantics)
61 throw ProgrammingError("R12IntEval::compute_tbint_tensor_() -- incorrect call semantics",
62 __FILE__,__LINE__);
63
64 // If need to antisymmetrize but particles are not truly equivalent, compute as AlphaBeta and antisymmetrize
65 const bool alphabeta = !(antisymmetrize && part1_strong_equiv_part2);
66
67 const bool CorrFactorInBraKet = CorrFactorInBra && CorrFactorInKet;
68
69 const unsigned int nbrasets = (CorrFactorInBra ? corrfactor()->nfunctions() : 1);
70 const unsigned int nketsets = (CorrFactorInKet ? corrfactor()->nfunctions() : 1);
71 const unsigned int nsets = (CorrFactorInBraKet ? UINT_MAX : nbrasets*nketsets);
72
73 // create transforms, if needed
74 typedef std::vector< Ref<TwoBodyMOIntsTransform> > tformvec;
75 const size_t num_tforms = transform_keys.size();
76 tformvec transforms(num_tforms);
77 for(unsigned int t=0; t<num_tforms; ++t) {
78 transforms[t] = moints_runtime4()->get(transform_keys[t]);
79 }
80
81 Timer tim_generic_tensor("Generic tensor");
82 std::ostringstream oss;
83 oss << "<" << space1_bra->id() << " " << space2_bra->id() << (antisymmetrize ? "||" : "|")
84 << space1_ket->id() << " " << space2_ket->id() << ">";
85 const std::string label = oss.str();
86 ExEnv::out0() << std::endl << indent
87 << "Entered generic tensor (" << label << ") evaluator" << std::endl;
88 ExEnv::out0() << incindent;
89
90 //
91 // WARNING: Assuming all transforms are over same spaces!!!
92 //
93 Ref<OrbitalSpace> tspace1_bra = transforms[0]->space1();
94 Ref<OrbitalSpace> tspace1_ket = transforms[0]->space2();
95 Ref<OrbitalSpace> tspace2_bra = transforms[0]->space3();
96 Ref<OrbitalSpace> tspace2_ket = transforms[0]->space4();
97
98 // maps spaceX to spaceX of the transform
99 std::vector<unsigned int> map1_bra, map1_ket, map2_bra, map2_ket;
100 // maps space2_ket to space1_ket of transform
101 std::vector<unsigned int> map12_ket;
102 // maps space1_ket to space2_ket of transform
103 std::vector<unsigned int> map21_ket;
104 map1_bra = *tspace1_bra<<*space1_bra;
105 map1_ket = *tspace1_ket<<*space1_ket;
106 map2_bra = *tspace2_bra<<*space2_bra;
107 map2_ket = *tspace2_ket<<*space2_ket;
108 if (!alphabeta) {
109 if (tspace1_ket == tspace2_ket) {
110 map12_ket = map1_ket;
111 map21_ket = map2_ket;
112 }
113 else {
114 map12_ket = *tspace1_ket<<*space2_ket;
115 map21_ket = *tspace2_ket<<*space1_ket;
116 }
117 }
118
119 const unsigned int tblock_ncols = tspace2_ket->rank();
120 const RefDiagSCMatrix evals1_bra = space1_bra->evals();
121 const RefDiagSCMatrix evals1_ket = space1_ket->evals();
122 const RefDiagSCMatrix evals2_bra = space2_bra->evals();
123 const RefDiagSCMatrix evals2_ket = space2_ket->evals();
124
125 // Using spinorbital iterators means I don't take into account perm symmetry
126 // More efficient algorithm will require generic code
127 const SpinCase2 S = (alphabeta ? AlphaBeta : AlphaAlpha);
128 SpinMOPairIter iterbra(space1_bra->rank(),space2_bra->rank(),S);
129 SpinMOPairIter iterket(space1_ket->rank(),space2_ket->rank(),S);
130 // size of one block of <space1_bra space2_bra|
131 const unsigned int nbra = iterbra.nij();
132 // size of one block of |space1_ket space2_ket>
133 const unsigned int nket = iterket.nij();
134
135 RefSCMatrix Tresult;
136 // Allocate storage for the result, if need to antisymmetrize at the end; else accumulate directly to T
137 if (antisymmetrize && alphabeta) {
138 Tresult = T.kit()->matrix(new SCDimension(nbra*nbrasets),
139 new SCDimension(nket*nketsets));
140 Tresult.assign(0.0);
141 }
142 else
143 Tresult = T;
144
145 unsigned int fbraket = 0;
146 unsigned int fbraoffset = 0;
147 for(unsigned int fbra=0; fbra<nbrasets; ++fbra,fbraoffset+=nbra) {
148
149 unsigned int fketoffset = 0;
150 for(unsigned int fket=0; fket<nketsets; ++fket,fketoffset+=nket,++fbraket) {
151
152 Ref<TwoBodyMOIntsTransform> tform = transforms[fbraket];
153 const Ref<TwoBodyIntDescr>& intdescr = tform->intdescr();
154 const unsigned int intsetidx = intdescr->intset(tbint_type);
155
157 ExEnv::out0() << indent << "Using transform " << tform->name() << std::endl;
158
159 tform->compute();
160 Ref<DistArray4> accum = tform->ints_distarray4();
161 accum->activate();
162
163 // split work over tasks which have access to integrals
164 std::vector<int> proc_with_ints;
165 const int nproc_with_ints = accum->tasks_with_access(proc_with_ints);
166 const int me = r12world()->world()->msg()->me();
167
168 if (accum->has_access(me)) {
169 for(iterbra.start(); iterbra; iterbra.next()) {
170 const int ij = iterbra.ij();
171
172 const int ij_proc = ij%nproc_with_ints;
173 if (ij_proc != proc_with_ints[me])
174 continue;
175
176 const unsigned int i = iterbra.i();
177 const unsigned int j = iterbra.j();
178 const unsigned int ii = map1_bra[i];
179 const unsigned int jj = map2_bra[j];
180
182 ExEnv::outn() << indent << "task " << me << ": working on (i,j) = " << i << "," << j << " " << std::endl;
183 Timer tim_intsretrieve("MO ints retrieve");
184 const double *ij_buf = accum->retrieve_pair_block(ii,jj,intsetidx);
185 tim_intsretrieve.exit();
187 ExEnv::outn() << indent << "task " << me << ": obtained ij blocks" << std::endl;
188
189 for(iterket.start(); iterket; iterket.next()) {
190 const unsigned int a = iterket.i();
191 const unsigned int b = iterket.j();
192 const unsigned int aa = map1_ket[a];
193 const unsigned int bb = map2_ket[b];
194 const int AB = aa*tblock_ncols+bb;
195 const int ab = iterket.ij();
196
197 const double I_ijab = ij_buf[AB];
198
199 if (alphabeta) {
200 if (debug_ > DefaultPrintThresholds::allO2N2) {
201 ExEnv::out0() << "i = " << i << " j = " << j << " a = " << a << " b = " << b
202 << " <ij|ab> = " << I_ijab << std::endl;
203 }
204 const double T_ijab = DataProcess::I2T(I_ijab,i,j,a,b,evals1_bra,evals1_ket,evals2_bra,evals2_ket);
205 Tresult.accumulate_element(ij+fbraoffset,ab+fketoffset,T_ijab);
206 }
207 else {
208 const int aa = map21_ket[a];
209 const int bb = map12_ket[b];
210 const int BA = bb*tblock_ncols+aa;
211 const double I_ijba = ij_buf[BA];
212 if (debug_ > DefaultPrintThresholds::allO2N2) {
213 ExEnv::out0() << "i = " << i << " j = " << j << " a = " << a << " b = " << b
214 << " <ij|ab> = " << I_ijab << " <ij|ba> = " << I_ijba << std::endl;
215 }
216 const double I_anti = I_ijab - I_ijba;
217 const double T_ijab = DataProcess::I2T(I_anti,i,j,a,b,evals1_bra,evals1_ket,evals2_bra,evals2_ket);
218 Tresult.accumulate_element(ij+fbraoffset,ab+fketoffset,T_ijab);
219 }
220
221 } // ket loop
222 accum->release_pair_block(ii,jj,intsetidx);
223
224 } // bra loop
225 } // loop over tasks with access
226
227 if (accum->data_persistent()) accum->deactivate();
228
229 } // ket blocks
230 } // bra blocks
231
232 if (antisymmetrize && alphabeta) {
233 // antisymmetrization implies equivalent particles -- hence symmetrize before antisymmetrize
234 symmetrize<false>(Tresult,Tresult,space1_bra,space1_ket);
235 sc::antisymmetrize(T,Tresult,space1_bra,space1_ket,true);
236 Tresult = 0;
237 }
238
239 ExEnv::out0() << decindent;
240 ExEnv::out0() << indent << "Exited generic tensor (" << label << ") evaluator" << std::endl;
241 tim_generic_tensor.exit();
242 }
243
245 namespace ManyBodyTensors {
246
247 enum Sign {
248 Minus = -1,
249 Plus = +1
250 };
251
253 template <Sign sign = Plus>
255 public:
256 static double I2T(double I, int i1, int i3, int i2, int i4,
257 const RefDiagSCMatrix& evals1,
258 const RefDiagSCMatrix& evals2,
259 const RefDiagSCMatrix& evals3,
260 const RefDiagSCMatrix& evals4)
261 {
262 if (sign == Plus)
263 return I;
264 else
265 return -I;
266 }
267 };
268
270 template <Sign sign = Plus>
272 public:
273 static double I2T(double I, int i1, int i3, int i2, int i4,
274 const RefDiagSCMatrix& evals1,
275 const RefDiagSCMatrix& evals2,
276 const RefDiagSCMatrix& evals3,
277 const RefDiagSCMatrix& evals4)
278 {
279 const double ediff = (- evals1(i1) - evals3(i3) + evals2(i2) + evals4(i4));
280 if (sign == Plus)
281 return I*ediff;
282 else
283 return -I*ediff;
284 }
285 };
286
288 template <Sign sign = Plus>
290 public:
291 static double I2T(double I, int i1, int i3, int i2, int i4,
292 const RefDiagSCMatrix& evals1,
293 const RefDiagSCMatrix& evals2,
294 const RefDiagSCMatrix& evals3,
295 const RefDiagSCMatrix& evals4)
296 {
297 const double ediff = (- evals1(i1) - evals3(i3) + evals2(i2) + evals4(i4));
298 if (sign == Plus)
299 return I/ediff;
300 else
301 return -I/ediff;
302 }
303 };
304
308 template <Sign sign = Plus>
310 public:
311 static double I2T(double I, int i1, int i3, int i2, int i4,
312 const RefDiagSCMatrix& evals1,
313 const RefDiagSCMatrix& evals2,
314 const RefDiagSCMatrix& evals3,
315 const RefDiagSCMatrix& evals4)
316 {
317 const double ediff = (- evals1(i1) - evals3(i3) + evals2(i2) + evals4(i4));
318 if (sign == Plus)
319 return I/std::sqrt(std::fabs(ediff));
320 else
321 return -I/std::sqrt(std::fabs(ediff));
322 }
323 };
324
329 }
330
331}
332
333#endif
334
static const unsigned int allO2N2
Print all o^2N^2 quantities.
Definition print.h:65
static const unsigned int diagnostics
Additional diagnostics, e.g., transform progress, etc.
Definition print.h:39
static std::ostream & outn()
Return an ostream that writes from all nodes.
Definition exenv.h:81
static std::ostream & out0()
Return an ostream that writes from node 0.
Applies (H0 - E0)
Definition compute_tbint_tensor.h:271
Tensor elements are <pq||rs>
Definition compute_tbint_tensor.h:254
Applies (H0 - E0)^{-1}, e.g. MP2 T2 tensor elements are <ij||ab> /(e_i + e_j - e_a - e_b)
Definition compute_tbint_tensor.h:289
Applies 1.0/sqrt(H0-E0) MP2 pseudo-T2 (S2) tensor elements are <ij||ab> /sqrt(|e_i + e_j - e_a - e_b|...
Definition compute_tbint_tensor.h:309
DEPRECATED void compute_tbint_tensor(RefSCMatrix &T, TwoBodyOper::type tbint_type, const Ref< OrbitalSpace > &space1, const Ref< OrbitalSpace > &space2, const Ref< OrbitalSpace > &space3, const Ref< OrbitalSpace > &space4, bool antisymmetrize, const std::vector< std::string > &tform_keys)
compute_tbint_tensor computes a 2-body tensor T using integrals of type tbint_type.
const Ref< R12WavefunctionWorld > & r12world() const
the R12World in which this object lives
Definition r12int_eval.h:642
The RefDiagSCMatrix class is a smart pointer to an DiagSCMatrix specialization.
Definition matrix.h:389
Contains all MPQC code up to version 3.
Definition mpqcin.h:14
void antisymmetrize(RefSCMatrix &Aanti, const RefSCMatrix &A, const Ref< OrbitalSpace > &bra, const Ref< OrbitalSpace > &ket, bool accumulate=false)
Antisymmetrizes 4-index quantity <ij|A|kl> -> <ij|A|kl> - <ij|A|lk> and saves to Aanti.
void symmetrize(const Ref< GPetiteList2 > &plist2, const Ref< Integral > &integral, const RefSymmSCMatrix &skel, const RefSymmSCMatrix &sym)
Uses plist2 to convert the "skeleton" matrix into the full matrix. Only applicable when the two basis...
type
types of known two-body operators
Definition operator.h:318

Generated at Wed Sep 25 2024 02:45:29 for MPQC 3.0.0-alpha using the documentation package Doxygen 1.12.0.