~ubuntu-branches/ubuntu/quantal/psicode/quantal

« back to all changes in this revision

Viewing changes to src/bin/cis/local.cc

  • Committer: Bazaar Package Importer
  • Author(s): Michael Banck, Michael Banck, Daniel Leidert
  • Date: 2009-02-23 00:12:02 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20090223001202-rutldoy3dimfpesc
Tags: 3.4.0-1
* New upstream release.

[ Michael Banck ]
* debian/patches/01_DESTDIR.dpatch: Refreshed.
* debian/patches/02_FHS.dpatch: Removed, applied upstream.
* debian/patches/03_debian_docdir: Likewise.
* debian/patches/04_man.dpatch: Likewise.
* debian/patches/06_466828_fix_gcc_43_ftbfs.dpatch: Likewise.
* debian/patches/07_464867_move_executables: Fixed and refreshed.
* debian/patches/00list: Adjusted.
* debian/control: Improved description.
* debian/patches-held: Removed.
* debian/rules (install/psi3): Do not ship the ruby bindings for now.

[ Daniel Leidert ]
* debian/rules: Fix txtdir via DEB_MAKE_INSTALL_TARGET.
* debian/patches/01_DESTDIR.dpatch: Refreshed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*! \file
 
2
    \ingroup CIS
 
3
    \brief Enter brief description of file here 
 
4
*/
 
5
 
 
6
#include <cstdio>
 
7
#include <cstdlib>
 
8
#include <cstring>
 
9
#include <cmath>
 
10
#include <libipv1/ip_lib.h>
 
11
#include <libciomr/libciomr.h>
 
12
#include <libpsio/psio.h>
 
13
#include <libiwl/iwl.h>
 
14
#include <libint/libint.h>
 
15
#include <libchkpt/chkpt.h>
 
16
#include <libqt/qt.h>
 
17
#include <libdpd/dpd.h>
 
18
#include <psifiles.h>
 
19
#include "MOInfo.h"
 
20
#include "Params.h"
 
21
#include "Local.h"
 
22
#define EXTERN
 
23
#include "globals.h"
 
