MADNESS  0.10.1
BSHApply.h
Go to the documentation of this file.
1 /*
2  * BSHApply.h
3  *
4  * Created on: Feb 26, 2020
5  * Author: fbischoff
6  */
7 
8 #ifndef SRC_APPS_CHEM_BSHAPPLY_H_
9 #define SRC_APPS_CHEM_BSHAPPLY_H_
10 
13 
14 namespace madness {
15 
16 /// apply the BSH operator on a vector of functions with corresponding potentials
17 
18 /// this class
19 /// - constructs the bsh operator with the appropriate exponents
20 /// - performs a level shift if necessary
21 /// - adds coupling terms: ( T - fock(i,i) ) psi_i = -V psi_i + \sum_{j\neq i} psi_j fock(j,i)
22 /// TODO: adding a level shift seems to make the operation less precise, why??
23 template<typename T, std::size_t NDIM>
24 class BSHApply {
25 
26 public:
29  double levelshift=0.0;
30  double lo=1.e-6;
31  double bshtol=1.e-5;
32  bool printme=false;
33  bool destroy_Vpsi=false;
35  return_value ret_value=residual; // return the new orbitals/functions or the residuals
36 
37 public:
39  metric() {
40  bshtol = FunctionDefaults <NDIM> ::get_thresh();
41  printme = printme and world.rank()==0;
42  }
43 
44 
45  /// apply the BSH operator on the vector of functions and respective potentials
46 
47  /// @param[in] eps orbital energies or the square fock matrix
48  /// @param[in] Vpsi vector of functions V*MOs
49  /// @return an MO structure holding the residuals and the orbital energy updates
50  std::tuple<std::vector<Function<T,NDIM> >, Tensor<double> > operator()(
51  const std::vector<Function<T,NDIM> > psi,
52  const Tensor<T> eps,
53  const std::vector<Function<T,NDIM> >& Vpsi1) const {
54 
55  double cpu0=cpu_time();
56  std::vector<Function<T,NDIM> > Vpsi=copy(world,Vpsi1);
57 
58  // add coupling between the functions (i.e. in case of localized orbitals)
59  // ( T + V ) \psi_i = \sum_j \psi_j F_{ji}
60  // ( T - F_{ii}) \psi_i = -V \psi_i + \sum_{j\neq i} \psi_jF_{ji}
61  // no coupling means F_{ij} =\eps_i \delta_{ij}, and the coupling term vanishes
63 
64  std::vector < std::shared_ptr<SeparatedConvolution<double,NDIM> > > ops(psi.size());
65  for (int i=0; i<eps.dim(0); ++i) {
66  T e_i= (eps.ndim()==2) ? eps(i,i) : eps(i);
67  if (printme) print("orbital energy for the BSH operator",e_i);
68  ops[i]=std::shared_ptr<SeparatedConvolution<double,NDIM> >(
69  BSHOperatorPtr<NDIM>(world, sqrt(-2.0*eps_in_green(e_i)), lo, bshtol));
70  ops[i]->destructive()=true;
71  }
72 
73  const std::vector<Function<T,NDIM> > tmp = apply(world,ops,-2.0*Vpsi);
74  const std::vector<Function<T,NDIM> > res=truncate(psi-tmp,FunctionDefaults<NDIM>::get_thresh()*0.1);
75  const std::vector<Function<T,NDIM> > bra_res=make_bra(res);
76 
77  // update eps
78  Tensor<double> norms=real(inner(world,make_bra(tmp),tmp));
79  Tensor<T> rnorms=inner(world,bra_res,res);
80  for (int i=0; i<norms.size(); ++i) {
81  norms(i)=sqrt(norms(i));
82  rnorms(i)=sqrt(rnorms(i));
83  }
84  if (printme) {
85  print("norm2(tmp)",norms);
86  print("norm2(res)",rnorms);
87  }
88 
89  Tensor<T> in=inner(world,Vpsi,bra_res); // no shift here!
90  Tensor<double> delta_eps(psi.size());
91  for (size_t i=0; i<psi.size(); ++i) delta_eps(i)=std::real(in(i))/(norms[i]*norms[i]);
92 
93  if (printme) print("orbital energy update",delta_eps);
94  double cpu1=cpu_time();
95  if (printme) printf("time in BSHApply() %8.4fs\n",cpu1-cpu0);
96 
97  if (ret_value==update) return std::make_tuple(tmp,delta_eps);
98  else if (ret_value==residual) return std::make_tuple(res,delta_eps);
99  else {
100  MADNESS_EXCEPTION("unknown return value in BSHApply",1);
101  }
102  }
103 
104 
105  /// apply the BSH operator on the vector of functions and respective potentials
106 
107  /// @param[in] arg the MO structure holding MOs and orbital energies
108  /// @param[in] Vpsi vector of functions V*MOs
109  /// @return an MO structure holding the residuals and the orbital energy updates
111  const std::vector<Function<T,NDIM> >& Vpsi) const {
112  std::tuple<std::vector<Function<T,NDIM>, Tensor<T> > > result;
113  result=this->operator()(arg.get_mos(),arg.get_eps(),Vpsi);
114  return result;
115  }
116 
117  std::vector<Function<T,NDIM> > make_bra(const std::vector<Function<T,NDIM> >& rhs) const {
118  if (metric.is_initialized()) return metric*rhs;
119  return rhs;
120  }
121 
122  /// limit the orbital energy (diagonal fock matrix element) entering the Green's function parameter mu
123  double eps_in_green(const T eps) const {
124 
125  if (std::imag(eps)>1.e-12)
126  MADNESS_EXCEPTION("complex orbital energies in BSHApply",1);
127  return std::min(-0.05,std::real(eps)+levelshift);
128  }
129 
130  std::vector<Function<T,NDIM> > add_coupling_and_levelshift(const std::vector<Function<T,NDIM> > psi,
131  const Tensor<T> fock1) const {
132 
133  // check dimensions
134  bool consistent=(psi.size()==size_t(fock1.dim(0)));
135  if ((fock1.ndim()==2) and not (psi.size()==size_t(fock1.dim(1)))) consistent=false;
136 
137  if (not consistent) {
138  print("Fock matrix dimensions",fock1.ndim(), fock1.dim(0), fock1.dim(1));
139  print("number of orbitals",psi.size());
140  MADNESS_EXCEPTION("confused Fock matrix/orbital energies in BSHApply - 1",1);
141  }
142 
143  bool do_coupling=(fock1.ndim()==2);
144 
145  // subtract the BSH energy (aka Fock diagonal elements) from the rhs
146  // ( T - fock(i,i) ) psi_i = -V psi_i + \sum_{j\neq i} psi_j fock(j,i)
147  // if there is no level shift and the orbital energies are large enough the
148  // diagonal should simply vanish.
149  if (do_coupling) {
150  Tensor<T> fock=copy(fock1);
151  for (int i=0; i<fock.dim(0); ++i) {
152  fock(i,i)-=eps_in_green(fock(i,i));
153  }
154  if (printme) {
155  print("coupling fock matrix");
156  print(fock);
157  }
158  return transform(world, psi, fock);
159 
160  } else {
161  std::vector<T> eps(psi.size());
162  if (fock1.ndim()==1)
163  for (int i=0; i<fock1.dim(0); ++i) eps[i]=fock1(i)-eps_in_green(fock1(i));
164  if (fock1.ndim()==2)
165  for (int i=0; i<fock1.dim(0); ++i) eps[i]=fock1(i,i)-eps_in_green(fock1(i,i));
166 
167  std::vector<Function<T,NDIM> > result=copy(world,psi);
168  scale(world,result,eps);
169  return result;
170  }
171 
172  }
173 
174 };
175 } // namespace madness
176 
177 
178 #endif /* SRC_APPS_CHEM_BSHAPPLY_H_ */
This header should include pretty much everything needed for the parallel runtime.
apply the BSH operator on a vector of functions with corresponding potentials
Definition: BSHApply.h:24
std::vector< Function< T, NDIM > > make_bra(const std::vector< Function< T, NDIM > > &rhs) const
Definition: BSHApply.h:117
double bshtol
Definition: BSHApply.h:31
bool destroy_Vpsi
Definition: BSHApply.h:33
std::vector< Function< T, NDIM > > add_coupling_and_levelshift(const std::vector< Function< T, NDIM > > psi, const Tensor< T > fock1) const
Definition: BSHApply.h:130
double levelshift
Definition: BSHApply.h:29
MolecularOrbitals< T, NDIM > operator()(const MolecularOrbitals< T, NDIM > &arg, const std::vector< Function< T, NDIM > > &Vpsi) const
apply the BSH operator on the vector of functions and respective potentials
Definition: BSHApply.h:110
Function< double, NDIM > metric
Definition: BSHApply.h:34
return_value ret_value
Definition: BSHApply.h:35
double eps_in_green(const T eps) const
limit the orbital energy (diagonal fock matrix element) entering the Green's function parameter mu
Definition: BSHApply.h:123
double lo
Definition: BSHApply.h:30
bool printme
Definition: BSHApply.h:32
World & world
Definition: BSHApply.h:28
BSHApply(World &world)
Definition: BSHApply.h:38
return_value
Definition: BSHApply.h:27
@ residual
Definition: BSHApply.h:27
@ update
Definition: BSHApply.h:27
std::tuple< std::vector< Function< T, NDIM > >, Tensor< double > > operator()(const std::vector< Function< T, NDIM > > psi, const Tensor< T > eps, const std::vector< Function< T, NDIM > > &Vpsi1) const
apply the BSH operator on the vector of functions and respective potentials
Definition: BSHApply.h:50
long dim(int i) const
Returns the size of dimension i.
Definition: basetensor.h:147
long ndim() const
Returns the number of dimensions in the tensor.
Definition: basetensor.h:144
long size() const
Returns the number of elements in the tensor.
Definition: basetensor.h:138
FunctionDefaults holds default paramaters as static class members.
Definition: funcdefaults.h:204
bool is_initialized() const
Returns true if the function is initialized.
Definition: mra.h:147
Definition: MolecularOrbitals.h:24
std::vector< Function< T, NDIM > > get_mos() const
Definition: MolecularOrbitals.h:64
A parallel world class.
Definition: world.h:132
ProcessID rank() const
Returns the process rank in this World (same as MPI_Comm_rank()).
Definition: world.h:318
auto T(World &world, response_space &f) -> response_space
Definition: global_functions.cc:34
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:2502
double psi(const Vector< double, 3 > &r)
Definition: hatom_energy.cc:78
#define MADNESS_EXCEPTION(msg, value)
Macro for throwing a MADNESS exception.
Definition: madness_exception.h:119
File holds all helper structures necessary for the CC_Operator and CC2 class.
Definition: DFParameters.h:10
static double cpu_time()
Returns the cpu time in seconds relative to an arbitrary origin.
Definition: timers.h:127
response_space scale(response_space a, double b)
response_space apply(World &world, std::vector< std::vector< std::shared_ptr< real_convolution_3d >>> &op, response_space &f)
Definition: basic_operators.cc:39
void truncate(World &world, response_space &v, double tol, bool fence)
Definition: basic_operators.cc:30
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:2002
void print(const T &t, const Ts &... ts)
Print items to std::cout (items separated by spaces) and terminate with a new line.
Definition: print.h:225
double inner(response_space &a, response_space &b)
Definition: response_functions.h:442
double imag(double x)
Definition: complexfun.h:56
double real(double x)
Definition: complexfun.h:52
std::vector< Function< TENSOR_RESULT_TYPE(T, R), NDIM > > transform(World &world, const std::vector< Function< T, NDIM > > &v, const Tensor< R > &c, bool fence=true)
Transforms a vector of functions according to new[i] = sum[j] old[j]*c[j,i].
Definition: vmra.h:689