MPQC  3.0.0-alpha
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 
39 namespace sc {
40 
41  template <typename DataProcess,
42  bool CorrFactorInBra,
43  bool CorrFactorInKet>
44  void
45  R12IntEval::compute_tbint_tensor(RefSCMatrix& T,
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 
181  if (debug_ > DefaultPrintThresholds::allO2N2)
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();
186  if (debug_ > DefaultPrintThresholds::allO2N2)
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 
sc::R12IntEval::compute_tbint_tensor
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.
sc::ManyBodyTensors::Apply_Inverse_Sqrt_H0minusE0
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
sc::RefDiagSCMatrix
The RefDiagSCMatrix class is a smart pointer to an DiagSCMatrix specialization.
Definition: matrix.h:389
sc::DefaultPrintThresholds::diagnostics
static const unsigned int diagnostics
Additional diagnostics, e.g., transform progress, etc.
Definition: print.h:39
sc::R12IntEval::r12world
const Ref< R12WavefunctionWorld > & r12world() const
the R12World in which this object lives
Definition: r12int_eval.h:642
sc::ManyBodyTensors::Apply_Inverse_H0minusE0
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
sc::TwoBodyOper::type
type
types of known two-body operators
Definition: operator.h:318
sc::ExEnv::out0
static std::ostream & out0()
Return an ostream that writes from node 0.
sc::ManyBodyTensors::Apply_H0minusE0
Applies (H0 - E0)
Definition: compute_tbint_tensor.h:271
sc::DefaultPrintThresholds::allO2N2
static const unsigned int allO2N2
Print all o^2N^2 quantities.
Definition: print.h:65
sc::ExEnv::outn
static std::ostream & outn()
Return an ostream that writes from all nodes.
Definition: exenv.h:81
sc::antisymmetrize
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.
sc
Contains all MPQC code up to version 3.
Definition: mpqcin.h:14
sc::ManyBodyTensors::Apply_Identity
Tensor elements are <pq||rs>
Definition: compute_tbint_tensor.h:254

Generated at Sun Jan 26 2020 23:23:58 for MPQC 3.0.0-alpha using the documentation package Doxygen 1.8.16.