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