1 //#define WORLD_INSTANTIATE_STATIC_TEMPLATES
2 #include <madness/mra/mra.h>
3 #include <madness/tensor/solvers.h>
4 #include <madness/external/tinyxml/tinyxml.h>
5 #include <madness/world/worldmem.h>
6 
7 using namespace madness;
8 
9 #include <chem/molecule.h>
10 #include <chem/molecularbasis.h>
11 #include <chem/xcfunctional.h>
12 
13 #include <chem/gth_pseudopotential.h>
14 #include "wst_functional.h"
15 
16 static const double twopi = 2.0*constants::pi;
17 
18 typedef std::shared_ptr<real_convolution_3d> poperatorT;
19 
20 static std::vector<int> at_to_bf, at_nbf;
21 
22 extern void drot(long n, double* MADNESS_RESTRICT a, double* MADNESS_RESTRICT b, double s, double c, long inc);
23 
drot3(long n,double * MADNESS_RESTRICT a,double * MADNESS_RESTRICT b,double s,double c,long inc)24 void drot3(long n, double* MADNESS_RESTRICT a, double* MADNESS_RESTRICT b, double s, double c, long inc) {
25     if (inc == 1) {
26         n*=3;
27         for (long i=0; i<n; i+=3) {
28             double aa0 = a[i  ]*c - b[i  ]*s;
29             double bb0 = b[i  ]*c + a[i  ]*s;
30             double aa1 = a[i+1]*c - b[i+1]*s;
31             double bb1 = b[i+1]*c + a[i+1]*s;
32             double aa2 = a[i+2]*c - b[i+2]*s;
33             double bb2 = b[i+2]*c + a[i+2]*s;
34             a[i  ] = aa0;
35             b[i  ] = bb0;
36             a[i+1] = aa1;
37             b[i+1] = bb1;
38             a[i+2] = aa2;
39             b[i+2] = bb2;
40         }
41     }
42     else {
43         inc*=3;
44         n*=inc;
45         for (long i=0; i<n; i+=inc) {
46             double aa0 = a[i  ]*c - b[i  ]*s;
47             double bb0 = b[i  ]*c + a[i  ]*s;
48             double aa1 = a[i+1]*c - b[i+1]*s;
49             double bb1 = b[i+1]*c + a[i+1]*s;
50             double aa2 = a[i+2]*c - b[i+2]*s;
51             double bb2 = b[i+2]*c + a[i+2]*s;
52             a[i  ] = aa0;
53             b[i  ] = bb0;
54             a[i+1] = aa1;
55             b[i+1] = bb1;
56             a[i+2] = aa2;
57             b[i+2] = bb2;
58         }
59     }
60 }
61 
62 // Functor for the initial guess atomic density
63 class MolecularGuessDensityFunctor : public FunctionFunctorInterface<double,3> {
64 private:
65     const Molecule& molecule;
66     const AtomicBasisSet& aobasis;
67 public:
MolecularGuessDensityFunctor(const Molecule & molecule,const AtomicBasisSet & aobasis)68     MolecularGuessDensityFunctor(const Molecule& molecule, const AtomicBasisSet& aobasis)
69         : molecule(molecule), aobasis(aobasis) {}
70 
operator ()(const coord_3d & x) const71     double operator()(const coord_3d& x) const {
72         return aobasis.eval_guess_density(molecule, x[0], x[1], x[2]);
73     }
74 };
75 
76 // Templated functor for the atomic Gaussian basis functions
77 template <typename Q>
78 class AtomicBasisFunctor : public FunctionFunctorInterface<Q,3> {
79 private:
80     const AtomicBasisFunction aofunc;
81 
82 public:
AtomicBasisFunctor(const AtomicBasisFunction & aofunc)83     AtomicBasisFunctor(const AtomicBasisFunction& aofunc)
84         : aofunc(aofunc)
85     {}
86 
operator ()(const coord_3d & x) const87     Q operator()(const coord_3d& x) const {
88         return aofunc(x[0], x[1], x[2]);
89     }
90 
special_points() const91     std::vector<coord_3d> special_points() const {
92         return std::vector<coord_3d>(1,aofunc.get_coords_vec());
93     }
94 
special_level()95     Level special_level() {
96       return 8;
97     }
98 };
99 
100 // Functor for the nuclear charge density
101 class NuclearDensityFunctor : public FunctionFunctorInterface<double,3> {
102   Molecule molecule;
103   std::vector<coord_3d> specialpts;
104 public:
NuclearDensityFunctor(const Molecule & molecule)105   NuclearDensityFunctor(const Molecule& molecule) :
106     molecule(molecule), specialpts(molecule.get_all_coords_vec()) {}
107 
operator ()(const Vector<double,3> & r) const108   double operator()(const Vector<double,3>& r) const {
109     return molecule.mol_nuclear_charge_density(r[0], r[1], r[2]);
110   }
111 
special_points() const112   std::vector<coord_3d> special_points() const{
113     return specialpts;
114   }
115 
special_level()116   Level special_level() {
117     return 15;
118   }
119 };
120 
121 // Functor for the nuclear potential
122 class MolecularPotentialFunctor : public FunctionFunctorInterface<double,3> {
123 private:
124     const Molecule& molecule;
125 public:
MolecularPotentialFunctor(const Molecule & molecule)126     MolecularPotentialFunctor(const Molecule& molecule)
127         : molecule(molecule) {}
128 
operator ()(const coord_3d & x) const129     double operator()(const coord_3d& x) const {
130         return molecule.nuclear_attraction_potential(x[0], x[1], x[2]);
131     }
132 
special_points() const133     std::vector<coord_3d> special_points() const {return molecule.get_all_coords_vec();}
134 };
135 
136 /// A MADNESS functor to compute either x, y, or z
137 class DipoleFunctor : public FunctionFunctorInterface<double,3> {
138 private:
139     const int axis;
140 public:
DipoleFunctor(int axis)141     DipoleFunctor(int axis) : axis(axis) {}
operator ()(const coord_3d & x) const142     double operator()(const coord_3d& x) const {
143         return x[axis];
144     }
145 };
146 
147 struct BoysLocalization {
148 
149     std::vector<int> aset;
150 
BoysLocalizationBoysLocalization151     BoysLocalization() {}
152 
BoysLocalizationBoysLocalization153     BoysLocalization(unsigned int norbs) {
154         aset = std::vector<int>(norbs, 0);
155     }
156 
set_sizeBoysLocalization157     void set_size(unsigned int norbs) {
158         aset = std::vector<int>(norbs, 0);
159     }
160 
DIPBoysLocalization161     inline double DIP(const real_tensor& dip, int i, int j, int k, int l)
162     {
163         return dip(i, j, 0) * dip(k, l, 0) + dip(i, j, 1) * dip(k, l, 1) + dip(i, j, 2) * dip(k, l, 2);
164     }
165 
operator ()BoysLocalization166     real_tensor operator ()(World& world,
167                             const vector_real_function_3d& mo,
168                             const double thresh = 1e-9,
169                             const double thetamax = 0.5,
170                             const bool randomize = true)
171     {
172         //START_TIMER(world);
173         const bool doprint = false;
174         long nmo = mo.size();
175         real_tensor dip(nmo, nmo, 3);
176         double safety = 1e-1;
177         double vtol = thresh*safety;
178         for(int axis = 0;axis < 3;++axis){
179             real_function_3d fdip = real_factory_3d(world).functor(real_functor_3d(new DipoleFunctor(axis))).initial_level(4);
180             dip(_, _, axis) = matrix_inner(world, mo, mul_sparse(world, fdip, mo, vtol), true);
181         }
182         real_tensor U(nmo, nmo);
183         if(world.rank() == 0){
184             for(long i = 0;i < nmo;++i)
185                 U(i, i) = 1.0;
186 
187             double tol = thetamax;
188             long ndone = 0;
189             bool converged = false;
190             for(long iter = 0;iter < 300;++iter){
191                 double sum = 0.0;
192                 for(long i = 0;i < nmo;++i){
193                     sum += DIP(dip, i, i, i, i);
194                 }
195                 long ndone_iter = 0;
196                 double maxtheta = 0.0;
197                 if(doprint)
198                     printf("iteration %ld sum=%.4f ndone=%ld tol=%.2e\n", iter, sum, ndone, tol);
199 
200                 for(long i = 0;i < nmo;++i){
201                     for(long j = 0;j < i;++j){
202                         if (aset[i] == aset[j]) {
203                             double g = DIP(dip, i, j, j, j) - DIP(dip, i, j, i, i);
204                             double h = 4.0 * DIP(dip, i, j, i, j) + 2.0 * DIP(dip, i, i, j, j) - DIP(dip, i, i, i, i) - DIP(dip, j, j, j, j);
205                             double sij = DIP(dip, i, j, i, j);
206                             bool doit = false;
207                             if(h >= 0.0){
208                                 doit = true;
209                                 if(doprint)
210                                     print("             forcing negative h", i, j, h);
211 
212                                 h = -1.0;
213                             }
214                             double theta = -g / h;
215                             maxtheta = std::max<double>(std::abs(theta), maxtheta);
216                             if(fabs(theta) > thetamax){
217                                 doit = true;
218                                 if(doprint)
219                                     print("             restricting", i, j);
220 
221                                 if(g < 0)
222                                     theta = -thetamax;
223 
224                                 else
225                                     theta = thetamax * 0.8;
226 
227                             }
228                             bool randomized = false;
229                             if(randomize && iter == 0 && sij > 0.01 && fabs(theta) < 0.01){
230                                 randomized = true;
231                                 if(doprint)
232                                     print("             randomizing", i, j);
233 
234                                 theta += (RandomValue<double>() - 0.5);
235                             }
236                             if(fabs(theta) >= tol || randomized || doit){
237                                 ++ndone_iter;
238                                 if(doprint)
239                                     print("     rotating", i, j, theta);
240 
241                                 double c = cos(theta);
242                                 double s = sin(theta);
243                                 drot3(nmo, &dip(i, 0, 0), &dip(j, 0, 0), s, c, 1);
244                                 drot3(nmo, &dip(0, i, 0), &dip(0, j, 0), s, c, nmo);
245                                 drot(nmo, &U(i, 0), &U(j, 0), s, c, 1);
246                             }
247                         }
248                     }
249                 }
250 
251                 ndone += ndone_iter;
252                 if(ndone_iter == 0 && tol == thresh){
253                     if(doprint)
254                         print("Boys localization converged in", ndone,"steps");
255 
256                     converged = true;
257                     break;
258                 }
259                 tol = std::max(0.1 * maxtheta, thresh);
260             }
261 
262             if(!converged){
263                 print("warning: boys localization did not fully converge: ", ndone);
264             }
265             U = transpose(U);
266 
267 	    bool switched = true;
268 	    while (switched) {
269 	      switched = false;
270 	      for (int i=0; i<nmo; i++) {
271 		for (int j=i+1; j<nmo; j++) {
272 		  if (aset[i] == aset[j]) {
273 		    double sold = U(i,i)*U(i,i) + U(j,j)*U(j,j);
274 		    double snew = U(i,j)*U(i,j) + U(j,i)*U(j,i);
275 		    if (snew > sold) {
276 		      real_tensor tmp = copy(U(_,i));
277 		      U(_,i) = U(_,j);
278 		      U(_,j) = tmp;
279 		      switched = true;
280 		    }
281 		  }
282 		}
283 	      }
284 	    }
285 
286         // Fix phases.
287         for (long i=0; i<nmo; ++i) {
288             if (U(i,i) < 0.0) U(_,i).scale(-1.0);
289         }
290 
291         }
292 
293         world.gop.broadcast(U.ptr(), U.size(), 0);
294         //END_TIMER(world, "Boys localize");
295         return U;
296     }
297 };
298 
299 // Main mini MolDFT class
300 class MiniDFT {
301 private:
302     Molecule molecule;
303     AtomicBasisSet aobasis;
304     BoysLocalization boys;
305     XCfunctional xc;
306 
307 
308 public:
MiniDFT(double thresh,int kwavelet,int truncate_mode,double boxsize,const Molecule & molecule)309     MiniDFT(double              thresh,
310             int                 kwavelet,
311             int                 truncate_mode,
312             double              boxsize,
313             const Molecule&     molecule) : molecule(molecule) {
314         FunctionDefaults<3>::set_thresh(thresh);
315         FunctionDefaults<3>::set_k(kwavelet);
316         FunctionDefaults<3>::set_cubic_cell(-boxsize,boxsize);
317         FunctionDefaults<3>::set_truncate_mode(truncate_mode);
318 
319 	std::string xc_data;
320 	//xc_data="lda";
321         xc_data = "GGA_X_PBE 1.0 GGA_C_PBE 1.0";
322 	//xc_data="GGA_X_PBE 1.";
323 	//xc_data="GGA_C_PBE 1.";
324 	//xc_data="GGA_X_B88 1.";
325 	xc.initialize(xc_data, false, world);
326     }
327 
328     // Make the atomic basis functions
makeao(World & world,const Molecule & molecule)329     vector_real_function_3d makeao(World& world, const Molecule& molecule) {
330         aobasis.atoms_to_bfn(molecule, at_to_bf, at_nbf);
331         vector_real_function_3d ao(aobasis.nbf(molecule));
332         for(int i = 0; i<aobasis.nbf(molecule); ++i) {
333             real_functor_3d aofunc(new AtomicBasisFunctor<double>(aobasis.get_atomic_basis_function(molecule, i)));
334             ao[i] = real_factory_3d(world).functor(aofunc).truncate_on_project().nofence().truncate_mode(0);
335             AtomicBasisFunction atbf = aobasis.get_atomic_basis_function(molecule, i);
336         }
337         world.gop.fence();
338         truncate(world, ao);
339         normalize(world, ao);
340         print_meminfo(world.rank(), "makeao");
341 
342         return ao;
343     }
344 
345     // Kinetic energy matrix (for the Fock matrix)
kinetic_energy_matrix(World & world,const vector_real_function_3d & v)346     real_tensor kinetic_energy_matrix(World& world, const vector_real_function_3d& v)
347     {
348         std::vector< std::shared_ptr<real_derivative_3d> > gradop = gradient_operator<double,3>(world);
349         reconstruct(world, v);
350         auto n = v.size();
351         real_tensor r(n, n);
352         for(int axis = 0;axis < 3;++axis){
353             vector_real_function_3d dv = apply(world, *(gradop[axis]), v);
354             r += matrix_inner(world, dv, dv, true);
355             dv.clear();
356         }
357         return r.scale(0.5);
358     }
359 
360     // Apply a (local) potential to the orbitals
apply_potential(World & world,const real_function_3d & potential,const vector_real_function_3d & psi)361     vector_real_function_3d apply_potential(World& world, const real_function_3d& potential, const vector_real_function_3d& psi)
362     {
363         return mul_sparse(world,potential,psi,FunctionDefaults<3>::get_thresh()*0.01);
364     }
365 
366     // Construct simple LDA exchange-correlation potential
make_lda_potential(World & world,const real_function_3d & rho)367     real_function_3d make_lda_potential(World& world, const real_function_3d &rho)
368     {
369         auto vlda = copy(rho);
370         vlda.reconstruct();
371         vlda.unaryop(xc_lda_potential());
372         return vlda;
373     }
374 
375     // Solve free-space Poisson's equation for a given charge density
make_coulomb_potential(World & world,const real_function_3d & rho)376     real_function_3d make_coulomb_potential(World& world, const real_function_3d& rho)
377     {
378         auto thresh = FunctionDefaults<3>::get_thresh();
379         auto op = CoulombOperator(world, 1e-10, thresh);
380         return op(rho);
381     }
382 
383     // BSH operators
make_bsh_operators(World & world,const real_tensor & evals,double shift)384     vector<poperatorT> make_bsh_operators(World& world, const real_tensor& evals, double shift)
385     {
386         auto thresh = FunctionDefaults<3>::get_thresh();
387         auto nmo = evals.dim(0);
388         vector<poperatorT> ops(nmo);
389         for(int i = 0;i < nmo; ++i){
390             auto eps = evals(i) + shift;
391             ops[i] = poperatorT(BSHOperatorPtr3D(world, sqrt(-2.0 * eps),  1e-10, thresh));
392         }
393         return ops;
394     }
395 
396     // orthogonalize orbitals using Gram-Schmidt
397     template<typename Q>
orthogonalize(World & world,std::vector<Function<Q,3>> & psi)398     void orthogonalize(World& world, std::vector<Function<Q,3> >& psi) {
399         compress(world, psi);
400         for (unsigned int i = 0; i < psi.size(); i++) {
401             Function<Q,3>& psi_i = psi[i];
402             psi_i.scale(1.0/psi_i.norm2());
403             for (unsigned int j = 0; j < i; j++) {
404                 Function<Q,3>& psi_j = psi[j];
405                 Q s = inner(psi_j,psi_i);
406                 psi_i.gaxpy(1.0,psi_j,-s); // |i> = |i> - |j><j|i>
407                 psi_i.scale(1.0/psi_i.norm2());
408             }
409         }
410     }
411 
412 
413     // DESTROYS VPSI
update(World & world,const vector_real_function_3d & psi,vector_real_function_3d & vpsi,const real_tensor & e,int iter,double & ravg)414     vector_real_function_3d update(World&                            world,
415                                    const vector_real_function_3d&    psi,
416                                    vector_real_function_3d&          vpsi,
417                                    const real_tensor&                e,
418                                    int                               iter,
419                                    double&                           ravg)
420     {
421         // psi = - 2 G(E+shift) * (V+shift) psi
422         int nmo = psi.size();
423 
424         // determine shift to make homo <=-0.1
425         auto shift = 0.0;
426         if (e(nmo-1) > -0.1) {
427             shift = -0.1 - e(nmo-1);
428             gaxpy(world, 1.0, vpsi, shift, psi);
429             print("shifting vpsi by ", shift);
430         }
431 
432         // Do the BSH thing
433         scale(world, vpsi, -2.0);
434         truncate(world, vpsi);
435         vector<poperatorT> ops = make_bsh_operators(world, e, shift);
436         vector_real_function_3d new_psi = apply(world, ops, vpsi);
437 
438         // Step restriction
439         auto damp = 0.2;
440         //if (iter < 10) damp = 0.95;
441         //else if (iter < 20) damp = 0.85;
442         //else damp = 0.75;
443         //print("  shift", shift, "damp", damp, "\n");
444 
445         printf("      eigenvalue    residual\n");
446         ravg = 0.0;
447         for (int i=0; i<nmo; i++) {
448             double rnorm = (psi[i]-new_psi[i]).norm2();
449             ravg += rnorm/(double)nmo;
450             printf("%4d  %15.10f  %18.6e\n", i, e[i], rnorm);
451             new_psi[i] = damp*psi[i] + (1.0-damp)*new_psi[i];
452         }
453 
454         truncate(world,new_psi);
455         normalize(world, new_psi);
456         orthogonalize<double>(world, new_psi);
457         truncate(world,new_psi);
458         normalize(world, new_psi);
459         return new_psi;
460     }
461 
462     // Construct charge density from the orbitals
make_density(World & world,const vector_real_function_3d & v)463     real_function_3d make_density(World& world, const vector_real_function_3d& v) {
464 
465        auto vsq = square(world, v);
466        compress(world, vsq);
467        real_function_3d rho = real_factory_3d(world);
468        rho.compress();
469        for(unsigned int i = 0;i < vsq.size();++i){
470          rho.gaxpy(1.0, vsq[i], 2.0, false);
471 
472        }
473        world.gop.fence();
474        vsq.clear();
475        return rho;
476     }
477 
478     // main routine of class
doit(World & world)479     void doit(World& world) {
480 
481         aobasis.read_file("6-31g");
482 
483         bool do_psp = true;
484 
485         auto kwavelet = FunctionDefaults<3>::get_k();
486         auto thresh = FunctionDefaults<3>::get_thresh();
487         if (world.rank() == 0) printf("wavelet order: %d\n", kwavelet);
488         if (world.rank() == 0) printf("thresh: %15.4e\n", thresh);
489 
490         // Nuclear potential (don't need if using pseudopotential)
491         //real_function_3d vnuc = real_factory_3d(world).functor(real_functor_3d(
492         //  new NuclearDensityFunctor(molecule))).truncate_mode(0).truncate_on_project();
493         auto safety = 0.1;
494         auto vtol = FunctionDefaults<3>::get_thresh() * safety;
495 
496         real_function_3d vnuc;
497         if (! do_psp){
498           vnuc = real_factory_3d(world).functor(real_functor_3d(
499             new MolecularPotentialFunctor(molecule))).thresh(vtol).truncate_on_project();
500           vnuc.reconstruct();
501           print("total nuclear charge", vnuc.trace());
502         }
503         //vnuc = -1.0*make_coulomb_potential(world, vnuc);
504 
505         // Create pseudopotential
506         GTHPseudopotential<double> ppotential(world, molecule);
507         if (do_psp){
508           ppotential.make_pseudo_potential(world);
509         }
510 
511         // Guess density
512         real_function_3d rho = real_factory_3d(world).functor(real_functor_3d(
513           new MolecularGuessDensityFunctor(molecule,aobasis))).truncate_on_project();
514         double nel = rho.trace();
515         if(world.rank() == 0)
516             print("guess dens trace", nel);
517         int nmo = int(molecule.total_nuclear_charge() + 0.1)/2;
518         rho.scale((2.0*nmo)/nel);
519 
520         // Make AO basis functions
521         auto psi = makeao(world, molecule);
522         auto norms = norm2s(world, psi);
523 
524         double ravg = 10000.0;
525         for (int iter=0; iter<100 && ravg > 1e-6; iter++) {
526 
527             bool doboys = false;
528             if (doboys) {
529                 if (iter==1) {
530                     boys.set_size(psi.size());
531                 }
532                 if (iter > 0) {
533                     real_tensor U = boys(world, psi);
534                     print(U);
535                 }
536             }
537 
538             print("\n\n  Iteration",iter,"\n");
539             auto rtr = rho.trace();
540             print("rho trace:  ", rtr);
541 
542             WSTFunctional wstf;
543             real_function_3d rho_half = 0.5 * rho;
544             std::pair<real_function_3d, double> pair_xc = wstf.apply_xc(world,xc,rho_half);
545             real_function_3d vxc = pair_xc.first;
546             real_function_3d vxc2 = make_lda_potential(world,rho);
547             double exc = pair_xc.second;
548 
549             vector_real_function_3d vpsi;
550             if (!do_psp){
551               real_function_3d v = vnuc + make_coulomb_potential(world,rho) + vxc;
552               vpsi = apply_potential(world, v, psi);
553             }
554             else{
555               double enl=0.0;
556               tensorT occ = tensorT(nmo);
557               for(int i = 0;i < nmo;++i)
558                   occ[i] = 1.0;
559               auto v = make_coulomb_potential(world,rho) + vxc + ppotential.vlocalp;
560               vpsi = ppotential.apply_potential(world, v, psi, occ, enl);
561             }
562 
563             bool doplots = false;
564             /*if (doplots) {
565                 char rho_name[25]; sprintf(rho_name, "rho_%d.dat", iter);
566                 char vxc_name[25]; sprintf(vxc_name, "vxc_%d.dat", iter);
567                 char vxc2_name[25]; sprintf(vxc2_name, "vxc2_%d.dat", iter);
568                 char v_name[25]; sprintf(v_name, "v_%d.dat", iter);
569                 int ppnts = 5001;
570                 plot_line(rho_name, ppnts, {0.0,0.0,-50.0}, {0.0,0.0,50.0}, rho);
571                 plot_line(vxc_name, ppnts, {0.0,0.0,-50.0}, {0.0,0.0,50.0}, vxc);
572                 plot_line(vxc2_name, ppnts, {0.0,0.0,-50.0}, {0.0,0.0,50.0}, vxc2);
573                 plot_line(v_name, ppnts, {0.0,0.0,-50.0}, {0.0,0.0,50.0}, v);
574             }*/
575 
576             auto ke_mat = kinetic_energy_matrix(world, psi);
577             auto pe_mat = matrix_inner(world, psi, vpsi, true);
578             auto ov_mat = matrix_inner(world, psi, psi, true);
579 
580             auto fock = ke_mat + pe_mat;
581             fock = 0.5*(fock + transpose(fock));
582 
583             real_tensor c;
584             tensor_real e;
585             sygv(fock, ov_mat, 1, c, e);
586             double rfactor = 1e-3;
587             for (int i = 0; i < fock.dim(0); i++)
588             {
589               auto thresh = FunctionDefaults<3>::get_thresh();
590               for (int j = 0; j < fock.dim(1); j++)
591               {
592                 if (std::abs(ov_mat(i,j)) < thresh*rfactor) ov_mat(i,j) = 0.0;
593                 if (std::abs(ke_mat(i,j)) < thresh*rfactor) ke_mat(i,j) = 0.0;
594                 if (std::abs(pe_mat(i,j)) < thresh*rfactor) pe_mat(i,j) = 0.0;
595                 if (std::abs(fock(i,j)) < thresh*0.1) fock(i,j) = 0.0;
596               }
597             }
598             if (world.rank() == 0) {
599               print("Kinetic (real part)");
600               print(ke_mat);
601               print("Potential (real part)");
602               print(pe_mat);
603               print("Fock (real part)");
604               print(fock);
605               print("eigenvalues"); print(e);
606             }
607 
608             if (iter == 0) {
609                 c = copy(c(_,Slice(0,nmo-1))); // truncate to occupied states
610                 e = e(Slice(0,nmo-1));
611             }
612 
613             auto trantol = vtol / std::min(30.0, double(psi.size()));
614             psi = transform(world, psi, c, trantol, true);
615             vpsi = transform(world, vpsi, c, trantol, true);
616 
617             psi = update(world, psi, vpsi, e, iter, ravg);
618             truncate(world, psi);
619 
620             auto rthresh = 50.0*thresh;
621             if (ravg < rthresh) {
622               print("reprojecting ...");
623               kwavelet += 2;
624               thresh /= 100.0;
625               FunctionDefaults<3>::set_k(kwavelet);
626               FunctionDefaults<3>::set_thresh(thresh);
627               if (!do_psp){
628                 vnuc = madness::project(vnuc, kwavelet, thresh, true);}
629               else{
630                 ppotential.reproject(kwavelet, thresh);}
631               for (int i = 0; i < nmo; i++) psi[i] = madness::project(psi[i], kwavelet, thresh, true);
632             }
633 
634             //int md = psi[3].max_depth();
635             //print("max depth:  ", md);
636 
637             rho = make_density(world, psi);
638         }
639     }
640 
641 };
642 
main(int argc,char ** argv)643 int main(int argc, char** argv) {
644     initialize(argc, argv);
645     World world(SafeMPI::COMM_WORLD);
646     startup(world,argc,argv);
647     std::cout.precision(9);
648 
649     Molecule molecule;
650 
651     //print("Env: MADNESS_HAS_LIBXC =      ", MADNESS_HAS_LIBXC);
652 
653     // Hydrogen atom
654     // Also for hydrogen need to make changes to nmo (set to 1)
655     // and make_density (multiply by 1.0 instead of 2.0)
656     //molecule.add_atom(0.0, 0.0, 0.0, 1.0, 1);
657 
658     // Hydrogen molecule
659     //molecule.add_atom(0.0, 0.0, 0.72372451, 1.0, 1);
660     //molecule.add_atom(0.0, 0.0, -0.72372451, 1.0, 1);
661 
662     // Helium atom
663     //molecule.add_atom(0.0, 0.0, 0.0, 2.0, 2);
664     //molecule.add_atom(0.0, 0.0, 5.0, 2.0, 2);
665 
666     // Neon atom
667     //molecule.add_atom(0, 0, 0, 8.0, 10);
668 
669     // Argon atom
670     //molecule.add_atom(0, 0, 0, 8.0, 18);
671 
672     // Calcium atom
673     //molecule.add_atom(0, 0, 0, 2.0, 20);
674 
675     // Silicon atom
676     //molecule.add_atom(0, 0, 0, 4.0, 14);
677 
678     // Carbon atom
679     //molecule.add_atom(0, 0, 0, 4.0, 6);
680 
681     // Oxygen atom
682     //molecule.add_atom(0.0, 0.0, 2.286, 6.0, 8);
683 
684     // Beryllium atom (at arbitrary location)
685     //molecule.add_atom(1.23943, -0.3422, 5, 2.0, 4);
686 
687     // Water (doesn't work)
688     //molecule.add_atom( 1.4375, 0, 1.15, 1.0, 1);
689     //molecule.add_atom(-1.4375, 0, 1.15, 1.0, 1);
690     //molecule.add_atom(0, 0, 0, 8.0, 8);
691 
692     // H2
693     molecule.add_atom(0.0, 0.0,  0.7  , 1.0, 1);
694     molecule.add_atom(0.0, 0.0, -0.7  , 1.0, 1);
695 
696     // CO2 (doesn't work)
697     //molecule.add_atom(0.0, 0.0, 0.0, 4.0, 6);
698     //molecule.add_atom(0.0, 0.0, 2.24064, 6.0, 8);
699     //molecule.add_atom(0.0, 0.0, -2.24064, 6.0, 8);
700 
701     // O2 (doesn't work)
702     //molecule.add_atom(0.0, 0.0, 0.0  , 8.0, 8);
703     //molecule.add_atom(0.0, 0.0, 2.286, 8.0, 8);
704 
705     molecule.orient();
706     molecule.set_eprec(1e-5);
707 
708     molecule.print();
709 
710     // MRA parameters
711     double thresh = 1e-4;
712     int kwavelet = 6;
713     int truncate_mode = 0;
714     double L = 50.0;
715 
716     MiniDFT dft(thresh, kwavelet, truncate_mode, L, molecule);
717     dft.doit(world);
718     return 0;
719 }
720 
721