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