1 /*
2 
3 Copyright (C) 2007 Lucas K. Wagner
4 
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 
19 */
20 #include "overlaps.h"
21 #include "integrals.h"
22 
23 //----------------------------------------------------------------------
24 
25 //Divide the job for the overlaps..
26 //NOTE: this is not the optimal division, since we're doing a triangular
27 //matrix.  Should be easy to change.
divide_job_ov(int node,int nprocs,int npoints,int & start,int & end)28 void divide_job_ov(int node, int nprocs, int npoints, int & start, int & end) {
29   start=node*npoints/nprocs;
30   end=(node+1)*npoints/nprocs;
31 }
32 
33 //----------------------------------------------------------------------
34 #include <vector>
35 using namespace std;
36 
37 
read_mo(string & orbin,int nmo,int nfunc,Array2<doublevar> & moCoeff)38 void read_mo(string & orbin, int nmo, int nfunc, Array2 <doublevar> & moCoeff) {
39   ifstream in(orbin.c_str());
40   if(!in) error("Couldn't open ", orbin);
41   string dummy;
42   in >> dummy;
43   while(dummy != "COEFFICIENTS")
44     in >> dummy;
45 
46   moCoeff.Resize(nmo, nfunc);
47   for(int m=0; m< nmo; m++) {
48     for(int f=0; f< nfunc; f++) {
49       in >> moCoeff(m,f);
50      }
51   }
52 }
53 
54 
55 /*!
56 Compare the sets of molecular orbitals, and
57 return true if they're the same, and false if not
58 Currently it doesn't use the lcao_overlap matrix, but
59 should be modified to do that; it's approximate otherwise.
60 */
compare_mo(Array2<doublevar> & oldMOCoeff,Array2<doublevar> & newMOCoeff,Array2<doublevar> & lcao_overlap,Array1<int> compare_list)61 bool compare_mo(Array2 <doublevar> & oldMOCoeff,
62                 Array2 <doublevar> & newMOCoeff,
63                 Array2 <doublevar> & lcao_overlap,
64                 Array1 <int> compare_list) {
65 
66  assert(oldMOCoeff.GetDim(1)==newMOCoeff.GetDim(1));
67 
68  int nfunctions=oldMOCoeff.GetDim(1);
69 
70  int ncompare=compare_list.GetDim(0);
71  if(newMOCoeff.GetDim(0) < ncompare)
72    error("the punch file doesn't have enough molecular orbitals to compare.");
73  if(oldMOCoeff.GetDim(0) < ncompare)
74    error("the old punch file doesn't have enough MO's to compare.");
75 
76   vector <int> unresolved_mos;
77 
78   //First check to see if the mo's are in the same place
79   //(most should be)
80   for(int i=0; i< ncompare; i++) {
81     int mo=compare_list(i);
82     double dot=0, mag_old=0, mag_new=0;
83     for(int f=0; f< nfunctions; f++) {
84       dot+=newMOCoeff(mo,f)*oldMOCoeff(mo,f);
85       mag_old+=oldMOCoeff(mo,f)*oldMOCoeff(mo,f);
86       mag_new+=newMOCoeff(mo,f)*newMOCoeff(mo,f);
87     }
88     dot /= sqrt(mag_old*mag_new);
89     dot =fabs(dot);
90     cout << "mo " << mo << "  dot " << dot << endl;
91     if(fabs(dot-1) > .01) {
92       unresolved_mos.push_back(mo);
93     }
94   }
95 
96   int nunresolved=unresolved_mos.size();
97   for(int i=0; i< nunresolved; i++) {
98     cout << "not matched: " << unresolved_mos[i] << endl;
99   }
100 
101 
102   bool are_same=true;
103   //See if any just swapped..
104   for(int i=0; i< nunresolved; i++) {
105     int mo1=unresolved_mos[i];
106     bool resolved_swapping=false;
107 
108     for(int j=0; j< nunresolved; j++) {
109       int mo2=unresolved_mos[j];
110 
111       double dot=0, mag_old=0, mag_new=0;
112       for(int f=0; f< nfunctions; f++) {
113         dot+=newMOCoeff(mo1,f)*oldMOCoeff(mo2,f);
114         mag_old+=oldMOCoeff(mo2,f)*oldMOCoeff(mo2,f);
115         mag_new+=newMOCoeff(mo1,f)*newMOCoeff(mo1,f);
116       }
117       dot /= sqrt(mag_old*mag_new);
118       dot=fabs(dot);
119       if(fabs(dot-1) < .01) {
120         cout << "switched orbital: mo " << mo2 << " went to " << mo1
121              << " dot product " << dot
122              << endl;
123         resolved_swapping=true;
124       }
125     }
126 
127     if(!resolved_swapping) {
128       cout << "Unresolvable change in mo " << mo1 << endl;
129       are_same=false;
130     }
131 
132   }
133 
134   return are_same;
135 }
136 
137 
138 //----------------------------------------------------------------------
139 
calculate_overlap(Array2<doublevar> & latvec,Array1<doublevar> & origin,Array1<Center> & centers,Array1<Contracted_gaussian> & basis,Gaussian_lookups & lookup,Array2<doublevar> & lcao_overlap)140 void calculate_overlap(Array2 <doublevar> & latvec,
141                        Array1 <doublevar> & origin,
142                        Array1 <Center> & centers,
143                        Array1 <Contracted_gaussian> & basis,
144                        Gaussian_lookups & lookup,
145                        Array2 <doublevar> & lcao_overlap) {
146 
147   assert(lookup.totbasis2cen.GetDim(0)==lookup.totbasis2cen.GetDim(0));
148 
149   int totbasis=lookup.totbasis2cen.GetDim(0);
150   //int ncenters=centers.GetDim(0);
151   int nbasis=basis.GetDim(0);
152 
153   //Find the ranges of the basis functions
154   //We calculate the range from viewing it as two
155   //primitive S orbitals with parameter equal to
156   //the smallest alpha orbital in the contraction
157   const doublevar basis_tolerance=1e-10;
158   Array1 <doublevar> minalpha(nbasis);
159   for(int bas=0; bas < nbasis; bas++) {
160     int nalpha=basis(bas).alpha.GetDim(0);
161     minalpha(bas)=basis(bas).alpha(0);
162     for(int a=1; a < nalpha; a++) {
163       if(basis(bas).alpha(a) < minalpha(bas))
164         minalpha(bas)=basis(bas).alpha(a);
165     }
166   }
167 
168   Array2 <doublevar> basis_range(nbasis, nbasis);
169   for(int bas1=0; bas1< nbasis; bas1++) {
170     for(int bas2=bas1; bas2 < nbasis; bas2++) {
171       doublevar gamma=minalpha(bas1)+minalpha(bas2);
172       basis_range(bas1, bas2)=-gamma
173                            *log( (gamma/pi)*sqrt(gamma/pi)*basis_tolerance)
174                            /(minalpha(bas1)*minalpha(bas2));
175       //cout << sqrt(basis_range(bas1, bas2)) << "   ";
176     }
177     //cout << endl;
178   }
179   for(int bas1=0; bas1 < nbasis; bas1++) {
180     for(int bas2=0; bas2 < bas1; bas2++) {
181       basis_range(bas1, bas2)= basis_range(bas2, bas1);
182     }
183   }
184 
185   int basis_start=0;
186   int basis_end=totbasis;
187 #ifdef USE_MPI
188   divide_job_ov(mpi_info.node, mpi_info.nprocs,
189                 totbasis, basis_start, basis_end);
190 #endif
191 
192   //lcao_overlap.Resize(totbasis, totbasis);
193   lcao_overlap.Resize(basis_end-basis_start, totbasis);
194   lcao_overlap=0;
195 
196 
197 
198   const int doublefac_size=10;
199   //offset by one, so we can map the range -1 to inf to 0 to inf
200   Array1 <int> doublefac_cache(doublefac_size);
201   for(int i=0; i< doublefac_size; i++) {
202     doublefac_cache(i)=doublefactorial(i-1);
203   }
204 
205   const int binomial_size=8;
206   Array2 <int> binomial_cache(binomial_size, binomial_size);
207   for(int i=0; i< binomial_size; i++) {
208     for(int j=0; j<=i; j++) {
209       binomial_cache(i,j)=binomial2(i,j);
210     }
211   }
212 
213   //  int basis_start=0;
214   //int basis_end=totbasis;
215   //#ifdef USE_MPI
216   //divide_job_ov(mpi_info.node, mpi_info.nprocs, totbasis, basis_start, basis_end);
217   //#endif
218 
219   Array1 <doublevar> move_pos(3);
220   for(int b1=basis_start; b1 < basis_end; b1++) {
221     //if(b1%5==0) cout << "."; cout.flush();
222     int offb=b1-basis_start;
223 
224     int bas1=lookup.totbasis2bas(b1);
225     int cen1=lookup.totbasis2cen(b1);
226     int nalpha1=basis(bas1).alpha.GetDim(0);
227 
228     for(int b2=b1; b2 < totbasis; b2++) {
229       int bas2=lookup.totbasis2bas(b2);
230       int cen2=lookup.totbasis2cen(b2);
231       int nalpha2=basis(bas2).alpha.GetDim(0);
232 
233 
234       doublevar overlap_tot=0;
235       const int depth=4;
236       for(int ii=-depth; ii <= depth; ii++) {
237       for(int jj=-depth; jj <= depth; jj++) {
238       for(int kk=-depth; kk <= depth; kk++) {
239 
240       for(int d=0; d< 3; d++)
241         move_pos(d)=centers(cen2).pos(d)-centers(cen1).pos(d)
242                     +ii*latvec(0,d)
243                     +jj*latvec(1,d)
244                     +kk*latvec(2,d);
245 
246       doublevar AB2=0.0;
247       for(int d=0; d< 3; d++) AB2+=move_pos(d)*move_pos(d);
248 
249       if(AB2 < basis_range(bas1, bas2))
250       for(int a1=0; a1 < nalpha1; a1++) {
251         for(int a2=0; a2 < nalpha2; a2++) {
252           //doublevar overlap=S12_f(basis(bas1).lvals, basis(bas2).lvals,
253           //                    basis(bas1).alpha(a1), basis(bas2).alpha(a2),
254           //                    centers(cen1).pos, move_pos);
255           doublevar alpha1=basis(bas1).alpha(a1);
256           doublevar alpha2=basis(bas2).alpha(a2);
257           doublevar gamma=alpha1+alpha2;
258 
259           doublevar invgamma=1.0/gamma;
260           doublevar PA, PB, dummyI=1.0;
261           doublevar sqrtgamma=sqrt(pi/gamma);
262           doublevar diff, tmpint, fsum;
263           for(int d=0; d< 3; d++) {
264             int l1=basis(bas1).lvals(d);
265             int l2=basis(bas2).lvals(d);
266             diff=move_pos(d);
267             //AB2+=diff*diff;
268             PA=diff*alpha2*invgamma;
269             PB=-diff*alpha1*invgamma;
270             tmpint=0.0;
271             for(int j=0; j<= 0.5*(l1+l2); j++) {
272               fsum=0.0;
273               int qstart=max(-2*j, 2*(j-l2));
274               int qend=min(2*j, 2*(l1-j));
275               for(int q=qstart; q<= qend; q+=2) {
276                 int ti=int(j+0.5*q);
277                 int tj=int(j-0.5*q);
278                 //fsum+=binomial2(l1,ti)*binomial2(l2,tj)*pow(PA, l1-ti)
279                 //  *pow(PB, l2-tj);
280                 fsum+=binomial_cache(l1,ti)*binomial_cache(l2,tj)
281                       *pow(PA, l1-ti)*pow(PB, l2-tj);
282               }
283               tmpint+=fsum
284                       *doublefac_cache(2*j)
285                       *pow(2.0*gamma, -j);
286             }
287             dummyI*=tmpint*sqrtgamma;
288           }
289           doublevar overlap=exp(-alpha1*alpha2*AB2*invgamma)*dummyI;
290           overlap_tot+=basis(bas1).coeff(a1)*basis(bas2).coeff(a2)*overlap;
291         }
292       }
293       }
294       }
295       }
296       //cout << "overlap_tot " << overlap_tot << endl;
297       lcao_overlap(offb, b2)=overlap_tot;
298 
299     }
300   }
301   //cout << endl;
302 
303   /*
304 #ifdef USE_MPI
305   for(int b1=0; b1 < totbasis; b1++) {
306 
307     int bcast_node=0;
308     for(int n=0; n< mpi_info.nprocs; n++) {
309       int node_start;//=n*nmo_fit/mpi_info.nprocs;
310       int node_end;//=(n+1)*nmo_fit/mpi_info.nprocs;
311       divide_job_ov(n, mpi_info.nprocs, totbasis, node_start, node_end);
312       if(b1 >= node_start && b1 < node_end) {
313         bcast_node=n;
314         break;
315       }
316     }
317 
318     //if(bcast_node==mpi_info.node)
319     //  cout << "broadcasting " << mo << " "  << bcast_node << endl;
320     MPI_Bcast(lcao_overlap.v+b1*totbasis, totbasis, MPI_DOUBLE, bcast_node,
321               MPI_COMM_WORLD);
322   }
323 #endif
324 
325 
326   //Enforce symmetric matrix
327   for(int b1=0; b1 < totbasis; b1++) {
328     for(int b2=0; b2 < b1; b2++) {
329       lcao_overlap(b1,b2)=lcao_overlap(b2,b1);
330     }
331   }
332   */
333 
334 
335 }
336 //----------------------------------------------------------------------
337 
338