24
 
 
25
namespace psi { namespace cis {
 
26
 
 
27
/*! 
 
28
** local_init(): Set up parameters of local excitation domains.
 
29
**
 
30
** The orbital domains constructed here are based on those described
 
31
** in Broughton and Pulay, J. Comp. Chem. 14, 736-740 (1993).  The
 
32
** localization of the occupied orbitals is done elsewhere (see the
 
33
** program "local").  Pair domains are defined as the union of pairs
 
34
** of single occupied orbital domains.  "Weak pairs", which are
 
35
** defined as pair domains whose individual occupied orbital domains
 
36
** have no atoms in common, are identified (cf. int *weak_pairs).
 
37
** 
 
38
** TDC, Jan-June 2002
 
39
*/
 
40
 
 
41
void local_init(void)
 
42
{
 
43
  int i, j, k, ij, stat, a, b, r, l, I, L;
 
44
  int nmo, nso, nocc, nocc_all, nvir, noei, nirreps, nfzc;
 
45
  double **C;  /* AO -> localized MO transformation matrix */
 
46
  double **Ci; /* localized MO -> AO transformation matrix */
 
47
  double **D;  /* 1/2 SCF closed-shell density matrix (AO) */
 
48
  double **Rt, **Rt_full; /* Projected, redundant virtual transform (R-tilde) */
 
49
  double **S;  /* AO overlap */
 
50
  double **St; /* Projected virtual overlap */
 
51
  double **Xt; /* Projected, non-redundant virtual transform (X-tilde) */
 
52
  double ***V;  /* MO -> projected, redundant virtual transform */
 
53
  double **Fmo;/* MO basis Fock matrix */
 
54
  double **F;  /* AO basis Fock matrix */
 
55
  double **Ft; /* Projected, redundant virtual Fock matrix */
 
56
  double **Fbar; /* Projected, non-redundant virtual Fock matrix */
 
57
  double ***W;  /* Transformation matrix from tilde -> bar for each ij pair*/
 
58
  double *eps_occ; /* occupied orbital energies for local denominators */
 
59
  double **eps_vir; /* virtual orbital energies for local denominators */
 
60
  double **X, **Y;
 
61
  double *evals, **evecs;
 
62
  double *eps_all; /* All MO energies */
 
63
  dpdfile2 fock, FMI, FAE;
 
64
 
 
65
  int natom, atom, am, offset, nshell, shell_length, next_atom;
 
66
  int row, col, max, m, errcod, cnt;
 
67
  int *rank, *boolean, *ipiv;
 
68
  int *l_length, *aostart, *aostop, *ao2atom;
 
69
  int *stype, *snuc;
 
70
  int **domain, *domain_len, **pairdomain, *pairdom_len, *pairdom_nrlen;
 
71
  int *weak_pairs;
 
72
  double *fR, cutoff, *charge, *SR, *Z, tmp, *ss;
 
73
 
 
74
  int print_test, num_entries, entry_len, orbital;
 
75
  int t1_length, t2_length, puream, weak;
 
76
  double norm;
 
77
 
 
78
  int num_zero;
 
79
  double **U, **R, **WW, **RS;
 
80
 
 
81
  chkpt_init(PSIO_OPEN_OLD);
 
82
  C = chkpt_rd_scf();
 
83
  natom = chkpt_rd_natom();
 
84
  nshell = chkpt_rd_nshell();
 
85
  puream = chkpt_rd_puream();
 
86
  eps_all = chkpt_rd_evals();
 
87
  stype = chkpt_rd_stype();
 
88
  snuc = chkpt_rd_snuc();
 
89
  chkpt_close();
 
90
 
 
91
  timer_on("Local");
 
92
 
 
93
  /* C1 symmetry only */
 
94
  nirreps = moinfo.nirreps;
 
95
  if(nirreps != 1) {
 
96
    fprintf(outfile, "\nError: localization must use C1 symmetry.\n");
 
97
    exit(PSI_RETURN_FAILURE);
 
98
  }
 
99
 
 
100
  nso = moinfo.nso;
 
101
  nmo = moinfo.nmo; /* should be the same as nso */
 
102
  if(nmo != nso) {
 
103
    fprintf(outfile, "\nError: NMO != NSO!  %d != %d\n", nmo, nso);
 
104
    exit(PSI_RETURN_FAILURE);
 
105
  }
 
106
 
 
107
  nocc = moinfo.occpi[0]; /* active doubly occupied orbitals */
 
108
  nfzc = moinfo.frdocc[0];  /* frozen doubly occupied orbitals */
 
109
  nocc_all = nocc + nfzc; /* all doubly occupied orbitals */
 
110
  nvir = moinfo.virtpi[0]; /* active virtual orbitals */
 
111
 
 
112
  local.nso = nso;
 
113
  local.natom = natom;
 
114
  local.nocc = nocc;
 
115
  local.nvir = nvir;
 
116
 
 
117
  /* A couple of scratch arrays */
 
118
  X = block_matrix(nso, nso);
 
119
  Y = block_matrix(nso, nso);
 
120
 
 
121
  /* Invert C */
 
122
  Ci = block_matrix(nso, nso);
 
123
  for(i=0; i < nso; i++)
 
124
    for(j=0; j < nso; j++)
 
125
      Y[i][j] = C[i][j];
 
126
 
 
127
  invert_matrix(C, Ci, nso, outfile);
 
128
 
 
129
  for(i=0; i < nso; i++)
 
130
    for(j=0; j < nso; j++)
 
131
      C[i][j] = Y[i][j];
 
132
 
 
133
  /*
 
134
    fprintf(outfile, "\n\tC inverse (Ci):\n");
 
135
    print_mat(Ci, nso, nso, outfile);
 
136
  */
 
137
 
 
138
  /* Compute the AO-basis overlap integrals */
 
139
  /*
 
140
    S = block_matrix(nso,nso);
 
141
    C_DGEMM('t','n',nso,nso,nso,1.0,&(Ci[0][0]),nso,&(Ci[0][0]),nso,
 
142
    0.0,&(S[0][0]),nso);
 
143
  */
 
144
 
 
145
  /* Get the overlap integrals -- these should be identical to AO S */
 
146
  noei = nso*(nso+1)/2;
 
147
  ss = init_array(noei);
 
148
  stat = iwl_rdone(PSIF_OEI,PSIF_SO_S,ss,noei,0,0,outfile);
 
149
  S = block_matrix(nso,nso);
 
150
  for(i=0,ij=0; i < nso; i++)
 
151
    for(j=0; j <= i; j++,ij++) {
 
152
      S[i][j] = S[j][i] = ss[ij];
 
153
    }
 
154
  free(ss);
 
155
 
 
156
  /*
 
157
    fprintf(outfile, "\n\tAO Overlap (S)\n");
 
158
    print_mat(S, nso, nso, outfile);
 
159
  */
 
160
 
 
161
  /* Build the SCF closed-shell density matrix/2 */
 
162
  D = block_matrix(nso,nso);
 
163
  for(i=0; i < nso; i++) 
 
164
    for(j=0; j < nso; j++)
 
165
      for(k=0; k < nocc_all; k++)
 
166
        D[i][j] += C[i][k] * C[j][k];
 
167
 
 
168
  /*
 
169
    fprintf(outfile, "\n\tAO-basis SCF Density (D):\n");
 
170
    print_mat(D, nso, nso, outfile);
 
171
  */
 
172
 
 
173
 
 
174
  /* Compute the length of each AM block */
 
175
  l_length = init_int_array(LIBINT_MAX_AM);
 
176
  l_length[0] = 1;
 
177
  for(l=1; l < LIBINT_MAX_AM; l++) {
 
178
    if(puream) l_length[l] = 2 * l + 1;
 
179
    else l_length[l] = l_length[l-1] + l + 1;
 
180
  }
 
181
 
 
182
  /* Set up the atom->AO and AO->atom lookups */
 
183
  aostart = init_int_array(natom);
 
184
  aostop = init_int_array(natom);
 
185
  for(i=0,atom=-1,offset=0; i < nshell; i++) {
 
186
    am = stype[i] - 1;
 
187
    shell_length = l_length[am];
 
188
 
 
189
    if(atom != snuc[i] - 1) {
 
190
      if(atom != -1) aostop[atom] = offset-1;
 
191
      atom = snuc[i]-1;
 
192
      aostart[atom] = offset;
 
193
    }
 
194
    offset += shell_length;
 
195
  }
 
196
  aostop[atom] = offset-1;
 
197
 
 
198
  ao2atom = init_int_array(nso);
 
199
  for(i=0; i < natom; i++)
 
200
    for(j=aostart[i]; j <= aostop[i]; j++) ao2atom[j] = i;
 
201
 
 
202
  free(stype);
 
203
  free(snuc);
 
204
 
 
205
  /************* Build the orbital domains ************/
 
206
 
 
207
  domain = init_int_matrix(nocc, natom);
 
208
  domain_len = init_int_array(nocc);
 
209
  charge = init_array(natom);
 
210
  rank = init_int_array(natom);
 
211
  boolean = init_int_array(natom);
 
212
  SR = init_array(nso);
 
213
  Z = init_array(nso);
 
214
  ipiv = init_int_array(nso);
 
215
  fR = init_array(nocc);
 
216
 
 
217
  for(i=nfzc; i < nocc_all; i++) {
 
218
 
 
219
    /* Compute the contribution of each atom to this orbital's charge/population */
 
220
    for(j=0; j < natom; j++) {
 
221
      charge[j] = 0.0;
 
222
      for(k=aostart[j]; k <= aostop[j]; k++) {
 
223
        tmp = 0.0;
 
224
        for(l=0; l < nso; l++) tmp += S[k][l] * C[l][i];
 
225
        tmp *= C[k][i];
 
226
        charge[j] += tmp;
 
227
      }
 
228
    }
 
229
 
 
230
    /* Rank the atomic contributions to the orbital's charge */
 
231
    for(j=0; j < natom; j++) { rank[j] = 0; boolean[j] = 0; }
 
232
    for(j=0,max=0; j < natom; j++) /* find the overall maximum */
 
233
      if(fabs(charge[j]) >= fabs(charge[max])) max = j;
 
234
    rank[0] = max; boolean[max] = 1;
 
235
    for(j=1; j < natom; j++) {
 
236
      max = 0;
 
237
      while(boolean[max]) max++; /* find an unused max */
 
238
      for(k=0; k < natom; k++) 
 
239
        if((fabs(charge[k]) >= fabs(charge[max])) && !boolean[k]) max = k;
 
240
      rank[j] = max; boolean[max] = 1;
 
241
    }
 
242
 
 
243
    /* Build the orbital's domain starting in order of decreasing charge contribution */
 
244
    for(j=0; j < nso; j++) {
 
245
      SR[j] = 0.0;
 
246
      for(k=0; k < nso; k++)
 
247
        SR[j] += S[j][k] * C[k][i]; 
 
248
    }
 
249
 
 
250
    domain[i-nfzc][rank[0]] = 1; /* at least one atom must be in the domain */
 
251
    domain_len[i-nfzc] = 1;
 
252
 
 
253
    fR[i-nfzc] = 1.0;
 
254
    next_atom = 1;
 
255
    while(fabs(fR[i-nfzc]) > local.cutoff) {
 
256
 
 
257
      /* Completeness check */
 
258
      for(j=0,row=0; j < natom; j++) {
 
259
        if(domain[i-nfzc][j]) { 
 
260
          for(k=aostart[j]; k <= aostop[j]; k++,row++) {
 
261
 
 
262
            Z[row] = SR[k];
 
263
 
 
264
            for(l=0,col=0; l < natom; l++) {
 
265
              if(domain[i-nfzc][l]) {
 
266
 
 
267
                for(m=aostart[l]; m <= aostop[l]; m++,col++)
 
268
                  X[row][col] = S[k][m];
 
269
 
 
270
              }
 
271
            } /* l */
 
272
 
 
273
          } /* k */
 
274
        }
 
275
      } /* j */
 
276
 
 
277
      errcod = C_DGESV(row, 1, &(X[0][0]), nso, &(ipiv[0]), &(Z[0]), nso);
 
278
      if(errcod) {
 
279
        fprintf(outfile, "\nError in DGESV return in orbital domain construction.\n");
 
280
        exit(PSI_RETURN_FAILURE);
 
281
      }
 
282
 
 
283
      fR[i-nfzc] = 1.0;
 
284
      for(j=0,row=0; j < natom; j++) {
 
285
        if(domain[i-nfzc][j]) {
 
286
          for(k=aostart[j]; k <= aostop[j]; k++,row++) 
 
287
            for(l=0; l < nso; l++) fR[i-nfzc] -= Z[row] * S[k][l] * C[l][i];
 
288
        }
 
289
      }
 
290
 
 
291
      /* Augment the domain if necessary */
 
292
      if(fabs(fR[i-nfzc]) > local.cutoff) { 
 
293
        domain[i-nfzc][rank[next_atom++]] = 1;
 
294
        domain_len[i-nfzc]++;
 
295
      }
 
296
 
 
297
    } /* cutoff check */
 
298
 
 
299
  } /* i */
 
300
 
 
301
  /* Allow user adjustment of selected domains */
 
302
  if(ip_exist("DOMAINS",0)) {
 
303
    ip_count("DOMAINS", &num_entries,0);
 
304
    for(i=0; i < num_entries; i++) {
 
305
      ip_count("DOMAINS", &entry_len, 1, i);
 
306
      ip_data("DOMAINS", "%d", &orbital, 2, i, 0);
 
307
 
 
308
      /* Clear out the current domain for this orbital */
 
309
      /*
 
310
      for(j=0; j < natom; j++) domain[orbital][j] = 0;
 
311
      domain_len[orbital] = 0;
 
312
      */
 
313
 
 
314
      for(j=1; j < entry_len; j++) {
 
315
        errcod = ip_data("DOMAINS","%d", &atom,2,i,j);
 
316
        domain[orbital][atom] = 1;
 
317
        domain_len[orbital]++;
 
318
      }
 
319
    }
 
320
  }
 
321
 
 
322
  /* Print the orbital domains */
 
323
  max = 0;
 
324
  for(i=0; i < nocc; i++) 
 
325
    if(domain_len[i] > max) max = domain_len[i];
 
326
 
 
327
  fprintf(outfile, "\n   ****** Occupied Orbital Domains ******\n");
 
328
  fprintf(outfile, "   Orbital  Domain");
 
329
  for(i=0; i < max-2; i++) fprintf(outfile, "   "); /* formatting junk */
 
330
  fprintf(outfile, "  Completeness\n");
 
331
  fprintf(outfile, "   -------  ------");
 
332
  for(i=0; i < max-2; i++) fprintf(outfile, "---"); /* more formatting junk */
 
333
  fprintf(outfile, "  ------------\n");
 
334
  for(i=0; i < nocc; i++) {
 
335
    fprintf(outfile, "      %2d    ",i);
 
336
    for(j=0,cnt=0; j < natom; j++) if(domain[i][j]) { fprintf(outfile, " %2d", j); cnt++; }
 
337
    if(cnt < max) for(; cnt < max; cnt++) fprintf(outfile, "   ");
 
338
    fprintf(outfile, "     %7.5f\n", fR[i]);
 
339
  }
 
340
  fflush(outfile);
 
341
 
 
342
  /* Build the pair domains */
 
343
  pairdomain = init_int_matrix(nocc*nocc,natom);
 
344
  pairdom_len = init_int_array(nocc*nocc);
 
345
  for(i=0,ij=0; i < nocc; i++)
 
346
    for(j=0; j < nocc; j++,ij++)
 
347
      for(k=0; k < natom; k++) {
 
348
        if(domain[i][k] || domain[j][k]) {
 
349
          pairdomain[ij][k] = 1;
 
350
          pairdom_len[ij] += aostop[k] - aostart[k] + 1;
 
351
        }
 
352
      }
 
353
 
 
354
  /* Identify and/or remove weak pairs */
 
355
  weak_pairs = init_int_array(nocc*nocc);
 
356
  fprintf(outfile, "\n");
 
357
  for(i=0,ij=0; i < nocc; i++)
 
358
    for(j=0; j < nocc; j++,ij++) {
 
359
      weak = 1;
 
360
      for(k=0; k < natom; k++)
 
361
        if(domain[i][k] && domain[j][k] && local.ghost != k) weak = 0;
 
362
 
 
363
      if(weak && strcmp(local.weakp,"NONE")) {
 
364
        weak_pairs[ij] = 1;
 
365
 
 
366
        if(!strcmp(local.weakp,"MP2"))
 
367
          fprintf(outfile, "\tPair %d %d [%d] is weak and will be treated with MP2.\n", i, j, ij);
 
368
        else if(!strcmp(local.weakp,"NEGLECT")) {
 
369
          fprintf(outfile, "\tPair %d %d = [%d] is weak and will be deleted.\n", i, j, ij);
 
370
        }
 
371
      }
 
372
      else weak_pairs[ij] = 0; 
 
373
    }
 
374
 
 
375
  /* Compute the total number of singles and doubles */
 
376
  t1_length = t2_length = 0;
 
377
  for(i=0,ij=0; i < nocc; i++) {
 
378
    t1_length += domain_len[i];
 
379
    for(j=0; j < nocc; j++,ij++) {
 
380
      for(k=0; k < natom; k++) {
 
381
        for(l=0; l < natom; l++) {
 
382
          if(pairdomain[ij][k] && pairdomain[ij][l] && !weak_pairs[ij]) {
 
383
            for(a=aostart[k]; a <= aostop[k]; a++)
 
384
              for(b=aostart[l]; b <= aostop[l]; b++)
 
385
                t2_length++;
 
386
          }
 
387
        }
 
388
      }
 
389
    }
 
390
  }
 
391
 
 
392
  /* Print excitation space reduction info */
 
393
  fprintf(outfile, "\n\tT1 Length = %d (local), %d (canonical)\n",
 
394
          t1_length, nocc*nvir);
 
395
  fprintf(outfile, "\tT2 Length = %d (local), %d (canonical)\n\n",
 
396
          t2_length, nocc*nocc*nvir*nvir);
 
397
  fflush(outfile);
 
398
 
 
399
  local.domain = domain;
 
400
  local.pairdomain = pairdomain;
 
401
  local.pairdom_len = pairdom_len;
 
402
  local.weak_pairs = weak_pairs;
 
403
  local.aostart = aostart;
 
404
  local.aostop = aostop;
 
405
 
 
406
  free(ao2atom);
 
407
  free(l_length);
 
408
  free(charge);
 
409
  free(rank);
 
410
  free(boolean);
 
411
  free(SR);
 
412
  free(Z);
 
413
  free(ipiv);
 
414
  free(fR);
 
415
 
 
416
  print_test = 0;
 
417
  ip_boolean("DOMAIN_PRINT",&(print_test),0);
 
418
  if(print_test) {
 
419
    fprintf(outfile, "Printing of orbital domains requested...exiting.\n\n");
 
420
    exit(PSI_RETURN_FAILURE);
 
421
  }
 
422
 
 
423
  /************* Orbital Domains Complete ***************/
 
424
 
 
425
  /* Compute the complete virtual space projector */
 
426
  Rt_full = block_matrix(nso,nso);
 
427
  for(i=0; i < nso; i++) Rt_full[i][i] = 1.0;
 
428
 
 
429
  C_DGEMM('n','n',nso,nso,nso,-1.0,&(D[0][0]),nso,&(S[0][0]),nso,
 
430
          1.0,&(Rt_full[0][0]),nso);
 
431
 
 
432
  /*
 
433
    fprintf(outfile, "\n\tVirtual-Space Projector (R-tilde):\n");
 
434
    print_mat(Rt_full, nso, nso, outfile);
 
435
  */
 
436
 
 
437
  /* Compute the norm of each PAO */
 
438
  for(i=0; i < nso; i++) {
 
439
    norm = 0.0;
 
440
    for(j=0; j < nso; j++) {
 
441
      norm += Rt_full[j][i] * Rt_full[j][i];
 
442
    }
 
443
    norm = sqrt(norm);
 
444
    if(norm < 0.1) {
 
445
      fprintf(outfile, "\tNorm of orbital %4d = %20.12f...deleteing\n", i, norm);
 
446
      for(j=0; j < nso; j++) Rt_full[j][i] = 0.0;
 
447
    }
 
448
  }
 
449
  fprintf(outfile, "\n");
 
450
  fflush(outfile);
 
451
 
 
452
  /* Grab the MO-basis Fock matrix */
 
453
  Fmo = block_matrix(nso, nso);
 
454
  for(i=0; i < nfzc; i++) Fmo[i][i] = eps_all[i];
 
455
  dpd_file2_init(&fock, CC_OEI, 0, 0, 0, "fIJ");
 
456
  dpd_file2_mat_init(&fock);
 
457
  dpd_file2_mat_rd(&fock);
 
458
  for(i=0; i < nocc; i++) 
 
459
    for(j=0; j < nocc; j++)
 
460
      Fmo[i+nfzc][j+nfzc] = fock.matrix[0][i][j];
 
461
  dpd_file2_mat_close(&fock);
 
462
  dpd_file2_close(&fock);
 
463
 
 
464
  dpd_file2_init(&fock, CC_OEI, 0, 1, 1, "fAB");
 
465
  dpd_file2_mat_init(&fock);
 
466
  dpd_file2_mat_rd(&fock);
 
467
  for(i=0; i < nvir; i++) 
 
468
    for(j=0; j < nvir; j++)
 
469
      Fmo[i+nfzc+nocc][j+nfzc+nocc] = fock.matrix[0][i][j];
 
470
  dpd_file2_mat_close(&fock);
 
471
  dpd_file2_close(&fock);
 
472
 
 
473
  /*
 
474
    fprintf(outfile, "\n\tMO Basis Fock matrix:\n");
 
475
    print_mat(Fmo, nso, nso, outfile);
 
476
  */
 
477
 
 
478
  /* Build the AO-basis Fock matrix */
 
479
  F = block_matrix(nso,nso);
 
480
  C_DGEMM('t','n',nso,nso,nso,1.0,&(Ci[0][0]),nso,&(Fmo[0][0]),nso,
 
481
          0.0,&(X[0][0]),nso);
 
482
  C_DGEMM('n','n',nso,nso,nso,1.0,&(X[0][0]),nso,&(Ci[0][0]),nso,
 
483
          0.0,&(F[0][0]),nso);
 
484
 
 
485
  /* Build the occupied orbital energy list */
 
486
  eps_occ = init_array(nocc);
 
487
  for(i=0;i < nocc; i++) eps_occ[i] = Fmo[i+nfzc][i+nfzc];
 
488
 
 
489
  /*
 
490
    fprintf(outfile, "\n\tAO-Basis Fock Matrix:\n");
 
491
    print_mat(F, nso, nso, outfile);
 
492
  */
 
493
 
 
494
  /* Compute R^+ S for virtual orbitals */
 
495
  RS = block_matrix(nvir,nso);
 
496
  for(a=0; a < nvir; a++)
 
497
    for(i=0; i < nso; i++)
 
498
      X[i][a] = C[i][a+nocc_all];
 
499
  C_DGEMM('t','n',nvir,nso,nso,1.0,&(X[0][0]),nso,&(S[0][0]),nso,0.0,&(RS[0][0]),nso);
 
500
 
 
501
  /* Build the virtual metric and W transforms for each pair domain */
 
502
  Rt = block_matrix(nso, nso);
 
503
  W = (double ***) malloc(nocc * nocc * sizeof(double **));
 
504
  V = (double ***) malloc(nocc * nocc * sizeof(double **));
 
505
  eps_vir = (double **) malloc(nocc * nocc * sizeof(double *));
 
506
  pairdom_nrlen = init_int_array(nocc * nocc); /* dimension of non-redundant basis */
 
507
  num_zero = 0;
 
508
 
 
509
  for(ij=0; ij < nocc * nocc; ij++) {
 
510
 
 
511
    if(pairdom_len[ij]) {
 
512
 
 
513
      zero_mat(Rt, nso, nso);
 
514
 
 
515
      /* Build the virtual space projector for this pair */
 
516
      for(k=0,L=0; k < natom; k++) {
 
517
        if(pairdomain[ij][k]) {
 
518
          for(l=aostart[k]; l <= aostop[k]; l++,L++) {
 
519
            for(m=0; m < nso; m++) {
 
520
              Rt[m][L] = Rt_full[m][l];
 
521
            }
 
522
          }
 
523
        }
 
524
      }
 
525
 
 
526
      /* Compute the MO -> projected virtual transformation matrix */
 
527
      V[ij] = block_matrix(nvir,pairdom_len[ij]);
 
528
      C_DGEMM('n','n',nvir,pairdom_len[ij],nso,1.0,&(RS[0][0]),nso,&(Rt[0][0]),nso,0.0,
 
529
              &(V[ij][0][0]),pairdom_len[ij]);
 
530
 
 
531
      /* Virtual space metric */
 
532
      St = block_matrix(pairdom_len[ij],pairdom_len[ij]);
 
533
      C_DGEMM('n','n',nso,pairdom_len[ij],nso,1.0,&(S[0][0]),nso,&(Rt[0][0]),nso,
 
534
              0.0,&(X[0][0]),nso);
 
535
      C_DGEMM('t','n',pairdom_len[ij],pairdom_len[ij],nso,1.0,&(Rt[0][0]),nso,&(X[0][0]),nso,
 
536
              0.0,&(St[0][0]),pairdom_len[ij]);
 
537
 
 
538
      /*
 
539
        fprintf(outfile, "\n\tVirtual-Space Metric (S-tilde) for ij = %d:\n", ij);
 
540
        print_mat(St, pairdom_len[ij], pairdom_len[ij], outfile);
 
541
      */
 
542
 
 
543
      /* Diagonalize metric */
 
544
      evals = init_array(pairdom_len[ij]);
 
545
      evecs = block_matrix(pairdom_len[ij],pairdom_len[ij]);
 
546
      sq_rsp(pairdom_len[ij],pairdom_len[ij],St,evals,1,evecs,1e-12);
 
547
 
 
548
      /* Count the number of zero eigenvalues */
 
549
      for(i=0,cnt=0; i < pairdom_len[ij]; i++) if(evals[i] <= 1e-6) cnt++;
 
550
 
 
551
      pairdom_nrlen[ij] = pairdom_len[ij]-cnt;
 
552
 
 
553
      /*
 
554
        fprintf(outfile, "\n\tS-tilde eigenvalues for ij = %d:\n", ij);
 
555
        for(i=0; i < pairdom_len[ij]; i++) fprintf(outfile, "\t%d %20.12f\n", i, evals[i]);
 
556
 
 
557
        fprintf(outfile, "\n\tS-tilde eigenvectors for ij = %d:\n", ij);
 
558
        print_mat(evecs,pairdom_len[ij],pairdom_len[ij],outfile);
 
559
      */
 
560
 
 
561
      /* Build the projected, non-redundant transform (X-tilde) */
 
562
      Xt = block_matrix(pairdom_len[ij],pairdom_nrlen[ij]);
 
563
      for(i=0,I=0; i < pairdom_len[ij]; i++) {
 
564
        if(evals[i] > 1e-6) {
 
565
          for(j=0; j < pairdom_len[ij]; j++)
 
566
            Xt[j][I] = evecs[j][i]/sqrt(evals[i]);
 
567
          I++;
 
568
        }
 
569
        else num_zero++;
 
570
      }
 
571
 
 
572
 
 
573
      /*
 
574
        fprintf(outfile, "\n\tTransform to non-redundant, projected virtuals (X-tilde) for ij = %d:\n", ij);
 
575
        print_mat(Xt, pairdom_len[ij], pairdom_nrlen[ij], outfile);
 
576
      */
 
577
 
 
578
      free_block(evecs);
 
579
      free(evals);
 
580
 
 
581
      /* Build the projected (redundant) virtual Fock matrix */
 
582
      Ft = block_matrix(pairdom_len[ij], pairdom_len[ij]);
 
583
      C_DGEMM('t','n',pairdom_len[ij],nso,nso,1.0,&(Rt[0][0]),nso,&(F[0][0]),nso,
 
584
              0.0,&(X[0][0]),nso);
 
585
      C_DGEMM('n','n',pairdom_len[ij],pairdom_len[ij],nso,1.0,&(X[0][0]),nso,&(Rt[0][0]),nso,
 
586
              0.0,&(Ft[0][0]),pairdom_len[ij]);
 
587
 
 
588
      /* Project the Fock matrix into the non-redundant virtual space */
 
589
      Fbar = block_matrix(pairdom_nrlen[ij],pairdom_nrlen[ij]);
 
590
      C_DGEMM('t','n',pairdom_nrlen[ij],pairdom_len[ij],pairdom_len[ij],1.0,
 
591
              &(Xt[0][0]),pairdom_nrlen[ij],&(Ft[0][0]),pairdom_len[ij],0.0,&(X[0][0]),nso);
 
592
      C_DGEMM('n','n',pairdom_nrlen[ij],pairdom_nrlen[ij],pairdom_len[ij],1.0,
 
593
              &(X[0][0]),nso,&(Xt[0][0]),pairdom_nrlen[ij],0.0,&(Fbar[0][0]),pairdom_nrlen[ij]);
 
594
 
 
595
      /*
 
596
        fprintf(outfile, "\n\tFbar matrix for ij = %d:\n", ij);
 
597
        print_mat(Fbar,pairdom_nrlen[ij],pairdom_nrlen[ij],outfile);
 
598
      */
 
599
 
 
600
      /* Diagonalize Fbar */
 
601
      evals = init_array(pairdom_nrlen[ij]);
 
602
      evecs = block_matrix(pairdom_nrlen[ij],pairdom_nrlen[ij]);
 
603
      sq_rsp(pairdom_nrlen[ij],pairdom_nrlen[ij],Fbar,evals,1,evecs,1e-12);
 
604
 
 
605
      /*
 
606
        fprintf(outfile, "\n\tFbar eigenvectors for ij = %d:\n", ij);
 
607
        print_mat(evecs,pairdom_nrlen[ij],pairdom_nrlen[ij],outfile);
 
608
      */
 
609
 
 
610
      /* Finally, build the W matrix */
 
611
      W[ij] = block_matrix(pairdom_len[ij],pairdom_nrlen[ij]);
 
612
      C_DGEMM('n','n',pairdom_len[ij],pairdom_nrlen[ij],pairdom_nrlen[ij],1.0,
 
613
              &(Xt[0][0]),pairdom_nrlen[ij],&(evecs[0][0]),pairdom_nrlen[ij],
 
614
              0.0,&(W[ij][0][0]),pairdom_nrlen[ij]);
 
615
 
 
616
 
 
617
      /*
 
618
        fprintf(outfile, "\n\tW Transformation Matrix for ij = %d:\n", ij);
 
619
        print_mat(W,pairdom_len[ij],pairdom_nrlen[ij],outfile);
 
620
      */
 
621
 
 
622
      /* build the orbital energy list */
 
623
      eps_vir[ij] = init_array(pairdom_nrlen[ij]);
 
624
      for(i=0; i < pairdom_nrlen[ij]; i++)
 
625
        eps_vir[ij][i] = evals[i]; /* virtual orbital energies */
 
626
 
 
627
      /*
 
628
        fprintf(outfile, "\n\tVirtual orbital Energies for ij = %d:\n", ij);
 
629
        for(i=0; i < pairdom_nrlen[ij]; i++)
 
630
        fprintf(outfile, "%d %20.12f\n", i, eps_vir[ij][i]);
 
631
      */
 
632
 
 
633
      free(evals);
 
634
      free_block(evecs);
 
635
 
 
636
      free_block(St);
 
637
      free_block(Xt);
 
638
      free_block(Fbar);
 
639
      free(Ft);
 
640
 
 
641
    } /* if(pairdom_len[ij]) */
 
642
 
 
643
  } /* ij loop */
 
644
 
 
645
  free_block(RS);
 
646
  free_block(F);
 
647
  free_block(Fmo);
 
648
  free_block(S);
 
649
  free_block(Rt_full);
 
650
  free_block(D);
 
651
  free_block(Ci);
 
652
  free_block(C);
 
653
 
 
654
  free_block(X);
 
655
  free_block(Y);
 
656
 
 
657
  local.W = W;
 
658
  local.V = V;
 
659
  local.eps_occ = eps_occ;
 
660
  local.eps_vir = eps_vir;
 
661
  local.pairdom_nrlen = pairdom_nrlen;
 
662
 
 
663
  local.weak_pair_energy = 0.0;
 
664
 
 
665
  fprintf(outfile, "\tLocalization parameters ready.\n\n");
 
666
  fflush(outfile);
 
667
 
 
668
  timer_off("Local");
 
669
}
 
670
 
 
671
/*
 
672
** local_done(): 
 
673
*/
 
674
 
 
675
void local_done(void)
 
676
{
 
677
  int i;
 
678
 
 
679
  free(local.eps_occ);
 
680
  for(i=0; i < local.nocc*local.nocc; i++) {
 
681
    if(local.pairdom_len[i]) {
 
682
      free_block(local.W[i]);
 
683
      free_block(local.V[i]);
 
684
      free(local.eps_vir[i]);
 
685
    }
 
686
  }
 
687
  free(local.W);
 
688
  free(local.V);
 
689
  free(local.eps_vir);
 
690
 
 
691
  free(local.aostart);
 
692
  free(local.aostop);
 
693
 
 
694
  free_int_matrix(local.pairdomain);
 
695
  free_int_matrix(local.domain);
 
696
  free(local.pairdom_len);
 
697
  free(local.pairdom_nrlen);
 
698
  free(local.weak_pairs);
 
699
 
 
700
  fprintf(outfile, "\tLocal parameters free.\n");
 
701
}
 
702
 
 
703
void local_filter_T2(dpdbuf4 *T2)
 
704
{
 
705
  int ij, i, j, a, b, ab;
 
706
  int nso, nocc, nvir;
 
707
  int *pairdom_len, *pairdom_nrlen, *weak_pairs;
 
708
  double ***V, ***W, *eps_occ, **eps_vir;
 
709
  double **X1, **X2, **T2tilde, **T2bar;
 
710
 
 
711
  nso = local.nso;
 
712
  nocc = local.nocc;
 
713
  nvir = local.nvir;
 
714
  V = local.V;
 
715
  W = local.W;
 
716
  eps_occ = local.eps_occ;
 
717
  eps_vir = local.eps_vir;
 
718
  pairdom_len = local.pairdom_len;
 
719
  pairdom_nrlen = local.pairdom_nrlen;
 
720
  weak_pairs = local.weak_pairs;
 
721
 
 
722
  /* Grab the MO-basis T2's */
 
723
  dpd_buf4_mat_irrep_init(T2, 0);
 
724
  dpd_buf4_mat_irrep_rd(T2, 0);
 
725
 
 
726
  X1 = block_matrix(nso,nvir);
 
727
  X2 = block_matrix(nvir,nso);
 
728
  T2tilde = block_matrix(nso,nso);
 
729
  T2bar = block_matrix(nvir, nvir);
 
730
  for(i=0,ij=0; i < nocc; i++) {
 
731
    for(j=0; j < nocc; j++,ij++) {
 
732
 
 
733
      /* Transform the virtuals to the redundant projected virtual basis */
 
734
      C_DGEMM('t', 'n', pairdom_len[ij], nvir, nvir, 1.0, &(V[ij][0][0]), pairdom_len[ij],
 
735
              &(T2->matrix[0][ij][0]), nvir, 0.0, &(X1[0][0]), nvir);
 
736
      C_DGEMM('n', 'n', pairdom_len[ij], pairdom_len[ij], nvir, 1.0, &(X1[0][0]), nvir,
 
737
              &(V[ij][0][0]), pairdom_len[ij], 0.0, &(T2tilde[0][0]), nso);
 
738
 
 
739
      /* Transform the virtuals to the non-redundant virtual basis */
 
740
      C_DGEMM('t', 'n', pairdom_nrlen[ij], pairdom_len[ij], pairdom_len[ij], 1.0, 
 
741
              &(W[ij][0][0]), pairdom_nrlen[ij], &(T2tilde[0][0]), nso, 0.0, &(X2[0][0]), nso);
 
742
      C_DGEMM('n', 'n', pairdom_nrlen[ij], pairdom_nrlen[ij], pairdom_len[ij], 1.0, 
 
743
              &(X2[0][0]), nso, &(W[ij][0][0]), pairdom_nrlen[ij], 0.0, &(T2bar[0][0]), nvir);
 
744
 
 
745
      /* Divide the new amplitudes by the denominators */
 
746
      for(a=0; a < pairdom_nrlen[ij]; a++) {
 
747
        for(b=0; b < pairdom_nrlen[ij]; b++) {
 
748
          T2bar[a][b] /= (eps_occ[i] + eps_occ[j] - eps_vir[ij][a] - eps_vir[ij][b]);
 
749
        }
 
750
      }
 
751
 
 
752
      /* Transform the new T2's to the redundant virtual basis */
 
753
      C_DGEMM('n', 'n', pairdom_len[ij], pairdom_nrlen[ij], pairdom_nrlen[ij], 1.0, 
 
754
              &(W[ij][0][0]), pairdom_nrlen[ij], &(T2bar[0][0]), nvir, 0.0, &(X1[0][0]), nvir);
 
755
      C_DGEMM('n','t', pairdom_len[ij], pairdom_len[ij], pairdom_nrlen[ij], 1.0, 
 
756
              &(X1[0][0]), nvir, &(W[ij][0][0]), pairdom_nrlen[ij], 0.0, &(T2tilde[0][0]), nso);
 
757
 
 
758
      /* Transform the new T2's to the MO basis */
 
759
      C_DGEMM('n', 'n', nvir, pairdom_len[ij], pairdom_len[ij], 1.0, 
 
760
              &(V[ij][0][0]), pairdom_len[ij], &(T2tilde[0][0]), nso, 0.0, &(X2[0][0]), nso);
 
761
      C_DGEMM('n', 't', nvir, nvir, pairdom_len[ij], 1.0, &(X2[0][0]), nso,
 
762
              &(V[ij][0][0]), pairdom_len[ij], 0.0, &(T2->matrix[0][ij][0]), nvir);
 
763
    }
 
764
 
 
765
  }
 
766
 
 
767
  free_block(X1);
 
768
  free_block(X2);
 
769
  free_block(T2tilde);
 
770
  free_block(T2bar);
 
771
 
 
772
  /* Write the updated MO-basis T2's to disk */
 
773
  dpd_buf4_mat_irrep_wrt(T2, 0);
 
774
  dpd_buf4_mat_irrep_close(T2, 0);
 
775
}
 
776
 
 
777
void local_filter_U2(dpdbuf4 *T2, double lambda)
 
778
{
 
779
  int ij, i, j, a, b, ab;
 
780
  int nso, nocc, nvir;
 
781
  int *pairdom_len, *pairdom_nrlen, *weak_pairs;
 
782
  double ***V, ***W, *eps_occ, **eps_vir;
 
783
  double **X1, **X2, **T2tilde, **T2bar;
 
784
 
 
785
  nso = local.nso;
 
786
  nocc = local.nocc;
 
787
  nvir = local.nvir;
 
788
  V = local.V;
 
789
  W = local.W;
 
790
  eps_occ = local.eps_occ;
 
791
  eps_vir = local.eps_vir;
 
792
  pairdom_len = local.pairdom_len;
 
793
  pairdom_nrlen = local.pairdom_nrlen;
 
794
  weak_pairs = local.weak_pairs;
 
795
 
 
796
  /* Grab the MO-basis T2's */
 
797
  dpd_buf4_mat_irrep_init(T2, 0);
 
798
  dpd_buf4_mat_irrep_rd(T2, 0);
 
799
 
 
800
  X1 = block_matrix(nso,nvir);
 
801
  X2 = block_matrix(nvir,nso);
 
802
  T2tilde = block_matrix(nso,nso);
 
803
  T2bar = block_matrix(nvir, nvir);
 
804
  for(i=0,ij=0; i < nocc; i++) {
 
805
    for(j=0; j < nocc; j++,ij++) {
 
806
 
 
807
      /* Transform the virtuals to the redundant projected virtual basis */
 
808
      C_DGEMM('t', 'n', pairdom_len[ij], nvir, nvir, 1.0, &(V[ij][0][0]), pairdom_len[ij],
 
809
              &(T2->matrix[0][ij][0]), nvir, 0.0, &(X1[0][0]), nvir);
 
810
      C_DGEMM('n', 'n', pairdom_len[ij], pairdom_len[ij], nvir, 1.0, &(X1[0][0]), nvir,
 
811
              &(V[ij][0][0]), pairdom_len[ij], 0.0, &(T2tilde[0][0]), nso);
 
812
 
 
813
      /* Transform the virtuals to the non-redundant virtual basis */
 
814
      C_DGEMM('t', 'n', pairdom_nrlen[ij], pairdom_len[ij], pairdom_len[ij], 1.0, 
 
815
              &(W[ij][0][0]), pairdom_nrlen[ij], &(T2tilde[0][0]), nso, 0.0, &(X2[0][0]), nso);
 
816
      C_DGEMM('n', 'n', pairdom_nrlen[ij], pairdom_nrlen[ij], pairdom_len[ij], 1.0, 
 
817
              &(X2[0][0]), nso, &(W[ij][0][0]), pairdom_nrlen[ij], 0.0, &(T2bar[0][0]), nvir);
 
818
 
 
819
      /* Divide the new amplitudes by the denominators */
 
820
      for(a=0; a < pairdom_nrlen[ij]; a++) {
 
821
        for(b=0; b < pairdom_nrlen[ij]; b++) {
 
822
          T2bar[a][b] /= (eps_occ[i] + eps_occ[j] - eps_vir[ij][a] - eps_vir[ij][b] + lambda);
 
823
        }
 
824
      }
 
825
 
 
826
      /* Transform the new T2's to the redundant virtual basis */
 
827
      C_DGEMM('n', 'n', pairdom_len[ij], pairdom_nrlen[ij], pairdom_nrlen[ij], 1.0, 
 
828
              &(W[ij][0][0]), pairdom_nrlen[ij], &(T2bar[0][0]), nvir, 0.0, &(X1[0][0]), nvir);
 
829
      C_DGEMM('n','t', pairdom_len[ij], pairdom_len[ij], pairdom_nrlen[ij], 1.0, 
 
830
              &(X1[0][0]), nvir, &(W[ij][0][0]), pairdom_nrlen[ij], 0.0, &(T2tilde[0][0]), nso);
 
831
 
 
832
      /* Transform the new T2's to the MO basis */
 
833
      C_DGEMM('n', 'n', nvir, pairdom_len[ij], pairdom_len[ij], 1.0, 
 
834
              &(V[ij][0][0]), pairdom_len[ij], &(T2tilde[0][0]), nso, 0.0, &(X2[0][0]), nso);
 
835
      C_DGEMM('n', 't', nvir, nvir, pairdom_len[ij], 1.0, &(X2[0][0]), nso,
 
836
              &(V[ij][0][0]), pairdom_len[ij], 0.0, &(T2->matrix[0][ij][0]), nvir);
 
837
    }
 
838
 
 
839
  }
 
840
 
 
841
  free_block(X1);
 
842
  free_block(X2);
 
843
  free_block(T2tilde);
 
844
  free_block(T2bar);
 
845
 
 
846
  /* Write the updated MO-basis T2's to disk */
 
847
  dpd_buf4_mat_irrep_wrt(T2, 0);
 
848
  dpd_buf4_mat_irrep_close(T2, 0);
 
849
}
 
850
 
 
851
 
 
852
}} // namespace psi::cis