[0b990d] | 1 | //
|
---|
| 2 | // bounds.cc
|
---|
| 3 | //
|
---|
| 4 | // Copyright (C) 1996 Limit Point Systems, Inc.
|
---|
| 5 | //
|
---|
| 6 | // Author: Curtis Janssen <cljanss@limitpt.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 <stdlib.h>
|
---|
| 29 | #include <math.h>
|
---|
| 30 |
|
---|
| 31 | #include <util/misc/formio.h>
|
---|
| 32 | #include <chemistry/qc/intv3/types.h>
|
---|
| 33 | #include <chemistry/qc/intv3/flags.h>
|
---|
| 34 | #include <chemistry/qc/intv3/int2e.h>
|
---|
| 35 |
|
---|
| 36 | using namespace std;
|
---|
| 37 | using namespace sc;
|
---|
| 38 |
|
---|
| 39 | #define COMPUTE_Q 1
|
---|
| 40 | #define COMPUTE_R 2
|
---|
| 41 |
|
---|
| 42 | /* find the biggest number in the buffer */
|
---|
| 43 | static double
|
---|
| 44 | find_max(double *int_buffer,int nint)
|
---|
| 45 | {
|
---|
| 46 | int i;
|
---|
| 47 | double max = 0.0;
|
---|
| 48 | for (i=0; i<nint; i++) {
|
---|
| 49 | double val = int_buffer[i];
|
---|
| 50 | if (val<0) val = -val;
|
---|
| 51 | if (val > max) max = val;
|
---|
| 52 | }
|
---|
| 53 | return max;
|
---|
| 54 | }
|
---|
| 55 |
|
---|
| 56 | void
|
---|
| 57 | Int2eV3::int_init_bounds_nocomp()
|
---|
| 58 | {
|
---|
| 59 | int i;
|
---|
| 60 | int nshell=bs1_->nshell();
|
---|
| 61 | int nsht=nshell*(nshell+1)/2;
|
---|
| 62 |
|
---|
| 63 | if (int_Qvec) free(int_Qvec);
|
---|
| 64 |
|
---|
| 65 | int_Qvec = (int_bound_t *) malloc(sizeof(int_bound_t)*nsht);
|
---|
| 66 | used_storage_ += sizeof(int_bound_t)*nsht;
|
---|
| 67 | if(int_Qvec==0) {
|
---|
| 68 | ExEnv::errn() << scprintf("int_init_bounds_nocomp: cannot malloc int_Qvec: %d",
|
---|
| 69 | nsht)
|
---|
| 70 | << endl;
|
---|
| 71 | exit(1);
|
---|
| 72 | }
|
---|
| 73 |
|
---|
| 74 | int_Rvec = 0;
|
---|
| 75 |
|
---|
| 76 | int_Q = int_bound_min;
|
---|
| 77 | for (i=0; i<nsht; i++) int_Qvec[i] = 0;
|
---|
| 78 | }
|
---|
| 79 |
|
---|
| 80 | void
|
---|
| 81 | Int2eV3::init_bounds()
|
---|
| 82 | {
|
---|
| 83 | int_init_bounds_nocomp();
|
---|
| 84 | compute_bounds(&int_Q,int_Qvec,COMPUTE_Q);
|
---|
| 85 | }
|
---|
| 86 |
|
---|
| 87 | void
|
---|
| 88 | Int2eV3::int_init_bounds_1der_nocomp()
|
---|
| 89 | {
|
---|
| 90 | int i;
|
---|
| 91 | int nshell=bs1_->nshell();
|
---|
| 92 | int nsht=nshell*(nshell+1)/2;
|
---|
| 93 |
|
---|
| 94 | if (!int_derivative_bounds) {
|
---|
| 95 | ExEnv::errn() << "requested der bounds but space not allocated" << endl;
|
---|
| 96 | exit(1);
|
---|
| 97 | }
|
---|
| 98 |
|
---|
| 99 | if (int_Qvec) free(int_Qvec);
|
---|
| 100 | if (int_Rvec) free(int_Rvec);
|
---|
| 101 |
|
---|
| 102 | int_Qvec = (int_bound_t *) malloc(sizeof(int_bound_t)*nsht);
|
---|
| 103 | int_Rvec = (int_bound_t *) malloc(sizeof(int_bound_t)*nsht);
|
---|
| 104 | used_storage_ += sizeof(int_bound_t)*nsht*2;
|
---|
| 105 | if((int_Qvec==0) || (int_Rvec==0)) {
|
---|
| 106 | ExEnv::errn() << scprintf("int_init_bounds_1der_nocomp: cannot malloc int_{R,Q}vec: %d",nsht) << endl;
|
---|
| 107 | exit(1);
|
---|
| 108 | }
|
---|
| 109 |
|
---|
| 110 | int_Q = int_bound_min;
|
---|
| 111 | int_R = int_bound_min;
|
---|
| 112 | for (i=0; i<nsht; i++) int_Qvec[i] = int_Rvec[i] = 0;
|
---|
| 113 | }
|
---|
| 114 |
|
---|
| 115 | void
|
---|
| 116 | Int2eV3::int_bounds_comp(int s1, int s2)
|
---|
| 117 | {
|
---|
| 118 | compute_bounds_shell(&int_Q,int_Qvec,COMPUTE_Q,s1,s2);
|
---|
| 119 | }
|
---|
| 120 |
|
---|
| 121 | void
|
---|
| 122 | Int2eV3::int_bounds_1der_comp(int s1, int s2)
|
---|
| 123 | {
|
---|
| 124 | compute_bounds_shell(&int_Q,int_Qvec,COMPUTE_Q,s1,s2);
|
---|
| 125 | compute_bounds_shell(&int_R,int_Rvec,COMPUTE_R,s1,s2);
|
---|
| 126 | }
|
---|
| 127 |
|
---|
| 128 | void
|
---|
| 129 | Int2eV3::init_bounds_1der()
|
---|
| 130 | {
|
---|
| 131 | int_init_bounds_1der_nocomp();
|
---|
| 132 | compute_bounds(&int_Q,int_Qvec,COMPUTE_Q);
|
---|
| 133 | compute_bounds(&int_R,int_Rvec,COMPUTE_R);
|
---|
| 134 | }
|
---|
| 135 |
|
---|
| 136 | void
|
---|
| 137 | Int2eV3::done_bounds()
|
---|
| 138 | {
|
---|
| 139 | if (int_Qvec) free(int_Qvec);
|
---|
| 140 | int_Qvec = 0;
|
---|
| 141 | }
|
---|
| 142 |
|
---|
| 143 | void
|
---|
| 144 | Int2eV3::done_bounds_1der()
|
---|
| 145 | {
|
---|
| 146 | if (int_Qvec) free(int_Qvec);
|
---|
| 147 | if (int_Rvec) free(int_Rvec);
|
---|
| 148 | int_Qvec = 0;
|
---|
| 149 | int_Rvec = 0;
|
---|
| 150 | }
|
---|
| 151 |
|
---|
| 152 | int
|
---|
| 153 | Int2eV3::erep_4bound(int s1, int s2, int s3, int s4)
|
---|
| 154 | {
|
---|
| 155 | if (!int_Qvec)
|
---|
| 156 | return 256;
|
---|
| 157 |
|
---|
| 158 | int Qij;
|
---|
| 159 | int Qkl;
|
---|
| 160 | if (s1 >= 0 && s2 >= 0) {
|
---|
| 161 | int ij=(s1>s2) ? ((s1*(s1+1))>>1)+s2 : ((s2*(s2+1))>>1)+s1;
|
---|
| 162 | Qij = int_Qvec[ij];
|
---|
| 163 | }
|
---|
| 164 | else Qij = int_Q;
|
---|
| 165 | if (s3 >=0 && s4 >= 0) {
|
---|
| 166 | int kl=(s3>s4) ? ((s3*(s3+1))>>1)+s4 : ((s4*(s4+1))>>1)+s3;
|
---|
| 167 | Qkl = int_Qvec[kl];
|
---|
| 168 | }
|
---|
| 169 | else Qkl = int_Q;
|
---|
| 170 |
|
---|
| 171 | return Qij+Qkl;
|
---|
| 172 | }
|
---|
| 173 |
|
---|
| 174 | int
|
---|
| 175 | Int2eV3::int_erep_2bound(int s1, int s2)
|
---|
| 176 | {
|
---|
| 177 | if (!int_Qvec)
|
---|
| 178 | return int_bound_max;
|
---|
| 179 |
|
---|
| 180 | int ij=(s1>s2) ? ((s1*(s1+1))>>1)+s2 : ((s2*(s2+1))>>1)+s1;
|
---|
| 181 |
|
---|
| 182 | return((int) int_Qvec[ij]);
|
---|
| 183 | }
|
---|
| 184 |
|
---|
| 185 | int
|
---|
| 186 | Int2eV3::int_erep_0bound_1der()
|
---|
| 187 | {
|
---|
| 188 | #if 0
|
---|
| 189 | ExEnv::outn() << scprintf("int_erep_0bound_1der(): Q: %4d R: %4d\n", int_Q,int_R);
|
---|
| 190 | #endif
|
---|
| 191 | return 1 + int_Q + int_R;
|
---|
| 192 | }
|
---|
| 193 |
|
---|
| 194 | int
|
---|
| 195 | Int2eV3::int_erep_2bound_1der(int s1, int s2)
|
---|
| 196 | {
|
---|
| 197 | if (!int_Qvec || !int_Rvec)
|
---|
| 198 | return int_bound_max;
|
---|
| 199 |
|
---|
| 200 | int ij=(s1>s2) ? ((s1*(s1+1))>>1)+s2 : ((s2*(s2+1))>>1)+s1;
|
---|
| 201 | int b1 = int_Qvec[ij] + int_R;
|
---|
| 202 | int b2 = int_Q + int_Rvec[ij];
|
---|
| 203 |
|
---|
| 204 | #if 0
|
---|
| 205 | ExEnv::outn() << scprintf("int_erep_2bound_1der(%d,%d): Q: %4d R: %4d\n",s1,s2,
|
---|
| 206 | int_Qvec[ij],int_Rvec[ij]);
|
---|
| 207 | #endif
|
---|
| 208 |
|
---|
| 209 | /* The actual bound is Qij R + Q Rij
|
---|
| 210 | * but since I'm using log base 2 I'll use
|
---|
| 211 | * 2 * max (Qij R, Q Rij) -> 1 + max (Qij + R, Q + Rij)
|
---|
| 212 | */
|
---|
| 213 |
|
---|
| 214 | return 1 + ((b1>b2)? b1 : b2);
|
---|
| 215 | }
|
---|
| 216 |
|
---|
| 217 | int
|
---|
| 218 | Int2eV3::erep_4bound_1der(int s1, int s2, int s3, int s4)
|
---|
| 219 | {
|
---|
| 220 | if (!int_Qvec || !int_Rvec)
|
---|
| 221 | return 256;
|
---|
| 222 |
|
---|
| 223 | int Qij, Qkl, Rij, Rkl;
|
---|
| 224 |
|
---|
| 225 | if (s1 >= 0 && s2 >= 0) {
|
---|
| 226 | int ij=(s1>s2) ? ((s1*(s1+1))>>1)+s2 : ((s2*(s2+1))>>1)+s1;
|
---|
| 227 | Qij = int_Qvec[ij];
|
---|
| 228 | Rij = int_Rvec[ij];
|
---|
| 229 | }
|
---|
| 230 | else {
|
---|
| 231 | Qij = int_Q;
|
---|
| 232 | Rij = int_R;
|
---|
| 233 | }
|
---|
| 234 | if (s3 >= 0 && s4 >= 0) {
|
---|
| 235 | int kl=(s3>s4) ? ((s3*(s3+1))>>1)+s4 : ((s4*(s4+1))>>1)+s3;
|
---|
| 236 | Qkl = int_Qvec[kl];
|
---|
| 237 | Rkl = int_Rvec[kl];
|
---|
| 238 | }
|
---|
| 239 | else {
|
---|
| 240 | Qkl = int_Q;
|
---|
| 241 | Rkl = int_R;
|
---|
| 242 | }
|
---|
| 243 |
|
---|
| 244 | int b1 = Qij + Rkl;
|
---|
| 245 | int b2 = Qkl + Rij;
|
---|
| 246 |
|
---|
| 247 | #if 0
|
---|
| 248 | ExEnv::outn() << scprintf("int_erep_4bound_1der(%d,%d,%d,%d): Q: %4d %4d R: %4d %4d\n",
|
---|
| 249 | s1,s2,s3,s4,
|
---|
| 250 | int_Qvec[ij],int_Qvec[kl],int_Rvec[ij],int_Rvec[kl]);
|
---|
| 251 | #endif
|
---|
| 252 |
|
---|
| 253 | /* The actual bound is Qij Rkl + Qkl Rij
|
---|
| 254 | * but since I'm using log base 2 I'll use
|
---|
| 255 | * 2 * max (Qij Rkl, Qkl Rij) -> 1 + max (Qij + Rkl, Qkl + Rij)
|
---|
| 256 | */
|
---|
| 257 |
|
---|
| 258 | return 1 + ((b1>b2)? b1 : b2 );
|
---|
| 259 | }
|
---|
| 260 |
|
---|
| 261 | /* ripped off from clj's libintv2 */
|
---|
| 262 | /* (add subsequently ripped back on from ets's libdmtscf) */
|
---|
| 263 |
|
---|
| 264 | /* Compute the partial bound arrays, either Q or R can be computed
|
---|
| 265 | * with appropiate choice of flag. */
|
---|
| 266 | void
|
---|
| 267 | Int2eV3::compute_bounds(int_bound_t *overall, int_bound_t *vec, int flag)
|
---|
| 268 | {
|
---|
| 269 | int sh1,sh2;
|
---|
| 270 |
|
---|
| 271 | if ((bs1_ != bs2_)&&(bs1_ != bs3_)&&(bs1_ != bs4_)) {
|
---|
| 272 | ExEnv::errn() << scprintf("bounds.compute_bounds: all centers must be the same")
|
---|
| 273 | << endl;
|
---|
| 274 | exit(1);
|
---|
| 275 | }
|
---|
| 276 |
|
---|
| 277 | int nshell=bs1_->nshell();
|
---|
| 278 | int nsht=(nshell*(nshell+1))/2;
|
---|
| 279 |
|
---|
| 280 | int me = grp_->me();
|
---|
| 281 | int n = grp_->n();
|
---|
| 282 |
|
---|
| 283 | for (int i=0; i<nsht; i++) vec[i] = 0;
|
---|
| 284 |
|
---|
| 285 | *overall = int_bound_min;
|
---|
| 286 | int sh12 = 0;
|
---|
| 287 | for(sh1=0; sh1 < bs1_->nshell() ; sh1++) {
|
---|
| 288 | for(sh2=0; sh2 <= sh1 ; sh2++,sh12++) {
|
---|
| 289 | if (sh12%n == me) compute_bounds_shell(overall,vec,flag,sh1,sh2);
|
---|
| 290 | }
|
---|
| 291 | }
|
---|
| 292 |
|
---|
| 293 | grp_->sum(vec,nsht);
|
---|
| 294 | grp_->max(overall,1);
|
---|
| 295 | }
|
---|
| 296 |
|
---|
| 297 | /* Compute the partial bound arrays, either Q or R can be computed
|
---|
| 298 | * with appropiate choice of flag. */
|
---|
| 299 | void
|
---|
| 300 | Int2eV3::compute_bounds_shell(int_bound_t *overall, int_bound_t *vec,
|
---|
| 301 | int flag, int sh1, int sh2)
|
---|
| 302 | {
|
---|
| 303 | int nint;
|
---|
| 304 | int shellij;
|
---|
| 305 | int shells[4],size[4];
|
---|
| 306 | double max;
|
---|
| 307 | double tol = pow(2.0,double(int_bound_min));
|
---|
| 308 | double loginv = 1.0/log(2.0);
|
---|
| 309 | int old_int_integral_storage = int_integral_storage;
|
---|
| 310 | int_integral_storage = 0;
|
---|
| 311 |
|
---|
| 312 | int old_perm = permute();
|
---|
| 313 | set_permute(0);
|
---|
| 314 | int old_red = redundant();
|
---|
| 315 | set_redundant(1);
|
---|
| 316 |
|
---|
| 317 | if ((bs1_ != bs2_)&&(bs1_ != bs3_)&&(bs1_ != bs4_)) {
|
---|
| 318 | ExEnv::errn() << scprintf("bounds.compute_bounds: all centers must be the same")
|
---|
| 319 | << endl;
|
---|
| 320 | exit(1);
|
---|
| 321 | }
|
---|
| 322 |
|
---|
| 323 | if (sh1<sh2) {
|
---|
| 324 | int tmp = sh1;
|
---|
| 325 | sh1 = sh2;
|
---|
| 326 | sh2 = tmp;
|
---|
| 327 | }
|
---|
| 328 |
|
---|
| 329 | shellij= ((sh1*(sh1+1))>>1) + sh2;
|
---|
| 330 | shells[0]=shells[2]=sh1;
|
---|
| 331 | shells[1]=shells[3]=sh2;
|
---|
| 332 |
|
---|
| 333 | if (flag == COMPUTE_Q) {
|
---|
| 334 | erep(shells,size);
|
---|
| 335 | nint = size[0]*size[1]*size[0]*size[1];
|
---|
| 336 | max = find_max(int_buffer,nint);
|
---|
| 337 | #if 0
|
---|
| 338 | ExEnv::outn() << scprintf("max for %d %d (size %d) is %15.11f\n", sh1, sh2, nint, max);
|
---|
| 339 | #endif
|
---|
| 340 | }
|
---|
| 341 | else if (flag == COMPUTE_R) {
|
---|
| 342 | double max1,max2;
|
---|
| 343 | int_erep_bound1der(0,sh1,sh2,&nint);
|
---|
| 344 | max1 = find_max(int_buffer,nint);
|
---|
| 345 | #if 0
|
---|
| 346 | ExEnv::outn() << scprintf("bound(%d) for (%d,%d) is %12.8f int_buffer =",
|
---|
| 347 | flag,sh1,sh2,max1);
|
---|
| 348 | for (i=0; (i<nint)&&(i<27); i++)
|
---|
| 349 | ExEnv::outn() << scprintf(" %12.8f",int_buffer[i]);
|
---|
| 350 | if (nint > 27) ExEnv::outn() << scprintf(" ...");
|
---|
| 351 | ExEnv::outn() << scprintf("\n");
|
---|
| 352 | #endif
|
---|
| 353 | int_erep_bound1der(0,sh2,sh1,&nint);
|
---|
| 354 | max2 = find_max(int_buffer,nint);
|
---|
| 355 | max = (max1>max2)?max1:max2;
|
---|
| 356 | }
|
---|
| 357 | else {
|
---|
| 358 | ExEnv::outn() << scprintf("bad bound flag\n"); exit(1);
|
---|
| 359 | }
|
---|
| 360 |
|
---|
| 361 | /* Compute the partial bound value. */
|
---|
| 362 | max = sqrt(max);
|
---|
| 363 | if (max>tol) {
|
---|
| 364 | vec[shellij] = (int_bound_t) ceil(log(max)*loginv);
|
---|
| 365 | }
|
---|
| 366 | else {
|
---|
| 367 | vec[shellij] = (int_bound_t) int_bound_min;
|
---|
| 368 | }
|
---|
| 369 |
|
---|
| 370 | /* Multiply R contributions by a factor of two to account for
|
---|
| 371 | * fact that contributions from both centers must be accounted
|
---|
| 372 | * for. */
|
---|
| 373 | if (flag == COMPUTE_R) vec[shellij]++;
|
---|
| 374 | if (vec[shellij]>*overall) *overall = vec[shellij];
|
---|
| 375 | #if 0
|
---|
| 376 | ExEnv::outn() << scprintf("bound(%d) for (%d,%d) is %4d int_buffer =",
|
---|
| 377 | flag,sh1,sh2,vec[shellij]);
|
---|
| 378 | for (i=0; (i<nint)&&(i<27); i++) ExEnv::outn() << scprintf(" %12.8f",int_buffer[i]);
|
---|
| 379 | if (nint > 27) ExEnv::outn() << scprintf(" ...");
|
---|
| 380 | ExEnv::outn() << scprintf("\n");
|
---|
| 381 | #endif
|
---|
| 382 | int_integral_storage = old_int_integral_storage;
|
---|
| 383 |
|
---|
| 384 | set_permute(old_perm);
|
---|
| 385 | set_redundant(old_red);
|
---|
| 386 |
|
---|
| 387 | }
|
---|
| 388 |
|
---|
| 389 | /* This function is used to convert a double to its log base 2 rep
|
---|
| 390 | * for use in bound computations. */
|
---|
| 391 | int
|
---|
| 392 | Int2eV3::bound_to_logbound(double value)
|
---|
| 393 | {
|
---|
| 394 | double tol = pow(2.0,double(int_bound_min));
|
---|
| 395 | double loginv = 1.0/log(2.0);
|
---|
| 396 | int_bound_t res;
|
---|
| 397 |
|
---|
| 398 | if (value > tol) res = (int_bound_t) ceil(log(value)*loginv);
|
---|
| 399 | else res = int_bound_min;
|
---|
| 400 | return res;
|
---|
| 401 | }
|
---|
| 402 |
|
---|
| 403 | /* This function is used to convert a double from its log base 2 rep. */
|
---|
| 404 | double
|
---|
| 405 | Int2eV3::logbound_to_bound(int value)
|
---|
| 406 | {
|
---|
| 407 | return pow(2.0,(double)value);
|
---|
| 408 | }
|
---|
| 409 |
|
---|
| 410 | /////////////////////////////////////////////////////////////////////////////
|
---|
| 411 |
|
---|
| 412 | // Local Variables:
|
---|
| 413 | // mode: c++
|
---|
| 414 | // c-file-style: "CLJ-CONDENSED"
|
---|
| 415 | // End:
|
---|