1
/*! \defgroup MVO mvo: Compute modified virtual orbitals, etc */
6
** \brief Compute modified virtual orbitals, etc.
8
** This program reads the frozen core operator from TRANSQT
9
** output ** and diagonalizes the virtual-virtual block to make
10
** Modified Virtual Orbitals (MVO's) as described in
11
** C. W. Bauschlicher, J. Chem. Phys. 72, 880 (1980)
14
** Georgia Institute of Technology
22
#include <libipv1/ip_lib.h>
23
#include <libpsio/psio.h>
24
#include <libciomr/libciomr.h>
25
#include <libchkpt/chkpt.h>
28
#include <libiwl/iwl.h>
34
/* First definitions of globals */
36
FILE *infile, *outfile;
37
char *psi_file_prefix;
40
namespace psi { namespace mvo {
46
/* Max length of ioff array */
47
#define IOFF_MAX 32641
50
#define MIN0(a,b) (((a)<(b)) ? (a) : (b))
51
#define MAX0(a,b) (((a)>(b)) ? (a) : (b))
52
#define INDEX(i,j) ((i>j) ? (ioff[(i)]+(j)) : (ioff[(j)]+(i)))
55
/* Function prototypes */
56
void init_io(int argc, char *argv[]);
59
void get_parameters();
60
void print_parameters();
64
void get_reorder_array(void);
65
void get_fzc_operator(void);
67
void get_canonical(void);
68
void get_mp2nos(void);
69
/* void get_unos(void); */
70
}} // end namespace psi::mvo
72
using namespace psi::mvo;
74
int main(int argc, char *argv[])
87
else if (params.unos) {
90
else if (params.canonical) {
102
namespace psi { namespace mvo {
104
void init_io(int argc, char *argv[])
107
int num_extra_args = 0;
110
extra_args = (char **) malloc(argc*sizeof(char *));
112
for (i=1; i<argc; i++) {
113
if (strcmp(argv[i], "--quiet") == 0) {
114
params.print_lvl = 0;
117
extra_args[num_extra_args++] = argv[i];
121
psi_start(&infile,&outfile,&psi_file_prefix,num_extra_args,extra_args,0);
122
if (params.print_lvl) tstart(outfile);
125
psio_init(); psio_ipv1_config();
132
if (params.print_lvl) {
133
fprintf(outfile, "\n");
134
fprintf(outfile,"\t**************************************************\n");
135
fprintf(outfile,"\t* MVO: Obtain Modified Virtual Orbitals *\n");
136
fprintf(outfile,"\t* *\n");
137
fprintf(outfile,"\t* C. David Sherrill *\n");
138
fprintf(outfile,"\t* March 2001 *\n");
139
fprintf(outfile,"\t**************************************************\n");
140
fprintf(outfile, "\n");
147
ioff = (int *) malloc(IOFF_MAX * sizeof(int));
149
fprintf(stderr, "(transqt): error malloc'ing ioff array\n");
153
for(i=1; i < IOFF_MAX; i++) {
154
ioff[i] = ioff[i-1] + i;
161
if (params.print_lvl) tstop(outfile);
162
psi_stop(infile,outfile,psi_file_prefix);
166
void get_parameters(void)
170
errcod = ip_string("WFN", &(params.wfn),0);
171
if(errcod == IPE_KEY_NOT_FOUND) {
172
params.wfn = (char *) malloc(sizeof(char)*5);
173
strcpy(params.wfn, "CCSD");
176
params.h_fzc_file = PSIF_OEI;
177
errcod = ip_data("FZC_FILE","%d",&(params.h_fzc_file),0);
179
params.print_mos = 0;
180
errcod = ip_boolean("PRINT_MOS", &(params.print_mos),0);
182
params.print_lvl = 1;
183
errcod = ip_data("PRINT", "%d", &(params.print_lvl),0);
185
params.oei_erase = 0;
186
errcod = ip_boolean("OEI_ERASE",&(params.oei_erase),0);
189
errcod = ip_boolean("FZC",&(params.fzc),0);
191
/* remove restricted docc from RAS 1 ? */
192
params.del_restr_docc = 1;
193
errcod = ip_boolean("DELETE_RESTR_DOCC",&(params.del_restr_docc),0);
196
errcod = ip_boolean("MP2NOS",&(params.mp2nos),0);
199
errcod = ip_boolean("UNOS",&(params.unos),0);
201
if (strcmp(params.wfn, "CI")==0 || strcmp(params.wfn, "DETCAS")==0 ||
202
strcmp(params.wfn, "DETCI")==0) {
209
params.fzc_fock_coeff = 1.0;
210
errcod = ip_data("FZC_FOCK_COEFF", "%lf", &(params.fzc_fock_coeff),0);
212
params.fock_coeff = 0.0;
213
errcod = ip_data("FOCK_COEFF", "%lf", &(params.fock_coeff),0);
216
errcod = ip_boolean("IVO", &(params.ivo), 0);
218
params.canonical = 0;
219
errcod = ip_boolean("CANONICAL", &(params.canonical), 0);
225
void print_parameters(void)
228
if (params.print_lvl) {
229
fprintf(outfile,"\n");
230
fprintf(outfile,"\tInput Parameters:\n");
231
fprintf(outfile,"\t-----------------\n");
232
fprintf(outfile,"\tWavefunction = %s\n", params.wfn);
233
fprintf(outfile,"\tPrint MOs = %s\n",
234
(params.print_mos ? "Yes": "No"));
235
fprintf(outfile,"\tErase OEI file = %s\n",
236
(params.oei_erase ? "Yes": "No"));
237
fprintf(outfile,"\tFrozen core = %s\n",
238
(params.fzc ? "Yes": "No"));
239
fprintf(outfile,"\tDelete Restricted Docc = %s\n",
240
(params.del_restr_docc ? "Yes" : "No"));
241
fprintf(outfile,"\tIVO = %s\n",
242
(params.ivo ? "Yes": "No"));
243
fprintf(outfile,"\tCanonical = %s\n",
244
(params.canonical ? "Yes": "No"));
245
fprintf(outfile,"\tFrozen Core OEI file = %d\n",
247
fprintf(outfile,"\tfzc_fock_coeff = %lf\n",
248
params.fzc_fock_coeff);
249
fprintf(outfile,"\tfock_coeff = %lf\n",
251
fprintf(outfile,"\tPrint Level = %d\n", params.print_lvl);
258
void get_fzc_operator(void)
261
moinfo.fzc_operator = (double *) init_array(moinfo.fzc_op_size);
263
iwl_rdone(params.h_fzc_file, moinfo.fzc_operator, &(moinfo.efzc),
264
ioff, moinfo.nmo, 0, 0, params.oei_erase,
265
(params.print_lvl>4), outfile);
267
iwl_rdone(params.h_fzc_file, PSIF_MO_FZC, moinfo.fzc_operator,
268
moinfo.fzc_op_size, params.oei_erase,
269
(params.print_lvl>4), outfile);
275
void get_moinfo(void)
277
int i,j,k,h,errcod,size,row,col,p,q,offset,first_offset,last_offset,warned;
279
double **tmpmat, **so2ao;
280
double N; /* number of valence electrons */
282
chkpt_init(PSIO_OPEN_OLD);
283
moinfo.nmo = chkpt_rd_nmo();
284
moinfo.nso = chkpt_rd_nso();
285
moinfo.nao = chkpt_rd_nao();
286
moinfo.nirreps = chkpt_rd_nirreps();
287
moinfo.iopen = chkpt_rd_iopen();
288
moinfo.labels = chkpt_rd_irr_labs();
289
moinfo.sopi = chkpt_rd_sopi();
290
moinfo.orbspi = chkpt_rd_orbspi();
291
moinfo.clsdpi = chkpt_rd_clsdpi();
292
moinfo.openpi = chkpt_rd_openpi();
294
moinfo.fzc_op_size = (moinfo.nmo * (moinfo.nmo + 1)) / 2;
296
moinfo.sosym = init_int_array(moinfo.nso);
297
for (i=0,k=0; i<moinfo.nirreps; i++) {
298
for (j=0; j<moinfo.sopi[i]; j++,k++) {
303
moinfo.orbsym = init_int_array(moinfo.nmo);
304
for (i=0,k=0; i<moinfo.nirreps; i++) {
305
for (j=0; j<moinfo.orbspi[i]; j++,k++) {
306
moinfo.orbsym[k] = i;
310
moinfo.frdocc = init_int_array(moinfo.nirreps);
311
moinfo.fruocc = init_int_array(moinfo.nirreps);
312
errcod = ip_int_array("FROZEN_DOCC", moinfo.frdocc, moinfo.nirreps);
313
errcod = ip_int_array("FROZEN_UOCC", moinfo.fruocc, moinfo.nirreps);
315
moinfo.rstrdocc = init_int_array(moinfo.nirreps);
316
moinfo.rstruocc = init_int_array(moinfo.nirreps);
317
errcod = ip_int_array("RESTRICTED_DOCC",moinfo.rstrdocc,moinfo.nirreps);
318
errcod = ip_int_array("RESTRICTED_UOCC",moinfo.rstruocc,moinfo.nirreps);
321
if (params.treat_cor_as_fzc) {
322
for (i=0; i<moinfo.nirreps; i++) {
323
moinfo.frdocc[i] += moinfo.rstrdocc[i];
324
moinfo.rstrdocc[i] = 0;
330
for (i=0; i<moinfo.nirreps; i++) {
331
moinfo.frdocc[i] = 0;
337
for (i=0; i<moinfo.nirreps; i++) {
338
moinfo.nfzc += moinfo.frdocc[i];
339
moinfo.nfzv += moinfo.fruocc[i];
343
tmpi = init_int_array(moinfo.nirreps);
344
errcod = ip_int_array("DOCC", tmpi, moinfo.nirreps);
345
if (errcod == IPE_OK) {
346
for (i=0,warned=0; i<moinfo.nirreps; i++) {
347
if (tmpi[i] != moinfo.clsdpi[i] && !warned) {
348
fprintf(outfile, "\tWarning: DOCC doesn't match PSIF_CHKPT\n");
351
moinfo.clsdpi[i] = tmpi[i];
352
moinfo.ndocc += tmpi[i];
356
for (i=0; i<moinfo.nirreps; i++) {
357
moinfo.ndocc += moinfo.clsdpi[i];
362
errcod = ip_int_array("SOCC", tmpi, moinfo.nirreps);
363
if (errcod == IPE_OK) {
364
for (i=0,warned=0; i<moinfo.nirreps; i++) {
365
if (tmpi[i] != moinfo.openpi[i] && !warned) {
366
fprintf(outfile, "\tWarning: SOCC doesn't match PSIF_CHKPT\n");
369
moinfo.openpi[i] = tmpi[i];
370
moinfo.nsocc += tmpi[i];
374
moinfo.virtpi = init_int_array(moinfo.nirreps);
375
for(i=0; i < moinfo.nirreps; i++) {
376
moinfo.virtpi[i] = moinfo.orbspi[i]-moinfo.clsdpi[i]-moinfo.openpi[i];
379
if (params.print_lvl) {
380
fprintf(outfile,"\n\tCheckpoint file parameters:\n");
381
fprintf(outfile,"\t------------------\n");
382
fprintf(outfile,"\tNumber of irreps = %d\n",moinfo.nirreps);
383
fprintf(outfile,"\tNumber of SOs = %d\n",moinfo.nso);
384
fprintf(outfile,"\tNumber of MOs = %d\n\n",moinfo.nmo);
386
"\tLabel\t# SOs\t# MOs\t# FZDC\t# DOCC\t# SOCC\t# VIRT\t# FZVR\n");
388
"\t-----\t-----\t-----\t------\t------\t------\t------\t------\n");
389
for(i=0; i < moinfo.nirreps; i++) {
391
"\t %s\t %d\t %d\t %d\t %d\t %d\t %d\t %d\n",
392
moinfo.labels[i],moinfo.sopi[i],moinfo.orbspi[i],moinfo.frdocc[i],
393
moinfo.clsdpi[i],moinfo.openpi[i],moinfo.virtpi[i],
401
Construct first and last index arrays for SOs: this defines the first
402
absolute orbital index and last absolute orbital
403
index for each irrep. When there are no orbitals for an irrep, the
404
value is -1 for first[] and -2 for last[]. Note that there must be
405
basis functions in the first irrep (i.e. totally symmetric) for this to
408
moinfo.first_so = init_int_array(moinfo.nirreps);
409
moinfo.last_so = init_int_array(moinfo.nirreps);
410
for(h=0; h < moinfo.nirreps; h++) {
411
moinfo.first_so[h] = -1;
412
moinfo.last_so[h] = -2;
415
last_offset = moinfo.sopi[0] - 1;
416
moinfo.first_so[0] = first_offset;
417
moinfo.last_so[0] = last_offset;
418
for(h=1; h < moinfo.nirreps; h++) {
419
first_offset += moinfo.sopi[h-1];
420
last_offset += moinfo.sopi[h];
422
moinfo.first_so[h] = first_offset;
423
moinfo.last_so[h] = last_offset;
428
Construct first and last index arrays: this defines the first
429
absolute orbital index (Pitzer ordering) and last absolute orbital
430
index for each irrep. When there are no orbitals for an irrep, the
431
value is -1 for first[] and -2 for last[]. Note that there must be
432
orbitals in the first irrep (i.e. totally symmetric) for this to work.
434
moinfo.first = init_int_array(moinfo.nirreps);
435
moinfo.last = init_int_array(moinfo.nirreps);
436
for(h=0; h < moinfo.nirreps; h++) {
437
moinfo.first[h] = -1;
441
last_offset = moinfo.orbspi[0] - 1;
442
moinfo.first[0] = first_offset;
443
moinfo.last[0] = last_offset;
444
for(h=1; h < moinfo.nirreps; h++) {
445
first_offset += moinfo.orbspi[h-1];
446
last_offset += moinfo.orbspi[h];
447
if(moinfo.orbspi[h]) {
448
moinfo.first[h] = first_offset;
449
moinfo.last[h] = last_offset;
453
Construct first and last active index arrays: this defines the first
454
absolute orbital index (Pitzer ordering) and last absolute orbital
455
index for each irrep, excluding frozen orbitals. When there are no
456
orbitals for an irrep, the value is -1 for first[] and -2 for last[].
457
Note that there must be orbitals in the first irrep (i.e. totally
458
symmetric) for this to work.
460
moinfo.fstact = init_int_array(moinfo.nirreps);
461
moinfo.lstact = init_int_array(moinfo.nirreps);
462
for(h=0; h < moinfo.nirreps; h++) {
463
moinfo.fstact[h] = -1;
464
moinfo.lstact[h] = -2;
466
first_offset = moinfo.frdocc[0];
467
last_offset = moinfo.orbspi[0] - moinfo.fruocc[0] - 1;
468
moinfo.fstact[0] = first_offset;
469
moinfo.lstact[0] = last_offset;
470
for(h=1; h < moinfo.nirreps; h++) {
471
first_offset += moinfo.orbspi[h-1]+moinfo.frdocc[h]-moinfo.frdocc[h-1];
472
last_offset += moinfo.orbspi[h] - moinfo.fruocc[h] + moinfo.fruocc[h-1];
473
if(moinfo.orbspi[h]) {
474
moinfo.fstact[h] = first_offset;
475
moinfo.lstact[h] = last_offset;
479
/* Now define active[] such that frozen orbitals are taken into account */
480
moinfo.active = init_int_array(moinfo.nirreps);
481
for(h=0; h < moinfo.nirreps; h++) {
482
moinfo.active[h] = moinfo.orbspi[h]-moinfo.frdocc[h]-moinfo.fruocc[h];
487
/* in case IVO's have been asked for */
490
/* count the number of valence electrons */
491
for (h=0; h < moinfo.nirreps; h++) {
492
N += 2.0 * (double) (moinfo.clsdpi[h] - moinfo.frdocc[h]);
493
N += (double) moinfo.openpi[h];
496
/* use the number of valence electrons to compute the mixing ratio */
497
params.fock_coeff = (N-1)/N;
500
fprintf(outfile, "inside IVO routine now, N=%f, fock=%f\n", N,
504
if (params.fock_coeff < 0.0) params.fock_coeff = 0.0;
505
params.fzc_fock_coeff = 1.0 - params.fock_coeff;
513
void get_reorder_array(void)
516
int j, k, l, fzv_offset;
518
/* the following will only be set nonzero if it is a CI related WFN */
519
moinfo.ras_opi = init_int_matrix(MAX_RAS_SPACES,moinfo.nirreps);
520
moinfo.order = init_int_array(moinfo.nmo);
522
if (strcmp(params.wfn, "CI") == 0 || strcmp(params.wfn, "DETCI") == 0
523
|| strcmp(params.wfn, "QDPT") == 0
524
|| strcmp(params.wfn, "OOCCD") == 0
525
|| strcmp(params.wfn, "DETCAS") == 0) {
527
moinfo.ras_opi = init_int_matrix(MAX_RAS_SPACES,moinfo.nirreps);
529
if (!ras_set2(moinfo.nirreps, moinfo.nmo, params.fzc,
530
params.del_restr_docc, moinfo.orbspi, moinfo.clsdpi, moinfo.openpi,
531
moinfo.frdocc, moinfo.fruocc, moinfo.rstrdocc, moinfo.rstruocc,
532
moinfo.ras_opi, moinfo.order, params.ras_type, 0)) {
533
fprintf(outfile, "Error in ras_set2(). Aborting.\n");
537
else { /* default (CC, MP2, other) */
538
reorder_qt(moinfo.clsdpi, moinfo.openpi, moinfo.frdocc, moinfo.fruocc,
539
moinfo.order, moinfo.orbspi, moinfo.nirreps);
542
/* construct an array to map the other direction, i.e., from correlated */
543
/* to Pitzer order */
544
moinfo.corr2pitz = init_int_array(moinfo.nmo);
545
for (i=0; i<moinfo.nmo; i++) {
547
moinfo.corr2pitz[j] = i;
555
free(moinfo.fzc_operator);
556
free_int_matrix(moinfo.ras_opi);
562
int h, nirreps, nvir, ntri, offset, row, col;
563
int i, j, ij, iabs, jabs, icorr, jcorr, ijcorr, nocc;
564
int ndv, ndoccv, *ndvph, k, colv;
566
double *FCvv, *FC, **evecs, *evals, **Cvv, **Cvvp, **Cnew;
567
double *eig_unsrt, **scf_vector;
569
FC = moinfo.fzc_operator;
570
nirreps = moinfo.nirreps;
572
chkpt_init(PSIO_OPEN_OLD);
573
scf_vector = chkpt_rd_scf();
574
eig_unsrt = chkpt_rd_evals();
577
/* read in which of the doccs are to be treated as virtuals */
580
if (ip_exist("DOCC_VIRT",0)) {
581
errcod = ip_count("DOCC_VIRT",&ndv,0);
582
params.docc_virt = init_int_array(ndv);
583
for(k=0; k < ndv; k++) {
584
params.docc_virt[k] = 0;
585
errcod = ip_data("DOCC_VIRT","%d",(&(params.docc_virt[k])),1,k);
589
/* finished reading in which doccs are to be treated as virtuals */
591
/* form the vv block of FC for each irrep h */
592
for (h=0,offset=0; h < nirreps; h++) {
594
/* find out which doccs are to be treated as virtuals */
596
ndvph = init_int_array(moinfo.clsdpi[h]);
597
for (k=0;k<moinfo.clsdpi[h];k++) {
600
if (ip_exist("DOCC_VIRT",0)) {
601
for (k=0;k<(ndv-1);k=(k+2)) {
602
if ( (params.docc_virt[k]) == (h+1)) {
604
ndvph[(params.docc_virt[k+1])-1] = ndoccv;
608
/* ndoccv is the number of doccs to be treated as virts for irrep h */
609
/* ndvph is a 1-d array of length "number of doccs for irrep h". */
610
/* it is a string of integers, 0 meaning "leave this docc alone", */
611
/* 1 at position j means that docc number j is the first docc-virt, */
612
/* 2 at position j means that docc number j is the second docc-virt */
615
nvir = moinfo.virtpi[h] + ndoccv;
616
nocc = moinfo.clsdpi[h] + moinfo.openpi[h] - ndoccv;
620
if (params.print_lvl) {
621
fprintf(outfile, "Working on irrep %d (%d vir, %d occ)\n",
625
ntri = (nvir * (nvir+1))/2;
626
FCvv = init_array(ntri);
627
evals = init_array(ntri);
628
evecs = block_matrix(nvir,nvir);
629
Cvv = block_matrix(moinfo.sopi[h],nvir);
630
Cvvp = block_matrix(moinfo.sopi[h],nvir);
631
Cnew = block_matrix(moinfo.sopi[h],moinfo.orbspi[h]);
633
for (i=0,ij=0; i<nvir; i++) {
634
/* convert this MO index into a Correlated MO index */
636
iabs = i + nocc + offset;
639
for (k=0; k<(nocc + ndoccv); k++) {
640
if ( (i+1) == ndvph[k] )
644
icorr = moinfo.order[iabs];
645
for (j=0; j<=i; j++,ij++) {
647
jabs = j + nocc + offset;
650
for (k=0; k<(nocc + ndoccv); k++) {
651
if ( (j+1) == ndvph[k] )
655
jcorr = moinfo.order[jabs];
656
ijcorr = INDEX(icorr,jcorr);
657
FCvv[ij] = params.fzc_fock_coeff * FC[ijcorr] ;
658
if (i==j) FCvv[ij] += params.fock_coeff * eig_unsrt[iabs];
662
if (params.print_lvl) {
663
fprintf(outfile, "Old FCvv matrix for irrep %d\n", h);
664
print_array(FCvv, nvir, outfile);
667
/* diagonalize the vv block of FC */
668
rsp(nvir, nvir, ntri, FCvv, evals, 1, evecs, 1E-12);
670
if (params.print_lvl) {
671
fprintf(outfile, "\nDiagonalization matrix for FCvv irrep %d\n", h);
672
print_mat(evecs, nvir, nvir, outfile);
674
fprintf(outfile, "\nEigenvalues of FCvv for irrep %d\n", h);
675
for (i=0; i<nvir; i++) {
676
fprintf(outfile, "%lf ", evals[i]);
678
fprintf(outfile, "\n");
681
/* load up the vv part of SCF matrix C */
682
for (i=moinfo.first_so[h],row=0; i<= moinfo.last_so[h]; i++,row++) {
684
for (j=moinfo.first_so[h],k=0; j < (moinfo.first_so[h]+nocc+ndoccv); j++,k++) {
686
Cvv[row][colv] = scf_vector[i][j];
690
for (j=moinfo.first_so[h]+nocc+ndoccv,col=ndoccv; j<=moinfo.last_so[h]; j++,col++) {
691
Cvv[row][col] = scf_vector[i][j];
695
if (params.print_lvl) {
696
fprintf(outfile, "Old Cvv matrix for irrep %d\n", h);
697
print_mat(Cvv, moinfo.sopi[h], nvir, outfile);
700
/* multiply the FCvv eigenvectors by Cvv to get new Cvv */
701
mmult(Cvv, 0, evecs, 0, Cvvp, 0, moinfo.sopi[h], nvir, nvir, 0);
703
if (params.print_lvl) {
704
fprintf(outfile, "New Cvv matrix for irrep %d\n", h);
705
print_mat(Cvvp, moinfo.sopi[h], nvir, outfile);
708
/* Load up the new C matrix and write it out */
710
/* load up the occupied orbitals */
711
for (i=moinfo.first_so[h],row=0; i<= moinfo.last_so[h]; i++,row++) {
712
for (j=moinfo.first_so[h],col=0; j< moinfo.first_so[h]+nocc+ndoccv; j++,col++) {
713
if (ndvph[col] != 0) {
714
Cnew[row][col] = Cvvp[row][(ndvph[col]-1)];
717
Cnew[row][col] = scf_vector[i][j];
722
/* load up the new virtuals */
723
for (i=0; i<moinfo.sopi[h]; i++) {
724
for (j=ndoccv; j<nvir; j++) {
725
Cnew[i][j+nocc] = Cvvp[i][j];
729
if (params.print_lvl) {
730
fprintf(outfile, "New C matrix for irrep %d\n", h);
731
print_mat(Cnew, moinfo.sopi[h], moinfo.orbspi[h], outfile);
734
chkpt_init(PSIO_OPEN_OLD);
735
chkpt_wt_scf_irrep(Cnew, h);
738
offset += moinfo.orbspi[h];
745
free_block(scf_vector);
748
}} // end namespace psi::mvo