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 
32   $Id$
33 */
34 
35 /// \file test6.cc
36 /// \brief test various functionality for 6d functions
37 
38 #include <madness/mra/mra.h>
39 
40 using namespace madness;
41 
ok(const bool b)42 std::string ok(const bool b) {if (b) return "ok   "; return "fail ";};
43 
check_small(const double val,const double eps,const std::string message)44 int check_small(const double val, const double eps, const std::string message) {
45 	bool is_small=(fabs(val)<eps);
46 	print(ok(is_small),val,message);
47 	return (is_small) ? 0 : 1;
48 }
49 
check(bool b,const std::string message)50 int check(bool b, const std::string message) {
51 	print(ok(b),message);
52 	return (b) ? 0 : 1;
53 }
54 
is_small(const double & val,const double & eps)55 bool is_small(const double& val, const double& eps) {
56 	return (val<eps);
57 }
58 
59 
is_large(const double & val,const double & eps)60 bool is_large(const double& val, const double& eps) {
61 	return (val>eps);
62 }
63 
64 template<size_t NDIM>
load_function(World & world,Function<double,NDIM> & pair,const std::string name)65 void load_function(World& world, Function<double,NDIM>& pair, const std::string name) {
66     if (world.rank()==0)  print("loading function ", name);
67 
68     archive::ParallelInputArchive ar(world, name.c_str());
69     ar & pair;
70 
71     FunctionDefaults<3>::set_k(pair.k());
72     FunctionDefaults<6>::set_k(pair.k());
73 
74     FunctionDefaults<3>::set_thresh(pair.thresh());
75     FunctionDefaults<6>::set_thresh(pair.thresh());
76 
77     std::string line="loaded function "+name;
78     pair.print_size(line);
79 
80 }
81 
82 template<size_t NDIM>
save_function(World & world,Function<double,NDIM> & pair,const std::string name)83 void save_function(World& world, Function<double,NDIM>& pair, const std::string name) {
84     if (world.rank()==0)  print("saving function ", name);
85 
86     archive::ParallelOutputArchive ar(world, name.c_str());
87     ar & pair;
88 
89     std::string line="saved function "+name;
90     pair.print_size(line);
91 
92 }
93 
94 
one_3d(const coord_3d & r)95 static double one_3d(const coord_3d& r) {
96 	return 1.0;
97 }
98 
zero_3d(const coord_3d & r)99 static double zero_3d(const coord_3d& r) {
100 	return 0.0;
101 }
102 
one_6d(const coord_6d & r)103 static double one_6d(const coord_6d& r) {
104 	return 1.0;
105 }
106 
gauss_3d(const coord_3d & r)107 static double gauss_3d(const coord_3d& r) {
108     const double x=r[0], y=r[1], z=r[2];
109     const double r2= sqrt(x*x + y*y + z*z);
110     const double norm=0.712705695388313;
111     return norm*exp(-r2);
112 }
113 
tightgauss_3d(const coord_3d & r)114 static double tightgauss_3d(const coord_3d& r) {
115     const double x=r[0], y=r[1], z=r[2];
116     const double r2= sqrt(x*x + y*y + z*z);
117     const double norm=0.712705695388313;
118     return norm*exp(-2.0*r2);
119 }
120 
gauss_plus_one_3d(const coord_3d & r)121 static double gauss_plus_one_3d(const coord_3d& r) {
122     return gauss_3d(r)+one_3d(r);
123 }
gauss_plus_tight_3d(const coord_3d & r)124 static double gauss_plus_tight_3d(const coord_3d& r) {
125     return gauss_3d(r)+tightgauss_3d(r);
126 }
127 
128 
gauss_6d(const coord_6d & r)129 static double gauss_6d(const coord_6d& r) {
130     coord_3d r1, r2;
131     r1[0]=r[0],    r1[1]=r[1],    r1[2]=r[2];
132     r2[0]=r[3],    r2[1]=r[4],    r2[2]=r[5];
133     return gauss_3d(r1)*gauss_3d(r2);
134 }
135 
136 
r2r(const coord_6d & r)137 static double r2r(const coord_6d& r) {
138     coord_3d r1, r2;
139     r1[0]=r[0],    r1[1]=r[1],    r1[2]=r[2];
140     r2[0]=r[3],    r2[1]=r[4],    r2[2]=r[5];
141     double g1=gauss_3d(r1);
142     return g1*g1*gauss_3d(r2);
143 }
144 
145 //static double add_test(const coord_6d& r) {
146 //    coord_3d r1, r2;
147 //    r1[0]=r[0],    r1[1]=r[1],    r1[2]=r[2];
148 //    r2[0]=r[3],    r2[1]=r[4],    r2[2]=r[5];
149 //    double g1=gauss_3d(r1);
150 //    double g2=gauss_3d(r2);
151 //
152 //    return g1*g2 + g1*g1*g2;
153 //}
154 
V(const Vector<double,3> & r)155 static double V(const Vector<double,3>& r) {
156   return -1.0/sqrt(r[0]*r[0]+r[1]*r[1]+r[2]*r[2]+1e-12);
157 }
158 
159 /// test f(1,2) = g(1) h(2)
test_hartree_product(World & world,const long & k,const double thresh)160 int test_hartree_product(World& world, const long& k, const double thresh) {
161 
162 	print("entering hartree_product");
163 	int nerror=0;
164 	bool good;
165 
166     real_function_3d phi=real_factory_3d(world).f(gauss_3d);
167     real_function_3d phisq=phi*phi;
168 
169     {
170         real_function_6d ij=hartree_product(phi,phi);
171         ij.truncate();
172 
173         double norm=ij.norm2();
174         print("norm(ij)",norm);
175 
176         double err=ij.err(gauss_6d);
177         good=is_small(err,thresh);
178         print(ok(good), "hartree_product(phi,phi) error:",err);
179         if (not good) nerror++;
180 
181     }
182 
183     {
184         real_function_6d ij=hartree_product(phisq,phi);
185         double err=ij.err(r2r);
186         good=is_small(err,thresh);
187         print(ok(good), "hartree_product(phi^2,phi) error:",err);
188         if (not good) nerror++;
189     }
190 
191 	print("all done\n");
192 	return nerror;
193 }
194 
195 /// test f(1,2)*g(1)
test_multiply(World & world,const long & k,const double thresh)196 int test_multiply(World& world, const long& k, const double thresh) {
197 
198     print("entering multiply f(1,2)*g(1)");
199     int nerror=0;
200     bool good;
201 
202     real_function_6d f12=TwoElectronFactory(world).f12().thresh(thresh).gamma(1.0);
203 
204 
205     const real_function_3d phi=real_factory_3d(world).f(gauss_3d);
206     const real_function_3d phisq=phi*phi;
207 
208     real_function_6d fii=CompositeFactory<double,6,3>(world)
209     	    	.particle1(copy(phi))
210     	    	.particle2(copy(phi))
211     	    	.g12(f12);
212     real_function_6d fi2i=CompositeFactory<double,6,3>(world)
213     	    	.particle1(copy(phisq))
214     	    	.particle2(copy(phi))
215     	    	.g12(f12);
216 
217     real_function_6d fii2=CompositeFactory<double,6,3>(world)
218                 .particle1(copy(phi))
219                 .particle2(copy(phisq))
220                 .g12(f12);
221 
222 
223     if (1) {
224     	fii.fill_tree();
225     	save_function(world,fii,"fii");
226     	fi2i.fill_tree();
227     	save_function(world,fi2i,"fi2i");
228         fii2.fill_tree();
229         save_function(world,fii2,"fii2");
230 
231     } else {
232     	load_function(world,fii,"fii");
233         load_function(world,fi2i,"fi2i");
234     	load_function(world,fii2,"fii2");
235     }
236     fii.print_size("f12 |phi phi>");
237     fi2i.print_size("f12 |phi^2 phi>");
238     fii2.print_size("f12 |phi phi^2>");
239 
240 
241     real_function_6d iij1=multiply(copy(fii),phi,1);
242     iij1.print_size("multiply 1");
243     iij1.truncate().reduce_rank();
244     iij1.print_size("multiply 1 truncated");
245     double err=(fi2i-iij1).norm2();
246     good=is_small(err,thresh);
247     print(ok(good), "multiply f(1,2)*g(1) error:",err);
248 
249     {
250         real_function_6d iij2=multiply(copy(fii),phi,2);
251         iij2.print_size("multiply 2");
252         iij2.truncate().reduce_rank();
253         iij2.print_size("multiply 2 truncated");
254         double err=(fii2-iij2).norm2();
255         good=is_small(err,thresh);
256         print(ok(good), "multiply f(1,2)*g(2) error:",err);
257     }
258 
259 
260 
261     real_function_6d iij3=CompositeFactory<double,6,3>(world)
262     	    	.ket(copy(fii)).V_for_particle1(copy(phi));
263     iij3.fill_tree();
264     iij3.print_size("CompositeFactory");
265     iij3.truncate();
266     iij3.print_size("CompositeFactory truncated");
267 
268     double err4=(fi2i-iij3).norm2();
269     print("error in CompositeFactory 1",err4);
270     good=is_small(err4,thresh);
271     print(ok(good), "CompositeFactory f(1,2)*g(1) error:",err4);
272 
273 
274     if (not good) nerror++;
275 
276     print("all done\n");
277     return nerror;
278 }
279 
280 /// test f(1,2) + g(1,2) for both f and g reconstructed
test_add(World & world,const long & k,const double thresh)281 int test_add(World& world, const long& k, const double thresh) {
282 
283     print("entering add");
284     int nerror=0;
285 
286     // simple test for 3d functions and different adding schemes
287     real_function_3d one3=real_factory_3d(world).f(one_3d);
288     real_function_3d gauss3=real_factory_3d(world).f(gauss_3d);
289     real_function_3d gauss_plus_one3=real_factory_3d(world).f(gauss_plus_one_3d);
290 
291     {
292     	real_function_3d r1=one3+gauss3;
293     	double error1=r1.err(gauss_plus_one_3d);
294     	nerror+=check_small(error1,thresh,"operator+");
295     }
296     {
297     	real_function_3d r1=one3+gauss3;	// this has been checked before
298     	real_function_3d r2=r1-gauss_plus_one3;
299     	double error2=r2.err(zero_3d);
300     	nerror+=check_small(error2,thresh,"operator-");
301     }
302     {
303     	one3.compress(); gauss3.compress();
304     	real_function_3d r3=gaxpy_oop(1.0,one3,1.0,gauss3);
305     	nerror+=check(r3.is_compressed(),"is compressed");
306     	double error3=r3.err(gauss_plus_one_3d);
307     	nerror+=check_small(error3,thresh,"gaxpy_oop add");
308     }
309     {
310     	one3.reconstruct(); gauss3.reconstruct();
311     	real_function_3d r4=gaxpy_oop_reconstructed(1.0,one3,1.0,gauss3);
312     	nerror+=check(!r4.is_compressed(),"is reconstructed");
313     	double error4=r4.err(gauss_plus_one_3d);
314     	nerror+=check_small(error4,thresh,"gaxpy_oop_reconstructed");
315     }
316     {
317     	real_function_3d r=copy(one3);
318     	r.compress(); gauss3.compress();
319     	r+=gauss3;
320     	nerror+=check(r.is_compressed(),"is reconstructed");
321     	double error1=r.err(gauss_plus_one_3d);
322     	nerror+=check_small(error1,thresh,"operator+=, compressed");
323     }
324     {
325     	real_function_3d r=copy(one3);
326     	r.reconstruct(); gauss3.reconstruct();
327     	r+=gauss3;
328     	nerror+=check(r.is_compressed(),"is reconstructed");
329     	double error1=r.err(gauss_plus_one_3d);
330     	nerror+=check_small(error1,thresh,"operator+=, reconstructed");
331     }
332     {
333     	one3.reconstruct(); gauss3.reconstruct();
334     	real_function_3d r=gaxpy_oop_reconstructed(1.0,one3,-1.0,gauss3);
335     	nerror+=check(!r.is_compressed(),"is reconstructed");
336     	real_function_3d r2=one3-gauss3;
337     	double error=(r-r2).norm2();
338     	nerror+=check_small(error,thresh,"gaxpy_oop_reconstructed subtract");
339     }
340     {
341     	real_function_3d r=copy(gauss3);
342     	r.reconstruct(); gauss3.reconstruct();
343     	r.add_scalar(1.0);
344     	nerror+=check(!r.is_compressed(),"is reconstructed");
345     	double error1=r.err(gauss_plus_one_3d);
346     	nerror+=check_small(error1,thresh,"add_scalar");
347     }
348 
349 
350     // 6d tests; mainly consistency checks since err() function is very expensive in 6d
351     real_function_6d f=hartree_product(gauss3,gauss3);
352     real_function_6d one6=real_factory_6d(world).f(one_6d);
353 
354     {
355     	real_function_6d r=copy(f);
356     	r.add_scalar(1.0);
357     	real_function_6d r2=one6+f;
358     	double error=(r2-r).norm2();
359     	nerror+=check_small(error,thresh,"6d add_scalar/operator+/-");
360     }
361     {
362         real_function_3d tightgauss3=real_factory_3d(world).f(tightgauss_3d);
363         real_function_3d gauss_plus_tight3=real_factory_3d(world).f(gauss_plus_tight_3d);
364 
365     	real_function_6d r=hartree_product(gauss_plus_tight3,gauss_plus_tight3);
366     	real_function_6d r1=hartree_product(gauss3,gauss3);
367     	real_function_6d r2=hartree_product(gauss3,tightgauss3);
368     	real_function_6d r22=hartree_product(tightgauss3,gauss3);
369     	r22+=r2;
370     	r22.scale(0.5);
371     	real_function_6d r3=hartree_product(tightgauss3,tightgauss3);
372     	real_function_6d r4=gaxpy_oop_reconstructed(1.0,r,-2.0,r22)-r1-r3;
373     	double error=r4.norm2();
374     	nerror+=check_small(error,1.5*thresh,"6d gaxpy_oop_reconstructed/operator+=/operator- note loosened threshold");
375     }
376 
377     print("all done\n");
378     return nerror;
379 }
380 
381 
382 /// test f(1,2) + g(1,2) for both f and g reconstructed
test_exchange(World & world,const long & k,const double thresh)383 int test_exchange(World& world, const long& k, const double thresh) {
384 
385     print("entering exchange f(1,2)*g(1)");
386     int nerror=0;
387     bool good;
388 
389     double norm;
390     real_function_3d phi=real_factory_3d(world).f(gauss_3d);
391 
392 
393     real_convolution_3d poisson = CoulombOperator(world,0.0001,thresh);
394 
395     real_function_3d rho = 2.0*phi*phi;
396     real_function_3d coulombpot=poisson(rho);
397 
398 
399     real_function_6d f=2.0*hartree_product(phi,phi);
400     real_function_6d f2=multiply(f,phi,1);
401     f2.print_size("f2 after apply");
402     norm=f2.norm2();
403     if (world.rank()==0) print("f2 norm",norm);
404     real_function_6d x=poisson(f2);
405 
406     x.print_size("x after apply");
407     norm=x.norm2();
408     if (world.rank()==0) print("x norm",norm);
409     x=multiply(x,phi,1);
410     x.print_size("x after multiply");
411     norm=x.norm2();
412     if (world.rank()==0) print("x norm",norm);
413 
414 
415     real_function_6d tmp=0.5*multiply(f,coulombpot,1);
416     tmp.print_size("tmp after multiply");
417     norm=tmp.norm2();
418     if (world.rank()==0) print("tmp norm",norm);
419 
420     real_function_6d diff=tmp-x;
421     diff.print_size("diff");
422     norm=diff.norm2();
423     if (world.rank()==0) print("diff norm",norm);
424     good=is_small(norm,thresh);
425     print(ok(good), "exchange error:",norm);
426     if (not good) nerror++;
427 
428     // do only orbital
429     real_function_3d tmp2=phi*coulombpot;
430     tmp2.print_size("J phi after multiply");
431     norm=tmp2.norm2()*phi.norm2();
432     if (world.rank()==0) print("J phi norm",norm);
433 
434 
435 
436     print("all done\n");
437     return nerror;
438 }
439 
440 /// test inner product using redundant wave functions
test_inner(World & world,const long & k,const double thresh)441 int test_inner(World& world, const long& k, const double thresh) {
442 
443     print("entering inner");
444     int nerror=0;
445     bool good;
446 
447     double norm;
448     real_function_3d phi=real_factory_3d(world).f(gauss_3d);
449     real_function_3d phi2=phi*phi;
450 
451     real_function_6d f1=hartree_product(phi,phi);
452     real_function_6d f2=hartree_product(phi,phi2);
453 
454     double a1=inner(f1,f2);
455     double a2=inner(phi,phi) * inner(phi,phi2);
456     norm=a1-a2;
457 
458     if (world.rank()==0) print("diff norm",norm);
459     good=is_small(norm,thresh);
460     print(ok(good), "inner error:",norm);
461     if (not good) nerror++;
462 
463     print("all done\n");
464     return nerror;
465 }
466 
467 
468 /// test 6D convolution
test_convolution(World & world,const long & k,const double thresh)469 int test_convolution(World& world, const long& k, const double thresh) {
470 
471     print("entering convolution");
472     int nerror=0;
473     bool good;
474 
475     double eps=-0.5;
476 
477     // solve the 3D H-atom
478     real_function_3d phi=real_factory_3d(world).f(gauss_3d);
479     const real_function_3d v=real_factory_3d(world).f(V);
480 	real_function_3d vphi=v*phi;
481 
482     v.print_size("v");
483 //    real_convolution_3d poisson = CoulombOperator(world,0.0001,thresh);
484     real_convolution_3d green = BSHOperator<3>(world, sqrt(-2.0*eps), 1.e-8, 1.e-6);
485 
486     for (int i=0; i<10; ++i) {
487 
488     	vphi=v*phi;
489     	double PE=inner(vphi,phi);
490     	print("<phi | V | phi>: ",PE);
491 
492     	real_derivative_3d Dx = free_space_derivative<double,3>(world,0);
493     	Function<double,3> du = Dx(phi);
494     	double KE = 3*0.5*(du.inner(du));
495     	print("<phi | T | phi>: ",KE);
496     	print("<phi | H | phi>: ",KE + PE);
497 
498 
499     	phi=green(-2.0*vphi);
500     	double norm=phi.norm2();
501     	phi.scale(1.0/norm);
502     	print("phi.norm2()",norm);
503     }
504 
505     vphi=v*phi;
506     double PE=inner(vphi,phi);
507    	print("<phi | V | phi>: ",PE);
508 
509     // solve the H-atom in 6D
510     real_convolution_6d green6 = BSHOperator<6>(world, sqrt(-2.0*(eps+eps)), 1.e-8, 1.e-6);
511 
512 	real_function_6d result1=-2.0*green6(copy(vphi),copy(phi)).truncate().reduce_rank();
513 	result1=result1-2.0*green6(copy(phi),copy(vphi)).truncate().reduce_rank();
514 	world.gop.fence();
515 
516 	double a=result1.norm2();
517 	if (world.rank()==0) print("<GVphi | GVphi> ",a);
518 
519 	real_function_6d diff=result1-hartree_product(phi,phi);
520 	double norm=diff.norm2();
521 
522     if (world.rank()==0) print("diff norm",norm);
523     good=is_small(norm,thresh);
524     print(ok(good), "inner error:",norm);
525     if (not good) nerror++;
526 
527     print("all done\n");
528     return nerror;
529 }
530 
531 
532 
533 
test(World & world,const long & k,const double thresh)534 int test(World& world, const long& k, const double thresh) {
535 
536     print("entering test");
537     int nerror=0;
538 
539     typedef Key<3> keyT;
540 
541     real_function_3d phi=real_factory_3d(world).f(gauss_3d);
542 
543 //    real_function_6d ij=hartree_product(phi,phi);
544     real_function_3d ij=phi;
545     ij.compress();
546 
547     // get the root NS coeffs
548     keyT key0=ij.get_impl()->get_cdata().key0;
549     GenTensor<double> NScoeff=(ij.get_impl()->get_coeffs().find(key0)).get()->second.coeff();
550 
551     {
552 		// convert NS coeffs to values directly
553 		GenTensor<double> val1=ij.get_impl()->NScoeffs2values(key0,NScoeff,false);
554 
555 		// convert NS coeffs to S coeffs, and then to values
556 		Tensor<double> Scoeff=ij.get_impl()->unfilter(NScoeff).full_tensor_copy();
557 		Tensor<double> val2(ij.get_impl()->get_cdata().v2k);
558 
559 		for (KeyChildIterator<3> kit(key0); kit; ++kit) {
560 			const keyT& child = kit.key();
561 			std::vector<Slice> cp = ij.get_impl()->child_patch(child);
562 			Tensor<double> child_s_coeff=Scoeff(cp);
563 			val2(cp)=ij.get_impl()->coeffs2values(child,child_s_coeff);
564 		}
565 
566 		Tensor<double> diff=val2-val1.full_tensor_copy();
567 		double error=diff.normf();
568 		print("error in NScoeff2values",error);
569     }
570 
571     {
572 		// convert S coeffs to values directly
573 		const std::vector<Slice>& s0=ij.get_impl()->get_cdata().s0;
574 		GenTensor<double> val1=ij.get_impl()->NScoeffs2values(key0,GenTensor<double>(NScoeff(s0)),true);
575 
576 		// convert NS coeffs to S coeffs, and then to values
577 		Tensor<double> Scoeff(ij.get_impl()->get_cdata().v2k);
578 		Scoeff(s0)=(NScoeff.full_tensor_copy()(s0));
579 		Scoeff=ij.get_impl()->unfilter(Scoeff);
580 		Tensor<double> val2(ij.get_impl()->get_cdata().v2k);
581 
582 		for (KeyChildIterator<3> kit(key0); kit; ++kit) {
583 			const keyT& child = kit.key();
584 			std::vector<Slice> cp = ij.get_impl()->child_patch(child);
585 			Tensor<double> child_s_coeff=Scoeff(cp);
586 			val2(cp)=ij.get_impl()->coeffs2values(child,child_s_coeff);
587 		}
588 
589 		Tensor<double> diff=val2-val1.full_tensor_copy();
590 		double error=diff.normf();
591 		print("error in Scoeff2values",error);
592     }
593 
594     {
595 		// convert S coeffs to values directly
596 		const std::vector<Slice>& s0=ij.get_impl()->get_cdata().s0;
597 		GenTensor<double> val1=ij.get_impl()->NS_fcube_for_mul(key0,key0,GenTensor<double>(NScoeff(s0)),true);
598 
599 		// convert NS coeffs to S coeffs, and then to values
600 		Tensor<double> Scoeff(ij.get_impl()->get_cdata().v2k);
601 		Scoeff(s0)=(NScoeff.full_tensor_copy()(s0));
602 		Scoeff=ij.get_impl()->unfilter(Scoeff);
603 		Tensor<double> val2(ij.get_impl()->get_cdata().v2k);
604 
605 		for (KeyChildIterator<3> kit(key0); kit; ++kit) {
606 			const keyT& child = kit.key();
607 			std::vector<Slice> cp = ij.get_impl()->child_patch(child);
608 			Tensor<double> child_s_coeff=Scoeff(cp);
609 			val2(cp)=ij.get_impl()->coeffs2values(child,child_s_coeff);
610 		}
611 
612 		Tensor<double> diff=val2-val1.full_tensor_copy();
613 		double error=diff.normf();
614 		print("error in NS_fcube_for_mul",error);
615     }
616 
617     {
618 		// convert NS coeffs to values directly
619 		GenTensor<double> val1=ij.get_impl()->NScoeffs2values(key0,NScoeff,false);
620 		GenTensor<double> coeff1=ij.get_impl()->values2NScoeffs(key0,val1);
621 		GenTensor<double> val2=ij.get_impl()->NScoeffs2values(key0,coeff1,false);
622 
623 		Tensor<double> diff=val2.full_tensor_copy()-val1.full_tensor_copy();
624 		double error=diff.normf();
625 		print("error in values2NScoeffs(NScoeff2values)",error);
626     }
627 
628     print("all done\n");
629     return nerror;
630 }
631 
632 
main(int argc,char ** argv)633 int main(int argc, char**argv) {
634 
635     initialize(argc,argv);
636     World world(SafeMPI::COMM_WORLD);
637     srand(time(nullptr));
638     startup(world,argc,argv);
639 
640     // the parameters
641     long k=5;
642     double thresh=1.e-3;
643     double L=16;
644     TensorType tt=TT_2D;
645 
646     // override the default parameters
647     for(int i = 1; i < argc; i++) {
648         const std::string arg=argv[i];
649 
650         // break parameters into key and val
651         size_t pos=arg.find("=");
652         std::string key=arg.substr(0,pos);
653         std::string val=arg.substr(pos+1);
654 
655         if (key=="size") L=atof(val.c_str());               // usage: size=10
656         if (key=="k") k=atoi(val.c_str());                  // usage: k=5
657         if (key=="thresh") thresh=atof(val.c_str());        // usage: thresh=1.e-3
658         if (key=="TT") {
659             if (val=="TT_2D") tt=TT_2D;
660             else if (val=="TT_FULL") tt=TT_FULL;
661             else if (val=="TT_TENSORTRAIN") tt=TT_TENSORTRAIN;
662             else {
663                 print("arg",arg, "key",key,"val",val);
664                 MADNESS_EXCEPTION("confused tensor type",0);
665             }
666 
667         }
668     }
669 
670     FunctionDefaults<3>::set_thresh(thresh);
671     FunctionDefaults<3>::set_k(k);
672     FunctionDefaults<3>::set_cubic_cell(-L/2,L/2);
673     FunctionDefaults<6>::set_thresh(thresh);
674     FunctionDefaults<6>::set_k(k);
675     FunctionDefaults<6>::set_cubic_cell(-L/2,L/2);
676     FunctionDefaults<6>::set_tensor_type(tt);
677 
678     print("entering testsuite for 6-dimensional functions\n");
679     print("k            ",k);
680     print("thresh       ",thresh);
681     print("boxsize      ",L);
682     print("tensor type: ", FunctionDefaults<6>::get_tensor_type());
683     print("");
684 
685 
686     int error=0;
687 
688     real_function_3d phi=real_factory_3d(world).f(gauss_3d);
689     double norm=phi.norm2();
690     if (world.rank()==0) printf("phi.norm2()   %12.8f\n",norm);
691 
692     real_function_3d phi2=2.0*phi*phi;
693     norm=phi2.norm2();
694     if (world.rank()==0) printf("phi2.norm2()  %12.8f\n",norm);
695 
696     test(world,k,thresh);
697     error+=test_hartree_product(world,k,thresh);
698     error+=test_convolution(world,k,thresh);
699     error+=test_multiply(world,k,thresh);
700     error+=test_add(world,k,thresh);
701     error+=test_exchange(world,k,thresh);
702     error+=test_inner(world,k,thresh);
703 
704 
705     print(ok(error==0),error,"finished test suite\n");
706 
707     world.gop.fence();
708     finalize();
709 
710     return error;
711 }
712 
713 
714