MPQC  2.3.1
lgbuild.h
1 //
2 // lgbuild.h --- definition of the local G matrix builder
3 //
4 // Copyright (C) 1996 Limit Point Systems, Inc.
5 //
6 // Author: Edward Seidl <seidl@janed.com>
7 // Maintainer: LPS
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 #ifndef _chemistry_qc_scf_lgbuild_h
29 #define _chemistry_qc_scf_lgbuild_h
30 
31 #ifdef __GNUC__
32 #pragma interface
33 #endif
34 
35 #undef SCF_CHECK_INTS
36 #undef SCF_CHECK_BOUNDS
37 #undef SCF_DONT_USE_BOUNDS
38 
39 #include <scconfig.h>
40 #include <chemistry/qc/scf/gbuild.h>
41 
42 namespace sc {
43 
44 template<class T>
45 class LocalGBuild : public GBuild<T> {
46  public:
47  double tnint;
48 
49  protected:
50  MessageGrp *grp_;
51  TwoBodyInt *tbi_;
52  GaussianBasisSet *gbs_;
53  PetiteList *rpl_;
54 
55  signed char * restrictxx pmax;
56  int threadno_;
57  int nthread_;
58  double accuracy_;
59 
60  public:
61  LocalGBuild(T& t, const Ref<TwoBodyInt>& tbi, const Ref<PetiteList>& rpl,
62  const Ref<GaussianBasisSet>& bs, const Ref<MessageGrp>& g,
63  signed char *pm, double acc, int nt=1, int tn=0) :
64  GBuild<T>(t),
65  pmax(pm), nthread_(nt), threadno_(tn), accuracy_(acc)
66  {
67  grp_ = g.pointer();
68  tbi_ = tbi.pointer();
69  rpl_ = rpl.pointer();
70  gbs_ = bs.pointer();
71  }
72  ~LocalGBuild() {}
73 
74  void run() {
75  int tol = (int) (log(accuracy_)/log(2.0));
76  int me=grp_->me();
77  int nproc = grp_->n();
78 
79  // grab references for speed
80  GaussianBasisSet& gbs = *gbs_;
81  PetiteList& pl = *rpl_;
82  TwoBodyInt& tbi = *tbi_;
83 
84  tbi.set_redundant(0);
85  const double *intbuf = tbi.buffer();
86 
87  tnint=0;
88  sc_int_least64_t threadind=0;
89  sc_int_least64_t ijklind=0;
90 
91  for (int i=0; i < gbs.nshell(); i++) {
92  if (!pl.in_p1(i))
93  continue;
94 
95  int fi=gbs.shell_to_function(i);
96  int ni=gbs(i).nfunction();
97 
98  for (int j=0; j <= i; j++) {
99  int oij = i_offset(i)+j;
100 
101  if (!pl.in_p2(oij))
102  continue;
103 
104  int fj=gbs.shell_to_function(j);
105  int nj=gbs(j).nfunction();
106  int pmaxij = pmax[oij];
107 
108  for (int k=0; k <= i; k++, ijklind++) {
109  if (ijklind%nproc != me)
110  continue;
111 
112  threadind++;
113  if (threadind % nthread_ != threadno_)
114  continue;
115 
116  int fk=gbs.shell_to_function(k);
117  int nk=gbs(k).nfunction();
118 
119  int pmaxijk=pmaxij, ptmp;
120  if ((ptmp=pmax[i_offset(i)+k]-1) > pmaxijk) pmaxijk=ptmp;
121  if ((ptmp=pmax[ij_offset(j,k)]-1) > pmaxijk) pmaxijk=ptmp;
122 
123  int okl = i_offset(k);
124  for (int l=0; l <= (k==i?j:k); l++,okl++) {
125  int pmaxijkl = pmaxijk;
126  if ((ptmp=pmax[okl]) > pmaxijkl) pmaxijkl=ptmp;
127  if ((ptmp=pmax[i_offset(i)+l]-1) > pmaxijkl) pmaxijkl=ptmp;
128  if ((ptmp=pmax[ij_offset(j,l)]-1) > pmaxijkl) pmaxijkl=ptmp;
129 
130  int qijkl = pl.in_p4(oij,okl,i,j,k,l);
131  if (!qijkl)
132  continue;
133 
134 #ifdef SCF_CHECK_BOUNDS
135  double intbound = pow(2.0,double(tbi.log2_shell_bound(i,j,k,l)));
136  double pbound = pow(2.0,double(pmaxijkl));
137  intbound *= qijkl;
138  GBuild<T>::contribution.set_bound(intbound, pbound);
139 #else
140 # ifndef SCF_DONT_USE_BOUNDS
141  if (tbi.log2_shell_bound(i,j,k,l)+pmaxijkl < tol)
142  continue;
143 # endif
144 #endif
145 
146  //tim_enter_default();
147  tbi.compute_shell(i,j,k,l);
148  //tim_exit_default();
149 
150  int e12 = (i==j);
151  int e34 = (k==l);
152  int e13e24 = (i==k) && (j==l);
153  int e_any = e12||e34||e13e24;
154 
155  int fl=gbs.shell_to_function(l);
156  int nl=gbs(l).nfunction();
157 
158  int ii,jj,kk,ll;
159  int I,J,K,L;
160  int index=0;
161 
162  for (I=0, ii=fi; I < ni; I++, ii++) {
163  for (J=0, jj=fj; J <= (e12 ? I : nj-1); J++, jj++) {
164  for (K=0, kk=fk; K <= (e13e24 ? I : nk-1); K++, kk++) {
165  int lend = (e34 ? ((e13e24)&&(K==I) ? J : K)
166  : ((e13e24)&&(K==I)) ? J : nl-1);
167 
168  for (L=0, ll=fl; L <= lend; L++, ll++, index++) {
169 
170  double pki_int = intbuf[index];
171 
172  if ((pki_int>0?pki_int:-pki_int) < 1.0e-15)
173  continue;
174 
175 #ifdef SCF_CHECK_INTS
176 #ifdef HAVE_ISNAN
177  if (isnan(pki_int))
178  abort();
179 #endif
180 #endif
181 
182  if (qijkl > 1)
183  pki_int *= qijkl;
184 
185  if (e_any) {
186  int ij,kl;
187  double val;
188 
189  if (jj == kk) {
190  /*
191  * if i=j=k or j=k=l, then this integral contributes
192  * to J, K1, and K2 of G(ij), so
193  * pkval = (ijkl) - 0.25 * ((ikjl)-(ilkj))
194  * = 0.5 * (ijkl)
195  */
196  if (ii == jj || kk == ll) {
197  ij = i_offset(ii)+jj;
198  kl = i_offset(kk)+ll;
199  val = (ij==kl) ? 0.5*pki_int : pki_int;
200 
201  GBuild<T>::contribution.cont5(ij,kl,val);
202 
203  } else {
204  /*
205  * if j=k, then this integral contributes
206  * to J and K1 of G(ij)
207  *
208  * pkval = (ijkl) - 0.25 * (ikjl)
209  * = 0.75 * (ijkl)
210  */
211  ij = i_offset(ii)+jj;
212  kl = i_offset(kk)+ll;
213  val = (ij==kl) ? 0.5*pki_int : pki_int;
214 
215  GBuild<T>::contribution.cont4(ij,kl,val);
216 
217  /*
218  * this integral also contributes to K1 and K2 of
219  * G(il)
220  *
221  * pkval = -0.25 * ((ijkl)+(ikjl))
222  * = -0.5 * (ijkl)
223  */
224  ij = ij_offset(ii,ll);
225  kl = ij_offset(kk,jj);
226  val = (ij==kl) ? 0.5*pki_int : pki_int;
227 
228  GBuild<T>::contribution.cont3(ij,kl,val);
229  }
230  } else if (ii == kk || jj == ll) {
231  /*
232  * if i=k or j=l, then this integral contributes
233  * to J and K2 of G(ij)
234  *
235  * pkval = (ijkl) - 0.25 * (ilkj)
236  * = 0.75 * (ijkl)
237  */
238  ij = i_offset(ii)+jj;
239  kl = i_offset(kk)+ll;
240  val = (ij==kl) ? 0.5*pki_int : pki_int;
241 
242  GBuild<T>::contribution.cont4(ij,kl,val);
243 
244  /*
245  * this integral also contributes to K1 and K2 of
246  * G(ik)
247  *
248  * pkval = -0.25 * ((ijkl)+(ilkj))
249  * = -0.5 * (ijkl)
250  */
251  ij = ij_offset(ii,kk);
252  kl = ij_offset(jj,ll);
253  val = (ij==kl) ? 0.5*pki_int : pki_int;
254 
255  GBuild<T>::contribution.cont3(ij,kl,val);
256 
257  } else {
258  /*
259  * This integral contributes to J of G(ij)
260  *
261  * pkval = (ijkl)
262  */
263  ij = i_offset(ii)+jj;
264  kl = i_offset(kk)+ll;
265  val = (ij==kl) ? 0.5*pki_int : pki_int;
266 
267  GBuild<T>::contribution.cont1(ij,kl,val);
268 
269  /*
270  * and to K1 of G(ik)
271  *
272  * pkval = -0.25 * (ijkl)
273  */
274  ij = ij_offset(ii,kk);
275  kl = ij_offset(jj,ll);
276  val = (ij==kl) ? 0.5*pki_int : pki_int;
277 
278  GBuild<T>::contribution.cont2(ij,kl,val);
279 
280  if ((ii != jj) && (kk != ll)) {
281  /*
282  * if i!=j and k!=l, then this integral also
283  * contributes to K2 of G(il)
284  *
285  * pkval = -0.25 * (ijkl)
286  *
287  * note: if we get here, then ik can't equal jl,
288  * so pkval wasn't multiplied by 0.5 above.
289  */
290  ij = ij_offset(ii,ll);
291  kl = ij_offset(kk,jj);
292 
293  GBuild<T>::contribution.cont2(ij,kl,val);
294  }
295  }
296  } else { // !e_any
297  if (jj == kk) {
298  /*
299  * if j=k, then this integral contributes
300  * to J and K1 of G(ij)
301  *
302  * pkval = (ijkl) - 0.25 * (ikjl)
303  * = 0.75 * (ijkl)
304  */
305  GBuild<T>::contribution.cont4(i_offset(ii)+jj,i_offset(kk)+ll,pki_int);
306 
307  /*
308  * this integral also contributes to K1 and K2 of
309  * G(il)
310  *
311  * pkval = -0.25 * ((ijkl)+(ikjl))
312  * = -0.5 * (ijkl)
313  */
314  GBuild<T>::contribution.cont3(ij_offset(ii,ll),ij_offset(kk,jj),pki_int);
315 
316  } else if (ii == kk || jj == ll) {
317  /*
318  * if i=k or j=l, then this integral contributes
319  * to J and K2 of G(ij)
320  *
321  * pkval = (ijkl) - 0.25 * (ilkj)
322  * = 0.75 * (ijkl)
323  */
324  GBuild<T>::contribution.cont4(i_offset(ii)+jj,i_offset(kk)+ll,pki_int);
325 
326  /*
327  * this integral also contributes to K1 and K2 of
328  * G(ik)
329  *
330  * pkval = -0.25 * ((ijkl)+(ilkj))
331  * = -0.5 * (ijkl)
332  */
333  GBuild<T>::contribution.cont3(ij_offset(ii,kk),ij_offset(jj,ll),pki_int);
334 
335  } else {
336  /*
337  * This integral contributes to J of G(ij)
338  *
339  * pkval = (ijkl)
340  */
341  GBuild<T>::contribution.cont1(i_offset(ii)+jj,i_offset(kk)+ll,pki_int);
342 
343  /*
344  * and to K1 of G(ik)
345  *
346  * pkval = -0.25 * (ijkl)
347  */
348  GBuild<T>::contribution.cont2(ij_offset(ii,kk),ij_offset(jj,ll),pki_int);
349 
350  /*
351  * and to K2 of G(il)
352  *
353  * pkval = -0.25 * (ijkl)
354  */
355  GBuild<T>::contribution.cont2(ij_offset(ii,ll),ij_offset(kk,jj),pki_int);
356  }
357  }
358  }
359  }
360  }
361  }
362 
363  tnint += (double) ni*nj*nk*nl;
364  }
365  }
366  }
367  }
368  }
369 };
370 
371 }
372 
373 #endif
374 
375 // Local Variables:
376 // mode: c++
377 // c-file-style: "ETS"
378 // End:
sc::LocalGBuild::run
void run()
This is called with the Thread is run from a ThreadGrp.
Definition: lgbuild.h:74
sc::TwoBodyInt
This is an abstract base type for classes that compute integrals involving two electrons.
Definition: tbint.h:49
sc::Ref
A template class that maintains references counts.
Definition: ref.h:332
sc::TwoBodyInt::buffer
virtual const double * buffer(tbint_type type=eri) const
The computed shell integrals will be put in the buffer returned by this member.
sc::Ref::pointer
T * pointer() const
Returns a pointer the reference counted object.
Definition: ref.h:383
sc::GBuild
Definition: gbuild.h:41
sc::TwoBodyInt::compute_shell
virtual void compute_shell(int, int, int, int)=0
Given four shell indices, integrals will be computed and placed in the buffer.
sc::MessageGrp::me
int me()
Returns my processor number. In the range [0,n()).
Definition: message.h:138
sc::PetiteList
Definition: petite.h:119
sc::MessageGrp::n
int n()
Returns the number of processors.
Definition: message.h:136
sc::LocalGBuild
Definition: lgbuild.h:45
sc::TwoBodyInt::set_redundant
virtual void set_redundant(int i)
See redundant().
Definition: tbint.h:135
sc::TwoBodyInt::log2_shell_bound
virtual int log2_shell_bound(int=-1, int=-1, int=-1, int=-1)=0
Return log base 2 of the maximum magnitude of any integral in a shell block obtained from compute_she...
sc::GaussianBasisSet
The GaussianBasisSet class is used describe a basis set composed of atomic gaussian orbitals.
Definition: gaussbas.h:145
sc::GaussianBasisSet::shell_to_function
int shell_to_function(int i) const
Return the number of the first function in the given shell.
Definition: gaussbas.h:454
sc::GaussianBasisSet::nshell
int nshell() const
Return the number of shells.
Definition: gaussbas.h:417
sc::MessageGrp
The MessageGrp abstract class provides a mechanism for moving data and objects between nodes in a par...
Definition: message.h:109

Generated at Sun Jan 26 2020 23:33:04 for MPQC 2.3.1 using the documentation package Doxygen 1.8.16.