00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include "QMCElectronNucleusCuspParameters.h"
00014
00015 QMCElectronNucleusCuspParameters::QMCElectronNucleusCuspParameters()
00016 {
00017 rc = -2.0;
00018 sgn0 = -2;
00019 sigma_sq = -1.0;
00020 Zeff = -1.0;
00021 Z = -1;
00022 C = 0.0;
00023 noC = true;
00024 }
00025
00026 void QMCElectronNucleusCuspParameters::operator=(const QMCElectronNucleusCuspParameters& rhs)
00027 {
00028 rc = rhs.rc;
00029 alpha = rhs.alpha;
00030 idealCurve = rhs.idealCurve;
00031 orbitalCoefficients = rhs.orbitalCoefficients;
00032
00033 C = rhs.C;
00034 noC = rhs.noC;
00035
00036 sgn0 = rhs.sgn0;
00037 sigma_sq = rhs.sigma_sq;
00038
00039 phi0 = rhs.phi0;
00040 n0 = rhs.n0;
00041
00042 Z = rhs.Z;
00043 Zeff = rhs.Zeff;
00044 }
00045
00046 void QMCElectronNucleusCuspParameters::initialize
00047 (const Array2D<qmcfloat>& temp_OrbitalCoefficients, double temp_n0,
00048 double temp_rc, const Polynomial& temp_idealCurve, int temp_Z)
00049 {
00050 orbitalCoefficients = temp_OrbitalCoefficients;
00051 idealCurve = temp_idealCurve;
00052
00053 if (temp_Z > 0)
00054 Z = temp_Z;
00055 else
00056 {
00057 cerr << "ERROR in QMCElectronNucleusCuspParameters: temp_Z = " << temp_Z;
00058 cerr << endl;
00059 exit(0);
00060 }
00061
00062 n0 = temp_n0;
00063
00064 if (temp_rc > 0)
00065 rc = temp_rc;
00066 else
00067 {
00068 cerr << "ERROR in QMCElectronNucleusCuspParameters: temp_rc = ";
00069 cerr << temp_rc << endl;
00070 exit(0);
00071 }
00072 }
00073
00074 double QMCElectronNucleusCuspParameters::get_rc()
00075 {
00076 if (rc < 0.0)
00077 {
00078 cerr << "ERROR in QMCElectronNucleusCuspParameters: rc = " << rc << endl;
00079 exit(0);
00080 }
00081 return rc;
00082 }
00083
00084 double QMCElectronNucleusCuspParameters::getSigmaSq()
00085 {
00086 if (sigma_sq < 0)
00087 {
00088 cerr << "ERROR in QMCElectronNucleusCuspParameters: sigma_sq = ";
00089 cerr << sigma_sq << endl;
00090 exit(0);
00091 }
00092 return sigma_sq;
00093 }
00094
00095 void QMCElectronNucleusCuspParameters::set_rc(double temp_rc)
00096 {
00097 if (temp_rc >= 0.0)
00098 rc = temp_rc;
00099 else
00100 {
00101 cerr << "ERROR in QMCElectronNucleusCuspParameters: temp_rc = ";
00102 cerr << temp_rc << endl;
00103 exit(0);
00104 }
00105 }
00106
00107 void QMCElectronNucleusCuspParameters::replaceOrbitalValues(double x, double y,
00108 double z, double r, double& orb_value, double& orb_gradx, double& orb_grady,
00109 double& orb_gradz, double& orb_laplacian)
00110 {
00111 if (r > rc)
00112 {
00113
00114 }
00115
00116 else if (r < rc)
00117 {
00118
00119
00120
00121 double temp_value;
00122 double temp_gradx;
00123 double temp_grady;
00124 double temp_gradz;
00125 double temp_laplacian;
00126
00127 evaluateOriginalOrbital(x,y,z,r,temp_value,temp_gradx,temp_grady,
00128 temp_gradz,temp_laplacian);
00129
00130
00131
00132
00133 orb_value -= temp_value;
00134 orb_gradx -= temp_gradx;
00135 orb_grady -= temp_grady;
00136 orb_gradz -= temp_gradz;
00137 orb_laplacian -= temp_laplacian;
00138
00139 evaluateReplacementOrbital(x,y,z,r,temp_value,temp_gradx,temp_grady,
00140 temp_gradz,temp_laplacian);
00141
00142 orb_value += temp_value;
00143 orb_gradx += temp_gradx;
00144 orb_grady += temp_grady;
00145 orb_gradz += temp_gradz;
00146 orb_laplacian += temp_laplacian;
00147 }
00148 }
00149
00150 void QMCElectronNucleusCuspParameters::replaceOrbitalValues(double x, double y,
00151 double z, double r, double& orb_value)
00152 {
00153 if (r > rc)
00154 {
00155
00156 }
00157
00158 else if (r < rc)
00159 {
00160
00161
00162
00163 double temp_value;
00164
00165 evaluateOriginalOrbital(x,y,z,r,temp_value);
00166
00167
00168
00169
00170 orb_value -= temp_value;
00171
00172 evaluateReplacementOrbital(x,y,z,r,temp_value);
00173
00174 orb_value += temp_value;
00175 }
00176 }
00177
00178 void QMCElectronNucleusCuspParameters::evaluateOriginalOrbital(double x,
00179 double y, double z, double r, double& orig_value, double& orig_gradx,
00180 double& orig_grady, double& orig_gradz, double& orig_laplacian)
00181 {
00182
00183
00184
00185
00186 double r_sq = r*r;
00187
00188 int nGaussians = orbitalCoefficients.dim1();
00189
00190 double term_value = 0.0;
00191 double p0 = 0.0;
00192 double p1 = 0.0;
00193 double temp = 0.0;
00194
00195 orig_value = 0.0;
00196 orig_gradx = 0.0;
00197 orig_grady = 0.0;
00198 orig_gradz = 0.0;
00199 orig_laplacian = 0.0;
00200
00201 for (int i=0; i<nGaussians; i++)
00202 {
00203 p0 = orbitalCoefficients(i,0);
00204 p1 = orbitalCoefficients(i,1);
00205 term_value = p1*exp(-p0*r_sq);
00206
00207 orig_value += term_value;
00208
00209 temp = -2*p0*term_value;
00210
00211 orig_gradx += x*temp;
00212 orig_grady += y*temp;
00213 orig_gradz += z*temp;
00214
00215 orig_laplacian += 2*p0*(2*p0*r_sq-3)*term_value;
00216 }
00217 }
00218
00219 void QMCElectronNucleusCuspParameters::evaluateOriginalOrbital(double x,
00220 double y, double z, double r, double& orig_value)
00221 {
00222
00223
00224
00225
00226 double r_sq = r*r;
00227
00228 int nGaussians = orbitalCoefficients.dim1();
00229
00230 double term_value = 0.0;
00231 double p0 = 0.0;
00232 double p1 = 0.0;
00233
00234 orig_value = 0.0;
00235
00236 for (int i=0; i<nGaussians; i++)
00237 {
00238 p0 = orbitalCoefficients(i,0);
00239 p1 = orbitalCoefficients(i,1);
00240 term_value = p1*exp(-p0*r_sq);
00241
00242 orig_value += term_value;
00243 }
00244 }
00245
00246 void QMCElectronNucleusCuspParameters::evaluateReplacementOrbital(double x,
00247 double y, double z, double r, double& rep_value, double& rep_gradx,
00248 double& rep_grady, double& rep_gradz, double& rep_laplacian)
00249 {
00250
00251
00252
00253 double exp_value = 0.0;
00254 double temp_gradient = 0.0;
00255
00256 alpha.evaluate(r);
00257
00258 exp_value = sgn0*exp(alpha.getFunctionValue());
00259
00260 rep_value = C + exp_value;
00261
00262 temp_gradient = (exp_value*alpha.getFirstDerivativeValue())/r;
00263
00264 rep_gradx = temp_gradient*x;
00265 rep_grady = temp_gradient*y;
00266 rep_gradz = temp_gradient*z;
00267
00268 rep_laplacian = exp_value*(alpha.getSecondDerivativeValue() +
00269 alpha.getFirstDerivativeValue()*(2.0/r+alpha.getFirstDerivativeValue()));
00270 }
00271
00272 void QMCElectronNucleusCuspParameters::evaluateReplacementOrbital(double x,
00273 double y, double z, double r, double& rep_value)
00274 {
00275
00276
00277
00278 double exp_value = 0.0;
00279
00280 alpha.evaluate(r);
00281
00282 exp_value = sgn0*exp(alpha.getFunctionValue());
00283
00284 rep_value = C + exp_value;
00285 }
00286
00287 double QMCElectronNucleusCuspParameters::calculateLocalEnergy(double r,
00288 bool rIsZero)
00289 {
00290 if (rIsZero == true)
00291 {
00292 alpha.evaluate(0.0);
00293 if (noC == true)
00294 return -0.5*(alpha.getSecondDerivativeValue() +
00295 alpha.getFirstDerivativeValue()*alpha.getFirstDerivativeValue());
00296 else
00297 {
00298 double exp_value = sgn0*exp(alpha.getFunctionValue());
00299 return (-0.5*exp_value/(C+exp_value))*
00300 (alpha.getSecondDerivativeValue() +
00301 alpha.getFirstDerivativeValue()*alpha.getFirstDerivativeValue());
00302 }
00303 }
00304
00305 else
00306 {
00307 if (r < 0)
00308 {
00309 cerr << "ERROR in ";
00310 cerr << "QMCElectronNucleusCuspParameters::calculateLocalEnergy: ";
00311 cerr << "r = " << r << endl;
00312 exit(0);
00313 }
00314
00315 alpha.evaluate(r);
00316
00317 double localKE = -0.5*(alpha.getSecondDerivativeValue() +
00318 alpha.getFirstDerivativeValue()*(2.0/r+alpha.getFirstDerivativeValue()));
00319
00320 if (noC == true)
00321 return localKE - Zeff/r;
00322
00323 else
00324 {
00325 double exp_value = sgn0*exp(alpha.getFunctionValue());
00326 return localKE*exp_value/(C+exp_value) - Zeff/r;
00327 }
00328 }
00329 }
00330
00331 void QMCElectronNucleusCuspParameters::fitReplacementOrbital(double temp_phi0)
00332 {
00333
00334
00335
00336 phi0 = temp_phi0;
00337
00338 double rc_sq = rc*rc;
00339
00340 int nGaussians = orbitalCoefficients.dim1();
00341
00342 double term_value = 0.0;
00343 double orig_value = 0.0;
00344 double orig_firstDerivative = 0.0;
00345 double orig_secondDerivative = 0.0;
00346
00347 double p0,p1;
00348
00349 for (int i=0; i<nGaussians; i++)
00350 {
00351 p0 = orbitalCoefficients(i,0);
00352 p1 = orbitalCoefficients(i,1);
00353 term_value = p1*exp(-p0*rc_sq);
00354
00355 orig_value += term_value;
00356
00357 orig_firstDerivative += -2*p0*rc*term_value;
00358
00359 orig_secondDerivative += 2*p0*(2*p0*rc_sq-1)*term_value;
00360 }
00361
00362
00363 if (phi0-orig_value > 0)
00364 sgn0 = 1;
00365 else
00366 sgn0 = -1;
00367
00368
00369 noC = true;
00370 C = 0.0;
00371 if (orig_value*phi0 < 0)
00372 {
00373 noC = false;
00374 if (orig_value > 0.0 && orig_value < 0.1)
00375 C = orig_value + 0.1;
00376 else if (orig_value < 0.0 && orig_value > -0.1)
00377 C = orig_value - 0.1;
00378 else
00379 C = 2*orig_value;
00380 }
00381 else
00382 {
00383
00384
00385
00386
00387
00388
00389 if (orig_value > 0.0 && orig_value < 0.1)
00390 {
00391 noC = false;
00392 C = orig_value - 0.1;
00393 }
00394 else if (orig_value < 0.0 && orig_value > -0.1)
00395 {
00396 noC = false;
00397 C = orig_value + 0.1;
00398 }
00399 }
00400
00401 if (sgn0 == 1 && phi0 < 0.0)
00402 {
00403 noC = false;
00404 if (orig_value > -0.1)
00405 C = orig_value - 0.1;
00406 else
00407 C = 2*orig_value;
00408 }
00409 else if (sgn0 == -1 && phi0 > 0.0)
00410 {
00411 noC = false;
00412 if (orig_value < 0.1)
00413 C = orig_value + 0.1;
00414 else
00415 C = 2*orig_value;
00416 }
00417
00418
00419 Zeff = Z*fabs(1+(n0/phi0));
00420
00421
00422 double x1 = log(fabs(orig_value-C));
00423
00424
00425 double x2 = orig_firstDerivative/(orig_value-C);
00426
00427
00428 double x3 = orig_secondDerivative/(orig_value-C);
00429
00430
00431
00432 double x4;
00433
00434 if (n0/phi0 >= -1.0)
00435 x4 = -Z*(phi0+n0)/(phi0-C);
00436 else
00437 x4 = Z*(phi0+n0)/(phi0-C);
00438
00439
00440
00441 if ( (sgn0 == 1 && phi0<0.0) || (sgn0 == -1 && phi0>0.0) )
00442 x4 *= -1;
00443
00444
00445 double x5 = log(fabs(phi0-C));
00446
00447 Array1D<double> temp_cs;
00448 temp_cs.allocate(5);
00449
00450 double rc_inv = 1/rc;
00451
00452 temp_cs(0) = x5;
00453 temp_cs(1) = x4;
00454 temp_cs(2) = (6*(x1-x5)*rc_inv-3*(x2+x4))*rc_inv+0.5*(x3-x2*x2);
00455 temp_cs(3) = ((8*(x5-x1)*rc_inv+5*x2+3*x4)*rc_inv+x2*x2-x3)*rc_inv;
00456 temp_cs(4) =((3*(x1-x5)*rc_inv-2*x2-x4)*rc_inv+0.5*(x3-x2*x2))*rc_inv*rc_inv;
00457
00458 alpha.initialize(temp_cs);
00459
00460 temp_cs.deallocate();
00461
00462 calculateSigmaSq();
00463 }
00464
00465 void QMCElectronNucleusCuspParameters::calculateSigmaSq()
00466 {
00467
00468
00469
00470 if (noC == true)
00471
00472
00473
00474
00475 findMaxDeviation(0.0,rc,true,sigma_sq);
00476
00477 else
00478 {
00479
00480
00481
00482
00483
00484
00485
00486
00487 Array1D<double> temp_coeffs;
00488 temp_coeffs = alpha.getCoefficients();
00489 temp_coeffs(0) -= log(fabs(C));
00490
00491 Polynomial temp_poly;
00492 temp_poly.initialize(temp_coeffs);
00493
00494 Array1D<Complex> roots = temp_poly.getRoots();
00495
00496 double root = -2;
00497 const double tol = 1e-8;
00498 for (int i=0; i<roots.dim1(); i++)
00499 {
00500 double re = roots(i).real();
00501 double im = roots(i).imaginary();
00502
00503 if (re > 0 && re < rc && fabs(im) < tol)
00504 {
00505 root = re;
00506 break;
00507 }
00508 }
00509
00510 if (root < 0)
00511 findMaxDeviation(0.0,rc,true,sigma_sq);
00512
00513 else
00514 {
00515 double max1 = 0.0;
00516 double max2 = 0.0;
00517
00518 if (root-rc/5 > 0.0)
00519 findMaxDeviation(0.0,root-rc/5,true,max1);
00520
00521 if (root+rc/5 < rc)
00522 findMaxDeviation(root+rc/5,rc,false,max2);
00523
00524 sigma_sq = max1 > max2 ? max1 : max2;
00525 }
00526 }
00527 }
00528
00529 void QMCElectronNucleusCuspParameters::findMaxDeviation(double lower,
00530 double upper, bool lowerBoundZero, double& max)
00531 {
00532 #define GOLD 0.61803399
00533
00534
00535
00536
00537 double lowR = lower;
00538 double repEnergy = calculateLocalEnergy(lowR,lowerBoundZero);
00539 idealCurve.evaluate(lowR);
00540 double idealEnergy = Z*Z*idealCurve.getFunctionValue();
00541 double lowValue = (repEnergy-idealEnergy)*(repEnergy-idealEnergy);
00542
00543 double highR = upper;
00544 repEnergy = calculateLocalEnergy(highR,false);
00545 idealCurve.evaluate(highR);
00546 idealEnergy = Z*Z*idealCurve.getFunctionValue();
00547 double highValue = (repEnergy-idealEnergy)*(repEnergy-idealEnergy);
00548
00549 double midR = GOLD*(upper-lower)+lower;
00550 repEnergy = calculateLocalEnergy(midR,false);
00551 idealCurve.evaluate(midR);
00552 idealEnergy = Z*Z*idealCurve.getFunctionValue();
00553 double midValue = (repEnergy-idealEnergy)*(repEnergy-idealEnergy);
00554
00555 while (highR-lowR > 1e-4)
00556 {
00557 if (highValue > lowValue)
00558 {
00559 lowR = midR;
00560 lowValue = midValue;
00561 if (highValue > midValue)
00562 midR = lowR+GOLD*(highR-lowR);
00563 else if (highValue <= midValue)
00564 midR = highR-GOLD*(highR-lowR);
00565 }
00566 else if (highValue < lowValue)
00567 {
00568 highR = midR;
00569 highValue = midValue;
00570 if (lowValue > midValue)
00571 midR = highR-GOLD*(highR-lowR);
00572 else if (lowValue <= midValue)
00573 midR = lowR+GOLD*(highR-lowR);
00574 }
00575 repEnergy = calculateLocalEnergy(midR,false);
00576 idealCurve.evaluate(midR);
00577 idealEnergy = Z*Z*idealCurve.getFunctionValue();
00578 midValue = (repEnergy-idealEnergy)*(repEnergy-idealEnergy);
00579 }
00580
00581 if (highValue > midValue)
00582 max = highValue > lowValue ? highValue : lowValue;
00583 else if (midValue >= highValue)
00584 max = midValue > lowValue ? midValue : lowValue;
00585
00586 #undef GOLD
00587 }
00588
00589 void QMCElectronNucleusCuspParameters::printParameters()
00590 {
00591 cout << "***ElectronNucleusCuspParameters***" << endl;
00592 cout << "rc = " << rc << endl;
00593
00594 Array1D<double> temp_coeffs;
00595 temp_coeffs = alpha.getCoefficients();
00596 cout << "alpha coefficients:" << endl;
00597 for (int i=0; i<temp_coeffs.dim1(); i++)
00598 cout << "\t" << temp_coeffs(i);
00599 cout << endl;
00600
00601 temp_coeffs = idealCurve.getCoefficients();
00602 cout << "ideal curve coefficients:" << endl;
00603 for (int i=0; i<temp_coeffs.dim1(); i++)
00604 cout << "\t" << temp_coeffs(i);
00605 cout << endl;
00606
00607 cout << "n0 = " << n0 << endl;
00608 cout << "C = " << C << endl;
00609 cout << "sgn0 = " << sgn0 << endl;
00610 cout << "sigmaSq = " << sigma_sq << endl;
00611 cout << "phi0 = " << phi0 << endl;
00612 cout << "Z = " << Z << endl;
00613 cout << "Zeff = " << Zeff << endl;
00614 cout << "Orbital coefficients:" << endl;
00615 for (int i=0; i<orbitalCoefficients.dim1(); i++)
00616 {
00617 cout << "\t" << orbitalCoefficients(i,0) << "\t";
00618 cout << orbitalCoefficients(i,1) << endl;
00619 }
00620 cout << "The local energy of the replacement orbital at rc = ";
00621 cout << calculateLocalEnergy(rc,false) << endl;
00622 idealCurve.evaluate(rc);
00623 cout << "The ideal local energy at rc = ";
00624 cout << Z*Z*idealCurve.getFunctionValue() << endl;
00625
00626 double ovalue,ogradx,ogrady,ogradz,olap,ox,oy,oz,nor;
00627
00628 ovalue = 0.0;
00629 ogradx = 0.0;
00630 ogrady = 0.0;
00631 ogradz = 0.0;
00632 olap = 0.0;
00633
00634 ox = rc;
00635 oy = 0.0;
00636 oz = 0.0;
00637 nor = rc;
00638
00639 evaluateOriginalOrbital(ox,oy,oz,nor,ovalue,ogradx,ogrady,ogradz,olap);
00640 cout << "Original orbital value at rc = " << ovalue << endl;
00641 cout << "Original gradient at rc = " << ogradx << endl;
00642 cout << "Original laplacian at rc = " << olap << endl;
00643
00644 ovalue = 0.0;
00645 ogradx = 0.0;
00646 ogrady = 0.0;
00647 ogradz = 0.0;
00648 olap = 0.0;
00649
00650 evaluateReplacementOrbital(ox,oy,oz,nor,ovalue,ogradx,ogrady,ogradz,olap);
00651 cout << "Replacement orbital value at rc = " << ovalue << endl;
00652 cout << "Replacement gradient at rc = " << ogradx << endl;
00653 cout << "Replacement laplacian at rc = " << olap << endl;
00654 cout << endl << endl;
00655 }
00656
00657 ostream& operator <<(ostream& strm, QMCElectronNucleusCuspParameters &rhs)
00658 {
00659
00660
00661 return strm;
00662 }
00663