MADNESS  version 0.9
correlationfactor.h
Go to the documentation of this file.
1 /*
2  This file is part of MADNESS.
3 
4  Copyright (C) 2007,2010 Oak Ridge National Laboratory
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program; if not, write to the Free Software
18  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 
20  For more information please contact:
21 
22  Robert J. Harrison
23  Oak Ridge National Laboratory
24  One Bethel Valley Road
25  P.O. Box 2008, MS-6367
26 
27  email: harrisonrj@ornl.gov
28  tel: 865-241-3937
29  fax: 865-572-0680
30 
31  $Id$
32 */
33 
34 //#define WORLD_INSTANTIATE_STATIC_TEMPLATES
35 
36 
83 #ifndef MADNESS_CHEM_NUCLEARCORRELATIONFACTOR_H__INCLUDED
84 #define MADNESS_CHEM_NUCLEARCORRELATIONFACTOR_H__INCLUDED
85 
86 
87 #include <madness/mra/mra.h>
88 #include <madness/mra/lbdeux.h>
89 #include <chem/molecule.h>
90 #include <chem/potentialmanager.h>
91 
92 namespace madness {
93 class SCF;
94 
96 class NuclearCorrelationFactor {
97 public:
98  enum corrfactype {None, GaussSlater, LinearSlater, Polynomial,
99  Slater, Two};
101 
103 
106  NuclearCorrelationFactor(World& world, const Molecule& mol)
107  : world(world), vtol(FunctionDefaults<3>::get_thresh()*0.1)
108  , molecule(mol) {}
109 
111  void initialize() {
112 
113  // construct the potential functions
114  // keep tighter threshold for orthogonalization
115  for (int axis=0; axis<3; ++axis) {
116  functorT U1f=functorT(new U1_functor(this,axis));
117  U1_function.push_back(real_factory_3d(world).thresh(vtol)
118  .functor(U1f).truncate_on_project());
119  U1_function.back().set_thresh(FunctionDefaults<3>::get_thresh());
120  }
121 
122  // U2 is the term -S"/S - Z/r
123  functorT U2f=functorT(new U2_functor(this));
124  U2_function=real_factory_3d(world).thresh(vtol)
125  .functor(U2f).truncate_on_project();
126  U2_function.set_thresh(FunctionDefaults<3>::get_thresh());
127 
128  // U3 is the term SA'/SA . SB'/SB
129  functorT U3f=functorT(new U3_functor(this));
130  real_function_3d tmp=real_factory_3d(world).thresh(vtol)
131  .functor(U3f).truncate_on_project();
132  tmp.set_thresh(FunctionDefaults<3>::get_thresh());
133  U2_function+=tmp;
134  U2_function.truncate();
135  }
136 
137  virtual corrfactype type() const = 0;
138 
140  virtual real_function_3d apply_U(const real_function_3d& rhs) const {
141 
142  // the purely local part
143  real_function_3d result=(U2()*rhs).truncate();
144 
145  // the part with the derivative operators
146  result.compress();
147  for (int axis=0; axis<3; ++axis) {
148  real_derivative_3d D = free_space_derivative<double,3>(world, axis);
149  const real_function_3d Drhs=D(rhs).truncate();
150  result+=U1(axis)*Drhs;
151  }
152 
153  result.truncate();
154  return result;
155  }
156 
158  virtual real_function_3d function() const {
159  functorT Rf=functorT(new R_functor(this,1));
160  real_function_3d r=real_factory_3d(world).thresh(vtol)
161  .functor(Rf).truncate_on_project();
162  return r;
163  }
164 
166  virtual real_function_3d square() const {
167  real_function_3d R2=real_factory_3d(world).thresh(vtol)
168  .functor2(R_functor(this,2)).truncate_on_project();
169  return R2;
170  }
171 
173  virtual real_function_3d inverse() const {
174  real_function_3d R_inverse=real_factory_3d(world).thresh(vtol)
175  .functor2(R_functor(this,-1)).truncate_on_project();
176  return R_inverse;
177  }
178 
180  virtual real_function_3d U1(const int axis) const {
181  return U1_function[axis];
182  }
183 
185  virtual real_function_3d U2() const {return U2_function;}
186 
187 private:
188 
190  World& world;
191 
193  double vtol;
194 
196  const Molecule& molecule;
197 
199  std::vector<real_function_3d> U1_function;
200 
202  real_function_3d U2_function;
203 
205 
209  virtual double S(const double& r, const double& Z) const = 0;
210 
212 
216  virtual coord_3d Sp(const coord_3d& vr1A, const double& Z) const = 0;
217 
219 
225  virtual double Spp_div_S(const double& r, const double& Z) const = 0;
226 
227  class R_functor : public FunctionFunctorInterface<double,3> {
228  const NuclearCorrelationFactor* ncf;
229  int exponent;
230  public:
231  R_functor(const NuclearCorrelationFactor* ncf, const int e=1)
232  : ncf(ncf), exponent(e) {}
233  double operator()(const coord_3d& xyz) const {
234  double result=1.0;
235  for (int i=0; i<ncf->molecule.natom(); ++i) {
236  const Atom& atom=ncf->molecule.get_atom(i);
237  const coord_3d vr1A=xyz-atom.get_coords();
238  const double r=vr1A.normf();
239  result*=ncf->S(r,atom.q);
240  }
241  if (exponent==-1) return 1.0/result;
242  else if (exponent==2) return result*result;
243  else if (exponent==1) return result;
244  else {
245  return std::pow(result,double(exponent));
246  }
247 
248  }
249  std::vector<coord_3d> special_points() const {
250  return ncf->molecule.get_all_coords_vec();
251  }
252  };
253 
255 
257  class U1_functor : public FunctionFunctorInterface<double,3> {
258 
259  const NuclearCorrelationFactor* ncf;
260  const int axis;
261 
262  public:
263  U1_functor(const NuclearCorrelationFactor* ncf, const int axis)
264  : ncf(ncf), axis(axis) {}
265 
266  double operator()(const coord_3d& xyz) const {
267  double result=0.0;
268  for (int i=0; i<ncf->molecule.natom(); ++i) {
269  const Atom& atom=ncf->molecule.get_atom(i);
270  const coord_3d vr1A=xyz-atom.get_coords();
271  const double r=vr1A.normf();
272  result+=(ncf->Sp(vr1A,atom.q)[axis]/ncf->S(r,atom.q));
273  }
274  return -1.0*result;
275  }
276  std::vector<coord_3d> special_points() const {
277  return ncf->molecule.get_all_coords_vec();
278  }
279  };
280 
281  class U2_functor : public FunctionFunctorInterface<double,3> {
282  const NuclearCorrelationFactor* ncf;
283  public:
284  U2_functor(const NuclearCorrelationFactor* ncf) : ncf(ncf) {}
285  double operator()(const coord_3d& xyz) const {
286  double result=0.0;
287  for (int i=0; i<ncf->molecule.natom(); ++i) {
288  const Atom& atom=ncf->molecule.get_atom(i);
289  const coord_3d vr1A=xyz-atom.get_coords();
290  const double r=vr1A.normf();
291  result+=ncf->Spp_div_S(r,atom.q);
292  }
293  return result;
294  }
295  std::vector<coord_3d> special_points() const {
296  return ncf->molecule.get_all_coords_vec();
297  }
298  };
299 
300  class U3_functor : public FunctionFunctorInterface<double,3> {
301  const NuclearCorrelationFactor* ncf;
302  public:
303  U3_functor(const NuclearCorrelationFactor* ncf) : ncf(ncf) {}
304  double operator()(const coord_3d& xyz) const {
305  std::vector<coord_3d> all_terms(ncf->molecule.natom());
306  for (int i=0; i<ncf->molecule.natom(); ++i) {
307  const Atom& atom=ncf->molecule.get_atom(i);
308  const coord_3d vr1A=xyz-atom.get_coords();
309  const double r=vr1A.normf();
310  all_terms[i]=ncf->Sp(vr1A,atom.q)*(1.0/ncf->S(r,atom.q));
311  }
312 
313  double result=0.0;
314  for (int i=0; i<ncf->molecule.natom(); ++i) {
315  for (int j=0; j<i; ++j) {
316  result+=all_terms[i][0]*all_terms[j][0]
317  +all_terms[i][1]*all_terms[j][1]
318  +all_terms[i][2]*all_terms[j][2];
319  }
320  }
321 
322  return -1.0*result;
323  }
324  std::vector<coord_3d> special_points() const {
325  return ncf->molecule.get_all_coords_vec();
326  }
327  };
328 
329 };
330 
332 
337 class GaussSlater : public NuclearCorrelationFactor {
338 public:
340 
343  GaussSlater(World& world, const Molecule& mol)
344  : NuclearCorrelationFactor(world,mol) {
345 
346  if (world.rank()==0) {
347  print("constructed nuclear correlation factor of the form");
348  print(" R = Prod_A S_A");
349  print(" S_A = exp(-Z_A r_{1A}) + (1 - exp(-Z_A^2*r_{1A}^2))");
350  print("which is of Gaussian-Slater type\n");
351  }
352 
353  initialize();
354  }
355 
356  corrfactype type() const {return NuclearCorrelationFactor::GaussSlater;}
357 
358 private:
359 
361  double S(const double& r, const double& Z) const {
362  const double rho=r*Z;
363  return exp(-rho)+(1.0-exp(-(rho*rho)));
364  }
365 
367  coord_3d Sp(const coord_3d& vr1A, const double& Z) const {
368 
369  const double r=sqrt(vr1A[0]*vr1A[0] +
370  vr1A[1]*vr1A[1] + vr1A[2]*vr1A[2]);
371 
372  const double eA=exp(-Z*r);
373  const double gA=exp(-Z*Z*r*r);
374  coord_3d term=(2.0*gA*Z*Z*vr1A-Z*eA*n12(vr1A,1.e-8));
375  return term;
376  }
377 
379 
381  double Spp_div_S(const double& r, const double& Z) const {
382  const double rho=Z*r;
383  if (rho<1.e-4) {
384  return Z*Z*(-3.5 - 4.0*rho + 6.0*rho*rho + 12.0*rho*rho*rho);
385  } else {
386  const double e=exp(-rho);
387  const double g=exp(-rho*rho);
388  const double term1=-Z/r*(1.0-g);
389  const double term2=-g*Z*Z*(3.0-2.0*Z*Z*r*r) - Z*Z/2.0*e;
390  const double S_inv=exp(-rho)+(1.0-exp(-(rho*rho)));
391  return (term1+term2)/S_inv;
392  }
393  }
394 
395 };
396 
397 
398 
400 
405 class LinearSlater : public NuclearCorrelationFactor {
406 public:
408 
411  LinearSlater(World& world, const Molecule& mol, const double a)
412  : NuclearCorrelationFactor(world,mol), a_(1.0) {
413 
414  if (a!=0.0) a_=a;
415 
416  if (world.rank()==0) {
417  print("constructed nuclear correlation factor of the form");
418  print(" S_A = -Z_A r_{1A} exp(-Z_A r_{1A}) + 1");
419  print(" a = ",a_);
420  print("which is of linear Slater type\n");
421  }
422  initialize();
423  }
424 
425  corrfactype type() const {return NuclearCorrelationFactor::LinearSlater;}
426 
427 private:
428 
430  double a_;
431 
432  double a_param() const {return 1.0;}
433 
435  double S(const double& r, const double& Z) const {
436  const double rho=r*Z;
437  const double b=a_param();
438  return (-rho)*exp(-b*rho)+1.0;
439  }
440 
442  coord_3d Sp(const coord_3d& vr1A, const double& Z) const {
443 
444  const double b=a_param();
445  const double r=sqrt(vr1A[0]*vr1A[0] +
446  vr1A[1]*vr1A[1] + vr1A[2]*vr1A[2]);
447 
448  const double ebrz=exp(-b*r*Z);
449  const coord_3d term=Z*ebrz*(b*Z*(vr1A) - n12(vr1A));
450  return term;
451  }
452 
454 
456  double Spp_div_S(const double& r, const double& Z) const {
457 
458  const double b=a_param();
459  const double rho=Z*r;
460  if (rho<1.e-4) {
461  const double O0=1.0- 3.0* b;
462  const double O1=Z - 4.0*b*Z + 3.0*b*b*Z;
463  const double O2=Z*Z - 5.0*b*Z*Z + 6.5*b*b*Z*Z - 5.0/3.0*b*b*b*Z*Z;
464  return Z*Z*(O0 + O1*r + O2*r*r);
465 
466  } else {
467  const double ebrz=exp(-b*rho);
468  const double num=Z* (ebrz - 1.0 + 0.5*ebrz*rho* (2.0 + b*(b*rho-4.0)));
469  const double denom=r*(rho*ebrz-1.0);
470  return -num/denom;
471  }
472  }
473 };
474 
475 
476 
478 class Slater : public NuclearCorrelationFactor {
479 public:
481 
484  Slater(World& world, const Molecule& mol, const double a)
485  : NuclearCorrelationFactor(world,mol), a_(1.5) {
486 
487  if (a!=0.0) a_=a;
488 
489  if (world.rank()==0) {
490  print("\nconstructed nuclear correlation factor of the form");
491  print(" S_A = 1/(a-1) exp(-a Z_A r_{1A}) + 1");
492  print(" a = ",a_);
493  print("which is of Slater type\n");
494  }
495  initialize();
496  }
497 
498  corrfactype type() const {return NuclearCorrelationFactor::Slater;}
499 
500 private:
501 
503  double a_;
504 
505  double a_param() const {return a_;}
506 
508  double S(const double& r, const double& Z) const {
509  const double a=a_param();
510  return 1.0+1.0/(a-1.0) * exp(-a*Z*r);
511  }
512 
514  coord_3d Sp(const coord_3d& vr1A, const double& Z) const {
515  const double a=a_param();
516  const double r=vr1A.normf();
517  return -(a*exp(-a*Z*r)*Z)/(a-1.0)*n12(vr1A);
518  }
519 
521  double Spp_div_S(const double& r, const double& Z) const {
522  const double a=a_param();
523 
524  if (r*Z<1.e-4) {
525  const double O0=1.0-(1.5*a);
526  const double O1=(a-1.0)*(a-1.0)*Z;
527  const double O2=(1.0/12.0 * (a-1.0)*(12.0+a*(5*a-18.0)))*Z*Z;
528  return Z*Z*(O0 + O1*r + O2*r*r);
529 
530  } else {
531  const double earz=exp(-a*r*Z);
532  const double num=Z*(-earz + a*earz - (a-1.0) - 0.5*a*a*r*Z*earz);
533  const double denom=(r*earz + (a-1.0) * r);
534  return num/denom;
535  }
536  }
537 
538 };
539 
541 
544 template<std::size_t N>
545 class Polynomial : public NuclearCorrelationFactor {
546 public:
548 
551  Polynomial(World& world, const Molecule& mol, const double a)
552  : NuclearCorrelationFactor(world,mol) {
553 
555  a_=(2. + (-2. + sqrt(-1. + N))*N)/(-2. + N);
556 
557  if (a!=0.0) a_=a;
558 
559  if (world.rank()==0) {
560  print("constructed nuclear correlation factor of the form");
561  print(" R = Prod_A S_A");
562  print(" S_A = 1 + a (r/b -1)^N if r<b, with b= (N*a)/((1+a) Z)");
563  print(" = 1 else ");
564  print("which is of polynomial type with exponent N = ",N);
565  }
566  initialize();
567  }
568 
569  corrfactype type() const {return NuclearCorrelationFactor::Polynomial;}
570 
571 private:
572 
574  double a_;
575 
576  double a_param() const {return a_;}
577 
579  static double b_param(const double& a) {return N*a/(1.0+a);}
580 
582  double S(const double& r, const double& Z) const {
583 
584  const double rho=r*Z;
585  const double a=Polynomial<N>::a_param();
586  const double b=Polynomial<N>::b_param(a);
587 
588  if (rho<b) {
589  const double arg=-1.0 + rho/b;
590  return 1.0 + power<N>(-1.0) * a*power<N>(arg);
591  } else {
592  return 1.0;
593  }
594 
595  }
596 
598  coord_3d Sp(const coord_3d& vr1A, const double& Z) const {
599 
600  const double r=vr1A.normf();
601  const double rho=r*Z;
602  const double a=Polynomial<N>::a_param();
603  const double b=Polynomial<N>::b_param(a);
604 
605  if (rho<b) {
606  return power<N>(-1.)*(1.+a)* Z* power<N-1>(-1.+rho/b)*n12(vr1A);
607  }
608  return coord_3d(0.0);
609  }
610 
612 
614  double Spp_div_S(const double& r, const double& Z) const {
615 
616  const double rho=r*Z;
617  const double a=Polynomial<N>::a_param();
618  const double b=Polynomial<N>::b_param(a);
619 
620  if (rho<1.e-6) {
621  const double ap1=1.0+a;
622  const double c0=((3. *(1. + a) - (3. + a) * N))/(2.* a*N);
623  const double c1=((2.* ap1*ap1 - ap1* (3. + a)*N + N*N)*Z)/(a*a*N*N);
624  const double c2=((30.*ap1*ap1*ap1- ap1*ap1* (55 + 18* a)*N +
625  30 *ap1 *N*N + (-5 + a* (8 + a)) *N*N*N)* Z*Z)/(12 *a*a*a*N*N*N);
626  return Z*Z*(c0 + c1*r + c2*r*r);
627 
628  } else if (rho<b) {
629 
630  const double num=Z* (2 + (power<N>(-1)* a* power<N>(-1 + rho/b)
631  * (-2 *a*N*N + (1 + a) *N* (1 + a *(-3 + N) + N)* rho +
632  2 *(1 + a)*(1+a)* rho*rho))/power<2>(a* N - (1 + a)*rho));
633 
634  const double denom=2.* (r + power<N>(-1) *a* r* power<N>(-1 + rho/b));
635  return -num/denom;
636 
637  } else {
638  return -Z*Z/rho;
639  }
640  }
641 
642 };
643 
644 
645 class PseudoNuclearCorrelationFactor : public NuclearCorrelationFactor {
646 
647 public:
649 
652  PseudoNuclearCorrelationFactor(World& world, const Molecule& mol,
653  const std::shared_ptr<PotentialManager> pot, const double fac)
654  : NuclearCorrelationFactor(world,mol), potentialmanager(pot), fac(fac) {
655 
656  if (world.rank()==0) {
657  print("constructed nuclear correlation factor of the form");
658  print(" R = ",fac);
659  print("which means it's (nearly) a conventional calculation\n");
660  }
661  initialize();
662 
663  // add the missing -Z/r part to U2!
664  }
665 
666  corrfactype type() const {return None;}
667 
669 
672  real_function_3d U2() const {
673 
674 // if (not U2_function.is_initialized()) {
675  MADNESS_ASSERT(potentialmanager->vnuclear().is_initialized());
676 // }
677  return potentialmanager->vnuclear();
678  }
679 
681 
683  real_function_3d apply_U(const real_function_3d& rhs) const {
684  return (U2()*rhs).truncate();
685  }
686 
687 
688 private:
689 
691  std::shared_ptr<PotentialManager> potentialmanager;
692 
694  const double fac;
695 
697  double S(const double& r, const double& Z) const {
698  return fac;
699  }
700 
702  coord_3d Sp(const coord_3d& vr1A, const double& Z) const {
703  return coord_3d(0.0);
704  }
705 
707 
709  double Spp_div_S(const double& r, const double& Z) const {
710  return 0.0;
711  }
712 };
713 
715 create_nuclear_correlation_factor(World& world, const SCF& calc);
716 
718 class CorrelationFactor {
719 
720  World& world;
721  double _gamma;
722  double dcut;
723  double lo;
724 
725 public:
726 
728  CorrelationFactor(World& world) : world(world), _gamma(-1.0), dcut(1.e-10),
729  lo(1.e-10) {
730  }
731 
733  CorrelationFactor(World& world, const double& gamma, const double dcut,
734  const Molecule& molecule) : world(world), _gamma(gamma), dcut(dcut) {
735  lo = molecule.smallest_length_scale();
736  if (world.rank()==0) {
737 
738  if (gamma>0.0) print("constructed correlation factor with gamma=",gamma);
739  else if (gamma==0.0) print("constructed linear correlation factor");
740  }
741  }
742 
744  CorrelationFactor(const CorrelationFactor& other) : world(other.world) {
745  _gamma=other._gamma;
746  dcut=other.dcut;
747  lo=other.lo;
748  }
749 
751  CorrelationFactor& operator=(const CorrelationFactor& other) {
752  _gamma=other._gamma;
753  dcut=other.dcut;
754  lo=other.lo;
755  return *this;
756  }
757 
759  double gamma() const {return _gamma;}
760 
762  double operator()(const coord_6d& r) const {
763  const double rr=r12(r);
764  if (_gamma>0.0) return (1.0-exp(-_gamma*rr))/(2.0*_gamma);
765  return 0.5*rr;
766  }
767 
769  real_function_6d apply_U(const real_function_3d& phi_i, const real_function_3d& phi_j,
770  const double eps) const {
771 // const double bsh_thresh=FunctionDefaults<6>::get_thresh*0.1;
772  const double bsh_thresh=1.e-7;
773 
774  real_function_6d result=real_factory_6d(world);
775 
776  real_convolution_6d op_mod = BSHOperator<6>(world, sqrt(-2*eps), lo,bsh_thresh);
777  op_mod.modified()=true;
778 
779  for (int axis=0; axis<3; ++axis) {
780  if (world.rank()==0) print("working on axis",axis);
781  real_derivative_3d D = free_space_derivative<double,3>(world, axis);
782  const real_function_3d Di=(D(phi_i)).truncate();
783  const real_function_3d Dj=(D(phi_j)).truncate();
784 
785  const real_function_6d u=U1(axis);
786 
787  real_function_6d tmp1=CompositeFactory<double,6,3>(world)
788  .g12(u).particle1(copy(Di)).particle2(copy(phi_j));
789  tmp1.fill_tree(op_mod).truncate();
790  real_function_6d tmp2=CompositeFactory<double,6,3>(world)
791  .g12(u).particle1(copy(phi_i)).particle2(copy(Dj));
792  tmp2.fill_tree(op_mod).truncate();
793  if (world.rank()==0) print("done with fill_tree");
794 
795  result=result+(tmp1-tmp2).truncate();
796  tmp1.clear();
797  tmp2.clear();
798  world.gop.fence();
799  result.truncate().reduce_rank();
800 
801  if (world.rank()==0) printf("done with multiplication with U at ime %.1f\n",wall_time());
802  result.print_size("result");
803  }
804 
805 // load_balance(result,true);
806 
807  // include the purely local potential that (partially) cancels 1/r12
808  if (_gamma>0.0) {
809  real_function_6d fg3=real_factory_6d(world).functor2(fg_(_gamma,dcut)).is_on_demand();
810  real_function_6d mul=CompositeFactory<double,6,3>(world)
811  .g12(fg3).particle1(copy(phi_i)).particle2(copy(phi_j));
812  mul.fill_tree(op_mod).truncate();
813  mul.print_size("mul");
814 
815  result=(result+mul).truncate().reduce_rank();
816  }
817  result.print_size("U * |ij>");
818  return result;
819  }
820 
822  real_function_6d U1(const int axis) const {
823  const real_function_6d u1=real_factory_6d(world)
824  .functor2(U(_gamma,axis,dcut)).is_on_demand();
825  return u1;
826  }
827 
829  real_function_6d U2() const {
830  if (world.rank()==0) print("U2 for the electronic correlation factor");
831  if (world.rank()==0) print("is expensive -- do you really need it??");
832  MADNESS_EXCEPTION("U2() not implemented, since it might be expensive",1);
833  return real_factory_6d(world);
834  }
835 
837  real_function_6d f() const {
838 // real_function_6d tmp=real_factory_6d(world).functor2(*this).is_on_demand();
840  real_function_6d tmp=TwoElectronFactory(world)
841  .dcut(dcut).gamma(_gamma).f12().thresh(thresh);
842  return tmp;
843  }
844 
846  real_function_6d f2() const {
847  real_function_6d tmp=real_factory_6d(world).functor2(f2_(_gamma)).is_on_demand();
848  return tmp;
849  }
850 
852  real_function_6d fg() const {
853  real_function_6d tmp=real_factory_6d(world).functor2(fg_(_gamma,dcut)).is_on_demand();
854  return tmp;
855  }
856 
858  real_function_6d f_over_r() const {
859  real_function_6d tmp=real_factory_6d(world).functor2(f_over_r_(_gamma,dcut)).is_on_demand();
860  return tmp;
861  }
862 
864  real_function_6d nablaf2() const {
865  real_function_6d tmp=real_factory_6d(world).functor2(nablaf2_(_gamma)).is_on_demand();
866  return tmp;
867  }
868 
869 private:
871  struct fg_ {
872  double gamma;
873  double dcut;
874  fg_(double gamma, double dcut) : gamma(gamma), dcut(dcut) {
875  MADNESS_ASSERT(gamma>0.0);
876  }
877  double operator()(const coord_6d& r) const {
878  const double rr=r12(r);
879  const double e=exp(-gamma*rr);
880  return (1.0-e)*u(rr,dcut) + 0.5*gamma*e;
881  }
882  };
883 
885  struct f_over_r_ {
886  double gamma;
887  double dcut;
888  f_over_r_(double gamma, double dcut) : gamma(gamma), dcut(dcut) {
889  MADNESS_ASSERT(gamma>0.0);
890  }
891  double operator()(const coord_6d& r) const {
892  const double rr=r12(r);
893  const double e=exp(-gamma*rr);
894  return (1.0-e)*u(rr,dcut)/(2.0*gamma);
895  }
896  };
897 
899  struct U {
900  double gamma;
901  int axis;
902  double dcut;
903  U(double gamma, int axis, double dcut) : gamma(gamma), axis(axis),
904  dcut(dcut) {
905  MADNESS_ASSERT(axis>=0 and axis<3);
906  }
907  double operator()(const coord_6d& r) const {
908  const double rr=r12(r);
909  const coord_3d vr12=vec(r[0]-r[3],r[1]-r[4],r[2]-r[5]);
910  const coord_3d N=n12(vr12);
911  if (gamma>0.0) return -0.5*exp(-gamma*rr)*N[axis];
912  MADNESS_EXCEPTION("no gamma in electronic corrfac::U1",1);
913 // const double rr=r12(r);
914 // const double g12=u(rr,dcut);
915 // double a=0.5;
916 // if (gamma>0.0) a=0.5*exp(-gamma*rr);
917 // return -a*x12(r,axis) * g12;
918  }
919  };
920 
922  struct f2_ {
923  double gamma;
924  f2_(double gamma) : gamma(gamma) {MADNESS_ASSERT(gamma>0.0);}
925  double operator()(const coord_6d& r) const {
926  const double rr=r12(r);
927  const double e=exp(-gamma*rr);
928  const double f=(1.0-e)/(2.0*gamma);
929  return f*f;
930  }
931  };
932 
934  struct nablaf2_ {
935  double gamma;
936  nablaf2_(double gamma) : gamma(gamma) {
937  MADNESS_ASSERT(gamma>0.0);
938  MADNESS_ASSERT(gamma=1.0); // I don't think this is right
939  }
940  double operator()(const coord_6d& r) const {
941  const double rr=r12(r);
942  const double f=exp(-2.0*gamma*rr)/(4.0*gamma*gamma);
943  return f;
944  }
945  };
946 
948  static double u(double r, double c) {
949  r = r/c;
950  double r2 = r*r, pot;
951  if (r > 6.5){
952  pot = 1.0/r;
953  } else if (r > 1e-2) {
954  pot = erf(r)/r + exp(-r2)*0.56418958354775630;
955  } else{
956  pot = 1.6925687506432689-r2*(0.94031597257959381-r2*(0.39493270848342941-0.12089776790309064*r2));
957  }
958  return pot/c;
959  }
960 
961  static double r12(const coord_6d& r) {
962  const double x12=r[0]-r[3];
963  const double y12=r[1]-r[4];
964  const double z12=r[2]-r[5];
965  const double r12=sqrt(x12*x12 + y12*y12 + z12*z12);
966  return r12;
967  }
968  static double x12(const coord_6d& r, const int axis) {
969  return r[axis]-r[axis+3];
970  }
971 
972 
973 };
974 
976 class CorrelationFactor2 {
977 
978  World& world;
979  double _gamma;
981 
982 public:
983 
984  double dcut;
985  double lo;
986  double vtol;
987 
988 
990  CorrelationFactor2(World& world) : world(world), _gamma(0.5), dcut(1.e-10),
991  lo(1.e-10), vtol(FunctionDefaults<3>::get_thresh()*0.1) {
992  MADNESS_ASSERT(_gamma==0.5);
993  }
994 
996  double gamma() const {return _gamma;}
997 
998  real_function_6d function() const {
999  functorT R=functorT(new R_functor(_gamma,1));
1000  return real_factory_6d(world).functor(R).is_on_demand();
1001  }
1002 
1003  real_function_6d square() const {
1004  functorT R2=functorT(new R_functor(_gamma,2));
1005  return real_factory_6d(world).functor(R2).is_on_demand();
1006  }
1007 
1008  real_function_6d inverse() const {
1009  functorT R=functorT(new R_functor(_gamma,-1));
1010  return real_factory_6d(world).functor(R).is_on_demand();
1011  }
1012 
1014  real_function_6d U1(const int axis) const {
1015  functorT U1f=functorT(new U1_functor(_gamma,axis));
1016  return real_factory_6d(world).functor(U1f).is_on_demand();
1017  }
1018 
1020  real_function_6d U2() const {
1021  functorT U2f=functorT(new U2_functor(_gamma));
1022  return real_factory_6d(world).functor(U2f).is_on_demand();
1023  }
1024 
1026  real_function_6d apply_U(const real_function_6d& psi, const double eps) const {
1027  const double bsh_thresh=1.e-7;
1028 
1029  real_function_6d result=real_factory_6d(world);
1030 
1031  real_convolution_6d op_mod = BSHOperator<6>(world, sqrt(-2*eps), lo,bsh_thresh);
1032  op_mod.modified()=true;
1033 
1034  for (int axis=0; axis<3; ++axis) {
1035  if (world.rank()==0) print("working on axis",axis);
1036  real_derivative_6d D1 = free_space_derivative<double,6>(world, axis);
1037  real_derivative_6d D2 = free_space_derivative<double,6>(world, axis+3);
1038  const real_function_6d Drhs1=D1(psi).truncate();
1039  const real_function_6d Drhs2=D2(psi).truncate();
1040 
1041  const real_function_6d u1=U1(axis);
1042 
1043  real_function_6d tmp1=CompositeFactory<double,6,3>(world)
1044  .g12(u1).ket(copy(Drhs1));
1045  tmp1.fill_tree(op_mod).truncate();
1046 
1047  real_function_6d tmp2=CompositeFactory<double,6,3>(world)
1048  .g12(u1).ket(copy(Drhs2));
1049  tmp2.fill_tree(op_mod).truncate();
1050  if (world.rank()==0) print("done with fill_tree");
1051 
1052  result=result+(tmp1-tmp2).truncate();
1053  tmp1.clear();
1054  tmp2.clear();
1055  world.gop.fence();
1056  result.truncate().reduce_rank();
1057 
1058  if (world.rank()==0)
1059  printf("done with multiplication with U at ime %.1f\n",wall_time());
1060  result.print_size("result");
1061  }
1062 
1063  real_function_6d u2=U2();
1064  real_function_6d r2=CompositeFactory<double,6,3>(world).ket(copy(psi))
1065  .g12(u2);
1066  r2.fill_tree(op_mod);
1067  result=(result+r2).truncate();
1068  return result;
1069  }
1070 
1071 
1072 private:
1073 
1075  class R_functor : public FunctionFunctorInterface<double,6> {
1076  double gamma;
1077  int exponent;
1078 
1079  public:
1080  R_functor(double gamma, int e=1) : gamma(gamma), exponent(e) {
1081  MADNESS_ASSERT(gamma=0.5);
1082  }
1083 
1084  // only valid for gamma=1
1085  double operator()(const coord_6d& r) const {
1086  const double rr=r12(r);
1087  double val=(1.0-0.5*exp(-gamma*rr));
1088  if (exponent==1) return val;
1089  else if (exponent==2) return val*val;
1090  else if (exponent==-1) return 1.0/val;
1091  else {
1092  MADNESS_EXCEPTION("fancy exponent in correlationfactor2",1);
1093  }
1094  }
1095  };
1096 
1098  class U2_functor : public FunctionFunctorInterface<double,6> {
1099  double gamma;
1100 
1101  public:
1102  U2_functor(double gamma) : gamma(gamma) {
1103  MADNESS_ASSERT(gamma=0.5);
1104  }
1105 
1106  // only valid for gamma=1
1107  double operator()(const coord_6d& r) const {
1108  const double rr=r12(r);
1109  // Taylor expansion for small r
1110  if (rr<1.e-4) { // valid for gamma==0.5, otherwise singular
1111  return 5./4.0 - rr + (35.0* rr*rr)/48.0 - (101.0*rr*rr*rr)/192.0;
1112  }
1113  const double egr=exp(-gamma*rr);
1114  return -(-8.*egr + 8.0 + rr*egr)/(4.0 *rr*egr - 8 *rr);
1115  }
1116  };
1117 
1119 
1124  class U1_functor : public FunctionFunctorInterface<double,6> {
1125  double gamma;
1126  int axis;
1127 
1128  public:
1129  U1_functor(double gamma, int axis) : gamma(gamma), axis(axis) {
1130  MADNESS_ASSERT(gamma==0.5);
1131  MADNESS_ASSERT(axis<3);
1132  }
1133 
1134  double operator()(const coord_6d& r) const {
1135  const double rr=r12(r);
1136  const coord_3d vr12=vec(r[0]-r[3],r[1]-r[4],r[2]-r[5]);
1137  const coord_3d N=n12(vr12);
1138  // Taylor expansion for small r
1139  double val;
1140  if (rr<1.e-4) { // valid for gamma==0.5, otherwise singular
1141  val = 0.5 - 0.5*rr + 0.125*(3.*rr*rr) - (13.* rr*rr*rr)/48.0;
1142  } else {
1143  const double egr=exp(-gamma*rr);
1144  val=egr/(4.0-2.0*egr);
1145  }
1146  // NOTE the sign
1147  return -val*N[axis];
1148  }
1149  };
1150 
1152  static double r12(const coord_6d& r) {
1153  const double x12=r[0]-r[3];
1154  const double y12=r[1]-r[4];
1155  const double z12=r[2]-r[5];
1156  const double r12=sqrt(x12*x12 + y12*y12 + z12*z12);
1157  return r12;
1158  }
1159 
1160 };
1161 
1162 
1163 }
1164 
1165 #endif /* NUCLEARCORRELATIONFACTOR_H_ */
1166 
1167 
const double thresh
Definition: dielectric.cc:185
Derivative< double, 6 > real_derivative_6d
Definition: functypedefs.h:173
Definition: shared_ptr_bits.h:38
Vector< T, NDIM > n12(const Vector< T, NDIM > &r, const double eps=1.e-6)
helper function unit vector in direction r
Definition: array.h:546
NDIM const Function< R, NDIM > & g
Definition: mra.h:2179
const mpreal exp(const mpreal &v, mp_rnd_t rnd_mode)
Definition: mpreal.h:2234
FunctionFactory & functor2(const opT &op)
Definition: function_factory.h:136
const mpreal erf(const mpreal &v, mp_rnd_t rnd_mode)
Definition: mpreal.h:2457
const double R
Definition: dielectric.cc:191
Main include file for MADNESS and defines Function interface.
Function< T, NDIM > & truncate(double tol=0.0, bool fence=true)
Truncate the function with optional fence. Compresses with fence if not compressed.
Definition: mra.h:577
FunctionFactory< double, 6 > real_factory_6d
Definition: functypedefs.h:96
void truncate(World &world, std::vector< Function< T, NDIM > > &v, double tol=0.0, bool fence=true)
Truncates a vector of functions.
Definition: vmra.h:194
Function< T, NDIM > & fill_tree(const Function< R, NDIM > &g, bool fence=true)
With this being an on-demand function, fill the MRA tree according to different criteria.
Definition: mra.h:1060
Vector< double, 3 > coord_3d
Definition: funcplot.h:634
NDIM & f
Definition: mra.h:2179
static const double & get_thresh()
Returns the default threshold.
Definition: funcdefaults.h:225
double smallest_length_scale() const
Definition: DFcode/molecule.cc:300
Definition: DFcode/molecule.h:82
World & initialize(int &argc, char **&argv)
Initialize the MADNESS runtime.
Definition: world.cc:134
std::shared_ptr< NuclearCorrelationFactor > create_nuclear_correlation_factor(World &world, const SCF &calc)
create and return a new nuclear correlation factor
Definition: correlationfactor.cc:48
Tensor< typename Tensor< T >::scalar_type > arg(const Tensor< T > &t)
Return a new tensor holding the argument of each element of t (complex types only) ...
Definition: tensor.h:2429
Function< double, 3 > real_function_3d
Definition: functypedefs.h:65
Derivative< double, 3 > real_derivative_3d
Definition: functypedefs.h:170
std::shared_ptr< FunctionFunctorInterface< double, 3 > > functorT
Definition: chem/corepotential.cc:58
double q
Coordinates and charge in atomic units.
Definition: DFcode/molecule.h:56
int power< 2 >(int base)
Definition: power.h:58
SeparatedConvolution< double, 6 > real_convolution_6d
Definition: functypedefs.h:124
Vector< T, 1 > vec(T x)
Your friendly neighborhood factory function.
Definition: array.h:456
Function< T, NDIM > copy(const Function< T, NDIM > &f, const std::shared_ptr< WorldDCPmapInterface< Key< NDIM > > > &pmap, bool fence=true)
Create a new copy of the function with different distribution and optional fence. ...
Definition: mra.h:1835
FunctionFactory & functor(const std::shared_ptr< FunctionFunctorInterface< T, NDIM > > &f)
Definition: function_factory.h:129
double psi(const Vector< double, 3 > &r)
Definition: apps/ii/hatom_energy.cc:42
Function< double, 6 > real_function_6d
Definition: functypedefs.h:68
FLOAT a(int j, FLOAT z)
Definition: y1.cc:86
T normf() const
return the 2-norm of the vector elements
Definition: array.h:258
tensorT sqrt(const tensorT &s, double tol=1e-8)
Computes matrix square root (not used any more?)
Definition: DFcode/moldft.cc:446
Function< T, NDIM > square(const Function< T, NDIM > &f, bool fence=true)
Create a new function that is the square of f - global comm only if not reconstructed.
Definition: mra.h:1806
const mpreal gamma(const mpreal &v, mp_rnd_t rnd_mode)
Definition: mpreal.h:2429
Abstract Atom class.
Definition: DFcode/molecule.h:54
Vector< double, 6 > coord_6d
Definition: funcplot.h:635
Implements (2nd generation) static load/data balancing for functions.
virtual FunctionFactory & is_on_demand()
Definition: function_factory.h:227
Definition: tkato/SCF.h:52
void print(const A &a)
Print a single item to std::cout terminating with new line.
Definition: print.h:122
FunctionFactory< double, 3 > real_factory_3d
Definition: functypedefs.h:93
#define MADNESS_EXCEPTION(msg, value)
Definition: worldexc.h:88
double thresh() const
Returns value of truncation threshold. No communication.
Definition: mra.h:542
const T1 const T2 & f2
Definition: gtest-tuple.h:680
Holds machinery to set up Functions/FuncImpls using various Factories and Interfaces.
Definition: chem/atomutil.cc:45
const double c
Definition: gfit.cc:200
const double R2
Definition: vnucso.cc:89
FLOAT b(int j, FLOAT z)
Definition: y1.cc:79
madness::Vector< double, 3 > get_coords() const
Definition: DFcode/molecule.h:70
double wall_time()
Returns the wall time in seconds relative to arbitrary origin.
Definition: world.cc:248
Function< TENSOR_RESULT_TYPE(Q, T), NDIM > mul(const Q alpha, const Function< T, NDIM > &f, bool fence=true)
Returns new function equal to alpha*f(x) with optional fence.
Definition: mra.h:1528