[0b990d] | 1 | //
|
---|
| 2 | // aotoso.cc --- more symmetry stuff
|
---|
| 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 | #include <float.h>
|
---|
| 29 |
|
---|
| 30 | #include <util/misc/formio.h>
|
---|
| 31 |
|
---|
| 32 | #include <chemistry/qc/basis/basis.h>
|
---|
| 33 | #include <chemistry/qc/basis/integral.h>
|
---|
| 34 | #include <chemistry/qc/basis/shellrot.h>
|
---|
| 35 | #include <chemistry/qc/basis/petite.h>
|
---|
| 36 | #include <chemistry/qc/basis/f77sym.h>
|
---|
| 37 |
|
---|
| 38 | using namespace std;
|
---|
| 39 | using namespace sc;
|
---|
| 40 |
|
---|
| 41 | extern "C" {
|
---|
| 42 | void
|
---|
| 43 | F77_DGESVD(const char * JOBU, const char *JOBVT,
|
---|
| 44 | int *M, int *N, double *A, int *LDA,
|
---|
| 45 | double *S, double *U, int *LDU, double *VT, int *LDVT,
|
---|
| 46 | double *WORK, int *LWORK, int *INFO );
|
---|
| 47 | }
|
---|
| 48 |
|
---|
| 49 | ////////////////////////////////////////////////////////////////////////////
|
---|
| 50 |
|
---|
| 51 | contribution::contribution()
|
---|
| 52 | {
|
---|
| 53 | }
|
---|
| 54 |
|
---|
| 55 | contribution::~contribution()
|
---|
| 56 | {
|
---|
| 57 | }
|
---|
| 58 |
|
---|
| 59 | contribution::contribution(int b, double c) : bfn(b), coef(c)
|
---|
| 60 | {
|
---|
| 61 | }
|
---|
| 62 |
|
---|
| 63 | ////////////////////////////////////////////////////////////////////////////
|
---|
| 64 |
|
---|
| 65 | SO::SO() : len(0), length(0), cont(0)
|
---|
| 66 | {
|
---|
| 67 | }
|
---|
| 68 |
|
---|
| 69 | SO::SO(int l) : len(0), length(0), cont(0)
|
---|
| 70 | {
|
---|
| 71 | set_length(l);
|
---|
| 72 | }
|
---|
| 73 |
|
---|
| 74 | SO::~SO()
|
---|
| 75 | {
|
---|
| 76 | set_length(0);
|
---|
| 77 | }
|
---|
| 78 |
|
---|
| 79 | SO&
|
---|
| 80 | SO::operator=(const SO& so)
|
---|
| 81 | {
|
---|
| 82 | set_length(so.length);
|
---|
| 83 | length = so.length;
|
---|
| 84 | for (int i=0; i < length; i++)
|
---|
| 85 | cont[i] = so.cont[i];
|
---|
| 86 | return *this;
|
---|
| 87 | }
|
---|
| 88 |
|
---|
| 89 | void
|
---|
| 90 | SO::set_length(int l)
|
---|
| 91 | {
|
---|
| 92 | len=l;
|
---|
| 93 | length=l;
|
---|
| 94 | if (cont) {
|
---|
| 95 | delete[] cont;
|
---|
| 96 | cont=0;
|
---|
| 97 | }
|
---|
| 98 |
|
---|
| 99 | if (l)
|
---|
| 100 | cont = new contribution[l];
|
---|
| 101 | }
|
---|
| 102 |
|
---|
| 103 | void
|
---|
| 104 | SO::reset_length(int l)
|
---|
| 105 | {
|
---|
| 106 | length=l;
|
---|
| 107 |
|
---|
| 108 | if (l <= len)
|
---|
| 109 | return;
|
---|
| 110 |
|
---|
| 111 | l=l+10;
|
---|
| 112 |
|
---|
| 113 | contribution *newcont = new contribution[l];
|
---|
| 114 |
|
---|
| 115 | if (cont) {
|
---|
| 116 | for (int i=0; i < len; i++)
|
---|
| 117 | newcont[i] = cont[i];
|
---|
| 118 |
|
---|
| 119 | delete[] cont;
|
---|
| 120 | }
|
---|
| 121 |
|
---|
| 122 | cont=newcont;
|
---|
| 123 | len=l;
|
---|
| 124 | }
|
---|
| 125 |
|
---|
| 126 | int
|
---|
| 127 | SO::equiv(const SO& so)
|
---|
| 128 | {
|
---|
| 129 | int i;
|
---|
| 130 |
|
---|
| 131 | if (so.length != length)
|
---|
| 132 | return 0;
|
---|
| 133 |
|
---|
| 134 | double c=0;
|
---|
| 135 | for (i=0; i < length; i++) {
|
---|
| 136 | if (cont[i].bfn != so.cont[i].bfn)
|
---|
| 137 | return 0;
|
---|
| 138 | c += cont[i].coef*so.cont[i].coef;
|
---|
| 139 | }
|
---|
| 140 |
|
---|
| 141 | // if the overlap == 1.0, they're equal (SO's should have been
|
---|
| 142 | // normalized by now)
|
---|
| 143 | if (fabs(fabs(c)-1.0) < 1.0e-3)
|
---|
| 144 | return 1;
|
---|
| 145 |
|
---|
| 146 | return 0;
|
---|
| 147 | }
|
---|
| 148 |
|
---|
| 149 | ////////////////////////////////////////////////////////////////////////////
|
---|
| 150 |
|
---|
| 151 | SO_block::SO_block() : len(0), so(0)
|
---|
| 152 | {
|
---|
| 153 | }
|
---|
| 154 |
|
---|
| 155 | SO_block::SO_block(int l) : len(0), so(0)
|
---|
| 156 | {
|
---|
| 157 | set_length(l);
|
---|
| 158 | }
|
---|
| 159 |
|
---|
| 160 | SO_block::~SO_block()
|
---|
| 161 | {
|
---|
| 162 | set_length(0);
|
---|
| 163 | }
|
---|
| 164 |
|
---|
| 165 | void
|
---|
| 166 | SO_block::set_length(int l)
|
---|
| 167 | {
|
---|
| 168 | len=l;
|
---|
| 169 | if (so) {
|
---|
| 170 | delete[] so;
|
---|
| 171 | so=0;
|
---|
| 172 | }
|
---|
| 173 |
|
---|
| 174 | if (l)
|
---|
| 175 | so = new SO[l];
|
---|
| 176 | }
|
---|
| 177 |
|
---|
| 178 | void
|
---|
| 179 | SO_block::reset_length(int l)
|
---|
| 180 | {
|
---|
| 181 | if (len == l) return;
|
---|
| 182 |
|
---|
| 183 | SO *newso = new SO[l];
|
---|
| 184 |
|
---|
| 185 | if (so) {
|
---|
| 186 | for (int i=0; i < len; i++)
|
---|
| 187 | newso[i] = so[i];
|
---|
| 188 |
|
---|
| 189 | delete[] so;
|
---|
| 190 | }
|
---|
| 191 |
|
---|
| 192 | so=newso;
|
---|
| 193 | len=l;
|
---|
| 194 | }
|
---|
| 195 |
|
---|
| 196 | int
|
---|
| 197 | SO_block::add(SO& s, int i)
|
---|
| 198 | {
|
---|
| 199 | // first check to see if s is already here
|
---|
| 200 | for (int j=0; j < ((i < len) ? i : len); j++)
|
---|
| 201 | if (so[j].equiv(s))
|
---|
| 202 | return 0;
|
---|
| 203 |
|
---|
| 204 | if (i >= len)
|
---|
| 205 | reset_length(i+1);
|
---|
| 206 | so[i] = s;
|
---|
| 207 |
|
---|
| 208 | return 1;
|
---|
| 209 | }
|
---|
| 210 |
|
---|
| 211 | void
|
---|
| 212 | SO_block::print(const char *title)
|
---|
| 213 | {
|
---|
| 214 | int i,j;
|
---|
| 215 | ExEnv::out0() << indent << "SO block " << title << endl;
|
---|
| 216 | for (i=0; i < len; i++) {
|
---|
| 217 | ExEnv::out0() << indent << "SO " << i+1 << endl << indent;
|
---|
| 218 | for (j=0; j < so[i].length; j++)
|
---|
| 219 | ExEnv::out0() << scprintf(" %10d",so[i].cont[j].bfn);
|
---|
| 220 | ExEnv::out0() << endl << indent;
|
---|
| 221 | for (j=0; j < so[i].length; j++)
|
---|
| 222 | ExEnv::out0() << scprintf(" %10.7f",so[i].cont[j].coef);
|
---|
| 223 | ExEnv::out0() << endl;
|
---|
| 224 | }
|
---|
| 225 | }
|
---|
| 226 |
|
---|
| 227 | ////////////////////////////////////////////////////////////////////////////
|
---|
| 228 |
|
---|
| 229 | struct lin_comb {
|
---|
| 230 | int ns;
|
---|
| 231 | int f0;
|
---|
| 232 | int mapf0;
|
---|
| 233 | double **c;
|
---|
| 234 |
|
---|
| 235 | lin_comb(int ins, int if0, int imf0) : ns(ins), f0(if0), mapf0(imf0) {
|
---|
| 236 | int i;
|
---|
| 237 |
|
---|
| 238 | c = new double*[ns];
|
---|
| 239 | for (i=0; i < ns; i++) {
|
---|
| 240 | c[i] = new double[ns];
|
---|
| 241 | memset(c[i],0,sizeof(double)*ns);
|
---|
| 242 | }
|
---|
| 243 | }
|
---|
| 244 |
|
---|
| 245 | ~lin_comb() {
|
---|
| 246 | if (c) {
|
---|
| 247 | for (int i=0; i < ns; i++)
|
---|
| 248 | if (c[i])
|
---|
| 249 | delete[] c[i];
|
---|
| 250 | delete[] c;
|
---|
| 251 | c=0;
|
---|
| 252 | }
|
---|
| 253 | }
|
---|
| 254 |
|
---|
| 255 | void print() const {
|
---|
| 256 | int i;
|
---|
| 257 | ExEnv::out0() << indent;
|
---|
| 258 | for (i=0; i < ns; i++)
|
---|
| 259 | ExEnv::out0() << scprintf(" %10d",mapf0+i);
|
---|
| 260 | ExEnv::out0() << endl;
|
---|
| 261 |
|
---|
| 262 | for (i=0; i < ns; i++) {
|
---|
| 263 | ExEnv::out0() << indent << scprintf("%2d",f0+i);
|
---|
| 264 | for (int j=0; j < ns; j++)
|
---|
| 265 | ExEnv::out0() << scprintf(" %10.7f",c[i][j]);
|
---|
| 266 | ExEnv::out0() << endl;
|
---|
| 267 | }
|
---|
| 268 | }
|
---|
| 269 | };
|
---|
| 270 |
|
---|
| 271 | ////////////////////////////////////////////////////////////////////////////
|
---|
| 272 |
|
---|
| 273 | SO_block *
|
---|
| 274 | PetiteList::aotoso_info()
|
---|
| 275 | {
|
---|
| 276 | int iuniq, i, j, d, ii, jj, g, s, c, ir;
|
---|
| 277 |
|
---|
| 278 | GaussianBasisSet& gbs = *gbs_.pointer();
|
---|
| 279 | Molecule& mol = *gbs.molecule().pointer();
|
---|
| 280 |
|
---|
| 281 | // create the character table for the point group
|
---|
| 282 | CharacterTable ct = mol.point_group()->char_table();
|
---|
| 283 | SymmetryOperation so;
|
---|
| 284 |
|
---|
| 285 | if (c1_) {
|
---|
| 286 | SO_block *SOs = new SO_block[1];
|
---|
| 287 | SOs[0].set_length(gbs.nbasis());
|
---|
| 288 | for (i=0; i < gbs.nbasis(); i++) {
|
---|
| 289 | SOs[0].so[i].set_length(1);
|
---|
| 290 | SOs[0].so[i].cont[0].bfn=i;
|
---|
| 291 | SOs[0].so[i].cont[0].coef=1.0;
|
---|
| 292 | }
|
---|
| 293 | return SOs;
|
---|
| 294 | }
|
---|
| 295 |
|
---|
| 296 | // ncomp is the number of symmetry blocks we have. for point groups with
|
---|
| 297 | // complex E representations, this will be cut in two eventually
|
---|
| 298 | int ncomp=0;
|
---|
| 299 | for (i=0; i < nirrep_; i++)
|
---|
| 300 | ncomp += ct.gamma(i).degeneracy();
|
---|
| 301 |
|
---|
| 302 | // saoelem is the current SO in a block
|
---|
| 303 | int *saoelem = new int[ncomp];
|
---|
| 304 | memset(saoelem,0,sizeof(int)*ncomp);
|
---|
| 305 |
|
---|
| 306 | int *whichir = new int[ncomp];
|
---|
| 307 | int *whichcmp = new int[ncomp];
|
---|
| 308 | for (i=ii=0; i < nirrep_; i++) {
|
---|
| 309 | for (int j=0; j < ct.gamma(i).degeneracy(); j++,ii++) {
|
---|
| 310 | whichir[ii] = i;
|
---|
| 311 | whichcmp[ii] = j;
|
---|
| 312 | }
|
---|
| 313 | }
|
---|
| 314 |
|
---|
| 315 | // SOs is an array of SO_blocks which holds the redundant SO's
|
---|
| 316 | SO_block *SOs = new SO_block[ncomp];
|
---|
| 317 |
|
---|
| 318 | for (i=0; i < ncomp; i++) {
|
---|
| 319 | ir = whichir[i];
|
---|
| 320 | int len = (ct.gamma(ir).complex()) ? nbf_in_ir_[ir]/2 : nbf_in_ir_[ir];
|
---|
| 321 | SOs[i].set_length(len);
|
---|
| 322 | }
|
---|
| 323 |
|
---|
| 324 | // loop over all unique shells
|
---|
| 325 | for (iuniq=0; iuniq < gbs.molecule()->nunique(); iuniq++) {
|
---|
| 326 | int nequiv = gbs.molecule()->nequivalent(iuniq);
|
---|
| 327 | i = gbs.molecule()->unique(iuniq);
|
---|
| 328 | for (s=0; s < gbs.nshell_on_center(i); s++) {
|
---|
| 329 | int shell_i = gbs.shell_on_center(i,s);
|
---|
| 330 |
|
---|
| 331 | // test to see if there are any high am cartesian functions in this
|
---|
| 332 | // shell. for now don't allow symmetry with cartesian functions...I
|
---|
| 333 | // just can't seem to get them working.
|
---|
| 334 | for (c=0; c < gbs(i,s).ncontraction(); c++) {
|
---|
| 335 | if (gbs(i,s).am(c) > 1 && gbs(i,s).is_cartesian(c)) {
|
---|
| 336 | if (ng_ != nirrep_) {
|
---|
| 337 | ExEnv::err0() << indent
|
---|
| 338 | << "PetiteList::aotoso: cannot yet handle"
|
---|
| 339 | << " symmetry for angular momentum >= 2\n";
|
---|
| 340 | abort();
|
---|
| 341 | }
|
---|
| 342 | }
|
---|
| 343 | }
|
---|
| 344 |
|
---|
| 345 | // the functions do not mix between contractions
|
---|
| 346 | // so the contraction loop can be done outside the symmetry
|
---|
| 347 | // operation loop
|
---|
| 348 | int bfn_offset_in_shell = 0;
|
---|
| 349 | for (c=0; c < gbs(i,s).ncontraction(); c++) {
|
---|
| 350 | int nfuncuniq = gbs(i,s).nfunction(c);
|
---|
| 351 | int nfuncall = nfuncuniq * nequiv;
|
---|
| 352 |
|
---|
| 353 | // allocate an array to store linear combinations of orbitals
|
---|
| 354 | // this is destroyed by the SVD routine
|
---|
| 355 | double **linorb = new double*[nfuncuniq];
|
---|
| 356 | linorb[0] = new double[nfuncuniq*nfuncall];
|
---|
| 357 | for (j=1; j<nfuncuniq; j++) {
|
---|
| 358 | linorb[j] = &linorb[j-1][nfuncall];
|
---|
| 359 | }
|
---|
| 360 |
|
---|
| 361 | // a copy of linorb
|
---|
| 362 | double **linorbcop = new double*[nfuncuniq];
|
---|
| 363 | linorbcop[0] = new double[nfuncuniq*nfuncall];
|
---|
| 364 | for (j=1; j<nfuncuniq; j++) {
|
---|
| 365 | linorbcop[j] = &linorbcop[j-1][nfuncall];
|
---|
| 366 | }
|
---|
| 367 |
|
---|
| 368 | // allocate an array for the SVD routine
|
---|
| 369 | double **u = new double*[nfuncuniq];
|
---|
| 370 | u[0] = new double[nfuncuniq*nfuncuniq];
|
---|
| 371 | for (j=1; j<nfuncuniq; j++) {
|
---|
| 372 | u[j] = &u[j-1][nfuncuniq];
|
---|
| 373 | }
|
---|
| 374 |
|
---|
| 375 | // loop through each irrep to form the linear combination
|
---|
| 376 | // of orbitals of that symmetry
|
---|
| 377 | int irnum = 0;
|
---|
| 378 | for (ir=0; ir<ct.nirrep(); ir++) {
|
---|
| 379 | int cmplx = (ct.complex() && ct.gamma(ir).complex());
|
---|
| 380 | for (int comp=0; comp < ct.gamma(ir).degeneracy(); comp++) {
|
---|
| 381 | memset(linorb[0], 0, nfuncuniq*nfuncall*sizeof(double));
|
---|
| 382 | for (d=0; d < ct.gamma(ir).degeneracy(); d++) {
|
---|
| 383 | // if this is a point group with a complex E representation,
|
---|
| 384 | // then only do the first set of projections for E
|
---|
| 385 | if (d && cmplx) break;
|
---|
| 386 |
|
---|
| 387 | // operate on each function in this contraction with each
|
---|
| 388 | // symmetry operation to form symmetrized linear combinations
|
---|
| 389 | // of orbitals
|
---|
| 390 |
|
---|
| 391 | for (g=0; g<ng_; g++) {
|
---|
| 392 | // the character
|
---|
| 393 | double ccdg = ct.gamma(ir).p(comp,d,g);
|
---|
| 394 |
|
---|
| 395 | so = ct.symm_operation(g);
|
---|
| 396 | int equivatom = atom_map_[i][g];
|
---|
| 397 | int atomoffset
|
---|
| 398 | = gbs.molecule()->atom_to_unique_offset(equivatom);
|
---|
| 399 |
|
---|
| 400 | ShellRotation rr
|
---|
| 401 | = ints_->shell_rotation(gbs(i,s).am(c),
|
---|
| 402 | so,gbs(i,s).is_pure(c));
|
---|
| 403 |
|
---|
| 404 | for (ii=0; ii < rr.dim(); ii++) {
|
---|
| 405 | for (jj=0; jj < rr.dim(); jj++) {
|
---|
| 406 | linorb[ii][atomoffset*nfuncuniq+jj] += ccdg * rr(ii,jj);
|
---|
| 407 | }
|
---|
| 408 | }
|
---|
| 409 | }
|
---|
| 410 | }
|
---|
| 411 | // find the linearly independent SO's for this irrep/component
|
---|
| 412 | memcpy(linorbcop[0], linorb[0], nfuncuniq*nfuncall*sizeof(double));
|
---|
| 413 | double *singval = new double[nfuncuniq];
|
---|
| 414 | double djunk=0; int ijunk=1;
|
---|
| 415 | int lwork = 5*nfuncall;
|
---|
| 416 | double *work = new double[lwork];
|
---|
| 417 | int info;
|
---|
| 418 | // solves At = V SIGMA Ut (since FORTRAN array layout is used)
|
---|
| 419 | F77_DGESVD("N","A",&nfuncall,&nfuncuniq,linorb[0],&nfuncall,
|
---|
| 420 | singval, &djunk, &ijunk, u[0], &nfuncuniq,
|
---|
| 421 | work, &lwork, &info);
|
---|
| 422 | // put the lin indep symm orbs into the so array
|
---|
| 423 | for (j=0; j<nfuncuniq; j++) {
|
---|
| 424 | if (singval[j] > 1.0e-6) {
|
---|
| 425 | SO tso;
|
---|
| 426 | tso.set_length(nfuncall);
|
---|
| 427 | int ll = 0, llnonzero = 0;
|
---|
| 428 | for (int k=0; k<nequiv; k++) {
|
---|
| 429 | for (int l=0; l<nfuncuniq; l++,ll++) {
|
---|
| 430 | double tmp = 0.0;
|
---|
| 431 | for (int m=0; m<nfuncuniq; m++) {
|
---|
| 432 | tmp += u[m][j] * linorbcop[m][ll] / singval[j];
|
---|
| 433 | }
|
---|
| 434 | if (fabs(tmp) > DBL_EPSILON) {
|
---|
| 435 | int equivatom = gbs.molecule()->equivalent(iuniq,k);
|
---|
| 436 | tso.cont[llnonzero].bfn
|
---|
| 437 | = l
|
---|
| 438 | + bfn_offset_in_shell
|
---|
| 439 | + gbs.shell_to_function(gbs.shell_on_center(equivatom,
|
---|
| 440 | s));
|
---|
| 441 | tso.cont[llnonzero].coef = tmp;
|
---|
| 442 | llnonzero++;
|
---|
| 443 | }
|
---|
| 444 | }
|
---|
| 445 | }
|
---|
| 446 | tso.reset_length(llnonzero);
|
---|
| 447 | if (llnonzero == 0) {
|
---|
| 448 | ExEnv::errn() << "aotoso: internal error: no bfns in SO"
|
---|
| 449 | << endl;
|
---|
| 450 | abort();
|
---|
| 451 | }
|
---|
| 452 | if (SOs[irnum+comp].add(tso,saoelem[irnum+comp])) {
|
---|
| 453 | saoelem[irnum+comp]++;
|
---|
| 454 | }
|
---|
| 455 | else {
|
---|
| 456 | ExEnv::errn() << "aotoso: internal error: "
|
---|
| 457 | << "impossible duplicate SO"
|
---|
| 458 | << endl;
|
---|
| 459 | abort();
|
---|
| 460 | }
|
---|
| 461 | }
|
---|
| 462 | }
|
---|
| 463 | delete[] singval;
|
---|
| 464 | delete[] work;
|
---|
| 465 | }
|
---|
| 466 | irnum += ct.gamma(ir).degeneracy();
|
---|
| 467 | }
|
---|
| 468 | bfn_offset_in_shell += gbs(i,s).nfunction(c);
|
---|
| 469 |
|
---|
| 470 | delete[] linorb[0];
|
---|
| 471 | delete[] linorb;
|
---|
| 472 | delete[] linorbcop[0];
|
---|
| 473 | delete[] linorbcop;
|
---|
| 474 | delete[] u[0];
|
---|
| 475 | delete[] u;
|
---|
| 476 | }
|
---|
| 477 | }
|
---|
| 478 | }
|
---|
| 479 |
|
---|
| 480 | // Make sure all the nodes agree on what the symmetry orbitals are.
|
---|
| 481 | // (All the above work for me > 0 is ignored.)
|
---|
| 482 | Ref<MessageGrp> grp = MessageGrp::get_default_messagegrp();
|
---|
| 483 | for (i=0; i<ncomp; i++) {
|
---|
| 484 | int len = SOs[i].len;
|
---|
| 485 | grp->bcast(len);
|
---|
| 486 | SOs[i].reset_length(len);
|
---|
| 487 | for (j=0; j<len; j++) {
|
---|
| 488 | int solen = SOs[i].so[j].length;
|
---|
| 489 | grp->bcast(solen);
|
---|
| 490 | SOs[i].so[j].reset_length(solen);
|
---|
| 491 | for (int k=0; k<solen; k++) {
|
---|
| 492 | grp->bcast(SOs[i].so[j].cont[k].bfn);
|
---|
| 493 | grp->bcast(SOs[i].so[j].cont[k].coef);
|
---|
| 494 | }
|
---|
| 495 | }
|
---|
| 496 | }
|
---|
| 497 |
|
---|
| 498 | for (i=0; i < ncomp; i++) {
|
---|
| 499 | ir = whichir[i];
|
---|
| 500 | int scal = ct.gamma(ir).complex() ? 2 : 1;
|
---|
| 501 |
|
---|
| 502 | if (saoelem[i] < nbf_in_ir_[ir]/scal) {
|
---|
| 503 | // if we found too few, there are big problems
|
---|
| 504 |
|
---|
| 505 | ExEnv::err0() << indent
|
---|
| 506 | << scprintf("trouble making SO's for irrep %s\n",
|
---|
| 507 | ct.gamma(ir).symbol());
|
---|
| 508 | ExEnv::err0() << indent
|
---|
| 509 | << scprintf(" only found %d out of %d SO's\n",
|
---|
| 510 | saoelem[i], nbf_in_ir_[ir]/scal);
|
---|
| 511 | SOs[i].print("");
|
---|
| 512 | abort();
|
---|
| 513 |
|
---|
| 514 | } else if (saoelem[i] > nbf_in_ir_[ir]/scal) {
|
---|
| 515 | // there are some redundant so's left...need to do something to get
|
---|
| 516 | // the elements we want
|
---|
| 517 |
|
---|
| 518 | ExEnv::err0() << indent
|
---|
| 519 | << scprintf("trouble making SO's for irrep %s\n",
|
---|
| 520 | ct.gamma(ir).symbol());
|
---|
| 521 | ExEnv::err0() << indent
|
---|
| 522 | << scprintf(" found %d SO's, but there should only be %d\n",
|
---|
| 523 | saoelem[i], nbf_in_ir_[ir]/scal);
|
---|
| 524 | SOs[i].print("");
|
---|
| 525 | abort();
|
---|
| 526 | }
|
---|
| 527 | }
|
---|
| 528 |
|
---|
| 529 | if (ct.complex()) {
|
---|
| 530 | SO_block *nSOs = new SO_block[nblocks_];
|
---|
| 531 |
|
---|
| 532 | int in=0;
|
---|
| 533 |
|
---|
| 534 | for (i=ir=0; ir < nirrep_; ir++) {
|
---|
| 535 | if (ct.gamma(ir).complex()) {
|
---|
| 536 | nSOs[in].set_length(nbf_in_ir_[ir]);
|
---|
| 537 | int k;
|
---|
| 538 | for (k=0; k < SOs[i].len; k++)
|
---|
| 539 | nSOs[in].add(SOs[i].so[k],k);
|
---|
| 540 | i++;
|
---|
| 541 |
|
---|
| 542 | for (j=0; j < SOs[i].len; j++,k++)
|
---|
| 543 | nSOs[in].add(SOs[i].so[j],k);
|
---|
| 544 |
|
---|
| 545 | i++;
|
---|
| 546 | in++;
|
---|
| 547 | } else {
|
---|
| 548 | for (j=0; j < ct.gamma(ir).degeneracy(); j++,i++,in++) {
|
---|
| 549 | nSOs[in].set_length(nbf_in_ir_[ir]);
|
---|
| 550 | for (int k=0; k < SOs[i].len; k++)
|
---|
| 551 | nSOs[in].add(SOs[i].so[k],k);
|
---|
| 552 | }
|
---|
| 553 | }
|
---|
| 554 | }
|
---|
| 555 |
|
---|
| 556 | SO_block *tmp= SOs;
|
---|
| 557 | SOs = nSOs;
|
---|
| 558 | delete[] tmp;
|
---|
| 559 | }
|
---|
| 560 |
|
---|
| 561 | delete[] saoelem;
|
---|
| 562 | delete[] whichir;
|
---|
| 563 | delete[] whichcmp;
|
---|
| 564 |
|
---|
| 565 | return SOs;
|
---|
| 566 | }
|
---|
| 567 |
|
---|
| 568 | RefSCMatrix
|
---|
| 569 | PetiteList::aotoso()
|
---|
| 570 | {
|
---|
| 571 | RefSCMatrix aoso(AO_basisdim(), SO_basisdim(), gbs_->so_matrixkit());
|
---|
| 572 | aoso.assign(0.0);
|
---|
| 573 |
|
---|
| 574 | if (c1_) {
|
---|
| 575 | aoso->unit();
|
---|
| 576 | return aoso;
|
---|
| 577 | }
|
---|
| 578 |
|
---|
| 579 | SO_block *sos = aotoso_info();
|
---|
| 580 |
|
---|
| 581 | BlockedSCMatrix *aosop = dynamic_cast<BlockedSCMatrix*>(aoso.pointer());
|
---|
| 582 |
|
---|
| 583 | for (int b=0; b < aosop->nblocks(); b++) {
|
---|
| 584 | RefSCMatrix aosb = aosop->block(b);
|
---|
| 585 |
|
---|
| 586 | if (aosb.null())
|
---|
| 587 | continue;
|
---|
| 588 |
|
---|
| 589 | SO_block& sob = sos[b];
|
---|
| 590 |
|
---|
| 591 | Ref<SCMatrixSubblockIter> iter =
|
---|
| 592 | aosb->local_blocks(SCMatrixSubblockIter::Write);
|
---|
| 593 |
|
---|
| 594 | for (iter->begin(); iter->ready(); iter->next()) {
|
---|
| 595 | if (dynamic_cast<SCMatrixRectBlock*>(iter->block())) {
|
---|
| 596 | SCMatrixRectBlock *blk = dynamic_cast<SCMatrixRectBlock*>(iter->block());
|
---|
| 597 |
|
---|
| 598 | int jlen = blk->jend-blk->jstart;
|
---|
| 599 |
|
---|
| 600 | for (int j=0; j < sob.len; j++) {
|
---|
| 601 | if (j < blk->jstart || j >= blk->jend)
|
---|
| 602 | continue;
|
---|
| 603 |
|
---|
| 604 | SO& soj = sob.so[j];
|
---|
| 605 |
|
---|
| 606 | for (int i=0; i < soj.len; i++) {
|
---|
| 607 | int ii=soj.cont[i].bfn;
|
---|
| 608 |
|
---|
| 609 | if (ii < blk->istart || ii >= blk->iend)
|
---|
| 610 | continue;
|
---|
| 611 |
|
---|
| 612 | blk->data[(ii-blk->istart)*jlen+(j-blk->jstart)] =
|
---|
| 613 | soj.cont[i].coef;
|
---|
| 614 | }
|
---|
| 615 | }
|
---|
| 616 | } else {
|
---|
| 617 | SCMatrixRectSubBlock *blk =
|
---|
| 618 | dynamic_cast<SCMatrixRectSubBlock*>(iter->block());
|
---|
| 619 |
|
---|
| 620 | for (int j=0; j < sob.len; j++) {
|
---|
| 621 | if (j < blk->jstart || j >= blk->jend)
|
---|
| 622 | continue;
|
---|
| 623 |
|
---|
| 624 | SO& soj = sob.so[j];
|
---|
| 625 |
|
---|
| 626 | for (int i=0; i < soj.len; i++) {
|
---|
| 627 | int ii=soj.cont[i].bfn;
|
---|
| 628 |
|
---|
| 629 | if (ii < blk->istart || ii >= blk->iend)
|
---|
| 630 | continue;
|
---|
| 631 |
|
---|
| 632 | blk->data[ii*blk->istride+j] = soj.cont[i].coef;
|
---|
| 633 | }
|
---|
| 634 | }
|
---|
| 635 | }
|
---|
| 636 | }
|
---|
| 637 | }
|
---|
| 638 |
|
---|
| 639 | delete[] sos;
|
---|
| 640 |
|
---|
| 641 | return aoso;
|
---|
| 642 | }
|
---|
| 643 |
|
---|
| 644 | RefSCMatrix
|
---|
| 645 | PetiteList::sotoao()
|
---|
| 646 | {
|
---|
| 647 | if (c1_)
|
---|
| 648 | return aotoso();
|
---|
| 649 | else if (nirrep_ == ng_) // subgroup of d2h
|
---|
| 650 | return aotoso().t();
|
---|
| 651 | else
|
---|
| 652 | return aotoso().i();
|
---|
| 653 | }
|
---|
| 654 |
|
---|
| 655 | RefSymmSCMatrix
|
---|
| 656 | PetiteList::to_SO_basis(const RefSymmSCMatrix& a)
|
---|
| 657 | {
|
---|
| 658 | // SO basis is always blocked, so first make sure a is blocked
|
---|
| 659 | RefSymmSCMatrix aomatrix = dynamic_cast<BlockedSymmSCMatrix*>(a.pointer());
|
---|
| 660 | if (aomatrix.null()) {
|
---|
| 661 | aomatrix = gbs_->so_matrixkit()->symmmatrix(AO_basisdim());
|
---|
| 662 | aomatrix->convert(a);
|
---|
| 663 | }
|
---|
| 664 |
|
---|
| 665 | // if C1, then do nothing
|
---|
| 666 | if (c1_)
|
---|
| 667 | return aomatrix.copy();
|
---|
| 668 |
|
---|
| 669 | RefSymmSCMatrix somatrix(SO_basisdim(), gbs_->so_matrixkit());
|
---|
| 670 | somatrix.assign(0.0);
|
---|
| 671 | somatrix->accumulate_transform(aotoso(), aomatrix,
|
---|
| 672 | SCMatrix::TransposeTransform);
|
---|
| 673 |
|
---|
| 674 | return somatrix;
|
---|
| 675 | }
|
---|
| 676 |
|
---|
| 677 | RefSymmSCMatrix
|
---|
| 678 | PetiteList::to_AO_basis(const RefSymmSCMatrix& somatrix)
|
---|
| 679 | {
|
---|
| 680 | // if C1, then do nothing
|
---|
| 681 | if (c1_)
|
---|
| 682 | return somatrix.copy();
|
---|
| 683 |
|
---|
| 684 | RefSymmSCMatrix aomatrix(AO_basisdim(), gbs_->so_matrixkit());
|
---|
| 685 | aomatrix.assign(0.0);
|
---|
| 686 |
|
---|
| 687 | if (nirrep_ == ng_) // subgroup of d2h
|
---|
| 688 | aomatrix->accumulate_transform(aotoso(), somatrix);
|
---|
| 689 | else
|
---|
| 690 | aomatrix->accumulate_transform(aotoso().i(), somatrix,
|
---|
| 691 | SCMatrix::TransposeTransform);
|
---|
| 692 |
|
---|
| 693 | return aomatrix;
|
---|
| 694 | }
|
---|
| 695 |
|
---|
| 696 | RefSCMatrix
|
---|
| 697 | PetiteList::evecs_to_SO_basis(const RefSCMatrix& aoev)
|
---|
| 698 | {
|
---|
| 699 | ExEnv::err0() << indent
|
---|
| 700 | << "PetiteList::evecs_to_SO_basis: don't work yet\n";
|
---|
| 701 | abort();
|
---|
| 702 |
|
---|
| 703 | RefSCMatrix aoevecs = dynamic_cast<BlockedSCMatrix*>(aoev.pointer());
|
---|
| 704 | if (aoevecs.null()) {
|
---|
| 705 | aoevecs = gbs_->so_matrixkit()->matrix(AO_basisdim(), AO_basisdim());
|
---|
| 706 | aoevecs->convert(aoev);
|
---|
| 707 | }
|
---|
| 708 |
|
---|
| 709 | RefSCMatrix soev = aotoso().t() * aoevecs;
|
---|
| 710 | soev.print("soev");
|
---|
| 711 |
|
---|
| 712 | RefSCMatrix soevecs(SO_basisdim(), SO_basisdim(), gbs_->so_matrixkit());
|
---|
| 713 | soevecs->convert(soev);
|
---|
| 714 |
|
---|
| 715 | return soevecs;
|
---|
| 716 | }
|
---|
| 717 |
|
---|
| 718 | RefSCMatrix
|
---|
| 719 | PetiteList::evecs_to_AO_basis(const RefSCMatrix& soevecs)
|
---|
| 720 | {
|
---|
| 721 | // if C1, then do nothing
|
---|
| 722 | if (c1_)
|
---|
| 723 | return soevecs.copy();
|
---|
| 724 |
|
---|
| 725 | RefSCMatrix aoev = aotoso() * soevecs;
|
---|
| 726 |
|
---|
| 727 | return aoev;
|
---|
| 728 | }
|
---|
| 729 |
|
---|
| 730 | /////////////////////////////////////////////////////////////////////////////
|
---|
| 731 |
|
---|
| 732 | void
|
---|
| 733 | PetiteList::symmetrize(const RefSymmSCMatrix& skel,
|
---|
| 734 | const RefSymmSCMatrix& sym)
|
---|
| 735 | {
|
---|
| 736 | GaussianBasisSet& gbs = *gbs_.pointer();
|
---|
| 737 |
|
---|
| 738 | // SO basis is always blocked, so first make sure skel is blocked
|
---|
| 739 | RefSymmSCMatrix bskel = dynamic_cast<BlockedSymmSCMatrix*>(skel.pointer());
|
---|
| 740 | if (bskel.null()) {
|
---|
| 741 | bskel = gbs.so_matrixkit()->symmmatrix(AO_basisdim());
|
---|
| 742 | bskel->convert(skel);
|
---|
| 743 | }
|
---|
| 744 |
|
---|
| 745 | // if C1, then do nothing
|
---|
| 746 | if (c1_) {
|
---|
| 747 | sym.assign(bskel);
|
---|
| 748 | return;
|
---|
| 749 | }
|
---|
| 750 |
|
---|
| 751 | int b,c;
|
---|
| 752 |
|
---|
| 753 | CharacterTable ct = gbs.molecule()->point_group()->char_table();
|
---|
| 754 |
|
---|
| 755 | RefSCMatrix aoso = aotoso();
|
---|
| 756 | BlockedSCMatrix *lu = dynamic_cast<BlockedSCMatrix*>(aoso.pointer());
|
---|
| 757 |
|
---|
| 758 | for (b=0; b < lu->nblocks(); b++) {
|
---|
| 759 | if (lu->block(b).null())
|
---|
| 760 | continue;
|
---|
| 761 |
|
---|
| 762 | int ir = ct.which_irrep(b);
|
---|
| 763 |
|
---|
| 764 | double skal = (double)ct.order()/(double)ct.gamma(ir).degeneracy();
|
---|
| 765 | skal = sqrt(skal);
|
---|
| 766 | lu->block(b).scale(skal);
|
---|
| 767 | }
|
---|
| 768 |
|
---|
| 769 | sym.assign(0.0);
|
---|
| 770 | sym.accumulate_transform(aoso,bskel,SCMatrix::TransposeTransform);
|
---|
| 771 | aoso=0;
|
---|
| 772 |
|
---|
| 773 | BlockedSymmSCMatrix *la = dynamic_cast<BlockedSymmSCMatrix*>(sym.pointer());
|
---|
| 774 |
|
---|
| 775 | // loop through blocks and finish symmetrizing degenerate blocks
|
---|
| 776 | for (b=0; b < la->nblocks(); b++) {
|
---|
| 777 | if (la->block(b).null())
|
---|
| 778 | continue;
|
---|
| 779 |
|
---|
| 780 | int ir=ct.which_irrep(b);
|
---|
| 781 |
|
---|
| 782 | if (ct.gamma(ir).degeneracy()==1)
|
---|
| 783 | continue;
|
---|
| 784 |
|
---|
| 785 | if (ct.gamma(ir).complex()) {
|
---|
| 786 | int nbf = nbf_in_ir_[ir]/2;
|
---|
| 787 |
|
---|
| 788 | RefSymmSCMatrix irrep = la->block(b).get_subblock(0, nbf-1);
|
---|
| 789 | irrep.accumulate(la->block(b).get_subblock(nbf, 2*nbf-1));
|
---|
| 790 |
|
---|
| 791 | RefSCMatrix sub = la->block(b).get_subblock(nbf, 2*nbf-1, 0, nbf-1);
|
---|
| 792 | RefSCMatrix subt = sub.t();
|
---|
| 793 | subt.scale(-1.0);
|
---|
| 794 | sub.accumulate(subt);
|
---|
| 795 | subt=0;
|
---|
| 796 |
|
---|
| 797 | la->block(b).assign_subblock(irrep, 0, nbf-1);
|
---|
| 798 | la->block(b).assign_subblock(irrep,nbf, 2*nbf-1);
|
---|
| 799 | la->block(b).assign_subblock(sub, nbf, 2*nbf-1, 0, nbf-1);
|
---|
| 800 |
|
---|
| 801 | } else {
|
---|
| 802 | RefSymmSCMatrix irrep = la->block(b).copy();
|
---|
| 803 | for (c=1; c < ct.gamma(ir).degeneracy(); c++)
|
---|
| 804 | irrep.accumulate(la->block(b+c));
|
---|
| 805 |
|
---|
| 806 | for (c=0; c < ct.gamma(ir).degeneracy(); c++)
|
---|
| 807 | la->block(b+c).assign(irrep);
|
---|
| 808 |
|
---|
| 809 | b += ct.gamma(ir).degeneracy()-1;
|
---|
| 810 | }
|
---|
| 811 | }
|
---|
| 812 | }
|
---|
| 813 |
|
---|
| 814 | /////////////////////////////////////////////////////////////////////////////
|
---|
| 815 |
|
---|
| 816 | // Local Variables:
|
---|
| 817 | // mode: c++
|
---|
| 818 | // c-file-style: "ETS"
|
---|
| 819 | // End:
|
---|