From e1acd01933c1f6c54af5794dd15d638c2d63f6ac Mon Sep 17 00:00:00 2001 From: fbischoff Date: Fri, 27 Jan 2023 11:41:19 +0100 Subject: [PATCH 001/109] more tests in test_ccpairfunction --- src/madness/chem/test_ccpairfunction.cc | 97 +++++++++++++++++++++++-- 1 file changed, 89 insertions(+), 8 deletions(-) diff --git a/src/madness/chem/test_ccpairfunction.cc b/src/madness/chem/test_ccpairfunction.cc index 505c0828c29..f3c4e282764 100644 --- a/src/madness/chem/test_ccpairfunction.cc +++ b/src/madness/chem/test_ccpairfunction.cc @@ -666,6 +666,83 @@ int test_dirac_convolution(World& world, std::shared_ptr = 0.032 mEh +int test_helium(World& world, std::shared_ptr ncf, const Molecule& molecule, + const CCParameters& parameters) { + + test_output t1("CCPairFunction::test_helium"); + CCTimer timer(world, "testing"); + + real_function_3d Vnuc = real_factory_3d(world).f([](const coord_3d& r) {return -2.0/(r.normf()+1.e-8);}); + real_function_3d psi = real_factory_3d(world).f([](const coord_3d& r) {return exp(-r.normf());}); + + auto iterate=[&world](const real_function_3d& potential, real_function_3d& psi, double& eps) { + real_convolution_3d op = BSHOperator3D(world, sqrt(-2*eps), 0.001, 1e-6); + real_function_3d Vpsi = (potential*psi); + Vpsi.scale(-2.0).truncate(); + real_function_3d tmp = op(Vpsi).truncate(); + double norm = tmp.norm2(); + real_function_3d r = tmp-psi; + double rnorm = r.norm2(); + double eps_new = eps - 0.5*inner(Vpsi,r)/(norm*norm); + if (world.rank() == 0) { + print("norm=",norm," eps=",eps," err(psi)=",rnorm," err(eps)=",eps_new-eps); + } + psi = tmp.scale(1.0/norm); + eps = eps_new; + }; + psi.truncate(); + psi.scale(1.0/psi.norm2()); + double eps = -0.6; + real_convolution_3d op = CoulombOperator(world, 0.001, 1e-6); + for (int iter=0; iter<10; iter++) { + real_function_3d rho = square(psi).truncate(); + real_function_3d potential = Vnuc + op(rho).truncate(); + iterate(potential, psi, eps); + } + double kinetic_energy = 0.0; + for (int axis=0; axis<3; axis++) { + real_derivative_3d D = free_space_derivative(world, axis); + real_function_3d dpsi = D(psi); + kinetic_energy += inner(dpsi,dpsi); + } + real_function_3d rho = square(psi); + double two_electron_energy = inner(op(rho),rho); + double nuclear_attraction_energy = 2.0*inner(Vnuc,rho); + double total_energy = kinetic_energy + two_electron_energy + nuclear_attraction_energy; + + t1.checkpoint(fabs(total_energy+2.8616533)<1.e-4,"helium iterations",timer.reset()); + print("ke, total", kinetic_energy, total_energy); + + + CCConvolutionOperator::Parameters param; + CCConvolutionOperator f(world,OT_F12,param); + CCConvolutionOperator g(world,OT_G12,param); + + CCPairFunction fij(&f,psi,psi); + CCPairFunction gij(&g,psi,psi); + CCPairFunction ij({psi},{psi}); + std::vector vfij={fij}; + std::vector vgij={gij}; + std::vector vij={ij}; + + StrongOrthogonalityProjector SO(world); + SO.set_spaces({psi},{psi},{psi},{psi}); + std::vector Qfij=SO(vfij); + std::vector Qgij=SO(vgij); + + double result1=inner(vgij,Qfij); + print(")",result1); + double result2=inner(vfij,Qgij); + print("(",result2); + bool good=fabs(result1-result2)<1.e-5; + good=good and fabs(result1+3.2624783e-02)<1.e-5; + t1.checkpoint(good,"V matrix element",timer.reset()); + + return (t1.get_final_success()) ? 0 : 1; + +} + /** functionality * * - ctor OK @@ -697,7 +774,7 @@ int main(int argc, char **argv) { #ifdef USE_GENTENSOR try { - parser.set_keyval("geometry", "source=library,he"); + parser.set_keyval("geometry", "he"); parser.print_map(); Molecule mol(world, parser); mol.print(); @@ -709,14 +786,18 @@ int main(int argc, char **argv) { mol, nullptr, std::make_pair("slater", 2.0)); isuccess+=test_constructor(world, ncf, mol, ccparam); - isuccess+=test_overlap(world, ncf, mol, ccparam); - isuccess+=test_swap_particles(world, ncf, mol, ccparam); - isuccess+=test_scalar_multiplication(world, ncf, mol, ccparam); - isuccess+=test_partial_inner(world, ncf, mol, ccparam); - isuccess+=test_projector(world, ncf, mol, ccparam); +// isuccess+=test_overlap(world, ncf, mol, ccparam); +// isuccess+=test_swap_particles(world, ncf, mol, ccparam); +// isuccess+=test_scalar_multiplication(world, ncf, mol, ccparam); +// isuccess+=test_partial_inner(world, ncf, mol, ccparam); +// isuccess+=test_projector(world, ncf, mol, ccparam); + FunctionDefaults<3>::set_cubic_cell(-10,10); + isuccess+=test_helium(world,ncf,mol,ccparam); + data1.clear(); + } catch (std::exception& e) { + madness::print("an error occured"); + madness::print(e.what()); data1.clear(); - } catch (...) { - } #else print("could not run test_ccpairfunction: U need to compile with ENABLE_GENTENSOR=1"); From 9fe055f2879732683fb1d31e924c371d31c61167 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Mon, 30 Jan 2023 11:24:31 +0100 Subject: [PATCH 002/109] fixed partial_inner for 6 dimensions --- src/madness/mra/funcimpl.h | 8 ++++---- src/madness/tensor/srconf.h | 9 ++++++++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/madness/mra/funcimpl.h b/src/madness/mra/funcimpl.h index 69444e57d19..cb1057ed044 100644 --- a/src/madness/mra/funcimpl.h +++ b/src/madness/mra/funcimpl.h @@ -5861,9 +5861,9 @@ namespace madness { int gparticle= v1[0]==0 ? 0 : 1; // which particle to integrate over int hparticle= v2[0]==0 ? 0 : 1; // which particle to integrate over // merge multiple contraction dimensions into one - Tensor gtensor = gcoeff1.get_svdtensor().make_vector_with_weights(gparticle); + Tensor gtensor = gcoeff1.get_svdtensor().flat_vector_with_weights(gparticle); Tensor gtensor_other = gcoeff1.get_svdtensor().flat_vector((gparticle+1)%2); - Tensor htensor = hcoeff1.get_svdtensor().make_vector_with_weights(hparticle); + Tensor htensor = hcoeff1.get_svdtensor().flat_vector_with_weights(hparticle); Tensor htensor_other = hcoeff1.get_svdtensor().flat_vector((hparticle+1)%2); Tensor tmp1=inner(gtensor,htensor,1,1); // tmp1(r,r') = sum_j b(r,j) a(r',j) Tensor tmp2=inner(tmp1,gtensor_other,0,0); // tmp2(r',i) = sum_r tmp1(r,r') a(r,i) @@ -5875,9 +5875,9 @@ namespace madness { if (key.level() > 0) { GenTensor gcoeff2 = copy(gcoeff1(g->get_cdata().s0)); GenTensor hcoeff2 = copy(hcoeff1(h->get_cdata().s0)); - Tensor gtensor = gcoeff2.get_svdtensor().make_vector_with_weights(gparticle); + Tensor gtensor = gcoeff2.get_svdtensor().flat_vector_with_weights(gparticle); Tensor gtensor_other = gcoeff2.get_svdtensor().flat_vector((gparticle+1)%2); - Tensor htensor = hcoeff2.get_svdtensor().make_vector_with_weights(hparticle); + Tensor htensor = hcoeff2.get_svdtensor().flat_vector_with_weights(hparticle); Tensor htensor_other = hcoeff2.get_svdtensor().flat_vector((hparticle+1)%2); Tensor tmp1=inner(gtensor,htensor,1,1); // tmp1(r,r') = sum_j b(r,j) a(r',j) Tensor tmp2=inner(tmp1,gtensor_other,0,0); // tmp2(r',i) = sum_r tmp1(r,r') a(r,i) diff --git a/src/madness/tensor/srconf.h b/src/madness/tensor/srconf.h index 480b0e7f2c5..9ecb4858b48 100644 --- a/src/madness/tensor/srconf.h +++ b/src/madness/tensor/srconf.h @@ -693,10 +693,17 @@ namespace madness { Tensor make_vector_with_weights(const int dim) const { Tensor v=copy(vector_[dim].reshape(rank(),vector_[dim].size()/rank())); for (unsigned int r=0; r flat_vector_with_weights(const int dim) const { + return make_vector_with_weights(dim).reshape(rank(),vector_[dim].size()/rank()); + } + protected: /// return the number of coefficients unsigned int nCoeff() const { From 67e4faa0f08de6dba7e522c88725fd88043c73f9 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Mon, 30 Jan 2023 14:54:05 +0100 Subject: [PATCH 003/109] more tests for CCPairFunction::inner --- src/madness/chem/ccpairfunction.cc | 64 ++++++++++++ src/madness/chem/ccpairfunction.h | 67 ++++++++----- src/madness/chem/test_ccpairfunction.cc | 124 +++++++++++++++++++----- src/madness/mra/testinnerext.cc | 2 +- 4 files changed, 207 insertions(+), 50 deletions(-) diff --git a/src/madness/chem/ccpairfunction.cc b/src/madness/chem/ccpairfunction.cc index 46bcd016907..ddd3458cafc 100644 --- a/src/madness/chem/ccpairfunction.cc +++ b/src/madness/chem/ccpairfunction.cc @@ -90,6 +90,70 @@ real_function_3d inner(const CCPairFunction& c, const real_function_3d& f, return c.partial_inner(f,v11,v22); } +CCPairFunction inner(const CCPairFunction& c1, const CCPairFunction& c2, + const std::tuple v1, const std::tuple v2) { + auto v11=std::array({std::get<0>(v1),std::get<1>(v1),std::get<2>(v1)}); + auto v22=std::array({std::get<0>(v2),std::get<1>(v2),std::get<2>(v2)}); + + return c1.partial_inner(c2,v11,v22); +} + +CCPairFunction CCPairFunction::partial_inner(const CCPairFunction& other, + const std::array& v1, + const std::array& v2) const { + auto a012=std::array{0,1,2}; + auto a345=std::array{3,4,5}; + MADNESS_CHECK(v1==a012 or v1== a345); + MADNESS_CHECK(v2==a012 or v2== a345); + + auto integration_index=[&a012,&a345](auto v) {return (v==a012) ? 0l : 1l;}; + auto remaining_index=[&integration_index](auto v) {return (integration_index(v)+1)%2;}; + + CCPairFunction result; + if (this->is_pure()) { + if (other.is_pure()) { + real_function_6d tmp=madness::innerXX<6>(this->get_function(),other.get_function(),v1,v2); + return CCPairFunction(tmp); + + } else if (other.is_decomposed_no_op()) { + // \int \sum_i f(1,2) a_i(1) b_i(3) d1 = \sum_i b_i(3) \int a_i(1) f(1,2) d1 + vector_real_function_3d tmp; + for (auto& a : other.get_vector(integration_index(v2))) { + tmp.push_back(innerXX<3>(this->get_function(),a,v1,a012)); // a012 is correct, referring to 3D function + } + return CCPairFunction(tmp,other.get_vector(remaining_index(v2))); + + } else if (other.is_op_decomposed()) { + + } else { + MADNESS_EXCEPTION("confused CCPairfunction",1); + } + + } else if (this->is_decomposed_no_op()) { + if (other.is_pure()) { + return other.partial_inner(*this,v2,v1); + } else if (other.is_decomposed_no_op()) { + // \int \sum_i a_i(1) b_i(2) \sum_j c_j(1) d_j(3) d1 + // = \sum_ij b_i(2) d_j(3) + // = \sum_i b~_i(2) d~_i(3) // cholesky decomposition of S_ac + Tensor ovlp=matrix_inner(world(),this->get_vector(integration_index(v1)),other.get_vector(integration_index(v2))); + cholesky(ovlp); + auto left=transform(world(),this->get_vector(remaining_index(v1)),transpose(ovlp)); + auto right=transform(world(),other.get_vector(remaining_index(v2)),transpose(ovlp)); + return CCPairFunction(left,right); + + } else if (other.is_op_decomposed()) { + + } + + } else if (this->is_op_decomposed()) { + + } else { + MADNESS_EXCEPTION("confused CCPairfunction",1); + } + return result; + +} real_function_3d CCPairFunction::partial_inner(const real_function_3d& f, const std::array& v1, diff --git a/src/madness/chem/ccpairfunction.h b/src/madness/chem/ccpairfunction.h index 81678347040..d5969ec573a 100644 --- a/src/madness/chem/ccpairfunction.h +++ b/src/madness/chem/ccpairfunction.h @@ -131,7 +131,7 @@ class TwoBodyFunctionPureComponent : public TwoBodyFunctionComponentBase { std::string name(const bool transpose) const override { if (transpose) return "< u |"; - return "|u>"; + return "| u >"; } @@ -203,25 +203,41 @@ class TwoBodyFunctionSeparatedComponent : public TwoBodyFunctionComponentBase { std::string name(const bool transpose) const override { if (transpose) { - if (has_operator()) return "name(); - return "name(); + return "name() + "|xy>"; - return "|ab>"; + if (has_operator()) return get_operator_ptr()->name() + "| ab>"; + return "| ab>"; }; void serialize() {} template - TwoBodyFunctionPureComponent apply(const SeparatedConvolution* op, const int particle=0) {} + TwoBodyFunctionPureComponent apply(const SeparatedConvolution* op, const int particle=0) { + MADNESS_EXCEPTION("TwoBodyFunctionPureComponent apply not yet implemented",1); + } /// return f(2,1) void swap_particles_inplace() override { std::swap(a,b); } + long rank() const { + MADNESS_CHECK(a.size()==b.size()); + return a.size(); + } + std::vector> get_a() const {return a;} std::vector> get_b() const {return b;} + std::vector> get_vector(const int i) const { + MADNESS_CHECK(i==0 or i==1); + if (i==0) return a; + else if (i==1) return b; + else { + MADNESS_EXCEPTION("confused index in TwoBodyFunctionSeparatedComponent",1); + } + } + const CCConvolutionOperator* get_operator_ptr() const {return op;}; private: @@ -258,6 +274,15 @@ class TwoBodyFunctionSeparatedComponent : public TwoBodyFunctionComponentBase { * - mul_partial */ +/// a 6D function, either in full or low rank form, possibly including an 2-particle function + +/** + * the function is stored as + * - pure: full rank form, 6D + * - decomposed: sum of two vectors of 3D functions \sum_i |a_i(1) b_i(2)> + * - op_decomposed: as above, with an 2-particle function: f(1,2) \sum_i |a_i b_i> + * +**/ struct CCPairFunction { using T=double; @@ -366,6 +391,11 @@ using T=double; return decomposed().get_b(); } + std::vector> get_vector(const int i) const { + MADNESS_CHECK(component->is_decomposed()); + return decomposed().get_vector(i); + } + const CCConvolutionOperator& get_operator() const { MADNESS_CHECK(is_op_decomposed()); return *decomposed().get_operator_ptr(); @@ -392,7 +422,8 @@ using T=double; /// @param[out] _particle (projection from 6D to 3D) real_function_3d project_out(const CCFunction& f, const size_t particle) const; - // result is: _particle + /// result is: _particle + /// @param[in] x: a 3D-CC_function /// @param[in] op: a CC_convoltion_operator which is currently either f12 or g12 /// @param[in] particle: the particle on which the operation acts (can be 1 or 2) @@ -439,22 +470,6 @@ using T=double; /// the 3 types of 6D-function that occur in the CC potential which coupled doubles to singles std::shared_ptr component; -// World& world; -// /// the type of the given 6D-function -// const PairFormat type; -// /// if type==decomposed this is the first particle -// vector_real_function_3d a; -// /// if type==decomposed this is the second particle -// vector_real_function_3d b; -// /// if type==op_decomposed_ this is the symmetric 6D-operator (g12 or f12) in u=op12|xy> -// const CCConvolutionOperator *op; -// /// if type==op_decomposed_ this is the first particle in u=op12|xy> -// CCFunction x; -// /// if type==op_decomposed_ this is the second particle in u=op12|xy> -// CCFunction y; -// /// if type=pure_ this is just the MRA 6D-function -// real_function_6d u; - /// @param[in] f: a 3D-CC_function /// @param[in] particle: the particle on which the operation acts /// @param[out] _particle (projection from 6D to 3D) for the case that u=|ab> so _particle = *|b> if particle==1 @@ -500,6 +515,10 @@ using T=double; const std::array& v1, const std::array& v2) const; + CCPairFunction partial_inner(const CCPairFunction& other, + const std::array& v1, + const std::array& v2) const; + }; /// apply the projector on the argument function, potentially yielding a vector of CCPairfunctions as result @@ -516,6 +535,8 @@ CCPairFunction apply(const ProjectorBase& P, const CCPairFunction& argument); real_function_3d inner(const CCPairFunction& c, const real_function_3d& f, const std::tuple v1, const std::tuple v2={0,1,2}); +CCPairFunction inner(const CCPairFunction& c1, const CCPairFunction& c2, + const std::tuple v1, const std::tuple v2); } // namespace madness diff --git a/src/madness/chem/test_ccpairfunction.cc b/src/madness/chem/test_ccpairfunction.cc index f3c4e282764..f6facc3637b 100644 --- a/src/madness/chem/test_ccpairfunction.cc +++ b/src/madness/chem/test_ccpairfunction.cc @@ -17,13 +17,13 @@ using namespace madness; struct data { real_function_3d f1,f2,f3,f4,f5; - real_function_6d f; + real_function_6d f12,f23; - std::shared_ptr f12; + std::shared_ptr f12_op; data() {} data(World& world, CCParameters& parameters) { - f12.reset(new CCConvolutionOperator(world,OT_F12,parameters)); + f12_op.reset(new CCConvolutionOperator(world,OT_F12,parameters)); if (not f1.is_initialized()) initialize(world); } @@ -44,29 +44,36 @@ struct data { double r2=r[3]*r[3] + r[4]*r[4] + r[5]*r[5]; return exp(-1.0*r1 - 2.0*r2); }; - f = real_factory_6d(world).f(g); + auto g23 = [](const coord_6d& r) { + double r1=r[0]*r[0] + r[1]*r[1] + r[2]*r[2]; + double r2=r[3]*r[3] + r[4]*r[4] + r[5]*r[5]; + return exp(-1.0*r1 - 2.0*r2) + exp(-2.0*r1 - 3.0*r2); + }; + f12 = real_factory_6d(world).f(g); + f23 = real_factory_6d(world).f(g23); } void clear() { - f12.reset(); + f12_op.reset(); f1.clear(); f2.clear(); f3.clear(); f4.clear(); f5.clear(); - f.clear(); + f12.clear(); + f23.clear(); } auto get_functions() const { - return std::make_tuple(f1,f2,f3,f4,f5,f); + return std::make_tuple(f1,f2,f3,f4,f5,f12); } auto get_ccpairfunctions() const { - CCPairFunction p1; - CCPairFunction p2(f); - CCPairFunction p3({f1,f2},{f1,f3}); - CCPairFunction p4(f12.get(),{f1,f2},{f1,f3}); - return std::make_tuple(p1,p2,p3); + CCPairFunction p1(f12); + CCPairFunction p2({f1,f2},{f2,f3}); + CCPairFunction p3(f12_op.get(),{f1,f2},{f2,f3}); + CCPairFunction p4(f23); // two-term, corresponds to p2 + return std::make_tuple(p1,p2,p3,p4); } }; @@ -327,9 +334,70 @@ int test_overlap(World& world, std::shared_ptr ncf, co -int test_partial_inner(World& world, std::shared_ptr ncf, const Molecule& molecule, +int test_partial_inner_6d(World& world, std::shared_ptr ncf, const Molecule& molecule, + const CCParameters& parameter) { + + CCTimer timer(world, "testing"); + test_output t1("CCPairFunction::test_partial_inner_6d"); + t1.set_cout_to_terminal(); + auto [f1,f2,f3,f4,f5,f] = data1.get_functions(); + + std::vector a = {f1, f2}; + std::vector b = {f2, f3}; + + CCConvolutionOperator f12(world, OT_F12, parameter); + + auto [p1,p2,p3,p4]=data1.get_ccpairfunctions(); + CCPairFunction p11({f1},{f1}); + CCPairFunction p12({f1},{f2}); + + double g11=inner(f1,f1); + double g22=inner(f2,f2); + double g12=inner(f1,f2); + double g13=inner(f1,f3); + double g23=inner(f2,f3); + double g33=inner(f3,f3); + real_function_3d gf11=f12(f1*f1); + real_function_3d gf12=f12(f1*f2); + real_function_3d gf13=f12(f1*f3); + + t1.checkpoint(true,"prep",timer.reset()); + + // p1 = p12 = e(-r1 -2r2) + // p2 = e(-r1) * e(-2r2) + e(-2r1) * e(-3e2) separated + // p4 = e(-r1) * e(-2r2) + e(-2r1) * e(-3e2) 6d + for (auto test_p1 : {p2,p4}) { + for (auto test_p2 : {p2,p4}) { + CCPairFunction r1=inner(test_p1,test_p2,{0,1,2},{0,1,2}); + CCPairFunction r2=inner(test_p1,test_p2,{0,1,2},{3,4,5}); + CCPairFunction r3=inner(test_p1,test_p2,{3,4,5},{0,1,2}); + CCPairFunction r4=inner(test_p1,test_p2,{3,4,5},{3,4,5}); + + double n1=inner(r1,p11); + double n2=inner(r2,p11); + double n3=inner(r3,p11); + double n4=inner(r4,p11); + + double ref_n1=g11*g12*g12 + g12*g12*g13 + g12*g13*g12 + g22*g13*g13; + double ref_n2=g12*g12*g11 + g13*g12*g12 + g22*g13*g11 + g23*g13*g12; + double ref_n3=ref_n2; + double ref_n4=g22*g11*g11 + g23*g11*g12 + g23*g12*g11 + g33*g12*g12; + + bool good=fabs(n1-ref_n1)::get_thresh(); + t1.checkpoint(good,test_p1.name(true)+test_p2.name()+" -- 1"); + good=fabs(n2-ref_n2)::get_thresh(); + t1.checkpoint(good,test_p1.name(true)+test_p2.name()+" -- 2"); + good=fabs(n3-ref_n3)::get_thresh(); + t1.checkpoint(good,test_p1.name(true)+test_p2.name()+" -- 3"); + good=fabs(n4-ref_n4)::get_thresh(); + t1.checkpoint(good,test_p1.name(true)+test_p2.name()+" -- 4",timer.reset()); + + } + } + return (t1.get_final_success()) ? 0 : 1; +} +int test_partial_inner_3d(World& world, std::shared_ptr ncf, const Molecule& molecule, const CCParameters& parameter) { - int success=0; CCTimer timer(world, "testing"); test_output t1("CCPairFunction::test_partial_inner"); @@ -340,9 +408,11 @@ int test_partial_inner(World& world, std::shared_ptr n CCConvolutionOperator f12(world, OT_F12, parameter); - CCPairFunction p1(f); + CCPairFunction p1(f); // e(-r1 - 2r2) CCPairFunction p2(a,b); CCPairFunction p3(&f12,a,b); + CCPairFunction p11({f1},{f1}); + CCPairFunction p12({f1},{f2}); double g11=inner(f1,f1); double g22=inner(f2,f2); @@ -357,22 +427,22 @@ int test_partial_inner(World& world, std::shared_ptr n print("time in preparation",timer.reset()); t1.checkpoint(true,"prep"); - // test pure + // test pure/3d { real_function_3d r=inner(p1,f1,{0,1,2},{0,1,2}); double norm=inner(r,f2); double ref_norm=g11 * g22; print("norm, ref_norm",norm,ref_norm); - bool good=fabs(norm-ref_norm::get_thresh()); + bool good=fabs(norm-ref_norm)::get_thresh(); t1.checkpoint(good,"pure -- 1"); } - // test pure + // test pure/3d { real_function_3d r=inner(p1,f1,{3,4,5},{0,1,2}); double norm=inner(r,f2); double ref_norm=g12 * g12; print("norm, ref_norm",norm,ref_norm); - bool good=fabs(norm-ref_norm::get_thresh()); + bool good=fabs(norm-ref_norm)::get_thresh(); t1.checkpoint(good,"pure -- 2"); } // test decomposed @@ -381,7 +451,7 @@ int test_partial_inner(World& world, std::shared_ptr n double norm=inner(r,f2); double ref_norm=g11 * g22 + g12 * g23; print("norm, ref_norm",norm,ref_norm); - bool good=fabs(norm-ref_norm::get_thresh()); + bool good=fabs(norm-ref_norm)::get_thresh(); t1.checkpoint(good,"decomposed -- 1"); } // test decomposed @@ -390,7 +460,7 @@ int test_partial_inner(World& world, std::shared_ptr n double norm=inner(r,f2); double ref_norm=g12 * g12 + g13 * g22; print("norm, ref_norm",norm,ref_norm); - bool good=fabs(norm-ref_norm::get_thresh()); + bool good=fabs(norm-ref_norm)::get_thresh(); t1.checkpoint(good,"decomposed -- 2"); } // test op_decomposed @@ -400,7 +470,7 @@ int test_partial_inner(World& world, std::shared_ptr n double norm=inner(r,f2); double ref_norm=inner(gf11*f2,f2) + inner(gf12*f2,f3); print("norm, ref_norm",norm,ref_norm); - bool good=fabs(norm-ref_norm::get_thresh()); + bool good=fabs(norm-ref_norm)::get_thresh(); t1.checkpoint(good,"op_decomposed -- 1"); } // test op_decomposed @@ -410,7 +480,7 @@ int test_partial_inner(World& world, std::shared_ptr n double norm=inner(r,f2); double ref_norm=inner(gf12*f1,f2) + inner(gf13*f2,f2); print("norm, ref_norm",norm,ref_norm); - bool good=fabs(norm-ref_norm::get_thresh()); + bool good=fabs(norm-ref_norm)::get_thresh(); t1.checkpoint(good,"op_decomposed -- 2"); } @@ -765,6 +835,7 @@ int main(int argc, char **argv) { startup(world, argc, argv); commandlineparser parser(argc, argv); FunctionDefaults<6>::set_tensor_type(TT_2D); + FunctionDefaults<6>::set_thresh(1.e-3); FunctionDefaults<3>::set_thresh(1.e-5); FunctionDefaults<3>::set_cubic_cell(-1.0,1.0); FunctionDefaults<6>::set_cubic_cell(-1.0,1.0); @@ -789,10 +860,11 @@ int main(int argc, char **argv) { // isuccess+=test_overlap(world, ncf, mol, ccparam); // isuccess+=test_swap_particles(world, ncf, mol, ccparam); // isuccess+=test_scalar_multiplication(world, ncf, mol, ccparam); -// isuccess+=test_partial_inner(world, ncf, mol, ccparam); +// isuccess+=test_partial_inner_3d(world, ncf, mol, ccparam); + isuccess+=test_partial_inner_6d(world, ncf, mol, ccparam); // isuccess+=test_projector(world, ncf, mol, ccparam); - FunctionDefaults<3>::set_cubic_cell(-10,10); - isuccess+=test_helium(world,ncf,mol,ccparam); +// FunctionDefaults<3>::set_cubic_cell(-10,10); +// isuccess+=test_helium(world,ncf,mol,ccparam); data1.clear(); } catch (std::exception& e) { madness::print("an error occured"); diff --git a/src/madness/mra/testinnerext.cc b/src/madness/mra/testinnerext.cc index b8833f923d7..a0695691407 100644 --- a/src/madness/mra/testinnerext.cc +++ b/src/madness/mra/testinnerext.cc @@ -84,11 +84,11 @@ bool test_loose1(std::string msg, double a, double b, double tol=thresh) { int test_partial_inner(World& world) { - print("\ntesting partial inner\n"); bool do_low_rank=false; #if HAVE_GENTENSOR do_low_rank=true; #endif + print("\ntesting partial inner; low rank: ",do_low_rank,"\n"); real_function_1d one_1d=real_factory_1d(world).functor([](const coord_1d& r){return 1.0;}); real_function_2d one_2d=real_factory_2d(world).functor([](const coord_2d& r){return 1.0;}); From 55b9e6ec54d08f97ae3c206851b34843fb8ade57 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Fri, 3 Feb 2023 22:19:58 +0100 Subject: [PATCH 004/109] implementing SlaterF12: f12 = 1/(2 mu) (1-exp(-mu r)) as single operator, as opposed to a single Slater function and a separately treated term 1 --- src/madness/chem/PNOF12Potentials.cpp | 2 - src/madness/mra/gfit.h | 77 ++++++++++++++++++++++++++- src/madness/mra/mra.h | 14 +---- src/madness/mra/operator.h | 46 ++++++++-------- src/madness/mra/vmra.h | 52 +++++++++++++----- 5 files changed, 137 insertions(+), 54 deletions(-) diff --git a/src/madness/chem/PNOF12Potentials.cpp b/src/madness/chem/PNOF12Potentials.cpp index ce3b5659386..6b5e5092d65 100644 --- a/src/madness/chem/PNOF12Potentials.cpp +++ b/src/madness/chem/PNOF12Potentials.cpp @@ -81,8 +81,6 @@ F12Potentials::F12Potentials(World& world,const Nemo& nemo, const BasisFunctions fop = std::shared_ptr < real_convolution_3d > (SlaterF12OperatorPtr(world, param.gamma(), lo, eps)); slaterop = std::shared_ptr < real_convolution_3d > (SlaterF12OperatorPtr(world, param.gamma(), lo, eps)); slaterop_sq = std::shared_ptr < real_convolution_3d > (SlaterF12OperatorPtr(world, param.gamma() * 2.0, lo, eps)); - slaterop->is_slaterf12 = false; - slaterop_sq->is_slaterf12 = false; fop = std::shared_ptr < real_convolution_3d > (SlaterF12OperatorPtr(world, param.gamma(), lo, eps)); //test diff --git a/src/madness/mra/gfit.h b/src/madness/mra/gfit.h index bb13810e930..9820064924c 100644 --- a/src/madness/mra/gfit.h +++ b/src/madness/mra/gfit.h @@ -95,10 +95,35 @@ class GFit { /// @parma[in] prnt print level static GFit SlaterFit(double gamma, double lo, double hi, double eps, bool prnt=false) { GFit fit; - slater_fit(gamma,lo,hi,eps,fit.coeffs_,fit.exponents_,prnt); + slater_fit(gamma,lo,hi,eps,fit.coeffs_,fit.exponents_,false); + if (prnt) { + print("Slater fit"); + auto exact = [&gamma](const double r) -> double { return exp(-gamma * r); }; + fit.print_accuracy(exact, lo, hi); + } return fit; } + /// return a fit for the F12 correlation factor + + /// the Slater function is defined by + /// f(r) = 1 - exp(-\gamma r) + /// @param[in] gamma the exponent of the Slater function + /// @param[in] lo the smallest length scale that needs to be precisely represented + /// @param[in] hi the largest length scale that needs to be precisely represented + /// @param[in] eps the precision threshold + /// @parma[in] prnt print level + static GFit F12Fit(double gamma, double lo, double hi, double eps, bool prnt=false) { + GFit fit; + f12_fit(gamma,lo*0.1,hi,eps*0.01,fit.coeffs_,fit.exponents_,false); + if (prnt) { + print("f12 fit"); + auto exact=[&gamma](const double r) -> double {return 1.0-exp(-gamma*r);}; + fit.print_accuracy(exact,lo,hi); + } + return fit; + } + /// return a fit for a general isotropic function /// note that the error is controlled over a uniform grid, the boundaries @@ -157,6 +182,35 @@ class GFit { } + /// print coefficients and exponents, and values and errors + + /// @param[in] op the exact function, e.g. 1/r, exp(-mu r), etc + /// @param[in] lo lower bound for the range r + /// @param[in] hi higher bound for the range r + template + void print_accuracy(opT op, const double lo, const double hi) const { + + std::cout << "weights and roots" << std::endl; + for (int i=0; i coeffs_; @@ -453,7 +507,26 @@ class GFit { pexpnt = expnt; } - void static bsh_fit_ndim(int ndim, double mu, double lo, double hi, double eps, + + /// fit a correlation factor (1- exp(-mu r)) + + /// use the Slater fit with an additional term: 1*exp(-0 r^2) + static void f12_fit(double gamma, double lo, double hi, double eps, + Tensor& pcoeff, Tensor& pexpnt, bool prnt) { + Tensor coeff,expnt; + slater_fit(gamma, lo, hi, eps, coeff, expnt, prnt); + + pcoeff=Tensor(coeff.size()+1); + pcoeff(Slice(1,-1,1))=-coeff(_); + pexpnt=Tensor(expnt.size()+1); + pexpnt(Slice(1,-1,1))=expnt(_); + + pcoeff(0l)=1.0; + pexpnt(0l)=1.e-10; + } + + + void static bsh_fit_ndim(int ndim, double mu, double lo, double hi, double eps, Tensor& pcoeff, Tensor& pexpnt, bool prnt) { if (mu > 0) { diff --git a/src/madness/mra/mra.h b/src/madness/mra/mra.h index 9fab680c1d6..da48db5b505 100644 --- a/src/madness/mra/mra.h +++ b/src/madness/mra/mra.h @@ -2134,8 +2134,7 @@ namespace madness { Function result; MADNESS_ASSERT(not f.is_on_demand()); - bool print_timings=(NDIM==6); -// bool print_timings=false; + bool print_timings=(NDIM==6) and op.print_timings; if (VERIFY_TREE) ff.verify_tree(); ff.reconstruct(); @@ -2143,7 +2142,6 @@ namespace madness { if (op.modified()) { - MADNESS_ASSERT(not op.is_slaterf12); ff.get_impl()->make_redundant(true); result = apply_only(op, ff, fence); ff.get_impl()->undo_redundant(false); @@ -2151,14 +2149,6 @@ namespace madness { } else { - // the slaterf12 function is - // 1/(2 mu) \int d1 (1 - exp(- mu r12)) f(1) - // = 1/(2 mu) (f.trace() - \int d1 exp(-mu r12) f(1) ) - // f.trace() is just a number - R ftrace=0.0; - if (op.is_slaterf12) ftrace=f.trace(); -// print("ftrace",ftrace); - // saves the standard() step, which is very expensive in 6D // Function fff=copy(ff); Function fff=(ff); @@ -2190,8 +2180,6 @@ namespace madness { } else { ff.standard(); } - if (op.is_slaterf12) result=(result-ftrace).scale(-0.5/op.mu()); - } if (print_timings) result.print_size("result after reconstruction"); return result; diff --git a/src/madness/mra/operator.h b/src/madness/mra/operator.h index 2a0cbc5a4c8..1efa12e0de7 100644 --- a/src/madness/mra/operator.h +++ b/src/madness/mra/operator.h @@ -118,9 +118,10 @@ namespace madness { bool doleaves; ///< If should be applied to leaf coefficients ... false by default bool isperiodicsum;///< If true the operator 1D kernels have been summed over lattice translations ///< and may be non-zero at both ends of the unit cell - bool modified_; ///< use modified NS form - int particle_; - bool destructive_; ///< destroy the argument or restore it (expensive for 6d functions) + bool modified_=false; ///< use modified NS form + int particle_=1; ///< must only be 1 or 2 + bool destructive_=false; ///< destroy the argument or restore it (expensive for 6d functions) + bool print_timings=false; typedef Key keyT; const static size_t opdim=NDIM; @@ -130,8 +131,7 @@ namespace madness { Timer timer_stats_accumulate; // if this is a Slater-type convolution kernel: 1-exp(-mu r12)/(2 mu) - bool is_slaterf12; - double mu_; + double mu_=0.0; ///< some introspection private: @@ -881,7 +881,6 @@ namespace madness { , modified_(false) , particle_(1) , destructive_(false) - , is_slaterf12(false) , mu_(0.0) , bc(bc) , k(k) @@ -916,7 +915,6 @@ namespace madness { , modified_(false) , particle_(1) , destructive_(false) - , is_slaterf12(false) , mu_(0.0) , ops(argops) , bc(bc) @@ -947,7 +945,6 @@ namespace madness { , modified_(false) , particle_(1) , destructive_(false) - , is_slaterf12(mu>0.0) , mu_(mu) , ops(coeff.dim(0)) , bc(bc) @@ -992,7 +989,6 @@ namespace madness { , modified_(false) , particle_(1) , destructive_(false) - , is_slaterf12(false) , mu_(0.0) , ops(coeff.dim(0)) , bc(bc) @@ -1104,7 +1100,6 @@ namespace madness { template Function operator()(const Function& f1, const Function& f2) const { - MADNESS_ASSERT(not is_slaterf12); return madness::apply(*this, std::vector>({f1}), std::vector>({f2})); } @@ -1117,7 +1112,6 @@ namespace madness { template Function operator()(const std::vector>& f1, const std::vector>& f2) const { - MADNESS_ASSERT(not is_slaterf12); return madness::apply(*this, f1, f2); } @@ -1770,28 +1764,29 @@ namespace madness { /// Factory function generating separated kernel for convolution with (1 - exp(-mu*r))/(2 mu) in 3D - /// note that the 1/2mu factor is not included here, nor is the term 1/(2mu) + /// includes the factor 1/(2 mu) static inline SeparatedConvolution SlaterF12Operator(World& world, - double mu, double lo, double eps, - const BoundaryConditions<3>& bc=FunctionDefaults<3>::get_bc(), - int k=FunctionDefaults<3>::get_k()) { + double mu, double lo, double eps, + const BoundaryConditions<3>& bc=FunctionDefaults<3>::get_bc(), + int k=FunctionDefaults<3>::get_k()) { const Tensor& cell_width = FunctionDefaults<3>::get_cell_width(); double hi = cell_width.normf(); // Diagonal width of cell if (bc(0,0) == BC_PERIODIC) hi *= 100; // Extend range for periodic summation - GFit fit=GFit::SlaterFit(mu,lo,hi,eps,false); - Tensor coeff=fit.coeffs(); - Tensor expnt=fit.exponents(); + GFit fit=GFit::F12Fit(mu,lo,hi,eps,false); + Tensor coeff=0.5/mu*fit.coeffs(); + Tensor expnt=fit.exponents(); if (bc(0,0) == BC_PERIODIC) { fit.truncate_periodic_expansion(coeff, expnt, cell_width.max(), false); } - return SeparatedConvolution(world, coeff, expnt, bc, k, false, mu); + + auto sepop=SeparatedConvolution(world, coeff, expnt, bc, k, false, mu); + return sepop; } /// Factory function generating separated kernel for convolution with exp(-mu*r) in 3D - /// Note that the 1/(2mu) factor is not included, this is just the exponential function static inline SeparatedConvolution SlaterOperator(World& world, double mu, double lo, double eps, const BoundaryConditions<3>& bc=FunctionDefaults<3>::get_bc(), @@ -1809,7 +1804,6 @@ namespace madness { fit.truncate_periodic_expansion(coeff, expnt, cell_width.max(), false); } SeparatedConvolution tmp(world, coeff, expnt, bc, k, false, mu); - tmp.is_slaterf12 = false; return tmp; } @@ -1832,11 +1826,12 @@ namespace madness { fit.truncate_periodic_expansion(coeff, expnt, cell_width.max(), false); } SeparatedConvolution* tmp=new SeparatedConvolution(world, coeff, expnt, bc, k, false, mu); - tmp->is_slaterf12 = false; return tmp; } /// Factory function generating separated kernel for convolution with (1 - exp(-mu*r))/(2 mu) in 3D + + /// includes the factor 1/(2 mu) static inline SeparatedConvolution* SlaterF12OperatorPtr(World& world, double mu, double lo, double eps, const BoundaryConditions<3>& bc=FunctionDefaults<3>::get_bc(), @@ -1846,13 +1841,14 @@ namespace madness { double hi = cell_width.normf(); // Diagonal width of cell if (bc(0,0) == BC_PERIODIC) hi *= 100; // Extend range for periodic summation - GFit fit=GFit::SlaterFit(mu,lo,hi,eps,false); - Tensor coeff=fit.coeffs(); - Tensor expnt=fit.exponents(); + GFit fit=GFit::F12Fit(mu,lo,hi,eps,false); + Tensor coeff=0.5/mu*fit.coeffs(); + Tensor expnt=fit.exponents(); if (bc(0,0) == BC_PERIODIC) { fit.truncate_periodic_expansion(coeff, expnt, cell_width.max(), false); } + return new SeparatedConvolution(world, coeff, expnt, bc, k, false, mu); } diff --git a/src/madness/mra/vmra.h b/src/madness/mra/vmra.h index 23c16efb55b..f4ea33ca3cf 100644 --- a/src/madness/mra/vmra.h +++ b/src/madness/mra/vmra.h @@ -1011,7 +1011,45 @@ namespace madness { } - /// Computes the square of a vector of functions --- q[i] = v[i]**2 + /// multiply a high-dimensional function with a low-dimensional function + + /// @param[in] f NDIM function of NDIM dimensions + /// @param[in] g LDIM function of LDIM + /// @param[in] v dimension indices of f to multiply + /// @return h[i](0,1,2,3) = f(0,1,2,3) * g[i](1,2,3) for v={1,2,3} + template + std::vector > partial_mul(const Function f, const std::vector > g, + const int particle) { + + World& world=f.world(); + std::vector > result(g.size()); + for (auto& r : result) r.set_impl(f, false); + + FunctionImpl* fimpl=f.get_impl().get(); + fimpl->make_redundant(false); + make_redundant(world,g,false); + world.gop.fence(); + + for (std::size_t i=0; i* gimpl=g[i].get_impl().get(); + result[i].get_impl()->multiply(fimpl,gimpl,particle); // stupid naming inconsistency + } + world.gop.fence(); + + fimpl->undo_redundant(false); + for (auto& ig : g) ig.get_impl()->undo_redundant(false); + world.gop.fence(); + return result; + } + + template + std::vector > multiply(const Function f, const std::vector > g, + const std::tuple v) { + return partial_mul(f,g,std::array({std::get<0>(v),std::get<1>(v),std::get<2>(v)})); + } + + +/// Computes the square of a vector of functions --- q[i] = v[i]**2 template std::vector< Function > square(World& world, @@ -1312,7 +1350,6 @@ namespace madness { std::vector< Function > result(f.size()); for (unsigned int i=0; iis_slaterf12); result[i] = apply_only(*op[i], f[i], false); } @@ -1335,7 +1372,7 @@ namespace madness { PROFILE_BLOCK(Vapply); std::vector< Function >& ncf = *const_cast< std::vector< Function >* >(&f); - bool print_timings=(NDIM==6) and (world.rank()==0); + bool print_timings=(NDIM==6) and (world.rank()==0) and op.print_timings; double wall0=wall_time(); reconstruct(world, f); @@ -1365,15 +1402,6 @@ namespace madness { } reconstruct(world, result); - if (op.is_slaterf12) { - MADNESS_ASSERT(not op.destructive()); - if (typeid(T)!=typeid(R)) MADNESS_EXCEPTION("think again!",1); - for (unsigned int i=0; i Date: Sat, 4 Feb 2023 23:28:29 +0100 Subject: [PATCH 005/109] ccpairfunction inner product tests seem to work --- src/madness/chem/ccpairfunction.cc | 105 ++++++++++++++++++++++-- src/madness/chem/ccpairfunction.h | 9 ++ src/madness/chem/test_ccpairfunction.cc | 78 ++++++++++++++++-- 3 files changed, 178 insertions(+), 14 deletions(-) diff --git a/src/madness/chem/ccpairfunction.cc b/src/madness/chem/ccpairfunction.cc index ddd3458cafc..18b63d13633 100644 --- a/src/madness/chem/ccpairfunction.cc +++ b/src/madness/chem/ccpairfunction.cc @@ -17,6 +17,42 @@ CCPairFunction::invert_sign() { return *this; } +bool CCPairFunction::is_convertible_to_pure() const { + if (is_pure()) return true; + bool operator_condition=true; + if (has_operator()) { + const auto type=get_operator().type(); + if (type==OT_SLATER or type==OT_F12) operator_condition=true; + else operator_condition=false; + } + bool size_condition=is_decomposed() and (get_a().size()==1); + return operator_condition and size_condition; +}; + + +void CCPairFunction::convert_to_pure_inplace() { + if (is_pure()) return; + pureT result=real_factory_6d(world()); + MADNESS_CHECK(get_a().size()<3); + for (int i=0; i(world()) + .g12(get_operator().get_kernel()) + .particle1(get_a()[i]) + .particle2(get_b()[i]); + } else if (is_decomposed_no_op()) { + tmp= CompositeFactory(world()) + .particle1(get_a()[i]) + .particle2(get_b()[i]); + } + tmp.fill_tree(); + result+=tmp; + } + component.reset(new TwoBodyFunctionPureComponent(result)); +}; + + double CCPairFunction::make_xy_u(const CCFunction& xx, const CCFunction& yy) const { double result = 0.0; @@ -125,6 +161,23 @@ CCPairFunction CCPairFunction::partial_inner(const CCPairFunction& other, } else if (other.is_op_decomposed()) { + // \int \sum_i h(1,2) f(1,3) c_i(1) d_i(3) d1 + // = \sum_i d_i(3) \int h_c_i(1,2) f(1,3) d1 + // = \sum_i d_i(3) H_i(3,2) + const auto& h=this->pure().get_function(); + const auto& c=other.get_vector(integration_index(v2)); + const auto& d=other.get_vector(remaining_index(v2)); + auto& op=*(other.get_operator().get_op()); + op.particle()=integration_index(v1)+1; + + const vector_real_function_6d tmp=partial_mul(h,c,integration_index(v1)+1); + auto H=apply(world(),op,tmp); + real_function_6d result=real_factory_6d(world()); +// const vector_real_function_6d result=partial_mul(H,d,integration_index(v1)+1); + for (int i=0; i b_i(2) d_j(3) - // = \sum_i b~_i(2) d~_i(3) // cholesky decomposition of S_ac + // = \sum_i b~_i(2) d~_i(3) // SVD decomposition of S_ac Tensor ovlp=matrix_inner(world(),this->get_vector(integration_index(v1)),other.get_vector(integration_index(v2))); - cholesky(ovlp); - auto left=transform(world(),this->get_vector(remaining_index(v1)),transpose(ovlp)); - auto right=transform(world(),other.get_vector(remaining_index(v2)),transpose(ovlp)); + Tensor< typename Tensor::scalar_type > s; + Tensor U,VT; + svd(ovlp,U,s,VT); + for (int i=0; iget_vector(remaining_index(v1)),U); + auto right=transform(world(),other.get_vector(remaining_index(v2)),transpose(VT)); return CCPairFunction(left,right); } else if (other.is_op_decomposed()) { - + // \int \sum_ij a_i(1) b_i(2) f(1,3) c_j(1) d_j(3) d1 + // = \sum_ij b_i(2) d_j(3) \int ac_ij(1) f(1,3) d1 + // = \sum_i b_i(2) \sum_j d_j(3) g_ij(3) + // = \sum_i b_i(2) h_i(3) + const auto& a=this->get_vector(integration_index(v1)); + const auto& b=this->get_vector(remaining_index(v1)); + const auto& c=other.get_vector(integration_index(v2)); + const auto& d=other.get_vector(remaining_index(v2)); + const auto& op=*(other.get_operator().get_op()); + std::decay_t h(a.size()); // /same type as a, without reference& + for (int i=0; iis_op_decomposed()) { - + if (other.is_pure()) { + return other.partial_inner(*this,v2,v1); + } else if (other.is_decomposed_no_op()) { + return other.partial_inner(*this,v2,v1); + } else if (other.is_op_decomposed()) { + if (this->is_convertible_to_pure()) { + CCPairFunction tmp=copy(*this); + tmp.convert_to_pure_inplace(); + return tmp.partial_inner(other,v1,v2); + } else if (other.is_convertible_to_pure()) { + CCPairFunction tmp=copy(other); + tmp.convert_to_pure_inplace(); + return this->partial_inner(tmp,v1,v2); + } else { + MADNESS_EXCEPTION("no partial_inner for this combination: ",1); + } + } else { + MADNESS_EXCEPTION("confused CCPairfunction",1); + } } else { MADNESS_EXCEPTION("confused CCPairfunction",1); } @@ -234,7 +325,7 @@ double CCPairFunction::inner_internal(const CCPairFunction& other, const real_fu const CCPairFunction& f1=*this; const CCPairFunction& f2=other; - double thresh=FunctionDefaults<6>::get_thresh(); + double thresh=FunctionDefaults<6>::get_thresh()*0.1; double result = 0.0; if (f1.is_pure() and f2.is_pure()) { diff --git a/src/madness/chem/ccpairfunction.h b/src/madness/chem/ccpairfunction.h index d5969ec573a..b0442695ddd 100644 --- a/src/madness/chem/ccpairfunction.h +++ b/src/madness/chem/ccpairfunction.h @@ -286,6 +286,8 @@ class TwoBodyFunctionSeparatedComponent : public TwoBodyFunctionComponentBase { struct CCPairFunction { using T=double; +using pureT=Function; + public: /// empty ctor @@ -386,6 +388,7 @@ using T=double; MADNESS_CHECK(component->is_decomposed()); return decomposed().get_a(); } + vector_real_function_3d get_b() const { MADNESS_CHECK(component->is_decomposed()); return decomposed().get_b(); @@ -401,6 +404,12 @@ using T=double; return *decomposed().get_operator_ptr(); } + /// can this be converted to a pure representation (depends on the operator, if present) + bool is_convertible_to_pure() const; + + /// convert this into a pure hi-dim function + void convert_to_pure_inplace(); + CCPairFunction& operator*=(const double fac) { if (component->is_pure()) pure()*=fac; if (component->is_decomposed()) decomposed()*=fac; diff --git a/src/madness/chem/test_ccpairfunction.cc b/src/madness/chem/test_ccpairfunction.cc index f6facc3637b..ca03221fb6a 100644 --- a/src/madness/chem/test_ccpairfunction.cc +++ b/src/madness/chem/test_ccpairfunction.cc @@ -15,6 +15,7 @@ using namespace madness; +bool longtest=false; struct data { real_function_3d f1,f2,f3,f4,f5; real_function_6d f12,f23; @@ -359,7 +360,9 @@ int test_partial_inner_6d(World& world, std::shared_ptr + // CCPairFunction p2({f1,f2},{f2,f3}); + // CCPairFunction p4(f23); // two-term, corresponds to p2 + CCPairFunction p5(&f12,std::vector({f1}),std::vector({f2})); + for (auto& test_p1 : {p2, p4}) { + CCPairFunction r1=inner(test_p1,p5,{0,1,2},{0,1,2}); + CCPairFunction r2=inner(test_p1,p5,{0,1,2},{3,4,5}); + CCPairFunction r3=inner(test_p1,p5,{3,4,5},{0,1,2}); + CCPairFunction r4=inner(test_p1,p5,{3,4,5},{3,4,5}); + + double ref_n1=inner(gf11,f2*f1) * g12 + inner(gf12,f1*f2) * g13; + double ref_n2=inner(gf12,f1*f1) * g12 + inner(gf22,f1*f1) * g13; + double ref_n3=inner(gf12,f2*f1) * g11 + inner(gf13,f1*f2) * g12; + double ref_n4=inner(gf22,f1*f1) * g11 + inner(gf23,f1*f1) * g12; + + double n1=inner(r1,p11); + double n2=inner(r2,p11); + double n3=inner(r3,p11); + double n4=inner(r4,p11); +// print("n1, ref_n1",n1,ref_n1, n1-ref_n1); +// print("n2, ref_n2",n2,ref_n2, n2-ref_n2); +// print("n3, ref_n3",n3,ref_n3, n3-ref_n3); +// print("n4, ref_n4",n4,ref_n4, n4-ref_n4); + + bool good=fabs(n1-ref_n1)::get_thresh(); + t1.checkpoint(good,test_p1.name(true)+p5.name()+" -- 1"); + good=fabs(n2-ref_n2)::get_thresh(); + t1.checkpoint(good,test_p1.name(true)+p5.name()+" -- 2"); + good=fabs(n3-ref_n3)::get_thresh(); + t1.checkpoint(good,test_p1.name(true)+p5.name()+" -- 3"); + good=fabs(n4-ref_n4)::get_thresh(); + t1.checkpoint(good,test_p1.name(true)+p5.name()+" -- 4",timer.reset()); + + } + + // test < a(1) b(2) f(1,2) | f(1,3) c(1)d(3) > + // CCPairFunction p3(f12_op.get(),{f1,f2},{f2,f3}); + // CCPairFunction p5(&f12,{f1},{f2}); + if (longtest) { + CCPairFunction r1=inner(p3,p5,{0,1,2},{0,1,2}); + print("time after r1 ", timer.reset()); + double n1=inner(r1,p11); + p3.convert_to_pure_inplace(); + p5.convert_to_pure_inplace(); + print("n1",n1); + print("time after r2a ", timer.reset()); + CCPairFunction r1a=inner(p3,p5,{0,1,2},{0,1,2}); + double n1a=inner(r1a,p11); + print("n1a",n1a); + print("diff",n1-n1a); + CCPairFunction r2=inner(p3,p5,{0,1,2},{3,4,5}); + print("time after r2 ", timer.reset()); + CCPairFunction r3=inner(p3,p5,{3,4,5},{0,1,2}); + print("time after r3 ", timer.reset()); + CCPairFunction r4=inner(p3,p5,{3,4,5},{3,4,5}); + print("time after r4 ", timer.reset()); + + } + + return (t1.get_final_success()) ? 0 : 1; } int test_partial_inner_3d(World& world, std::shared_ptr ncf, const Molecule& molecule, @@ -857,14 +921,14 @@ int main(int argc, char **argv) { mol, nullptr, std::make_pair("slater", 2.0)); isuccess+=test_constructor(world, ncf, mol, ccparam); -// isuccess+=test_overlap(world, ncf, mol, ccparam); -// isuccess+=test_swap_particles(world, ncf, mol, ccparam); -// isuccess+=test_scalar_multiplication(world, ncf, mol, ccparam); -// isuccess+=test_partial_inner_3d(world, ncf, mol, ccparam); + isuccess+=test_overlap(world, ncf, mol, ccparam); + isuccess+=test_swap_particles(world, ncf, mol, ccparam); + isuccess+=test_scalar_multiplication(world, ncf, mol, ccparam); + isuccess+=test_partial_inner_3d(world, ncf, mol, ccparam); isuccess+=test_partial_inner_6d(world, ncf, mol, ccparam); -// isuccess+=test_projector(world, ncf, mol, ccparam); -// FunctionDefaults<3>::set_cubic_cell(-10,10); -// isuccess+=test_helium(world,ncf,mol,ccparam); + isuccess+=test_projector(world, ncf, mol, ccparam); + FunctionDefaults<3>::set_cubic_cell(-10,10); + isuccess+=test_helium(world,ncf,mol,ccparam); data1.clear(); } catch (std::exception& e) { madness::print("an error occured"); From 1f42384b481214c623fe0bcdd237e9c26d953a2c Mon Sep 17 00:00:00 2001 From: fbischoff Date: Sun, 5 Feb 2023 22:20:09 +0100 Subject: [PATCH 006/109] minor cleanup --- src/madness/chem/CCPotentials.cc | 2 -- src/madness/chem/CCStructures.cc | 19 ------------------- src/madness/chem/CCStructures.h | 4 ---- src/madness/chem/ccpairfunction.h | 5 ----- 4 files changed, 30 deletions(-) diff --git a/src/madness/chem/CCPotentials.cc b/src/madness/chem/CCPotentials.cc index e7a9ab31bd4..1448d1d6b49 100644 --- a/src/madness/chem/CCPotentials.cc +++ b/src/madness/chem/CCPotentials.cc @@ -3412,13 +3412,11 @@ void CCPotentials::test_singles_potential() const { void CCPotentials::test() { output.section("Testing enums"); - PairFormat test1 = PT_DECOMPOSED; CalcType test2 = CT_MP2; OpType test3 = OT_G12; FuncType test4 = HOLE; CCState test5 = GROUND_STATE; PotentialType test6 = POT_F3D_; - assign_name(test1); assign_name(test2); assign_name(test3); assign_name(test4); diff --git a/src/madness/chem/CCStructures.cc b/src/madness/chem/CCStructures.cc index 09002270164..949a858b140 100644 --- a/src/madness/chem/CCStructures.cc +++ b/src/madness/chem/CCStructures.cc @@ -444,25 +444,6 @@ CCConvolutionOperator::init_op(const OpType& type, const Parameters& parameters) } -/// Assigns strings to enums for formated output -std::string -assign_name(const PairFormat& input) { - switch (input) { - case PT_FULL: - return "full"; - case PT_DECOMPOSED: - return "decomposed"; - case PT_OP_DECOMPOSED: - return "operator-decomposed"; - default: { - MADNESS_EXCEPTION("Unvalid enum assignement!", 1); - return "undefined"; - } - } - MADNESS_EXCEPTION("assign_name:pairtype, should not end up here", 1); - return "unknown pairtype"; -} - /// Assigns strings to enums for formated output std::string assign_name(const CCState& input) { diff --git a/src/madness/chem/CCStructures.h b/src/madness/chem/CCStructures.h index 1f1631b15a6..324adad1509 100644 --- a/src/madness/chem/CCStructures.h +++ b/src/madness/chem/CCStructures.h @@ -61,10 +61,6 @@ enum PotentialType { POT_singles_ }; -/// Assigns strings to enums for formated output -std::string -assign_name(const PairFormat& input); - /// Assigns strings to enums for formated output std::string assign_name(const CCState& input); diff --git a/src/madness/chem/ccpairfunction.h b/src/madness/chem/ccpairfunction.h index b0442695ddd..00ca3d09f83 100644 --- a/src/madness/chem/ccpairfunction.h +++ b/src/madness/chem/ccpairfunction.h @@ -23,11 +23,6 @@ class ProjectorBase; /// Types of Functions used by CC_function class enum FuncType { UNDEFINED, HOLE, PARTICLE, MIXED, RESPONSE }; -/// FuncTypes used by the CC_function_6d structure -enum PairFormat { PT_UNDEFINED, PT_FULL, PT_DECOMPOSED, PT_OP_DECOMPOSED }; - - - /// structure for a CC Function 3D which holds an index and a type // the type is defined by the enum FuncType (definition at the start of this file) struct CCFunction { From adfd67b99dcc22a95adba96908e7868387953564 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Mon, 6 Feb 2023 21:39:56 +0100 Subject: [PATCH 007/109] reviving 6d testsuite --- src/madness/mra/funcimpl.h | 2 +- src/madness/mra/test6.cc | 79 ++++++++++++++++-------------- src/madness/world/test_utilities.h | 11 ++++- 3 files changed, 53 insertions(+), 39 deletions(-) diff --git a/src/madness/mra/funcimpl.h b/src/madness/mra/funcimpl.h index cb1057ed044..3a5f8dc97f6 100644 --- a/src/madness/mra/funcimpl.h +++ b/src/madness/mra/funcimpl.h @@ -499,7 +499,7 @@ namespace madness { std::vector s0(NDIM/2,s); const double tol=f->get_thresh(); - const double thresh=f->truncate_tol(tol, key); + const double thresh=f->truncate_tol(tol, key)*0.3; // custom factor to "ensure" accuracy // include the wavelets in the norm, makes it much more accurate const double fnorm=fcoeff.normf(); const double gnorm=gcoeff.normf(); diff --git a/src/madness/mra/test6.cc b/src/madness/mra/test6.cc index ee05cd4f85e..6b3cdc5ce8e 100644 --- a/src/madness/mra/test6.cc +++ b/src/madness/mra/test6.cc @@ -36,6 +36,7 @@ /// \brief test various functionality for 6d functions #include +#include using namespace madness; @@ -158,9 +159,8 @@ static double V(const Vector& r) { /// test f(1,2) = g(1) h(2) int test_hartree_product(World& world, const long& k, const double thresh) { - - print("entering hartree_product"); - int nerror=0; + test_output output("testing hartree_product"); +// output.set_cout_to_terminal(); bool good; real_function_3d phi=real_factory_3d(world).f(gauss_3d); @@ -168,28 +168,31 @@ int test_hartree_product(World& world, const long& k, const double thresh) { { real_function_6d ij=hartree_product(phi,phi); + ij.print_size("ij before truncation"); ij.truncate(); + ij.print_size("ij after truncation"); double norm=ij.norm2(); - print("norm(ij)",norm); - double err=ij.err(gauss_6d); - good=is_small(err,thresh); - print(ok(good), "hartree_product(phi,phi) error:",err); - if (not good) nerror++; + print("norm(ij), error, thresh",norm, err, thresh); + + good=is_small(err,thresh*2.5); + output.checkpoint(good, "hartree_product(phi,phi)"); } { - real_function_6d ij=hartree_product(phisq,phi); - double err=ij.err(r2r); - good=is_small(err,thresh); - print(ok(good), "hartree_product(phi^2,phi) error:",err); - if (not good) nerror++; + real_function_6d iij=hartree_product(phisq,phi); + iij.print_size("iij before truncation"); + double norm=iij.norm2(); + double err=iij.err(r2r); + print("norm(iij), error, thresh",norm, err, thresh); + good=is_small(err,thresh*2.0); + output.checkpoint(good, "hartree_product(phi^2,phi)"); } print("all done\n"); - return nerror; + return (output.get_final_success()) ? 0 : 1; } /// test f(1,2)*g(1) @@ -643,8 +646,9 @@ int test(World& world, const long& k, const double thresh) { int main(int argc, char**argv) { - initialize(argc,argv); - World world(SafeMPI::COMM_WORLD); +// initialize(argc,argv); +// World world(SafeMPI::COMM_WORLD); + World& world= initialize(argc,argv); srand(time(nullptr)); startup(world,argc,argv); @@ -678,13 +682,14 @@ int main(int argc, char**argv) { } } - FunctionDefaults<3>::set_thresh(thresh); + FunctionDefaults<3>::set_thresh(thresh*0.1); FunctionDefaults<3>::set_k(k); FunctionDefaults<3>::set_cubic_cell(-L/2,L/2); FunctionDefaults<6>::set_thresh(thresh); FunctionDefaults<6>::set_k(k); FunctionDefaults<6>::set_cubic_cell(-L/2,L/2); FunctionDefaults<6>::set_tensor_type(tt); + FunctionDefaults<6>::set_truncate_mode(3); print("entering testsuite for 6-dimensional functions\n"); print("k ",k); @@ -696,26 +701,28 @@ int main(int argc, char**argv) { int error=0; - real_function_3d phi=real_factory_3d(world).f(gauss_3d); - double norm=phi.norm2(); - if (world.rank()==0) printf("phi.norm2() %12.8f\n",norm); - - real_function_3d phi2=2.0*phi*phi; - norm=phi2.norm2(); - if (world.rank()==0) printf("phi2.norm2() %12.8f\n",norm); - - test(world,k,thresh); - error+=test_hartree_product(world,k,thresh); - error+=test_convolution(world,k,thresh); - error+=test_multiply(world,k,thresh); - error+=test_add(world,k,thresh); - error+=test_exchange(world,k,thresh); - error+=test_inner(world,k,thresh); - error+=test_replicate(world,k,thresh); - - print(ok(error==0),error,"finished test suite\n"); + { + real_function_3d phi=real_factory_3d(world).f(gauss_3d); + double norm=phi.norm2(); + if (world.rank()==0) printf("phi.norm2() %12.8f\n",norm); + + real_function_3d phi2=2.0*phi*phi; + norm=phi2.norm2(); + if (world.rank()==0) printf("phi2.norm2() %12.8f\n",norm); + +// test(world,k,thresh); + error+=test_hartree_product(world,k,thresh); +// error+=test_convolution(world,k,thresh); +// error+=test_multiply(world,k,thresh); +// error+=test_add(world,k,thresh); +// error+=test_exchange(world,k,thresh); +// error+=test_inner(world,k,thresh); +// error+=test_replicate(world,k,thresh); + + print(ok(error==0),error,"finished test suite\n"); + world.gop.fence(); + } - world.gop.fence(); finalize(); return error; diff --git a/src/madness/world/test_utilities.h b/src/madness/world/test_utilities.h index 345b02f262c..d87cfe9a1d4 100644 --- a/src/madness/world/test_utilities.h +++ b/src/madness/world/test_utilities.h @@ -16,6 +16,8 @@ struct test_output { test_output(std::string line) { std::cout << ltrim_to_length(line,70); logger << std::scientific << std::setprecision(8) ; + time_begin=cpu_time(); + time_last_checkpoint=time_begin; set_cout_to_logger(); } @@ -42,7 +44,9 @@ struct test_output { if (not have_checkpoints) print(""); // first checkpoint have_checkpoints=true; std::cout << " " << ltrim_to_length(message,66); - print_success_fail(std::cout,success,time); + double time1=cpu_time()-time_last_checkpoint; + time_last_checkpoint=cpu_time(); + print_success_fail(std::cout,success,time1); if (not success) { print_and_clear_log(); } @@ -65,7 +69,8 @@ struct test_output { set_cout_to_terminal(); if (have_checkpoints) std::cout << ltrim_to_length("--> final result -->",70); success = success and final_success; - print_success_fail(std::cout,success); + double time_end=cpu_time(); + print_success_fail(std::cout,success,time_end-time_begin); if (not success) print_and_clear_log(); return (success) ? 0 : 1; } @@ -94,6 +99,8 @@ struct test_output { bool cout_set_to_logger=false; // do not change this directly! bool have_checkpoints=false; std::streambuf* stream_buffer_cout; + double time_begin=0.0; + double time_last_checkpoint=0.0; }; From 969ced22cb8fa97beb90294ba2ead2f212244cf2 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Tue, 7 Feb 2023 15:08:28 +0100 Subject: [PATCH 008/109] minor changes --- src/madness/chem/CCStructures.cc | 12 +++++++----- src/madness/chem/ccpairfunction.cc | 9 ++++++++- src/madness/chem/ccpairfunction.h | 5 ++++- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/madness/chem/CCStructures.cc b/src/madness/chem/CCStructures.cc index 949a858b140..93e6281bf29 100644 --- a/src/madness/chem/CCStructures.cc +++ b/src/madness/chem/CCStructures.cc @@ -406,33 +406,35 @@ size_t CCConvolutionOperator::info() const { SeparatedConvolution * CCConvolutionOperator::init_op(const OpType& type, const Parameters& parameters) const { + bool debug=false; + bool printme=(world.rank()==0) and debug; switch (type) { case OT_G12 : { - if (world.rank() == 0) + if (printme) std::cout << "Creating " << assign_name(type) << " Operator with thresh=" << parameters.thresh_op << " and lo=" << parameters.lo << std::endl; return CoulombOperatorPtr(world, parameters.lo, parameters.thresh_op); } case OT_F12 : { - if (world.rank() == 0) + if (printme) std::cout << "Creating " << assign_name(type) << " Operator with thresh=" << parameters.thresh_op << " and lo=" << parameters.lo << " and Gamma=" << parameters.gamma << std::endl; return SlaterF12OperatorPtr(world, parameters.gamma, parameters.lo, parameters.thresh_op); } case OT_SLATER : { - if (world.rank() == 0) + if (printme) std::cout << "Creating " << assign_name(type) << " Operator with thresh=" << parameters.thresh_op << " and lo=" << parameters.lo << " and Gamma=" << parameters.gamma << std::endl; return SlaterOperatorPtr(world, parameters.gamma, parameters.lo, parameters.thresh_op); } case OT_BSH : { - if (world.rank() == 0) + if (printme) std::cout << "Creating " << assign_name(type) << " Operator with thresh=" << parameters.thresh_op << " and lo=" << parameters.lo << " and Gamma=" << parameters.gamma << std::endl; return BSHOperatorPtr3D(world, parameters.gamma, parameters.lo, parameters.thresh_op); } case OT_ONE : { - if (world.rank() == 0) + if (printme) std::cout << "Creating " << assign_name(type) << " Operator " << std::endl; return nullptr; } diff --git a/src/madness/chem/ccpairfunction.cc b/src/madness/chem/ccpairfunction.cc index 18b63d13633..f34ed5c3bc0 100644 --- a/src/madness/chem/ccpairfunction.cc +++ b/src/madness/chem/ccpairfunction.cc @@ -398,7 +398,7 @@ double CCPairFunction::inner_internal(const CCPairFunction& other, const real_fu else ket = CCPairFunction(f2.get_a(),f2.get_b()); double tmp=op.first * inner(ket,bra,R2); - print("inner",bra.name(true),ket.name()," : ",tmp); +// print("inner",bra.name(true),ket.name()," : ",tmp); result+=tmp; } } else MADNESS_EXCEPTION( @@ -458,6 +458,7 @@ std::vector apply(const ProjectorBase& projector, const std::vec } } else if (pf.is_op_decomposed()) { if (auto SO=dynamic_cast*>(&projector)) { +// CCTimer t(world,"SO block"); // Q12 = 1 - O1 (1 - 1/2 O2) - O2 (1 - 1/2 O1) QProjector Q1(world,SO->bra1(),SO->ket1()); Q1.set_particle(0); @@ -465,8 +466,11 @@ std::vector apply(const ProjectorBase& projector, const std::vec Q2.set_particle(1); auto tmp=Q1(Q2(std::vector({pf}))); for (auto& t: tmp) result.push_back(t); +// t.print(); } else if (auto P=dynamic_cast*>(&projector)) { +// CCTimer t(world,"P block"); + // Q12 = 1 - O1 (1 - 1/2 O2) - O2 (1 - 1/2 O1) std::vector tmp= zero_functions_compressed(world,P->get_ket_vector().size()); // per term a_i b_k: @@ -485,8 +489,10 @@ std::vector apply(const ProjectorBase& projector, const std::vec truncate(world,tmp); if (P->get_particle()==0) result.push_back(CCPairFunction(P->get_ket_vector(),tmp)); if (P->get_particle()==1) result.push_back(CCPairFunction(tmp,P->get_ket_vector())); +// t.print(); } else if (auto Q=dynamic_cast*>(&projector)) { +// CCTimer t(world,"Q block"); // Q1 f12 |a_i b_i> = f12 |a_i b_i> - \sum_k |k(1) a_i(2)*f_(kb_i)(2) > result.push_back(pf); // reuse the projector code above @@ -495,6 +501,7 @@ std::vector apply(const ProjectorBase& projector, const std::vec t*=-1.0; result.push_back(t); } +// t.print(); } else { MADNESS_EXCEPTION("CCPairFunction: unknown projector type",1); diff --git a/src/madness/chem/ccpairfunction.h b/src/madness/chem/ccpairfunction.h index 00ca3d09f83..a6ae94b94a8 100644 --- a/src/madness/chem/ccpairfunction.h +++ b/src/madness/chem/ccpairfunction.h @@ -457,12 +457,15 @@ using pureT=Function; } friend double inner(const std::vector& va, const std::vector& vb) { + double wall0=cpu_time(); real_function_3d R2; double result=0.0; for (auto& a : va) { for (auto& b : vb) { double tmp=a.inner_internal(b,R2); - print("result from inner",a.name(true),b.name(),tmp); + double wall1=cpu_time(); +// print("result from inner",a.name(true),b.name(),tmp,wall1-wall0,"s"); + wall0=wall1; result+=tmp; } } From 0db4e00cf307edf2e821ebc92a2d3aaee0e7c303 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Tue, 7 Feb 2023 16:17:50 +0100 Subject: [PATCH 009/109] some refactoring --- src/madness/chem/CCPotentials.cc | 142 ++++++++++++------------ src/madness/chem/CCPotentials.h | 12 +- src/madness/chem/CCStructures.h | 8 ++ src/madness/chem/ccpairfunction.cc | 3 +- src/madness/chem/ccpairfunction.h | 32 ++++-- src/madness/chem/test_ccpairfunction.cc | 55 ++++----- 6 files changed, 139 insertions(+), 113 deletions(-) diff --git a/src/madness/chem/CCPotentials.cc b/src/madness/chem/CCPotentials.cc index 1448d1d6b49..4d202f08bf0 100644 --- a/src/madness/chem/CCPotentials.cc +++ b/src/madness/chem/CCPotentials.cc @@ -24,10 +24,12 @@ CCPotentials::CCPotentials(World& world_, std::shared_ptr nemo, const CCP //mo_ket_(make_mo_ket(nemo)), //mo_bra_(make_mo_bra(nemo)), //orbital_energies_(init_orbital_energies(nemo)) - g12(world, OT_G12, param), f12(world, OT_F12, param), +// g12(std::shared_ptrget_calc()->molecule), get_potentials(world, param), output(world) { + g12=std::shared_ptr(new CCConvolutionOperator(world,OT_G12,param)); + f12=std::shared_ptr(new CCConvolutionOperator(world,OT_F12,param)); output.debug = parameters.debug(); // reset_nemo(nemo); // g12.update_elements(mo_bra_, mo_ket_); @@ -87,7 +89,7 @@ CCPotentials::make_pair_gs(const real_function_6d& u, const CC_vecfunction& tau, CCPairFunction u_part(u); functions.push_back(u_part); if (parameters.decompose_Q()) { - CCPairFunction f_part(&f12, t(i), t(j)); + CCPairFunction f_part(f12, t(i), t(j)); functions.push_back(f_part); CCPairFunction Ot1 = apply_Ot(f_part, pt, 1); CCPairFunction Ot2 = apply_Ot(f_part, pt, 2); @@ -232,9 +234,9 @@ CCPotentials::make_pair_ex(const real_function_6d& u, const CC_vecfunction& tau, CCPairFunction u_part(u); functions.push_back(u_part); if (parameters.decompose_Q()) { - CCPairFunction f_xt(&f12, x(i), t(j)); + CCPairFunction f_xt(f12, x(i), t(j)); functions.push_back(f_xt); - CCPairFunction f_tx(&f12, t(i), x(j)); + CCPairFunction f_tx(f12, t(i), x(j)); functions.push_back(f_tx); { CCPairFunction Ot1_xt = apply_Ot(f_xt, pt, 1); // O1t(f|xt>) @@ -257,7 +259,7 @@ CCPotentials::make_pair_ex(const real_function_6d& u, const CC_vecfunction& tau, functions.push_back(QtOt_tx.invert_sign()); // - " } if (parameters.QtAnsatz()) { - CCPairFunction ftt(&f12, t(i), t(j)); // f|tt> + CCPairFunction ftt(f12, t(i), t(j)); // f|tt> CCPairFunction O1x_tt = apply_Ot(ftt, x, 1); // O1x(f|tt>) CCPairFunction OxQt_tt = apply_Qt(O1x_tt, pt, 2); // O1xQt(f|tt>) functions.push_back(OxQt_tt.invert_sign()); // - " @@ -322,11 +324,11 @@ CCPotentials::compute_pair_correlation_energy(const CCPair& u, const CC_vecfunct for (size_t mm = 0; mm < u.functions.size(); mm++) { double tmp = 0.0; - const double part1 = make_xy_op_u(mobi, mobj, g12, u.functions[mm]); + const double part1 = make_xy_op_u(mobi, mobj, *g12, u.functions[mm]); if (symmetric) tmp = part1; else //if(world.rank()==0) std::cout << std::fixed << std::setprecision(10) << part1 << "\n"; { - const double part2 = make_xy_op_u(mobj, mobi, g12, u.functions[mm]); + const double part2 = make_xy_op_u(mobj, mobi, *g12, u.functions[mm]); tmp = 2.0 * (2.0 * part1 - part2); // non symmetric pairs -> offdiagonal -> count twice } result += tmp; @@ -336,8 +338,8 @@ CCPotentials::compute_pair_correlation_energy(const CCPair& u, const CC_vecfunct } if (u.ctype == CT_CC2 && !singles.get_vecfunction().empty()) { MADNESS_ASSERT(singles.type == PARTICLE); - const double omega_s = 2.0 * mobi.inner(g12(mobj, singles(u.j)) * singles(u.i).function) - - mobi.inner(g12(mobj, singles(u.i)) * singles(u.j).function); + const double omega_s = 2.0 * mobi.inner((*g12)(mobj, singles(u.j)) * singles(u.i).function) - + mobi.inner((*g12)(mobj, singles(u.i)) * singles(u.j).function); if (world.rank() == 0) std::cout << std::setw(15) << "from singles=" << std::setfill(' ') << std::fixed << std::setprecision(10) << omega_s << "\n\n"; @@ -408,11 +410,11 @@ CCPotentials::compute_excited_pair_energy(const CCPair& d, const CC_vecfunction& const CCFunction& xbi = xbra(d.i); const CCFunction& mobj = mo_bra_(d.j); double result = 0.0; - double s2b = 2.0 * make_xy_op_u(xbi, mobj, g12, d.functions) - make_xy_op_u(mobj, xbi, g12, d.functions); + double s2b = 2.0 * make_xy_op_u(xbi, mobj, *g12, d.functions) - make_xy_op_u(mobj, xbi, *g12, d.functions); double s2c = 0.0; for (const auto& ktmp : x.functions) { const size_t k = ktmp.first; - const real_function_3d j_igk = g12(mo_bra_(d.i), mo_ket_(k)) * mo_bra_(d.j).function; + const real_function_3d j_igk = (*g12)(mo_bra_(d.i), mo_ket_(k)) * mo_bra_(d.j).function; s2c -= 2.0 * make_xy_u(xbra(k), j_igk, d.functions) - make_xy_u(j_igk, xbra(k), d.functions); } result = s2b + s2c; @@ -438,23 +440,23 @@ CCPotentials::compute_cispd_energy(const CC_vecfunction& x, const Pairs for (const auto& ktmp : x.functions) { // s2b part: const size_t k = ktmp.first; - s2b += 2.0 * make_xy_op_u(xbra(i), mo_bra_(k), g12, get_pair_function(cispd, i, k)) - - make_xy_op_u(mo_bra_(k), xbra(i), g12, get_pair_function(cispd, i, k)); - const real_function_3d kgi = g12(mo_bra_(k), mo_ket_(i)); - const real_function_3d kgxi = g12(mo_bra_(k), x(i)); - const real_function_3d kgxk = g12(mo_bra_(k), x(k)); + s2b += 2.0 * make_xy_op_u(xbra(i), mo_bra_(k), *g12, get_pair_function(cispd, i, k)) - + make_xy_op_u(mo_bra_(k), xbra(i), *g12, get_pair_function(cispd, i, k)); + const real_function_3d kgi = (*g12)(mo_bra_(k), mo_ket_(i)); + const real_function_3d kgxi = (*g12)(mo_bra_(k), x(i)); + const real_function_3d kgxk = (*g12)(mo_bra_(k), x(k)); for (const auto& ltmp : x.functions) { // s2c part: const size_t l = ltmp.first; - const real_function_3d k_lgxk = mo_bra_(k).function * g12(mo_bra_(l), x(k)); + const real_function_3d k_lgxk = mo_bra_(k).function * (*g12)(mo_bra_(l), x(k)); const real_function_3d l_kgxk = mo_bra_(l).function * kgxk; const real_function_3d l_kgi = mo_bra_(l).function * kgi; const real_function_3d l_kgxi = mo_bra_(l).function * kgxi; s2c += 2.0 * make_xy_u(xbra(i), l_kgi, get_pair_function(cispd, k, l)) - make_xy_u(l_kgi, xbra(i), get_pair_function(cispd, k, l)); const double xil = xbra(i).function.inner(x(l).function); - s4a += xil * (2.0 * make_xy_op_u(mo_bra_(l), mo_bra_(k), g12, get_pair_function(mp2, i, k)) - - make_xy_op_u(mo_bra_(k), mo_bra_(l), g12, get_pair_function(mp2, i, k))); + s4a += xil * (2.0 * make_xy_op_u(mo_bra_(l), mo_bra_(k), *g12, get_pair_function(mp2, i, k)) - + make_xy_op_u(mo_bra_(k), mo_bra_(l), *g12, get_pair_function(mp2, i, k))); s4b += 2.0 * make_xy_u(xbra(i), l_kgxi, get_pair_function(mp2, k, l)) - make_xy_u(l_kgxi, xbra(i), get_pair_function(mp2, k, l)); s4c += 4.0 * make_xy_u(xbra(i), l_kgxk, get_pair_function(mp2, i, l)) - @@ -514,7 +516,7 @@ CCPotentials::fock_residue_6d(const CCPair& u) const { // make the coulomb and local Un part with the composite factory real_function_3d hartree_potential = real_factory_3d(world); for (const auto& tmp : mo_ket_.functions) - hartree_potential += g12(mo_bra_(tmp.first), mo_ket_(tmp.first)); + hartree_potential += (*g12)(mo_bra_(tmp.first), mo_ket_(tmp.first)); real_function_3d local_part = (2.0 * hartree_potential + nemo_->ncf->U2()); if (parameters.debug()) local_part.print_size("vlocal"); @@ -853,7 +855,7 @@ CCPotentials::make_constant_part_cc2_gs(const CCPair& u, const CC_vecfunction& t CCTimer time_Vcc(world, "G(Coulomb Coupling Potential)"); real_function_6d GVcc = real_factory_6d(world); // make the g12|titj> function as op_decomposed function (not constructed in 6D) - CCPairFunction gtt(&g12, ti, tj); + CCPairFunction gtt(g12, ti, tj); // make Otau(1)(g12|titj>) CCPairFunction Otau1_gtt = apply_Ot(gtt, tau, 1); // make Otau1Q2 part and the Otau1Otau2. Otau1Otau2 part IS NOT used in the symmetry exploit @@ -920,7 +922,7 @@ CCPotentials::make_constant_part_cc2_Qt_gs(const CCPair& u, const CC_vecfunction CCTimer time_comm(world, "commutator"); const vector_real_function_3d Vtmp = get_potentials(tau, POT_singles_); const CC_vecfunction V(Vtmp, UNDEFINED, parameters.freeze()); - const CCPairFunction ftt(&f12, ti, tj); + const CCPairFunction ftt(f12, ti, tj); const CCPairFunction O1ftt = apply_Ot(ftt, V, 1); const CCPairFunction O1Q2ftt = apply_Qt(O1ftt, t, 2); const real_function_6d part1 = -2.0 * apply_G(O1Q2ftt, G); @@ -999,7 +1001,7 @@ CCPotentials::make_constant_part_cispd(const CCPair& u, const CC_vecfunction& x, real_function_6d GVcc; { time_cr.start(); - const CCPairFunction gij(&g12, moi, moj); + const CCPairFunction gij(g12, moi, moj); const CCPairFunction O1x_gij = apply_Ot(gij, x, 1); const CCPairFunction OQ_part = apply_Qt(O1x_gij, mo_ket_, 2); const real_function_6d GOQ = -2.0 * apply_G(OQ_part, G); @@ -1122,7 +1124,7 @@ CCPotentials::make_constant_part_cispd_Qt(const CCPair& u, const CC_vecfunction& const vector_real_function_3d Vxtmp = sub(world, get_potentials(x, POT_singles_), x.omega * x.get_vecfunction()); const CC_vecfunction Vx(Vxtmp, UNDEFINED, parameters.freeze()); - CCPairFunction ftt(&f12, moi, moj); + CCPairFunction ftt(f12, moi, moj); real_function_6d tmp1; real_function_6d tmp2; { @@ -1212,7 +1214,7 @@ CCPotentials::make_constant_part_cc2_ex(const CCPair& u, const CC_vecfunction& t real_function_6d tmp2; // make the xt parts of the functional and the QtOx part of the projector response { - CCPairFunction gxt(&g12, xi, tj); + CCPairFunction gxt(g12, xi, tj); // make QOtau*g*|xt> CCPairFunction O2tmp = apply_Ot(gxt, tau, 2); CCPairFunction QO = apply_Qt(O2tmp, mo_ket_, 1); @@ -1225,7 +1227,7 @@ CCPotentials::make_constant_part_cc2_ex(const CCPair& u, const CC_vecfunction& t CCPairFunction OO = apply_Ot(O1tmp, tau, 2); const real_function_6d part3 = -2.0 * apply_G(OO, G); // QtOx*g|titj> - CCPairFunction gtt(&g12, ti, tj); + CCPairFunction gtt(g12, ti, tj); CCPairFunction O2x = apply_Ot(gtt, x, 2); CCPairFunction QtOx = apply_Qt(O2x, t, 1); const real_function_6d part4 = -2.0 * apply_G(QtOx, G); @@ -1233,7 +1235,7 @@ CCPotentials::make_constant_part_cc2_ex(const CCPair& u, const CC_vecfunction& t } if (symmetric) tmp2 = swap_particles(tmp1); else { - CCPairFunction gtx(&g12, ti, xj); + CCPairFunction gtx(g12, ti, xj); // make QOtau*g*|tx> CCPairFunction O2tmp = apply_Ot(gtx, tau, 2); CCPairFunction QO = apply_Qt(O2tmp, mo_ket_, 1); @@ -1246,7 +1248,7 @@ CCPotentials::make_constant_part_cc2_ex(const CCPair& u, const CC_vecfunction& t CCPairFunction OO = apply_Ot(O1tmp, tau, 2); const real_function_6d part3 = -2.0 * apply_G(OO, G); // OxQt*g|titj> - CCPairFunction gtt(&g12, ti, tj); + CCPairFunction gtt(g12, ti, tj); CCPairFunction O1x = apply_Ot(gtt, x, 1); CCPairFunction OxQt = apply_Qt(O1x, t, 2); const real_function_6d part4 = -2.0 * apply_G(OxQt, G); @@ -1352,7 +1354,7 @@ CCPotentials::make_constant_part_cc2_Qt_ex(const CCPair& u, const CC_vecfunction const vector_real_function_3d Vtmp = get_potentials(tau, POT_singles_); const CC_vecfunction V(Vtmp, UNDEFINED, parameters.freeze()); { - const CCPairFunction fxt(&f12, xi, tj); + const CCPairFunction fxt(f12, xi, tj); const CCPairFunction O1V = apply_Ot(fxt, V, 1); const CCPairFunction OQ = apply_Qt(O1V, t, 2); const CCPairFunction O2V = apply_Ot(fxt, V, 2); @@ -1364,7 +1366,7 @@ CCPotentials::make_constant_part_cc2_Qt_ex(const CCPair& u, const CC_vecfunction real_function_6d part2; // the tx parts if (symmetric) part2 = swap_particles(part1); else { - const CCPairFunction ftx(&f12, ti, xj); + const CCPairFunction ftx(f12, ti, xj); const CCPairFunction O1V = apply_Ot(ftx, V, 1); const CCPairFunction OQ = apply_Qt(O1V, t, 2); const CCPairFunction O2V = apply_Ot(ftx, V, 2); @@ -1392,7 +1394,7 @@ CCPotentials::make_constant_part_cc2_Qt_ex(const CCPair& u, const CC_vecfunction const vector_real_function_3d Vttmp = get_potentials(tau, POT_singles_); const CC_vecfunction Vx(Vxtmp, UNDEFINED, parameters.freeze()); const CC_vecfunction Vt(Vttmp, UNDEFINED, parameters.freeze()); - CCPairFunction ftt(&f12, ti, tj); + CCPairFunction ftt(f12, ti, tj); real_function_6d tmp1; real_function_6d tmp2; { @@ -1600,7 +1602,7 @@ CCPotentials::apply_transformed_Ue(const CCFunction& x, const CCFunction& y, con const double a = inner(Uxy, tmp); const real_function_3d xx = (x.function * x.function * nemo_->ncf->square()); const real_function_3d yy = (y.function * y.function * nemo_->ncf->square()); - const real_function_3d gxx = g12(xx); + const real_function_3d gxx = (*g12)(xx); const double aa = inner(yy, gxx); const double error = std::fabs(a - aa); const double diff = a - aa; @@ -1862,7 +1864,7 @@ CCPotentials::apply_gf(const real_function_3d& f) const { BSHOperatorPtr3D(world, parameters.gamma(), parameters.lo(), parameters.thresh_poisson())); double bsh_prefactor = 4.0 * constants::pi; double prefactor = 1.0 / (2.0 * parameters.gamma()); - return prefactor * (g12(f) - bsh_prefactor * (*fBSH)(f)).truncate(); + return prefactor * ((*g12)(f) - bsh_prefactor * (*fBSH)(f)).truncate(); } double @@ -1939,9 +1941,9 @@ CCPotentials::apply_s2b_operation(const CCFunction& bra, const CCPairFunction& u real_function_3d result; MADNESS_ASSERT(particle == 1 || particle == 2); if (u.is_pure()) { - result = u.dirac_convolution(bra, g12, particle); + result = u.dirac_convolution(bra, *g12, particle); } else if (u.is_decomposed_no_op()) { - result = u.dirac_convolution(bra, g12, particle); + result = u.dirac_convolution(bra, *g12, particle); } else if (u.is_op_decomposed()) { // retunrns _particle CCFunction a; @@ -2404,7 +2406,7 @@ CCPotentials::fock_residue_closed_shell(const CC_vecfunction& singles) const { const CCFunction& taui = tmpi.second; real_function_3d hartree_potential = real_function_3d(world); for (const auto& tmpk : mo_ket_.functions) - hartree_potential += g12(mo_bra_(tmpk.first), tmpk.second); + hartree_potential += (*g12)(mo_bra_(tmpk.first), tmpk.second); const real_function_3d Ji = hartree_potential * taui.function; J.push_back(Ji); } @@ -2461,7 +2463,7 @@ madness::real_function_3d CCPotentials::K(const CCFunction& f) const { real_function_3d result = real_factory_3d(world); for (const auto k_iterator : mo_ket_.functions) { - result += g12(mo_bra_(k_iterator.first), f) * mo_ket_(k_iterator.first).function; + result += (*g12)(mo_bra_(k_iterator.first), f) * mo_ket_(k_iterator.first).function; } return result; } @@ -2487,7 +2489,7 @@ CCPotentials::apply_K(const real_function_6d& u, const size_t& particle) const { real_function_6d copyu = copy(u); real_function_6d X = (multiply(copyu, copy(mo_bra_(k).function), particle)).truncate(); // real_function_6d Y=(*poisson)(X); - real_function_6d Y = g12(X, particle); // overwrite X to save space + real_function_6d Y = (*g12)(X, particle); // overwrite X to save space result += (multiply(copy(Y), copy(mo_ket_(k).function), particle)).truncate(); // this will destroy X, but I d not intend to use it again so I choose here to save this copy } @@ -2559,7 +2561,7 @@ CCPotentials::make_f_xy(const CCFunction& x, const CCFunction& y, const real_con if (x.type != UNDEFINED && y.type != UNDEFINED) { CCTimer timer_db(world, "f|xy> sanity check"); const double test1 = (mo_bra_(y.i).function).inner(fxy.project_out(mo_bra_(x.i).function, 0)); - const double test2 = (mo_bra_(y.i).function).inner(f12(mo_bra_(x.i), x) * y.function); + const double test2 = (mo_bra_(y.i).function).inner((*f12)(mo_bra_(x.i), x) * y.function); const double sanity = test1 - test2; if (fabs(sanity) > FunctionDefaults<6>::get_thresh()) { if (world.rank() == 0) @@ -2620,11 +2622,11 @@ CCPotentials::ccs_unprojected(const CC_vecfunction& ti, const CC_vecfunction& tk for (const auto& itmp : ti.functions) { real_function_3d kgtk = real_factory_3d(world); for (const auto& ktmp : tk.functions) - kgtk += g12(mo_bra_(ktmp.first), ktmp.second); + kgtk += (*g12)(mo_bra_(ktmp.first), ktmp.second); const real_function_3d kgtk_ti = kgtk * ti(itmp.first).function; real_function_3d kgti_tk = real_factory_3d(world); for (const auto& ktmp : tk.functions) - kgti_tk += g12(mo_bra_(ktmp.first), ti(itmp.first)) * tk(ktmp.first).function; + kgti_tk += (*g12)(mo_bra_(ktmp.first), ti(itmp.first)) * tk(ktmp.first).function; const real_function_3d resulti = 2.0 * kgtk_ti - kgti_tk; result.push_back(resulti); } @@ -2654,8 +2656,8 @@ CCPotentials::x_s3a(const CC_vecfunction& x, const CC_vecfunction& t) const { for (const auto ktmp : mo_ket_.functions) { // unfrozen summation !!!!!! important !!!! const size_t k = ktmp.first; - const double gpart = make_xy_op_ab(x(i), mo_bra_(k), g12, t(i), mo_ket_(k)); - const double xpart = make_xy_op_ab(x(i), mo_bra_(k), g12, mo_ket_(k), t(i)); + const double gpart = make_xy_op_ab(x(i), mo_bra_(k), *g12, t(i), mo_ket_(k)); + const double xpart = make_xy_op_ab(x(i), mo_bra_(k), *g12, mo_ket_(k), t(i)); pot += (2.0 * gpart - xpart); } } @@ -2683,8 +2685,8 @@ CCPotentials::x_s3c(const CC_vecfunction& x, const CC_vecfunction& t) const { const size_t i = itmp.first; for (const auto ktmp : t.functions) { const size_t k = ktmp.first; - result += (2.0 * make_xy_op_ab(x(i), mo_bra_(k), g12, mo_ket_(i), t(k)) - - make_xy_op_ab(x(i), mo_bra_(k), g12, t(k), mo_ket_(i))); + result += (2.0 * make_xy_op_ab(x(i), mo_bra_(k), *g12, mo_ket_(i), t(k)) - + make_xy_op_ab(x(i), mo_bra_(k), *g12, t(k), mo_ket_(i))); } } return result; @@ -2699,8 +2701,8 @@ CCPotentials::x_s5b(const CC_vecfunction& x, const CC_vecfunction& t1, const CC_ const size_t i = itmp.first; for (const auto ktmp : t1.functions) { const size_t k = ktmp.first; - result += (2.0 * make_xy_op_ab(x(i), mo_bra_(k), g12, t1(i), t2(k)) - - make_xy_op_ab(x(i), mo_bra_(k), g12, t2(k), t1(i))); + result += (2.0 * make_xy_op_ab(x(i), mo_bra_(k), *g12, t1(i), t2(k)) - + make_xy_op_ab(x(i), mo_bra_(k), *g12, t2(k), t1(i))); } } return result; @@ -2717,8 +2719,8 @@ CCPotentials::x_s5c(const CC_vecfunction& x, const CC_vecfunction& t1, const CC_ const size_t k = ktmp.first; for (const auto ltmp : t2.functions) { const size_t l = ltmp.first; - result += (2.0 * make_xy_op_ab(mo_bra_(l), mo_bra_(k), g12, mo_ket_(i), t1(k)) - - make_xy_op_ab(mo_bra_(l), mo_bra_(k), g12, t1(k), mo_ket_(i))) * + result += (2.0 * make_xy_op_ab(mo_bra_(l), mo_bra_(k), *g12, mo_ket_(i), t1(k)) - + make_xy_op_ab(mo_bra_(l), mo_bra_(k), *g12, t1(k), mo_ket_(i))) * x(i).function.inner(t2(l).function); } } @@ -2738,8 +2740,8 @@ CCPotentials::x_s6(const CC_vecfunction& x, const CC_vecfunction& t1, const CC_v const size_t k = ktmp.first; for (const auto ltmp : t2.functions) { const size_t l = ltmp.first; - result += (2.0 * make_xy_op_ab(mo_bra_(l), mo_bra_(k), g12, t3(i), t1(k)) - - make_xy_op_ab(mo_bra_(l), mo_bra_(k), g12, t1(k), t3(i))) * + result += (2.0 * make_xy_op_ab(mo_bra_(l), mo_bra_(k), *g12, t3(i), t1(k)) - + make_xy_op_ab(mo_bra_(l), mo_bra_(k), *g12, t1(k), t3(i))) * x(i).function.inner(t2(l).function); } } @@ -2754,8 +2756,8 @@ CCPotentials::x_s2b(const CC_vecfunction& x, const Pairs& u) const { const size_t i = itmp.first; for (const auto ktmp : x.functions) { const size_t k = ktmp.first; - result += (2.0 * make_xy_op_u(x(i), mo_bra_(k), g12, get_pair_function(u, i, k)) - - make_xy_op_u(mo_bra_(k), x(i), g12, get_pair_function(u, i, k))); + result += (2.0 * make_xy_op_u(x(i), mo_bra_(k), *g12, get_pair_function(u, i, k)) - + make_xy_op_u(mo_bra_(k), x(i), *g12, get_pair_function(u, i, k))); } } return result; @@ -2768,7 +2770,7 @@ CCPotentials::x_s2c(const CC_vecfunction& x, const Pairs& u) const { const size_t i = itmp.first; for (const auto ktmp : x.functions) { const size_t k = ktmp.first; - const real_function_3d kgi = g12(mo_bra_(k), mo_ket_(i)); + const real_function_3d kgi = (*g12)(mo_bra_(k), mo_ket_(i)); for (const auto ltmp : x.functions) { const size_t l = ltmp.first; real_function_3d l_kgi = (mo_bra_(l).function * kgi).truncate(); @@ -2790,8 +2792,8 @@ CCPotentials::x_s4a(const CC_vecfunction& x, const CC_vecfunction& t, const Pair const size_t k = ktmp.first; for (const auto ltmp : x.functions) { const size_t l = ltmp.first; - result += (2.0 * make_xy_op_u(mo_bra_(l), mo_bra_(k), g12, get_pair_function(u, i, k)) - - make_xy_op_u(mo_bra_(k), mo_bra_(l), g12, get_pair_function(u, i, k))) * + result += (2.0 * make_xy_op_u(mo_bra_(l), mo_bra_(k), *g12, get_pair_function(u, i, k)) - + make_xy_op_u(mo_bra_(k), mo_bra_(l), *g12, get_pair_function(u, i, k))) * x(i).function.inner(t(l).function); } } @@ -2807,7 +2809,7 @@ CCPotentials::x_s4b(const CC_vecfunction& x, const CC_vecfunction& t, const Pair const size_t i = itmp.first; for (const auto ktmp : x.functions) { const size_t k = ktmp.first; - const real_function_3d kgti = g12(mo_bra_(k), t(i)); + const real_function_3d kgti = (*g12)(mo_bra_(k), t(i)); for (const auto ltmp : x.functions) { const size_t l = ltmp.first; real_function_3d l_kgti = (mo_bra_(l).function * kgti).truncate(); @@ -2827,10 +2829,10 @@ CCPotentials::x_s4c(const CC_vecfunction& x, const CC_vecfunction& t, const Pair const size_t i = itmp.first; for (const auto ktmp : x.functions) { const size_t k = ktmp.first; - const real_function_3d kgtk = g12(mo_bra_(k), t(k)); + const real_function_3d kgtk = (*g12)(mo_bra_(k), t(k)); for (const auto ltmp : x.functions) { const size_t l = ltmp.first; - const real_function_3d lgtk = g12(mo_bra_(l), t(k)); + const real_function_3d lgtk = (*g12)(mo_bra_(l), t(k)); const real_function_3d k_lgtk = (mo_bra_(k).function * lgtk).truncate(); const real_function_3d l_kgtk = (mo_bra_(l).function * kgtk).truncate(); result += (4.0 * make_xy_u(x(i), l_kgtk, get_pair_function(u, i, l)) - @@ -2897,7 +2899,7 @@ CCPotentials::s2c(const CC_vecfunction& singles, const Pairs& doubles) c real_function_3d resulti_r = real_factory_3d(world); for (const auto& ktmp : singles.functions) { const size_t k = ktmp.first; - const real_function_3d kgi = g12(mo_bra_(k), mo_ket_(i)); + const real_function_3d kgi = (*g12)(mo_bra_(k), mo_ket_(i)); for (const auto& ltmp : singles.functions) { const size_t l = ltmp.first; const real_function_3d l_kgi = mo_bra_(l).function * kgi; @@ -2961,7 +2963,7 @@ CCPotentials::s4b(const CC_vecfunction& singles, const Pairs& doubles) c real_function_3d resulti = real_factory_3d(world); for (const auto& ktmp : singles.functions) { const size_t k = ktmp.first; - const real_function_3d kgi = g12(mo_bra_(k), singles(i)); + const real_function_3d kgi = (*g12)(mo_bra_(k), singles(i)); vector_real_function_3d l_kgi = mul_sparse(world, kgi, active_mo_bra, parameters.thresh_3D()); truncate(world, l_kgi); for (const auto& ltmp : singles.functions) { @@ -2992,7 +2994,7 @@ CCPotentials::s4c(const CC_vecfunction& singles, const Pairs& doubles) c real_function_3d kgtauk = real_factory_3d(world); for (const auto& ktmp : singles.functions) { const size_t k = ktmp.first; - kgtauk += g12(mo_bra_(k), singles(k)); + kgtauk += (*g12)(mo_bra_(k), singles(k)); } vector_real_function_3d l_kgtauk = mul(world, kgtauk, active_mo_bra); truncate(world, l_kgtauk); @@ -3005,7 +3007,7 @@ CCPotentials::s4c(const CC_vecfunction& singles, const Pairs& doubles) c } for (const auto& ktmp : singles.functions) { const size_t k = ktmp.first; - const real_function_3d k_lgtauk = (mo_bra_(k).function * g12(mo_bra_(l), singles(k))).truncate(); + const real_function_3d k_lgtauk = (mo_bra_(k).function * (*g12)(mo_bra_(l), singles(k))).truncate(); for (size_t mm = 0; mm < uil.size(); mm++) { part3 += uil[mm].project_out(k_lgtauk, 2); part4 += uil[mm].project_out(k_lgtauk, 1); @@ -3104,7 +3106,7 @@ void CCPotentials::test_pair_consistency(const CCPairFunction& u, const size_t i v1.push_back(u); std::vector v2; v2.push_back(u); - CCPairFunction ftt(&f12, mo_ket_(i), mo_ket_(j)); + CCPairFunction ftt(f12, mo_ket_(i), mo_ket_(j)); CCPairFunction O1xftt = apply_Ot(ftt, x, 1); CCPairFunction OxQftt = apply_Qt(O1xftt, mo_ket_, 2); CCPairFunction OxQ = OxQftt.invert_sign(); @@ -3129,7 +3131,7 @@ void CCPotentials::test_pair_consistency(const CCPairFunction& u, const size_t i v1.push_back(u); std::vector v2; v2.push_back(u); - CCPairFunction ftt(&f12, mo_ket_(i), mo_ket_(j)); + CCPairFunction ftt(f12, mo_ket_(i), mo_ket_(j)); CCPairFunction O1xftt = apply_Ot(ftt, x, 1); CCPairFunction OxQftt = apply_Qt(O1xftt, mo_ket_, 2); v2.push_back(OxQftt); @@ -3165,8 +3167,8 @@ bool CCPotentials::test_compare_pairs(const CCPair& pair1, const CCPair& pair2) } else output("Test Passed, diff=" + std::to_string(diff)); // test energy integration - double energy_1 = make_xy_op_u(mo_bra_(pair1.i), mo_bra_(pair1.j), g12, pair1.functions); - double energy_2 = make_xy_op_u(mo_bra_(pair2.i), mo_bra_(pair2.j), g12, pair2.functions); + double energy_1 = make_xy_op_u(mo_bra_(pair1.i), mo_bra_(pair1.j), *g12, pair1.functions); + double energy_2 = make_xy_op_u(mo_bra_(pair2.i), mo_bra_(pair2.j), *g12, pair2.functions); double diff_energy = energy_1 - energy_2; if (world.rank() == 0) std::cout << std::fixed << std::setprecision(10) @@ -3488,7 +3490,7 @@ void CCPotentials::test() { const double lo = parameters.thresh_6D(); const double hi = parameters.thresh_3D(); { - CCPairFunction fab(&f12, a, b); + CCPairFunction fab(f12, a, b); const double test1 = overlap(fab, fab); const double prefactor = 1.0 / (4 * y * y); const double test2 = prefactor * (aR.inner(a) * bR.inner(b) - 2.0 * bb.inner(af2a) + bb.inner(affa)); @@ -3561,7 +3563,7 @@ void CCPotentials::test() { if (fabs(diff) > hi) passed_hi = false; } { - CCPairFunction fab(&f12, a, b); + CCPairFunction fab(f12, a, b); CCPairFunction ab2(ab_6d); const double test1 = overlap(fab, ab2); const double test2 = bb.inner(afa); @@ -3573,7 +3575,7 @@ void CCPotentials::test() { if (fabs(diff) > hi) passed_hi = false; } { - CCPairFunction fab(&f12, a, b); + CCPairFunction fab(f12, a, b); CCPairFunction ab2(mo_ket_.get_vecfunction(), mo_ket_.get_vecfunction()); const double test1 = overlap(fab, ab2); const double test2 = bb.inner(afa); diff --git a/src/madness/chem/CCPotentials.h b/src/madness/chem/CCPotentials.h index a70efcc0f43..76000bf49f2 100644 --- a/src/madness/chem/CCPotentials.h +++ b/src/madness/chem/CCPotentials.h @@ -794,10 +794,10 @@ class CCPotentials { // update the intermediates void update_intermediates(const CC_vecfunction& t) { - g12.update_elements(mo_bra_, t); - g12.sanity(); - f12.update_elements(mo_bra_, t); - f12.sanity(); + g12->update_elements(mo_bra_, t); + g12->sanity(); + f12->update_elements(mo_bra_, t); + f12->sanity(); } /// clear stored potentials @@ -829,9 +829,9 @@ class CCPotentials { std::vector orbital_energies_; /// the coulomb operator with all intermediates public: - CCConvolutionOperator g12; + std::shared_ptr g12; /// the f12 operator with all intermediates - CCConvolutionOperator f12; + std::shared_ptr f12; /// the correlation factor, holds necessary regularized potentials CorrelationFactor corrfac; /// Manager for stored intermediate potentials which are s2c, s2b and the whole singles potentials without fock-residue for GS and EX state diff --git a/src/madness/chem/CCStructures.h b/src/madness/chem/CCStructures.h index 324adad1509..88e6c1c0e34 100644 --- a/src/madness/chem/CCStructures.h +++ b/src/madness/chem/CCStructures.h @@ -894,8 +894,16 @@ struct CCConvolutionOperator { << "!!!!!\n\n" << std::endl; MADNESS_EXCEPTION(msg.c_str(), 1); } +public: }; +template +std::shared_ptr CCConvolutionOperatorPtr(World& world, const OpType type, + CCConvolutionOperator::Parameters param) { + return std::shared_ptr(new CCConvolutionOperator(world,type,param)); +} + + class CCPair : public archive::ParallelSerializableObject { public: CCPair(){}; diff --git a/src/madness/chem/ccpairfunction.cc b/src/madness/chem/ccpairfunction.cc index f34ed5c3bc0..beef6a41d18 100644 --- a/src/madness/chem/ccpairfunction.cc +++ b/src/madness/chem/ccpairfunction.cc @@ -394,7 +394,8 @@ double CCPairFunction::inner_internal(const CCPairFunction& other, const real_fu CCPairFunction bra(f1.get_a(),f1.get_b()); for (const auto& op : ops) { CCPairFunction ket; - if (op.second.get_op()) ket = CCPairFunction(&op.second,f2.get_a(),f2.get_b()); + auto op1=std::shared_ptr(new CCConvolutionOperator(op.second)); + if (op1->get_op()) ket = CCPairFunction(op1,f2.get_a(),f2.get_b()); else ket = CCPairFunction(f2.get_a(),f2.get_b()); double tmp=op.first * inner(ket,bra,R2); diff --git a/src/madness/chem/ccpairfunction.h b/src/madness/chem/ccpairfunction.h index a6ae94b94a8..eb38b4a110c 100644 --- a/src/madness/chem/ccpairfunction.h +++ b/src/madness/chem/ccpairfunction.h @@ -85,7 +85,9 @@ class TwoBodyFunctionComponentBase { virtual void swap_particles_inplace() = 0; virtual bool is_pure() const {return false;} virtual bool is_decomposed() const {return false;} - virtual bool has_operator() const {return false;} + virtual bool has_operator() const = 0; + virtual void set_operator(const std::shared_ptr op) = 0; + virtual const CCConvolutionOperator* get_operator_ptr() const = 0; virtual void print_size() const = 0; virtual std::string name(const bool transpose=false) const = 0; virtual World& world() const =0; @@ -116,6 +118,8 @@ class TwoBodyFunctionPureComponent : public TwoBodyFunctionComponentBase { bool is_pure() const override {return true;} + bool has_operator() const override {return op!=nullptr;} + World& world() const override {return u.world();}; void serialize() {} @@ -125,7 +129,11 @@ class TwoBodyFunctionPureComponent : public TwoBodyFunctionComponentBase { } std::string name(const bool transpose) const override { - if (transpose) return "< u |"; + if (transpose) { + if (has_operator()) return "< u |"+get_operator_ptr()->name(); + return "< u |"; + } + if (has_operator()) return get_operator_ptr()->name() + "| u >"; return "| u >"; } @@ -141,6 +149,10 @@ class TwoBodyFunctionPureComponent : public TwoBodyFunctionComponentBase { u=swap_particles(u); } + const CCConvolutionOperator* get_operator_ptr() const override {return op.get();}; + + void set_operator(const std::shared_ptr op1) override {op=op1;} + real_function_6d& get_function() { return u; } @@ -148,6 +160,7 @@ class TwoBodyFunctionPureComponent : public TwoBodyFunctionComponentBase { private: /// pure 6D function real_function_6d u; + std::shared_ptr op; }; @@ -164,7 +177,7 @@ class TwoBodyFunctionSeparatedComponent : public TwoBodyFunctionComponentBase { TwoBodyFunctionSeparatedComponent(const std::vector>& a, const std::vector>& b, - const CCConvolutionOperator* op) : a(a), b(b), op(op) {}; + const std::shared_ptr op) : a(a), b(b), op(op) {}; TwoBodyFunctionSeparatedComponent(const TwoBodyFunctionSeparatedComponent& other) = default; @@ -233,13 +246,15 @@ class TwoBodyFunctionSeparatedComponent : public TwoBodyFunctionComponentBase { } } - const CCConvolutionOperator* get_operator_ptr() const {return op;}; + const CCConvolutionOperator* get_operator_ptr() const override {return op.get();}; + + void set_operator(const std::shared_ptr op1) override {op=op1;} private: std::vector> a; std::vector> b; - const CCConvolutionOperator* op=nullptr; + std::shared_ptr op; }; @@ -305,12 +320,12 @@ using pureT=Function; } /// takes a deep copy of the argument functions - explicit CCPairFunction(const CCConvolutionOperator *op_, const CCFunction& f1, const CCFunction& f2) : + explicit CCPairFunction(const std::shared_ptr op_, const CCFunction& f1, const CCFunction& f2) : CCPairFunction(op_,std::vector({f1.function}),std::vector({f2.function})) { } /// takes a deep copy of the argument functions - explicit CCPairFunction(const CCConvolutionOperator *op_, const std::vector& f1, + explicit CCPairFunction(const std::shared_ptr op_, const std::vector& f1, const std::vector& f2) { World& world=f1.front().world(); component.reset(new TwoBodyFunctionSeparatedComponent(copy(world,f1),copy(world,f2),op_)); @@ -395,8 +410,7 @@ using pureT=Function; } const CCConvolutionOperator& get_operator() const { - MADNESS_CHECK(is_op_decomposed()); - return *decomposed().get_operator_ptr(); + return *(component->get_operator_ptr()); } /// can this be converted to a pure representation (depends on the operator, if present) diff --git a/src/madness/chem/test_ccpairfunction.cc b/src/madness/chem/test_ccpairfunction.cc index ca03221fb6a..677f2d39c18 100644 --- a/src/madness/chem/test_ccpairfunction.cc +++ b/src/madness/chem/test_ccpairfunction.cc @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -72,7 +73,7 @@ struct data { auto get_ccpairfunctions() const { CCPairFunction p1(f12); CCPairFunction p2({f1,f2},{f2,f3}); - CCPairFunction p3(f12_op.get(),{f1,f2},{f2,f3}); + CCPairFunction p3(f12_op,{f1,f2},{f2,f3}); CCPairFunction p4(f23); // two-term, corresponds to p2 return std::make_tuple(p1,p2,p3,p4); } @@ -91,13 +92,13 @@ int test_constructor(World& world, std::shared_ptr ncf vector_real_function_3d a= zero_functions(world,3); vector_real_function_3d b= zero_functions(world,3); - CCConvolutionOperator f12(world, OT_F12, parameter); + auto f12=CCConvolutionOperatorPtr(world, OT_F12, parameter); t1.checkpoint(true,"preparation"); CCPairFunction p1; CCPairFunction p2(f); CCPairFunction p3({f1,f2},{f1,f3}); - CCPairFunction p4(&f12,{f1,f2},{f2,f3}); + CCPairFunction p4(f12,{f1,f2},{f2,f3}); t1.checkpoint(true,"construction"); { @@ -151,8 +152,8 @@ int test_overlap(World& world, std::shared_ptr ncf, co CCTimer timer(world, "testing"); auto R2 = ncf->square(); - CCConvolutionOperator g12(world, OT_G12, parameters); - CCConvolutionOperator f12(world, OT_F12, parameters); + auto g12=CCConvolutionOperatorPtr(world, OT_G12, parameters); + auto f12=CCConvolutionOperatorPtr(world, OT_F12, parameters); CorrelationFactor corrfac(world, 1.0, 1.e-7, molecule); @@ -223,7 +224,7 @@ int test_overlap(World& world, std::shared_ptr ncf, co double time_init = timer.reset(); if (world.rank() == 0) print("time spent in initializing ", time_init); { - CCPairFunction fab(&f12, a, b); + CCPairFunction fab(f12, a, b); const double test1 = inner(fab, fab, R2); const double diff = test1 - ab_f2_ab; if (fabs(diff) > lo) passed_lo = false; @@ -260,7 +261,7 @@ int test_overlap(World& world, std::shared_ptr ncf, co { CCPairFunction ab1(mo_ket_.get_vecfunction(), mo_ket_.get_vecfunction()); - CCPairFunction fab(&f12, a, b); + CCPairFunction fab(f12, a, b); timer.reset(); const double test1 = inner(ab1, fab, R2); const double test2 = ab_f_ab; @@ -301,7 +302,7 @@ int test_overlap(World& world, std::shared_ptr ncf, co // if (fabs(diff) > hi) passed_hi = false; // } { - CCPairFunction fab(&f12, a, b); + CCPairFunction fab(f12, a, b); CCPairFunction ab2(fab_6d); const double test1 = inner(fab, ab2, R2); const double test2 = ab_f2_ab; @@ -315,7 +316,7 @@ int test_overlap(World& world, std::shared_ptr ncf, co t1.checkpoint(success, "op_dec/pure"); { - CCPairFunction fab(&f12, a, b); + CCPairFunction fab(f12, a, b); CCPairFunction ab2(mo_ket_.get_vecfunction(), mo_ket_.get_vecfunction()); timer.reset(); const double test1 = inner(fab, ab2, R2); @@ -346,7 +347,7 @@ int test_partial_inner_6d(World& world, std::shared_ptr a = {f1, f2}; std::vector b = {f2, f3}; - CCConvolutionOperator f12(world, OT_F12, parameter); + auto f12=CCConvolutionOperatorPtr(world, OT_F12, parameter); auto [p1,p2,p3,p4]=data1.get_ccpairfunctions(); CCPairFunction p11({f1},{f1}); @@ -358,11 +359,11 @@ int test_partial_inner_6d(World& world, std::shared_ptr // CCPairFunction p2({f1,f2},{f2,f3}); // CCPairFunction p4(f23); // two-term, corresponds to p2 - CCPairFunction p5(&f12,std::vector({f1}),std::vector({f2})); + CCPairFunction p5(f12,std::vector({f1}),std::vector({f2})); for (auto& test_p1 : {p2, p4}) { CCPairFunction r1=inner(test_p1,p5,{0,1,2},{0,1,2}); CCPairFunction r2=inner(test_p1,p5,{0,1,2},{3,4,5}); @@ -470,11 +471,11 @@ int test_partial_inner_3d(World& world, std::shared_ptr a = {f1, f2}; std::vector b = {f2, f3}; - CCConvolutionOperator f12(world, OT_F12, parameter); + auto f12=CCConvolutionOperatorPtr(world, OT_F12, parameter); CCPairFunction p1(f); // e(-r1 - 2r2) CCPairFunction p2(a,b); - CCPairFunction p3(&f12,a,b); + CCPairFunction p3(f12,a,b); CCPairFunction p11({f1},{f1}); CCPairFunction p12({f1},{f2}); @@ -483,9 +484,9 @@ int test_partial_inner_3d(World& world, std::shared_ptr ncf, std::vector b = {f3, f1, f2}; std::vector o = orthonormalize_cd({f1-f3, f5}); // projects on an orthonormal basis a = orthonormalize_cd(a); // projects on an orthonormal basis - CCConvolutionOperator f12(world, OT_F12, parameter); + auto f12=CCConvolutionOperatorPtr(world, OT_F12, parameter); { double n1=inner(f1,o[0]); @@ -705,7 +706,7 @@ int test_projector(World& world, std::shared_ptr ncf, } CCPairFunction p1(a,b); - CCPairFunction p2(&f12,a,b); + CCPairFunction p2(f12,a,b); CCPairFunction p3(f); // outer (f1,f2) std::vector vp1({p1}); @@ -850,11 +851,11 @@ int test_helium(World& world, std::shared_ptr ncf, con CCConvolutionOperator::Parameters param; - CCConvolutionOperator f(world,OT_F12,param); - CCConvolutionOperator g(world,OT_G12,param); + auto f=CCConvolutionOperatorPtr(world,OT_F12,param); + auto g=CCConvolutionOperatorPtr(world,OT_G12,param); - CCPairFunction fij(&f,psi,psi); - CCPairFunction gij(&g,psi,psi); + CCPairFunction fij(f,psi,psi); + CCPairFunction gij(g,psi,psi); CCPairFunction ij({psi},{psi}); std::vector vfij={fij}; std::vector vgij={gij}; From 25d52ce637114d7c48bc86dff0e87c3b0b7245a3 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Wed, 8 Feb 2023 17:31:27 +0100 Subject: [PATCH 010/109] CCPairFunction::inner works now with pure and decomposed, with and without 2-particle factor --- src/madness/chem/CCStructures.h | 22 ++- src/madness/chem/ccpairfunction.cc | 210 ++++++++++++++---------- src/madness/chem/ccpairfunction.h | 34 +++- src/madness/chem/mp2.cc | 30 ++++ src/madness/chem/test_ccpairfunction.cc | 159 ++++++++++++++++-- src/madness/mra/mra.h | 3 +- 6 files changed, 340 insertions(+), 118 deletions(-) diff --git a/src/madness/chem/CCStructures.h b/src/madness/chem/CCStructures.h index 88e6c1c0e34..613b2c48364 100644 --- a/src/madness/chem/CCStructures.h +++ b/src/madness/chem/CCStructures.h @@ -734,6 +734,22 @@ struct CCConvolutionOperator { } + /// combine 2 convolution operators to one + + /// @return a vector of pairs: factor and convolution operator + friend std::vector> combine(const std::shared_ptr left, + const std::shared_ptr right) { + std::vector> result; + if (left and right) return combine(*left,*right); + if (left) { + result.push_back(std::make_pair(1.0,CCConvolutionOperator(*left))); + } else if (right) { + result.push_back(std::make_pair(1.0,CCConvolutionOperator(*right))); + } + return result; + } + +protected: /// combine 2 convolution operators to one /// @return a vector of pairs: factor and convolution operator @@ -770,6 +786,7 @@ struct CCConvolutionOperator { return result; } +public: /// @param[in] f: a 3D function /// @param[out] the convolution op(f), no intermediates are used real_function_3d operator()(const real_function_3d& f) const { @@ -800,8 +817,8 @@ struct CCConvolutionOperator { // @param[in] f: a vector of 3D functions // @param[out] the convolution of op with each function, no intermeditates are used vector_real_function_3d operator()(const vector_real_function_3d& f) const { - if (op) return apply(world, (*op), f); - return f; + MADNESS_CHECK(op); + return apply(world, (*op), f); } // @param[in] bra: a 3D CC_function, if nuclear-correlation factors are used they have to be applied before @@ -860,6 +877,7 @@ struct CCConvolutionOperator { if (type() == OT_G12) return TwoElectronFactory(world).dcut(1.e-7); else if (type() == OT_F12) return TwoElectronFactory(world).dcut(1.e-7).f12().gamma(parameters.gamma); else if (type() == OT_FG12) return TwoElectronFactory(world).dcut(1.e-7).BSH().gamma(parameters.gamma); + else if (type() == OT_SLATER) return TwoElectronFactory(world).dcut(1.e-7).slater().gamma(parameters.gamma); else error("no kernel of type " + name() + " implemented"); return TwoElectronFactory(world); } diff --git a/src/madness/chem/ccpairfunction.cc b/src/madness/chem/ccpairfunction.cc index beef6a41d18..b4061a9608b 100644 --- a/src/madness/chem/ccpairfunction.cc +++ b/src/madness/chem/ccpairfunction.cc @@ -17,37 +17,43 @@ CCPairFunction::invert_sign() { return *this; } -bool CCPairFunction::is_convertible_to_pure() const { - if (is_pure()) return true; - bool operator_condition=true; +bool CCPairFunction::is_convertible_to_pure_no_op() const { if (has_operator()) { const auto type=get_operator().type(); - if (type==OT_SLATER or type==OT_F12) operator_condition=true; - else operator_condition=false; + if (not (type==OT_SLATER or type==OT_F12)) return false; } - bool size_condition=is_decomposed() and (get_a().size()==1); - return operator_condition and size_condition; + if (is_decomposed() and (get_a().size()>1)) return false; + return true; }; -void CCPairFunction::convert_to_pure_inplace() { - if (is_pure()) return; +void CCPairFunction::convert_to_pure_no_op_inplace() { + pureT tmp; pureT result=real_factory_6d(world()); - MADNESS_CHECK(get_a().size()<3); - for (int i=0; i(world()) - .g12(get_operator().get_kernel()) - .particle1(get_a()[i]) - .particle2(get_b()[i]); - } else if (is_decomposed_no_op()) { - tmp= CompositeFactory(world()) - .particle1(get_a()[i]) - .particle2(get_b()[i]); - } + if (is_pure_no_op()) { + return; + } else if (is_pure()) { + tmp= CompositeFactory(world()) + .g12(get_operator().get_kernel()) + .ket(get_function()); tmp.fill_tree(); - result+=tmp; + result=tmp; + } else if (is_decomposed()) { + MADNESS_CHECK(get_a().size()<3); + for (int i=0; i(world()) + .g12(get_operator().get_kernel()) + .particle1(get_a()[i]) + .particle2(get_b()[i]); + } else if (is_decomposed_no_op()) { + tmp= CompositeFactory(world()) + .particle1(get_a()[i]) + .particle2(get_b()[i]); + } + tmp.fill_tree(); + result+=tmp; + } } component.reset(new TwoBodyFunctionPureComponent(result)); }; @@ -74,8 +80,11 @@ CCPairFunction::make_xy_u(const CCFunction& xx, const CCFunction& yy) const { real_function_3d CCPairFunction::project_out(const CCFunction& f, const size_t particle) const { MADNESS_ASSERT(particle == 1 or particle == 2); real_function_3d result; - if (is_pure()) { - result = pure().get_function().project_out(f.function, particle - 1); // this needs 0 or 1 for particle but we give 1 or 2 + if (is_pure_no_op()) { + result = pure().get_function().project_out(f.function, + particle - 1); // this needs 0 or 1 for particle but we give 1 or 2 + } else if (is_op_pure()) { + MADNESS_EXCEPTION("implement CCPairFunction::project_out for op_pure",1); } else if (is_decomposed_no_op()) { result = project_out_decomposed(f.function, particle); } else if (is_op_decomposed()) { @@ -141,6 +150,8 @@ CCPairFunction CCPairFunction::partial_inner(const CCPairFunction& other, auto a345=std::array{3,4,5}; MADNESS_CHECK(v1==a012 or v1== a345); MADNESS_CHECK(v2==a012 or v2== a345); + MADNESS_CHECK(not this->is_op_pure()); // not implemented yet + MADNESS_CHECK(not other.is_op_pure()); // not implemented yet auto integration_index=[&a012,&a345](auto v) {return (v==a012) ? 0l : 1l;}; auto remaining_index=[&integration_index](auto v) {return (integration_index(v)+1)%2;}; @@ -225,13 +236,13 @@ CCPairFunction CCPairFunction::partial_inner(const CCPairFunction& other, } else if (other.is_decomposed_no_op()) { return other.partial_inner(*this,v2,v1); } else if (other.is_op_decomposed()) { - if (this->is_convertible_to_pure()) { + if (this->is_convertible_to_pure_no_op()) { CCPairFunction tmp=copy(*this); - tmp.convert_to_pure_inplace(); + tmp.convert_to_pure_no_op_inplace(); return tmp.partial_inner(other,v1,v2); - } else if (other.is_convertible_to_pure()) { + } else if (other.is_convertible_to_pure_no_op()) { CCPairFunction tmp=copy(other); - tmp.convert_to_pure_inplace(); + tmp.convert_to_pure_no_op_inplace(); return this->partial_inner(tmp,v1,v2); } else { MADNESS_EXCEPTION("no partial_inner for this combination: ",1); @@ -253,6 +264,7 @@ real_function_3d CCPairFunction::partial_inner(const real_function_3d& f, auto a345=std::array{3,4,5}; MADNESS_CHECK(v2==a012 ); // only 3 dimension in f MADNESS_CHECK(v1==a012 or v1== a345); // 6 dimension in f + MADNESS_CHECK(not this->is_op_pure()); // not implemented yet int particle=-1; if (v1== a012) particle=0; if (v1== a345) particle=1; @@ -320,7 +332,9 @@ CCPairFunction::assign_particles(const size_t particle) const { } } +/// compute the inner product of this and other +/// there are 4 possible components: pure/decomposed with and without operator, gives us 16 pair combinations.. double CCPairFunction::inner_internal(const CCPairFunction& other, const real_function_3d& R2) const { const CCPairFunction& f1=*this; const CCPairFunction& f2=other; @@ -328,84 +342,102 @@ double CCPairFunction::inner_internal(const CCPairFunction& other, const real_fu double thresh=FunctionDefaults<6>::get_thresh()*0.1; double result = 0.0; - if (f1.is_pure() and f2.is_pure()) { - CCTimer tmp(world(), "making R1R2|u>"); + if (f1.is_pure() and f2.is_pure()) { // these are 4 combinations pure/pure + pureT bra=f1.get_function(); + pureT ket=f2.get_function(); if (R2.is_initialized()) { real_function_6d R1u = multiply(::copy(f1.pure().get_function()), ::copy(R2), 1); real_function_6d R1R2u = multiply(R1u, ::copy(R2), 2); // R1u function now broken -// tmp.info(); - result = f2.pure().get_function().inner(R1R2u); + bra = R1R2u; + } + // include the operator(s), if any + if (f1.has_operator() or f2.has_operator()) { + auto ops=combine(f1.get_operator_ptr(),f2.get_operator_ptr()); + for (const auto& single_op : ops) { + auto fac=single_op.first; + auto op=single_op.second; + print(op.name()); + double bla=0.0; + if (op.get_op()) { + real_function_6d tmp1 = CompositeFactory(world()).g12(op.get_kernel()).ket(ket); + bla=fac*inner(bra,tmp1); + } else { + bla=fac*inner(bra,ket); + } + result+=bla; + } } else { - result = f2.pure().get_function().inner(f1.pure().get_function()); + // no operators + result=inner(bra,ket); } } else if (f1.is_pure() and f2.is_decomposed()) { // with or without operator - vector_real_function_3d a = R2.is_initialized() ? R2 * f2.get_a() : copy(world(), f2.get_a()); - vector_real_function_3d b = R2.is_initialized() ? R2 * f2.get_b() : copy(world(), f2.get_b()); - real_function_6d op; - if (f2.has_operator()) { - if (f2.decomposed().get_operator_ptr()->type() == OT_F12) { - op = TwoElectronFactory(world()).dcut(f2.get_operator().parameters.lo).gamma( - f2.get_operator().parameters.gamma).f12().thresh(thresh); - } else if (f2.get_operator().type() == OT_G12) { - op = TwoElectronFactory(world()).dcut(f2.get_operator().parameters.lo).thresh(thresh); - } else { - MADNESS_EXCEPTION(("6D Overlap with operatortype " + assign_name(f2.get_operator().type()) + " not supported").c_str(), 1); + const vector_real_function_3d a = R2.is_initialized() ? R2 * f2.get_a() : copy(world(), f2.get_a()); + const vector_real_function_3d b = R2.is_initialized() ? R2 * f2.get_b() : copy(world(), f2.get_b()); + const pureT& bra=f1.get_function(); + + auto ops=combine(f1.get_operator_ptr(),f2.get_operator_ptr()); + if (ops.size()>0) { + for (const auto& single_op : ops) { + auto fac = single_op.first; + auto op = single_op.second; + print(op.name()); + double bla=0.0; + for (int i=0; i(world()).g12(op.get_kernel()).particle1(a[i]).particle2(b[i]); + bla += fac * inner(bra, tmp); + } else { + real_function_6d tmp = CompositeFactory(world()).particle1(a[i]).particle2(b[i]); + bla += fac * inner(bra,tmp); + } + } + result+=bla; + } + } else { // no operators + for (int i=0; i(world()).particle1(a[i]).particle2(b[i]); + result+=inner(bra,tmp); } - } - for (int i=0; i(world()).g12(op).particle1(x).particle2(y); - else opxy= CompositeFactory(world()).particle1(x).particle2(y); - result+= f1.pure().get_function().inner(opxy); } } else if (f1.is_decomposed() and f2.is_pure()) { // with or without op result= f2.inner_internal(f1,R2); - } else if (f1.is_decomposed_no_op() and f2.is_decomposed_no_op()) { + + } else if (f1.is_decomposed() and f2.is_decomposed()) { MADNESS_ASSERT(f1.get_a().size() == f1.get_b().size()); MADNESS_ASSERT(f2.get_a().size() == f2.get_b().size()); - vector_real_function_3d a = R2.is_initialized() ? R2* f2.get_a() : f2.get_a(); - vector_real_function_3d b = R2.is_initialized() ? R2* f2.get_b() : f2.get_b(); - // = \sum_ij = \sum_ij - result = (matrix_inner(world(), a, f1.get_a()).emul(matrix_inner(world(), b, f1.get_b()))).sum(); - } else if (f1.is_decomposed_no_op() and f2.is_op_decomposed()) { - MADNESS_ASSERT(f1.get_a().size() == f1.get_b().size()); - // = const vector_real_function_3d& a1 = f1.get_a(); const vector_real_function_3d& b1 = f1.get_b(); - const vector_real_function_3d a2 = R2.is_initialized() ? R2 * f2.get_a() : copy(world(),f2.get_a()); - const vector_real_function_3d b2 = R2.is_initialized() ? R2 * f2.get_b() : copy(world(),f2.get_b()); - for (size_t i = 0; i < a1.size(); i++) { - vector_real_function_3d aa = truncate(a1[i] * a2); - vector_real_function_3d aopx = f2.get_operator()(aa); - vector_real_function_3d bb = truncate(b1[i] * b2); - result += inner(bb,aopx); - } + const vector_real_function_3d a2 = R2.is_initialized() ? R2* f2.get_a() : f2.get_a(); + const vector_real_function_3d b2 = R2.is_initialized() ? R2* f2.get_b() : f2.get_b(); - } else if (f1.is_op_decomposed() and f2.is_decomposed_no_op()) { - return f2.inner_internal(f1,R2); - - } else if (f1.is_op_decomposed() and f2.is_op_decomposed()) { - MADNESS_CHECK(can_combine(f1.get_operator(),f2.get_operator())); - MADNESS_CHECK(f1.get_a().size()==1); - std::vector> ops=combine(f1.get_operator(),f2.get_operator()); - CCPairFunction bra(f1.get_a(),f1.get_b()); - for (const auto& op : ops) { - CCPairFunction ket; - auto op1=std::shared_ptr(new CCConvolutionOperator(op.second)); - if (op1->get_op()) ket = CCPairFunction(op1,f2.get_a(),f2.get_b()); - else ket = CCPairFunction(f2.get_a(),f2.get_b()); - - double tmp=op.first * inner(ket,bra,R2); -// print("inner",bra.name(true),ket.name()," : ",tmp); - result+=tmp; + + auto ops=combine(f1.get_operator_ptr(),f2.get_operator_ptr()); + if (ops.size()==0) { + // = \sum_ij = \sum_ij + result = (matrix_inner(world(), a1, a2)).trace(matrix_inner(world(),b1,b2)); + } else { + // = + for (const auto& single_op : ops) { + auto fac = single_op.first; + auto op = single_op.second; + + double bla=0.0; + if (op.get_op()) { + for (size_t i = 0; i < a1.size(); i++) { + vector_real_function_3d aa = truncate(a1[i] * a2); + vector_real_function_3d bb = truncate(b1[i] * b2); + vector_real_function_3d aopx = op(aa); + bla += fac * inner(bb, aopx); + } + } else { + bla += fac*(matrix_inner(world(), a1, a2)).trace(matrix_inner(world(),b1,b2)); + } + result+=bla; + } } } else MADNESS_EXCEPTION( - ("CCPairFunction Overlap not supported for combination " + f1.name() + " and " + f2.name()).c_str(), 1) - - ; + ("CCPairFunction Overlap not supported for combination " + f1.name() + " and " + f2.name()).c_str(), 1) ; return result; } diff --git a/src/madness/chem/ccpairfunction.h b/src/madness/chem/ccpairfunction.h index eb38b4a110c..5c10f2e2bb9 100644 --- a/src/madness/chem/ccpairfunction.h +++ b/src/madness/chem/ccpairfunction.h @@ -87,7 +87,7 @@ class TwoBodyFunctionComponentBase { virtual bool is_decomposed() const {return false;} virtual bool has_operator() const = 0; virtual void set_operator(const std::shared_ptr op) = 0; - virtual const CCConvolutionOperator* get_operator_ptr() const = 0; + virtual const std::shared_ptr get_operator_ptr() const = 0; virtual void print_size() const = 0; virtual std::string name(const bool transpose=false) const = 0; virtual World& world() const =0; @@ -102,11 +102,12 @@ class TwoBodyFunctionPureComponent : public TwoBodyFunctionComponentBase { TwoBodyFunctionPureComponent() = default; explicit TwoBodyFunctionPureComponent(const Function& f) : u(f) {} + explicit TwoBodyFunctionPureComponent(const std::shared_ptr op, const Function& f) + : u(f), op(op) {} /// deep copy std::shared_ptr clone() override { - TwoBodyFunctionPureComponent result; - result.u=madness::copy(u); + TwoBodyFunctionPureComponent result(op,madness::copy(u)); return std::make_shared>(result); } @@ -149,7 +150,7 @@ class TwoBodyFunctionPureComponent : public TwoBodyFunctionComponentBase { u=swap_particles(u); } - const CCConvolutionOperator* get_operator_ptr() const override {return op.get();}; + const std::shared_ptr get_operator_ptr() const override {return op;}; void set_operator(const std::shared_ptr op1) override {op=op1;} @@ -246,7 +247,7 @@ class TwoBodyFunctionSeparatedComponent : public TwoBodyFunctionComponentBase { } } - const CCConvolutionOperator* get_operator_ptr() const override {return op.get();}; + const std::shared_ptr get_operator_ptr() const override {return op;}; void set_operator(const std::shared_ptr op1) override {op=op1;} @@ -289,6 +290,7 @@ class TwoBodyFunctionSeparatedComponent : public TwoBodyFunctionComponentBase { /** * the function is stored as * - pure: full rank form, 6D + * - op_pure: full rank form, 6D with an 2-particle function f(1,2) |u> * - decomposed: sum of two vectors of 3D functions \sum_i |a_i(1) b_i(2)> * - op_decomposed: as above, with an 2-particle function: f(1,2) \sum_i |a_i b_i> * @@ -308,6 +310,11 @@ using pureT=Function; component.reset(new TwoBodyFunctionPureComponent(copy(ket))); } + /// takes a deep copy of the argument function + explicit CCPairFunction(const std::shared_ptr op_, const real_function_6d& ket) { + component.reset(new TwoBodyFunctionPureComponent(op_,copy(ket))); + } + /// takes a deep copy of the argument functions explicit CCPairFunction(const vector_real_function_3d& f1, const vector_real_function_3d& f2) { World& world=f1.front().world(); @@ -378,11 +385,13 @@ using pureT=Function; return fac*f; } + bool has_operator() const {return component->has_operator();} bool is_pure() const {return component->is_pure();} + bool is_op_pure() const {return is_pure() and has_operator();} + bool is_pure_no_op() const {return is_pure() and (not has_operator());} bool is_decomposed() const {return component->is_decomposed();} - bool is_decomposed_no_op() const {return component->is_decomposed() and (not component->has_operator());} bool is_op_decomposed() const {return component->is_decomposed() and component->has_operator();} - bool has_operator() const {return component->has_operator();} + bool is_decomposed_no_op() const {return component->is_decomposed() and (not component->has_operator());} TwoBodyFunctionPureComponent& pure() const { if (auto ptr=dynamic_cast*>(component.get())) return *ptr; @@ -410,14 +419,20 @@ using pureT=Function; } const CCConvolutionOperator& get_operator() const { + MADNESS_CHECK(component and component->has_operator()); return *(component->get_operator_ptr()); } + const std::shared_ptr get_operator_ptr() const { + MADNESS_CHECK(component); + return component->get_operator_ptr(); + } + /// can this be converted to a pure representation (depends on the operator, if present) - bool is_convertible_to_pure() const; + bool is_convertible_to_pure_no_op() const; /// convert this into a pure hi-dim function - void convert_to_pure_inplace(); + void convert_to_pure_no_op_inplace(); CCPairFunction& operator*=(const double fac) { if (component->is_pure()) pure()*=fac; @@ -459,6 +474,7 @@ using pureT=Function; double make_xy_u(const CCFunction& xx, const CCFunction& yy) const; + /// compute the inner product of this and other double inner_internal(const CCPairFunction& other, const real_function_3d& R2) const; friend double inner(const CCPairFunction& a, const CCPairFunction& b, const real_function_3d& R2) { diff --git a/src/madness/chem/mp2.cc b/src/madness/chem/mp2.cc index bf1cb96b4c1..81ddcb81da7 100644 --- a/src/madness/chem/mp2.cc +++ b/src/madness/chem/mp2.cc @@ -50,6 +50,8 @@ #include #include #include +#include +#include #include @@ -540,6 +542,7 @@ void MP2::test(const std::string filename) { /// @return the energy double MP2::compute_gQf(const int i, const int j, ElectronPair& pair) const { + CCTimer t1(world,"gQf old"); // for clarity of notation const int k = pair.i; const int l = pair.j; @@ -619,6 +622,33 @@ double MP2::compute_gQf(const int i, const int j, ElectronPair& pair) const { if (world.rank() == 0) printf("<%d%d | g Q12 f | %d%d> %12.8f\n", i, j, k, l, e); + print("gQf old",t1.reset()); + + CCTimer timer(world,"gQf with ccpairfunction"); + CCConvolutionOperator::Parameters param; + auto f=CCConvolutionOperatorPtr(world,OT_F12,param); + auto g=CCConvolutionOperatorPtr(world,OT_G12,param); +// print("operator constructor",timer.reset()); + + CCPairFunction fij(f,ket_i,ket_j); + CCPairFunction gij(g,bra_k,bra_l); +// CCPairFunction ij({psi},{psi}); + std::vector vfij={fij}; + std::vector vgij={gij}; +// std::vector vij={ij}; +// print("g/f ij constructor",timer.reset()); + +// StrongOrthogonalityProjector SO(world); +// SO.set_spaces({psi},{psi},{psi},{psi}); + std::vector Qfij=Q12(vfij); +// std::vector Qgij=Q12(vgij); +// print("SO application",timer.reset()); + + double result1=inner(vgij,Qfij); + print("inner",timer.reset()); + + print(")",result1); + return e; } diff --git a/src/madness/chem/test_ccpairfunction.cc b/src/madness/chem/test_ccpairfunction.cc index 677f2d39c18..7e317a6e23f 100644 --- a/src/madness/chem/test_ccpairfunction.cc +++ b/src/madness/chem/test_ccpairfunction.cc @@ -66,16 +66,33 @@ struct data { f23.clear(); } + /// get some standard functions + + /// f1: exp(-1.0 r^2) + /// f2: exp(-2.0 r^2) + /// f3: exp(-3.0 r^2) + /// f4: exp(-4.0 r^2) + /// f5: exp(-5.0 r^2) + /// f12: exp(-r_1^2 - 2 r_2^2) + /// f23: exp(-r_1^2 - 2 r_2^2) + exp(-2 r_1^2 - 3 r_2^2) auto get_functions() const { return std::make_tuple(f1,f2,f3,f4,f5,f12); } + /// get some standard ccpairfunctions + + /// p1: pure, corresponds to f12 + /// p2: dec, corresponds to f23 + /// p3: op_dec, corresponds to f23 + /// p4: pure, corresponds to f23 + /// p5: op_pure, corresponds to f23 auto get_ccpairfunctions() const { CCPairFunction p1(f12); CCPairFunction p2({f1,f2},{f2,f3}); CCPairFunction p3(f12_op,{f1,f2},{f2,f3}); CCPairFunction p4(f23); // two-term, corresponds to p2 - return std::make_tuple(p1,p2,p3,p4); + CCPairFunction p5(f12_op,f23); // two-term, corresponds to p2 + return std::make_tuple(p1,p2,p3,p4,p5); } }; @@ -142,8 +159,125 @@ int test_constructor(World& world, std::shared_ptr ncf } t1.checkpoint(true,"checks on assignment"); - t1.end(); + return t1.end(); + +} + +int test_transformations(World& world, std::shared_ptr ncf, const Molecule& molecule, + const CCParameters& parameter) { + test_output t1("CCPairFunction::test_transformations"); + + real_function_6d f=real_factory_6d(world); + auto [f1,f2,f3,f4,f5,ff]=data1.get_functions(); + auto f12=CCConvolutionOperatorPtr(world, OT_F12, parameter); + auto g12=CCConvolutionOperatorPtr(world, OT_G12, parameter); + + + CCPairFunction p1(ff); + t1.checkpoint(p1.is_pure(),"is_pure"); + t1.checkpoint(p1.is_pure_no_op(),"is_pure_no_op"); + + CCPairFunction p2(f12,ff); + t1.checkpoint(p2.is_pure(),"is_pure"); + t1.checkpoint(p2.is_op_pure(),"is_op_pure"); + t1.checkpoint(p2.is_convertible_to_pure_no_op(),"is_convertible_to_pure_no_op"); + CCPairFunction p3=copy(p2); + p3.convert_to_pure_no_op_inplace(); + t1.checkpoint(p2.is_op_pure(),"is_op_pure"); + t1.checkpoint(p3.is_pure_no_op(),"is_pure_no_op"); + + CCPairFunction p4(g12,ff); + t1.checkpoint(p4.is_pure(),"is_pure"); + t1.checkpoint(p4.is_op_pure(),"is_op_pure"); + t1.checkpoint(not p4.is_convertible_to_pure_no_op(),"not is_convertible_to_pure_no_op"); + + CCPairFunction p5(f12,f1,f2); + t1.checkpoint(not p5.is_pure(),"is_pure"); + t1.checkpoint(p5.is_op_decomposed(),"is_op_decomposed"); + t1.checkpoint(p5.is_convertible_to_pure_no_op(),"is_convertible_to_pure_no_op"); + CCPairFunction p6=copy(p5); + p6.convert_to_pure_no_op_inplace(); + t1.checkpoint(p6.is_pure_no_op(),"is_pure_no_op"); + + return t1.end(); +} + +int test_inner(World& world, std::shared_ptr ncf, const Molecule& molecule, + const CCParameters& parameters) { + test_output t1("CCPairFunction::test_inner"); + t1.set_cout_to_terminal(); + + /// f1: exp(-1.0 r^2) + /// f2: exp(-2.0 r^2) + /// f3: exp(-3.0 r^2) + /// f4: exp(-4.0 r^2) + /// f5: exp(-5.0 r^2) + /// f: exp(-r_1^2 - 2 r_2^2) + /// f23: exp(-r_1^2 - 2 r_2^2) + exp(-2 r_1^2 - 3 r_2^2) + auto [f1,f2,f3,f4,f5,f]=data1.get_functions(); + /// p1: pure, corresponds to f12 + /// p2: dec, corresponds to f23 + /// p3: op_dec, corresponds to f23 + /// p4: pure, corresponds to f23 + /// p5: op_pure, corresponds to f23 + auto [p1,p2,p3,p4,p5]=data1.get_ccpairfunctions(); + auto f12 = *(data1.f12_op); + + /// results + auto a=std::vector({f1,f2}); + auto b=std::vector({f2,f3}); + std::vector a_ij_functions, b_ij_functions; + for (int i=0; i = \sum_{ij} + double ab_ab=aij.trace(bij); + + // = \sum_{ij} < _1(2) | b_ib_j(2) > + double ab_f_ab=dot(world,f12(a_ij_functions),b_ij_functions).trace(); + + // = \sum_{ij} < _2 | b_ib_j(2) > + // f^2 = 1/(4y^2)(1 - 2*f(y) + f2(2y)) , f2(2y) =f2(y)^2 + // operator apply of SlaterF12Operator includes a factor of 1/(2 gamma) and the identity + // operator apply of SlaterOperator has no further terms + const double y = parameters.gamma(); + SeparatedConvolution fop= SlaterOperator(world, y, parameters.lo(), parameters.thresh_bsh_3D()); + SeparatedConvolution fsq = SlaterOperator(world, 2.0 * y, parameters.lo(), parameters.thresh_bsh_3D()); + + const double prefactor = 1.0 / (4 * y * y); + const double ab_f2_ab = prefactor*( ab_ab + -2.0*dot(world,apply(world,fop,a_ij_functions),b_ij_functions).trace() + +dot(world,apply(world,fsq,a_ij_functions),b_ij_functions).trace() ); + + + for (auto& ket : {p2, p3, p4, p5}) { + for (auto& bra : {p2, p3, p4, p5}) { + double ref=0.0; + if (bra.has_operator() and ket.has_operator()) ref=ab_f2_ab; + if (bra.has_operator() and (not ket.has_operator())) ref=ab_f_ab; + if ((not bra.has_operator()) and ket.has_operator()) ref=ab_f_ab; + if ((not bra.has_operator()) and (not ket.has_operator())) ref=ab_ab; + double result=inner(bra,ket); + + print(bra.name(true)+ket.name(),"ref, result, diff", ref, result, ref-result); + double thresh=FunctionDefaults<3>::get_thresh(); + bool good=(fabs(result-ref) ncf, co CCTimer timer(world, "testing"); auto R2 = ncf->square(); - auto g12=CCConvolutionOperatorPtr(world, OT_G12, parameters); auto f12=CCConvolutionOperatorPtr(world, OT_F12, parameters); CorrelationFactor corrfac(world, 1.0, 1.e-7, molecule); @@ -169,7 +302,6 @@ int test_overlap(World& world, std::shared_ptr ncf, co bool passed_lo = true; bool passed_hi = true; bool success=true; - int isuccess=0; const double lo = parameters.thresh_6D(); const double hi = parameters.thresh_3D(); const double hi_loose = parameters.thresh_3D()*5.0; @@ -187,8 +319,7 @@ int test_overlap(World& world, std::shared_ptr ncf, co real_function_3d a = mo_ket_(0).function; real_function_3d b = mo_ket_(0).function; - real_function_6d fab_6d = CompositeFactory(world).g12(corrfac.f()).particle1(copy(a)).particle2( - copy(b)); + real_function_6d fab_6d = CompositeFactory(world).g12(corrfac.f()).particle1(copy(a)).particle2(copy(b)); fab_6d.fill_tree().truncate().reduce_rank(); fab_6d.print_size("fab_6d"); @@ -233,7 +364,6 @@ int test_overlap(World& world, std::shared_ptr ncf, co printer(" op_dec/op_dec : ", test1, ab_f2_ab, timer.reset()); success=(fabs(diff) < hi); } - if (not success) isuccess++; t1.checkpoint(success, "op_dec/op_dec"); { CCPairFunction ab(mo_ket_.get_vecfunction(), mo_ket_.get_vecfunction()); @@ -245,7 +375,6 @@ int test_overlap(World& world, std::shared_ptr ncf, co if (fabs(diff) > hi) passed_hi = false; success=(fabs(diff) < hi); } - if (not success) isuccess++; t1.checkpoint(success, "dec/dec"); { CCPairFunction fab(fab_6d); @@ -256,7 +385,6 @@ int test_overlap(World& world, std::shared_ptr ncf, co if (fabs(diff) > hi) passed_hi = false; success=(fabs(diff) < hi_loose); } - if (not success) isuccess++; t1.checkpoint(success, "pure/pure"); { @@ -271,7 +399,6 @@ int test_overlap(World& world, std::shared_ptr ncf, co if (fabs(diff) > hi) passed_hi = false; success=(fabs(diff) < hi); } - if (not success) isuccess++; t1.checkpoint(success, "dec/op_dec"); { @@ -287,7 +414,6 @@ int test_overlap(World& world, std::shared_ptr ncf, co success=(fabs(diff) < hi_loose); } - if (not success) isuccess++; t1.checkpoint(success, "dec/pure"); // { // CCPairFunction fab(fab_6d); @@ -312,7 +438,6 @@ int test_overlap(World& world, std::shared_ptr ncf, co if (fabs(diff) > hi) passed_hi = false; success=(fabs(diff) < hi_loose); // be a bit loose here .. } - if (not success) isuccess++; t1.checkpoint(success, "op_dec/pure"); { @@ -328,7 +453,6 @@ int test_overlap(World& world, std::shared_ptr ncf, co if (fabs(diff) > hi) passed_hi = false; success=(fabs(diff) < hi); } - if (not success) isuccess++; t1.checkpoint(success, "op_dec/dec"); return (t1.get_final_success()) ? 0 : 1; @@ -349,7 +473,7 @@ int test_partial_inner_6d(World& world, std::shared_ptrget_impl()==g.get_impl()) { + if (this->get_impl()->is_redundant()) this->get_impl()->undo_redundant(true); double norm=this->norm2(); return norm*norm; } @@ -1356,13 +1357,13 @@ namespace madness { TENSOR_RESULT_TYPE(T,R) inner_on_demand(const Function& g) const { MADNESS_ASSERT(g.is_on_demand() and (not this->is_on_demand())); - this->reconstruct(); // save for later, will be removed by make_Vphi std::shared_ptr< FunctionFunctorInterface > func=g.get_impl()->get_functor(); //leaf_op fnode_is_leaf(this->get_impl().get()); Leaf_op_other fnode_is_leaf(this->get_impl().get()); g.get_impl()->make_Vphi(fnode_is_leaf,true); // fence here + this->reconstruct(); if (VERIFY_TREE) verify_tree(); TENSOR_RESULT_TYPE(T,R) local = impl->inner_local(*g.get_impl()); From b8345e1f18d2aaaa6f6b1de69e295aaa4f6525a3 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Wed, 8 Feb 2023 17:42:46 +0100 Subject: [PATCH 011/109] CCPairFunction::inner works now with pure and decomposed, with and without 2-particle factor --- src/madness/chem/ccpairfunction.cc | 1 + src/madness/chem/test_ccpairfunction.cc | 182 +----------------------- 2 files changed, 2 insertions(+), 181 deletions(-) diff --git a/src/madness/chem/ccpairfunction.cc b/src/madness/chem/ccpairfunction.cc index b4061a9608b..5a66d687d81 100644 --- a/src/madness/chem/ccpairfunction.cc +++ b/src/madness/chem/ccpairfunction.cc @@ -455,6 +455,7 @@ std::vector apply(const ProjectorBase& projector, const std::vec std::vector result; for (const auto& pf : argument) { if (pf.is_pure()) { + MADNESS_CHECK(not pf.has_operator()); // not yet implemented if (auto SO=dynamic_cast*>(&projector)) { auto tmp=(*SO)(pf.get_function()); auto tmp2=CCPairFunction(tmp); diff --git a/src/madness/chem/test_ccpairfunction.cc b/src/madness/chem/test_ccpairfunction.cc index 7e317a6e23f..a274a0afe06 100644 --- a/src/madness/chem/test_ccpairfunction.cc +++ b/src/madness/chem/test_ccpairfunction.cc @@ -274,191 +274,11 @@ int test_inner(World& world, std::shared_ptr ncf, cons double thresh=FunctionDefaults<3>::get_thresh(); bool good=(fabs(result-ref) ncf, const Molecule& molecule, - const CCParameters& parameters) { - CCTimer timer(world, "testing"); - auto R2 = ncf->square(); - - auto f12=CCConvolutionOperatorPtr(world, OT_F12, parameters); - - CorrelationFactor corrfac(world, 1.0, 1.e-7, molecule); - - auto g = [](const coord_3d& r) { return exp(-1.0 * r.normf()); }; - real_function_3d f1 = real_factory_3d(world).f(g); - real_function_3d R2f = R2 * f1; - double norm = inner(f1, R2f); - f1.scale(1.0 / sqrt(norm)); - R2f.scale(1.0 / sqrt(norm)); - CC_vecfunction mo_ket_(std::vector(1, f1), HOLE); - CC_vecfunction mo_bra_(std::vector(1, R2f), HOLE); - - bool passed_lo = true; - bool passed_hi = true; - bool success=true; - const double lo = parameters.thresh_6D(); - const double hi = parameters.thresh_3D(); - const double hi_loose = parameters.thresh_3D()*5.0; - - print("threshold 3D / 6D", hi,lo); - test_output t1("CCPairFunction::inner"); - t1.set_cout_to_terminal(); - // f^2 = 1/(4y^2)(1 - 2*f2(y) + f2(2y)) , f2(2y) =f2(y)^2 - // operator apply of SlaterF12Operator includes a factor of 1/(2 gamma) and the identity - // operator apply of SlaterOperator has no further terms - const double y = parameters.gamma(); - SeparatedConvolution f = SlaterF12Operator(world, y, parameters.lo(), parameters.thresh_bsh_3D()); - SeparatedConvolution f2 = SlaterOperator(world, y, parameters.lo(), parameters.thresh_bsh_3D()); - SeparatedConvolution ff = SlaterOperator(world, 2.0 * y, parameters.lo(), parameters.thresh_bsh_3D()); - - real_function_3d a = mo_ket_(0).function; - real_function_3d b = mo_ket_(0).function; - real_function_6d fab_6d = CompositeFactory(world).g12(corrfac.f()).particle1(copy(a)).particle2(copy(b)); - fab_6d.fill_tree().truncate().reduce_rank(); - fab_6d.print_size("fab_6d"); - - real_function_3d aR = mo_bra_(0).function; - real_function_3d bR = mo_bra_(0).function; - - const real_function_3d aa = (aR * a).truncate(); - const real_function_3d bb = (bR * b).truncate(); - const real_function_3d af2a = f2(aa); - const real_function_3d affa = ff(aa); - const real_function_3d afa = f(aa); - - const double prefactor = 1.0 / (4 * y * y); - const double term1= prefactor * (aR.inner(a) * bR.inner(b)); - const double term2= prefactor * 2.0 * bb.inner(af2a) ; - const double term3= prefactor * bb.inner(affa); - const double ab_f2_ab = prefactor * (aR.inner(a) * bR.inner(b) - 2.0 * bb.inner(af2a) + bb.inner(affa)); - const double ab_f_ab = inner(f(aa), bb); - - const long rank = world.rank(); - auto printer = [&rank](std::string msg, const double result, const double reference, const double time) { - if (rank == 0) { - long len = std::max(0l, long(40 - msg.size())); - msg += std::string(len, ' '); - std::cout << msg << std::fixed << std::setprecision(8) << "result, ref, diff " - << result << " " << reference << " " << std::setw(9) << std::setprecision(2) << std::scientific - << result - reference - << ", elapsed time " << std::fixed << std::setw(5) << std::setprecision(2) << time << std::endl; - } - }; - t1.checkpoint(true, "initialization"); - - double time_init = timer.reset(); - if (world.rank() == 0) print("time spent in initializing ", time_init); - { - CCPairFunction fab(f12, a, b); - const double test1 = inner(fab, fab, R2); - const double diff = test1 - ab_f2_ab; - if (fabs(diff) > lo) passed_lo = false; - if (fabs(diff) > hi) passed_hi = false; - - printer(" op_dec/op_dec : ", test1, ab_f2_ab, timer.reset()); - success=(fabs(diff) < hi); - } - t1.checkpoint(success, "op_dec/op_dec"); - { - CCPairFunction ab(mo_ket_.get_vecfunction(), mo_ket_.get_vecfunction()); - const double test1 = inner(ab, ab, R2); - const double test2 = double(mo_ket_.size()); // mos are normed - const double diff = test1 - test2; - printer(" dec/dec : ", test1, double(mo_ket_.size()), timer.reset()); - if (fabs(diff) > lo) passed_lo = false; - if (fabs(diff) > hi) passed_hi = false; - success=(fabs(diff) < hi); - } - t1.checkpoint(success, "dec/dec"); - { - CCPairFunction fab(fab_6d); - const double test1 = inner(fab, fab, R2); - const double diff = test1 - ab_f2_ab; - printer(" pure/pure : ", test1, ab_f2_ab, timer.reset()); - if (fabs(diff) > lo) passed_lo = false; - if (fabs(diff) > hi) passed_hi = false; - success=(fabs(diff) < hi_loose); - } - t1.checkpoint(success, "pure/pure"); - - { - CCPairFunction ab1(mo_ket_.get_vecfunction(), mo_ket_.get_vecfunction()); - CCPairFunction fab(f12, a, b); - timer.reset(); - const double test1 = inner(ab1, fab, R2); - const double test2 = ab_f_ab; - const double diff = test1 - test2; - printer(" dec/op_dec : ", test1, ab_f_ab, timer.reset()); - if (fabs(diff) > lo) passed_lo = false; - if (fabs(diff) > hi) passed_hi = false; - success=(fabs(diff) < hi); - } - t1.checkpoint(success, "dec/op_dec"); - - { - // the next tests evaulate in different ways - CCPairFunction fab(fab_6d); - CCPairFunction ab2(mo_ket_.get_vecfunction(), mo_ket_.get_vecfunction()); - const double test1 = inner(fab, ab2, R2); - const double test2 = bb.inner(afa); - const double diff = test1 - test2; - printer(" dec/pure", test1, test2, timer.reset()); - if (fabs(diff) > lo) passed_lo = false; - if (fabs(diff) > hi) passed_hi = false; - - success=(fabs(diff) < hi_loose); - } - t1.checkpoint(success, "dec/pure"); -// { -// CCPairFunction fab(fab_6d); -// CCPairFunction ab2(ab_6d); -// const double test1 = overlap(fab, ab2); -// const double test2 = bb.inner(afa); -// const double diff = test1 - test2; -// if (world.rank() == 0) -// std::cout << "Overlap Test 6 : " << std::fixed << std::setprecision(10) << "result=" << test1 -// << ", test=" << test2 << ", diff=" << diff << "\n"; -// if (fabs(diff) > lo) passed_lo = false; -// if (fabs(diff) > hi) passed_hi = false; -// } - { - CCPairFunction fab(f12, a, b); - CCPairFunction ab2(fab_6d); - const double test1 = inner(fab, ab2, R2); - const double test2 = ab_f2_ab; - const double diff = test1 - test2; - printer(" op_dec/pure : ", test1, test2, timer.reset()); - if (fabs(diff) > lo) passed_lo = false; - if (fabs(diff) > hi) passed_hi = false; - success=(fabs(diff) < hi_loose); // be a bit loose here .. - } - t1.checkpoint(success, "op_dec/pure"); - - { - CCPairFunction fab(f12, a, b); - CCPairFunction ab2(mo_ket_.get_vecfunction(), mo_ket_.get_vecfunction()); - timer.reset(); - const double test1 = inner(fab, ab2, R2); -// const double test2 = bb.inner(afa); - const double test2 = ab_f_ab; - const double diff = test1 - test2; - printer(" op_dec/dec : ", test1, test2, timer.reset()); - if (fabs(diff) > lo) passed_lo = false; - if (fabs(diff) > hi) passed_hi = false; - success=(fabs(diff) < hi); - } - t1.checkpoint(success, "op_dec/dec"); - - return (t1.get_final_success()) ? 0 : 1; -} - - int test_partial_inner_6d(World& world, std::shared_ptr ncf, const Molecule& molecule, const CCParameters& parameter) { @@ -1046,7 +866,7 @@ int main(int argc, char **argv) { mol, nullptr, std::make_pair("slater", 2.0)); isuccess+=test_constructor(world, ncf, mol, ccparam); -// isuccess+=test_transformations(world, ncf, mol, ccparam); + isuccess+=test_transformations(world, ncf, mol, ccparam); isuccess+=test_inner(world, ncf, mol, ccparam); isuccess+=test_swap_particles(world, ncf, mol, ccparam); isuccess+=test_scalar_multiplication(world, ncf, mol, ccparam); From ac685b4651d43bee9c3e7f89d20c8f36a9e3e0be Mon Sep 17 00:00:00 2001 From: fbischoff Date: Wed, 8 Feb 2023 22:34:15 +0100 Subject: [PATCH 012/109] Update cmake.yml --- .github/workflows/cmake.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index b815f63fa3f..b0f9196f809 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -52,7 +52,7 @@ jobs: - name: Install prerequisite MacOS packages if: ${{ matrix.os == 'macos-latest' }} run: | - brew install ninja gcc@10 boost eigen open-mpi bison tbb@2020 ccache + brew install ninja gcc@10 boost eigen open-mpi bison tbb@2022 ccache if [ "X${{ matrix.build_type }}" = "XDebug" ]; then brew install cereal fi From 88d9a07225874ea9e640fdb6f5b9414a54a558cc Mon Sep 17 00:00:00 2001 From: fbischoff Date: Wed, 8 Feb 2023 22:38:01 +0100 Subject: [PATCH 013/109] Update cmake.yml --- .github/workflows/cmake.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index b0f9196f809..a4af1318935 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -52,11 +52,11 @@ jobs: - name: Install prerequisite MacOS packages if: ${{ matrix.os == 'macos-latest' }} run: | - brew install ninja gcc@10 boost eigen open-mpi bison tbb@2022 ccache + brew install ninja gcc@10 boost eigen open-mpi bison tbb ccache if [ "X${{ matrix.build_type }}" = "XDebug" ]; then brew install cereal fi - echo "TBBROOT=/usr/local/opt/tbb@2020" >> $GITHUB_ENV + echo "TBBROOT=/usr/local/opt/tbb" >> $GITHUB_ENV echo "/usr/local/opt/bison/bin" >> $GITHUB_PATH - name: Install prerequisites Ubuntu packages From 2ed5e6b74edc23c542980cb38b91bc8446bc78e1 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Thu, 9 Feb 2023 15:02:53 +0100 Subject: [PATCH 014/109] CCPairFunction::multiply with single-particle functions --- src/madness/chem/ccpairfunction.cc | 25 ++++++++++++- src/madness/chem/ccpairfunction.h | 14 +++++++ src/madness/chem/test_ccpairfunction.cc | 50 +++++++++++++++++++++---- 3 files changed, 79 insertions(+), 10 deletions(-) diff --git a/src/madness/chem/ccpairfunction.cc b/src/madness/chem/ccpairfunction.cc index 5a66d687d81..254c92df010 100644 --- a/src/madness/chem/ccpairfunction.cc +++ b/src/madness/chem/ccpairfunction.cc @@ -58,6 +58,29 @@ void CCPairFunction::convert_to_pure_no_op_inplace() { component.reset(new TwoBodyFunctionPureComponent(result)); }; +CCPairFunction multiply(const CCPairFunction& other, const real_function_3d& f, const std::array& v1) { + auto a012=std::array{0,1,2}; + auto a345=std::array{3,4,5}; + int particle=-1; + if (v1== a012) particle=0; + if (v1== a345) particle=1; + MADNESS_CHECK(particle==0 or particle==1); + World& world=other.world(); + + if (other.is_decomposed()) { + if (particle == 0) { + return CCPairFunction(other.get_operator_ptr(), f * other.get_a(), copy(world, other.get_b())); + } else { + return CCPairFunction(other.get_operator_ptr(), copy(world, other.get_a()), f * other.get_b()); + } + } else if (other.is_pure()) { + auto tmp=multiply(other.get_function(),f,particle+1); + return CCPairFunction(other.get_operator_ptr(),tmp); + } else { + MADNESS_EXCEPTION("confused CCPairFunction in multiply",1); + } +}; + double CCPairFunction::make_xy_u(const CCFunction& xx, const CCFunction& yy) const { @@ -356,7 +379,6 @@ double CCPairFunction::inner_internal(const CCPairFunction& other, const real_fu for (const auto& single_op : ops) { auto fac=single_op.first; auto op=single_op.second; - print(op.name()); double bla=0.0; if (op.get_op()) { real_function_6d tmp1 = CompositeFactory(world()).g12(op.get_kernel()).ket(ket); @@ -380,7 +402,6 @@ double CCPairFunction::inner_internal(const CCPairFunction& other, const real_fu for (const auto& single_op : ops) { auto fac = single_op.first; auto op = single_op.second; - print(op.name()); double bla=0.0; for (int i=0; i; component.reset(new TwoBodyFunctionSeparatedComponent(copy(world,f1),copy(world,f2))); } + /// takes a deep copy of the argument functions + explicit CCPairFunction(const real_function_3d& f1, const real_function_3d& f2) : + CCPairFunction(std::vector({f1}),std::vector({f2})) { + } + /// takes a deep copy of the argument functions explicit CCPairFunction(const std::pair& f) : CCPairFunction(f.first,f.second) { @@ -338,6 +343,12 @@ using pureT=Function; component.reset(new TwoBodyFunctionSeparatedComponent(copy(world,f1),copy(world,f2),op_)); } + /// takes a deep copy of the argument functions + explicit CCPairFunction(const std::shared_ptr op_, const real_function_3d& f1, + const real_function_3d& f2) : CCPairFunction(op_,std::vector({f1}), + std::vector({f2})) { + }; + /// shallow assignment operator CCPairFunction& operator()(const CCPairFunction& other) { component=other.component; @@ -450,6 +461,9 @@ using pureT=Function; return component->name(transpose); } + /// multiply CCPairFunction with a 3D function of one of the two particles + friend CCPairFunction multiply(const CCPairFunction& other, const real_function_3d& f, const std::array& v1); + /// @param[in] f: a 3D-CC_function /// @param[in] particle: the particle on which the operation acts /// @param[out] _particle (projection from 6D to 3D) diff --git a/src/madness/chem/test_ccpairfunction.cc b/src/madness/chem/test_ccpairfunction.cc index a274a0afe06..6d050f7364c 100644 --- a/src/madness/chem/test_ccpairfunction.cc +++ b/src/madness/chem/test_ccpairfunction.cc @@ -202,6 +202,39 @@ int test_transformations(World& world, std::shared_ptr return t1.end(); } +int test_multiply(World& world, std::shared_ptr ncf, const Molecule& molecule, + const CCParameters& parameters) { + test_output t1("CCPairFunction::test_multiply"); + + // consistency check, relies on CCPairFunction::inner to work correctly + + double thresh=FunctionDefaults<3>::get_thresh(); + auto [p1,p2,p3,p4,p5]=data1.get_ccpairfunctions(); // p2-p5 correspond to f23 + auto [f1,f2,f3,f4,f5,f]=data1.get_functions(); + + // reference value is = + CCPairFunction bra(f1,f2); + CCPairFunction bra1(f1*f2,f2); + CCPairFunction bra2(f1,f2*f2); + for (auto& p : {p2,p3,p4,p5}) { + + auto tmp1=multiply(p,f2,{0,1,2}); + double ovlp1=inner(bra,tmp1); + double ref1=p.has_operator() ? inner(bra1,p3) : inner(bra1,p2); + + bool good=(fabs(ovlp1-ref1) ncf, const Molecule& molecule, const CCParameters& parameters) { test_output t1("CCPairFunction::test_inner"); @@ -270,7 +303,7 @@ int test_inner(World& world, std::shared_ptr ncf, cons if ((not bra.has_operator()) and (not ket.has_operator())) ref=ab_ab; double result=inner(bra,ket); - print(bra.name(true)+ket.name(),"ref, result, diff", ref, result, ref-result); +// print(bra.name(true)+ket.name(),"ref, result, diff", ref, result, ref-result); double thresh=FunctionDefaults<3>::get_thresh(); bool good=(fabs(result-ref)::set_cubic_cell(-10,10); - isuccess+=test_helium(world,ncf,mol,ccparam); + isuccess+=test_multiply(world, ncf, mol, ccparam); +// isuccess+=test_swap_particles(world, ncf, mol, ccparam); +// isuccess+=test_scalar_multiplication(world, ncf, mol, ccparam); +// isuccess+=test_partial_inner_3d(world, ncf, mol, ccparam); +// isuccess+=test_partial_inner_6d(world, ncf, mol, ccparam); +// isuccess+=test_projector(world, ncf, mol, ccparam); +// FunctionDefaults<3>::set_cubic_cell(-10,10); +// isuccess+=test_helium(world,ncf,mol,ccparam); data1.clear(); } catch (std::exception& e) { madness::print("an error occured"); From 37f0fc2ceffad60f36794e75ef78a95663d9b28e Mon Sep 17 00:00:00 2001 From: fbischoff Date: Thu, 9 Feb 2023 15:39:34 +0100 Subject: [PATCH 015/109] convenience function: f12 * CCPairfunction --- src/madness/chem/ccpairfunction.cc | 14 ++++++ src/madness/chem/ccpairfunction.h | 23 +++++++++ src/madness/chem/test_ccpairfunction.cc | 66 +++++++++++++++++++------ 3 files changed, 88 insertions(+), 15 deletions(-) diff --git a/src/madness/chem/ccpairfunction.cc b/src/madness/chem/ccpairfunction.cc index 254c92df010..b6d96379986 100644 --- a/src/madness/chem/ccpairfunction.cc +++ b/src/madness/chem/ccpairfunction.cc @@ -82,6 +82,20 @@ CCPairFunction multiply(const CCPairFunction& other, const real_function_3d& f, }; +/// multiplication with a 2-particle function +CCPairFunction& CCPairFunction::multiply_with_op_inplace(const std::shared_ptr op) { + if (has_operator()) { + auto ops=combine(get_operator_ptr(),op); + MADNESS_CHECK(ops.size()==1); + MADNESS_CHECK(ops.front().first==1.0); + auto newop=std::make_shared(ops.front().second); + set_operator(newop); + } else { + set_operator(op); + } + return *this; +} + double CCPairFunction::make_xy_u(const CCFunction& xx, const CCFunction& yy) const { double result = 0.0; diff --git a/src/madness/chem/ccpairfunction.h b/src/madness/chem/ccpairfunction.h index 1b3342d479e..2940f5b3ebf 100644 --- a/src/madness/chem/ccpairfunction.h +++ b/src/madness/chem/ccpairfunction.h @@ -386,16 +386,33 @@ using pureT=Function; /// deep copy necessary otherwise: shallow copy errors CCPairFunction invert_sign(); + /// scalar multiplication: f*fac CCPairFunction operator*(const double fac) const { CCPairFunction result=copy(*this); result*=fac; return result; } + /// scalar multiplication: fac*f friend CCPairFunction operator*(const double fac, const CCPairFunction& f) { return fac*f; } + /// multiplication with a 2-particle function + friend CCPairFunction operator*(const std::shared_ptr op, const CCPairFunction& f) { + CCPairFunction result=copy(f); + return result.multiply_with_op_inplace(op); + } + + /// multiplication with a 2-particle function + CCPairFunction operator*(const std::shared_ptr op) { + CCPairFunction result=copy(*this); + return result.multiply_with_op_inplace(op); + } + + CCPairFunction& multiply_with_op_inplace(const std::shared_ptr op); + + bool has_operator() const {return component->has_operator();} bool is_pure() const {return component->is_pure();} bool is_op_pure() const {return is_pure() and has_operator();} @@ -439,6 +456,12 @@ using pureT=Function; return component->get_operator_ptr(); } + void set_operator(const std::shared_ptr op) { + MADNESS_CHECK(not has_operator()); + MADNESS_CHECK(component); + component->set_operator(op); + } + /// can this be converted to a pure representation (depends on the operator, if present) bool is_convertible_to_pure_no_op() const; diff --git a/src/madness/chem/test_ccpairfunction.cc b/src/madness/chem/test_ccpairfunction.cc index 6d050f7364c..7c682208aa3 100644 --- a/src/madness/chem/test_ccpairfunction.cc +++ b/src/madness/chem/test_ccpairfunction.cc @@ -101,7 +101,6 @@ data data1; int test_constructor(World& world, std::shared_ptr ncf, const Molecule& molecule, const CCParameters& parameter) { - int success=0; test_output t1("CCPairFunction::constructor"); real_function_6d f=real_factory_6d(world); @@ -159,8 +158,8 @@ int test_constructor(World& world, std::shared_ptr ncf } t1.checkpoint(true,"checks on assignment"); - return t1.end(); + return t1.end(); } int test_transformations(World& world, std::shared_ptr ncf, const Molecule& molecule, @@ -202,6 +201,48 @@ int test_transformations(World& world, std::shared_ptr return t1.end(); } +int test_multiply_with_f12(World& world, std::shared_ptr ncf, const Molecule& molecule, + const CCParameters& parameters) { + test_output t1("CCPairFunction::test_multiply_with_f12"); + + // p1: pure, corresponds to f12 + // p2: dec, corresponds to f23 + // p3: op_dec, corresponds to f23 + // p4: pure, corresponds to f23 + // p5: op_pure, corresponds to f23 + auto [p1,p2,p3,p4,p5]=data1.get_ccpairfunctions(); // p2-p5 correspond to f23 + auto f12=data1.f12_op; + + double thresh=FunctionDefaults<3>::get_thresh(); + + // decomposed + CCPairFunction tmp1=f12*p2; // should now be identical to p3 + CCPairFunction tmp2=p2*f12; // should now be identical to p3 + double ref=inner(p2,p3); + + double r1=inner(p2,tmp1); + bool good=(fabs(ref-r1) ncf, const Molecule& molecule, const CCParameters& parameters) { test_output t1("CCPairFunction::test_multiply"); @@ -532,7 +573,6 @@ int test_partial_inner_3d(World& world, std::shared_ptr ncf, const Molecule& molecule, const CCParameters& parameter) { - int success=0; test_output t1("CCPairFunction::test_apply"); return (t1.get_final_success()) ? 0 : 1; @@ -540,7 +580,6 @@ int test_apply(World& world, std::shared_ptr ncf, cons int test_scalar_multiplication(World& world, std::shared_ptr ncf, const Molecule& molecule, const CCParameters& parameter) { - int success=0; CCTimer timer(world, "testing"); test_output t1("CCPairFunction::test_scalar_multiplication"); @@ -576,7 +615,6 @@ int test_scalar_multiplication(World& world, std::shared_ptr::get_thresh(); t1.checkpoint(bsuccess,"scaling"); - if (bsuccess) success++; t1.end(); return (t1.get_final_success()) ? 0 : 1; @@ -584,7 +622,6 @@ int test_scalar_multiplication(World& world, std::shared_ptr ncf, const Molecule& molecule, const CCParameters& parameters) { - int success = 0; test_output t1("CCPairFunction::swap_particles"); CCTimer timer(world, "testing swap_particles"); @@ -659,7 +696,6 @@ int test_swap_particles(World& world, std::shared_ptr int test_projector(World& world, std::shared_ptr ncf, const Molecule& molecule, const CCParameters& parameter) { - int success=0; test_output t1("CCPairFunction::test_projector"); CCTimer timer(world, "testing"); @@ -772,7 +808,6 @@ int test_projector(World& world, std::shared_ptr ncf, int test_dirac_convolution(World& world, std::shared_ptr ncf, const Molecule& molecule, const CCParameters& parameter) { - int success=0; test_output t1("CCPairFunction::test_dirac_convolution"); return (t1.get_final_success()) ? 0 : 1; @@ -902,13 +937,14 @@ int main(int argc, char **argv) { isuccess+=test_transformations(world, ncf, mol, ccparam); isuccess+=test_inner(world, ncf, mol, ccparam); isuccess+=test_multiply(world, ncf, mol, ccparam); -// isuccess+=test_swap_particles(world, ncf, mol, ccparam); -// isuccess+=test_scalar_multiplication(world, ncf, mol, ccparam); -// isuccess+=test_partial_inner_3d(world, ncf, mol, ccparam); -// isuccess+=test_partial_inner_6d(world, ncf, mol, ccparam); -// isuccess+=test_projector(world, ncf, mol, ccparam); -// FunctionDefaults<3>::set_cubic_cell(-10,10); -// isuccess+=test_helium(world,ncf,mol,ccparam); + isuccess+=test_multiply_with_f12(world, ncf, mol, ccparam); + isuccess+=test_swap_particles(world, ncf, mol, ccparam); + isuccess+=test_scalar_multiplication(world, ncf, mol, ccparam); + isuccess+=test_partial_inner_3d(world, ncf, mol, ccparam); + isuccess+=test_partial_inner_6d(world, ncf, mol, ccparam); + isuccess+=test_projector(world, ncf, mol, ccparam); + FunctionDefaults<3>::set_cubic_cell(-10,10); + isuccess+=test_helium(world,ncf,mol,ccparam); data1.clear(); } catch (std::exception& e) { madness::print("an error occured"); From 21bdff6dd2deae6775abd51717f4780ce6e05486 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Fri, 10 Feb 2023 23:48:25 +0100 Subject: [PATCH 016/109] additional factors in operator.h and gfit, moving towards MP3 --- src/apps/mp2/mp2.cc | 7 ++ src/madness/chem/CCStructures.cc | 12 +++ src/madness/chem/CCStructures.h | 32 +++--- src/madness/chem/ccpairfunction.cc | 4 +- src/madness/chem/ccpairfunction.h | 14 ++- src/madness/chem/mp2.cc | 54 ++++++++++ src/madness/chem/mp2.h | 4 + src/madness/mra/gfit.h | 158 +++++++++++++++++++++-------- src/madness/mra/operator.h | 49 +++++++++ 9 files changed, 276 insertions(+), 58 deletions(-) diff --git a/src/apps/mp2/mp2.cc b/src/apps/mp2/mp2.cc index 69988610b33..7ba639380d9 100644 --- a/src/apps/mp2/mp2.cc +++ b/src/apps/mp2/mp2.cc @@ -84,6 +84,13 @@ int main(int argc, char** argv) { printf("final hf/mp2/total energy %12.8f %12.8f %12.8f\n", hf_energy,mp2_energy,hf_energy+mp2_energy); } + double mp3_correction=mp2.mp3(); + print("mp3 correction",mp3_correction); + double mp3_energy=mp3_correction+mp2_energy; + if(world.rank() == 0) { + printf("final hf/mp3/total energy %12.8f %12.8f %12.8f\n", + hf_energy,mp3_energy,hf_energy+mp3_energy); + } } } catch (std::exception& e) { diff --git a/src/madness/chem/CCStructures.cc b/src/madness/chem/CCStructures.cc index 93e6281bf29..7e2e67e7737 100644 --- a/src/madness/chem/CCStructures.cc +++ b/src/madness/chem/CCStructures.cc @@ -433,6 +433,18 @@ CCConvolutionOperator::init_op(const OpType& type, const Parameters& parameters) << " and lo=" << parameters.lo << " and Gamma=" << parameters.gamma << std::endl; return BSHOperatorPtr3D(world, parameters.gamma, parameters.lo, parameters.thresh_op); } + case OT_FG12: { + if (printme) + std::cout << "Creating " << assign_name(type) << " Operator with thresh=" << parameters.thresh_op + << " and lo=" << parameters.lo << " and Gamma=" << parameters.gamma << std::endl; + return FGOperatorPtr(world, parameters.gamma, parameters.lo, parameters.thresh_op); + } + case OT_F2G12: { + if (printme) + std::cout << "Creating " << assign_name(type) << " Operator with thresh=" << parameters.thresh_op + << " and lo=" << parameters.lo << " and Gamma=" << parameters.gamma << std::endl; + return F2GOperatorPtr(world, parameters.gamma, parameters.lo, parameters.thresh_op); + } case OT_ONE : { if (printme) std::cout << "Creating " << assign_name(type) << " Operator " << std::endl; diff --git a/src/madness/chem/CCStructures.h b/src/madness/chem/CCStructures.h index 613b2c48364..d7354427778 100644 --- a/src/madness/chem/CCStructures.h +++ b/src/madness/chem/CCStructures.h @@ -25,11 +25,12 @@ enum OpType { OT_UNDEFINED, OT_ONE, /// indicates the identity OT_G12, /// 1/r - OT_SLATER, /// exp(r) - OT_F12, /// 1-exp(r) - OT_FG12, /// (1-exp(r))/r - OT_F212, /// (1-exp(r))^2 - OT_BSH /// exp(r)/r + OT_SLATER, /// exp(-r) + OT_F12, /// 1-exp(-r) + OT_FG12, /// (1-exp(-r))/r + OT_F212, /// (1-exp(-r))^2 + OT_F2G12, /// (1-exp(-r))^2/r = 1/r + exp(-2r)/r - 2 exp(-r)/r + OT_BSH /// exp(-r)/r }; /// Calculation Types used by CC2 @@ -724,6 +725,17 @@ struct CCConvolutionOperator { type=OT_FG12; param.gamma=right.parameters.gamma; } + if ((left.type()==OT_G12) and (right.type()==OT_F212)) { + type=OT_F2G12; + param.gamma=right.parameters.gamma; + } + if (((left.type()==OT_F212) and (right.type()==OT_G12)) or + ((left.type()==OT_F12) and (right.type()==OT_FG12)) or + ((left.type()==OT_FG12) and (right.type()==OT_F12))) { + type=OT_F2G12; + if (right.type()!=OT_G12) MADNESS_CHECK(right.parameters.gamma == left.parameters.gamma); + param.gamma=right.parameters.gamma; + } if ((left.type()==OT_F12) and (right.type()==OT_F12)) { type=OT_F212; // keep the original gamma @@ -760,15 +772,11 @@ struct CCConvolutionOperator { std::vector> result; if (type==OT_FG12) { // fg = (1 - exp(-gamma r12)) / r12 = 1/r12 - exp(-gamma r12)/r12 = coulomb - bsh + result.push_back(std::make_pair(1.0, CCConvolutionOperator(left.world, OT_FG12, param))); - // coulombfit return 1/r - // we need 1/(2 gamma) 1/r - result.push_back(std::make_pair(1.0/(2.0*param.gamma),CCConvolutionOperator(left.world, OT_G12, param))); + } else if (type==OT_F2G12) { + result.push_back(std::make_pair(1.0, CCConvolutionOperator(left.world, OT_F2G12, param))); - // bshfit returns 1/(4 pi) exp(-gamma r)/r - // we need 1/(2 gamma) exp(-gamma r)/r - const double factor = 4.0 * constants::pi /(2.0*param.gamma); - result.push_back(std::make_pair(-factor,CCConvolutionOperator(left.world, OT_BSH, param))); } else if (type==OT_F212) { // we use the slater operator which is S = e^(-y*r12), y=gamma // the f12 operator is: 1/2y*(1-e^(-y*r12)) = 1/2y*(1-S) diff --git a/src/madness/chem/ccpairfunction.cc b/src/madness/chem/ccpairfunction.cc index b6d96379986..aecf8da494c 100644 --- a/src/madness/chem/ccpairfunction.cc +++ b/src/madness/chem/ccpairfunction.cc @@ -89,9 +89,9 @@ CCPairFunction& CCPairFunction::multiply_with_op_inplace(const std::shared_ptr(ops.front().second); - set_operator(newop); + reset_operator(newop); } else { - set_operator(op); + reset_operator(op); } return *this; } diff --git a/src/madness/chem/ccpairfunction.h b/src/madness/chem/ccpairfunction.h index 2940f5b3ebf..8b65dcddb7b 100644 --- a/src/madness/chem/ccpairfunction.h +++ b/src/madness/chem/ccpairfunction.h @@ -404,6 +404,17 @@ using pureT=Function; return result.multiply_with_op_inplace(op); } + /// multiplication with a 2-particle function + friend std::vector operator*(const std::shared_ptr op, + const std::vector& f) { + std::vector result; + for (auto& ff : f) { + result.push_back(copy(ff)); + result.back().multiply_with_op_inplace(op); + } + return result; + } + /// multiplication with a 2-particle function CCPairFunction operator*(const std::shared_ptr op) { CCPairFunction result=copy(*this); @@ -456,8 +467,7 @@ using pureT=Function; return component->get_operator_ptr(); } - void set_operator(const std::shared_ptr op) { - MADNESS_CHECK(not has_operator()); + void reset_operator(const std::shared_ptr op) { MADNESS_CHECK(component); component->set_operator(op); } diff --git a/src/madness/chem/mp2.cc b/src/madness/chem/mp2.cc index 81ddcb81da7..80db26bd159 100644 --- a/src/madness/chem/mp2.cc +++ b/src/madness/chem/mp2.cc @@ -262,6 +262,7 @@ double MP2::value(const Tensor& x) { if (world.rank() == 0) { printf("current decoupled mp2 energy %12.8f\n", correlation_energy); } + if (param.no_compute()) return correlation_energy; correlation_energy = 0.0; if (hf->get_calc().param.do_localize()) { @@ -282,6 +283,59 @@ double MP2::value(const Tensor& x) { return correlation_energy; } +double MP2::mp3() const { + + Pairs> clusterfunctions; + double mp3_energy=0.0; + CCTimer t1(world,"make pairs"); + // load converged MP1 wave functions + for (int i = param.freeze(); i < hf->nocc(); ++i) { + for (int j = i; j < hf->nocc(); ++j) { +// pairs(i, j) = make_pair(i, j); // initialize + clusterfunctions(i,j).push_back(CCPairFunction(pairs(i,j).function)); + CCPairFunction ij(hf->nemo(i),hf->nemo(j)); + + CCConvolutionOperator::Parameters cparam; + cparam.thresh_op*=0.1; + auto f12=CCConvolutionOperatorPtr(world,OT_F12,cparam); + auto vfij=Q12(std::vector({f12*ij})); + for (auto& p : vfij) clusterfunctions(i,j).push_back(p); + } + } + t1.print(); + CCTimer t2(world,"recompute MP2"); + // recompute MP2 energy + CCConvolutionOperator::Parameters cparam; + auto g12=CCConvolutionOperatorPtr(world,OT_G12,cparam); + for (int i = param.freeze(); i < hf->nocc(); ++i) { + for (int j = i; j < hf->nocc(); ++j) { + auto bra=g12*CCPairFunction(hf->R2orbital(i),hf->R2orbital(j)); + double energy1=inner(bra,clusterfunctions(i,j).front()); + double energy=energy1+pairs(i,j).ij_gQf_ij; + print("MP2 energy: gQf, u",pairs(i,j).ij_gQf_ij,energy1,energy); + print("time compute ",t2.reset()); + + double energy2=inner({bra},clusterfunctions(i,j)); + printf("MP2 energy: cluster %12.8f\n",energy2); + print("time clusterfunction",t2.reset()); + } + } + + CCTimer t3(world,"MP3"); + // compute the MP3 energy + for (int i = param.freeze(); i < hf->nocc(); ++i) { + for (int j = i; j < hf->nocc(); ++j) { + auto bra=g12*clusterfunctions(i,j); + double energy2=inner(bra,clusterfunctions(i,j)); + print("MP3 energy: term1",energy2); + } + } + t3.print(); + + + return mp3_energy; +} + /// solve the residual equation for electron pair (i,j) void MP2::solve_residual_equations(ElectronPair& result, const double econv, const double dconv) const { diff --git a/src/madness/chem/mp2.h b/src/madness/chem/mp2.h index 162e5158803..3802c693199 100644 --- a/src/madness/chem/mp2.h +++ b/src/madness/chem/mp2.h @@ -332,6 +332,7 @@ class MP2 : public OptimizationTargetInterface, public QCPropertyInterface { initialize < int > ("freeze", 0); initialize < int > ("maxsub", 2); initialize < bool > ("restart", true); + initialize < bool > ("no_compute", false); initialize < int > ("maxiter", 5); read_and_set_derived_values(world,parser); @@ -362,6 +363,7 @@ class MP2 : public OptimizationTargetInterface, public QCPropertyInterface { int i() const { return this->get >("pair")[0]; } /// convenience function int j() const { return this->get >("pair")[1]; } /// convenience function int restart() const { return this->get("restart"); } /// convenience function + int no_compute() const { return this->get("no_compute"); } /// convenience function int maxiter() const { return this->get("maxiter"); } /// convenience function int maxsub() const { return this->get("maxsub"); } /// convenience function bool do_oep() const { return do_oep1;} @@ -442,6 +444,8 @@ class MP2 : public OptimizationTargetInterface, public QCPropertyInterface { return hf->orbital_energy(i) + hf->orbital_energy(j); } + double mp3() const; + /// solve the residual equation for electron pair (i,j) /// \todo Parameter documentation. Below are un-doxygenated comments that no longer seem relevant? diff --git a/src/madness/mra/gfit.h b/src/madness/mra/gfit.h index 9820064924c..a2110e9dc44 100644 --- a/src/madness/mra/gfit.h +++ b/src/madness/mra/gfit.h @@ -79,8 +79,14 @@ class GFit { /// @parma[in] prnt print level static GFit BSHFit(double mu, double lo, double hi, double eps, bool prnt=false) { GFit fit; - if (NDIM==3) bsh_fit(mu,lo,hi,eps,fit.coeffs_,fit.exponents_,prnt); + if (NDIM==3) bsh_fit(mu,lo,hi,eps,fit.coeffs_,fit.exponents_,prnt,true); else bsh_fit_ndim(NDIM,mu,lo,hi,eps,fit.coeffs_,fit.exponents_,prnt); + + if (prnt) { + print("bsh fit"); + auto exact = [&mu](const double r) -> double { return 1.0/(4.0 * constants::pi) * exp(-mu * r)/r; }; + fit.print_accuracy(exact, lo, hi); + } return fit; } @@ -124,6 +130,84 @@ class GFit { return fit; } + /// return a fit for the FG function + + /// fg = 1/(2 mu) * (1 - exp(-gamma r12)) / r12 + /// = 1/(2 mu) *( 1/r12 - exp(-gamma r12)/r12) + /// = 1/(2 mu) * (coulomb - bsh) + /// @param[in] gamma the exponent of the Slater function + /// @param[in] lo the smallest length scale that needs to be precisely represented + /// @param[in] hi the largest length scale that needs to be precisely represented + /// @param[in] eps the precision threshold + /// @parma[in] prnt print level + static GFit FGFit(double gamma, double lo, double hi, double eps, bool prnt=false) { + GFit bshfit,coulombfit; + eps*=0.1; + lo*=0.1; + bool restrict_interval=false; + bsh_fit(gamma,lo,hi,eps,bshfit.coeffs_,bshfit.exponents_,false,restrict_interval); + bsh_fit(0.0,lo,hi,eps,coulombfit.coeffs_,coulombfit.exponents_,false,restrict_interval); + // check the exponents are identical + auto diffexponents=(coulombfit.exponents() - bshfit.exponents()); + MADNESS_CHECK(diffexponents.normf()/coulombfit.exponents().size()<1.e-12); + auto diffcoefficients=(coulombfit.coeffs() - bshfit.coeffs()); + GFit fgfit; + fgfit.exponents_=bshfit.exponents_; + fgfit.coeffs_=4.0*constants::pi*0.5/gamma*diffcoefficients; + GFit::prune_small_coefficients(eps,lo,hi,fgfit.coeffs_,fgfit.exponents_); + + if (prnt) { + print("fg fit"); + auto exact=[&gamma](const double r) -> double {return 0.5/gamma*(1.0-exp(-gamma*r))/r;}; + fgfit.print_accuracy(exact,lo,hi); + } + return fgfit; + } + + /// return a fit for the F2G function + + /// f2g = (1/(2 mu) * (1 - exp(-gamma r12)))^2 / r12 + /// = 1/(4 mu^2) * [ 1/r12 - 2 exp(-gamma r12)/r12) + exp(-2 gamma r12)/r12 ] + /// @param[in] gamma the exponent of the Slater function + /// @param[in] lo the smallest length scale that needs to be precisely represented + /// @param[in] hi the largest length scale that needs to be precisely represented + /// @param[in] eps the precision threshold + /// @parma[in] prnt print level + static GFit F2GFit(double gamma, double lo, double hi, double eps, bool prnt=false) { + GFit bshfit,coulombfit,bsh2fit; + eps*=0.1; + lo*=0.1; + bool restrict_interval=false; + bsh_fit(gamma,lo,hi,eps,bshfit.coeffs_,bshfit.exponents_,false,restrict_interval); + bsh_fit(2.0*gamma,lo,hi,eps,bsh2fit.coeffs_,bsh2fit.exponents_,false,restrict_interval); + bsh_fit(0.0,lo,hi,eps,coulombfit.coeffs_,coulombfit.exponents_,false,restrict_interval); + + // check the exponents are identical + auto diffexponents=(coulombfit.exponents() - bshfit.exponents()); + MADNESS_CHECK(diffexponents.normf()/coulombfit.exponents().size()<1.e-12); + auto diffexponents1=(coulombfit.exponents() - bsh2fit.exponents()); + MADNESS_CHECK(diffexponents1.normf()/coulombfit.exponents().size()<1.e-12); + + auto coefficients=(coulombfit.coeffs() - 2.0* bshfit.coeffs() + bsh2fit.coeffs()); + GFit f2gfit; + f2gfit.exponents_=bshfit.exponents_; + // additional factor 4 pi due to implementation of bsh_fit + double fourpi=4.0*constants::pi; + double fourmu2=4.0*gamma*gamma; + f2gfit.coeffs_=fourpi/fourmu2*coefficients; + GFit::prune_small_coefficients(eps,lo,hi,f2gfit.coeffs_,f2gfit.exponents_); + + if (prnt) { + print("fg fit"); + auto exact=[&gamma](const double r) -> double { + return 0.25/(gamma*gamma)*(1.0-2.0*exp(-gamma*r)+exp(-2.0*gamma*r))/r; + }; + f2gfit.print_accuracy(exact,lo,hi); + } + return f2gfit; + } + + /// return a fit for a general isotropic function /// note that the error is controlled over a uniform grid, the boundaries @@ -139,7 +223,26 @@ class GFit { /// return the exponents of the fit Tensor exponents() const {return exponents_;} - void truncate_periodic_expansion(Tensor& c, Tensor& e, + void static prune_small_coefficients(const double eps, const double lo, const double hi, + Tensor& coeff, Tensor& expnt) { + double mid = lo + (hi-lo)*0.5; + long npt=coeff.size(); + long i; + for (i=npt-1; i>0; --i) { + double cnew = coeff[i]*exp(-(expnt[i]-expnt[i-1])*mid*mid); + double errlo = coeff[i]*exp(-expnt[i]*lo*lo) - + cnew*exp(-expnt[i-1]*lo*lo); + double errhi = coeff[i]*exp(-expnt[i]*hi*hi) - + cnew*exp(-expnt[i-1]*hi*hi); + if (std::max(std::abs(errlo),std::abs(errhi)) > 0.03*eps) break; + npt--; + coeff[i-1] = coeff[i-1] + cnew; + } + coeff = coeff(Slice(0,npt-1)); + expnt = expnt(Slice(0,npt-1)); + } + + void truncate_periodic_expansion(Tensor& c, Tensor& e, double L, bool discardG0) const { double tcut = 0.25/L/L; @@ -227,11 +330,14 @@ class GFit { /// Multiresolution Quantum Chemistry in Multiwavelet Bases, /// Lecture Notes in Computer Science, vol. 2660, p. 707, 2003. static void bsh_fit(double mu, double lo, double hi, double eps, - Tensor& pcoeff, Tensor& pexpnt, bool prnt) { + Tensor& pcoeff, Tensor& pexpnt, bool prnt, bool use_mu_for_restricting_interval) { - if (mu < 0.0) throw "cannot handle negative mu in bsh_fit"; + if (mu < 0.0) throw "cannot handle negative mu in bsh_fit"; + bool restrict_interval=(mu>0) and use_mu_for_restricting_interval; - if (mu > 0) { + +// if (mu > 0) { + if (restrict_interval) { // Restrict hi according to the exponential decay double r = -log(4*constants::pi*0.01*eps); r = -log(r * 4*constants::pi*0.01*eps); @@ -249,7 +355,8 @@ class GFit { else if (eps >= 1e-12) TT = 26; else TT = 30; - if (mu > 0) { +// if (mu > 0) { + if (restrict_interval) { slo = -0.5*log(4.0*TT/(mu*mu)); } else { @@ -307,21 +414,9 @@ class GFit { // end points ... if this error is less than the desired // precision, can discard the diffuse gaussian. - if (mu == 0.0) { - double mid = lo + (hi-lo)*0.5; - long i; - for (i=npt-1; i>0; --i) { - double cnew = coeff[i]*exp(-(expnt[i]-expnt[i-1])*mid*mid); - double errlo = coeff[i]*exp(-expnt[i]*lo*lo) - - cnew*exp(-expnt[i-1]*lo*lo); - double errhi = coeff[i]*exp(-expnt[i]*hi*hi) - - cnew*exp(-expnt[i-1]*hi*hi); - if (std::max(std::abs(errlo),std::abs(errhi)) > 0.03*eps) break; - npt--; - coeff[i-1] = coeff[i-1] + cnew; - } - coeff = coeff(Slice(0,npt-1)); - expnt = expnt(Slice(0,npt-1)); +// if (mu == 0.0) { + if (restrict_interval) { + GFit::prune_small_coefficients(eps,lo,hi,coeff,expnt); } // Modify the coeffs of the largest exponents to satisfy the moment conditions @@ -382,27 +477,6 @@ class GFit { coeff(Slice(0,nmom-1)) = ncoeff; } - if (prnt) { - for (int i=0; i(world, coeff, expnt, bc, k, false, mu); } + /// Factory function generating separated kernel for convolution with 1/(2 mu)*(1 - exp(-mu*r))/r in 3D + + /// fg = (1 - exp(-gamma r12)) / r12 = 1/r12 - exp(-gamma r12)/r12 = coulomb - bsh + /// includes the factor 1/(2 mu) + static inline SeparatedConvolution* FGOperatorPtr(World& world, + double mu, double lo, double eps, + const BoundaryConditions<3>& bc=FunctionDefaults<3>::get_bc(), + int k=FunctionDefaults<3>::get_k()) { + + const Tensor& cell_width = FunctionDefaults<3>::get_cell_width(); + double hi = cell_width.normf(); // Diagonal width of cell + if (bc(0,0) == BC_PERIODIC) hi *= 100; // Extend range for periodic summation + + GFit fit=GFit::FGFit(mu,lo,hi,eps,false); + Tensor coeff=fit.coeffs(); + Tensor expnt=fit.exponents(); + + if (bc(0,0) == BC_PERIODIC) { + fit.truncate_periodic_expansion(coeff, expnt, cell_width.max(), false); + } + + return new SeparatedConvolution(world, coeff, expnt, bc, k, false, mu); + } + + /// Factory function generating separated kernel for convolution with (1/(2 mu)*(1 - exp(-mu*r)))^2/r in 3D + + /// f2g = (1/(2 gamma) (1 - exp(-gamma r12)))^2 / r12 + /// = 1/(4 gamma) * [ 1/r12 - 2 exp(-gamma r12)/r12 + exp(-2 gamma r12)/r12 ] + /// includes the factor 1/(2 mu)^2 + static inline SeparatedConvolution* F2GOperatorPtr(World& world, + double mu, double lo, double eps, + const BoundaryConditions<3>& bc=FunctionDefaults<3>::get_bc(), + int k=FunctionDefaults<3>::get_k()) { + + const Tensor& cell_width = FunctionDefaults<3>::get_cell_width(); + double hi = cell_width.normf(); // Diagonal width of cell + if (bc(0,0) == BC_PERIODIC) hi *= 100; // Extend range for periodic summation + + GFit fit=GFit::F2GFit(mu,lo,hi,eps,false); + Tensor coeff=fit.coeffs(); + Tensor expnt=fit.exponents(); + + if (bc(0,0) == BC_PERIODIC) { + fit.truncate_periodic_expansion(coeff, expnt, cell_width.max(), false); + } + + return new SeparatedConvolution(world, coeff, expnt, bc, k, false, mu); + } + /// Factory function generating separated kernel for convolution a normalized /// Gaussian (aka a widened delta function) From a8d8992487b797b800e38f4197eecf98397c5cf6 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Sun, 26 Feb 2023 19:13:42 +0100 Subject: [PATCH 017/109] working on mp3 --- src/madness/chem/ccpairfunction.h | 9 ++++- src/madness/chem/mp2.cc | 67 +++++++++++++++++++++++++++++-- 2 files changed, 72 insertions(+), 4 deletions(-) diff --git a/src/madness/chem/ccpairfunction.h b/src/madness/chem/ccpairfunction.h index 8b65dcddb7b..581cc0f1383 100644 --- a/src/madness/chem/ccpairfunction.h +++ b/src/madness/chem/ccpairfunction.h @@ -415,6 +415,13 @@ using pureT=Function; return result; } + friend std::vector multiply(const std::vector& other, const real_function_3d f, + const std::array& v1) { + std::vector result; + for (auto& o : other) result.push_back(multiply(o,f,v1)); + return result; + } + /// multiplication with a 2-particle function CCPairFunction operator*(const std::shared_ptr op) { CCPairFunction result=copy(*this); @@ -541,7 +548,7 @@ using pureT=Function; for (auto& b : vb) { double tmp=a.inner_internal(b,R2); double wall1=cpu_time(); -// print("result from inner",a.name(true),b.name(),tmp,wall1-wall0,"s"); + print("result from inner",a.name(true),b.name(),tmp,wall1-wall0,"s"); wall0=wall1; result+=tmp; } diff --git a/src/madness/chem/mp2.cc b/src/madness/chem/mp2.cc index 80db26bd159..a8adddfe3b4 100644 --- a/src/madness/chem/mp2.cc +++ b/src/madness/chem/mp2.cc @@ -322,12 +322,73 @@ double MP2::mp3() const { } CCTimer t3(world,"MP3"); + + // compute the term + madness::Pairs gij; + + for (int i = param.freeze(); i < hf->nocc(); ++i) { + for (int j = i; j < hf->nocc(); ++j) { + gij.insert(i,j,(*g12)(hf->nemo(i)*hf->R2orbital(j))); + } + } // compute the MP3 energy + double term1=0.0; for (int i = param.freeze(); i < hf->nocc(); ++i) { for (int j = i; j < hf->nocc(); ++j) { - auto bra=g12*clusterfunctions(i,j); - double energy2=inner(bra,clusterfunctions(i,j)); - print("MP3 energy: term1",energy2); + auto bra=clusterfunctions(i,j); + bra=multiply(bra,hf->nemo_ptr->ncf->square(),{0,1,2}); + bra=multiply(bra,hf->nemo_ptr->ncf->square(),{3,4,5}); + double tmp1=inner(bra,g12*clusterfunctions(i,j)); + double tmp2=inner(bra,g12*clusterfunctions(j,i)); + double fac= (i==j) ? 0.5 : 1.0; + double tmp=fac * (4.0*tmp1 - 2.0*tmp2); + print("MP3 energy: term1",i,j,tmp); + term1+=tmp; + } + } + double term2=0.0; + for (int i = param.freeze(); i < hf->nocc(); ++i) { + for (int j = param.freeze(); j < hf->nocc(); ++j) { + auto bra_ij=multiply(clusterfunctions(i,j),hf->nemo_ptr->ncf->square(),{0,1,2}); + bra_ij=multiply(bra_ij,hf->nemo_ptr->ncf->square(),{3,4,5}); + double tmp=0.0; + for (int k=param.freeze(); knocc(); ++k) { + auto tau_ij_gik = multiply(bra_ij,gij(i,k),{3,4,5}); + auto tau_ij_gjk = multiply(bra_ij,gij(j,k),{3,4,5}); + + double tmp1=2.0*inner(tau_ij_gik,clusterfunctions(k,j)) + - inner(tau_ij_gik,clusterfunctions(j,k)) + +2.0* inner(tau_ij_gjk,clusterfunctions(i,k)) + - inner(tau_ij_gjk,clusterfunctions(k,i)); + tmp-=2.0*tmp1; + } + print("mp3 energy: term2",i,j,tmp); + term2+=tmp; + } + } + double term3=0.0; + for (int i = param.freeze(); i < hf->nocc(); ++i) { + for (int j = param.freeze(); j < hf->nocc(); ++j) { + double tmp=0.0; + for (int k=param.freeze(); knocc(); ++k) { + for (int l=param.freeze(); lnocc(); ++l) { + auto bra = clusterfunctions(i,k); + bra=multiply(bra,hf->nemo_ptr->ncf->square(),{0,1,2}); + bra=multiply(bra,hf->nemo_ptr->ncf->square(),{3,4,5}); + double ovlp1=inner(bra,clusterfunctions(j,l)); + double ovlp2=inner(bra,clusterfunctions(l,j)); + auto ket_i=hf->nemo(i); + auto ket_k=hf->nemo(k); + auto bra_j=hf->R2orbital(j); + auto bra_l=hf->R2orbital(l); + + double g_jlik=inner(bra_j*ket_i, (*g12)(bra_l*ket_k)); + double g_jlki=inner(bra_j*ket_k, (*g12)(bra_l*ket_i)); + tmp+=(2.0*ovlp1 - ovlp2)*g_jlik; + } + } + print("mp3 energy: term3",i,j,tmp); + term3+=tmp; } } t3.print(); From 43689a5429329725e28a6645370f01ae30f346af Mon Sep 17 00:00:00 2001 From: fbischoff Date: Thu, 2 Mar 2023 23:05:43 +0100 Subject: [PATCH 018/109] before terms G, I, H, J --- src/madness/chem/mp2.cc | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/madness/chem/mp2.cc b/src/madness/chem/mp2.cc index a8adddfe3b4..0b12f484790 100644 --- a/src/madness/chem/mp2.cc +++ b/src/madness/chem/mp2.cc @@ -285,7 +285,8 @@ double MP2::value(const Tensor& x) { double MP2::mp3() const { - Pairs> clusterfunctions; + typedef std::vector ClusterFunction; + Pairs clusterfunctions; double mp3_energy=0.0; CCTimer t1(world,"make pairs"); // load converged MP1 wave functions @@ -342,15 +343,37 @@ double MP2::mp3() const { double tmp2=inner(bra,g12*clusterfunctions(j,i)); double fac= (i==j) ? 0.5 : 1.0; double tmp=fac * (4.0*tmp1 - 2.0*tmp2); - print("MP3 energy: term1",i,j,tmp); + print("mp3 energy: term1",i,j,tmp); term1+=tmp; } } + + // compute intermediates for terms G, I, H, and J + const auto R2=hf->nemo_ptr->ncf->square(); + // \sum_j tau_ij(1,2) * phi_j(2) + std::vector tau_i_jj(hf->nocc()-param.freeze()); + // \sum_j tau_ij(1,2) * phi_j(1) + std::vector tau_ij_j; + for (int i = param.freeze(); i < hf->nocc(); ++i) { + for (int j = param.freeze(); j < hf->nocc(); ++j) { + auto tmp1=multiply(clusterfunctions(i,j),R2,{0,1,2}); + auto tmp2=multiply(tmp1,hf->R2orbital(j),{3,4,5}); + for (auto& t : tmp2) tau_i_jj[i].push_back(t); + + auto tmp3=multiply(clusterfunctions(i,j),R2,{3,4,5}); + auto tmp4=multiply(tmp3,hf->R2orbital(j),{0,1,2}); + for (auto& t : tmp4) tau_i_jj[i].push_back(t); + } + } + double term2=0.0; for (int i = param.freeze(); i < hf->nocc(); ++i) { for (int j = param.freeze(); j < hf->nocc(); ++j) { auto bra_ij=multiply(clusterfunctions(i,j),hf->nemo_ptr->ncf->square(),{0,1,2}); bra_ij=multiply(bra_ij,hf->nemo_ptr->ncf->square(),{3,4,5}); + + + double tmp=0.0; for (int k=param.freeze(); knocc(); ++k) { auto tau_ij_gik = multiply(bra_ij,gij(i,k),{3,4,5}); @@ -366,6 +389,7 @@ double MP2::mp3() const { term2+=tmp; } } + double term3=0.0; for (int i = param.freeze(); i < hf->nocc(); ++i) { for (int j = param.freeze(); j < hf->nocc(); ++j) { @@ -392,6 +416,7 @@ double MP2::mp3() const { } } t3.print(); + mp3_energy=term1+term2+term3; return mp3_energy; From 410ffe63182bcba1248b681dd9c4775004ea0b93 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Tue, 14 Mar 2023 11:49:47 +0100 Subject: [PATCH 019/109] faster inner product with on-demand functions --- src/madness/chem/mp2.cc | 41 +++-- src/madness/chem/test_ccpairfunction.cc | 2 +- src/madness/mra/funcimpl.h | 226 +++++++++++++++++------- src/madness/mra/mra.h | 32 ++-- src/madness/mra/mraimpl.h | 19 +- src/madness/tensor/gentensor.h | 4 +- src/madness/tensor/lowranktensor.h | 5 +- 7 files changed, 218 insertions(+), 111 deletions(-) diff --git a/src/madness/chem/mp2.cc b/src/madness/chem/mp2.cc index 0b12f484790..26fe8d98548 100644 --- a/src/madness/chem/mp2.cc +++ b/src/madness/chem/mp2.cc @@ -293,14 +293,20 @@ double MP2::mp3() const { for (int i = param.freeze(); i < hf->nocc(); ++i) { for (int j = i; j < hf->nocc(); ++j) { // pairs(i, j) = make_pair(i, j); // initialize - clusterfunctions(i,j).push_back(CCPairFunction(pairs(i,j).function)); + ClusterFunction tmp; + tmp.push_back(CCPairFunction(pairs(i,j).function)); CCPairFunction ij(hf->nemo(i),hf->nemo(j)); CCConvolutionOperator::Parameters cparam; cparam.thresh_op*=0.1; auto f12=CCConvolutionOperatorPtr(world,OT_F12,cparam); auto vfij=Q12(std::vector({f12*ij})); - for (auto& p : vfij) clusterfunctions(i,j).push_back(p); + for (auto& p : vfij) tmp.push_back(p); + + tmp=multiply(tmp,hf->nemo_ptr->ncf->function(),{0,1,2}); + tmp=multiply(tmp,hf->nemo_ptr->ncf->function(),{3,4,5}); + clusterfunctions(i,j)=tmp; + } } t1.print(); @@ -310,7 +316,7 @@ double MP2::mp3() const { auto g12=CCConvolutionOperatorPtr(world,OT_G12,cparam); for (int i = param.freeze(); i < hf->nocc(); ++i) { for (int j = i; j < hf->nocc(); ++j) { - auto bra=g12*CCPairFunction(hf->R2orbital(i),hf->R2orbital(j)); + auto bra=g12*CCPairFunction(hf->orbital(i),hf->orbital(j)); double energy1=inner(bra,clusterfunctions(i,j).front()); double energy=energy1+pairs(i,j).ij_gQf_ij; print("MP2 energy: gQf, u",pairs(i,j).ij_gQf_ij,energy1,energy); @@ -337,8 +343,6 @@ double MP2::mp3() const { for (int i = param.freeze(); i < hf->nocc(); ++i) { for (int j = i; j < hf->nocc(); ++j) { auto bra=clusterfunctions(i,j); - bra=multiply(bra,hf->nemo_ptr->ncf->square(),{0,1,2}); - bra=multiply(bra,hf->nemo_ptr->ncf->square(),{3,4,5}); double tmp1=inner(bra,g12*clusterfunctions(i,j)); double tmp2=inner(bra,g12*clusterfunctions(j,i)); double fac= (i==j) ? 0.5 : 1.0; @@ -349,30 +353,37 @@ double MP2::mp3() const { } // compute intermediates for terms G, I, H, and J - const auto R2=hf->nemo_ptr->ncf->square(); + // \sum_j tau_ij(1,2) * phi_j(2) std::vector tau_i_jj(hf->nocc()-param.freeze()); // \sum_j tau_ij(1,2) * phi_j(1) std::vector tau_ij_j; for (int i = param.freeze(); i < hf->nocc(); ++i) { for (int j = param.freeze(); j < hf->nocc(); ++j) { - auto tmp1=multiply(clusterfunctions(i,j),R2,{0,1,2}); - auto tmp2=multiply(tmp1,hf->R2orbital(j),{3,4,5}); + auto tmp2=multiply(clusterfunctions(i,j),hf->orbital(j),{3,4,5}); for (auto& t : tmp2) tau_i_jj[i].push_back(t); - auto tmp3=multiply(clusterfunctions(i,j),R2,{3,4,5}); - auto tmp4=multiply(tmp3,hf->R2orbital(j),{0,1,2}); + auto tmp4=multiply(clusterfunctions(i,j),hf->orbital(j),{0,1,2}); for (auto& t : tmp4) tau_i_jj[i].push_back(t); } } + // terms G, I, H, J of Bartlett/Silver 1975 + double term2a=0.0; + for (int i = param.freeze(); i < hf->nocc(); ++i) { + double G=inner(tau_i_jj[i],g12*tau_i_jj[i]); + double I=inner(tau_i_jj[i],g12*tau_ij_j[i]); + double H=inner(tau_ij_j[i],g12*tau_i_jj[i]); + double J=inner(tau_ij_j[i],g12*tau_ij_j[i]); + double tmp = (8.0 *G - 4.0*I + 2.0* H - 4.0*J); + print("mp3 energy: term2",i,tmp); + term2a+=tmp; + } + double term2=0.0; for (int i = param.freeze(); i < hf->nocc(); ++i) { for (int j = param.freeze(); j < hf->nocc(); ++j) { - auto bra_ij=multiply(clusterfunctions(i,j),hf->nemo_ptr->ncf->square(),{0,1,2}); - bra_ij=multiply(bra_ij,hf->nemo_ptr->ncf->square(),{3,4,5}); - - + auto bra_ij=clusterfunctions(i,j); double tmp=0.0; for (int k=param.freeze(); knocc(); ++k) { @@ -397,8 +408,6 @@ double MP2::mp3() const { for (int k=param.freeze(); knocc(); ++k) { for (int l=param.freeze(); lnocc(); ++l) { auto bra = clusterfunctions(i,k); - bra=multiply(bra,hf->nemo_ptr->ncf->square(),{0,1,2}); - bra=multiply(bra,hf->nemo_ptr->ncf->square(),{3,4,5}); double ovlp1=inner(bra,clusterfunctions(j,l)); double ovlp2=inner(bra,clusterfunctions(l,j)); auto ket_i=hf->nemo(i); diff --git a/src/madness/chem/test_ccpairfunction.cc b/src/madness/chem/test_ccpairfunction.cc index 7c682208aa3..35865505bbc 100644 --- a/src/madness/chem/test_ccpairfunction.cc +++ b/src/madness/chem/test_ccpairfunction.cc @@ -350,7 +350,7 @@ int test_inner(World& world, std::shared_ptr ncf, cons t1.checkpoint(good,bra.name(true)+ket.name()); } } - return (t1.get_final_success()) ? 0 : 1; + return t1.end(); } diff --git a/src/madness/mra/funcimpl.h b/src/madness/mra/funcimpl.h index 3a5f8dc97f6..a5706b284e6 100644 --- a/src/madness/mra/funcimpl.h +++ b/src/madness/mra/funcimpl.h @@ -893,6 +893,7 @@ namespace madness { private: typedef WorldObject< FunctionImpl > woT; ///< Base class world object type public: + typedef T typeT; typedef FunctionImpl implT; ///< Type of this class (implementation) typedef std::shared_ptr< FunctionImpl > pimplT; ///< pointer to this class typedef Tensor tensorT; ///< Type of tensor for anything but to hold coeffs @@ -3235,11 +3236,11 @@ namespace madness { /// /// k=number of wavelets, so k=5 means max order is 4, so max exactly /// representable squarable polynomial is of order 2. - void tnorm(const tensorT& t, double* lo, double* hi) const; + void static tnorm(const tensorT& t, double* lo, double* hi); - void tnorm(const GenTensor& t, double* lo, double* hi) const; + void static tnorm(const GenTensor& t, double* lo, double* hi); - void tnorm(const SVDTensor& t, double* lo, double* hi, const int particle) const; + void static tnorm(const SVDTensor& t, double* lo, double* hi, const int particle); // This invoked if node has not been autorefined void do_square_inplace(const keyT& key); @@ -3736,69 +3737,63 @@ namespace madness { + /// pointwise multiplication of two tensors, returns result and estimates error + + /// provide one of the two factors upon construction, the other factor upon operator() call. + /// + /// error is estimated by oversampling: pointwise multiplication will result in a coefficient + /// tensor of order 2k, estimate the error through the norm of the k+1 contribution + /// + /// error does not account for inaccurate representation of the input tensors! + /// U need to compute that somewhere else! template struct pointwise_multiplier { - const implT* impl; - const FunctionImpl* gimpl; coeffT val_lhs, coeff_lhs; + long oversampling=1; double error=0.0; double lo=0.0, hi=0.0, lo1=0.0, hi1=0.0, lo2=0.0, hi2=0.0; - pointwise_multiplier() :gimpl(0), impl(0) {} - pointwise_multiplier(const Key key, const coeffT& clhs, implT* i, const FunctionImpl* gimpl) - : impl(i), gimpl(gimpl), coeff_lhs(clhs) { - val_lhs=impl->coeffs2values(key,coeff_lhs); - error=0.0; - impl->tnorm(coeff_lhs,&lo,&hi); - gimpl->tnorm(coeff_lhs.get_svdtensor(),&lo1,&hi1,1); - gimpl->tnorm(coeff_lhs.get_svdtensor(),&lo2,&hi2,2); - } - - pointwise_multiplier(const Key key, const coeffT& clhs, implT* i) - : impl(i), gimpl(0), coeff_lhs(clhs) { - val_lhs=impl->coeffs2values(key,coeff_lhs); + pointwise_multiplier() {} + pointwise_multiplier(const Key key, const coeffT& clhs) : coeff_lhs(clhs) { + auto fcf=FunctionCommonFunctionality(coeff_lhs.dim(0)); + val_lhs=fcf.coeffs2values(key,coeff_lhs); error=0.0; - impl->tnorm(coeff_lhs,&lo,&hi); - } - - /// multiply values of rhs and lhs, result on rhs, rhs and lhs are of the same dimensions - coeffT operator()(const Key key, const coeffT& coeff_rhs) { - double rlo, rhi; - impl->tnorm(coeff_rhs,&rlo,&rhi); - error = hi*rlo + rhi*lo + rhi*hi; - coeffT val_rhs=impl->coeffs2values(key, coeff_rhs); - val_rhs.emul(val_lhs); - return impl->values2coeffs(key,val_rhs); - + implT::tnorm(coeff_lhs,&lo,&hi); + if (coeff_lhs.is_svd_tensor()) { + FunctionImpl::tnorm(coeff_lhs.get_svdtensor(),&lo1,&hi1,1); + FunctionImpl::tnorm(coeff_lhs.get_svdtensor(),&lo2,&hi2,2); + } } /// multiply values of rhs and lhs, result on rhs, rhs and lhs are of the same dimensions tensorT operator()(const Key key, const tensorT& coeff_rhs) { MADNESS_ASSERT(coeff_rhs.dim(0)==coeff_lhs.dim(0)); + auto fcf=FunctionCommonFunctionality(coeff_lhs.dim(0)); // the tnorm estimate is not tight enough to be efficient, better use oversampling bool use_tnorm=false; if (use_tnorm) { double rlo, rhi; - impl->tnorm(coeff_rhs,&rlo,&rhi); + implT::tnorm(coeff_rhs,&rlo,&rhi); error = hi*rlo + rhi*lo + rhi*hi; - tensorT val_rhs=impl->coeffs2values(key, coeff_rhs); + tensorT val_rhs=fcf.coeffs2values(key, coeff_rhs); val_rhs.emul(val_lhs.full_tensor_copy()); - return impl->values2coeffs(key,val_rhs); + return fcf.values2coeffs(key,val_rhs); } else { // use quadrature of order k+1 - auto cdata=FunctionCommonData::get(impl->get_k()+1); // npt=k+1 - FunctionCommonFunctionality fcf_hi_npt(cdata); + auto& cdata=FunctionCommonData::get(coeff_rhs.dim(0)); // npt=k+1 + auto& cdata_npt=FunctionCommonData::get(coeff_rhs.dim(0)+oversampling); // npt=k+1 + FunctionCommonFunctionality fcf_hi_npt(cdata_npt); // coeffs2values for rhs: k -> npt=k+1 - tensorT coeff1(cdata.vk); - coeff1(impl->cdata.s0)=coeff_rhs; // s0 is smaller than vk! + tensorT coeff1(cdata_npt.vk); + coeff1(cdata.s0)=coeff_rhs; // s0 is smaller than vk! tensorT val_rhs_k1=fcf_hi_npt.coeffs2values(key,coeff1); // coeffs2values for lhs: k -> npt=k+1 - tensorT coeff_lhs_k1(cdata.vk); - coeff_lhs_k1(impl->cdata.s0)=coeff_lhs.full_tensor_copy(); + tensorT coeff_lhs_k1(cdata_npt.vk); + coeff_lhs_k1(cdata.s0)=coeff_lhs.full_tensor_copy(); tensorT val_lhs_k1=fcf_hi_npt.coeffs2values(key,coeff_lhs_k1); // multiply @@ -3808,24 +3803,25 @@ namespace madness { tensorT result1=fcf_hi_npt.values2coeffs(key,val_lhs_k1); // extract coeffs up to k - tensorT result=copy(result1(impl->cdata.s0)); - result1(impl->cdata.s0)=0.0; + tensorT result=copy(result1(cdata.s0)); + result1(cdata.s0)=0.0; error=result1.normf(); return result; - } - } /// multiply values of rhs and lhs, result on rhs, rhs and lhs are of differnet dimensions coeffT operator()(const Key key, const tensorT& coeff_rhs, const int particle) { Key key1, key2; key.break_apart(key1,key2); - MADNESS_ASSERT(gimpl); - FunctionCommonFunctionality fcf_lo(gimpl->cdata); - FunctionCommonFunctionality fcf_hi(impl->cdata); - FunctionCommonFunctionality fcf_lo_npt(gimpl->get_k()+1); - FunctionCommonFunctionality fcf_hi_npt(impl->get_k()+1); + const long k=coeff_rhs.dim(0); + auto& cdata=FunctionCommonData::get(k); + auto& cdata_lowdim=FunctionCommonData::get(k); + FunctionCommonFunctionality fcf_lo(cdata_lowdim); + FunctionCommonFunctionality fcf_hi(cdata); + FunctionCommonFunctionality fcf_lo_npt(k+oversampling); + FunctionCommonFunctionality fcf_hi_npt(k+oversampling); + // make hi-dim values from lo-dim coeff_rhs on npt grid points tensorT ones=tensorT(fcf_lo_npt.cdata.vk); @@ -3852,16 +3848,14 @@ namespace madness { coeffT result1=fcf_hi_npt.values2coeffs(key,val_lhs_npt); // extract coeffs up to k - coeffT result=copy(result1(impl->cdata.s0)); - result1(impl->cdata.s0)=0.0; + coeffT result=copy(result1(cdata.s0)); + result1(cdata.s0)=0.0; error=result1.normf(); - result.reduce_rank(impl->get_tensor_args().thresh); return result; - } template void serialize(const Archive& ar) { - ar & error & lo & lo1 & lo2 & hi & hi1& hi2 & gimpl & impl & val_lhs & coeff_lhs; + ar & error & lo & lo1 & lo2 & hi & hi1& hi2 & val_lhs & coeff_lhs; } @@ -4081,20 +4075,14 @@ namespace madness { double error=refine_error; // prepare the multiplication - pointwise_multiplier pm; - if (have_v1()) pm=pointwise_multiplier(key,coeff_ket,result,iav1.get_impl()); - else if (have_v2()) { - pm=pointwise_multiplier(key,coeff_ket,result,iav2.get_impl()); - } else { - pm=pointwise_multiplier(key,coeff_ket,result); - } + pointwise_multiplier pm(key,coeff_ket); // perform the multiplication, compute tnorm part of the total error coeffT cresult(result->cdata.vk,result->get_tensor_args()); if (have_v1()) { cresult+=pm(key,cpot1.get_tensor(),1); error+=pm.error; - } + } if (have_v2()) { cresult+=pm(key,cpot2.get_tensor(),2); error+=pm.error; @@ -5314,6 +5302,122 @@ namespace madness { (rangeT(coeffs.begin(),coeffs.end()),do_inner_local(&g, leaves_only)); } + /// compute + + /// with |ket> either explicitly given or to be constructed by outer product |ket> = |p1 p2> + /// invoked by ket + template + TENSOR_RESULT_TYPE(T,R) compute_inner_with_coeffs(const Key& key, coeffT coeff_bra, + coeffT coeff_ket, coeffT coeff_eri, coeffT coeff_v1, coeffT coeff_v2, + coeffT coeff_p1, coeffT coeff_p2) { + + typedef TENSOR_RESULT_TYPE(T,R) resultT; + // + coeffT ket = (coeff_ket.has_data()) ? coeff_ket : outer(coeff_p1,coeff_p2); + coeffT v1v2ket; + double error=0.0; + + if (coeff_v1.has_data()) { + pointwise_multiplier pm(key,coeff_ket); + v1v2ket = pm(key,coeff_v1.full_tensor(), 1); + error+=pm.error; + v1v2ket+= pm(key,coeff_v2.full_tensor(), 2); + error+=pm.error; + } else { + v1v2ket = ket; + } + + resultT result; + if (coeff_eri.has_data()) { // project bra*ket onto eri, avoid multiplication with eri + pointwise_multiplier pm(key,v1v2ket); + tensorT braket=pm(key,coeff_bra.full_tensor_copy().conj()); + result=coeff_eri.full_tensor().trace(braket); + + } else { // no eri, project ket onto bra + result=coeff_bra.full_tensor_copy().trace_conj(v1v2ket.full_tensor_copy()); + } + return result; + + } + + /// called by ket + template + TENSOR_RESULT_TYPE(T,R) compute_inner_for_key(const Key& key, const FunctionImpl* gimpl, + const GenTensor& coeff_bra) const { + typedef TENSOR_RESULT_TYPE(T,R) resultT; + typedef FunctionImpl implR; + + // get the composite functor and everything that makes up gimpl + auto func=dynamic_cast* >(gimpl->functor.get()); + MADNESS_ASSERT(func); + + // returns coefficients, empty if no functor present + auto get_coeff = [](const auto& key, const auto& impl) { + bool have_impl=impl.get(); + if (have_impl) return impl->get_coeffs().find(key).get()->second.coeff(); // waits -> ask Robert + return GenTensor::typeT>(); + }; + + Key key1,key2; + key.break_apart(key1,key2); + + // get all coefficients (apart from the eri coefficients) + auto coeff_ket=get_coeff(key,func->impl_ket); + auto coeff_v1=get_coeff(key1,func->impl_m1); + auto coeff_v2=get_coeff(key2,func->impl_m2); + auto coeff_p1=get_coeff(key1,func->impl_p1); + auto coeff_p2=get_coeff(key2,func->impl_p2); + + // make eri coefficients + coeffT coeff_eri; + if (func->impl_eri) { + MADNESS_CHECK(func->impl_eri->get_functor()->provides_coeff()); + coeff_eri=func->impl_eri->get_functor()->coeff(key).full_tensor(); + } + + Future result=woT::task(gimpl->get_coeffs().owner(key), &implT:: template compute_inner_with_coeffs, key, + coeff_bra, coeff_ket, coeff_eri, coeff_v1, coeff_v2, coeff_p1, coeff_p2); + return result; + } + + + /// Returns the inner product of this with function g constructed on-the-fly + + /// handles compressed and redundant form + template + TENSOR_RESULT_TYPE(T,R) inner_local_on_demand(const FunctionImpl& gimpl) const { + PROFILE_MEMBER_FUNC(FunctionImpl); + typedef TENSOR_RESULT_TYPE(T,R) resultT; + typedef FunctionImpl implR; + + MADNESS_ASSERT(this->is_reconstructed()); + + + long nsum=0; + for (const auto& c : coeffs) if (c.second.has_coeff()) nsum++; + std::vector< Future > sum = future_vector_factory(nsum); + + long isum=0; + for (const auto& c : coeffs) { + const keyT& key=c.first; + const nodeT& fnode = c.second; + if (fnode.has_coeff()) { + auto bra_coeff = fnode.coeff(); + sum[isum] = woT::task(gimpl.get_coeffs().owner(key), &implR:: template compute_inner_for_key, key, &gimpl, bra_coeff); + isum++; + } + } + auto accumulate = [&sum]() { + resultT result=0.0; + for (auto& s : sum) result+=s.get(); + return result; + }; + auto result=accumulate(); +// Future result=gimpl.get_coeffs().task(key0(),&accumulate); + return result; + + } + /// Type of the entry in the map returned by make_key_vec_map typedef std::vector< std::pair > mapvecT; diff --git a/src/madness/mra/mra.h b/src/madness/mra/mra.h index 6a52c878986..44198030e7d 100644 --- a/src/madness/mra/mra.h +++ b/src/madness/mra/mra.h @@ -1353,29 +1353,23 @@ namespace madness { /// g is constructed with an implicit multiplication, e.g. /// result = , with g = 1/r12 | gg> /// @param[in] g on-demand function - template - TENSOR_RESULT_TYPE(T,R) inner_on_demand(const Function& g) const { - MADNESS_ASSERT(g.is_on_demand() and (not this->is_on_demand())); - + template + TENSOR_RESULT_TYPE(T, R) inner_on_demand(const Function& g) const { + MADNESS_ASSERT(g.is_on_demand() and (not this->is_on_demand())); - // save for later, will be removed by make_Vphi - std::shared_ptr< FunctionFunctorInterface > func=g.get_impl()->get_functor(); - //leaf_op fnode_is_leaf(this->get_impl().get()); - Leaf_op_other fnode_is_leaf(this->get_impl().get()); - g.get_impl()->make_Vphi(fnode_is_leaf,true); // fence here - this->reconstruct(); + constexpr std::size_t LDIM=NDIM/2; + auto func=dynamic_cast* >(g.get_impl()->get_functor().get()); + MADNESS_ASSERT(func); + func->make_redundant(true); + this->reconstruct(); // if this == &g we don't need g to be redundant - if (VERIFY_TREE) verify_tree(); - TENSOR_RESULT_TYPE(T,R) local = impl->inner_local(*g.get_impl()); - impl->world.gop.sum(local); - impl->world.gop.fence(); + if (VERIFY_TREE) verify_tree(); - // restore original state - g.get_impl()->set_functor(func); - g.get_impl()->get_coeffs().clear(); - g.get_impl()->set_tree_state(on_demand); + TENSOR_RESULT_TYPE(T, R) local = impl->inner_local_on_demand(*g.get_impl()); + impl->world.gop.sum(local); + impl->world.gop.fence(); - return local; + return local; } /// project this on the low-dim function g: h(x) = diff --git a/src/madness/mra/mraimpl.h b/src/madness/mra/mraimpl.h index 88d14e32efc..b70b696ca9e 100644 --- a/src/madness/mra/mraimpl.h +++ b/src/madness/mra/mraimpl.h @@ -961,6 +961,11 @@ namespace madness { /// Returns true if this block of coeffs needs autorefining template bool FunctionImpl::autorefine_square_test(const keyT& key, const nodeT& t) const { + // Chosen approach looks stupid but it is more accurate + // than the simple approach of summing everything and + // subtracting off the low-order stuff to get the high + // order (assuming the high-order stuff is small relative + // to the low-order) double lo, hi; tnorm(t.coeff().full_tensor_copy(), &lo, &hi); double test = 2*lo*hi + hi*hi; @@ -2982,13 +2987,9 @@ namespace madness { template - void FunctionImpl::tnorm(const tensorT& t, double* lo, double* hi) const { + void FunctionImpl::tnorm(const tensorT& t, double* lo, double* hi) { //PROFILE_MEMBER_FUNC(FunctionImpl); // Too fine grain for routine profiling - // Chosen approach looks stupid but it is more accurate - // than the simple approach of summing everything and - // subtracting off the low-order stuff to get the high - // order (assuming the high-order stuff is small relative - // to the low-order) + auto& cdata=FunctionCommonData::get(t.dim(0)); tensorT work = copy(t); tensorT tlo = work(cdata.sh); *lo = tlo.normf(); @@ -2997,7 +2998,8 @@ namespace madness { } template - void FunctionImpl::tnorm(const GenTensor& t, double* lo, double* hi) const { + void FunctionImpl::tnorm(const GenTensor& t, double* lo, double* hi) { + auto& cdata=FunctionCommonData::get(t.dim(0)); coeffT shalf=t(cdata.sh); *lo=shalf.normf(); coeffT sfull=copy(t); @@ -3007,9 +3009,10 @@ namespace madness { template void FunctionImpl::tnorm(const SVDTensor& t, double* lo, double* hi, - const int particle) const { + const int particle) { *lo=0.0; *hi=0.0; + auto& cdata=FunctionCommonData::get(t.dim(0)); if (t.rank()==0) return; const tensorT vec=t.flat_vector(particle-1); for (long i=0; isize()>0;}; bool has_data() const {return this->size()>0;}; diff --git a/src/madness/tensor/lowranktensor.h b/src/madness/tensor/lowranktensor.h index 1618038332d..d56be254275 100644 --- a/src/madness/tensor/lowranktensor.h +++ b/src/madness/tensor/lowranktensor.h @@ -695,9 +695,6 @@ class GenTensor { friend GenTensor transform_dir( const GenTensor& t, const Tensor& c, const int axis); - template - friend GenTensor outer( - const GenTensor& t1, const GenTensor& t2); std::string what_am_i() const { TensorType tt; @@ -815,7 +812,7 @@ void change_tensor_type(GenTensor& t, const TensorArgs& targs) { /// all other combinations are currently invalid. template GenTensor outer(const GenTensor& t1, - const GenTensor& t2, const TensorArgs final_tensor_args) { + const GenTensor& t2, const TensorArgs final_tensor_args=TensorArgs(-1.0,TT_2D)) { typedef TENSOR_RESULT_TYPE(T,Q) resultT; From 0b7deb31efd88a82c21c5c6174386cc26cf5d46d Mon Sep 17 00:00:00 2001 From: fbischoff Date: Tue, 14 Mar 2023 13:49:47 +0100 Subject: [PATCH 020/109] fixed tests --- src/madness/mra/funcimpl.h | 19 ++++++++++++++++--- src/madness/mra/gfit.h | 35 +++++++++++++++++++---------------- src/madness/mra/mra.h | 2 +- 3 files changed, 36 insertions(+), 20 deletions(-) diff --git a/src/madness/mra/funcimpl.h b/src/madness/mra/funcimpl.h index a5706b284e6..e0569a58532 100644 --- a/src/madness/mra/funcimpl.h +++ b/src/madness/mra/funcimpl.h @@ -5351,11 +5351,24 @@ namespace madness { auto func=dynamic_cast* >(gimpl->functor.get()); MADNESS_ASSERT(func); + + auto find_valid_parent = [](auto& key, auto& impl, auto&& find_valid_parent) { + if (impl->get_coeffs().probe(key)) return key; + auto parentkey=key.parent(); + return find_valid_parent(parentkey, impl, find_valid_parent); + }; + // returns coefficients, empty if no functor present - auto get_coeff = [](const auto& key, const auto& impl) { + auto get_coeff = [&find_valid_parent](const auto& key, const auto& impl) { bool have_impl=impl.get(); - if (have_impl) return impl->get_coeffs().find(key).get()->second.coeff(); // waits -> ask Robert - return GenTensor::typeT>(); + if (have_impl) { + auto parentkey = find_valid_parent(key, impl, find_valid_parent); + auto parentcoeff=impl->get_coeffs().find(parentkey).get()->second.coeff(); + auto coeff=impl->parent_to_child(parentcoeff, parentkey, key); + return coeff; + } else { + return GenTensor::typeT>(); + } }; Key key1,key2; diff --git a/src/madness/mra/gfit.h b/src/madness/mra/gfit.h index a2110e9dc44..cba73a8633a 100644 --- a/src/madness/mra/gfit.h +++ b/src/madness/mra/gfit.h @@ -79,7 +79,8 @@ class GFit { /// @parma[in] prnt print level static GFit BSHFit(double mu, double lo, double hi, double eps, bool prnt=false) { GFit fit; - if (NDIM==3) bsh_fit(mu,lo,hi,eps,fit.coeffs_,fit.exponents_,prnt,true); + bool fix_interval=false; + if (NDIM==3) bsh_fit(mu,lo,hi,eps,fit.coeffs_,fit.exponents_,prnt,fix_interval); else bsh_fit_ndim(NDIM,mu,lo,hi,eps,fit.coeffs_,fit.exponents_,prnt); if (prnt) { @@ -144,9 +145,10 @@ class GFit { GFit bshfit,coulombfit; eps*=0.1; lo*=0.1; - bool restrict_interval=false; - bsh_fit(gamma,lo,hi,eps,bshfit.coeffs_,bshfit.exponents_,false,restrict_interval); - bsh_fit(0.0,lo,hi,eps,coulombfit.coeffs_,coulombfit.exponents_,false,restrict_interval); +// bool restrict_interval=false; + bool fix_interval=true; + bsh_fit(gamma,lo,hi,eps,bshfit.coeffs_,bshfit.exponents_,false,fix_interval); + bsh_fit(0.0,lo,hi,eps,coulombfit.coeffs_,coulombfit.exponents_,false,fix_interval); // check the exponents are identical auto diffexponents=(coulombfit.exponents() - bshfit.exponents()); MADNESS_CHECK(diffexponents.normf()/coulombfit.exponents().size()<1.e-12); @@ -177,10 +179,11 @@ class GFit { GFit bshfit,coulombfit,bsh2fit; eps*=0.1; lo*=0.1; - bool restrict_interval=false; - bsh_fit(gamma,lo,hi,eps,bshfit.coeffs_,bshfit.exponents_,false,restrict_interval); - bsh_fit(2.0*gamma,lo,hi,eps,bsh2fit.coeffs_,bsh2fit.exponents_,false,restrict_interval); - bsh_fit(0.0,lo,hi,eps,coulombfit.coeffs_,coulombfit.exponents_,false,restrict_interval); +// bool restrict_interval=false; + bool fix_interval=true; + bsh_fit(gamma,lo,hi,eps,bshfit.coeffs_,bshfit.exponents_,false,fix_interval); + bsh_fit(2.0*gamma,lo,hi,eps,bsh2fit.coeffs_,bsh2fit.exponents_,false,fix_interval); + bsh_fit(0.0,lo,hi,eps,coulombfit.coeffs_,coulombfit.exponents_,false,fix_interval); // check the exponents are identical auto diffexponents=(coulombfit.exponents() - bshfit.exponents()); @@ -330,14 +333,14 @@ class GFit { /// Multiresolution Quantum Chemistry in Multiwavelet Bases, /// Lecture Notes in Computer Science, vol. 2660, p. 707, 2003. static void bsh_fit(double mu, double lo, double hi, double eps, - Tensor& pcoeff, Tensor& pexpnt, bool prnt, bool use_mu_for_restricting_interval) { + Tensor& pcoeff, Tensor& pexpnt, bool prnt, bool fix_interval) { if (mu < 0.0) throw "cannot handle negative mu in bsh_fit"; - bool restrict_interval=(mu>0) and use_mu_for_restricting_interval; +// bool restrict_interval=(mu>0) and use_mu_for_restricting_interval; -// if (mu > 0) { - if (restrict_interval) { + if ((mu > 0) and (not fix_interval)) { +// if (restrict_interval) { // Restrict hi according to the exponential decay double r = -log(4*constants::pi*0.01*eps); r = -log(r * 4*constants::pi*0.01*eps); @@ -355,8 +358,8 @@ class GFit { else if (eps >= 1e-12) TT = 26; else TT = 30; -// if (mu > 0) { - if (restrict_interval) { + if ((mu > 0) and (not fix_interval)) { +// if (restrict_interval) { slo = -0.5*log(4.0*TT/(mu*mu)); } else { @@ -414,8 +417,8 @@ class GFit { // end points ... if this error is less than the desired // precision, can discard the diffuse gaussian. -// if (mu == 0.0) { - if (restrict_interval) { + if ((mu == 0.0) and (not fix_interval)) { +// if (restrict_interval) { GFit::prune_small_coefficients(eps,lo,hi,coeff,expnt); } diff --git a/src/madness/mra/mra.h b/src/madness/mra/mra.h index 44198030e7d..ee107c46b47 100644 --- a/src/madness/mra/mra.h +++ b/src/madness/mra/mra.h @@ -1357,7 +1357,7 @@ namespace madness { TENSOR_RESULT_TYPE(T, R) inner_on_demand(const Function& g) const { MADNESS_ASSERT(g.is_on_demand() and (not this->is_on_demand())); - constexpr std::size_t LDIM=NDIM/2; + constexpr std::size_t LDIM=std::max(NDIM/2,std::size_t(1)); auto func=dynamic_cast* >(g.get_impl()->get_functor().get()); MADNESS_ASSERT(func); func->make_redundant(true); From b653c3cf0f231f3e2c7baa145abbf36d9c076644 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Tue, 14 Mar 2023 16:23:00 +0100 Subject: [PATCH 021/109] fixed tests --- src/madness/tensor/gentensor.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/madness/tensor/gentensor.h b/src/madness/tensor/gentensor.h index 40dae9af541..f80d4c68593 100644 --- a/src/madness/tensor/gentensor.h +++ b/src/madness/tensor/gentensor.h @@ -203,8 +203,8 @@ namespace madness { GenTensor get_tensor() const {return *this;} GenTensor& get_tensor() {return *this;} - Tensor full_tensor_copy() const {return copy(*this);} - Tensor full_tensor_copy() {return copy(*this);} + Tensor full_tensor_copy() const {return copy(*this);} + Tensor full_tensor_copy() {return copy(*this);} bool is_assigned() const {return this->size()>0;}; bool has_data() const {return this->size()>0;}; From 7d1d4a248acfc9f4a68d6f2051511960f64dd62c Mon Sep 17 00:00:00 2001 From: fbischoff Date: Mon, 10 Apr 2023 23:19:24 +0200 Subject: [PATCH 022/109] towards low-rank representation of functions via random projections --- src/apps/mp2/mp2.cc | 1 + src/madness/chem/MolecularOrbitals.h | 2 +- src/madness/chem/SCF.cc | 4 +- src/madness/chem/ccpairfunction.cc | 66 +++- src/madness/chem/ccpairfunction.h | 25 +- src/madness/chem/molecularbasis.cc | 8 +- src/madness/chem/mp2.cc | 90 ++++-- src/madness/chem/test_ccpairfunction.cc | 362 +++++++++++++++++++++- src/madness/mra/funcimpl.h | 198 ++++++------ src/madness/mra/funcplot.h | 2 +- src/madness/mra/function_interface.h | 10 + src/madness/mra/mra.h | 1 + src/madness/mra/operator.h | 18 ++ src/madness/mra/testinnerext.cc | 30 ++ src/madness/world/archive.h | 2 +- src/madness/world/parallel_archive.h | 6 +- src/madness/world/redirectio.cc | 4 +- src/madness/world/text_fstream_archive.cc | 6 +- src/madness/world/text_fstream_archive.h | 8 +- src/madness/world/thread.h | 2 +- 20 files changed, 671 insertions(+), 174 deletions(-) diff --git a/src/apps/mp2/mp2.cc b/src/apps/mp2/mp2.cc index 7ba639380d9..bfc9c3f2286 100644 --- a/src/apps/mp2/mp2.cc +++ b/src/apps/mp2/mp2.cc @@ -80,6 +80,7 @@ int main(int argc, char** argv) { else { const double hf_energy=mp2.get_hf().value(); const double mp2_energy=mp2.value(); +// const double mp2_energy=0.0; if(world.rank() == 0) { printf("final hf/mp2/total energy %12.8f %12.8f %12.8f\n", hf_energy,mp2_energy,hf_energy+mp2_energy); diff --git a/src/madness/chem/MolecularOrbitals.h b/src/madness/chem/MolecularOrbitals.h index 173239ee989..7ceae5fc646 100644 --- a/src/madness/chem/MolecularOrbitals.h +++ b/src/madness/chem/MolecularOrbitals.h @@ -180,7 +180,7 @@ class MolecularOrbitals : public archive::ParallelSerializableObject { for (int i=mo.size()-1; i>=0; --i) { // double n=get_mos()[i].norm2(); char buf[1024]; - sprintf(buf,"%5d %10s %12.8f %6.2f %8d", i, irreps[i].c_str(),get_eps()[i], + snprintf(buf,1024,"%5d %10s %12.8f %6.2f %8d", i, irreps[i].c_str(),get_eps()[i], get_occ()[i],get_localize_sets()[i]); cout << std::string(buf) <("plotlo"); i <= param.get("plothi"); ++i) { char fname[256]; if (i < param.nalpha()) { - sprintf(fname, "amo-%5.5d.dx", i); + snprintf(fname,256, "amo-%5.5d.dx", i); plotdx(amo[i], fname, param.plot_cell(), npt, true); } if (!param.spin_restricted() && i < param.nbeta()) { - sprintf(fname, "bmo-%5.5d.dx", i); + snprintf(fname,256, "bmo-%5.5d.dx", i); plotdx(bmo[i], fname, param.plot_cell(), npt, true); } } diff --git a/src/madness/chem/ccpairfunction.cc b/src/madness/chem/ccpairfunction.cc index aecf8da494c..dc5f8eb7641 100644 --- a/src/madness/chem/ccpairfunction.cc +++ b/src/madness/chem/ccpairfunction.cc @@ -5,6 +5,7 @@ #include #include #include +#include using namespace madness; @@ -58,6 +59,23 @@ void CCPairFunction::convert_to_pure_no_op_inplace() { component.reset(new TwoBodyFunctionPureComponent(result)); }; +std::vector consolidate(const std::vector& other) { + + std::vector result; + std::vector all_pure; + for (auto& c : other) { + if (c.is_pure_no_op()) all_pure.push_back(c.get_function()); + else result.push_back(c); + } + if (not all_pure.empty()) { + for (std::size_t i=1; i& v1) { auto a012=std::array{0,1,2}; auto a345=std::array{3,4,5}; @@ -382,11 +400,11 @@ double CCPairFunction::inner_internal(const CCPairFunction& other, const real_fu if (f1.is_pure() and f2.is_pure()) { // these are 4 combinations pure/pure pureT bra=f1.get_function(); pureT ket=f2.get_function(); - if (R2.is_initialized()) { - real_function_6d R1u = multiply(::copy(f1.pure().get_function()), ::copy(R2), 1); - real_function_6d R1R2u = multiply(R1u, ::copy(R2), 2); // R1u function now broken - bra = R1R2u; - } +// if (R2.is_initialized()) { +// real_function_6d R1u = multiply(::copy(f1.pure().get_function()), ::copy(R2), 1); +// real_function_6d R1R2u = multiply(R1u, ::copy(R2), 2); // R1u function now broken +// bra = R1R2u; +// } // include the operator(s), if any if (f1.has_operator() or f2.has_operator()) { auto ops=combine(f1.get_operator_ptr(),f2.get_operator_ptr()); @@ -395,7 +413,12 @@ double CCPairFunction::inner_internal(const CCPairFunction& other, const real_fu auto op=single_op.second; double bla=0.0; if (op.get_op()) { - real_function_6d tmp1 = CompositeFactory(world()).g12(op.get_kernel()).ket(ket); + real_function_6d tmp1; + if (R2.is_initialized()) { + tmp1= CompositeFactory(world()).g12(op.get_kernel()).ket(ket).particle1(R2).particle2(R2); + } else { + tmp1= CompositeFactory(world()).g12(op.get_kernel()).ket(ket); + } bla=fac*inner(bra,tmp1); } else { bla=fac*inner(bra,ket); @@ -585,5 +608,36 @@ std::vector apply(const ProjectorBase& projector, const std::vec return result; }; +template +std::vector apply(const SeparatedConvolution& op, const std::vector& argument) { + if (argument.size()==0) return argument; + World& world=argument.front().world(); + std::vector result; + for (const auto& arg : argument) { + if (arg.is_pure()) { + result.push_back(CCPairFunction(op(arg.get_function()))); + } else if (arg.is_op_pure()) { + auto tmp=arg.to_pure(); + result.push_back(apply(op,tmp)); + } else if (arg.is_decomposed_no_op()) { + MADNESS_CHECK(op.particle()==1 or op.particle()==2); + if (op.particle()==1) { + auto tmp= madness::apply(world,op,arg.get_a()); + result.push_back(CCPairFunction(tmp,arg.get_b())); + } else if (op.particle()==2) { + auto tmp= madness::apply(world,op,arg.get_b()); + result.push_back(CCPairFunction(arg.get_a(),tmp)); + } + } else if (arg.is_op_decomposed()) { // sucks.. + auto tmp=arg.to_pure(); + result.push_back(apply(op,tmp)); + } + } + + return result; +} + + +template std::vector apply(const SeparatedConvolution& op, const std::vector& argument); } // namespace madness \ No newline at end of file diff --git a/src/madness/chem/ccpairfunction.h b/src/madness/chem/ccpairfunction.h index 581cc0f1383..ca84233407b 100644 --- a/src/madness/chem/ccpairfunction.h +++ b/src/madness/chem/ccpairfunction.h @@ -365,6 +365,10 @@ using pureT=Function; return result; } + /// add all like functions up, return *this for chaining + friend std::vector consolidate(const std::vector& other); + + void info() const { print_size(); } World& world() const { @@ -482,6 +486,14 @@ using pureT=Function; /// can this be converted to a pure representation (depends on the operator, if present) bool is_convertible_to_pure_no_op() const; + /// out-of-place conversion to pure function + CCPairFunction to_pure() const { + auto tmp=copy(*this); + MADNESS_CHECK(tmp.is_convertible_to_pure_no_op()); + tmp.convert_to_pure_no_op_inplace(); + return tmp; + } + /// convert this into a pure hi-dim function void convert_to_pure_no_op_inplace(); @@ -540,9 +552,10 @@ using pureT=Function; return a.inner_internal(b,R2); } - friend double inner(const std::vector& va, const std::vector& vb) { + friend double inner(const std::vector& va, const std::vector& vb, + const real_function_3d R2=real_function_3d()) { double wall0=cpu_time(); - real_function_3d R2; +// real_function_3d R2; double result=0.0; for (auto& a : va) { for (auto& b : vb) { @@ -623,6 +636,14 @@ std::vector apply(const ProjectorBase& P, const std::vector +std::vector apply(const SeparatedConvolution& op, const std::vector& argument); + +/// convenience function +template +CCPairFunction apply(const SeparatedConvolution& op, const CCPairFunction& argument); + real_function_3d inner(const CCPairFunction& c, const real_function_3d& f, const std::tuple v1, const std::tuple v2={0,1,2}); diff --git a/src/madness/chem/molecularbasis.cc b/src/madness/chem/molecularbasis.cc index d18df1a3b19..994d2b59903 100644 --- a/src/madness/chem/molecularbasis.cc +++ b/src/madness/chem/molecularbasis.cc @@ -43,12 +43,12 @@ std::ostream& operator<<(std::ostream& s, const ContractedGaussianShell& c) { const std::vector& coeff = c.get_coeff(); const std::vector& expnt = c.get_expnt(); - p += sprintf(p,"%s [",tag[c.angular_momentum()]); + p += snprintf(p,32768,"%s [",tag[c.angular_momentum()]); for (int i=0; i({f12*ij})); for (auto& p : vfij) tmp.push_back(p); - tmp=multiply(tmp,hf->nemo_ptr->ncf->function(),{0,1,2}); - tmp=multiply(tmp,hf->nemo_ptr->ncf->function(),{3,4,5}); clusterfunctions(i,j)=tmp; - + print("prep pairs",t1.reset()); } } t1.print(); + auto R2 = hf->nemo_ptr->ncf->square(); + CCTimer t2(world,"recompute MP2"); // recompute MP2 energy CCConvolutionOperator::Parameters cparam; auto g12=CCConvolutionOperatorPtr(world,OT_G12,cparam); for (int i = param.freeze(); i < hf->nocc(); ++i) { for (int j = i; j < hf->nocc(); ++j) { - auto bra=g12*CCPairFunction(hf->orbital(i),hf->orbital(j)); + auto bra=g12*CCPairFunction(hf->R2orbital(i),hf->R2orbital(j)); double energy1=inner(bra,clusterfunctions(i,j).front()); double energy=energy1+pairs(i,j).ij_gQf_ij; print("MP2 energy: gQf, u",pairs(i,j).ij_gQf_ij,energy1,energy); @@ -330,7 +330,7 @@ double MP2::mp3() const { CCTimer t3(world,"MP3"); - // compute the term + // compute the term (2) madness::Pairs gij; for (int i = param.freeze(); i < hf->nocc(); ++i) { @@ -338,47 +338,72 @@ double MP2::mp3() const { gij.insert(i,j,(*g12)(hf->nemo(i)*hf->R2orbital(j))); } } + print("\n compute term1 of the MP3 energy\n"); // compute the MP3 energy double term1=0.0; - for (int i = param.freeze(); i < hf->nocc(); ++i) { - for (int j = i; j < hf->nocc(); ++j) { - auto bra=clusterfunctions(i,j); - double tmp1=inner(bra,g12*clusterfunctions(i,j)); - double tmp2=inner(bra,g12*clusterfunctions(j,i)); - double fac= (i==j) ? 0.5 : 1.0; - double tmp=fac * (4.0*tmp1 - 2.0*tmp2); - print("mp3 energy: term1",i,j,tmp); - term1+=tmp; + if (0) { + for (int i = param.freeze(); i < hf->nocc(); ++i) { + for (int j = i; j < hf->nocc(); ++j) { + auto bra = clusterfunctions(i, j); + double tmp1 = inner(bra, g12 * clusterfunctions(i, j), R2); + double tmp2 = inner(bra, g12 * clusterfunctions(j, i), R2); + double fac = (i == j) ? 0.5 : 1.0; + double tmp = fac * (4.0 * tmp1 - 2.0 * tmp2); + print("mp3 energy: term1", i, j, tmp); + term1 += tmp; + } } } + printf("MP3 energy: term1 %12.8f\n",term1); + print("time term1",t3.reset()); + // compute intermediates for terms G, I, H, and J // \sum_j tau_ij(1,2) * phi_j(2) std::vector tau_i_jj(hf->nocc()-param.freeze()); // \sum_j tau_ij(1,2) * phi_j(1) - std::vector tau_ij_j; + std::vector tau_ij_j(hf->nocc()-param.freeze()); for (int i = param.freeze(); i < hf->nocc(); ++i) { for (int j = param.freeze(); j < hf->nocc(); ++j) { - auto tmp2=multiply(clusterfunctions(i,j),hf->orbital(j),{3,4,5}); + auto tmp2=multiply(clusterfunctions(i,j),hf->R2orbital(j),{3,4,5}); for (auto& t : tmp2) tau_i_jj[i].push_back(t); - auto tmp4=multiply(clusterfunctions(i,j),hf->orbital(j),{0,1,2}); - for (auto& t : tmp4) tau_i_jj[i].push_back(t); + auto tmp4=multiply(clusterfunctions(i,j),hf->R2orbital(j),{0,1,2}); + for (auto& t : tmp4) tau_ij_j[i].push_back(t); } } + print("info on tau_i_jj and tau_ij_j"); + for (int i = param.freeze(); i < hf->nocc(); ++i) { + for (auto& c: tau_i_jj[i]) c.info(); + } + for (int i = param.freeze(); i < hf->nocc(); ++i) { + for (auto& c: tau_ij_j[i]) c.info(); + } + print("time GHIJ prep",t3.reset()); // terms G, I, H, J of Bartlett/Silver 1975 double term2a=0.0; + real_convolution_3d& g=*(g12->get_op()); + g.particle()=2; for (int i = param.freeze(); i < hf->nocc(); ++i) { - double G=inner(tau_i_jj[i],g12*tau_i_jj[i]); - double I=inner(tau_i_jj[i],g12*tau_ij_j[i]); - double H=inner(tau_ij_j[i],g12*tau_i_jj[i]); - double J=inner(tau_ij_j[i],g12*tau_ij_j[i]); + auto gtau=g(tau_i_jj[i]); + print("info on gtau_i_jj"); + for (auto& g :gtau) g.info(); + double G=inner(gtau,tau_i_jj[i],R2); + print("G",G); +// double G=inner(tau_i_jj[i],g12*tau_i_jj[i],R2); + double I=inner(tau_i_jj[i],g12*tau_ij_j[i],R2); + print("I",I); + double H=inner(tau_ij_j[i],g12*tau_i_jj[i],R2); + print("H",H); + double J=inner(tau_ij_j[i],g12*tau_ij_j[i],R2); + print("J",J); double tmp = (8.0 *G - 4.0*I + 2.0* H - 4.0*J); print("mp3 energy: term2",i,tmp); term2a+=tmp; } + print("time GHIJ ",t3.reset()); double term2=0.0; for (int i = param.freeze(); i < hf->nocc(); ++i) { @@ -390,16 +415,17 @@ double MP2::mp3() const { auto tau_ij_gik = multiply(bra_ij,gij(i,k),{3,4,5}); auto tau_ij_gjk = multiply(bra_ij,gij(j,k),{3,4,5}); - double tmp1=2.0*inner(tau_ij_gik,clusterfunctions(k,j)) - - inner(tau_ij_gik,clusterfunctions(j,k)) - +2.0* inner(tau_ij_gjk,clusterfunctions(i,k)) - - inner(tau_ij_gjk,clusterfunctions(k,i)); + double tmp1=2.0*inner(tau_ij_gik,clusterfunctions(k,j),R2) + - inner(tau_ij_gik,clusterfunctions(j,k),R2) + +2.0* inner(tau_ij_gjk,clusterfunctions(i,k),R2) + - inner(tau_ij_gjk,clusterfunctions(k,i),R2); tmp-=2.0*tmp1; } print("mp3 energy: term2",i,j,tmp); term2+=tmp; } } + print("time term2",t3.reset()); double term3=0.0; for (int i = param.freeze(); i < hf->nocc(); ++i) { @@ -408,8 +434,8 @@ double MP2::mp3() const { for (int k=param.freeze(); knocc(); ++k) { for (int l=param.freeze(); lnocc(); ++l) { auto bra = clusterfunctions(i,k); - double ovlp1=inner(bra,clusterfunctions(j,l)); - double ovlp2=inner(bra,clusterfunctions(l,j)); + double ovlp1=inner(bra,clusterfunctions(j,l),R2); + double ovlp2=inner(bra,clusterfunctions(l,j),R2); auto ket_i=hf->nemo(i); auto ket_k=hf->nemo(k); auto bra_j=hf->R2orbital(j); @@ -424,8 +450,14 @@ double MP2::mp3() const { term3+=tmp; } } + print("time term3",t3.reset()); t3.print(); - mp3_energy=term1+term2+term3; + printf("term1 %12.8f\n",term1); + printf("term2a %12.8f\n",term2a); + printf("term2 %12.8f\n",term2); + printf("term3 %12.8f\n",term3); + mp3_energy=term1+term2a+term2+term3; + printf("MP3 en %12.8f\n",mp3_energy); return mp3_energy; diff --git a/src/madness/chem/test_ccpairfunction.cc b/src/madness/chem/test_ccpairfunction.cc index 35865505bbc..e6e808bdce4 100644 --- a/src/madness/chem/test_ccpairfunction.cc +++ b/src/madness/chem/test_ccpairfunction.cc @@ -99,6 +99,289 @@ struct data { data data1; +template +class LowRank { +public: + + World& world; + std::vector> g,h; + + + LowRank(std::vector> g, std::vector> h) + : world(g.front().world()), g(g), h(h) {} + + LowRank(World& world, long n) : world(world) { + g= zero_functions_compressed(world,n); + h= zero_functions_compressed(world,n); + } + +// LowRank() =default; // Default constructor necessary for storage in vector + + LowRank(const LowRank& a) : world(a.world), g(copy(world,a.g)), h(copy(world,a.h)) {} // Copy constructor necessary + + LowRank& operator=(const LowRank& f) { // Assignment required for storage in vector + LowRank ff(f); + std::swap(ff.g,g); + std::swap(ff.h,h); + return *this; + } + + LowRank operator-(const LowRank& b) const { // Operator- necessary + return LowRank(g-b.g,h-b.h); + } + + LowRank& operator+=(const LowRank& b) { // Operator+= necessary + g+=b.g; + h+=b.h; + return *this; + } + + LowRank operator*(double a) const { // Scale by a constant necessary + return LowRank(g*a,h*a); + } + +// double get() const {return x;} +}; + +// This interface is necessary to compute inner products +template +double inner(const LowRank& a, const LowRank& b) { + World& world=a.world; + return (matrix_inner(world,a.g,b.g).emul(matrix_inner(world,a.h,b.h))).sum(); +} + + +// The default constructor for functions does not initialize +// them to any value, but the solver needs functions initialized +// to zero for which we also need the world object. +template +struct allocator1 { + World& world; + const int n; + + /// @param[in] world the world + /// @param[in] nn the number of functions in a given vector + allocator1(World& world, const int nn) : + world(world), n(nn) { + } + + /// allocate a vector of n empty functions + LowRank operator()() { + return LowRank(world,n); + } +}; + + +/// Computes the electrostatic potential due to a Gaussian charge distribution + +/// stolen from testsuite.cc +class GaussianPotential : public FunctionFunctorInterface { +public: + typedef Vector coordT; + const coordT center; + const double exponent; + const double coefficient; + + GaussianPotential(const coordT& center, double expnt, double coefficient) + : center(center) + , exponent(sqrt(expnt)) + , coefficient(coefficient*pow(constants::pi/exponent,1.5)*pow(expnt,-0.75)) {} + + double operator()(const coordT& x) const { + double sum = 00; + for (int i=0; i<3; ++i) { + double xx = center[i]-x[i]; + sum += xx*xx; + }; + double r = sqrt(sum); + if (r<1.e-4) { // correct thru order r^3 + const double sqrtpi=sqrt(constants::pi); + const double a=exponent; + return coefficient*(2.0*a/sqrtpi - 2.0*a*a*a*r*r/(3.0*sqrtpi)); + } else { + return coefficient*erf(exponent*r)/r; + } + } +}; + +template +struct randomgaussian { + Vector random_origin; + double exponent; + double radius=2; + randomgaussian(double exponent) : exponent(exponent) { + Vector ran; // [0,1] + RandomVector(NDIM,ran.data()); + random_origin=2.0*radius*ran-Vector(radius); + print("origin at ",random_origin, ", exponent",exponent); + } + double operator()(const Vector& r) const { +// return exp(-exponent*inner(r-random_origin,r-random_origin)); + return exp(-exponent*(r-random_origin).normf()); + } + +}; + +template +void orthonormalize(World& world, std::vector>& g, std::vector>& h, Tensor& s) { + /** + * |g >< h| = |g_ortho> < h | h_ortho > gg hh U s VT > g_ortho=orthonormalize_canonical(g,1.e-8); + std::vector> h_ortho=orthonormalize_canonical(h,1.e-8); + auto gg=matrix_inner(world,g_ortho,g); + auto hh=matrix_inner(world,h,h_ortho); + auto ovlp=inner(gg,hh); + Tensor U,VT; + svd(ovlp,U,s,VT); + auto V=transpose(VT); + + // truncate +// for (int i=1; i f=FunctionFactory(world).functor([&LDIM](const Vector& r) + { + Vector r1,r2; + for (int i=0; i> omega2(n); + for (long i=0; i(RandomValue()*3.0)); + omega2[i]=FunctionFactory(world).functor(randomgaussian(RandomValue()*10.0)); + } + t1.checkpoint(true,"projection 1D functions"); + + std::vector> Y(n); +// for (int i=0; i> g=orthonormalize_canonical(Y,1.e-12); + print("g.size()",g.size()); + t1.checkpoint(true,"Y orthonormalizing"); + std::vector> h(g.size()); +// for (int i=0; i s; + orthonormalize(world,g,h,s); + + + auto fapprox=s[0]*hartree_product(g[0],h[0]); + for (int i=1; i({f,fapprox,f-fapprox},"f_and_approx",std::vector({"adsf","asdf","diff"})); + t1.checkpoint(true,"plotting"); + + /* + * optimize + */ + + auto s_into_h = [&world](const Tensor& s, const auto& hvec) { + auto hs=copy(world,hvec); + for (int i=0; i> htmp(g.size()), gtmp(g.size()); + for (int j=0; j1) orthonormalize(world,g,h,s); + print("s after",s); + + if (iopt%2==0) { + fapprox=s[0]*hartree_product(g[0],h[0]); + for (int i=1; i({f,fapprox,f-fapprox},"f_and_approx_opt",std::vector({"adsf","asdf","diff"})); + t1.checkpoint(true,"plotting"); + + + + + + return t1.end(); +} + int test_constructor(World& world, std::shared_ptr ncf, const Molecule& molecule, const CCParameters& parameter) { test_output t1("CCPairFunction::constructor"); @@ -162,6 +445,49 @@ int test_constructor(World& world, std::shared_ptr ncf return t1.end(); } +int test_operator_apply(World& world, std::shared_ptr ncf, const Molecule& molecule, + const CCParameters& parameter) { + test_output t1("CCPairFunction::test_operator_apply"); +// t1.set_cout_to_terminal(); + + double exponent=1.0; // corresponds to the exponent of data::f1 and data::ff +// double coefficient=pow(1.0/constants::pi*exponent,0.5*3); + double coefficient=1.0; + const coord_3d center={0.0,0.0,-0.0}; + + auto Gaussian = [¢er, &exponent, &coefficient](const coord_3d& r) { + return coefficient * exp(-exponent*inner(r-center,r-center)); + }; + + // this won't work, the simulation cell is only [-1,1].. + // Normalized Gaussian exponent a produces potential erf(sqrt(a)*r)/r +// GaussianPotential gpot(center, exponent, coefficient); +// real_function_3d op_a=real_factory_3d(world).functor(gpot); + + real_function_3d a=real_factory_3d(world).functor(Gaussian); + exponent=2.0; + real_function_3d b=real_factory_3d(world).functor(Gaussian); + + auto [f1,f2,f3,f4,f5,ff]=data1.get_functions(); + CCPairFunction c1(a,b); + CCPairFunction c2(f1,f2); +// CCPairFunction ref(op_a,b); + auto op= CoulombOperator(world,1.e-5,FunctionDefaults<3>::get_thresh()); + op.print_timings=false; + op.particle()=1; + + auto op_c1=op(c1); + auto op_c2=op(c2); +// double a1=inner(ref,ref); + double norm1=inner(op_c1,op_c1); + double norm2=inner(op_c2,op_c2); + print("norm1,norm2",norm1,norm2); + bool good=fabs(norm1-norm2)::get_thresh(); + t1.checkpoint(good,"op(xx)"); + return t1.end(); +} + + int test_transformations(World& world, std::shared_ptr ncf, const Molecule& molecule, const CCParameters& parameter) { test_output t1("CCPairFunction::test_transformations"); @@ -344,7 +670,7 @@ int test_inner(World& world, std::shared_ptr ncf, cons if ((not bra.has_operator()) and (not ket.has_operator())) ref=ab_ab; double result=inner(bra,ket); -// print(bra.name(true)+ket.name(),"ref, result, diff", ref, result, ref-result); + print(bra.name(true)+ket.name(),"ref, result, diff", ref, result, ref-result); double thresh=FunctionDefaults<3>::get_thresh(); bool good=(fabs(result-ref)::set_thresh(1.e-5); FunctionDefaults<3>::set_cubic_cell(-1.0,1.0); FunctionDefaults<6>::set_cubic_cell(-1.0,1.0); + FunctionDefaults<1>::set_thresh(1.e-5); + FunctionDefaults<1>::set_cubic_cell(-10.,10.); + FunctionDefaults<2>::set_thresh(1.e-4); + FunctionDefaults<2>::set_cubic_cell(-10.,10.); + FunctionDefaults<3>::set_thresh(1.e-4); + FunctionDefaults<3>::set_cubic_cell(-10.,10.); + FunctionDefaults<4>::set_thresh(1.e-4); + FunctionDefaults<4>::set_cubic_cell(-10.,10.); print("numerical parameters: k, eps(3D), eps(6D)", FunctionDefaults<3>::get_k(), FunctionDefaults<3>::get_thresh(), FunctionDefaults<6>::get_thresh()); int isuccess=0; @@ -933,18 +1267,20 @@ int main(int argc, char **argv) { std::shared_ptr ncf = create_nuclear_correlation_factor(world, mol, nullptr, std::make_pair("slater", 2.0)); - isuccess+=test_constructor(world, ncf, mol, ccparam); - isuccess+=test_transformations(world, ncf, mol, ccparam); - isuccess+=test_inner(world, ncf, mol, ccparam); - isuccess+=test_multiply(world, ncf, mol, ccparam); - isuccess+=test_multiply_with_f12(world, ncf, mol, ccparam); - isuccess+=test_swap_particles(world, ncf, mol, ccparam); - isuccess+=test_scalar_multiplication(world, ncf, mol, ccparam); - isuccess+=test_partial_inner_3d(world, ncf, mol, ccparam); - isuccess+=test_partial_inner_6d(world, ncf, mol, ccparam); - isuccess+=test_projector(world, ncf, mol, ccparam); - FunctionDefaults<3>::set_cubic_cell(-10,10); - isuccess+=test_helium(world,ncf,mol,ccparam); + isuccess+=test_lowrank_function(world); +// isuccess+=test_constructor(world, ncf, mol, ccparam); +// isuccess+=test_operator_apply(world, ncf, mol, ccparam); +// isuccess+=test_transformations(world, ncf, mol, ccparam); +// isuccess+=test_inner(world, ncf, mol, ccparam); +// isuccess+=test_multiply(world, ncf, mol, ccparam); +// isuccess+=test_multiply_with_f12(world, ncf, mol, ccparam); +// isuccess+=test_swap_particles(world, ncf, mol, ccparam); +// isuccess+=test_scalar_multiplication(world, ncf, mol, ccparam); +// isuccess+=test_partial_inner_3d(world, ncf, mol, ccparam); +// isuccess+=test_partial_inner_6d(world, ncf, mol, ccparam); +// isuccess+=test_projector(world, ncf, mol, ccparam); +// FunctionDefaults<3>::set_cubic_cell(-10,10); +// isuccess+=test_helium(world,ncf,mol,ccparam); data1.clear(); } catch (std::exception& e) { madness::print("an error occured"); diff --git a/src/madness/mra/funcimpl.h b/src/madness/mra/funcimpl.h index e0569a58532..dad15263bcc 100644 --- a/src/madness/mra/funcimpl.h +++ b/src/madness/mra/funcimpl.h @@ -5302,133 +5302,127 @@ namespace madness { (rangeT(coeffs.begin(),coeffs.end()),do_inner_local(&g, leaves_only)); } - /// compute - - /// with |ket> either explicitly given or to be constructed by outer product |ket> = |p1 p2> - /// invoked by ket - template - TENSOR_RESULT_TYPE(T,R) compute_inner_with_coeffs(const Key& key, coeffT coeff_bra, - coeffT coeff_ket, coeffT coeff_eri, coeffT coeff_v1, coeffT coeff_v2, - coeffT coeff_p1, coeffT coeff_p2) { + /// compute the inner product of this range with other + template + struct do_inner_local_on_demand { + const FunctionImpl* ket; + const FunctionImpl* bra; + bool leaves_only=true; typedef TENSOR_RESULT_TYPE(T,R) resultT; - // - coeffT ket = (coeff_ket.has_data()) ? coeff_ket : outer(coeff_p1,coeff_p2); - coeffT v1v2ket; - double error=0.0; - - if (coeff_v1.has_data()) { - pointwise_multiplier pm(key,coeff_ket); - v1v2ket = pm(key,coeff_v1.full_tensor(), 1); - error+=pm.error; - v1v2ket+= pm(key,coeff_v2.full_tensor(), 2); - error+=pm.error; - } else { - v1v2ket = ket; - } - - resultT result; - if (coeff_eri.has_data()) { // project bra*ket onto eri, avoid multiplication with eri - pointwise_multiplier pm(key,v1v2ket); - tensorT braket=pm(key,coeff_bra.full_tensor_copy().conj()); - result=coeff_eri.full_tensor().trace(braket); - } else { // no eri, project ket onto bra - result=coeff_bra.full_tensor_copy().trace_conj(v1v2ket.full_tensor_copy()); - } - return result; + do_inner_local_on_demand(const FunctionImpl* bra, const FunctionImpl* ket, + const bool leaves_only=true) + : bra(bra), ket(ket), leaves_only(leaves_only) {} + resultT operator()(typename dcT::const_iterator& it) const { - } + constexpr std::size_t LDIM=std::max(NDIM/2,std::size_t(1)); - /// called by ket - template - TENSOR_RESULT_TYPE(T,R) compute_inner_for_key(const Key& key, const FunctionImpl* gimpl, - const GenTensor& coeff_bra) const { - typedef TENSOR_RESULT_TYPE(T,R) resultT; - typedef FunctionImpl implR; + const keyT& key=it->first; + const nodeT& fnode = it->second; + if (not fnode.has_coeff()) return resultT(0.0); // probably internal nodes + + // assuming all boxes (esp the low-dim ones) are local, i.e. the functions are replicated + auto find_valid_parent = [](auto& key, auto& impl, auto&& find_valid_parent) { + MADNESS_CHECK(impl->get_coeffs().owner(key)==impl->world.rank()); // make sure everything is local! + if (impl->get_coeffs().probe(key)) return key; + auto parentkey=key.parent(); + return find_valid_parent(parentkey, impl, find_valid_parent); + }; - // get the composite functor and everything that makes up gimpl - auto func=dynamic_cast* >(gimpl->functor.get()); - MADNESS_ASSERT(func); + // returns coefficients, empty if no functor present + auto get_coeff = [&find_valid_parent](const auto& key, const auto& impl) { + bool have_impl=impl.get(); + if (have_impl) { + auto parentkey = find_valid_parent(key, impl, find_valid_parent); + MADNESS_CHECK(impl->get_coeffs().probe(parentkey)); + typename decltype(impl->coeffs)::accessor acc; + impl->get_coeffs().find(acc,parentkey); + auto parentcoeff=acc->second.coeff(); + auto coeff=impl->parent_to_child(parentcoeff, parentkey, key); + return coeff; + } else { + return GenTensor::typeT>(); + } + }; + Key key1,key2; + key.break_apart(key1,key2); - auto find_valid_parent = [](auto& key, auto& impl, auto&& find_valid_parent) { - if (impl->get_coeffs().probe(key)) return key; - auto parentkey=key.parent(); - return find_valid_parent(parentkey, impl, find_valid_parent); - }; + auto func=dynamic_cast* >(ket->functor.get()); + MADNESS_ASSERT(func); + + auto coeff_bra=fnode.coeff(); + auto coeff_ket=get_coeff(key,func->impl_ket); + auto coeff_v1=get_coeff(key1,func->impl_m1); + auto coeff_v2=get_coeff(key2,func->impl_m2); + auto coeff_p1=get_coeff(key1,func->impl_p1); + auto coeff_p2=get_coeff(key2,func->impl_p2); + + // construct |ket(1,2)> or |p(1)p(2)> or |p(1)p(2) ket(1,2)> + double error=0.0; + if (coeff_ket.has_data() and coeff_p1.has_data()) { + pointwise_multiplier pm(key,coeff_ket); + coeff_ket=pm(key,outer(coeff_p1,coeff_p2,TensorArgs(TT_FULL,-1.0)).full_tensor()); + error+=pm.error; + } else if (coeff_ket.has_data() or coeff_p1.has_data()) { + coeff_ket = (coeff_ket.has_data()) ? coeff_ket : outer(coeff_p1,coeff_p2); + } else { // not ket and no p1p2 + MADNESS_EXCEPTION("confused ket/p1p2 in do_inner_local_on_demand",1); + } - // returns coefficients, empty if no functor present - auto get_coeff = [&find_valid_parent](const auto& key, const auto& impl) { - bool have_impl=impl.get(); - if (have_impl) { - auto parentkey = find_valid_parent(key, impl, find_valid_parent); - auto parentcoeff=impl->get_coeffs().find(parentkey).get()->second.coeff(); - auto coeff=impl->parent_to_child(parentcoeff, parentkey, key); - return coeff; + // construct (v(1) + v(2)) |ket(1,2)> + coeffT v1v2ket; + if (coeff_v1.has_data()) { + pointwise_multiplier pm(key,coeff_ket); + v1v2ket = pm(key,coeff_v1.full_tensor(), 1); + error+=pm.error; + v1v2ket+= pm(key,coeff_v2.full_tensor(), 2); + error+=pm.error; } else { - return GenTensor::typeT>(); + v1v2ket = coeff_ket; } - }; - - Key key1,key2; - key.break_apart(key1,key2); - // get all coefficients (apart from the eri coefficients) - auto coeff_ket=get_coeff(key,func->impl_ket); - auto coeff_v1=get_coeff(key1,func->impl_m1); - auto coeff_v2=get_coeff(key2,func->impl_m2); - auto coeff_p1=get_coeff(key1,func->impl_p1); - auto coeff_p2=get_coeff(key2,func->impl_p2); - - // make eri coefficients - coeffT coeff_eri; - if (func->impl_eri) { - MADNESS_CHECK(func->impl_eri->get_functor()->provides_coeff()); - coeff_eri=func->impl_eri->get_functor()->coeff(key).full_tensor(); + resultT result; + if (func->impl_eri) { // project bra*ket onto eri, avoid multiplication with eri + MADNESS_CHECK(func->impl_eri->get_functor()->provides_coeff()); + coeffT coeff_eri=func->impl_eri->get_functor()->coeff(key).full_tensor(); + pointwise_multiplier pm(key,v1v2ket); + tensorT braket=pm(key,coeff_bra.full_tensor_copy().conj()); + error+=pm.error; + if (error>1.e-3) print("error in key",key,error); + result=coeff_eri.full_tensor().trace(braket); + + } else { // no eri, project ket onto bra + result=coeff_bra.full_tensor_copy().trace_conj(v1v2ket.full_tensor_copy()); + } + return result; } - Future result=woT::task(gimpl->get_coeffs().owner(key), &implT:: template compute_inner_with_coeffs, key, - coeff_bra, coeff_ket, coeff_eri, coeff_v1, coeff_v2, coeff_p1, coeff_p2); - return result; - } + resultT operator()(resultT a, resultT b) const { + return (a+b); + } + template void serialize(const Archive& ar) { + throw "NOT IMPLEMENTED"; + } + }; /// Returns the inner product of this with function g constructed on-the-fly - /// handles compressed and redundant form + /// the leaf boxes of this' MRA tree defines the inner product template TENSOR_RESULT_TYPE(T,R) inner_local_on_demand(const FunctionImpl& gimpl) const { PROFILE_MEMBER_FUNC(FunctionImpl); typedef TENSOR_RESULT_TYPE(T,R) resultT; typedef FunctionImpl implR; - MADNESS_ASSERT(this->is_reconstructed()); - - - long nsum=0; - for (const auto& c : coeffs) if (c.second.has_coeff()) nsum++; - std::vector< Future > sum = future_vector_factory(nsum); - - long isum=0; - for (const auto& c : coeffs) { - const keyT& key=c.first; - const nodeT& fnode = c.second; - if (fnode.has_coeff()) { - auto bra_coeff = fnode.coeff(); - sum[isum] = woT::task(gimpl.get_coeffs().owner(key), &implR:: template compute_inner_for_key, key, &gimpl, bra_coeff); - isum++; - } - } - auto accumulate = [&sum]() { - resultT result=0.0; - for (auto& s : sum) result+=s.get(); - return result; - }; - auto result=accumulate(); -// Future result=gimpl.get_coeffs().task(key0(),&accumulate); - return result; + MADNESS_CHECK(this->is_reconstructed()); + typedef Range rangeT; + rangeT range(coeffs.begin(), coeffs.end()); + return world.taskq.reduce>(range, + do_inner_local_on_demand(this, &gimpl)); } /// Type of the entry in the map returned by make_key_vec_map diff --git a/src/madness/mra/funcplot.h b/src/madness/mra/funcplot.h index 527194e8e4b..fe47723678b 100644 --- a/src/madness/mra/funcplot.h +++ b/src/madness/mra/funcplot.h @@ -889,7 +889,7 @@ namespace madness { const std::string namei=name+"_"+std::to_string(i); vf[i].print_size("plot:"+namei); plot_plane(world,vf[i],namei); - plot_cubefile(world,vf[i],namei+".cube",header); +// plot_cubefile(world,vf[i],namei+".cube",header); } } diff --git a/src/madness/mra/function_interface.h b/src/madness/mra/function_interface.h index b253cdf4283..b0c498730c1 100644 --- a/src/madness/mra/function_interface.h +++ b/src/madness/mra/function_interface.h @@ -189,6 +189,16 @@ namespace madness { } + /// replicate low-dimensional functions over all ranks of this world + void replicate_low_dim_functions(const bool fence) { + if (impl_m1 and (not impl_m1->is_on_demand())) impl_m1->replicate(false); + if (impl_m2 and (not impl_m2->is_on_demand())) impl_m2->replicate(false); + + if (impl_p1 and (not impl_p1->is_on_demand())) impl_p1->replicate(false); + if (impl_p2 and (not impl_p2->is_on_demand())) impl_p2->replicate(false); + if (fence) world.gop.fence(); + } + void make_redundant(const bool fence) { // prepare base functions that make this function if (impl_ket and (not impl_ket->is_on_demand())) impl_ket->make_redundant(false); diff --git a/src/madness/mra/mra.h b/src/madness/mra/mra.h index ee107c46b47..7fc1d88141b 100644 --- a/src/madness/mra/mra.h +++ b/src/madness/mra/mra.h @@ -1361,6 +1361,7 @@ namespace madness { auto func=dynamic_cast* >(g.get_impl()->get_functor().get()); MADNESS_ASSERT(func); func->make_redundant(true); + func->replicate_low_dim_functions(true); this->reconstruct(); // if this == &g we don't need g to be redundant if (VERIFY_TREE) verify_tree(); diff --git a/src/madness/mra/operator.h b/src/madness/mra/operator.h index 82d76a8e0a1..883fcb90eb9 100644 --- a/src/madness/mra/operator.h +++ b/src/madness/mra/operator.h @@ -52,6 +52,16 @@ namespace madness { + template + class SeparatedConvolution; + + class CCPairFunction; + template + std::vector apply(const SeparatedConvolution& op, const std::vector& argument); + + template + CCPairFunction apply(const SeparatedConvolution& op, const CCPairFunction& argument); + /// SeparatedConvolutionInternal keeps data for 1 term and all dimensions and 1 displacement /// Why is this here?? Why don't you just use ConvolutionND in SeparatedConvolutionData?? template @@ -1115,6 +1125,14 @@ namespace madness { return madness::apply(*this, f1, f2); } + /// apply this onto another suitable argument, returning the same type + + /// argT must implement argT::apply(const SeparatedConvolution& op, const argT& arg) + template + argT operator()(const argT& argument) const { + return madness::apply(*this,argument); + } + /// apply this operator on coefficients in full rank form diff --git a/src/madness/mra/testinnerext.cc b/src/madness/mra/testinnerext.cc index a0695691407..717831484eb 100644 --- a/src/madness/mra/testinnerext.cc +++ b/src/madness/mra/testinnerext.cc @@ -83,6 +83,35 @@ bool test_loose1(std::string msg, double a, double b, double tol=thresh) { } +int test_tight_diffuse(World& world) { + FunctionDefaults<4>::set_thresh(1.e-5); + double a=1.e2; + double b=1.e-2; + for (int i=0; i<4; ++i) { + a=std::pow(10.0,double(i)); + b=std::pow(0.1,double(i)); + print("a,b",a,b); + + real_function_2d aa=real_factory_2d(world).functor([&](const coord_2d& r){return exp(-a*inner(r,r));}); + real_function_2d bb=real_factory_2d(world).functor([&](const coord_2d& r){return exp(-b*inner(r,r));}); + real_function_4d cc=real_factory_4d(world).functor([&](const coord_4d& r){return exp(-b*inner(r,r));}); + real_function_4d dd=CompositeFactory(world).particle1(aa).particle2(copy(aa)); + aa.print_size("exp(-1000 r^2"); + bb.print_size("exp(-0.001 r^2"); + double result=inner(cc,dd); + double refresult=std::pow(constants::pi/(a+b),2.0); + print("result,refresult,error",result,refresult,result-refresult); + MADNESS_CHECK(test(" inner(exp(-a r^2 , exp(-b r^2)) ", result,refresult)); + } + + + + + return 0; + + +} + int test_partial_inner(World& world) { bool do_low_rank=false; #if HAVE_GENTENSOR @@ -260,6 +289,7 @@ int main(int argc, char** argv) { initialize<6>(world); test_partial_inner(world); + test_tight_diffuse(world); if (!smalltest) { real_function_3d alpha1 = real_factory_3d(world).f(alpha_func); diff --git a/src/madness/world/archive.h b/src/madness/world/archive.h index 7977bfd94c2..f51ab5d31c3 100644 --- a/src/madness/world/archive.h +++ b/src/madness/world/archive.h @@ -515,7 +515,7 @@ namespace madness { ar.load(&cookie, 1); // cannot use >> if (cookie != ck) { char msg[255]; - std::sprintf(msg,"InputArchive type mismatch: expected cookie " + std::snprintf(msg,255,"InputArchive type mismatch: expected cookie " "%u (%s) but got %u (%s) instead", ck, archive_type_names[ck], cookie,archive_type_names[cookie]); diff --git a/src/madness/world/parallel_archive.h b/src/madness/world/parallel_archive.h index 24d329b9d1b..097f5dce65b 100644 --- a/src/madness/world/parallel_archive.h +++ b/src/madness/world/parallel_archive.h @@ -171,7 +171,7 @@ namespace madness { strcpy(fname,filename); // Save the filename for later char buf[256]; MADNESS_ASSERT(strlen(filename)+7 <= sizeof(buf)); - sprintf(buf, "%s.%5.5d", filename, world.rank()); + snprintf(buf, 256, "%s.%5.5d", filename, world.rank()); if (world.rank() == 0) { ar.open(buf); @@ -217,7 +217,7 @@ namespace madness { exists(World& world, const char* filename) { char buf[256]; MADNESS_ASSERT(strlen(filename)+7 <= sizeof(buf)); - sprintf(buf, "%s.%5.5d", filename, world.rank()); + snprintf(buf, 256, "%s.%5.5d", filename, world.rank()); bool status; if (world.rank() == 0) status = (access(buf, F_OK|R_OK) == 0); @@ -268,7 +268,7 @@ namespace madness { char buf[268]; MADNESS_ASSERT(strlen(filename)+7 <= sizeof(buf)); for (ProcessID p=0; p" << std::endl; - sprintf(tag,"", + snprintf(tag,256,"", ARCHIVE_MAJOR_VERSION, ARCHIVE_MINOR_VERSION); os << tag << std::endl; os << "" << std::endl; for (int i=0; i<256; ++i) { - sprintf(tag,"%d \"%s\"",i,archive_type_names[i]); + snprintf(tag,256,"%d \"%s\"",i,archive_type_names[i]); store(tag,strlen(tag)); // Must use store to escape characters } os << "" << std::endl; @@ -144,7 +144,7 @@ namespace madness { is.getline(buf,256); char tag[256]; - sprintf(tag,"", + snprintf(tag,256,"", ARCHIVE_MAJOR_VERSION, ARCHIVE_MINOR_VERSION); if (strcmp(buf,tag)) { std::cout << "TextFstreamInputArchive: not an archive/bad version?" << std::endl; diff --git a/src/madness/world/text_fstream_archive.h b/src/madness/world/text_fstream_archive.h index 737b5209c91..b51f0d0e143 100644 --- a/src/madness/world/text_fstream_archive.h +++ b/src/madness/world/text_fstream_archive.h @@ -75,7 +75,7 @@ namespace madness { void store_start_tag() const { char tag[256]; unsigned char cookie = archive_typeinfo::cookie; - sprintf(tag,"", cookie); + snprintf(tag,256,"", cookie); os << tag << std::endl; MAD_ARCHIVE_DEBUG(std::cout << "textarchive: tag = " << tag << std::endl); } @@ -87,7 +87,7 @@ namespace madness { void store_end_tag() const { char tag[256]; unsigned char cookie = archive_typeinfo::cookie; - sprintf(tag,"",cookie); + snprintf(tag,256,"",cookie); os << tag << std::endl; } @@ -175,9 +175,9 @@ namespace madness { is.getline(ftag,256); unsigned char cookie = archive_typeinfo::cookie; if (end) - sprintf(tag,"",cookie); + snprintf(tag,256,"",cookie); else - sprintf(tag,"",cookie); + snprintf(tag,256,"",cookie); if (strcmp(tag,ftag) != 0) { std::cout << "TextFstreamInputArchive: type mismatch: expected=" << tag diff --git a/src/madness/world/thread.h b/src/madness/world/thread.h index b5962e3f485..ecd8557e077 100644 --- a/src/madness/world/thread.h +++ b/src/madness/world/thread.h @@ -1418,7 +1418,7 @@ namespace madness { std::cerr << "!!MADNESS: Hung queue?" << std::endl; if (counter++ > 3) { char errstr[256]; - sprintf(errstr, "ThreadPool::await() timed out after %.1lf seconds", timeout); + snprintf(errstr,256, "ThreadPool::await() timed out after %.1lf seconds", timeout); throw madness::MadnessException(errstr, 0, 1, __LINE__, __FUNCTION__, __FILE__); From 2d086882479fd76151e564415a1bb2e959088a3f Mon Sep 17 00:00:00 2001 From: fbischoff Date: Wed, 26 Apr 2023 12:43:00 +0200 Subject: [PATCH 023/109] low_rank_functions --- src/madness/chem/CMakeLists.txt | 2 +- src/madness/chem/test_ccpairfunction.cc | 283 ----------- src/madness/chem/test_low_rank_function.cc | 544 +++++++++++++++++++++ 3 files changed, 545 insertions(+), 284 deletions(-) create mode 100644 src/madness/chem/test_low_rank_function.cc diff --git a/src/madness/chem/CMakeLists.txt b/src/madness/chem/CMakeLists.txt index 33a4314b3ed..ef7b6e54f4f 100644 --- a/src/madness/chem/CMakeLists.txt +++ b/src/madness/chem/CMakeLists.txt @@ -144,7 +144,7 @@ if(BUILD_TESTING) # The list of unit test source files set(CHEM_TEST_SOURCES_SHORT test_pointgroupsymmetry.cc test_masks_and_boxes.cc test_QCCalculationParametersBase.cc test_qc.cc test_MolecularOrbitals.cc test_BSHApply.cc) - set(CHEM_TEST_SOURCES_LONG test_localizer.cc test_ccpairfunction.cc) + set(CHEM_TEST_SOURCES_LONG test_localizer.cc test_ccpairfunction.cc test_low_rank_function.cc) if (LIBXC_FOUND) list(APPEND CHEM_TEST_SOURCES_SHORT test_dft.cc ) list(APPEND CHEM_TEST_SOURCES_LONG test_SCFOperators.cc) diff --git a/src/madness/chem/test_ccpairfunction.cc b/src/madness/chem/test_ccpairfunction.cc index e6e808bdce4..a43cf338f2a 100644 --- a/src/madness/chem/test_ccpairfunction.cc +++ b/src/madness/chem/test_ccpairfunction.cc @@ -99,289 +99,6 @@ struct data { data data1; -template -class LowRank { -public: - - World& world; - std::vector> g,h; - - - LowRank(std::vector> g, std::vector> h) - : world(g.front().world()), g(g), h(h) {} - - LowRank(World& world, long n) : world(world) { - g= zero_functions_compressed(world,n); - h= zero_functions_compressed(world,n); - } - -// LowRank() =default; // Default constructor necessary for storage in vector - - LowRank(const LowRank& a) : world(a.world), g(copy(world,a.g)), h(copy(world,a.h)) {} // Copy constructor necessary - - LowRank& operator=(const LowRank& f) { // Assignment required for storage in vector - LowRank ff(f); - std::swap(ff.g,g); - std::swap(ff.h,h); - return *this; - } - - LowRank operator-(const LowRank& b) const { // Operator- necessary - return LowRank(g-b.g,h-b.h); - } - - LowRank& operator+=(const LowRank& b) { // Operator+= necessary - g+=b.g; - h+=b.h; - return *this; - } - - LowRank operator*(double a) const { // Scale by a constant necessary - return LowRank(g*a,h*a); - } - -// double get() const {return x;} -}; - -// This interface is necessary to compute inner products -template -double inner(const LowRank& a, const LowRank& b) { - World& world=a.world; - return (matrix_inner(world,a.g,b.g).emul(matrix_inner(world,a.h,b.h))).sum(); -} - - -// The default constructor for functions does not initialize -// them to any value, but the solver needs functions initialized -// to zero for which we also need the world object. -template -struct allocator1 { - World& world; - const int n; - - /// @param[in] world the world - /// @param[in] nn the number of functions in a given vector - allocator1(World& world, const int nn) : - world(world), n(nn) { - } - - /// allocate a vector of n empty functions - LowRank operator()() { - return LowRank(world,n); - } -}; - - -/// Computes the electrostatic potential due to a Gaussian charge distribution - -/// stolen from testsuite.cc -class GaussianPotential : public FunctionFunctorInterface { -public: - typedef Vector coordT; - const coordT center; - const double exponent; - const double coefficient; - - GaussianPotential(const coordT& center, double expnt, double coefficient) - : center(center) - , exponent(sqrt(expnt)) - , coefficient(coefficient*pow(constants::pi/exponent,1.5)*pow(expnt,-0.75)) {} - - double operator()(const coordT& x) const { - double sum = 00; - for (int i=0; i<3; ++i) { - double xx = center[i]-x[i]; - sum += xx*xx; - }; - double r = sqrt(sum); - if (r<1.e-4) { // correct thru order r^3 - const double sqrtpi=sqrt(constants::pi); - const double a=exponent; - return coefficient*(2.0*a/sqrtpi - 2.0*a*a*a*r*r/(3.0*sqrtpi)); - } else { - return coefficient*erf(exponent*r)/r; - } - } -}; - -template -struct randomgaussian { - Vector random_origin; - double exponent; - double radius=2; - randomgaussian(double exponent) : exponent(exponent) { - Vector ran; // [0,1] - RandomVector(NDIM,ran.data()); - random_origin=2.0*radius*ran-Vector(radius); - print("origin at ",random_origin, ", exponent",exponent); - } - double operator()(const Vector& r) const { -// return exp(-exponent*inner(r-random_origin,r-random_origin)); - return exp(-exponent*(r-random_origin).normf()); - } - -}; - -template -void orthonormalize(World& world, std::vector>& g, std::vector>& h, Tensor& s) { - /** - * |g >< h| = |g_ortho> < h | h_ortho > gg hh U s VT > g_ortho=orthonormalize_canonical(g,1.e-8); - std::vector> h_ortho=orthonormalize_canonical(h,1.e-8); - auto gg=matrix_inner(world,g_ortho,g); - auto hh=matrix_inner(world,h,h_ortho); - auto ovlp=inner(gg,hh); - Tensor U,VT; - svd(ovlp,U,s,VT); - auto V=transpose(VT); - - // truncate -// for (int i=1; i f=FunctionFactory(world).functor([&LDIM](const Vector& r) - { - Vector r1,r2; - for (int i=0; i> omega2(n); - for (long i=0; i(RandomValue()*3.0)); - omega2[i]=FunctionFactory(world).functor(randomgaussian(RandomValue()*10.0)); - } - t1.checkpoint(true,"projection 1D functions"); - - std::vector> Y(n); -// for (int i=0; i> g=orthonormalize_canonical(Y,1.e-12); - print("g.size()",g.size()); - t1.checkpoint(true,"Y orthonormalizing"); - std::vector> h(g.size()); -// for (int i=0; i s; - orthonormalize(world,g,h,s); - - - auto fapprox=s[0]*hartree_product(g[0],h[0]); - for (int i=1; i({f,fapprox,f-fapprox},"f_and_approx",std::vector({"adsf","asdf","diff"})); - t1.checkpoint(true,"plotting"); - - /* - * optimize - */ - - auto s_into_h = [&world](const Tensor& s, const auto& hvec) { - auto hs=copy(world,hvec); - for (int i=0; i> htmp(g.size()), gtmp(g.size()); - for (int j=0; j1) orthonormalize(world,g,h,s); - print("s after",s); - - if (iopt%2==0) { - fapprox=s[0]*hartree_product(g[0],h[0]); - for (int i=1; i({f,fapprox,f-fapprox},"f_and_approx_opt",std::vector({"adsf","asdf","diff"})); - t1.checkpoint(true,"plotting"); - - - - - - return t1.end(); -} - int test_constructor(World& world, std::shared_ptr ncf, const Molecule& molecule, const CCParameters& parameter) { test_output t1("CCPairFunction::constructor"); diff --git a/src/madness/chem/test_low_rank_function.cc b/src/madness/chem/test_low_rank_function.cc new file mode 100644 index 00000000000..516ffba178b --- /dev/null +++ b/src/madness/chem/test_low_rank_function.cc @@ -0,0 +1,544 @@ +// +// Created by Florian Bischoff on 4/24/23. +// + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +template +struct gauss { + double a=2.0; + gauss() = default; + double operator()(const Vector& r) const { + return exp(-a*inner(r,r)); + } +}; + +template +void orthonormalize_svd(World& world, std::vector>& g, std::vector>& h, Tensor& s) { + /** + * |g >s< h| = |g_ortho> s < h | h_ortho > gg s hh U s VT > g_ortho=orthonormalize_canonical(g,1.e-8); + std::vector> h_ortho=orthonormalize_canonical(h,1.e-8); + t.tag("orthonormalize_canonical"); + auto gg=matrix_inner(world,g_ortho,g); + auto hh=matrix_inner(world,h,h_ortho); + t.tag("matrix_inner"); + for (int i=0; i U,VT; + svd(ovlp,U,s,VT); + auto V=transpose(VT); + + // truncate +// for (int i=1; i +std::vector> form_inner(const Function& f, const std::vector>& vec) { + double cpu0=cpu_time(); + std::vector> result(vec.size()); + if constexpr (std::is_same,Function>::value) { + for (int i=0; i +typename std::enable_if>>::type form_inner(const real_convolution_3d& f, const std::vector>& vec) { + double cpu0=cpu_time(); + World& world=vec.front().world(); + std::vector> result=apply(world,f,vec); + double cpu1=cpu_time(); + std::printf("form inner finished after %4.2fs \n",cpu1-cpu0); + return result; +} + +template +class LowRank { +public: + + Tensor s; + std::vector> g,h; + + LowRank(Tensor& s, std::vector> g, std::vector> h) + : s(s), g(g), h(h) {} + +// LowRank(World& world, long n) : world(world) { +// g= zero_functions_compressed(world,n); +// h= zero_functions_compressed(world,n); +// } + + LowRank() =default; // Default constructor necessary for storage in vector + + LowRank(const LowRank& a) : s(a.s), g(copy(a.g.front().world(),a.g)), h(copy(a.h.front().world(),a.h)) {} // Copy constructor necessary + + LowRank& operator=(const LowRank& f) { // Assignment required for storage in vector + LowRank ff(f); + std::swap(ff.s,s); + std::swap(ff.g,g); + std::swap(ff.h,h); + return *this; + } + + template + void project(World& world, const hidimT& f, const std::vector>& regular_grid, const long ntrial) { + + timer t1(world); + auto Y=random_vectors(world, regular_grid, ntrial); + t1.tag("Yforming"); + print("Y.size()",Y.size()); + + + Localizer localizer; + +// std::vector> g=orthonormalize_canonical(Y,1.e-8); + g=orthonormalize_cd(Y); + print("g.size()",g.size()); + t1.tag("Y orthonormalizing"); + + bool localize=false; + if (localize) { + localizer.set_method("boys"); + MolecularOrbitals mos; + mos.set_mos(g); + std::vector set(g.size(),0); + mos.update_localize_set(set); + localizer.localize(mos,true); + g=mos.get_mos(); + t1.tag("Y localizing"); + } + + h=form_inner(f,g); + s=Tensor(g.size()); + s=1.0; + t1.tag("Y backprojection"); + } + + void orthonormalize_svd() { + ::orthonormalize_svd(g.front().world(),g,h,s); + } + + template + void optimize(const hidimT& f, const std::vector>& regular_grid) { + World& world=g.front().world(); + for (int iopt=0; iopt<8; ++iopt) { + timer t(world); + std::vector> htmp(g.size()), gtmp(g.size()); + + for (int i=0; i1) orthonormalize_svd(); + + if (iopt%2==0) compute_error(f,regular_grid); + t.end("finished optimization iteration "+std::to_string(iopt)); + } + } + + long rank() const {return s.size();} + + T operator()(const Vector& coord) const { + Vector left,right; + for (int i=0; i + double compute_error(const hidimT& f, const std::vector>& regular_grid) const { + const long ntrial=10; + World& world=g.front().world(); + timer t(world); + auto trial= random_vectors(world,regular_grid,ntrial); + + // result[j,1] = \sum_2 f(1,2) t(2,j) - \sum_2r g(1,r)s(r)h(r,2) t(2,j) + // ref[j,1] = \sum_2 f(1,2) t(2,j) + const std::vector> ref=form_inner(f,trial); + + // check[j,1] = \sum_jr g(1,r)s(r)h(r,2) t(2,j) + Tensor ht=matrix_inner(world,h,trial); // ht(r,j) + for (int r=0; r> check=transform(world,g,ht); + + std::vector norms=norm2s(world,ref-check); + double max=*std::max_element(norms.begin(),norms.end()); + double err=10.0*sqrt(2.0/constants::pi)*max; + std::stringstream ss; + + ss << "rank and error in f_approx " << g.size() << " " << std::scientific << err; + t.tag(ss.str()); + return err; + } + + +// LowRank operator-(const LowRank& b) const { // Operator- necessary +// return LowRank(g-b.g,h-b.h); +// } +// +// LowRank& operator+=(const LowRank& b) { // Operator+= necessary +// g+=b.g; +// h+=b.h; +// return *this; +// } + + LowRank operator*(double a) const { // Scale by a constant necessary + return LowRank(s*a,g,h); + } + +// double get() const {return x;} +}; + +// This interface is necessary to compute inner products +template +double inner(const LowRank& a, const LowRank& b) { + World& world=a.world; + return (matrix_inner(world,a.g,b.g).emul(matrix_inner(world,a.h,b.h))).sum(); +} + + +// // The default constructor for functions does not initialize +// // them to any value, but the solver needs functions initialized +// // to zero for which we also need the world object. +// template +// struct allocator1 { +// World& world; +// const int n; +// +// /// @param[in] world the world +// /// @param[in] nn the number of functions in a given vector +// allocator1(World& world, const int nn) : +// world(world), n(nn) { +// } +// +// /// allocate a vector of n empty functions +// LowRank operator()() { +// return LowRank(world,n); +// } +// }; + +Tensor gaussian_random_distribution(double mean, double variance, long n) { + std::random_device rd{}; + std::mt19937 gen{rd()}; + std::normal_distribution<> d{mean, variance}; + Tensor result(n); + for (int i = 0; i < n; ++i) result(i)=d(gen); + return result; +} + + + + +template +typename std::enable_if<(LDIM==3), real_convolution_3d>::type hidim(World& world) { + auto f_op= SlaterOperator(world,1.0,1.e-6,FunctionDefaults<3>::get_thresh()); + auto f12_functor=[](const Vector& r) { + Vector r1,r2; + for (int i=0; i(world,f12_functor,"f12_functor"); + return f_op; +} + +template +typename std::enable_if<(LDIM<3), Function>::type hidim(World& world) { + + auto f12_functor=[](const Vector& r) { + Vector r1,r2; + for (int i=0; i(world).functor(f12_functor); + plot_plane<2*LDIM>(world,f12_functor,"f12_functor"); +// Function f; + return f; +} + +// nran random vectors on a regular grid +template +std::vector> random_vectors(World &world, + const std::vector>& regular_grid, + const long nran) { + const long n = regular_grid.size(); + Tensor factors(n,nran); + for (long i=0; i +double compute_error_implicitly(const Tensor& s, + const std::vector>& g, + const std::vector>& h, + const hidimT& f, + const std::vector>& regular_grid) { + const long ntrial=10; + World& world=g.front().world(); + auto trial= random_vectors(world,regular_grid,ntrial); + + // result[j,1] = \sum_2 f(1,2) t(2,j) - \sum_2r g(1,r)s(r)h(r,2) t(2,j) + // ref[j,1] = \sum_2 f(1,2) t(2,j) + const std::vector> ref=form_inner(f,trial); + + // check[j,1] = \sum_jr g(1,r)s(r)h(r,2) t(2,j) + Tensor ht=matrix_inner(world,h,trial); // ht(r,j) + for (int r=0; r> check=transform(world,g,ht); + + std::vector norms=norm2s(world,ref-check); + double max=*std::max_element(norms.begin(),norms.end()); + double err=10.0*sqrt(2.0/constants::pi)*max; + return err; + +} + +template +typename std::enable_if::type compute_error (const Tensor& s, + const std::vector>& g, + const std::vector>& h, + const Function& f, + const std::vector>& regular_grid, + std::string name="") { + auto fapprox=s[0]*hartree_product(g[0],h[0]); + for (int i=1; i({f,fapprox,f-fapprox},name,std::vector({"adsf","asdf","diff"})); + return err; +}; + + +template +typename std::enable_if::type compute_error (const Tensor& s, + const std::vector>& g, + const std::vector>& h, + const SeparatedConvolution& f, + const std::vector>& regular_grid, + std::string name="") { + double cpu0=cpu_time(); + double err_implicit= compute_error_implicitly(s,g,h,f,regular_grid); + double err=-1.0; + double cpu1=cpu_time(); + print("rank and error in f_approx_opt", g.size(), err,err_implicit, "after ",cpu1-cpu0); + return err; +}; + +template +std::vector> uniformly_distributed_slater(World& world, + const double lo, const double hi, const long n_per_dim) { + const long total_n=std::pow(n_per_dim,NDIM); + Vector R; + auto sl=[&R](const Vector& r) { + return exp(-sqrt(inner(r-R,r-R)+1.e-3)); + }; + + Vector lovec,hivec; + lovec.fill(lo); + hivec.fill(hi); + Vector increment=(hivec-lovec)*(1.0/double(n_per_dim-1)); + std::vector> result(total_n); + std::vector stride(NDIM,1l); + // dim=5,5,5 + // stride=25,5,1 + for (long i=NDIM-2; i>=0; --i) stride[i]=n_per_dim*stride[i+1]; + for (long i=0; i tmp(NDIM); + for (int idim=0; idim(world).functor(sl); + } + + return result; + +} + +int test_lowrank_function(World& world) { + madness::default_random_generator.setstate(int(cpu_time())%4149); + + print(""); + constexpr std::size_t LDIM=3; + long n_per_dim=10; + long ntrial=50; + + print("LDIM, n_per_dim, ntrial",LDIM,n_per_dim,ntrial); + constexpr std::size_t NDIM=2*LDIM; + + auto f=hidim(world); + + double radius=2.0; + auto regular_grid=uniformly_distributed_slater(world,-radius,radius,n_per_dim); + print("regular_grid.size()",regular_grid.size()); + + LowRank lrf; + lrf.project(world,f,regular_grid,ntrial); + + lrf.compute_error(f,regular_grid); + lrf.orthonormalize_svd(); + lrf.compute_error(f,regular_grid); + + plot_plane<2*LDIM>(world,lrf,"lrf0"); + + print("\nstarting optimization\n"); + + lrf.optimize(f,regular_grid); + + lrf.compute_error(f,regular_grid); + plot_plane<2*LDIM>(world,lrf,"lrf1"); + + + return 0; +} + +int test_6d_convolution(World& world) { + timer t1(world); + real_function_3d one=real_factory_3d(world).functor([](const coord_3d& r){return 1.0;}); + real_function_3d phi=real_factory_3d(world).functor([](const coord_3d& r){return exp(-2.0*inner(r,r));}); +// auto f12= SlaterF12Operator(world,1.0,1.e-4,1.e-3); + auto g12=CoulombOperator(world,1.e-4,1.e-4); + g12.particle()=1; + auto f12=TwoElectronFactory(world).dcut(1.e-7).f12().gamma(1.0); + { + real_function_6d f = CompositeFactory(world).g12(f12).particle1(copy(phi)).particle2(copy(phi)); + f.fill_cuspy_tree(); + f.print_size("cuspy tree phi(1)phi(2)"); + t1.tag("fill cuspy tree"); + real_function_6d X = (multiply(f, copy(phi), 1)).truncate(); + real_function_6d Y = g12(X); // overwrite X to save space + real_function_6d Z = (multiply(f, copy(phi), 1)).truncate(); + t1.tag("apply exchange"); + + + } + + { + real_function_6d f = CompositeFactory(world).g12(f12).particle1(copy(phi)).particle2(copy(one)); + f.fill_cuspy_tree(); + f.print_size("cuspy tree phi(1)one(2)"); + t1.tag("fill cuspy tree"); + real_function_6d X = (multiply(f, copy(phi), 1)).truncate(); + real_function_6d Y = g12(X); // overwrite X to save space + real_function_6d Z = (multiply(f, copy(phi), 1)).truncate(); + t1.tag("apply exchange"); + } + t1.tag("fill cuspy tree"); + return 1.0; + +} + + +int main(int argc, char **argv) { + + madness::World& world = madness::initialize(argc, argv); + startup(world, argc, argv); + commandlineparser parser(argc, argv); + FunctionDefaults<6>::set_tensor_type(TT_2D); + FunctionDefaults<3>::set_thresh(1.e-5); + FunctionDefaults<3>::set_cubic_cell(-1.0,1.0); + FunctionDefaults<1>::set_thresh(1.e-5); + FunctionDefaults<1>::set_cubic_cell(-10.,10.); + FunctionDefaults<2>::set_thresh(1.e-4); + FunctionDefaults<2>::set_cubic_cell(-10.,10.); + FunctionDefaults<3>::set_thresh(1.e-4); + FunctionDefaults<3>::set_cubic_cell(-10.,10.); + FunctionDefaults<4>::set_thresh(1.e-4); + FunctionDefaults<4>::set_cubic_cell(-10.,10.); + FunctionDefaults<6>::set_thresh(1.e-3); + FunctionDefaults<6>::set_cubic_cell(-10.,10.); + print("numerical parameters: k, eps(3D), eps(6D)", FunctionDefaults<3>::get_k(), FunctionDefaults<3>::get_thresh(), + FunctionDefaults<6>::get_thresh()); + int isuccess=0; +#ifdef USE_GENTENSOR + + try { + parser.set_keyval("geometry", "he"); + parser.print_map(); + Molecule mol(world, parser); + mol.print(); + CCParameters ccparam(world, parser); + + + isuccess+= test_6d_convolution(world); + +// std::shared_ptr ncf = create_nuclear_correlation_factor(world, +// mol, nullptr, std::make_pair("slater", 2.0)); + isuccess+=test_lowrank_function(world); + } catch (std::exception& e) { + madness::print("an error occured"); + madness::print(e.what()); + } +#else + print("could not run test_ccpairfunction: U need to compile with ENABLE_GENTENSOR=1"); +#endif + finalize(); + + return isuccess; +} From 2a23f52c4675757b4bd5735866a9287d5f326a32 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Thu, 27 Apr 2023 13:47:53 +0200 Subject: [PATCH 024/109] low_rank_functions seems to work decently --- src/madness/chem/test_low_rank_function.cc | 196 ++++++++++++++------- 1 file changed, 132 insertions(+), 64 deletions(-) diff --git a/src/madness/chem/test_low_rank_function.cc b/src/madness/chem/test_low_rank_function.cc index 516ffba178b..6694c229832 100644 --- a/src/madness/chem/test_low_rank_function.cc +++ b/src/madness/chem/test_low_rank_function.cc @@ -24,6 +24,35 @@ struct gauss { } }; +struct hidim_orbitals { + std::shared_ptr f12; + real_function_3d phi1, phi2; + hidim_orbitals(std::shared_ptr& f, const real_function_3d& phi1, const real_function_3d& phi2) + : f12(f), phi1(phi1), phi2(phi2) { + } + + double operator()(const Vector& coord) const { + + Vector left,right; + for (int i=0; i<3; ++i) { + left[i]=coord[i]; + right[i]=coord[i+3]; + } + + auto f12_functor=[](const Vector& r) { + Vector r1,r2; + for (int i=0; i<3; ++i) { + r1[i]=r[i]; + r2[i]=r[i+3]; + } + return exp(-(r1-r2).normf()); + }; + + return phi1(left)*phi2(right)*f12_functor(coord); + } + +}; + template void orthonormalize_svd(World& world, std::vector>& g, std::vector>& h, Tensor& s) { /** @@ -73,6 +102,18 @@ void orthonormalize_svd(World& world, std::vector>& g, std::vec } +template +std::vector> form_inner(const hidim_orbitals& f, const std::vector>& vec) { + double cpu0=cpu_time(); + World& world=vec.front().world(); + auto tmp1=vec*f.phi1; + std::vector> result=apply(world,(*f.f12),tmp1); + result=result*f.phi2; + double cpu1=cpu_time(); + std::printf("form inner finished after %4.2fs \n",cpu1-cpu0); + return result; +} + // note that we assume f is symmetric!!!!! template std::vector> form_inner(const Function& f, const std::vector>& vec) { @@ -127,10 +168,10 @@ class LowRank { } template - void project(World& world, const hidimT& f, const std::vector>& regular_grid, const long ntrial) { + void project(World& world, const hidimT& f, const std::vector>& regular_grid_Y, const long ntrial) { timer t1(world); - auto Y=random_vectors(world, regular_grid, ntrial); + auto Y=random_vectors(world, regular_grid_Y, ntrial); t1.tag("Yforming"); print("Y.size()",Y.size()); @@ -165,7 +206,7 @@ class LowRank { } template - void optimize(const hidimT& f, const std::vector>& regular_grid) { + void optimize(const hidimT& f, const std::vector>& regular_grid_Y) { World& world=g.front().world(); for (int iopt=0; iopt<8; ++iopt) { timer t(world); @@ -180,8 +221,9 @@ class LowRank { h=htmp; if (g.size()>1) orthonormalize_svd(); + plot_plane<2*LDIM>(world,*this,"lrf_iter"+std::to_string(iopt)); - if (iopt%2==0) compute_error(f,regular_grid); + if (iopt%2==0) compute_error(f,regular_grid_Y); t.end("finished optimization iteration "+std::to_string(iopt)); } } @@ -202,11 +244,11 @@ class LowRank { // check accuracy by applying hi/lo-dim function on a set of trial functions // cf Halko, sec 4.3 template - double compute_error(const hidimT& f, const std::vector>& regular_grid) const { + double compute_error(const hidimT& f, const std::vector>& regular_grid_Y) const { const long ntrial=10; World& world=g.front().world(); timer t(world); - auto trial= random_vectors(world,regular_grid,ntrial); + auto trial= random_vectors(world,regular_grid_Y,ntrial); // result[j,1] = \sum_2 f(1,2) t(2,j) - \sum_2r g(1,r)s(r)h(r,2) t(2,j) // ref[j,1] = \sum_2 f(1,2) t(2,j) @@ -253,25 +295,6 @@ double inner(const LowRank& a, const LowRank& b) { } -// // The default constructor for functions does not initialize -// // them to any value, but the solver needs functions initialized -// // to zero for which we also need the world object. -// template -// struct allocator1 { -// World& world; -// const int n; -// -// /// @param[in] world the world -// /// @param[in] nn the number of functions in a given vector -// allocator1(World& world, const int nn) : -// world(world), n(nn) { -// } -// -// /// allocate a vector of n empty functions -// LowRank operator()() { -// return LowRank(world,n); -// } -// }; Tensor gaussian_random_distribution(double mean, double variance, long n) { std::random_device rd{}; @@ -282,9 +305,6 @@ Tensor gaussian_random_distribution(double mean, double variance, long n return result; } - - - template typename std::enable_if<(LDIM==3), real_convolution_3d>::type hidim(World& world) { auto f_op= SlaterOperator(world,1.0,1.e-6,FunctionDefaults<3>::get_thresh()); @@ -320,13 +340,13 @@ typename std::enable_if<(LDIM<3), Function>::type hidim(World& world) // nran random vectors on a regular grid template std::vector> random_vectors(World &world, - const std::vector>& regular_grid, + const std::vector>& regular_grid_Y, const long nran) { - const long n = regular_grid.size(); + const long n = regular_grid_Y.size(); Tensor factors(n,nran); for (long i=0; i& s, const std::vector>& g, const std::vector>& h, const hidimT& f, - const std::vector>& regular_grid) { + const std::vector>& regular_grid_Y) { const long ntrial=10; World& world=g.front().world(); - auto trial= random_vectors(world,regular_grid,ntrial); + auto trial= random_vectors(world,regular_grid_Y,ntrial); // result[j,1] = \sum_2 f(1,2) t(2,j) - \sum_2r g(1,r)s(r)h(r,2) t(2,j) // ref[j,1] = \sum_2 f(1,2) t(2,j) @@ -362,12 +382,12 @@ typename std::enable_if::type compute_error (const Tensor& s, const std::vector>& g, const std::vector>& h, const Function& f, - const std::vector>& regular_grid, + const std::vector>& regular_grid_Y, std::string name="") { auto fapprox=s[0]*hartree_product(g[0],h[0]); for (int i=1; i({f,fapprox,f-fapprox},name,std::vector({"adsf","asdf","diff"})); @@ -380,43 +400,67 @@ typename std::enable_if::type compute_error (const Tensor& s, const std::vector>& g, const std::vector>& h, const SeparatedConvolution& f, - const std::vector>& regular_grid, + const std::vector>& regular_grid_Y, std::string name="") { double cpu0=cpu_time(); - double err_implicit= compute_error_implicitly(s,g,h,f,regular_grid); + double err_implicit= compute_error_implicitly(s,g,h,f,regular_grid_Y); double err=-1.0; double cpu1=cpu_time(); print("rank and error in f_approx_opt", g.size(), err,err_implicit, "after ",cpu1-cpu0); return err; }; +template +struct cartesian_grid { + Vector lovec,hivec; + std::vector stride; + long index=0; + long n_per_dim; + long total_n; + Vector increment; + + cartesian_grid(const long n_per_dim, const double lo, const double hi) + : n_per_dim(n_per_dim) { + lovec.fill(lo); + hivec.fill(hi); + increment=(hivec-lovec)*(1.0/double(n_per_dim-1)); + stride=std::vector(NDIM,1l); + total_n=std::pow(n_per_dim,NDIM); + for (long i=NDIM-2; i>=0; --i) stride[i]=n_per_dim*stride[i+1]; + } + + void operator++() { + index++; + } + + bool operator()() const { + return index < total_n; + } + + Vector get_coordinates() const { + Vector tmp(NDIM); + for (int idim=0; idim std::vector> uniformly_distributed_slater(World& world, const double lo, const double hi, const long n_per_dim) { - const long total_n=std::pow(n_per_dim,NDIM); Vector R; auto sl=[&R](const Vector& r) { return exp(-sqrt(inner(r-R,r-R)+1.e-3)); }; - Vector lovec,hivec; - lovec.fill(lo); - hivec.fill(hi); - Vector increment=(hivec-lovec)*(1.0/double(n_per_dim-1)); - std::vector> result(total_n); - std::vector stride(NDIM,1l); - // dim=5,5,5 - // stride=25,5,1 - for (long i=NDIM-2; i>=0; --i) stride[i]=n_per_dim*stride[i+1]; - for (long i=0; i tmp(NDIM); - for (int idim=0; idim(world).functor(sl); + std::vector> result; + cartesian_grid cg(n_per_dim,lo,hi); + for (auto c=cg; c(); ++c) { + R=c.get_coordinates(); + result.push_back(FunctionFactory(world).functor(sl)); } - return result; } @@ -429,29 +473,53 @@ int test_lowrank_function(World& world) { long n_per_dim=10; long ntrial=50; + + print("LDIM, n_per_dim, ntrial",LDIM,n_per_dim,ntrial); constexpr std::size_t NDIM=2*LDIM; - auto f=hidim(world); + Function phi=FunctionFactory(world) + .functor([](const Vector& r) {return exp(-2.0*inner(r,r));}); + +// auto f=hidim(world); + std::shared_ptr f12(SlaterOperatorPtr(world,1.0,1.e-4,FunctionDefaults::get_thresh())); + auto f=hidim_orbitals(f12,phi,phi); + + plot_plane<2*LDIM>(world,f,"hidim_orbitals"); + double radius=2.0; - auto regular_grid=uniformly_distributed_slater(world,-radius,radius,n_per_dim); - print("regular_grid.size()",regular_grid.size()); + double lo=-radius; + double hi=radius; + + + auto regular_grid_Y=uniformly_distributed_slater(world,lo,hi,n_per_dim); + + std::vector phi1_values(regular_grid_Y.size()); + cartesian_grid cg(n_per_dim,lo,hi); + for (auto c=cg; c(); ++c) { + auto R=c.get_coordinates(); + phi1_values[c.index]=phi(R); + } + scale(world,regular_grid_Y,phi1_values); + regular_grid_Y=regular_grid_Y*phi; + + print("regular_grid_Y.size()",regular_grid_Y.size()); LowRank lrf; - lrf.project(world,f,regular_grid,ntrial); + lrf.project(world,f,regular_grid_Y,ntrial); - lrf.compute_error(f,regular_grid); + lrf.compute_error(f,regular_grid_Y); lrf.orthonormalize_svd(); - lrf.compute_error(f,regular_grid); + lrf.compute_error(f,regular_grid_Y); plot_plane<2*LDIM>(world,lrf,"lrf0"); print("\nstarting optimization\n"); - lrf.optimize(f,regular_grid); + lrf.optimize(f,regular_grid_Y); - lrf.compute_error(f,regular_grid); + lrf.compute_error(f,regular_grid_Y); plot_plane<2*LDIM>(world,lrf,"lrf1"); @@ -526,7 +594,7 @@ int main(int argc, char **argv) { CCParameters ccparam(world, parser); - isuccess+= test_6d_convolution(world); +// isuccess+= test_6d_convolution(world); // std::shared_ptr ncf = create_nuclear_correlation_factor(world, // mol, nullptr, std::make_pair("slater", 2.0)); From 5377a4e048c62e85cecacfff3513dd87b5e1fd7d Mon Sep 17 00:00:00 2001 From: fbischoff Date: Thu, 27 Apr 2023 23:41:31 +0200 Subject: [PATCH 025/109] optimize_cd and orthonormalize_cd working (fast) --- src/madness/chem/test_low_rank_function.cc | 81 +++++++++++++++++++++- 1 file changed, 79 insertions(+), 2 deletions(-) diff --git a/src/madness/chem/test_low_rank_function.cc b/src/madness/chem/test_low_rank_function.cc index 6694c229832..4f224b70007 100644 --- a/src/madness/chem/test_low_rank_function.cc +++ b/src/madness/chem/test_low_rank_function.cc @@ -146,6 +146,7 @@ class LowRank { Tensor s; std::vector> g,h; + std::string orthonormalize_method="cd"; LowRank(Tensor& s, std::vector> g, std::vector> h) : s(s), g(g), h(h) {} @@ -201,12 +202,88 @@ class LowRank { t1.tag("Y backprojection"); } + void orthonormalize() { + if (orthonormalize_method=="svd") { + orthonormalize_svd(); + } else if (orthonormalize_method=="cd") { + /** + * |g >s< h| = |g_ortho> s < h | + * = |g_ortho> gg s < h | + * = |g_ortho> gg=matrix_inner(world,g_ortho,g); + for (int i=0; i ovlp = matrix_inner(world, g, g); + cholesky(ovlp); // destroys ovlp and gives back Upper ∆ Matrix from CD + Tensor L = transpose(ovlp); + Tensor Linv = inverse(L); + Tensor U = transpose(Linv); + g=transform(world, g, U); + h=transform(world, h, inverse(U)); + Tensor ovlp1 = matrix_inner(world, g, g); + Tensor ovlp2 = matrix_inner(world, h, h); + for (int i=0; i void optimize(const hidimT& f, const std::vector>& regular_grid_Y) { + if (orthonormalize_method=="svd") optimize_svd(f,regular_grid_Y); + else if (orthonormalize_method=="cd") optimize_cd(f,regular_grid_Y); + else { + MADNESS_EXCEPTION("confused orthonormalize_method in low_rank_function",1); + } + } + + /// following Halko, Algorithm 4.4 + template + void optimize_cd(const hidimT& f, const std::vector>& regular_grid_Y) { + World& world=g.front().world(); + double ssum=s.sum()/s.dim(0); + print("ssum in optimize_cd",ssum); + for (int iopt=0; iopt<8; ++iopt) { + timer t(world); + + auto Ytilde=orthonormalize_symmetric(form_inner(f,g)); + auto Y=orthonormalize_symmetric(form_inner(f,Ytilde)); // only correct if f is symmetric!!! + + g=Y; + h=form_inner(f,g); + orthonormalize(); + + plot_plane<2*LDIM>(world,*this,"lrf_iter"+std::to_string(iopt)); + if (iopt%2==0) compute_error(f,regular_grid_Y); + t.end("finished optimization iteration "+std::to_string(iopt)); + } + } + + template + void optimize_svd(const hidimT& f, const std::vector>& regular_grid_Y) { World& world=g.front().world(); for (int iopt=0; iopt<8; ++iopt) { timer t(world); @@ -220,7 +297,7 @@ class LowRank { g=gtmp; h=htmp; - if (g.size()>1) orthonormalize_svd(); + if (g.size()>1) orthonormalize(); plot_plane<2*LDIM>(world,*this,"lrf_iter"+std::to_string(iopt)); if (iopt%2==0) compute_error(f,regular_grid_Y); @@ -510,7 +587,7 @@ int test_lowrank_function(World& world) { lrf.project(world,f,regular_grid_Y,ntrial); lrf.compute_error(f,regular_grid_Y); - lrf.orthonormalize_svd(); + lrf.orthonormalize(); lrf.compute_error(f,regular_grid_Y); plot_plane<2*LDIM>(world,lrf,"lrf0"); From d603f28a6ea2a534ef344262241750f1c3d17187 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Wed, 3 May 2023 23:14:56 +0200 Subject: [PATCH 026/109] error computation works for 1D --- src/madness/chem/test_low_rank_function.cc | 564 ++++++++++++--------- 1 file changed, 331 insertions(+), 233 deletions(-) diff --git a/src/madness/chem/test_low_rank_function.cc b/src/madness/chem/test_low_rank_function.cc index 4f224b70007..6af410b9960 100644 --- a/src/madness/chem/test_low_rank_function.cc +++ b/src/madness/chem/test_low_rank_function.cc @@ -15,6 +15,104 @@ #include #include +template +typename std::enable_if::type compute_error_with_reconstruction(const Tensor& s, + const std::vector>& g, + const std::vector>& h, + const Function& f, + std::string name="") { + auto fapprox=s[0]*hartree_product(g[0],h[0]); + for (int i=1; i({f,fapprox,f-fapprox},name,std::vector({"adsf","asdf","diff"})); + return err; +}; + + +Tensor gaussian_random_distribution(double mean, double variance, long n) { + std::random_device rd{}; + std::mt19937 gen{rd()}; + std::normal_distribution<> d{mean, variance}; + Tensor result(n); + for (int i = 0; i < n; ++i) result(i)=d(gen); + return result; +} + + +Tensor random_factors(const long n, const long nran) { + Tensor factors(n,nran); + for (long i=0; i +std::vector> random_vectors(World &world, + const std::vector>& regular_grid_Y, + const long nran) { + Tensor factors=random_factors(regular_grid_Y.size(),nran); + /// Transforms a vector of functions according to new[i] = sum[j] old[j]*c[j,i] + return truncate(transform(world,regular_grid_Y,factors)); +}; + + +template +struct cartesian_grid { + Vector lovec,hivec; + std::vector stride; + long index=0; + long n_per_dim; + long total_n; + Vector increment; + + cartesian_grid(const long n_per_dim, const double lo, const double hi) + : n_per_dim(n_per_dim) { + lovec.fill(lo); + hivec.fill(hi); + increment=(hivec-lovec)*(1.0/double(n_per_dim-1)); + stride=std::vector(NDIM,1l); + total_n=std::pow(n_per_dim,NDIM); + for (long i=NDIM-2; i>=0; --i) stride[i]=n_per_dim*stride[i+1]; + } + + cartesian_grid(const cartesian_grid& other) : lovec(other.lovec), + hivec(other.hivec), stride(other.stride), index(0), n_per_dim(other.n_per_dim), + total_n(other.total_n), increment(other.increment) { + } + + cartesian_grid& operator=(const cartesian_grid& other) { + cartesian_grid tmp(other); + std::swap(*this,other); + return *this; + } + + double volume_per_gridpoint() const{ + double volume=1.0; + for (int i=0; i get_coordinates() const { + Vector tmp(NDIM); + for (int idim=0; idim struct gauss { double a=2.0; @@ -103,12 +201,16 @@ void orthonormalize_svd(World& world, std::vector>& g, std::vec template -std::vector> form_inner(const hidim_orbitals& f, const std::vector>& vec) { +std::vector> form_inner(const hidim_orbitals& f, const std::vector>& vec, + const bool transpose) { double cpu0=cpu_time(); World& world=vec.front().world(); - auto tmp1=vec*f.phi1; - std::vector> result=apply(world,(*f.f12),tmp1); - result=result*f.phi2; + std::vector> result; + if (transpose) { + result=f.phi1*apply(world,(*f.f12),vec*f.phi2); + } else { + result=f.phi2*apply(world,(*f.f12),vec*f.phi1); + } double cpu1=cpu_time(); std::printf("form inner finished after %4.2fs \n",cpu1-cpu0); return result; @@ -116,14 +218,30 @@ std::vector> form_inner(const hidim_orbitals& f, const std::vec // note that we assume f is symmetric!!!!! template -std::vector> form_inner(const Function& f, const std::vector>& vec) { +std::vector> form_inner(const Function& f, const std::vector>& vec, + const bool transpose) { double cpu0=cpu_time(); std::vector> result(vec.size()); - if constexpr (std::is_same,Function>::value) { - for (int i=0; i,Function>::value) { + for (int i=0; i,Function>::value) { + for (int i=0; i,Function>::value) { +// for (int i=0; i> form_inner(const Function& f, const std: // note that we assume f is symmetric!!!!! template -typename std::enable_if>>::type form_inner(const real_convolution_3d& f, const std::vector>& vec) { +typename std::enable_if>>::type form_inner(const real_convolution_3d& f, + const std::vector>& vec, const bool transpose) { double cpu0=cpu_time(); World& world=vec.front().world(); std::vector> result=apply(world,f,vec); @@ -140,6 +259,17 @@ typename std::enable_if>>::type form_inner( return result; } +template +std::vector> form_inner(const hidimT& hidim, const std::vector>& vec) { + return form_inner(hidim,vec,false); +} + +template +std::vector> form_inner_transpose(const hidimT& hidim, const std::vector>& vec) { + return form_inner(hidim,vec,true); +} + + template class LowRank { public: @@ -147,10 +277,13 @@ class LowRank { Tensor s; std::vector> g,h; std::string orthonormalize_method="cd"; + cartesian_grid cg; LowRank(Tensor& s, std::vector> g, std::vector> h) : s(s), g(g), h(h) {} + LowRank(const cartesian_grid& cg) : cg(cg) {} + // LowRank(World& world, long n) : world(world) { // g= zero_functions_compressed(world,n); // h= zero_functions_compressed(world,n); @@ -176,29 +309,46 @@ class LowRank { t1.tag("Yforming"); print("Y.size()",Y.size()); +// for (int i=0; i> g=orthonormalize_canonical(Y,1.e-8); g=orthonormalize_cd(Y); +// for (int i=0; i mos; - mos.set_mos(g); - std::vector set(g.size(),0); - mos.update_localize_set(set); - localizer.localize(mos,true); - g=mos.get_mos(); - t1.tag("Y localizing"); - } +// Localizer localizer; +// bool localize=false; +// if (localize) { +// localizer.set_method("boys"); +// MolecularOrbitals mos; +// mos.set_mos(g); +// std::vector set(g.size(),0); +// mos.update_localize_set(set); +// localizer.localize(mos,true); +// g=mos.get_mos(); +// t1.tag("Y localizing"); +// } - h=form_inner(f,g); + h=form_inner_transpose(f,g); s=Tensor(g.size()); s=1.0; +// orthonormalize(); + plot_plane<2*LDIM>(world,*this,"lrf00"); + auto rec=reconstruct(); + plot_plane<2*LDIM>(world,rec,"lrf00-rec"); t1.tag("Y backprojection"); } @@ -212,35 +362,24 @@ class LowRank { * = |g_ortho> gg=matrix_inner(world,g_ortho,g); for (int i=0; i ovlp = matrix_inner(world, g, g); - cholesky(ovlp); // destroys ovlp and gives back Upper ∆ Matrix from CD - Tensor L = transpose(ovlp); - Tensor Linv = inverse(L); - Tensor U = transpose(Linv); - g=transform(world, g, U); - h=transform(world, h, inverse(U)); - Tensor ovlp1 = matrix_inner(world, g, g); - Tensor ovlp2 = matrix_inner(world, h, h); - for (int i=0; i - void optimize(const hidimT& f, const std::vector>& regular_grid_Y) { - if (orthonormalize_method=="svd") optimize_svd(f,regular_grid_Y); - else if (orthonormalize_method=="cd") optimize_cd(f,regular_grid_Y); + void optimize(const hidimT& f, const std::vector>& regular_grid_Y, long nopt=2) { + if (orthonormalize_method=="svd") optimize_svd(f,regular_grid_Y,nopt); + else if (orthonormalize_method=="cd") optimize_cd(f,regular_grid_Y,nopt); else { MADNESS_EXCEPTION("confused orthonormalize_method in low_rank_function",1); } @@ -262,18 +401,18 @@ class LowRank { /// following Halko, Algorithm 4.4 template - void optimize_cd(const hidimT& f, const std::vector>& regular_grid_Y) { + void optimize_cd(const hidimT& f, const std::vector>& regular_grid_Y, long nopt) { World& world=g.front().world(); double ssum=s.sum()/s.dim(0); - print("ssum in optimize_cd",ssum); - for (int iopt=0; iopt<8; ++iopt) { + MADNESS_CHECK(fabs(ssum-1.0)<1.e-10); + for (int iopt=0; iopt(world,*this,"lrf_iter"+std::to_string(iopt)); @@ -283,16 +422,16 @@ class LowRank { } template - void optimize_svd(const hidimT& f, const std::vector>& regular_grid_Y) { + void optimize_svd(const hidimT& f, const std::vector>& regular_grid_Y, long nopt) { World& world=g.front().world(); - for (int iopt=0; iopt<8; ++iopt) { + for (int iopt=0; iopt> htmp(g.size()), gtmp(g.size()); for (int i=0; i& coord) const { Vector left,right; for (int i=0; i double compute_error(const hidimT& f, const std::vector>& regular_grid_Y) const { - const long ntrial=10; + const long ntrial=15; World& world=g.front().world(); timer t(world); - auto trial= random_vectors(world,regular_grid_Y,ntrial); - // result[j,1] = \sum_2 f(1,2) t(2,j) - \sum_2r g(1,r)s(r)h(r,2) t(2,j) - // ref[j,1] = \sum_2 f(1,2) t(2,j) - const std::vector> ref=form_inner(f,trial); + // omega(ngrid,ntrial) is a set of random vectors on a regular grid + Tensor omega=random_factors(regular_grid_Y.size(),ntrial); + /// Transforms a vector of functions according to new[i] = sum[j] old[j]*c[j,i] + /// A_omega(1,ntrial) + auto A_omega=transform(world,regular_grid_Y,omega); // this is Y +// print("A_omega.size()",A_omega.size()); + + auto QTAw=matrix_inner(world,g,A_omega); + auto QQTAw=transform(world,g,QTAw); + + // test orthonormality of g + auto gTg=matrix_inner(world,g,g); + for (int i=0; i Aapproxnorms(ntrial,0.0); +// std::vector> A_approx_omega; +// if (LDIM<2) { +// auto A_approx=reconstruct(); +// auto A_approx_omega=transform(world,regular_grid_Y,omega); // this is Y +// print("A_approx_omega.size()",A_approx_omega.size()); +// Aapproxnorms=norm2s(world,A_approx_omega); +// } - // check[j,1] = \sum_jr g(1,r)s(r)h(r,2) t(2,j) - Tensor ht=matrix_inner(world,h,trial); // ht(r,j) - for (int r=0; r> check=transform(world,g,ht); + MADNESS_CHECK(std::pow(cg.n_per_dim,LDIM)==regular_grid_Y.size()); - std::vector norms=norm2s(world,ref-check); - double max=*std::max_element(norms.begin(),norms.end()); - double err=10.0*sqrt(2.0/constants::pi)*max; + // h_delta_i = h_j(R_i) + print("volume per gridpoint",cg.volume_per_gridpoint()); + Tensor h_delta_i(g.size(),regular_grid_Y.size()); + auto c=cg; + for (int i=0; i h_omega=inner(h_delta_i,omega); +// print("h_omega.max",h_omega.absmax()); + + + /// Transforms a vector of functions according to new[i] = sum[j] old[j]*c[j,i] + // gh_omega(1,ntrial) + std::vector> gh_omega=transform(world,g,h_omega); // = QQ^T omega +// print("gh_omega.size()",gh_omega.size()); + + std::vector Anorms=norm2s(world,A_omega); +// print("A norms",Anorms); + + std::vector QQTAnorms=norm2s(world,QQTAw); +// print("QQT A norms",QQTAnorms); +// print("A approx norms",Aapproxnorms); + + std::vector ghnorms=norm2s(world,gh_omega); +// print("gh norms",ghnorms); + std::vector QQTA_norms=norm2s(world,A_omega-QQTAw); + std::vector A_gh_norms=norm2s(world,A_omega-gh_omega); +// std::vector A_Approx_norms=norm2s(world,Anorms,Aapproxnorms); +// std::vector Aapprox_gh_norms=norm2s(world,Aapproxnorms-gh_omega); +// print("(1-QQT) A norms ",QQTA_norms); +// print("A - gh diff norms ",A_gh_norms); +// print("A_approx - gh diff norms",A_Approx_norms); +// print("A - A_approx diff norms ",Aapprox_gh_norms); + double max_gh=*std::max_element(A_gh_norms.begin(),A_gh_norms.end()); + double err_gh=10.0*sqrt(2.0/constants::pi)*max_gh* cg.volume_per_gridpoint(); + double max_QQT=*std::max_element(QQTA_norms.begin(),QQTA_norms.end()); + double err_QQT=10.0*sqrt(2.0/constants::pi)*max_QQT* cg.volume_per_gridpoint(); std::stringstream ss; - ss << "rank and error in f_approx " << g.size() << " " << std::scientific << err; + ss << "rank and error in f_approx " << g.size() << " " << std::scientific << err_gh << "; QQTA: " << err_QQT; t.tag(ss.str()); - return err; - } + if (LDIM<2) compute_error_with_reconstruction(s,h,g,f,"name"); -// LowRank operator-(const LowRank& b) const { // Operator- necessary -// return LowRank(g-b.g,h-b.h); -// } -// -// LowRank& operator+=(const LowRank& b) { // Operator+= necessary -// g+=b.g; -// h+=b.h; -// return *this; -// } + return err_gh; + } + + Function reconstruct() const { + auto fapprox=s[0]*hartree_product(g[0],h[0]); + for (int i=1; i& a, const LowRank& b) { -Tensor gaussian_random_distribution(double mean, double variance, long n) { - std::random_device rd{}; - std::mt19937 gen{rd()}; - std::normal_distribution<> d{mean, variance}; - Tensor result(n); - for (int i = 0; i < n; ++i) result(i)=d(gen); - return result; -} - template typename std::enable_if<(LDIM==3), real_convolution_3d>::type hidim(World& world) { - auto f_op= SlaterOperator(world,1.0,1.e-6,FunctionDefaults<3>::get_thresh()); + auto f_op= SlaterOperator(world,1.0,1.e-8,0.1*FunctionDefaults<3>::get_thresh()); auto f12_functor=[](const Vector& r) { Vector r1,r2; for (int i=0; i>::type hidim(World& world) r1[i]=r[i]; r2[i]=r[i+LDIM]; } - return exp(-(r1-r2).normf())* exp(-0.2*inner(r,r)); + return exp(-(r1-r2).normf())* exp(-2.0*inner(r,r)); }; auto f=FunctionFactory(world).functor(f12_functor); plot_plane<2*LDIM>(world,f12_functor,"f12_functor"); @@ -414,127 +597,18 @@ typename std::enable_if<(LDIM<3), Function>::type hidim(World& world) return f; } -// nran random vectors on a regular grid -template -std::vector> random_vectors(World &world, - const std::vector>& regular_grid_Y, - const long nran) { - const long n = regular_grid_Y.size(); - Tensor factors(n,nran); - for (long i=0; i -double compute_error_implicitly(const Tensor& s, - const std::vector>& g, - const std::vector>& h, - const hidimT& f, - const std::vector>& regular_grid_Y) { - const long ntrial=10; - World& world=g.front().world(); - auto trial= random_vectors(world,regular_grid_Y,ntrial); - - // result[j,1] = \sum_2 f(1,2) t(2,j) - \sum_2r g(1,r)s(r)h(r,2) t(2,j) - // ref[j,1] = \sum_2 f(1,2) t(2,j) - const std::vector> ref=form_inner(f,trial); - - // check[j,1] = \sum_jr g(1,r)s(r)h(r,2) t(2,j) - Tensor ht=matrix_inner(world,h,trial); // ht(r,j) - for (int r=0; r> check=transform(world,g,ht); - - std::vector norms=norm2s(world,ref-check); - double max=*std::max_element(norms.begin(),norms.end()); - double err=10.0*sqrt(2.0/constants::pi)*max; - return err; - -} - -template -typename std::enable_if::type compute_error (const Tensor& s, - const std::vector>& g, - const std::vector>& h, - const Function& f, - const std::vector>& regular_grid_Y, - std::string name="") { - auto fapprox=s[0]*hartree_product(g[0],h[0]); - for (int i=1; i({f,fapprox,f-fapprox},name,std::vector({"adsf","asdf","diff"})); - return err; -}; - - -template -typename std::enable_if::type compute_error (const Tensor& s, - const std::vector>& g, - const std::vector>& h, - const SeparatedConvolution& f, - const std::vector>& regular_grid_Y, - std::string name="") { - double cpu0=cpu_time(); - double err_implicit= compute_error_implicitly(s,g,h,f,regular_grid_Y); - double err=-1.0; - double cpu1=cpu_time(); - print("rank and error in f_approx_opt", g.size(), err,err_implicit, "after ",cpu1-cpu0); - return err; -}; - -template -struct cartesian_grid { - Vector lovec,hivec; - std::vector stride; - long index=0; - long n_per_dim; - long total_n; - Vector increment; - - cartesian_grid(const long n_per_dim, const double lo, const double hi) - : n_per_dim(n_per_dim) { - lovec.fill(lo); - hivec.fill(hi); - increment=(hivec-lovec)*(1.0/double(n_per_dim-1)); - stride=std::vector(NDIM,1l); - total_n=std::pow(n_per_dim,NDIM); - for (long i=NDIM-2; i>=0; --i) stride[i]=n_per_dim*stride[i+1]; - } - - void operator++() { - index++; - } - - bool operator()() const { - return index < total_n; - } - - Vector get_coordinates() const { - Vector tmp(NDIM); - for (int idim=0; idim std::vector> uniformly_distributed_slater(World& world, - const double lo, const double hi, const long n_per_dim) { + cartesian_grid& cg) { Vector R; auto sl=[&R](const Vector& r) { - return exp(-sqrt(inner(r-R,r-R)+1.e-3)); + return exp(-sqrt(inner(r-R,r-R)+1.e-12)); }; std::vector> result; - cartesian_grid cg(n_per_dim,lo,hi); - for (auto c=cg; c(); ++c) { + auto c=cg; + c.index=0; + for (; c(); ++c) { R=c.get_coordinates(); result.push_back(FunctionFactory(world).functor(sl)); } @@ -546,59 +620,77 @@ int test_lowrank_function(World& world) { madness::default_random_generator.setstate(int(cpu_time())%4149); print(""); - constexpr std::size_t LDIM=3; - long n_per_dim=10; - long ntrial=50; + constexpr std::size_t LDIM=1; + long n_per_dim=80; + double radius=3.0; + long ntrial=40; print("LDIM, n_per_dim, ntrial",LDIM,n_per_dim,ntrial); constexpr std::size_t NDIM=2*LDIM; + timer t1(world); - Function phi=FunctionFactory(world) + Function phi1=FunctionFactory(world) .functor([](const Vector& r) {return exp(-2.0*inner(r,r));}); - -// auto f=hidim(world); - std::shared_ptr f12(SlaterOperatorPtr(world,1.0,1.e-4,FunctionDefaults::get_thresh())); - auto f=hidim_orbitals(f12,phi,phi); +// Function phi2=FunctionFactory(world) +// .functor([](const Vector& r) { +// Vector R; +// R.fill(1.0); +// return exp(-1.0*inner(r-R,r-R)); +// }); + Function phi2=copy(phi1); + + auto f=hidim(world); + std::shared_ptr f12(SlaterOperatorPtr(world,1.0,1.e-6,FunctionDefaults::get_thresh())); +// auto f=hidim_orbitals(f12,phi1,phi2); plot_plane<2*LDIM>(world,f,"hidim_orbitals"); - double radius=2.0; double lo=-radius; double hi=radius; - auto regular_grid_Y=uniformly_distributed_slater(world,lo,hi,n_per_dim); - - std::vector phi1_values(regular_grid_Y.size()); cartesian_grid cg(n_per_dim,lo,hi); + LowRank lrf(cg); + + auto regular_grid_Y=uniformly_distributed_slater(world,cg); +// for (int i=0; i phi2_values(regular_grid_Y.size()); for (auto c=cg; c(); ++c) { - auto R=c.get_coordinates(); - phi1_values[c.index]=phi(R); + phi2_values[c.index]=phi2(c.get_coordinates()); +// print("c.index, coord",c.index,c.get_coordinates(),phi2_values[c.index]); } - scale(world,regular_grid_Y,phi1_values); - regular_grid_Y=regular_grid_Y*phi; + scale(world,regular_grid_Y,phi2_values); + regular_grid_Y=regular_grid_Y*phi1; print("regular_grid_Y.size()",regular_grid_Y.size()); - LowRank lrf; lrf.project(world,f,regular_grid_Y,ntrial); + t1.tag("project"); lrf.compute_error(f,regular_grid_Y); lrf.orthonormalize(); lrf.compute_error(f,regular_grid_Y); + t1.tag("orthonormalize"); plot_plane<2*LDIM>(world,lrf,"lrf0"); print("\nstarting optimization\n"); - lrf.optimize(f,regular_grid_Y); + lrf.optimize(f,regular_grid_Y,8); + t1.tag("optimize"); lrf.compute_error(f,regular_grid_Y); plot_plane<2*LDIM>(world,lrf,"lrf1"); + t1.end("total time "); + return 0; } @@ -646,18 +738,24 @@ int main(int argc, char **argv) { startup(world, argc, argv); commandlineparser parser(argc, argv); FunctionDefaults<6>::set_tensor_type(TT_2D); - FunctionDefaults<3>::set_thresh(1.e-5); - FunctionDefaults<3>::set_cubic_cell(-1.0,1.0); - FunctionDefaults<1>::set_thresh(1.e-5); + + double thresh=1.e-5; + int k=6; + FunctionDefaults<1>::set_thresh(thresh); FunctionDefaults<1>::set_cubic_cell(-10.,10.); - FunctionDefaults<2>::set_thresh(1.e-4); + FunctionDefaults<1>::set_k(k); + FunctionDefaults<2>::set_thresh(thresh); FunctionDefaults<2>::set_cubic_cell(-10.,10.); - FunctionDefaults<3>::set_thresh(1.e-4); + FunctionDefaults<2>::set_k(k); + FunctionDefaults<3>::set_thresh(thresh); FunctionDefaults<3>::set_cubic_cell(-10.,10.); - FunctionDefaults<4>::set_thresh(1.e-4); + FunctionDefaults<3>::set_k(k); + FunctionDefaults<4>::set_thresh(thresh); FunctionDefaults<4>::set_cubic_cell(-10.,10.); - FunctionDefaults<6>::set_thresh(1.e-3); + FunctionDefaults<4>::set_k(k); + FunctionDefaults<6>::set_thresh(thresh); FunctionDefaults<6>::set_cubic_cell(-10.,10.); + FunctionDefaults<6>::set_k(k); print("numerical parameters: k, eps(3D), eps(6D)", FunctionDefaults<3>::get_k(), FunctionDefaults<3>::get_thresh(), FunctionDefaults<6>::get_thresh()); int isuccess=0; From 5c71438c3885da3cc9f95b037041d75bf3ee5cd5 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Fri, 5 May 2023 19:22:48 +0200 Subject: [PATCH 027/109] code works for asymmetric case phi(x) neq phi(y) --- src/madness/chem/test_low_rank_function.cc | 66 +++++++++++++--------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/src/madness/chem/test_low_rank_function.cc b/src/madness/chem/test_low_rank_function.cc index 6af410b9960..210d374098e 100644 --- a/src/madness/chem/test_low_rank_function.cc +++ b/src/madness/chem/test_low_rank_function.cc @@ -207,9 +207,9 @@ std::vector> form_inner(const hidim_orbitals& f, const std::vec World& world=vec.front().world(); std::vector> result; if (transpose) { - result=f.phi1*apply(world,(*f.f12),vec*f.phi2); - } else { result=f.phi2*apply(world,(*f.f12),vec*f.phi1); + } else { + result=f.phi1*apply(world,(*f.f12),vec*f.phi2); } double cpu1=cpu_time(); std::printf("form inner finished after %4.2fs \n",cpu1-cpu0); @@ -346,9 +346,9 @@ class LowRank { s=Tensor(g.size()); s=1.0; // orthonormalize(); - plot_plane<2*LDIM>(world,*this,"lrf00"); - auto rec=reconstruct(); - plot_plane<2*LDIM>(world,rec,"lrf00-rec"); +// plot_plane<2*LDIM>(world,*this,"lrf00"); +// auto rec=reconstruct(); +// plot_plane<2*LDIM>(world,rec,"lrf00-rec"); t1.tag("Y backprojection"); } @@ -415,7 +415,7 @@ class LowRank { h=form_inner_transpose(f,g); orthonormalize(); - plot_plane<2*LDIM>(world,*this,"lrf_iter"+std::to_string(iopt)); +// plot_plane<2*LDIM>(world,*this,"lrf_iter"+std::to_string(iopt)); if (iopt%2==0) compute_error(f,regular_grid_Y); t.end("finished optimization iteration "+std::to_string(iopt)); } @@ -437,7 +437,7 @@ class LowRank { h=htmp; if (g.size()>1) orthonormalize(); - plot_plane<2*LDIM>(world,*this,"lrf_iter"+std::to_string(iopt)); +// plot_plane<2*LDIM>(world,*this,"lrf_iter"+std::to_string(iopt)); if (iopt%2==0) compute_error(f,regular_grid_Y); t.end("finished optimization iteration "+std::to_string(iopt)); @@ -539,7 +539,7 @@ class LowRank { ss << "rank and error in f_approx " << g.size() << " " << std::scientific << err_gh << "; QQTA: " << err_QQT; t.tag(ss.str()); - if (LDIM<2) compute_error_with_reconstruction(s,h,g,f,"name"); + if constexpr (LDIM<2) compute_error_with_reconstruction(s,h,g,f,"name"); return err_gh; } @@ -620,10 +620,10 @@ int test_lowrank_function(World& world) { madness::default_random_generator.setstate(int(cpu_time())%4149); print(""); - constexpr std::size_t LDIM=1; - long n_per_dim=80; - double radius=3.0; - long ntrial=40; + constexpr std::size_t LDIM=3; + long n_per_dim=10; + double radius=2.0; + long ntrial=80; @@ -631,19 +631,28 @@ int test_lowrank_function(World& world) { constexpr std::size_t NDIM=2*LDIM; timer t1(world); - Function phi1=FunctionFactory(world) + Function phi_slater=FunctionFactory(world) + .functor([](const Vector& r) {return exp(-2.0*r.normf());}); + + Function phi_gauss=FunctionFactory(world) .functor([](const Vector& r) {return exp(-2.0*inner(r,r));}); -// Function phi2=FunctionFactory(world) -// .functor([](const Vector& r) { -// Vector R; -// R.fill(1.0); -// return exp(-1.0*inner(r-R,r-R)); -// }); - Function phi2=copy(phi1); - - auto f=hidim(world); + + Function one=FunctionFactory(world) + .functor([](const Vector& r) {return 1.0;}); + + Function phi_gauss_displaced=FunctionFactory(world) + .functor([](const Vector& r) { + Vector R; + R.fill(0.5); + return exp(-1.0*inner(r-R,r-R)); + }); + + Function phi1=copy(phi_slater); + Function phi2=copy(one); + +// auto f=hidim(world); std::shared_ptr f12(SlaterOperatorPtr(world,1.0,1.e-6,FunctionDefaults::get_thresh())); -// auto f=hidim_orbitals(f12,phi1,phi2); + auto f=hidim_orbitals(f12,phi1,phi2); plot_plane<2*LDIM>(world,f,"hidim_orbitals"); @@ -675,15 +684,16 @@ int test_lowrank_function(World& world) { t1.tag("project"); lrf.compute_error(f,regular_grid_Y); - lrf.orthonormalize(); - lrf.compute_error(f,regular_grid_Y); - t1.tag("orthonormalize"); +// lrf.orthonormalize(); +// lrf.compute_error(f,regular_grid_Y); + t1.tag("compute error"); plot_plane<2*LDIM>(world,lrf,"lrf0"); + t1.tag("plot lrf0"); print("\nstarting optimization\n"); - lrf.optimize(f,regular_grid_Y,8); + lrf.optimize(f,regular_grid_Y,2); t1.tag("optimize"); lrf.compute_error(f,regular_grid_Y); @@ -739,7 +749,7 @@ int main(int argc, char **argv) { commandlineparser parser(argc, argv); FunctionDefaults<6>::set_tensor_type(TT_2D); - double thresh=1.e-5; + double thresh=1.e-4; int k=6; FunctionDefaults<1>::set_thresh(thresh); FunctionDefaults<1>::set_cubic_cell(-10.,10.); From 15f813e17705ddd057afcb5ac91fe7309caa523e Mon Sep 17 00:00:00 2001 From: fbischoff Date: Sun, 7 May 2023 12:21:28 +0200 Subject: [PATCH 028/109] working on K operator in low rank form --- src/madness/chem/test_low_rank_function.cc | 67 +++++++++++++++++++++- 1 file changed, 65 insertions(+), 2 deletions(-) diff --git a/src/madness/chem/test_low_rank_function.cc b/src/madness/chem/test_low_rank_function.cc index 210d374098e..cccd665e37a 100644 --- a/src/madness/chem/test_low_rank_function.cc +++ b/src/madness/chem/test_low_rank_function.cc @@ -291,7 +291,8 @@ class LowRank { LowRank() =default; // Default constructor necessary for storage in vector - LowRank(const LowRank& a) : s(a.s), g(copy(a.g.front().world(),a.g)), h(copy(a.h.front().world(),a.h)) {} // Copy constructor necessary + LowRank(const LowRank& a) : s(copy(a.s)), g(copy(a.g.front().world(),a.g)), + h(copy(a.h.front().world(),a.h)), cg(a.cg) {} // Copy constructor necessary LowRank& operator=(const LowRank& f) { // Assignment required for storage in vector LowRank ff(f); @@ -616,6 +617,47 @@ std::vector> uniformly_distributed_slater(World& world, } +real_function_6d K(World& world, const real_function_6d& f, const real_function_3d& phi) { + + print("entering K(real_function_6d)"); + timer t1(world); + const int particle=1; + real_convolution_3d op = CoulombOperator(world, 0.0001, FunctionDefaults<3>::get_thresh()); + op.destructive() = true; + op.particle() = particle; + + real_function_6d x = multiply(copy(f), copy(phi), particle).truncate(); + t1.tag("multiply before"); + x = op(x).truncate(); + t1.tag("apply G"); + real_function_6d result = multiply(x, copy(phi), particle).truncate(); + t1.tag("multiply after"); + + return result; +} + +template +LowRank K(World& world, const LowRank& f, const Function& phi) { + + print("entering K(LowRank)"); + timer t1(world); + const int particle=1; + real_convolution_3d op = CoulombOperator(world, 0.0001, FunctionDefaults<3>::get_thresh()); + op.destructive() = true; + op.particle() = particle; + + auto tmp=truncate(mul(world,phi,f.g)); + t1.tag("multiply before"); + auto x = apply(world,op,tmp); + t1.tag("apply G"); + auto g_final=mul(world,phi,x); + t1.tag("multiply after"); + LowRank result=f; + result.g=g_final; + + return result; +} + int test_lowrank_function(World& world) { madness::default_random_generator.setstate(int(cpu_time())%4149); @@ -623,7 +665,7 @@ int test_lowrank_function(World& world) { constexpr std::size_t LDIM=3; long n_per_dim=10; double radius=2.0; - long ntrial=80; + long ntrial=120; @@ -701,6 +743,27 @@ int test_lowrank_function(World& world) { t1.end("total time "); + real_function_6d f12f=TwoElectronFactory(world).slater(); + real_function_6d full_f=CompositeFactory(world).g12(f12f) + .particle1(copy(phi1)).particle2(copy(-1.0*phi2)); + full_f.fill_cuspy_tree(); + plot_plane<2*LDIM>(world,full_f,"full_f"); + + auto lrf_reconstruct=lrf.reconstruct(); + auto diff=(lrf_reconstruct-full_f).norm2(); + print("diff(lrf-full_f) ",diff); + + // apply K + auto klrf=K(world,lrf,phi1); + plot_plane<2*LDIM>(world,klrf,"Klrf"); + auto kfull_f=K(world,full_f,phi1); + plot_plane<2*LDIM>(world,kfull_f,"Kfull_f"); + + auto klrf_reconstruct=klrf.reconstruct(); + auto kdiff=(klrf_reconstruct-kfull_f).norm2(); + print("diff(K(lrf)-K(full_f)) ",kdiff); + + return 0; } From 6879f5c1a430517534eca60e3070783209e105f0 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Wed, 2 Aug 2023 13:17:30 -0400 Subject: [PATCH 029/109] fixes --- src/apps/mp2/mp2.cc | 5 +---- src/madness/chem/CCPotentials.h | 4 ++-- src/madness/chem/mp2.cc | 7 ------- src/madness/chem/mp2.h | 2 -- src/madness/mra/mra.h | 10 ---------- 5 files changed, 3 insertions(+), 25 deletions(-) diff --git a/src/apps/mp2/mp2.cc b/src/apps/mp2/mp2.cc index e0d6d638040..b15de2ba34c 100644 --- a/src/apps/mp2/mp2.cc +++ b/src/apps/mp2/mp2.cc @@ -80,8 +80,6 @@ int main(int argc, char** argv) { if (world.rank() == 0) printf("\nstarting at time %.1fs\n", wall_time()); - if (do_test) mp2.test(testfilename); - else { const double hf_energy=mp2.get_hf().value(); const double mp2_energy=mp2.value(); // const double mp2_energy=0.0; @@ -96,8 +94,7 @@ int main(int argc, char** argv) { printf("final hf/mp3/total energy %12.8f %12.8f %12.8f\n", hf_energy,mp3_energy,hf_energy+mp3_energy); } - } - } catch (std::exception& e) { + } catch (std::exception& e) { if (world.rank() == 0) { print("\ncaught an exception: \n", e.what()); diff --git a/src/madness/chem/CCPotentials.h b/src/madness/chem/CCPotentials.h index 13c09886758..18d4c227cd3 100644 --- a/src/madness/chem/CCPotentials.h +++ b/src/madness/chem/CCPotentials.h @@ -794,9 +794,9 @@ class CCPotentials { // update the intermediates void update_intermediates(const CC_vecfunction& t) { - g12.update_elements(mo_bra_, t); + g12->update_elements(mo_bra_, t); // g12.sanity(); - f12.update_elements(mo_bra_, t); + f12->update_elements(mo_bra_, t); // f12.sanity(); } diff --git a/src/madness/chem/mp2.cc b/src/madness/chem/mp2.cc index e9a867f8577..440b446ed94 100644 --- a/src/madness/chem/mp2.cc +++ b/src/madness/chem/mp2.cc @@ -708,13 +708,6 @@ double MP2::asymmetry(const real_function_6d& f, const std::string s) const { return diff; } -void MP2::test(const std::string filename) { - if (world.rank() == 0) - printf("starting coupling at time %8.1fs\n", wall_time()); - if (world.rank() == 0) - printf("ending coupling at time %8.1fs\n", wall_time()); -} - /// compute the matrix element /// scales quartically. I think I can get this down to cubically by diff --git a/src/madness/chem/mp2.h b/src/madness/chem/mp2.h index d58faadd827..2f1656b9861 100644 --- a/src/madness/chem/mp2.h +++ b/src/madness/chem/mp2.h @@ -507,8 +507,6 @@ class MP2 : public OptimizationTargetInterface, public QCPropertyInterface { double asymmetry(const real_function_6d& f, const std::string s) const; - void test(const std::string filename); - /// compute the matrix element /// scales quartically. I think I can get this down to cubically by diff --git a/src/madness/mra/mra.h b/src/madness/mra/mra.h index af7e2f1332c..5cca91c44b4 100644 --- a/src/madness/mra/mra.h +++ b/src/madness/mra/mra.h @@ -2138,7 +2138,6 @@ namespace madness { if (op.modified()) { - MADNESS_ASSERT(not op.is_slaterf12); ff.get_impl()->make_redundant(true); result = apply_only(op, ff, fence); ff.get_impl()->undo_redundant(false); @@ -2146,14 +2145,6 @@ namespace madness { } else { - // the slaterf12 function is - // 1/(2 mu) \int d1 (1 - exp(- mu r12)) f(1) - // = 1/(2 mu) (f.trace() - \int d1 exp(-mu r12) f(1) ) - // f.trace() is just a number - R ftrace=0.0; - if (op.is_slaterf12) ftrace=f.trace(); -// print("ftrace",ftrace); - // saves the standard() step, which is very expensive in 6D // Function fff=copy(ff); Function fff=(ff); @@ -2185,7 +2176,6 @@ namespace madness { } else { ff.standard(); } - if (op.is_slaterf12) result=(result-ftrace).scale(-0.5/op.mu()); } if (print_timings) result.print_size("result after reconstruction"); From 88b2443381a09ad203f7fa6d120ac5c536722099 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Fri, 4 Aug 2023 13:02:19 -0400 Subject: [PATCH 030/109] update --- src/madness/chem/test_ccpairfunction.cc | 360 +++++++++++++++++++++ src/madness/chem/test_low_rank_function.cc | 7 +- 2 files changed, 361 insertions(+), 6 deletions(-) diff --git a/src/madness/chem/test_ccpairfunction.cc b/src/madness/chem/test_ccpairfunction.cc index a43cf338f2a..629e6fa131a 100644 --- a/src/madness/chem/test_ccpairfunction.cc +++ b/src/madness/chem/test_ccpairfunction.cc @@ -15,6 +15,24 @@ using namespace madness; +template +struct randomgaussian { + Vector random_origin; + double exponent; + double radius=2; + randomgaussian(double exponent, double radius) : exponent(exponent), radius(radius) { + Vector ran; // [0,1] + RandomVector(NDIM,ran.data()); + random_origin=2.0*radius*ran-Vector(radius); +// print("origin at ",random_origin, ", exponent",exponent); + } + double operator()(const Vector& r) const { +// return exp(-exponent*inner(r-random_origin,r-random_origin)); + return exp(-exponent*(r-random_origin).normf()); + } + +}; + bool longtest=false; struct data { @@ -99,6 +117,347 @@ struct data { data data1; +template +class LowRank { +public: + + struct LRFunctor { + LRFunctor() = default; + + Function f; + std::shared_ptr> f12; + Function a,b; + }; + + World& world; + std::vector> g,h; + LRFunctor lrfunctor; + + /// construct from the hi-dim function f + LowRank(const Function& f) : world(f.world()) { + lrfunctor.f=f; + } + + /// construct from the hi-dim function f12*a(1)(b(2) + LowRank(const std::shared_ptr> f12, const Function& a, + const Function& b) : world(a.world) { + lrfunctor.a=a; + lrfunctor.b=b; + lrfunctor.f12=f12; + } + + LowRank(std::vector> g, std::vector> h) + : world(g.front().world()), g(g), h(h) {} + + LowRank(const LowRank& a) : world(a.world), g(copy(world,a.g)), h(copy(world,a.h)) {} // Copy constructor necessary + + LowRank& operator=(const LowRank& f) { // Assignment required for storage in vector + LowRank ff(f); + std::swap(ff.g,g); + std::swap(ff.h,h); + return *this; + } + + LowRank operator-(const LowRank& b) const { // Operator- necessary + return LowRank(g-b.g,h-b.h); + } + + LowRank& operator+=(const LowRank& b) { // Operator+= necessary + g+=b.g; + h+=b.h; + return *this; + } + + LowRank operator*(double a) const { // Scale by a constant necessary + return LowRank(g*a,h); + } + + LowRank multiply(const std::vector>& vec, const long particle) { + auto result=*this; // deep copy + if (particle==0) result.g=g*vec; + if (particle==1) result.h=h*vec; + return *this; + } + + /// following Halko + + /// ||A - Q Q^T A||< epsilon + /// Y = A Omega && Q = QR(Y) + /// || f(1,2) - \sum_i g_i(1) h_i(2) || < epsilon + /// Y_i(1) = \int f(1,2) Omega_i(2) d2 && g_i(1) = QR(Y_i(1)) && h_i(2) = \int g_i^*(1) f(1,2) d1 + void project(const long rank, const double radius=3.0) { + timer t1(world); + std::vector> omega2(rank); + for (long i=0; i(world).functor(randomgaussian(RandomValue()+3,radius)); + } + t1.tag("projection 1D functions"); + + std::vector> Y(rank); + + if constexpr (NDIM==1) for (int i=0; i reconstruct() const { + auto fapprox=hartree_product(g[0],h[0]); + for (int i=1; i orthonormalize(const bool s_in_h) { + timer t(world); + /** + * |g >< h| = |g_ortho> < h | h_ortho > gg hh U s VT > g_ortho=orthonormalize_canonical(g,1.e-8); + std::vector> h_ortho=orthonormalize_canonical(h,1.e-8); + auto gg=matrix_inner(world,g_ortho,g); + auto hh=matrix_inner(world,h,h_ortho); + auto ovlp=inner(gg,hh); + Tensor U,VT; + Tensor s; + svd(ovlp,U,s,VT); + auto V=transpose(VT); + + // truncate +// for (int i=1; i> htmp(g.size()), gtmp(g.size()); + for (int j=0; j1) s=orthonormalize(true); + + if (iopt%2==1) { + double err=error(); + print("optimization iteration",iopt,", error in f_approx_opt",err); + } + } + t.tag("optimize"); + } + + double explicit_error() const { + auto fapprox=reconstruct(); + return (lrfunctor.f-fapprox).norm2(); + } + + double randomized_error() const { + return 1.e9; + } + + double error() const { + if (NDIM<3) return explicit_error(); + else return randomized_error(); + } + +// double get() const {return x;} +}; + +// This interface is necessary to compute inner products +template +double inner(const LowRank& a, const LowRank& b) { + World& world=a.world; + return (matrix_inner(world,a.g,b.g).emul(matrix_inner(world,a.h,b.h))).sum(); +} + + + +/// Computes the electrostatic potential due to a Gaussian charge distribution + +/// stolen from testsuite.cc +class GaussianPotential : public FunctionFunctorInterface { +public: + typedef Vector coordT; + const coordT center; + const double exponent; + const double coefficient; + + GaussianPotential(const coordT& center, double expnt, double coefficient) + : center(center) + , exponent(sqrt(expnt)) + , coefficient(coefficient*pow(constants::pi/exponent,1.5)*pow(expnt,-0.75)) {} + + double operator()(const coordT& x) const { + double sum = 00; + for (int i=0; i<3; ++i) { + double xx = center[i]-x[i]; + sum += xx*xx; + }; + double r = sqrt(sum); + if (r<1.e-4) { // correct thru order r^3 + const double sqrtpi=sqrt(constants::pi); + const double a=exponent; + return coefficient*(2.0*a/sqrtpi - 2.0*a*a*a*r*r/(3.0*sqrtpi)); + } else { + return coefficient*erf(exponent*r)/r; + } + } +}; + +int test_lowrank_function(World& world) { + test_output t1("CCPairFunction::low rank function"); + t1.set_cout_to_terminal(); + madness::default_random_generator.setstate(int(cpu_time())%4149); + + constexpr std::size_t LDIM=1; + constexpr std::size_t NDIM=2*LDIM; + + Function f12=FunctionFactory(world).functor([&LDIM](const Vector& r) + { + Vector r1,r2; + for (int i=0; i phi0=FunctionFactory(world).functor([&LDIM](const Vector& r) + { + Vector r1,r2; + for (int i=0; i phi1=FunctionFactory(world).functor([&LDIM](const Vector& r) + { + Vector r1,r2; + for (int i=0; i f = phi0*phi1; +// f= f *f12; + + double norm=f12.norm2(); + print("norm",norm); + phi0.reconstruct(); + f12.reconstruct(); + Function reference=inner(phi0,f12,{0},{0}); + return 0; + + if (0) { + Function f; + double fnorm = f.norm2(); + print("norm(2D-f)", fnorm); + t1.checkpoint(true, "hi-dim projection"); + + long rank = 50; + double radius = 5.0; + + LowRank lr(copy(f)); + lr.project(rank, radius); + double err = lr.error(); + print("error in f_approx", err); + lr.orthonormalize(true); + t1.checkpoint(true, "start stuff"); + + err = lr.error(); + print("error in f_approx", err); + t1.checkpoint(true, "compute error"); + if (LDIM < 3) { + auto fapprox = lr.reconstruct(); + plot({f, fapprox, f - fapprox}, "f_and_approx", std::vector({"adsf", "asdf", "diff"})); + t1.checkpoint(true, "plotting"); + } + + /* + * optimize + */ + + lr.optimize(2); + t1.checkpoint(true, "optimization"); + + + err = lr.error(); + print("error in f_approx_opt", err); + + if (LDIM < 3) { + auto fapprox = lr.reconstruct(); + plot({f, fapprox, f - fapprox}, "f_and_approx_opt", + std::vector({"adsf", "asdf", "diff"})); + t1.checkpoint(true, "plotting"); + } + + /// int f(1,2) f12(2,3) d2 + f12.print_tree(); + auto reference=inner(f,f12,{1},{0}); + auto hbar=copy(world,lr.h); + for (auto& hh : hbar) hh=inner(f12,hh,{0},{0}); + auto result=lr; + result.h=hbar; + auto reference_approx=result.reconstruct(); + result.lrfunctor.f=reference; + double error=result.error(); + print("error ",error); + plot({reference, reference_approx, reference-reference_approx}, "contraction", std::vector({"adsf", "asdf", "diff"})); + } + +// auto result= + + + + + return t1.end(); +} + int test_constructor(World& world, std::shared_ptr ncf, const Molecule& molecule, const CCParameters& parameter) { test_output t1("CCPairFunction::constructor"); @@ -963,6 +1322,7 @@ int main(int argc, char **argv) { FunctionDefaults<1>::set_cubic_cell(-10.,10.); FunctionDefaults<2>::set_thresh(1.e-4); FunctionDefaults<2>::set_cubic_cell(-10.,10.); + FunctionDefaults<2>::set_tensor_type(TT_FULL); FunctionDefaults<3>::set_thresh(1.e-4); FunctionDefaults<3>::set_cubic_cell(-10.,10.); FunctionDefaults<4>::set_thresh(1.e-4); diff --git a/src/madness/chem/test_low_rank_function.cc b/src/madness/chem/test_low_rank_function.cc index cccd665e37a..e5ad6cb6e5b 100644 --- a/src/madness/chem/test_low_rank_function.cc +++ b/src/madness/chem/test_low_rank_function.cc @@ -284,11 +284,6 @@ class LowRank { LowRank(const cartesian_grid& cg) : cg(cg) {} -// LowRank(World& world, long n) : world(world) { -// g= zero_functions_compressed(world,n); -// h= zero_functions_compressed(world,n); -// } - LowRank() =default; // Default constructor necessary for storage in vector LowRank(const LowRank& a) : s(copy(a.s)), g(copy(a.g.front().world(),a.g)), @@ -662,7 +657,7 @@ int test_lowrank_function(World& world) { madness::default_random_generator.setstate(int(cpu_time())%4149); print(""); - constexpr std::size_t LDIM=3; + constexpr std::size_t LDIM=1; long n_per_dim=10; double radius=2.0; long ntrial=120; From cbab1b433244757cb4e980e3b46b79767d63b445 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Wed, 9 Aug 2023 14:45:41 -0400 Subject: [PATCH 031/109] first impression of low-rank integration looks good --- src/madness/chem/test_ccpairfunction.cc | 167 +++++++++++++++++------- src/madness/mra/funcplot.h | 2 +- 2 files changed, 122 insertions(+), 47 deletions(-) diff --git a/src/madness/chem/test_ccpairfunction.cc b/src/madness/chem/test_ccpairfunction.cc index 629e6fa131a..490256aa5d5 100644 --- a/src/madness/chem/test_ccpairfunction.cc +++ b/src/madness/chem/test_ccpairfunction.cc @@ -117,36 +117,38 @@ struct data { data data1; -template +template class LowRank { public: struct LRFunctor { LRFunctor() = default; - Function f; - std::shared_ptr> f12; - Function a,b; + Function f; + std::shared_ptr> f12; + Function a,b; }; World& world; - std::vector> g,h; + std::vector> g,h; LRFunctor lrfunctor; + LowRank(World& world) : world(world) {}; + /// construct from the hi-dim function f - LowRank(const Function& f) : world(f.world()) { + LowRank(const Function& f) : world(f.world()) { lrfunctor.f=f; } /// construct from the hi-dim function f12*a(1)(b(2) - LowRank(const std::shared_ptr> f12, const Function& a, - const Function& b) : world(a.world) { + LowRank(const std::shared_ptr> f12, const Function& a, + const Function& b) : world(a.world) { lrfunctor.a=a; lrfunctor.b=b; lrfunctor.f12=f12; } - LowRank(std::vector> g, std::vector> h) + LowRank(std::vector> g, std::vector> h) : world(g.front().world()), g(g), h(h) {} LowRank(const LowRank& a) : world(a.world), g(copy(world,a.g)), h(copy(world,a.h)) {} // Copy constructor necessary @@ -172,7 +174,7 @@ class LowRank { return LowRank(g*a,h); } - LowRank multiply(const std::vector>& vec, const long particle) { + LowRank multiply(const std::vector>& vec, const long particle) { auto result=*this; // deep copy if (particle==0) result.g=g*vec; if (particle==1) result.h=h*vec; @@ -187,17 +189,17 @@ class LowRank { /// Y_i(1) = \int f(1,2) Omega_i(2) d2 && g_i(1) = QR(Y_i(1)) && h_i(2) = \int g_i^*(1) f(1,2) d1 void project(const long rank, const double radius=3.0) { timer t1(world); - std::vector> omega2(rank); + std::vector> omega2(rank); for (long i=0; i(world).functor(randomgaussian(RandomValue()+3,radius)); + omega2[i]=FunctionFactory(world).functor(randomgaussian(RandomValue()+3,radius)); } t1.tag("projection 1D functions"); - std::vector> Y(rank); + std::vector> Y(rank); - if constexpr (NDIM==1) for (int i=0; i reconstruct() const { + Function reconstruct() const { auto fapprox=hartree_product(g[0],h[0]); for (int i=1; i gg hh U s VT > g_ortho=orthonormalize_canonical(g,1.e-8); - std::vector> h_ortho=orthonormalize_canonical(h,1.e-8); + std::vector> g_ortho=orthonormalize_canonical(g,1.e-8); + std::vector> h_ortho=orthonormalize_canonical(h,1.e-8); auto gg=matrix_inner(world,g_ortho,g); auto hh=matrix_inner(world,h,h_ortho); auto ovlp=inner(gg,hh); @@ -264,17 +266,18 @@ class LowRank { timer t(world); auto s=orthonormalize(true); for (int iopt=0; iopt> htmp(g.size()), gtmp(g.size()); + std::vector> gtmp(g.size()); for (int j=0; j> htmp(g.size()); for (int j=0; j& a, const LowRank& b) { +template +LowRank inner(const Function& lhs, const LowRank& rhs, const std::tuple v1, const std::tuple v2) { + World& world=rhs.world; + // int lhs(1,2) rhs(2,3) d2 = \sum \int lhs(1,2) g_i(2) h_i(3) d2 + // = \sum \int lhs(1,2) g_i(2) d2 h_i(3) + LowRank result(world); + result.h=rhs.h; + decltype(rhs.g) g; + for (int i=0; i +LowRank inner(const LowRank& f, const Function& g, const std::tuple v1, const std::tuple v2) { + World& world=f.world; + // int f(1,2) k(2,3) d2 = \sum \int g_i(1) h_i(2) k(2,3) d2 + // = \sum g_i(1) \int h_i(2) k(2,3) d2 + LowRank result(world); + result.g=f.g; + decltype(f.h) h; + for (int i=0; i::get_thresh(),FunctionDefaults::get_k(),NDIM); Function f12=FunctionFactory(world).functor([&LDIM](const Vector& r) { @@ -381,18 +417,45 @@ int test_lowrank_function(World& world) { } return exp(-(r2).normf());//* exp(-0.2*inner(r1,r1)); }); + Function one=FunctionFactory(world) + .functor([&LDIM](const Vector& r){ return 1.0; }); // f(1,2) = f12 * phi(1) * phi(2) -// Function f = phi0*phi1; -// f= f *f12; + Function f = phi0*phi1 *f12; + print("lhs = phi0 * phi1; rhs=phi0*f12"); + auto lhs=phi0*phi1; + auto rhs=phi0*f12; + auto rhsnorm=rhs.norm2(); + - double norm=f12.norm2(); - print("norm",norm); phi0.reconstruct(); f12.reconstruct(); - Function reference=inner(phi0,f12,{0},{0}); - return 0; + Function reference=inner(lhs,rhs,{0},{0}); + LowRank lrf(rhs); + lrf.project(50,3.0); + lrf.optimize(); + + double ferror=lrf.error(); + print("fnorm, error, rel. error",rhsnorm,ferror,ferror/rhsnorm); + + auto result=inner(lhs,lrf,{0},{0}); + double refnorm=reference.norm2(); + + auto reconstruct=result.reconstruct(); + auto diff=reference-reconstruct; + + double resultnorm=reconstruct.norm2(); + double diffnorm=diff.norm2(); + print("refnorm, resultnorm ",refnorm, resultnorm); + print("resultnorm, error, rel. error",resultnorm,diffnorm,diffnorm/resultnorm); + print("final - one: k,thresh ",FunctionDefaults<2>::get_k(),FunctionDefaults<2>::get_thresh(), + ferror/rhsnorm, diffnorm/resultnorm); + print("\n"); + + plot({reference, reconstruct, diff}, "f_and_approx", std::vector({"adsf", "asdf", "diff"})); + +// return 0; if (0) { Function f; double fnorm = f.norm2(); @@ -402,7 +465,7 @@ int test_lowrank_function(World& world) { long rank = 50; double radius = 5.0; - LowRank lr(copy(f)); + LowRank lr(copy(f)); lr.project(rank, radius); double err = lr.error(); print("error in f_approx", err); @@ -436,6 +499,7 @@ int test_lowrank_function(World& world) { t1.checkpoint(true, "plotting"); } + /// int f(1,2) f12(2,3) d2 f12.print_tree(); auto reference=inner(f,f12,{1},{0}); @@ -1313,20 +1377,31 @@ int main(int argc, char **argv) { madness::World& world = madness::initialize(argc, argv); startup(world, argc, argv); commandlineparser parser(argc, argv); + int k = parser.key_exists("k") ? std::atoi(parser.value("k").c_str()) : 6; + double thresh = parser.key_exists("thresh") ? std::stod(parser.value("thresh")) : 1.e-4; FunctionDefaults<6>::set_tensor_type(TT_2D); + + FunctionDefaults<1>::set_thresh(thresh); + FunctionDefaults<2>::set_thresh(thresh); + FunctionDefaults<3>::set_thresh(thresh); + FunctionDefaults<4>::set_thresh(thresh); + FunctionDefaults<5>::set_thresh(thresh); FunctionDefaults<6>::set_thresh(1.e-3); - FunctionDefaults<3>::set_thresh(1.e-5); - FunctionDefaults<3>::set_cubic_cell(-1.0,1.0); - FunctionDefaults<6>::set_cubic_cell(-1.0,1.0); - FunctionDefaults<1>::set_thresh(1.e-5); + + FunctionDefaults<1>::set_k(k); + FunctionDefaults<2>::set_k(k); + FunctionDefaults<3>::set_k(k); + FunctionDefaults<4>::set_k(k); + FunctionDefaults<5>::set_k(k); + FunctionDefaults<6>::set_k(k); + FunctionDefaults<1>::set_cubic_cell(-10.,10.); - FunctionDefaults<2>::set_thresh(1.e-4); FunctionDefaults<2>::set_cubic_cell(-10.,10.); - FunctionDefaults<2>::set_tensor_type(TT_FULL); - FunctionDefaults<3>::set_thresh(1.e-4); FunctionDefaults<3>::set_cubic_cell(-10.,10.); - FunctionDefaults<4>::set_thresh(1.e-4); FunctionDefaults<4>::set_cubic_cell(-10.,10.); + FunctionDefaults<6>::set_cubic_cell(-1.0,1.0); + + FunctionDefaults<2>::set_tensor_type(TT_FULL); print("numerical parameters: k, eps(3D), eps(6D)", FunctionDefaults<3>::get_k(), FunctionDefaults<3>::get_thresh(), FunctionDefaults<6>::get_thresh()); int isuccess=0; @@ -1339,7 +1414,7 @@ int main(int argc, char **argv) { mol.print(); CCParameters ccparam(world, parser); - data1=data(world,ccparam); +// data1=data(world,ccparam); std::shared_ptr ncf = create_nuclear_correlation_factor(world, mol, nullptr, std::make_pair("slater", 2.0)); diff --git a/src/madness/mra/funcplot.h b/src/madness/mra/funcplot.h index 29cf3068a29..283e7f1fc47 100644 --- a/src/madness/mra/funcplot.h +++ b/src/madness/mra/funcplot.h @@ -884,7 +884,7 @@ namespace madness { World& world=vf.front().world(); for(size_t i=0;i(world,vf[i],namei); // plot_cubefile(world,vf[i],namei+".cube",header); } From f741572529c0dc76a6bd0920ae14ea90075d5a1f Mon Sep 17 00:00:00 2001 From: fbischoff Date: Thu, 10 Aug 2023 11:57:54 -0400 Subject: [PATCH 032/109] generalizing to 3D -- still working --- src/madness/chem/CMakeLists.txt | 1 + src/madness/chem/lowrankfunction.h | 297 +++++++++++++++++++++ src/madness/chem/test_ccpairfunction.cc | 250 +---------------- src/madness/chem/test_low_rank_function.cc | 11 +- 4 files changed, 305 insertions(+), 254 deletions(-) create mode 100644 src/madness/chem/lowrankfunction.h diff --git a/src/madness/chem/CMakeLists.txt b/src/madness/chem/CMakeLists.txt index 3e2e68675db..d42b967967b 100644 --- a/src/madness/chem/CMakeLists.txt +++ b/src/madness/chem/CMakeLists.txt @@ -25,6 +25,7 @@ set(MADCHEM_HEADERS gth_pseudopotential.h GuessFactory.h localizer.h + lowrankfunction.h masks_and_boxes.h molecularbasis.h molecular_functors.h diff --git a/src/madness/chem/lowrankfunction.h b/src/madness/chem/lowrankfunction.h new file mode 100644 index 00000000000..7c78e116624 --- /dev/null +++ b/src/madness/chem/lowrankfunction.h @@ -0,0 +1,297 @@ +// +// Created by Florian Bischoff on 8/10/23. +// + +#ifndef MADNESS_LOWRANKFUNCTION_H +#define MADNESS_LOWRANKFUNCTION_H + + +#include +#include + +namespace madness { + + + + template + struct randomgaussian { + Vector random_origin; + double exponent; + double radius=2; + randomgaussian(double exponent, double radius) : exponent(exponent), radius(radius) { + Vector ran; // [0,1] + RandomVector(NDIM,ran.data()); + random_origin=2.0*radius*ran-Vector(radius); + // print("origin at ",random_origin, ", exponent",exponent); + } + double operator()(const Vector& r) const { + // return exp(-exponent*inner(r-random_origin,r-random_origin)); + return exp(-exponent*(r-random_origin).normf()); + } + }; + + + + template + class LowRank { + public: + + struct LRFunctor { + LRFunctor() = default; + + Function f; + std::shared_ptr> f12; + Function a,b; + bool has_f() const { + return f.is_initialized(); + } + bool has_f12() const { + return (f12.get()); + } + }; + template + struct particle { + std::array dims; + particle(const int p) : particle(std::vector(1,p)) {} + particle(const std::vector p) { + for (int i=0; i + typename std::enable_if_t> + get_tuple() const {return std::tuple(dims[0]);} + + template + typename std::enable_if_t> + get_tuple() const {return std::tuple(dims[0],dims[1]);} + + template + typename std::enable_if_t> + get_tuple() const {return std::tuple(dims[0],dims[1],dims[2]);} + }; + + static std::vector> inner(LRFunctor& functor, const std::vector>& rhs, + const particle p1, const particle p2) { + std::vector> result; + if (functor.has_f()) { + for (const auto& r : rhs) result.push_back(madness::inner(functor.f,r,p1.get_tuple(),p2.get_tuple())); + return result; + } + + } + + World& world; + std::vector> g,h; + LRFunctor lrfunctor; + + LowRank(World& world) : world(world) {}; + + /// construct from the hi-dim function f + LowRank(const Function& f) : world(f.world()) { + lrfunctor.f=f; + } + + /// construct from the hi-dim function f12*a(1)(b(2) + LowRank(const std::shared_ptr> f12, const Function& a, + const Function& b) : world(a.world) { + lrfunctor.a=a; + lrfunctor.b=b; + lrfunctor.f12=f12; + } + + LowRank(std::vector> g, std::vector> h) + : world(g.front().world()), g(g), h(h) {} + + LowRank(const LowRank& a) : world(a.world), g(copy(world,a.g)), h(copy(world,a.h)) {} // Copy constructor necessary + + LowRank& operator=(const LowRank& f) { // Assignment required for storage in vector + LowRank ff(f); + std::swap(ff.g,g); + std::swap(ff.h,h); + return *this; + } + + LowRank operator-(const LowRank& b) const { // Operator- necessary + return LowRank(g-b.g,h-b.h); + } + + LowRank& operator+=(const LowRank& b) { // Operator+= necessary + g+=b.g; + h+=b.h; + return *this; + } + + LowRank operator*(double a) const { // Scale by a constant necessary + return LowRank(g*a,h); + } + + LowRank multiply(const std::vector>& vec, const long particle) { + auto result=*this; // deep copy + if (particle==0) result.g=g*vec; + if (particle==1) result.h=h*vec; + return *this; + } + + /// following Halko + + /// ||A - Q Q^T A||< epsilon + /// Y = A Omega && Q = QR(Y) + /// || f(1,2) - \sum_i g_i(1) h_i(2) || < epsilon + /// Y_i(1) = \int f(1,2) Omega_i(2) d2 && g_i(1) = QR(Y_i(1)) && h_i(2) = \int g_i^*(1) f(1,2) d1 + void project(const long rank, const double radius=3.0) { + timer t1(world); + std::vector> omega2(rank); + for (long i=0; i(world).functor(randomgaussian(RandomValue()+3,radius)); + } + t1.tag("projection 1D functions"); + + std::vector> Y(rank); + + if constexpr (LDIM==1) Y=inner(lrfunctor,omega2,{1},{0}); + if constexpr (LDIM==2) Y=inner(lrfunctor,omega2,{2,3},{0,1}); + if constexpr (LDIM==3) Y=inner(lrfunctor,omega2,{3,4,5},{0,1,2}); + t1.tag("Yforming"); + print("Y.size()",Y.size()); + + g=orthonormalize_canonical(Y,1.e-12); + print("g.size()",g.size()); + t1.tag("Y orthonormalizing"); + h.resize(g.size()); + if constexpr (LDIM==1) h=inner(lrfunctor,g,{0},{0}); + if constexpr (LDIM==2) h=inner(lrfunctor,g,{0,1},{0,1}); + if constexpr (LDIM==3) h=inner(lrfunctor,g,{0,1,2},{0,1,2}); + + t1.tag("Y backprojection"); + + } + + long rank() const {return g.size();} + + Function reconstruct() const { + auto fapprox=hartree_product(g[0],h[0]); + for (int i=1; i orthonormalize(const bool s_in_h) { + timer t(world); + /** + * |g >< h| = |g_ortho> < h | h_ortho > gg hh U s VT > g_ortho=orthonormalize_canonical(g,1.e-8); + std::vector> h_ortho=orthonormalize_canonical(h,1.e-8); + auto gg=matrix_inner(world,g_ortho,g); + auto hh=matrix_inner(world,h,h_ortho); + auto ovlp=madness::inner(gg,hh); + Tensor U,VT; + Tensor s; + svd(ovlp,U,s,VT); + auto V=transpose(VT); + + g=transform(world,g_ortho,U); + h=transform(world,h_ortho,V); + + + // include singular values into h + if (s_in_h) for (int i=0; i simple projection + void optimize(const long nopt=2) { + + timer t(world); + auto s=orthonormalize(true); // includes singular values in h -> not normalized any more + for (int iopt=0; iopt> gtmp(g.size()); + /// remove singular values from h again -> normalized + if constexpr (LDIM == 1) gtmp= inner(lrfunctor, h, {1}, {0}); + if constexpr (LDIM == 2) gtmp= inner(lrfunctor, h, {2, 3}, {0, 1}); + if constexpr (LDIM == 3) gtmp= inner(lrfunctor, h, {3, 4, 5}, {0, 1, 2}); + std::vector sinv(s.size()); + for (int i=0; i> htmp(g.size()); + if constexpr (LDIM==1) htmp=inner(lrfunctor,g,{0},{0}); + if constexpr (LDIM==2) htmp=inner(lrfunctor,g,{0,1},{0,1}); + if constexpr (LDIM==3) htmp=inner(lrfunctor,g,{0,1,2},{0,1,2}); + h=htmp; + + if (g.size()>1) s=orthonormalize(true); + + if (iopt%2==1) { + double err=error(); + print("optimization iteration",iopt,", error in f_approx_opt",err); + } + } + t.tag("optimize"); + } + + double explicit_error() const { + auto fapprox=reconstruct(); + return (lrfunctor.f-fapprox).norm2(); + } + + double randomized_error() const { + return 1.e9; + } + + double error() const { + if (LDIM<3) return explicit_error(); + else return randomized_error(); + } + + // double get() const {return x;} + }; + + // This interface is necessary to compute inner products + template + double inner(const LowRank& a, const LowRank& b) { + World& world=a.world; + return (matrix_inner(world,a.g,b.g).emul(matrix_inner(world,a.h,b.h))).sum(); + } + + + + template + LowRank inner(const Function& lhs, const LowRank& rhs, const std::tuple v1, const std::tuple v2) { + World& world=rhs.world; + // int lhs(1,2) rhs(2,3) d2 = \sum \int lhs(1,2) g_i(2) h_i(3) d2 + // = \sum \int lhs(1,2) g_i(2) d2 h_i(3) + LowRank result(world); + result.h=rhs.h; + decltype(rhs.g) g; + for (int i=0; i + LowRank inner(const LowRank& f, const Function& g, const std::tuple v1, const std::tuple v2) { + World& world=f.world; + // int f(1,2) k(2,3) d2 = \sum \int g_i(1) h_i(2) k(2,3) d2 + // = \sum g_i(1) \int h_i(2) k(2,3) d2 + LowRank result(world); + result.g=f.g; + decltype(f.h) h; + for (int i=0; i #include #include +#include #include using namespace madness; -template -struct randomgaussian { - Vector random_origin; - double exponent; - double radius=2; - randomgaussian(double exponent, double radius) : exponent(exponent), radius(radius) { - Vector ran; // [0,1] - RandomVector(NDIM,ran.data()); - random_origin=2.0*radius*ran-Vector(radius); -// print("origin at ",random_origin, ", exponent",exponent); - } - double operator()(const Vector& r) const { -// return exp(-exponent*inner(r-random_origin,r-random_origin)); - return exp(-exponent*(r-random_origin).normf()); - } - -}; bool longtest=false; @@ -117,238 +101,6 @@ struct data { data data1; -template -class LowRank { -public: - - struct LRFunctor { - LRFunctor() = default; - - Function f; - std::shared_ptr> f12; - Function a,b; - }; - - World& world; - std::vector> g,h; - LRFunctor lrfunctor; - - LowRank(World& world) : world(world) {}; - - /// construct from the hi-dim function f - LowRank(const Function& f) : world(f.world()) { - lrfunctor.f=f; - } - - /// construct from the hi-dim function f12*a(1)(b(2) - LowRank(const std::shared_ptr> f12, const Function& a, - const Function& b) : world(a.world) { - lrfunctor.a=a; - lrfunctor.b=b; - lrfunctor.f12=f12; - } - - LowRank(std::vector> g, std::vector> h) - : world(g.front().world()), g(g), h(h) {} - - LowRank(const LowRank& a) : world(a.world), g(copy(world,a.g)), h(copy(world,a.h)) {} // Copy constructor necessary - - LowRank& operator=(const LowRank& f) { // Assignment required for storage in vector - LowRank ff(f); - std::swap(ff.g,g); - std::swap(ff.h,h); - return *this; - } - - LowRank operator-(const LowRank& b) const { // Operator- necessary - return LowRank(g-b.g,h-b.h); - } - - LowRank& operator+=(const LowRank& b) { // Operator+= necessary - g+=b.g; - h+=b.h; - return *this; - } - - LowRank operator*(double a) const { // Scale by a constant necessary - return LowRank(g*a,h); - } - - LowRank multiply(const std::vector>& vec, const long particle) { - auto result=*this; // deep copy - if (particle==0) result.g=g*vec; - if (particle==1) result.h=h*vec; - return *this; - } - - /// following Halko - - /// ||A - Q Q^T A||< epsilon - /// Y = A Omega && Q = QR(Y) - /// || f(1,2) - \sum_i g_i(1) h_i(2) || < epsilon - /// Y_i(1) = \int f(1,2) Omega_i(2) d2 && g_i(1) = QR(Y_i(1)) && h_i(2) = \int g_i^*(1) f(1,2) d1 - void project(const long rank, const double radius=3.0) { - timer t1(world); - std::vector> omega2(rank); - for (long i=0; i(world).functor(randomgaussian(RandomValue()+3,radius)); - } - t1.tag("projection 1D functions"); - - std::vector> Y(rank); - - if constexpr (LDIM==1) for (int i=0; i reconstruct() const { - auto fapprox=hartree_product(g[0],h[0]); - for (int i=1; i orthonormalize(const bool s_in_h) { - timer t(world); - /** - * |g >< h| = |g_ortho> < h | h_ortho > gg hh U s VT > g_ortho=orthonormalize_canonical(g,1.e-8); - std::vector> h_ortho=orthonormalize_canonical(h,1.e-8); - auto gg=matrix_inner(world,g_ortho,g); - auto hh=matrix_inner(world,h,h_ortho); - auto ovlp=inner(gg,hh); - Tensor U,VT; - Tensor s; - svd(ovlp,U,s,VT); - auto V=transpose(VT); - - // truncate -// for (int i=1; i> gtmp(g.size()); - for (int j=0; j> htmp(g.size()); - for (int j=0; j1) s=orthonormalize(true); - - if (iopt%2==1) { - double err=error(); - print("optimization iteration",iopt,", error in f_approx_opt",err); - } - } - t.tag("optimize"); - } - - double explicit_error() const { - auto fapprox=reconstruct(); - return (lrfunctor.f-fapprox).norm2(); - } - - double randomized_error() const { - return 1.e9; - } - - double error() const { - if (LDIM<3) return explicit_error(); - else return randomized_error(); - } - -// double get() const {return x;} -}; - -// This interface is necessary to compute inner products -template -double inner(const LowRank& a, const LowRank& b) { - World& world=a.world; - return (matrix_inner(world,a.g,b.g).emul(matrix_inner(world,a.h,b.h))).sum(); -} - - - -template -LowRank inner(const Function& lhs, const LowRank& rhs, const std::tuple v1, const std::tuple v2) { - World& world=rhs.world; - // int lhs(1,2) rhs(2,3) d2 = \sum \int lhs(1,2) g_i(2) h_i(3) d2 - // = \sum \int lhs(1,2) g_i(2) d2 h_i(3) - LowRank result(world); - result.h=rhs.h; - decltype(rhs.g) g; - for (int i=0; i -LowRank inner(const LowRank& f, const Function& g, const std::tuple v1, const std::tuple v2) { - World& world=f.world; - // int f(1,2) k(2,3) d2 = \sum \int g_i(1) h_i(2) k(2,3) d2 - // = \sum g_i(1) \int h_i(2) k(2,3) d2 - LowRank result(world); - result.g=f.g; - decltype(f.h) h; - for (int i=0; i #include #include +#include #include #include @@ -657,7 +658,7 @@ int test_lowrank_function(World& world) { madness::default_random_generator.setstate(int(cpu_time())%4149); print(""); - constexpr std::size_t LDIM=1; + constexpr std::size_t LDIM=3; long n_per_dim=10; double radius=2.0; long ntrial=120; @@ -687,11 +688,11 @@ int test_lowrank_function(World& world) { Function phi1=copy(phi_slater); Function phi2=copy(one); -// auto f=hidim(world); - std::shared_ptr f12(SlaterOperatorPtr(world,1.0,1.e-6,FunctionDefaults::get_thresh())); - auto f=hidim_orbitals(f12,phi1,phi2); + auto f=hidim(world); +// std::shared_ptr f12(SlaterOperatorPtr(world,1.0,1.e-6,FunctionDefaults::get_thresh())); +// auto f=hidim_orbitals(f12,phi1,phi2); - plot_plane<2*LDIM>(world,f,"hidim_orbitals"); +// plot_plane<2*LDIM>(world,f,"hidim_orbitals"); double lo=-radius; From f1674f42be358dcac12b72b38c016363a0f3c43d Mon Sep 17 00:00:00 2001 From: fbischoff Date: Thu, 10 Aug 2023 14:51:23 -0400 Subject: [PATCH 033/109] simple exchange example works, now making optimization faster through rrcd --- src/madness/chem/lowrankfunction.h | 84 ++++++++++++++++++++++--- src/madness/chem/test_ccpairfunction.cc | 39 +++++++++++- src/madness/mra/vmra.h | 2 +- 3 files changed, 114 insertions(+), 11 deletions(-) diff --git a/src/madness/chem/lowrankfunction.h b/src/madness/chem/lowrankfunction.h index 7c78e116624..ace58955314 100644 --- a/src/madness/chem/lowrankfunction.h +++ b/src/madness/chem/lowrankfunction.h @@ -53,10 +53,17 @@ namespace madness { struct particle { std::array dims; particle(const int p) : particle(std::vector(1,p)) {} + particle(const int p1, const int p2) : particle(std::vector({p1,p2})) {} + particle(const int p1, const int p2,const int p3) : particle(std::vector({p1,p2,p3})) {} particle(const std::vector p) { for (int i=0; i typename std::enable_if_t> get_tuple() const {return std::tuple(dims[0]);} @@ -70,13 +77,38 @@ namespace madness { get_tuple() const {return std::tuple(dims[0],dims[1],dims[2]);} }; + /// inner product: result(1) = \int f(1,2) rhs(2) d2 + + /// @param[in] functor the hidim function + /// @param[in] rhs the rhs + /// @param[in] p1 the variable in f(1,2) to be integrated over + /// @param[in] p2 the variable in rhs to be integrated over (usually all of them) static std::vector> inner(LRFunctor& functor, const std::vector>& rhs, const particle p1, const particle p2) { std::vector> result; + MADNESS_CHECK(functor.has_f() xor functor.has_f12()); + MADNESS_CHECK(p1.is_first() xor p1.is_last()); + MADNESS_CHECK(p2.is_first()); + if (functor.has_f()) { for (const auto& r : rhs) result.push_back(madness::inner(functor.f,r,p1.get_tuple(),p2.get_tuple())); - return result; + + } else if (functor.has_f12()) { + // functor is now a(1) b(2) f12 + // result(1) = \int a(1) f(1,2) b(2) rhs(2) d2 + World& world=rhs.front().world(); + auto premultiply= p1.is_first() ? functor.a : functor.b; + auto postmultiply= p1.is_first() ? functor.b : functor.a; + auto tmp=copy(world,rhs); + + if (premultiply.is_initialized()) tmp=tmp*premultiply; + result=apply(world,*(functor.f12),tmp); + if (postmultiply.is_initialized()) result=result*postmultiply; + + } else { + MADNESS_EXCEPTION("confused functor in LowRankFunction",1); } + return result; } @@ -93,7 +125,7 @@ namespace madness { /// construct from the hi-dim function f12*a(1)(b(2) LowRank(const std::shared_ptr> f12, const Function& a, - const Function& b) : world(a.world) { + const Function& b) : world(a.world()) { lrfunctor.a=a; lrfunctor.b=b; lrfunctor.f12=f12; @@ -154,7 +186,8 @@ namespace madness { t1.tag("Yforming"); print("Y.size()",Y.size()); - g=orthonormalize_canonical(Y,1.e-12); +// g=orthonormalize_canonical(Y,1.e-12); + g=orthonormalize_rrcd(Y,1.e-12); print("g.size()",g.size()); t1.tag("Y orthonormalizing"); h.resize(g.size()); @@ -174,8 +207,13 @@ namespace madness { return fapprox; } - /// @return the singular values s Tensor orthonormalize(const bool s_in_h) { + return orthonormalize_svd(s_in_h); + } + + + /// @return the singular values s + Tensor orthonormalize_svd(const bool s_in_h) { timer t(world); /** * |g >< h| = |g_ortho> < h | h_ortho > U s VT > g_ortho=orthonormalize_canonical(g,1.e-8); + t.tag("ortho1"); std::vector> h_ortho=orthonormalize_canonical(h,1.e-8); + t.tag("ortho2"); auto gg=matrix_inner(world,g_ortho,g); auto hh=matrix_inner(world,h,h_ortho); auto ovlp=madness::inner(gg,hh); @@ -192,23 +232,48 @@ namespace madness { svd(ovlp,U,s,VT); auto V=transpose(VT); + t.tag("svd"); g=transform(world,g_ortho,U); + t.tag("transform1"); h=transform(world,h_ortho,V); + t.tag("transform2"); // include singular values into h if (s_in_h) for (int i=0; is< h| = |g_ortho> s < h | + * = |g_ortho> gg s < h | + * = |g_ortho> gg=matrix_inner(world,g_ortho,g); + /// Transforms a vector of functions according to new[i] = sum[j] old[j]*c[j,i] + h=transform(world,h,transpose(gg)); + g=g_ortho; + } + - /// assumes g and h to be orthonormal -> simple projection + /// assumes g and h to be orthonormal -> simple projection void optimize(const long nopt=2) { timer t(world); - auto s=orthonormalize(true); // includes singular values in h -> not normalized any more for (int iopt=0; iopt not normalized any more std::vector> gtmp(g.size()); /// remove singular values from h again -> normalized if constexpr (LDIM == 1) gtmp= inner(lrfunctor, h, {1}, {0}); @@ -217,14 +282,15 @@ namespace madness { std::vector sinv(s.size()); for (int i=0; i> htmp(g.size()); if constexpr (LDIM==1) htmp=inner(lrfunctor,g,{0},{0}); if constexpr (LDIM==2) htmp=inner(lrfunctor,g,{0,1},{0,1}); if constexpr (LDIM==3) htmp=inner(lrfunctor,g,{0,1,2},{0,1,2}); h=htmp; - if (g.size()>1) s=orthonormalize(true); +// if (g.size()>1) s=orthonormalize(true); if (iopt%2==1) { double err=error(); diff --git a/src/madness/chem/test_ccpairfunction.cc b/src/madness/chem/test_ccpairfunction.cc index c57a224614a..e0be5362475 100644 --- a/src/madness/chem/test_ccpairfunction.cc +++ b/src/madness/chem/test_ccpairfunction.cc @@ -133,6 +133,43 @@ class GaussianPotential : public FunctionFunctorInterface { } }; +int test_lowrank_function3(World& world) { + test_output t1("CCPairFunction::low rank function"); + t1.set_cout_to_terminal(); + madness::default_random_generator.setstate(int(cpu_time())%4149); + + constexpr std::size_t LDIM=3; + constexpr std::size_t NDIM=2*LDIM; + print("eps, k, NDIM",FunctionDefaults::get_thresh(),FunctionDefaults::get_k(),NDIM); + + Function phi=FunctionFactory(world).functor([](const Vector& r) + { return exp(-r.normf());}); + std::shared_ptr f12(SlaterOperatorPtr(world,1.0,1.e-6,FunctionDefaults::get_thresh())); + + LowRank lrf(f12,copy(phi),copy(phi)); + lrf.project(300,2.0); + lrf.optimize(1); + + // compare + // \phi(1) \bar \phi(1) = \int phi(1) \phi(2) f(1,2) d2 + // = \int \sum_r\phi(1) g_r(1) h_r(2) \phi(2) d2 + // = \phi(1) \sum_r g_r(1) <\phi|h_r> + auto reference = phi* (*f12)(phi); + real_function_3d result=real_factory_3d(world); + for (int r=0; r ncf = create_nuclear_correlation_factor(world, mol, nullptr, std::make_pair("slater", 2.0)); - isuccess+=test_lowrank_function(world); + isuccess+=test_lowrank_function3(world); // isuccess+=test_constructor(world, ncf, mol, ccparam); // isuccess+=test_operator_apply(world, ncf, mol, ccparam); // isuccess+=test_transformations(world, ncf, mol, ccparam); diff --git a/src/madness/mra/vmra.h b/src/madness/mra/vmra.h index e5b978d1507..eaac3b8e10b 100644 --- a/src/madness/mra/vmra.h +++ b/src/madness/mra/vmra.h @@ -556,7 +556,7 @@ namespace madness { } // compute overlap World& world=v.front().world(); - Tensor ovlp = matrix_inner(world, v, v); + Tensor ovlp = matrix_inner(world, v, v,true); return orthonormalize_rrcd(v,ovlp,tol); } From b4c4438ee8bce42018fa4b2e2727f58cddaa318d Mon Sep 17 00:00:00 2001 From: fbischoff Date: Thu, 10 Aug 2023 15:52:18 -0400 Subject: [PATCH 034/109] exchange example working, cannot converge to small errors below 1.e-3 though --- src/madness/chem/lowrankfunction.h | 92 ++++++++++++++++++------- src/madness/chem/test_ccpairfunction.cc | 15 ++-- 2 files changed, 77 insertions(+), 30 deletions(-) diff --git a/src/madness/chem/lowrankfunction.h b/src/madness/chem/lowrankfunction.h index ace58955314..1845450f783 100644 --- a/src/madness/chem/lowrankfunction.h +++ b/src/madness/chem/lowrankfunction.h @@ -49,9 +49,28 @@ namespace madness { return (f12.get()); } }; + template struct particle { std::array dims; + + /// default constructor + particle() = default; + + /// convenience for particle 1 (the left/first particle) + static particle particle1() { + particle p; + for (int i=0; i(1,p)) {} particle(const int p1, const int p2) : particle(std::vector({p1,p2})) {} particle(const int p1, const int p2,const int p3) : particle(std::vector({p1,p2,p3})) {} @@ -77,6 +96,7 @@ namespace madness { get_tuple() const {return std::tuple(dims[0],dims[1],dims[2]);} }; + /// inner product: result(1) = \int f(1,2) rhs(2) d2 /// @param[in] functor the hidim function @@ -115,17 +135,19 @@ namespace madness { World& world; std::vector> g,h; LRFunctor lrfunctor; + particle p1=particle::particle1(); + particle p2=particle::particle2(); - LowRank(World& world) : world(world) {}; + LowRank(World& world) : world(world) {} /// construct from the hi-dim function f - LowRank(const Function& f) : world(f.world()) { + LowRank(const Function& f) : LowRank(f.world()) { lrfunctor.f=f; } /// construct from the hi-dim function f12*a(1)(b(2) LowRank(const std::shared_ptr> f12, const Function& a, - const Function& b) : world(a.world()) { + const Function& b) : LowRank(a.world()) { lrfunctor.a=a; lrfunctor.b=b; lrfunctor.f12=f12; @@ -174,27 +196,20 @@ namespace madness { timer t1(world); std::vector> omega2(rank); for (long i=0; i(world).functor(randomgaussian(RandomValue()+3,radius)); + omega2[i]=FunctionFactory(world).functor(randomgaussian(RandomValue()+5,radius)); } - t1.tag("projection 1D functions"); + t1.tag("projection lowdim functions"); - std::vector> Y(rank); - - if constexpr (LDIM==1) Y=inner(lrfunctor,omega2,{1},{0}); - if constexpr (LDIM==2) Y=inner(lrfunctor,omega2,{2,3},{0,1}); - if constexpr (LDIM==3) Y=inner(lrfunctor,omega2,{3,4,5},{0,1,2}); + auto Y=inner(lrfunctor,omega2,p2,p1); t1.tag("Yforming"); - print("Y.size()",Y.size()); -// g=orthonormalize_canonical(Y,1.e-12); g=orthonormalize_rrcd(Y,1.e-12); - print("g.size()",g.size()); t1.tag("Y orthonormalizing"); - h.resize(g.size()); - if constexpr (LDIM==1) h=inner(lrfunctor,g,{0},{0}); - if constexpr (LDIM==2) h=inner(lrfunctor,g,{0,1},{0,1}); - if constexpr (LDIM==3) h=inner(lrfunctor,g,{0,1,2},{0,1,2}); + print("Y.size()",Y.size()); + print("g.size()",g.size()); + + h=inner(lrfunctor,g,p1,p1); t1.tag("Y backprojection"); } @@ -220,9 +235,9 @@ namespace madness { * = |g_ortho> gg hh U s VT > g_ortho=orthonormalize_canonical(g,1.e-8); + std::vector> g_ortho=orthonormalize_rrcd(g,1.e-8); t.tag("ortho1"); - std::vector> h_ortho=orthonormalize_canonical(h,1.e-8); + std::vector> h_ortho=orthonormalize_rrcd(h,1.e-8); t.tag("ortho2"); auto gg=matrix_inner(world,g_ortho,g); auto hh=matrix_inner(world,h,h_ortho); @@ -232,6 +247,7 @@ namespace madness { svd(ovlp,U,s,VT); auto V=transpose(VT); + t.tag("svd"); g=transform(world,g_ortho,U); t.tag("transform1"); @@ -253,23 +269,49 @@ namespace madness { */ World& world=g.front().world(); - auto g_ortho= orthonormalize_cd(g); + auto g_ortho= orthonormalize_rrcd(g,1.e-10); // auto g_ortho= orthonormalize_canonical(g,1.e-8); // similar to SVD // auto g_ortho= orthonormalize_symmetric(g); auto ovlp=matrix_inner(world,g_ortho,g_ortho); for (int i=0; i gg=matrix_inner(world,g_ortho,g); /// Transforms a vector of functions according to new[i] = sum[j] old[j]*c[j,i] - h=transform(world,h,transpose(gg)); - g=g_ortho; - } + h=truncate(transform(world,h,transpose(gg))); + g=truncate(g_ortho); + } - /// assumes g and h to be orthonormal -> simple projection void optimize(const long nopt=2) { + optimize_cd(nopt); + } + + /// optimize using Cholesky decomposition + void optimize_cd(const long nopt) { + + timer t(world); + for (int iopt=0; ioptorthonormalize_cd(); // g orthonormal, h not + t.tag("ortho1"); + auto gtmp=inner(lrfunctor,h,p2,p1); + t.tag("inner1"); + g=orthonormalize_rrcd(gtmp,1.e-12); + t.tag("ortho2"); + h=inner(lrfunctor,g,p1,p1); + t.tag("inner2"); + + if (iopt%2==1) { + double err=error(); + print("optimization iteration",iopt,", error in f_approx_opt",err); + } + } + t.tag("optimize"); + } + + /// assumes g and h to be orthonormal -> simple projection + void optimize_svd(const long nopt=2) { timer t(world); for (int iopt=0; iopt::get_thresh(),FunctionDefaults::get_k(),NDIM); - Function phi=FunctionFactory(world).functor([](const Vector& r) + Function phi1=FunctionFactory(world).functor([](const Vector& r) { return exp(-r.normf());}); + Function phi2=FunctionFactory(world).functor([](const Vector& r) + { return exp(-2.0*r.normf());}); + std::shared_ptr f12(SlaterOperatorPtr(world,1.0,1.e-6,FunctionDefaults::get_thresh())); - LowRank lrf(f12,copy(phi),copy(phi)); - lrf.project(300,2.0); - lrf.optimize(1); + LowRank lrf(f12,copy(phi1),copy(phi2)); + lrf.project(500,3.0); + lrf.optimize(2); // compare // \phi(1) \bar \phi(1) = \int phi(1) \phi(2) f(1,2) d2 // = \int \sum_r\phi(1) g_r(1) h_r(2) \phi(2) d2 // = \phi(1) \sum_r g_r(1) <\phi|h_r> - auto reference = phi* (*f12)(phi); + auto reference = phi1* (*f12)(phi2); real_function_3d result=real_factory_3d(world); for (int r=0; r({reference, result, diff}, "f_and_approx", std::vector({"adsf", "asdf", "diff"})); + return t1.end(); From db17bc195de8ada8cdc303a485103423f6c7c825 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Mon, 14 Aug 2023 15:08:22 -0400 Subject: [PATCH 035/109] update, no news --- src/madness/chem/lowrankfunction.h | 120 ++++++++++++++++++++++-- src/madness/chem/test_ccpairfunction.cc | 57 ++++++++--- 2 files changed, 157 insertions(+), 20 deletions(-) diff --git a/src/madness/chem/lowrankfunction.h b/src/madness/chem/lowrankfunction.h index 1845450f783..3e9a70b9ad5 100644 --- a/src/madness/chem/lowrankfunction.h +++ b/src/madness/chem/lowrankfunction.h @@ -12,6 +12,60 @@ namespace madness { + template + struct cartesian_grid { + Vector lovec,hivec; + std::vector stride; + long index=0; + long n_per_dim; + long total_n; + Vector increment; + + cartesian_grid(const long n_per_dim, const double lo, const double hi) + : n_per_dim(n_per_dim) { + lovec.fill(lo); + hivec.fill(hi); + increment=(hivec-lovec)*(1.0/double(n_per_dim-1)); + stride=std::vector(NDIM,1l); + total_n=std::pow(n_per_dim,NDIM); + for (long i=NDIM-2; i>=0; --i) stride[i]=n_per_dim*stride[i+1]; + } + + cartesian_grid(const cartesian_grid& other) : lovec(other.lovec), + hivec(other.hivec), stride(other.stride), index(0), n_per_dim(other.n_per_dim), + total_n(other.total_n), increment(other.increment) { + } + + cartesian_grid& operator=(const cartesian_grid& other) { + cartesian_grid tmp(other); + std::swap(*this,other); + return *this; + } + + double volume_per_gridpoint() const{ + double volume=1.0; + for (int i=0; i get_coordinates() const { + Vector tmp(NDIM); + for (int idim=0; idim struct randomgaussian { @@ -26,7 +80,8 @@ namespace madness { } double operator()(const Vector& r) const { // return exp(-exponent*inner(r-random_origin,r-random_origin)); - return exp(-exponent*(r-random_origin).normf()); + double r2=inner(r-random_origin,r-random_origin); + return exp(-exponent*r2); } }; @@ -48,6 +103,16 @@ namespace madness { bool has_f12() const { return (f12.get()); } + T operator()(const Vector& r) const { + Vector first, second; + for (int i=0; i @@ -165,6 +230,17 @@ namespace madness { return *this; } + T operator()(const Vector& r) const { + Vector first, second; + for (int i=0; i> omega2(rank); - for (long i=0; i(world).functor(randomgaussian(RandomValue()+5,radius)); + std::vector> omega2; + if (gridtype=="random") { + for (long i=0; i(world).functor(randomgaussian(RandomValue()+10.0,radius))); + omega2.push_back(FunctionFactory(world).functor(randomgaussian(7.0,radius))); + } + print("using random gaussian distribution"); + } else if (gridtype=="cartesian") { + + cartesian_grid cg(9,-radius,radius); + auto c=cg; + c.index=0; + for (; c(); ++c) { + omega2.push_back(FunctionFactory(world) + .functor([&c](const Vector& r) + { + auto r_rel=r-c.get_coordinates(); + return exp(-10*madness::inner(r_rel,r_rel)); + })); + } + print("volume element in cartesian grid",cg.volume_per_gridpoint()); + } else { + MADNESS_EXCEPTION("confused gridtype",1); } + + t1.tag("projection lowdim functions"); + print("radius",radius); + print("initial rank",omega2.size()); auto Y=inner(lrfunctor,omega2,p2,p1); t1.tag("Yforming"); - g=orthonormalize_rrcd(Y,1.e-12); + g=orthonormalize_rrcd(Y,1.e-9); t1.tag("Y orthonormalizing"); print("Y.size()",Y.size()); @@ -279,13 +379,15 @@ namespace madness { Tensor gg=matrix_inner(world,g_ortho,g); /// Transforms a vector of functions according to new[i] = sum[j] old[j]*c[j,i] - h=truncate(transform(world,h,transpose(gg))); - g=truncate(g_ortho); +// h=truncate(transform(world,h,transpose(gg))); +// g=truncate(g_ortho); + h=(transform(world,h,transpose(gg))); + g=(g_ortho); } void optimize(const long nopt=2) { - optimize_cd(nopt); + optimize_svd(nopt); } /// optimize using Cholesky decomposition diff --git a/src/madness/chem/test_ccpairfunction.cc b/src/madness/chem/test_ccpairfunction.cc index 6e4d9d484ac..68daebf3246 100644 --- a/src/madness/chem/test_ccpairfunction.cc +++ b/src/madness/chem/test_ccpairfunction.cc @@ -16,6 +16,24 @@ using namespace madness; +struct XParameters : QCCalculationParametersBase { + + XParameters() : QCCalculationParametersBase() { + + // initialize with: key, value, comment (optional), allowed values (optional) + initialize("radius",5.0,"the radius"); + initialize("rank",500,"the number of grid points in random grids"); + initialize("gridtype","random","the grid type",{"random","cartesian"}); + } + + void read_and_set_derived_values(World& world, const commandlineparser& parser, std::string tag) { + read_input_and_commandline_options(world,parser,tag); + } + + double radius() const {return get("radius");} + int rank() const {return get("rank");} + std::string gridtype() const {return get("gridtype");} +}; bool longtest=false; @@ -133,7 +151,7 @@ class GaussianPotential : public FunctionFunctorInterface { } }; -int test_lowrank_function3(World& world) { +int test_lowrank_function3(World& world, XParameters& parameters) { test_output t1("CCPairFunction::low rank function"); t1.set_cout_to_terminal(); madness::default_random_generator.setstate(int(cpu_time())%4149); @@ -142,16 +160,30 @@ int test_lowrank_function3(World& world) { constexpr std::size_t NDIM=2*LDIM; print("eps, k, NDIM",FunctionDefaults::get_thresh(),FunctionDefaults::get_k(),NDIM); + Vector offset; + offset.fill(0.0); +// Function phi1=FunctionFactory(world).functor([](const Vector& r) +// { return exp(-r.normf());}); Function phi1=FunctionFactory(world).functor([](const Vector& r) - { return exp(-r.normf());}); - Function phi2=FunctionFactory(world).functor([](const Vector& r) - { return exp(-2.0*r.normf());}); + { return 1.0;}); + Function phi2=FunctionFactory(world).functor([&offset](const Vector& r) + { return exp(-1.0*(r-offset).normf());}); std::shared_ptr f12(SlaterOperatorPtr(world,1.0,1.e-6,FunctionDefaults::get_thresh())); + auto f = [](const coord_6d& r) { + coord_3d r1={r[0],r[1],r[2]}; + coord_3d r2={r[3],r[4],r[5]}; + return exp(-(r1-r2).normf() -r2.normf()); + }; + LowRank lrf(f12,copy(phi1),copy(phi2)); - lrf.project(500,3.0); - lrf.optimize(2); + lrf.project(parameters.rank(),parameters.radius(),parameters.gridtype()); +// lrf.optimize(1); + print("lrf.rank()",lrf.rank()); + + plot_plane<6>(world,lrf.lrfunctor,"plot_f12_r2"); + plot_plane<6>(world,lrf,"lrf_6d"); // compare // \phi(1) \bar \phi(1) = \int phi(1) \phi(2) f(1,2) d2 @@ -226,7 +258,7 @@ int test_lowrank_function(World& world) { f12.reconstruct(); Function reference=inner(lhs,rhs,{0},{0}); LowRank lrf(rhs); - lrf.project(50,3.0); + lrf.project(50,3.0,"random"); lrf.optimize(); double ferror=lrf.error(); @@ -260,7 +292,7 @@ int test_lowrank_function(World& world) { double radius = 5.0; LowRank lr(copy(f)); - lr.project(rank, radius); + lr.project(rank, radius,"random"); double err = lr.error(); print("error in f_approx", err); lr.orthonormalize(true); @@ -1180,7 +1212,7 @@ int main(int argc, char **argv) { FunctionDefaults<3>::set_thresh(thresh); FunctionDefaults<4>::set_thresh(thresh); FunctionDefaults<5>::set_thresh(thresh); - FunctionDefaults<6>::set_thresh(1.e-3); + FunctionDefaults<6>::set_thresh(1.e-4); FunctionDefaults<1>::set_k(k); FunctionDefaults<2>::set_k(k); @@ -1193,11 +1225,14 @@ int main(int argc, char **argv) { FunctionDefaults<2>::set_cubic_cell(-10.,10.); FunctionDefaults<3>::set_cubic_cell(-10.,10.); FunctionDefaults<4>::set_cubic_cell(-10.,10.); - FunctionDefaults<6>::set_cubic_cell(-1.0,1.0); + FunctionDefaults<6>::set_cubic_cell(-10.,10.); FunctionDefaults<2>::set_tensor_type(TT_FULL); print("numerical parameters: k, eps(3D), eps(6D)", FunctionDefaults<3>::get_k(), FunctionDefaults<3>::get_thresh(), FunctionDefaults<6>::get_thresh()); + XParameters parameters; + parameters.read_and_set_derived_values(world,parser,"grid"); + parameters.print("grid parameters"); int isuccess=0; #ifdef USE_GENTENSOR @@ -1213,7 +1248,7 @@ int main(int argc, char **argv) { std::shared_ptr ncf = create_nuclear_correlation_factor(world, mol, nullptr, std::make_pair("slater", 2.0)); - isuccess+=test_lowrank_function3(world); + isuccess+=test_lowrank_function3(world,parameters); // isuccess+=test_constructor(world, ncf, mol, ccparam); // isuccess+=test_operator_apply(world, ncf, mol, ccparam); // isuccess+=test_transformations(world, ncf, mol, ccparam); From d2d4cd797c4f7a27692b664d4990f1a12048b2e1 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Tue, 15 Aug 2023 16:38:23 -0400 Subject: [PATCH 036/109] update, having a hard time converging to high precision --- src/madness/chem/lowrankfunction.h | 25 ++++++++++++++++----- src/madness/chem/test_ccpairfunction.cc | 29 +++++++++++++++---------- 2 files changed, 36 insertions(+), 18 deletions(-) diff --git a/src/madness/chem/lowrankfunction.h b/src/madness/chem/lowrankfunction.h index 3e9a70b9ad5..374e30603d9 100644 --- a/src/madness/chem/lowrankfunction.h +++ b/src/madness/chem/lowrankfunction.h @@ -8,6 +8,8 @@ #include #include +#include + namespace madness { @@ -73,16 +75,26 @@ namespace madness { double exponent; double radius=2; randomgaussian(double exponent, double radius) : exponent(exponent), radius(radius) { - Vector ran; // [0,1] - RandomVector(NDIM,ran.data()); +// Vector ran; // [0,1] +// RandomVector(NDIM,ran.data()); + Vector ran= this->gaussian_random_distribution(0,radius); random_origin=2.0*radius*ran-Vector(radius); - // print("origin at ",random_origin, ", exponent",exponent); +// print("origin at ",random_origin, ", exponent",exponent); } double operator()(const Vector& r) const { // return exp(-exponent*inner(r-random_origin,r-random_origin)); double r2=inner(r-random_origin,r-random_origin); return exp(-exponent*r2); } + + Vector gaussian_random_distribution(double mean, double variance) { + std::random_device rd{}; + std::mt19937 gen{rd()}; + std::normal_distribution<> d{mean, variance}; + Vector result; + for (int i = 0; i < NDIM; ++i) result[i]=d(gen); + return result; + } }; @@ -274,7 +286,7 @@ namespace madness { if (gridtype=="random") { for (long i=0; i(world).functor(randomgaussian(RandomValue()+10.0,radius))); - omega2.push_back(FunctionFactory(world).functor(randomgaussian(7.0,radius))); + omega2.push_back(FunctionFactory(world).functor(randomgaussian(50.0,radius))); } print("using random gaussian distribution"); } else if (gridtype=="cartesian") { @@ -303,8 +315,9 @@ namespace madness { auto Y=inner(lrfunctor,omega2,p2,p1); t1.tag("Yforming"); - g=orthonormalize_rrcd(Y,1.e-9); - t1.tag("Y orthonormalizing"); + double tol=1.e-12; + g=orthonormalize_rrcd(Y,tol); + t1.tag("Y orthonormalizing with tol"+std::to_string(tol)); print("Y.size()",Y.size()); print("g.size()",g.size()); diff --git a/src/madness/chem/test_ccpairfunction.cc b/src/madness/chem/test_ccpairfunction.cc index 68daebf3246..903e6d1eb41 100644 --- a/src/madness/chem/test_ccpairfunction.cc +++ b/src/madness/chem/test_ccpairfunction.cc @@ -155,6 +155,7 @@ int test_lowrank_function3(World& world, XParameters& parameters) { test_output t1("CCPairFunction::low rank function"); t1.set_cout_to_terminal(); madness::default_random_generator.setstate(int(cpu_time())%4149); + madness::default_random_generator.setstate(int(cpu_time())%4149); constexpr std::size_t LDIM=3; constexpr std::size_t NDIM=2*LDIM; @@ -168,39 +169,43 @@ int test_lowrank_function3(World& world, XParameters& parameters) { { return 1.0;}); Function phi2=FunctionFactory(world).functor([&offset](const Vector& r) { return exp(-1.0*(r-offset).normf());}); + Function one=FunctionFactory(world) + .functor([](const Vector& r) { return 1.0;}); std::shared_ptr f12(SlaterOperatorPtr(world,1.0,1.e-6,FunctionDefaults::get_thresh())); - auto f = [](const coord_6d& r) { - coord_3d r1={r[0],r[1],r[2]}; - coord_3d r2={r[3],r[4],r[5]}; - return exp(-(r1-r2).normf() -r2.normf()); - }; +// auto f = [](const coord_6d& r) { +// coord_3d r1={r[0],r[1],r[2]}; +// coord_3d r2={r[3],r[4],r[5]}; +// return exp(-(r1-r2).normf() -r2.normf()); +// }; LowRank lrf(f12,copy(phi1),copy(phi2)); lrf.project(parameters.rank(),parameters.radius(),parameters.gridtype()); -// lrf.optimize(1); + lrf.optimize(1); print("lrf.rank()",lrf.rank()); - plot_plane<6>(world,lrf.lrfunctor,"plot_f12_r2"); - plot_plane<6>(world,lrf,"lrf_6d"); - // compare // \phi(1) \bar \phi(1) = \int phi(1) \phi(2) f(1,2) d2 - // = \int \sum_r\phi(1) g_r(1) h_r(2) \phi(2) d2 - // = \phi(1) \sum_r g_r(1) <\phi|h_r> + // = \int \sum_r g_r(1) h_r(2) d2 + // = \sum_r g_r(1) <\phi|h_r> auto reference = phi1* (*f12)(phi2); real_function_3d result=real_factory_3d(world); - for (int r=0; r({reference, result, diff}, "f_and_approx", std::vector({"adsf", "asdf", "diff"})); + plot_plane<6>(world,lrf.lrfunctor,"plot_f12_r2"); + plot_plane<6>(world,lrf,"lrf_6d"); + + return t1.end(); From d5403f55f10b7d28d0751371cc97565ac5574810 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Fri, 18 Aug 2023 13:14:37 -0400 Subject: [PATCH 037/109] converging the error of the RI approximation by increasing the volume (best value 4) and decreasing the volume per gridpoint (best value 0.02) --- src/madness/chem/lowrankfunction.h | 142 +++++++++++++++++++----- src/madness/chem/test_ccpairfunction.cc | 35 +++--- src/madness/mra/funcplot.h | 3 + 3 files changed, 141 insertions(+), 39 deletions(-) diff --git a/src/madness/chem/lowrankfunction.h b/src/madness/chem/lowrankfunction.h index 374e30603d9..fbcb8df053d 100644 --- a/src/madness/chem/lowrankfunction.h +++ b/src/madness/chem/lowrankfunction.h @@ -87,7 +87,7 @@ namespace madness { return exp(-exponent*r2); } - Vector gaussian_random_distribution(double mean, double variance) { + static Vector gaussian_random_distribution(double mean, double variance) { std::random_device rd{}; std::mt19937 gen{rd()}; std::normal_distribution<> d{mean, variance}; @@ -209,6 +209,60 @@ namespace madness { } + /// inner product: result(1) = \int f(1,2) delta(2) d2 + + /// @param[in] functor the hidim function + /// @param[in] grid grid points with delta functions + /// @param[in] p1 the variable in f(1,2) to be integrated over + /// @param[in] p2 the variable in rhs to be integrated over (usually all of them) + static std::vector> inner(LRFunctor& functor, const std::vector>& grid, + const particle p1, const particle p2) { + std::vector> result; + MADNESS_CHECK(functor.has_f() xor functor.has_f12()); + MADNESS_CHECK(p1.is_first() xor p1.is_last()); + MADNESS_CHECK(p2.is_first()); + + if (functor.has_f()) { + MADNESS_EXCEPTION("no grid points with an explicit hi-dim function",1); + + } else if (functor.has_f12()) { + // functor is now a(1) b(2) f12 + // result(1) = \int a(1) f(1,2) b(2) delta(R-2) d2 + // = a(1) f(1,R) b(R) + World& world=functor.f12->get_world(); + auto premultiply= p1.is_first() ? functor.a : functor.b; + auto postmultiply= p1.is_first() ? functor.b : functor.a; + + std::vector> f1R= slater_functions_on_grid(world,grid); + print("bla1"); + if (premultiply.is_initialized()) { + for (int i=0; i> slater_functions_on_grid(World& world, const std::vector>& grid) { + std::vector> result; + for (const auto& point : grid) { + auto sl=[&point](const Vector& r) { + return exp(-sqrt(madness::inner(r-point,r-point)+1.e-12)); + }; + result.push_back(FunctionFactory(world).functor(sl)); + } + return result; + } + + World& world; std::vector> g,h; LRFunctor lrfunctor; @@ -274,45 +328,58 @@ namespace madness { return *this; } + void project(const double volume_per_point, const double radius, const std::string gridtype, std::string rhsfunctiontype) { + long rank=0; + if (gridtype=="random") { + // number of points within radius = variance: 0.67 * #total points = 0.67*rank + // volume of sphere 4/3 pi *r^3 + // volume per point=volume/#points in radius = volume / (0.67 * rank) + // rank= volume/(0.67/volume_per_point) + double volume=4.0/3.0*constants::pi *std::pow(radius,3.0); + rank = lround(volume/(0.67*volume_per_point )); + } + project(rank,radius,gridtype,rhsfunctiontype); + } + /// following Halko /// ||A - Q Q^T A||< epsilon /// Y = A Omega && Q = QR(Y) /// || f(1,2) - \sum_i g_i(1) h_i(2) || < epsilon /// Y_i(1) = \int f(1,2) Omega_i(2) d2 && g_i(1) = QR(Y_i(1)) && h_i(2) = \int g_i^*(1) f(1,2) d1 - void project(const long rank, const double radius, const std::string gridtype) { + void project(const long rank, const double radius, const std::string gridtype, std::string rhsfunctiontype) { timer t1(world); - std::vector> omega2; + + // make grid + std::vector> grid; if (gridtype=="random") { - for (long i=0; i(world).functor(randomgaussian(RandomValue()+10.0,radius))); - omega2.push_back(FunctionFactory(world).functor(randomgaussian(50.0,radius))); + for (int i=0; i::gaussian_random_distribution(0,radius); + auto cell=FunctionDefaults::get_cell(); + auto is_in_cell = [&cell](const Vector& r) { + for (int d=0; dcell(d,1)) return false; + return true; + }; + if (not is_in_cell(tmp)) continue; + grid.push_back(tmp); } - print("using random gaussian distribution"); - } else if (gridtype=="cartesian") { + double volume = 4.0/3.0*constants::pi * std::pow(radius,3.0); + print("volume element in random grid",volume/(0.67*rank)); - cartesian_grid cg(9,-radius,radius); - auto c=cg; - c.index=0; - for (; c(); ++c) { - omega2.push_back(FunctionFactory(world) - .functor([&c](const Vector& r) - { - auto r_rel=r-c.get_coordinates(); - return exp(-10*madness::inner(r_rel,r_rel)); - })); - } + + } else if (gridtype=="cartesian") { + long nperdim=std::lround(std::pow(double(rank),1.0/3.0)); + cartesian_grid cg(nperdim,-radius,radius); + for (cg.index=0; cg(); ++cg) grid.push_back(cg.get_coordinates()); print("volume element in cartesian grid",cg.volume_per_gridpoint()); } else { - MADNESS_EXCEPTION("confused gridtype",1); + MADNESS_EXCEPTION("unknown grid type in project",1); } + print("grid is",gridtype,"with radius",radius,"and",grid.size(),"gridpoints"); + print("rhs functions are",rhsfunctiontype); - t1.tag("projection lowdim functions"); - print("radius",radius); - print("initial rank",omega2.size()); - - auto Y=inner(lrfunctor,omega2,p2,p1); + auto Y=Yformer(grid,rhsfunctiontype); t1.tag("Yforming"); double tol=1.e-12; @@ -327,6 +394,31 @@ namespace madness { } + /// apply a rhs (delta or exponential) on grid points to the hi-dim function and form Y = A_ij w_j (in Halko's language) + std::vector> Yformer(const std::vector>& grid, const std::string rhsfunctiontype, + const double exponent=30.0) { + + std::vector> Y; + if (rhsfunctiontype=="delta") { + Y=inner(lrfunctor,grid,p2,p1); + + } else if (rhsfunctiontype=="exponential") { + std::vector> omega; + for (const auto& point : grid) { + omega.push_back(FunctionFactory(world) + .functor([&point,&exponent](const Vector& r) + { + auto r_rel=r-point; + return exp(-exponent*madness::inner(r_rel,r_rel)); + })); + } + Y=inner(lrfunctor,omega,p2,p1); + } else { + MADNESS_EXCEPTION("confused rhsfunctiontype",1); + } + return Y; + } + long rank() const {return g.size();} Function reconstruct() const { diff --git a/src/madness/chem/test_ccpairfunction.cc b/src/madness/chem/test_ccpairfunction.cc index 903e6d1eb41..2fba2d652de 100644 --- a/src/madness/chem/test_ccpairfunction.cc +++ b/src/madness/chem/test_ccpairfunction.cc @@ -21,9 +21,12 @@ struct XParameters : QCCalculationParametersBase { XParameters() : QCCalculationParametersBase() { // initialize with: key, value, comment (optional), allowed values (optional) - initialize("radius",5.0,"the radius"); - initialize("rank",500,"the number of grid points in random grids"); + initialize("radius",2.0,"the radius"); + initialize("volume_element",0.1,"volume covered by each grid point"); + initialize("rank",500,"the number of grid points in random grids"); initialize("gridtype","random","the grid type",{"random","cartesian"}); + initialize("rhsfunctiontype","delta","the type of function",{"delta","exponential"}); + initialize("optimize",0,"number of optimization iterations"); } void read_and_set_derived_values(World& world, const commandlineparser& parser, std::string tag) { @@ -31,8 +34,11 @@ struct XParameters : QCCalculationParametersBase { } double radius() const {return get("radius");} - int rank() const {return get("rank");} + double volume_element() const {return get("volume_element");} + long rank() const {return get("rank");} + int optimize() const {return get("optimize");} std::string gridtype() const {return get("gridtype");} + std::string rhsfunctiontype() const {return get("rhsfunctiontype");} }; @@ -161,6 +167,8 @@ int test_lowrank_function3(World& world, XParameters& parameters) { constexpr std::size_t NDIM=2*LDIM; print("eps, k, NDIM",FunctionDefaults::get_thresh(),FunctionDefaults::get_k(),NDIM); + parameters.print("grid","end"); + Vector offset; offset.fill(0.0); // Function phi1=FunctionFactory(world).functor([](const Vector& r) @@ -181,12 +189,14 @@ int test_lowrank_function3(World& world, XParameters& parameters) { // }; LowRank lrf(f12,copy(phi1),copy(phi2)); - lrf.project(parameters.rank(),parameters.radius(),parameters.gridtype()); - lrf.optimize(1); +// plot_plane<6>(world,lrf.lrfunctor,"plot_f12_r2",PlotParameters(world).set_plane({"x1","x4"})); +// lrf.project(parameters.rank(),parameters.radius(),parameters.gridtype(),parameters.rhsfunctiontype()); + lrf.project(parameters.volume_element(),parameters.radius(),parameters.gridtype(),parameters.rhsfunctiontype()); + lrf.optimize(parameters.optimize()); print("lrf.rank()",lrf.rank()); // compare - // \phi(1) \bar \phi(1) = \int phi(1) \phi(2) f(1,2) d2 + // \phi(1) \bar \phi(1) = \intn phi(1) \phi(2) f(1,2) d2 // = \int \sum_r g_r(1) h_r(2) d2 // = \sum_r g_r(1) <\phi|h_r> auto reference = phi1* (*f12)(phi2); @@ -198,12 +208,10 @@ int test_lowrank_function3(World& world, XParameters& parameters) { double resultnorm=result.norm2(); double error=diff.norm2(); print("refnorm, resultnorm, abs. error, rel. error",refnorm, resultnorm, error, error/refnorm); - print("radius, initial/final rank, rel. error",parameters.radius(),parameters.rank(),lrf.rank(), error/refnorm); - - plot({reference, result, diff}, "f_and_approx", std::vector({"adsf", "asdf", "diff"})); + print("radius, initial/final rank, vol. el, rel. error",parameters.radius(),parameters.rank(),lrf.rank(), parameters.volume_element(), error/refnorm); - plot_plane<6>(world,lrf.lrfunctor,"plot_f12_r2"); - plot_plane<6>(world,lrf,"lrf_6d"); +// plot_plane(world,{reference, result, diff}, "f_and_approx", PlotParameters(world).set_plane({"x1","x2"})); +// plot_plane<6>(world,lrf,"lrf_6d",PlotParameters(world).set_plane({"x1","x4"})); @@ -263,7 +271,7 @@ int test_lowrank_function(World& world) { f12.reconstruct(); Function reference=inner(lhs,rhs,{0},{0}); LowRank lrf(rhs); - lrf.project(50,3.0,"random"); + lrf.project(50l,3.0,"random","delta"); lrf.optimize(); double ferror=lrf.error(); @@ -297,7 +305,7 @@ int test_lowrank_function(World& world) { double radius = 5.0; LowRank lr(copy(f)); - lr.project(rank, radius,"random"); + lr.project(rank, radius,"random","delta"); double err = lr.error(); print("error in f_approx", err); lr.orthonormalize(true); @@ -1237,7 +1245,6 @@ int main(int argc, char **argv) { FunctionDefaults<6>::get_thresh()); XParameters parameters; parameters.read_and_set_derived_values(world,parser,"grid"); - parameters.print("grid parameters"); int isuccess=0; #ifdef USE_GENTENSOR diff --git a/src/madness/mra/funcplot.h b/src/madness/mra/funcplot.h index a48917cf8bc..4a826b2e82a 100644 --- a/src/madness/mra/funcplot.h +++ b/src/madness/mra/funcplot.h @@ -83,6 +83,9 @@ namespace madness { template Vector origin() const { auto origin_vec=get>("origin"); + // fill in zeros if the default origin has fewer dimensions than the actual origin + std::size_t missing=NDIM-origin_vec.size(); + for (auto i=0; i o(origin_vec); return o; } From 961baca76a4a6da6df9b0fded62878408fb4e958 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Mon, 21 Aug 2023 14:02:04 -0400 Subject: [PATCH 038/109] update --- src/madness/chem/lowrankfunction.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/madness/chem/lowrankfunction.h b/src/madness/chem/lowrankfunction.h index fbcb8df053d..48f5cb2c36d 100644 --- a/src/madness/chem/lowrankfunction.h +++ b/src/madness/chem/lowrankfunction.h @@ -255,7 +255,7 @@ namespace madness { std::vector> result; for (const auto& point : grid) { auto sl=[&point](const Vector& r) { - return exp(-sqrt(madness::inner(r-point,r-point)+1.e-12)); + return exp(-sqrt(madness::inner(r-point,r-point)+1.e-8)); }; result.push_back(FunctionFactory(world).functor(sl)); } From 71de50a1d2be56f59d3640c6a17276723f3da4da Mon Sep 17 00:00:00 2001 From: fbischoff Date: Tue, 22 Aug 2023 11:19:40 -0400 Subject: [PATCH 039/109] update --- src/madness/chem/lowrankfunction.h | 20 +++++++---- src/madness/chem/test_ccpairfunction.cc | 46 +++++++++++++++++++------ src/madness/mra/vmra.h | 2 +- 3 files changed, 50 insertions(+), 18 deletions(-) diff --git a/src/madness/chem/lowrankfunction.h b/src/madness/chem/lowrankfunction.h index 48f5cb2c36d..54d71011808 100644 --- a/src/madness/chem/lowrankfunction.h +++ b/src/madness/chem/lowrankfunction.h @@ -98,7 +98,6 @@ namespace madness { }; - template class LowRank { public: @@ -196,11 +195,20 @@ namespace madness { World& world=rhs.front().world(); auto premultiply= p1.is_first() ? functor.a : functor.b; auto postmultiply= p1.is_first() ? functor.b : functor.a; - auto tmp=copy(world,rhs); - if (premultiply.is_initialized()) tmp=tmp*premultiply; - result=apply(world,*(functor.f12),tmp); - if (postmultiply.is_initialized()) result=result*postmultiply; + const int nbatch=30; + for (int i=0; i> tmp; + auto begin= rhs.begin()+i; + auto end= (i+nbatch) lrf(f12,copy(phi1),copy(phi2)); // plot_plane<6>(world,lrf.lrfunctor,"plot_f12_r2",PlotParameters(world).set_plane({"x1","x4"})); // lrf.project(parameters.rank(),parameters.radius(),parameters.gridtype(),parameters.rhsfunctiontype()); lrf.project(parameters.volume_element(),parameters.radius(),parameters.gridtype(),parameters.rhsfunctiontype()); - lrf.optimize(parameters.optimize()); - print("lrf.rank()",lrf.rank()); // compare // \phi(1) \bar \phi(1) = \intn phi(1) \phi(2) f(1,2) d2 // = \int \sum_r g_r(1) h_r(2) d2 // = \sum_r g_r(1) <\phi|h_r> - auto reference = phi1* (*f12)(phi2); - real_function_3d result=real_factory_3d(world); - for (int r=0; r(world,{reference, result, diff}, "f_and_approx", PlotParameters(world).set_plane({"x1","x2"})); // plot_plane<6>(world,lrf,"lrf_6d",PlotParameters(world).set_plane({"x1","x4"})); diff --git a/src/madness/mra/vmra.h b/src/madness/mra/vmra.h index eaac3b8e10b..2a56975b41d 100644 --- a/src/madness/mra/vmra.h +++ b/src/madness/mra/vmra.h @@ -532,7 +532,7 @@ namespace madness { Tensor U = transpose(Linv); World& world=v.front().world(); - return transform(world, pv, U); + return transform(world, pv, U,tol); } /// convenience routine for orthonromalize_cholesky: orthonromalize_cholesky without information on pivoting and rank From 8ab0f5f52e3efcdf0f328e27134643b386a7c712 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Tue, 22 Aug 2023 13:14:01 -0400 Subject: [PATCH 040/109] update --- src/madness/chem/lowrankfunction.h | 42 ++++++++++++++++++------------ 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/src/madness/chem/lowrankfunction.h b/src/madness/chem/lowrankfunction.h index 54d71011808..d986f40cf52 100644 --- a/src/madness/chem/lowrankfunction.h +++ b/src/madness/chem/lowrankfunction.h @@ -390,9 +390,12 @@ namespace madness { auto Y=Yformer(grid,rhsfunctiontype); t1.tag("Yforming"); - double tol=1.e-12; + double tol=1.e-8; + std::ostringstream oss; + oss << std::scientific << std::setprecision(1) << tol; + std::string scientificString = oss.str(); g=orthonormalize_rrcd(Y,tol); - t1.tag("Y orthonormalizing with tol"+std::to_string(tol)); + t1.tag("Y orthonormalizing with tol "+scientificString); print("Y.size()",Y.size()); print("g.size()",g.size()); @@ -474,28 +477,34 @@ namespace madness { return s; } - void orthonormalize_cd() { + + /// orthonormalize g or h by rr-cholesky + + /// usage: orthonormalize_cd(h,tol) or orthonormalize_cd(g,tol) + void orthonormalize_cd(const std::vector>& to_ortho, double tol) { + MADNESS_CHECK((&to_ortho == &h) or(&to_ortho == &g)) ; /** - * |g >s< h| = |g_ortho> s < h | - * = |g_ortho> gg s < h | + * |g >< h| = |g_ortho> < h | + * = |g_ortho> gg < h | * = |g_ortho> gg=matrix_inner(world,g_ortho,g); + Tensor gg=matrix_inner(world,ortho,to_ortho); /// Transforms a vector of functions according to new[i] = sum[j] old[j]*c[j,i] -// h=truncate(transform(world,h,transpose(gg))); -// g=truncate(g_ortho); - h=(transform(world,h,transpose(gg))); - g=(g_ortho); + if (&to_ortho == &h) { + g=(transform(world,g,transpose(gg))); + h=(ortho); + } else { + g=(ortho); + h=(transform(world,h,transpose(gg))); + } } @@ -506,13 +515,14 @@ namespace madness { /// optimize using Cholesky decomposition void optimize_cd(const long nopt) { + double tol=1.e-12; timer t(world); for (int iopt=0; ioptorthonormalize_cd(); // g orthonormal, h not + this->orthonormalize_cd(h,tol); // h orthonormal, g not t.tag("ortho1"); auto gtmp=inner(lrfunctor,h,p2,p1); t.tag("inner1"); - g=orthonormalize_rrcd(gtmp,1.e-12); + g=orthonormalize_rrcd(gtmp,tol); t.tag("ortho2"); h=inner(lrfunctor,g,p1,p1); t.tag("inner2"); From f316eff7ecd5e1bd647f1df81d38db8ccfea20e0 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Wed, 23 Aug 2023 13:23:53 -0400 Subject: [PATCH 041/109] update --- src/madness/chem/lowrankfunction.h | 2 +- src/madness/chem/test_ccpairfunction.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/madness/chem/lowrankfunction.h b/src/madness/chem/lowrankfunction.h index d986f40cf52..c984f10a5f4 100644 --- a/src/madness/chem/lowrankfunction.h +++ b/src/madness/chem/lowrankfunction.h @@ -390,7 +390,7 @@ namespace madness { auto Y=Yformer(grid,rhsfunctiontype); t1.tag("Yforming"); - double tol=1.e-8; + double tol=1.e-10; std::ostringstream oss; oss << std::scientific << std::setprecision(1) << tol; std::string scientificString = oss.str(); diff --git a/src/madness/chem/test_ccpairfunction.cc b/src/madness/chem/test_ccpairfunction.cc index 21c301fefc1..4e7a0863407 100644 --- a/src/madness/chem/test_ccpairfunction.cc +++ b/src/madness/chem/test_ccpairfunction.cc @@ -221,7 +221,7 @@ int test_lowrank_function3(World& world, XParameters& parameters) { lrf.optimize(parameters.optimize()); result=compute_result(lrf); - std::string msg="optimization:"+std::to_string(parameters.optimize()); + std::string msg="optimization:"+std::to_string(parameters.optimize())+" "; compute_error(reference,result,lrf,msg); // real_function_3d result=real_factory_3d(world); From 341e4aea432fc95bda9f446e3a12b63b1278c12f Mon Sep 17 00:00:00 2001 From: fbischoff Date: Mon, 4 Sep 2023 10:05:51 +0200 Subject: [PATCH 042/109] ri working to approx 1.e-4 relative error --- src/madness/chem/lowrankfunction.h | 41 ++++++++++++++++---- src/madness/chem/test_ccpairfunction.cc | 50 ++++++++++++------------- 2 files changed, 59 insertions(+), 32 deletions(-) diff --git a/src/madness/chem/lowrankfunction.h b/src/madness/chem/lowrankfunction.h index c984f10a5f4..f57885c9ec4 100644 --- a/src/madness/chem/lowrankfunction.h +++ b/src/madness/chem/lowrankfunction.h @@ -272,6 +272,8 @@ namespace madness { World& world; + double tol; // rrcd tol + bool stable_power_iteration=true; std::vector> g,h; LRFunctor lrfunctor; particle p1=particle::particle1(); @@ -336,7 +338,9 @@ namespace madness { return *this; } - void project(const double volume_per_point, const double radius, const std::string gridtype, std::string rhsfunctiontype) { + void project(const double volume_per_point, const double radius, const std::string gridtype, std::string rhsfunctiontype, + double tol1) { + tol=tol1; long rank=0; if (gridtype=="random") { // number of points within radius = variance: 0.67 * #total points = 0.67*rank @@ -390,7 +394,6 @@ namespace madness { auto Y=Yformer(grid,rhsfunctiontype); t1.tag("Yforming"); - double tol=1.e-10; std::ostringstream oss; oss << std::scientific << std::setprecision(1) << tol; std::string scientificString = oss.str(); @@ -481,7 +484,7 @@ namespace madness { /// orthonormalize g or h by rr-cholesky /// usage: orthonormalize_cd(h,tol) or orthonormalize_cd(g,tol) - void orthonormalize_cd(const std::vector>& to_ortho, double tol) { + void orthonormalize_cd(const std::vector>& to_ortho) { MADNESS_CHECK((&to_ortho == &h) or(&to_ortho == &g)) ; /** * |g >< h| = |g_ortho> < h | @@ -490,13 +493,16 @@ namespace madness { */ World& world=g.front().world(); + timer t(world); auto ortho= orthonormalize_rrcd(to_ortho,tol); + t.tag("ortho_cd ortho_first"); auto ovlp=matrix_inner(world,ortho,ortho); for (int i=0; i gg=matrix_inner(world,ortho,to_ortho); + t.tag("ortho_cd matrix_inner"); /// Transforms a vector of functions according to new[i] = sum[j] old[j]*c[j,i] if (&to_ortho == &h) { g=(transform(world,g,transpose(gg))); @@ -505,20 +511,41 @@ namespace madness { g=(ortho); h=(transform(world,h,transpose(gg))); } - + t.tag("ortho_cd ortho_second"); } void optimize(const long nopt=2) { - optimize_cd(nopt); + optimize_fast(nopt); + } + + /// optimize using Cholesky decomposition + + /// if stable_power_iteration is true, orthonormalize in between applications of the kernel (Alg. 4.4 in Halko) + /// @param[in] nopt number of half iterations (wrt to Alg. 4.3 in Halko) + void optimize_fast(const long nopt) { + timer t(world); + for (int i=0; iorthonormalize_cd(h,tol); // h orthonormal, g not + this->orthonormalize_cd(h); // h orthonormal, g not t.tag("ortho1"); auto gtmp=inner(lrfunctor,h,p2,p1); t.tag("inner1"); diff --git a/src/madness/chem/test_ccpairfunction.cc b/src/madness/chem/test_ccpairfunction.cc index 4e7a0863407..24d5ef87af9 100644 --- a/src/madness/chem/test_ccpairfunction.cc +++ b/src/madness/chem/test_ccpairfunction.cc @@ -24,8 +24,10 @@ struct XParameters : QCCalculationParametersBase { initialize("radius",2.0,"the radius"); initialize("volume_element",0.1,"volume covered by each grid point"); initialize("rank",500,"the number of grid points in random grids"); + initialize("stable_power_iteration",true,"use stable power iteration algorithm (orthonormalize)"); + initialize("tol",1.e-5,"rank-reduced choleski tolerance"); initialize("gridtype","random","the grid type",{"random","cartesian"}); - initialize("rhsfunctiontype","delta","the type of function",{"delta","exponential"}); + initialize("rhsfunctiontype","exponential","the type of function",{"delta","exponential"}); initialize("optimize",0,"number of optimization iterations"); } @@ -35,7 +37,9 @@ struct XParameters : QCCalculationParametersBase { double radius() const {return get("radius");} double volume_element() const {return get("volume_element");} + double tol() const {return get("tol");} long rank() const {return get("rank");} + bool stable_power_iteration() const {return get("stable_power_iteration");} int optimize() const {return get("optimize");} std::string gridtype() const {return get("gridtype");} std::string rhsfunctiontype() const {return get("rhsfunctiontype");} @@ -193,51 +197,47 @@ int test_lowrank_function3(World& world, XParameters& parameters) { for (int r=0; r lrf(f12,copy(phi1),copy(phi2)); + lrf.stable_power_iteration=parameters.stable_power_iteration(); // plot_plane<6>(world,lrf.lrfunctor,"plot_f12_r2",PlotParameters(world).set_plane({"x1","x4"})); // lrf.project(parameters.rank(),parameters.radius(),parameters.gridtype(),parameters.rhsfunctiontype()); - lrf.project(parameters.volume_element(),parameters.radius(),parameters.gridtype(),parameters.rhsfunctiontype()); + double cpu0=cpu_time(); + lrf.project(parameters.volume_element(),parameters.radius(),parameters.gridtype(),parameters.rhsfunctiontype(),parameters.tol()); + double cpu1=cpu_time(); // compare // \phi(1) \bar \phi(1) = \intn phi(1) \phi(2) f(1,2) d2 // = \int \sum_r g_r(1) h_r(2) d2 // = \sum_r g_r(1) <\phi|h_r> real_function_3d result=compute_result(lrf); - compute_error(reference,result,lrf,"initial projection"); + double projection_error=compute_relative_error(reference,result,lrf); + output(projection_error,lrf.rank(),cpu1-cpu0,0.0,0.0,0.0); + cpu0=cpu_time(); lrf.optimize(parameters.optimize()); + cpu1=cpu_time(); result=compute_result(lrf); - std::string msg="optimization:"+std::to_string(parameters.optimize())+" "; - compute_error(reference,result,lrf,msg); - -// real_function_3d result=real_factory_3d(world); -// for (int r=0; r(world,{reference, result, diff}, "f_and_approx", PlotParameters(world).set_plane({"x1","x2"})); -// plot_plane<6>(world,lrf,"lrf_6d",PlotParameters(world).set_plane({"x1","x4"})); - - + double optimization_error=compute_relative_error(reference,result,lrf); + output(projection_error,lrf.rank(),cpu1-cpu0,optimization_error,lrf.rank(),cpu1-cpu0); return t1.end(); From 491e6cbe84d9e82f999b7e84f7ab10fae4f62026 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Mon, 4 Sep 2023 10:55:52 +0200 Subject: [PATCH 043/109] faster by using truncations.. --- src/madness/chem/lowrankfunction.h | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/madness/chem/lowrankfunction.h b/src/madness/chem/lowrankfunction.h index f57885c9ec4..c8feef32c96 100644 --- a/src/madness/chem/lowrankfunction.h +++ b/src/madness/chem/lowrankfunction.h @@ -403,8 +403,8 @@ namespace madness { print("Y.size()",Y.size()); print("g.size()",g.size()); - h=inner(lrfunctor,g,p1,p1); - t1.tag("Y backprojection"); + h=truncate(inner(lrfunctor,g,p1,p1)); + t1.tag("Y backprojection with truncation"); } @@ -521,21 +521,20 @@ namespace madness { /// optimize using Cholesky decomposition /// if stable_power_iteration is true, orthonormalize in between applications of the kernel (Alg. 4.4 in Halko) - /// @param[in] nopt number of half iterations (wrt to Alg. 4.3 in Halko) + /// @param[in] nopt number of iterations (wrt to Alg. 4.3 in Halko) void optimize_fast(const long nopt) { timer t(world); for (int i=0; i Date: Tue, 5 Sep 2023 20:13:38 +0200 Subject: [PATCH 044/109] best rel error is 8.e-5 with thresh 1.e-5, radius 5, volume 1.0, takes 7800 seconds --- src/madness/chem/lowrankfunction.h | 17 ++-- src/madness/chem/test_ccpairfunction.cc | 125 ++++++++++++------------ 2 files changed, 72 insertions(+), 70 deletions(-) diff --git a/src/madness/chem/lowrankfunction.h b/src/madness/chem/lowrankfunction.h index c8feef32c96..3cf2141afc9 100644 --- a/src/madness/chem/lowrankfunction.h +++ b/src/madness/chem/lowrankfunction.h @@ -524,17 +524,18 @@ namespace madness { /// @param[in] nopt number of iterations (wrt to Alg. 4.3 in Halko) void optimize_fast(const long nopt) { timer t(world); + double tight_thresh=FunctionDefaults<3>::get_thresh()*0.1; for (int i=0; i::get_thresh(),FunctionDefaults::get_k(),NDIM); Function f12=FunctionFactory(world).functor([&LDIM](const Vector& r) - { - Vector r1,r2; - for (int i=0; i r1,r2; + for (int i=0; i phi0=FunctionFactory(world).functor([&LDIM](const Vector& r) - { - Vector r1,r2; - for (int i=0; i r1,r2; + for (int i=0; i phi1=FunctionFactory(world).functor([&LDIM](const Vector& r) - { - Vector r1,r2; - for (int i=0; i r1,r2; + for (int i=0; i one=FunctionFactory(world) .functor([&LDIM](const Vector& r){ return 1.0; }); @@ -386,7 +387,7 @@ int test_lowrank_function(World& world) { } int test_constructor(World& world, std::shared_ptr ncf, const Molecule& molecule, - const CCParameters& parameter) { + const CCParameters& parameter) { test_output t1("CCPairFunction::constructor"); real_function_6d f=real_factory_6d(world); @@ -449,7 +450,7 @@ int test_constructor(World& world, std::shared_ptr ncf } int test_operator_apply(World& world, std::shared_ptr ncf, const Molecule& molecule, - const CCParameters& parameter) { + const CCParameters& parameter) { test_output t1("CCPairFunction::test_operator_apply"); // t1.set_cout_to_terminal(); @@ -492,7 +493,7 @@ int test_operator_apply(World& world, std::shared_ptr int test_transformations(World& world, std::shared_ptr ncf, const Molecule& molecule, - const CCParameters& parameter) { + const CCParameters& parameter) { test_output t1("CCPairFunction::test_transformations"); real_function_6d f=real_factory_6d(world); @@ -531,7 +532,7 @@ int test_transformations(World& world, std::shared_ptr } int test_multiply_with_f12(World& world, std::shared_ptr ncf, const Molecule& molecule, - const CCParameters& parameters) { + const CCParameters& parameters) { test_output t1("CCPairFunction::test_multiply_with_f12"); // p1: pure, corresponds to f12 @@ -573,7 +574,7 @@ int test_multiply_with_f12(World& world, std::shared_ptr ncf, const Molecule& molecule, - const CCParameters& parameters) { + const CCParameters& parameters) { test_output t1("CCPairFunction::test_multiply"); // consistency check, relies on CCPairFunction::inner to work correctly @@ -606,7 +607,7 @@ int test_multiply(World& world, std::shared_ptr ncf, c return t1.end(); } int test_inner(World& world, std::shared_ptr ncf, const Molecule& molecule, - const CCParameters& parameters) { + const CCParameters& parameters) { test_output t1("CCPairFunction::test_inner"); t1.set_cout_to_terminal(); @@ -660,8 +661,8 @@ int test_inner(World& world, std::shared_ptr ncf, cons const double prefactor = 1.0 / (4 * y * y); const double ab_f2_ab = prefactor*( ab_ab - -2.0*dot(world,apply(world,fop,a_ij_functions),b_ij_functions).trace() - +dot(world,apply(world,fsq,a_ij_functions),b_ij_functions).trace() ); + -2.0*dot(world,apply(world,fop,a_ij_functions),b_ij_functions).trace() + +dot(world,apply(world,fsq,a_ij_functions),b_ij_functions).trace() ); for (auto& ket : {p2, p3, p4, p5}) { @@ -684,7 +685,7 @@ int test_inner(World& world, std::shared_ptr ncf, cons int test_partial_inner_6d(World& world, std::shared_ptr ncf, const Molecule& molecule, - const CCParameters& parameter) { + const CCParameters& parameter) { CCTimer timer(world, "testing"); test_output t1("CCPairFunction::test_partial_inner_6d"); @@ -809,7 +810,7 @@ int test_partial_inner_6d(World& world, std::shared_ptr ncf, const Molecule& molecule, - const CCParameters& parameter) { + const CCParameters& parameter) { CCTimer timer(world, "testing"); test_output t1("CCPairFunction::test_partial_inner"); @@ -908,7 +909,7 @@ int test_apply(World& world, std::shared_ptr ncf, cons } int test_scalar_multiplication(World& world, std::shared_ptr ncf, const Molecule& molecule, - const CCParameters& parameter) { + const CCParameters& parameter) { CCTimer timer(world, "testing"); test_output t1("CCPairFunction::test_scalar_multiplication"); @@ -1013,7 +1014,7 @@ int test_swap_particles(World& world, std::shared_ptr print("difference norms in exp(-21 - 21):",norm21_21,ref_12_12); double total_error= fabs(norm12_12-ref_12_12)+ fabs(norm12_21-ref_12_21) - + fabs(norm21_12-ref_12_21)+ fabs(norm21_21-ref_12_12); + + fabs(norm21_12-ref_12_21)+ fabs(norm21_21-ref_12_12); t1.checkpoint(total_error < FunctionDefaults<3>::get_thresh(), "swap_particles u"); @@ -1024,7 +1025,7 @@ int test_swap_particles(World& world, std::shared_ptr } int test_projector(World& world, std::shared_ptr ncf, const Molecule& molecule, - const CCParameters& parameter) { + const CCParameters& parameter) { test_output t1("CCPairFunction::test_projector"); CCTimer timer(world, "testing"); @@ -1144,7 +1145,7 @@ int test_dirac_convolution(World& world, std::shared_ptr = 0.032 mEh int test_helium(World& world, std::shared_ptr ncf, const Molecule& molecule, - const CCParameters& parameters) { + const CCParameters& parameters) { test_output t1("CCPairFunction::test_helium"); CCTimer timer(world, "testing"); @@ -1282,7 +1283,7 @@ int main(int argc, char **argv) { // data1=data(world,ccparam); std::shared_ptr ncf = create_nuclear_correlation_factor(world, - mol, nullptr, std::make_pair("slater", 2.0)); + mol, nullptr, std::make_pair("slater", 2.0)); isuccess+=test_lowrank_function3(world,parameters); // isuccess+=test_constructor(world, ncf, mol, ccparam); From 2dab7553f55b77a43dd736d8547bcb35226cc1f3 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Tue, 5 Sep 2023 21:10:26 +0200 Subject: [PATCH 045/109] separating lowrankfunction and ccpairfunction --- src/madness/chem/lowrankfunction.h | 1 + src/madness/chem/test_ccpairfunction.cc | 316 +------- src/madness/chem/test_low_rank_function.cc | 897 +++------------------ 3 files changed, 134 insertions(+), 1080 deletions(-) diff --git a/src/madness/chem/lowrankfunction.h b/src/madness/chem/lowrankfunction.h index 3cf2141afc9..649061d2d52 100644 --- a/src/madness/chem/lowrankfunction.h +++ b/src/madness/chem/lowrankfunction.h @@ -7,6 +7,7 @@ #include +#include #include #include diff --git a/src/madness/chem/test_ccpairfunction.cc b/src/madness/chem/test_ccpairfunction.cc index e0b70eec0f1..6fcd5d48017 100644 --- a/src/madness/chem/test_ccpairfunction.cc +++ b/src/madness/chem/test_ccpairfunction.cc @@ -16,35 +16,6 @@ using namespace madness; -struct XParameters : QCCalculationParametersBase { - - XParameters() : QCCalculationParametersBase() { - - // initialize with: key, value, comment (optional), allowed values (optional) - initialize("radius",2.0,"the radius"); - initialize("volume_element",0.1,"volume covered by each grid point"); - initialize("rank",500,"the number of grid points in random grids"); - initialize("stable_power_iteration",true,"use stable power iteration algorithm (orthonormalize)"); - initialize("tol",1.e-5,"rank-reduced choleski tolerance"); - initialize("gridtype","random","the grid type",{"random","cartesian"}); - initialize("rhsfunctiontype","exponential","the type of function",{"delta","exponential"}); - initialize("optimize",0,"number of optimization iterations"); - } - - void read_and_set_derived_values(World& world, const commandlineparser& parser, std::string tag) { - read_input_and_commandline_options(world,parser,tag); - } - - double radius() const {return get("radius");} - double volume_element() const {return get("volume_element");} - double tol() const {return get("tol");} - long rank() const {return get("rank");} - bool stable_power_iteration() const {return get("stable_power_iteration");} - int optimize() const {return get("optimize");} - std::string gridtype() const {return get("gridtype");} - std::string rhsfunctiontype() const {return get("rhsfunctiontype");} -}; - bool longtest=false; struct data { @@ -161,231 +132,6 @@ class GaussianPotential : public FunctionFunctorInterface { } }; -int test_lowrank_function3(World& world, XParameters& parameters) { - test_output t1("CCPairFunction::low rank function"); - t1.set_cout_to_terminal(); - madness::default_random_generator.setstate(int(cpu_time())%4149); - madness::default_random_generator.setstate(int(cpu_time())%4149); - - constexpr std::size_t LDIM=3; - constexpr std::size_t NDIM=2*LDIM; - print("eps, k, NDIM",FunctionDefaults::get_thresh(),FunctionDefaults::get_k(),NDIM); - - parameters.print("grid","end"); - - Vector offset; - offset.fill(0.0); -// Function phi1=FunctionFactory(world).functor([](const Vector& r) -// { return exp(-r.normf());}); - Function phi1=FunctionFactory(world).functor([](const Vector& r) - { return 1.0;}); - Function phi2=FunctionFactory(world).functor([&offset](const Vector& r) - { return exp(-1.0*(r-offset).normf());}); - Function one=FunctionFactory(world) - .functor([](const Vector& r) { return 1.0;}); - - std::shared_ptr f12(SlaterOperatorPtr(world,1.0,1.e-6,FunctionDefaults::get_thresh())); - -// auto f = [](const coord_6d& r) { -// coord_3d r1={r[0],r[1],r[2]}; -// coord_3d r2={r[3],r[4],r[5]}; -// return exp(-(r1-r2).normf() -r2.normf()); -// }; - - auto compute_result = [&world, &one](const auto& lrf) { - real_function_3d result=real_factory_3d(world); - for (int r=0; r lrf(f12,copy(phi1),copy(phi2)); - lrf.stable_power_iteration=parameters.stable_power_iteration(); -// plot_plane<6>(world,lrf.lrfunctor,"plot_f12_r2",PlotParameters(world).set_plane({"x1","x4"})); -// lrf.project(parameters.rank(),parameters.radius(),parameters.gridtype(),parameters.rhsfunctiontype()); - double cpu0=cpu_time(); - lrf.project(parameters.volume_element(),parameters.radius(),parameters.gridtype(),parameters.rhsfunctiontype(),parameters.tol()); - double cpu1=cpu_time(); - - // compare - // \phi(1) \bar \phi(1) = \intn phi(1) \phi(2) f(1,2) d2 - // = \int \sum_r g_r(1) h_r(2) d2 - // = \sum_r g_r(1) <\phi|h_r> - real_function_3d result=compute_result(lrf); - double projection_error=compute_relative_error(reference,result,lrf); - output(projection_error,lrf.rank(),cpu1-cpu0,0.0,0.0,0.0); - - double cpu2=cpu_time(); - lrf.optimize(parameters.optimize()); - double cpu3=cpu_time(); - result=compute_result(lrf); - double optimization_error=compute_relative_error(reference,result,lrf); - output(projection_error,lrf.rank(),cpu1-cpu0,optimization_error,lrf.rank(),cpu3-cpu2); - - - return t1.end(); - -} - -int test_lowrank_function(World& world) { - test_output t1("CCPairFunction::low rank function"); - t1.set_cout_to_terminal(); - madness::default_random_generator.setstate(int(cpu_time())%4149); - - constexpr std::size_t LDIM=1; - constexpr std::size_t NDIM=2*LDIM; - print("eps, k, NDIM",FunctionDefaults::get_thresh(),FunctionDefaults::get_k(),NDIM); - - Function f12=FunctionFactory(world).functor([&LDIM](const Vector& r) - { - Vector r1,r2; - for (int i=0; i phi0=FunctionFactory(world).functor([&LDIM](const Vector& r) - { - Vector r1,r2; - for (int i=0; i phi1=FunctionFactory(world).functor([&LDIM](const Vector& r) - { - Vector r1,r2; - for (int i=0; i one=FunctionFactory(world) - .functor([&LDIM](const Vector& r){ return 1.0; }); - - // f(1,2) = f12 * phi(1) * phi(2) - Function f = phi0*phi1 *f12; - print("lhs = phi0 * phi1; rhs=phi0*f12"); - auto lhs=phi0*phi1; - auto rhs=phi0*f12; - auto rhsnorm=rhs.norm2(); - - - phi0.reconstruct(); - f12.reconstruct(); - Function reference=inner(lhs,rhs,{0},{0}); - LowRank lrf(rhs); - lrf.project(50l,3.0,"random","delta"); - lrf.optimize(); - - double ferror=lrf.error(); - print("fnorm, error, rel. error",rhsnorm,ferror,ferror/rhsnorm); - - - auto result=inner(lhs,lrf,{0},{0}); - double refnorm=reference.norm2(); - - auto reconstruct=result.reconstruct(); - auto diff=reference-reconstruct; - - double resultnorm=reconstruct.norm2(); - double diffnorm=diff.norm2(); - print("refnorm, resultnorm ",refnorm, resultnorm); - print("resultnorm, error, rel. error",resultnorm,diffnorm,diffnorm/resultnorm); - print("final - one: k,thresh ",FunctionDefaults<2>::get_k(),FunctionDefaults<2>::get_thresh(), - ferror/rhsnorm, diffnorm/resultnorm); - print("\n"); - - plot({reference, reconstruct, diff}, "f_and_approx", std::vector({"adsf", "asdf", "diff"})); - -// return 0; - if (0) { - Function f; - double fnorm = f.norm2(); - print("norm(2D-f)", fnorm); - t1.checkpoint(true, "hi-dim projection"); - - long rank = 50; - double radius = 5.0; - - LowRank lr(copy(f)); - lr.project(rank, radius,"random","delta"); - double err = lr.error(); - print("error in f_approx", err); - lr.orthonormalize(true); - t1.checkpoint(true, "start stuff"); - - err = lr.error(); - print("error in f_approx", err); - t1.checkpoint(true, "compute error"); - if (LDIM < 3) { - auto fapprox = lr.reconstruct(); - plot({f, fapprox, f - fapprox}, "f_and_approx", std::vector({"adsf", "asdf", "diff"})); - t1.checkpoint(true, "plotting"); - } - - /* - * optimize - */ - - lr.optimize(2); - t1.checkpoint(true, "optimization"); - - - err = lr.error(); - print("error in f_approx_opt", err); - - if (LDIM < 3) { - auto fapprox = lr.reconstruct(); - plot({f, fapprox, f - fapprox}, "f_and_approx_opt", - std::vector({"adsf", "asdf", "diff"})); - t1.checkpoint(true, "plotting"); - } - - - /// int f(1,2) f12(2,3) d2 - f12.print_tree(); - auto reference=inner(f,f12,{1},{0}); - auto hbar=copy(world,lr.h); - for (auto& hh : hbar) hh=inner(f12,hh,{0},{0}); - auto result=lr; - result.h=hbar; - auto reference_approx=result.reconstruct(); - result.lrfunctor.f=reference; - double error=result.error(); - print("error ",error); - plot({reference, reference_approx, reference-reference_approx}, "contraction", std::vector({"adsf", "asdf", "diff"})); - } - -// auto result= - - - - - return t1.end(); -} - int test_constructor(World& world, std::shared_ptr ncf, const Molecule& molecule, const CCParameters& parameter) { test_output t1("CCPairFunction::constructor"); @@ -1241,35 +987,12 @@ int main(int argc, char **argv) { madness::World& world = madness::initialize(argc, argv); startup(world, argc, argv); commandlineparser parser(argc, argv); - int k = parser.key_exists("k") ? std::atoi(parser.value("k").c_str()) : 6; - double thresh = parser.key_exists("thresh") ? std::stod(parser.value("thresh")) : 1.e-4; FunctionDefaults<6>::set_tensor_type(TT_2D); - - FunctionDefaults<1>::set_thresh(thresh); - FunctionDefaults<2>::set_thresh(thresh); - FunctionDefaults<3>::set_thresh(thresh); - FunctionDefaults<4>::set_thresh(thresh); - FunctionDefaults<5>::set_thresh(thresh); - FunctionDefaults<6>::set_thresh(1.e-4); - - FunctionDefaults<1>::set_k(k); - FunctionDefaults<2>::set_k(k); - FunctionDefaults<3>::set_k(k); - FunctionDefaults<4>::set_k(k); - FunctionDefaults<5>::set_k(k); - FunctionDefaults<6>::set_k(k); - - FunctionDefaults<1>::set_cubic_cell(-10.,10.); - FunctionDefaults<2>::set_cubic_cell(-10.,10.); - FunctionDefaults<3>::set_cubic_cell(-10.,10.); - FunctionDefaults<4>::set_cubic_cell(-10.,10.); - FunctionDefaults<6>::set_cubic_cell(-10.,10.); - - FunctionDefaults<2>::set_tensor_type(TT_FULL); + FunctionDefaults<3>::set_thresh(1.e-5); + FunctionDefaults<3>::set_cubic_cell(-1.0,1.0); + FunctionDefaults<6>::set_cubic_cell(-1.0,1.0); print("numerical parameters: k, eps(3D), eps(6D)", FunctionDefaults<3>::get_k(), FunctionDefaults<3>::get_thresh(), FunctionDefaults<6>::get_thresh()); - XParameters parameters; - parameters.read_and_set_derived_values(world,parser,"grid"); int isuccess=0; #ifdef USE_GENTENSOR @@ -1280,25 +1003,24 @@ int main(int argc, char **argv) { mol.print(); CCParameters ccparam(world, parser); -// data1=data(world,ccparam); + data1=data(world,ccparam); std::shared_ptr ncf = create_nuclear_correlation_factor(world, - mol, nullptr, std::make_pair("slater", 2.0)); - - isuccess+=test_lowrank_function3(world,parameters); -// isuccess+=test_constructor(world, ncf, mol, ccparam); -// isuccess+=test_operator_apply(world, ncf, mol, ccparam); -// isuccess+=test_transformations(world, ncf, mol, ccparam); -// isuccess+=test_inner(world, ncf, mol, ccparam); -// isuccess+=test_multiply(world, ncf, mol, ccparam); -// isuccess+=test_multiply_with_f12(world, ncf, mol, ccparam); -// isuccess+=test_swap_particles(world, ncf, mol, ccparam); -// isuccess+=test_scalar_multiplication(world, ncf, mol, ccparam); -// isuccess+=test_partial_inner_3d(world, ncf, mol, ccparam); -// isuccess+=test_partial_inner_6d(world, ncf, mol, ccparam); -// isuccess+=test_projector(world, ncf, mol, ccparam); -// FunctionDefaults<3>::set_cubic_cell(-10,10); -// isuccess+=test_helium(world,ncf,mol,ccparam); + mol, nullptr, std::make_pair("slater", 2.0)); + + isuccess+=test_constructor(world, ncf, mol, ccparam); + isuccess+=test_operator_apply(world, ncf, mol, ccparam); + isuccess+=test_transformations(world, ncf, mol, ccparam); + isuccess+=test_inner(world, ncf, mol, ccparam); + isuccess+=test_multiply(world, ncf, mol, ccparam); + isuccess+=test_multiply_with_f12(world, ncf, mol, ccparam); + isuccess+=test_swap_particles(world, ncf, mol, ccparam); + isuccess+=test_scalar_multiplication(world, ncf, mol, ccparam); + isuccess+=test_partial_inner_3d(world, ncf, mol, ccparam); + isuccess+=test_partial_inner_6d(world, ncf, mol, ccparam); + isuccess+=test_projector(world, ncf, mol, ccparam); + FunctionDefaults<3>::set_cubic_cell(-10,10); + isuccess+=test_helium(world,ncf,mol,ccparam); data1.clear(); } catch (std::exception& e) { madness::print("an error occured"); diff --git a/src/madness/chem/test_low_rank_function.cc b/src/madness/chem/test_low_rank_function.cc index 70c57ed92a4..d53bd8e31cf 100644 --- a/src/madness/chem/test_low_rank_function.cc +++ b/src/madness/chem/test_low_rank_function.cc @@ -4,845 +4,176 @@ #include -#include -#include -#include -#include -#include -#include -#include #include +#include + #include +#include #include -template -typename std::enable_if::type compute_error_with_reconstruction(const Tensor& s, - const std::vector>& g, - const std::vector>& h, - const Function& f, - std::string name="") { - auto fapprox=s[0]*hartree_product(g[0],h[0]); - for (int i=1; i({f,fapprox,f-fapprox},name,std::vector({"adsf","asdf","diff"})); - return err; -}; - - -Tensor gaussian_random_distribution(double mean, double variance, long n) { - std::random_device rd{}; - std::mt19937 gen{rd()}; - std::normal_distribution<> d{mean, variance}; - Tensor result(n); - for (int i = 0; i < n; ++i) result(i)=d(gen); - return result; -} - - -Tensor random_factors(const long n, const long nran) { - Tensor factors(n,nran); - for (long i=0; i -std::vector> random_vectors(World &world, - const std::vector>& regular_grid_Y, - const long nran) { - Tensor factors=random_factors(regular_grid_Y.size(),nran); - /// Transforms a vector of functions according to new[i] = sum[j] old[j]*c[j,i] - return truncate(transform(world,regular_grid_Y,factors)); -}; - - -template -struct cartesian_grid { - Vector lovec,hivec; - std::vector stride; - long index=0; - long n_per_dim; - long total_n; - Vector increment; - - cartesian_grid(const long n_per_dim, const double lo, const double hi) - : n_per_dim(n_per_dim) { - lovec.fill(lo); - hivec.fill(hi); - increment=(hivec-lovec)*(1.0/double(n_per_dim-1)); - stride=std::vector(NDIM,1l); - total_n=std::pow(n_per_dim,NDIM); - for (long i=NDIM-2; i>=0; --i) stride[i]=n_per_dim*stride[i+1]; - } - - cartesian_grid(const cartesian_grid& other) : lovec(other.lovec), - hivec(other.hivec), stride(other.stride), index(0), n_per_dim(other.n_per_dim), - total_n(other.total_n), increment(other.increment) { - } - - cartesian_grid& operator=(const cartesian_grid& other) { - cartesian_grid tmp(other); - std::swap(*this,other); - return *this; - } - - double volume_per_gridpoint() const{ - double volume=1.0; - for (int i=0; i get_coordinates() const { - Vector tmp(NDIM); - for (int idim=0; idim -struct gauss { - double a=2.0; - gauss() = default; - double operator()(const Vector& r) const { - return exp(-a*inner(r,r)); + // initialize with: key, value, comment (optional), allowed values (optional) + initialize("radius",2.0,"the radius"); + initialize("volume_element",0.1,"volume covered by each grid point"); + initialize("rank",500,"the number of grid points in random grids"); + initialize("stable_power_iteration",true,"use stable power iteration algorithm (orthonormalize)"); + initialize("tol",1.e-12,"rank-reduced choleski tolerance"); + initialize("gridtype","random","the grid type",{"random","cartesian"}); + initialize("rhsfunctiontype","exponential","the type of function",{"delta","exponential"}); + initialize("optimize",1,"number of optimization iterations"); } -}; -struct hidim_orbitals { - std::shared_ptr f12; - real_function_3d phi1, phi2; - hidim_orbitals(std::shared_ptr& f, const real_function_3d& phi1, const real_function_3d& phi2) - : f12(f), phi1(phi1), phi2(phi2) { - } - - double operator()(const Vector& coord) const { - - Vector left,right; - for (int i=0; i<3; ++i) { - left[i]=coord[i]; - right[i]=coord[i+3]; - } - - auto f12_functor=[](const Vector& r) { - Vector r1,r2; - for (int i=0; i<3; ++i) { - r1[i]=r[i]; - r2[i]=r[i+3]; - } - return exp(-(r1-r2).normf()); - }; - - return phi1(left)*phi2(right)*f12_functor(coord); + void read_and_set_derived_values(World& world, const commandlineparser& parser, std::string tag) { + read_input_and_commandline_options(world,parser,tag); } + double radius() const {return get("radius");} + double volume_element() const {return get("volume_element");} + double tol() const {return get("tol");} + long rank() const {return get("rank");} + bool stable_power_iteration() const {return get("stable_power_iteration");} + int optimize() const {return get("optimize");} + std::string gridtype() const {return get("gridtype");} + std::string rhsfunctiontype() const {return get("rhsfunctiontype");} }; -template -void orthonormalize_svd(World& world, std::vector>& g, std::vector>& h, Tensor& s) { - /** - * |g >s< h| = |g_ortho> s < h | h_ortho > gg s hh U s VT > g_ortho=orthonormalize_canonical(g,1.e-8); - std::vector> h_ortho=orthonormalize_canonical(h,1.e-8); - t.tag("orthonormalize_canonical"); - auto gg=matrix_inner(world,g_ortho,g); - auto hh=matrix_inner(world,h,h_ortho); - t.tag("matrix_inner"); - for (int i=0; i U,VT; - svd(ovlp,U,s,VT); - auto V=transpose(VT); - - // truncate -// for (int i=1; i -std::vector> form_inner(const hidim_orbitals& f, const std::vector>& vec, - const bool transpose) { - double cpu0=cpu_time(); - World& world=vec.front().world(); - std::vector> result; - if (transpose) { - result=f.phi2*apply(world,(*f.f12),vec*f.phi1); - } else { - result=f.phi1*apply(world,(*f.f12),vec*f.phi2); - } - double cpu1=cpu_time(); - std::printf("form inner finished after %4.2fs \n",cpu1-cpu0); - return result; -} - -// note that we assume f is symmetric!!!!! -template -std::vector> form_inner(const Function& f, const std::vector>& vec, - const bool transpose) { - double cpu0=cpu_time(); - std::vector> result(vec.size()); - if (transpose) { - if constexpr (std::is_same,Function>::value) { - for (int i=0; i,Function>::value) { - for (int i=0; i,Function>::value) { -// for (int i=0; i -typename std::enable_if>>::type form_inner(const real_convolution_3d& f, - const std::vector>& vec, const bool transpose) { - double cpu0=cpu_time(); - World& world=vec.front().world(); - std::vector> result=apply(world,f,vec); - double cpu1=cpu_time(); - std::printf("form inner finished after %4.2fs \n",cpu1-cpu0); - return result; -} - -template -std::vector> form_inner(const hidimT& hidim, const std::vector>& vec) { - return form_inner(hidim,vec,false); -} - -template -std::vector> form_inner_transpose(const hidimT& hidim, const std::vector>& vec) { - return form_inner(hidim,vec,true); -} - - -template -class LowRank { -public: - - Tensor s; - std::vector> g,h; - std::string orthonormalize_method="cd"; - cartesian_grid cg; - - LowRank(Tensor& s, std::vector> g, std::vector> h) - : s(s), g(g), h(h) {} - - LowRank(const cartesian_grid& cg) : cg(cg) {} - - LowRank() =default; // Default constructor necessary for storage in vector - - LowRank(const LowRank& a) : s(copy(a.s)), g(copy(a.g.front().world(),a.g)), - h(copy(a.h.front().world(),a.h)), cg(a.cg) {} // Copy constructor necessary - - LowRank& operator=(const LowRank& f) { // Assignment required for storage in vector - LowRank ff(f); - std::swap(ff.s,s); - std::swap(ff.g,g); - std::swap(ff.h,h); - return *this; - } - - template - void project(World& world, const hidimT& f, const std::vector>& regular_grid_Y, const long ntrial) { - - timer t1(world); - auto Y=random_vectors(world, regular_grid_Y, ntrial); - t1.tag("Yforming"); - print("Y.size()",Y.size()); - -// for (int i=0; i> g=orthonormalize_canonical(Y,1.e-8); - g=orthonormalize_cd(Y); -// for (int i=0; i mos; -// mos.set_mos(g); -// std::vector set(g.size(),0); -// mos.update_localize_set(set); -// localizer.localize(mos,true); -// g=mos.get_mos(); -// t1.tag("Y localizing"); -// } - - h=form_inner_transpose(f,g); - s=Tensor(g.size()); - s=1.0; -// orthonormalize(); -// plot_plane<2*LDIM>(world,*this,"lrf00"); -// auto rec=reconstruct(); -// plot_plane<2*LDIM>(world,rec,"lrf00-rec"); - t1.tag("Y backprojection"); - } - - void orthonormalize() { - if (orthonormalize_method=="svd") { - orthonormalize_svd(); - } else if (orthonormalize_method=="cd") { - /** - * |g >s< h| = |g_ortho> s < h | - * = |g_ortho> gg s < h | - * = |g_ortho> gg=matrix_inner(world,g_ortho,g); - for (int i=0; i - void optimize(const hidimT& f, const std::vector>& regular_grid_Y, long nopt=2) { - if (orthonormalize_method=="svd") optimize_svd(f,regular_grid_Y,nopt); - else if (orthonormalize_method=="cd") optimize_cd(f,regular_grid_Y,nopt); - else { - MADNESS_EXCEPTION("confused orthonormalize_method in low_rank_function",1); - } - } - - /// following Halko, Algorithm 4.4 - template - void optimize_cd(const hidimT& f, const std::vector>& regular_grid_Y, long nopt) { - World& world=g.front().world(); - double ssum=s.sum()/s.dim(0); - MADNESS_CHECK(fabs(ssum-1.0)<1.e-10); - for (int iopt=0; iopt(world,*this,"lrf_iter"+std::to_string(iopt)); - if (iopt%2==0) compute_error(f,regular_grid_Y); - t.end("finished optimization iteration "+std::to_string(iopt)); - } - } - - template - void optimize_svd(const hidimT& f, const std::vector>& regular_grid_Y, long nopt) { - World& world=g.front().world(); - for (int iopt=0; iopt> htmp(g.size()), gtmp(g.size()); - - for (int i=0; i1) orthonormalize(); -// plot_plane<2*LDIM>(world,*this,"lrf_iter"+std::to_string(iopt)); - - if (iopt%2==0) compute_error(f,regular_grid_Y); - t.end("finished optimization iteration "+std::to_string(iopt)); - } - } - - T operator()(const Vector& coord) const { - Vector left,right; - for (int i=0; i - double compute_error(const hidimT& f, const std::vector>& regular_grid_Y) const { - const long ntrial=15; - World& world=g.front().world(); - timer t(world); - - // omega(ngrid,ntrial) is a set of random vectors on a regular grid - Tensor omega=random_factors(regular_grid_Y.size(),ntrial); - /// Transforms a vector of functions according to new[i] = sum[j] old[j]*c[j,i] - /// A_omega(1,ntrial) - auto A_omega=transform(world,regular_grid_Y,omega); // this is Y -// print("A_omega.size()",A_omega.size()); - - auto QTAw=matrix_inner(world,g,A_omega); - auto QQTAw=transform(world,g,QTAw); - - // test orthonormality of g - auto gTg=matrix_inner(world,g,g); - for (int i=0; i Aapproxnorms(ntrial,0.0); -// std::vector> A_approx_omega; -// if (LDIM<2) { -// auto A_approx=reconstruct(); -// auto A_approx_omega=transform(world,regular_grid_Y,omega); // this is Y -// print("A_approx_omega.size()",A_approx_omega.size()); -// Aapproxnorms=norm2s(world,A_approx_omega); -// } - - MADNESS_CHECK(std::pow(cg.n_per_dim,LDIM)==regular_grid_Y.size()); - - // h_delta_i = h_j(R_i) - print("volume per gridpoint",cg.volume_per_gridpoint()); - Tensor h_delta_i(g.size(),regular_grid_Y.size()); - auto c=cg; - for (int i=0; i h_omega=inner(h_delta_i,omega); -// print("h_omega.max",h_omega.absmax()); - - - /// Transforms a vector of functions according to new[i] = sum[j] old[j]*c[j,i] - // gh_omega(1,ntrial) - std::vector> gh_omega=transform(world,g,h_omega); // = QQ^T omega -// print("gh_omega.size()",gh_omega.size()); - - std::vector Anorms=norm2s(world,A_omega); -// print("A norms",Anorms); - - std::vector QQTAnorms=norm2s(world,QQTAw); -// print("QQT A norms",QQTAnorms); -// print("A approx norms",Aapproxnorms); - - std::vector ghnorms=norm2s(world,gh_omega); -// print("gh norms",ghnorms); - std::vector QQTA_norms=norm2s(world,A_omega-QQTAw); - std::vector A_gh_norms=norm2s(world,A_omega-gh_omega); -// std::vector A_Approx_norms=norm2s(world,Anorms,Aapproxnorms); -// std::vector Aapprox_gh_norms=norm2s(world,Aapproxnorms-gh_omega); -// print("(1-QQT) A norms ",QQTA_norms); -// print("A - gh diff norms ",A_gh_norms); -// print("A_approx - gh diff norms",A_Approx_norms); -// print("A - A_approx diff norms ",Aapprox_gh_norms); - double max_gh=*std::max_element(A_gh_norms.begin(),A_gh_norms.end()); - double err_gh=10.0*sqrt(2.0/constants::pi)*max_gh* cg.volume_per_gridpoint(); - double max_QQT=*std::max_element(QQTA_norms.begin(),QQTA_norms.end()); - double err_QQT=10.0*sqrt(2.0/constants::pi)*max_QQT* cg.volume_per_gridpoint(); - std::stringstream ss; - - ss << "rank and error in f_approx " << g.size() << " " << std::scientific << err_gh << "; QQTA: " << err_QQT; - t.tag(ss.str()); - - if constexpr (LDIM<2) compute_error_with_reconstruction(s,h,g,f,"name"); - - return err_gh; - } - - Function reconstruct() const { - auto fapprox=s[0]*hartree_product(g[0],h[0]); - for (int i=1; i -double inner(const LowRank& a, const LowRank& b) { - World& world=a.world; - return (matrix_inner(world,a.g,b.g).emul(matrix_inner(world,a.h,b.h))).sum(); -} - - - -template -typename std::enable_if<(LDIM==3), real_convolution_3d>::type hidim(World& world) { - auto f_op= SlaterOperator(world,1.0,1.e-8,0.1*FunctionDefaults<3>::get_thresh()); - auto f12_functor=[](const Vector& r) { - Vector r1,r2; - for (int i=0; i(world,f12_functor,"f12_functor"); - return f_op; -} - -template -typename std::enable_if<(LDIM<3), Function>::type hidim(World& world) { - - auto f12_functor=[](const Vector& r) { - Vector r1,r2; - for (int i=0; i(world).functor(f12_functor); - plot_plane<2*LDIM>(world,f12_functor,"f12_functor"); -// Function f; - return f; -} - -template -std::vector> uniformly_distributed_slater(World& world, - cartesian_grid& cg) { - Vector R; - auto sl=[&R](const Vector& r) { - return exp(-sqrt(inner(r-R,r-R)+1.e-12)); - }; - - std::vector> result; - auto c=cg; - c.index=0; - for (; c(); ++c) { - R=c.get_coordinates(); - result.push_back(FunctionFactory(world).functor(sl)); - } - return result; - -} - -real_function_6d K(World& world, const real_function_6d& f, const real_function_3d& phi) { - - print("entering K(real_function_6d)"); - timer t1(world); - const int particle=1; - real_convolution_3d op = CoulombOperator(world, 0.0001, FunctionDefaults<3>::get_thresh()); - op.destructive() = true; - op.particle() = particle; - - real_function_6d x = multiply(copy(f), copy(phi), particle).truncate(); - t1.tag("multiply before"); - x = op(x).truncate(); - t1.tag("apply G"); - real_function_6d result = multiply(x, copy(phi), particle).truncate(); - t1.tag("multiply after"); - - return result; -} - -template -LowRank K(World& world, const LowRank& f, const Function& phi) { - - print("entering K(LowRank)"); - timer t1(world); - const int particle=1; - real_convolution_3d op = CoulombOperator(world, 0.0001, FunctionDefaults<3>::get_thresh()); - op.destructive() = true; - op.particle() = particle; - - auto tmp=truncate(mul(world,phi,f.g)); - t1.tag("multiply before"); - auto x = apply(world,op,tmp); - t1.tag("apply G"); - auto g_final=mul(world,phi,x); - t1.tag("multiply after"); - LowRank result=f; - result.g=g_final; - - return result; -} - -int test_lowrank_function(World& world) { +int test_lowrank_function(World& world, LowRankFunctionParameters& parameters) { + test_output t1("CCPairFunction::low rank function"); + t1.set_cout_to_terminal(); + madness::default_random_generator.setstate(int(cpu_time())%4149); madness::default_random_generator.setstate(int(cpu_time())%4149); - print(""); constexpr std::size_t LDIM=3; - long n_per_dim=10; - double radius=2.0; - long ntrial=120; - - - - print("LDIM, n_per_dim, ntrial",LDIM,n_per_dim,ntrial); constexpr std::size_t NDIM=2*LDIM; - timer t1(world); - - Function phi_slater=FunctionFactory(world) - .functor([](const Vector& r) {return exp(-2.0*r.normf());}); - - Function phi_gauss=FunctionFactory(world) - .functor([](const Vector& r) {return exp(-2.0*inner(r,r));}); - + print("eps, k, NDIM",FunctionDefaults::get_thresh(),FunctionDefaults::get_k(),NDIM); + + parameters.print("grid","end"); + + Vector offset; + offset.fill(0.0); +// Function phi1=FunctionFactory(world).functor([](const Vector& r) +// { return exp(-r.normf());}); + Function phi1=FunctionFactory(world).functor([](const Vector& r) + { return 1.0;}); + Function phi2=FunctionFactory(world).functor([&offset](const Vector& r) + { return exp(-1.0*(r-offset).normf());}); Function one=FunctionFactory(world) - .functor([](const Vector& r) {return 1.0;}); - - Function phi_gauss_displaced=FunctionFactory(world) - .functor([](const Vector& r) { - Vector R; - R.fill(0.5); - return exp(-1.0*inner(r-R,r-R)); - }); - - Function phi1=copy(phi_slater); - Function phi2=copy(one); - - auto f=hidim(world); -// std::shared_ptr f12(SlaterOperatorPtr(world,1.0,1.e-6,FunctionDefaults::get_thresh())); -// auto f=hidim_orbitals(f12,phi1,phi2); - -// plot_plane<2*LDIM>(world,f,"hidim_orbitals"); - - - double lo=-radius; - double hi=radius; - - - cartesian_grid cg(n_per_dim,lo,hi); - LowRank lrf(cg); - - auto regular_grid_Y=uniformly_distributed_slater(world,cg); -// for (int i=0; i phi2_values(regular_grid_Y.size()); - for (auto c=cg; c(); ++c) { - phi2_values[c.index]=phi2(c.get_coordinates()); -// print("c.index, coord",c.index,c.get_coordinates(),phi2_values[c.index]); - } - scale(world,regular_grid_Y,phi2_values); - regular_grid_Y=regular_grid_Y*phi1; + .functor([](const Vector& r) { return 1.0;}); - print("regular_grid_Y.size()",regular_grid_Y.size()); + std::shared_ptr f12(SlaterOperatorPtr(world,1.0,1.e-6,FunctionDefaults::get_thresh())); - lrf.project(world,f,regular_grid_Y,ntrial); +// auto f = [](const coord_6d& r) { +// coord_3d r1={r[0],r[1],r[2]}; +// coord_3d r2={r[3],r[4],r[5]}; +// return exp(-(r1-r2).normf() -r2.normf()); +// }; - t1.tag("project"); - lrf.compute_error(f,regular_grid_Y); -// lrf.orthonormalize(); -// lrf.compute_error(f,regular_grid_Y); - t1.tag("compute error"); - - plot_plane<2*LDIM>(world,lrf,"lrf0"); - t1.tag("plot lrf0"); - - print("\nstarting optimization\n"); - - lrf.optimize(f,regular_grid_Y,2); - t1.tag("optimize"); - - lrf.compute_error(f,regular_grid_Y); - plot_plane<2*LDIM>(world,lrf,"lrf1"); - - t1.end("total time "); - - real_function_6d f12f=TwoElectronFactory(world).slater(); - real_function_6d full_f=CompositeFactory(world).g12(f12f) - .particle1(copy(phi1)).particle2(copy(-1.0*phi2)); - full_f.fill_cuspy_tree(); - plot_plane<2*LDIM>(world,full_f,"full_f"); - - auto lrf_reconstruct=lrf.reconstruct(); - auto diff=(lrf_reconstruct-full_f).norm2(); - print("diff(lrf-full_f) ",diff); - - // apply K - auto klrf=K(world,lrf,phi1); - plot_plane<2*LDIM>(world,klrf,"Klrf"); - auto kfull_f=K(world,full_f,phi1); - plot_plane<2*LDIM>(world,kfull_f,"Kfull_f"); - - auto klrf_reconstruct=klrf.reconstruct(); - auto kdiff=(klrf_reconstruct-kfull_f).norm2(); - print("diff(K(lrf)-K(full_f)) ",kdiff); + auto compute_result = [&world, &one](const auto& lrf) { + real_function_3d result=real_factory_3d(world); + for (int r=0; r lrf(f12,copy(phi1),copy(phi2)); + lrf.stable_power_iteration=parameters.stable_power_iteration(); +// plot_plane<6>(world,lrf.lrfunctor,"plot_f12_r2",PlotParameters(world).set_plane({"x1","x4"})); +// lrf.project(parameters.rank(),parameters.radius(),parameters.gridtype(),parameters.rhsfunctiontype()); + double cpu0=cpu_time(); + lrf.project(parameters.volume_element(),parameters.radius(),parameters.gridtype(),parameters.rhsfunctiontype(),parameters.tol()); + double cpu1=cpu_time(); -int test_6d_convolution(World& world) { - timer t1(world); - real_function_3d one=real_factory_3d(world).functor([](const coord_3d& r){return 1.0;}); - real_function_3d phi=real_factory_3d(world).functor([](const coord_3d& r){return exp(-2.0*inner(r,r));}); -// auto f12= SlaterF12Operator(world,1.0,1.e-4,1.e-3); - auto g12=CoulombOperator(world,1.e-4,1.e-4); - g12.particle()=1; - auto f12=TwoElectronFactory(world).dcut(1.e-7).f12().gamma(1.0); - { - real_function_6d f = CompositeFactory(world).g12(f12).particle1(copy(phi)).particle2(copy(phi)); - f.fill_cuspy_tree(); - f.print_size("cuspy tree phi(1)phi(2)"); - t1.tag("fill cuspy tree"); - real_function_6d X = (multiply(f, copy(phi), 1)).truncate(); - real_function_6d Y = g12(X); // overwrite X to save space - real_function_6d Z = (multiply(f, copy(phi), 1)).truncate(); - t1.tag("apply exchange"); + // compare + // \phi(1) \bar \phi(1) = \int phi(1) \phi(2) f(1,2) d2 + // = \int \sum_r g_r(1) h_r(2) d2 + // = \sum_r g_r(1) <\phi|h_r> + real_function_3d result=compute_result(lrf); + double projection_error=compute_relative_error(reference,result,lrf); + output(projection_error,lrf.rank(),cpu1-cpu0,0.0,0.0,0.0); + double cpu2=cpu_time(); + lrf.optimize(parameters.optimize()); + double cpu3=cpu_time(); + result=compute_result(lrf); + double optimization_error=compute_relative_error(reference,result,lrf); + output(projection_error,lrf.rank(),cpu1-cpu0,optimization_error,lrf.rank(),cpu3-cpu2); + bool success=(projection_error<5.e-2) and (optimization_error<1.e-2); - } - { - real_function_6d f = CompositeFactory(world).g12(f12).particle1(copy(phi)).particle2(copy(one)); - f.fill_cuspy_tree(); - f.print_size("cuspy tree phi(1)one(2)"); - t1.tag("fill cuspy tree"); - real_function_6d X = (multiply(f, copy(phi), 1)).truncate(); - real_function_6d Y = g12(X); // overwrite X to save space - real_function_6d Z = (multiply(f, copy(phi), 1)).truncate(); - t1.tag("apply exchange"); - } - t1.tag("fill cuspy tree"); - return 1.0; + return t1.end(success); } - int main(int argc, char **argv) { madness::World& world = madness::initialize(argc, argv); startup(world, argc, argv); commandlineparser parser(argc, argv); + int k = parser.key_exists("k") ? std::atoi(parser.value("k").c_str()) : 6; + double thresh = parser.key_exists("thresh") ? std::stod(parser.value("thresh")) : 1.e-4; FunctionDefaults<6>::set_tensor_type(TT_2D); - double thresh=1.e-4; - int k=6; FunctionDefaults<1>::set_thresh(thresh); - FunctionDefaults<1>::set_cubic_cell(-10.,10.); - FunctionDefaults<1>::set_k(k); FunctionDefaults<2>::set_thresh(thresh); - FunctionDefaults<2>::set_cubic_cell(-10.,10.); - FunctionDefaults<2>::set_k(k); FunctionDefaults<3>::set_thresh(thresh); - FunctionDefaults<3>::set_cubic_cell(-10.,10.); - FunctionDefaults<3>::set_k(k); FunctionDefaults<4>::set_thresh(thresh); - FunctionDefaults<4>::set_cubic_cell(-10.,10.); - FunctionDefaults<4>::set_k(k); + FunctionDefaults<5>::set_thresh(thresh); FunctionDefaults<6>::set_thresh(thresh); - FunctionDefaults<6>::set_cubic_cell(-10.,10.); + + FunctionDefaults<1>::set_k(k); + FunctionDefaults<2>::set_k(k); + FunctionDefaults<3>::set_k(k); + FunctionDefaults<4>::set_k(k); + FunctionDefaults<5>::set_k(k); FunctionDefaults<6>::set_k(k); + + FunctionDefaults<1>::set_cubic_cell(-10.,10.); + FunctionDefaults<2>::set_cubic_cell(-10.,10.); + FunctionDefaults<3>::set_cubic_cell(-10.,10.); + FunctionDefaults<4>::set_cubic_cell(-10.,10.); + FunctionDefaults<5>::set_cubic_cell(-10.,10.); + FunctionDefaults<6>::set_cubic_cell(-10.,10.); + + FunctionDefaults<2>::set_tensor_type(TT_FULL); print("numerical parameters: k, eps(3D), eps(6D)", FunctionDefaults<3>::get_k(), FunctionDefaults<3>::get_thresh(), FunctionDefaults<6>::get_thresh()); + LowRankFunctionParameters parameters; + parameters.read_and_set_derived_values(world,parser,"grid"); int isuccess=0; #ifdef USE_GENTENSOR try { parser.set_keyval("geometry", "he"); parser.print_map(); - Molecule mol(world, parser); - mol.print(); - CCParameters ccparam(world, parser); - -// isuccess+= test_6d_convolution(world); - -// std::shared_ptr ncf = create_nuclear_correlation_factor(world, -// mol, nullptr, std::make_pair("slater", 2.0)); - isuccess+=test_lowrank_function(world); + isuccess+=test_lowrank_function(world,parameters); } catch (std::exception& e) { madness::print("an error occured"); madness::print(e.what()); @@ -853,4 +184,4 @@ int main(int argc, char **argv) { finalize(); return isuccess; -} +} \ No newline at end of file From a0593f0658ec774218f54bb7a8ebe41f2ccf16fe Mon Sep 17 00:00:00 2001 From: fbischoff Date: Thu, 7 Sep 2023 12:57:11 +0200 Subject: [PATCH 046/109] mostly refactoring operator.h for easier construction of various operators --- src/madness/chem/CCPotentials.cc | 14 +- src/madness/chem/CCStructures.cc | 30 +- src/madness/chem/CCStructures.h | 115 +----- src/madness/chem/TDHF.cc | 2 +- src/madness/chem/ccpairfunction.cc | 128 +++---- src/madness/chem/lowrankfunction.h | 227 ++++------- src/madness/chem/mp2.cc | 8 +- src/madness/chem/test_low_rank_function.cc | 58 ++- src/madness/misc/CMakeLists.txt | 2 +- src/madness/misc/misc.h | 2 + src/madness/misc/unique_filename.cc | 25 ++ src/madness/mra/gfit.h | 95 +++-- src/madness/mra/operator.h | 414 ++++++++++++--------- src/madness/mra/vmra.h | 9 + 14 files changed, 570 insertions(+), 559 deletions(-) create mode 100644 src/madness/misc/unique_filename.cc diff --git a/src/madness/chem/CCPotentials.cc b/src/madness/chem/CCPotentials.cc index f6f7b9df637..b5de6c1b837 100644 --- a/src/madness/chem/CCPotentials.cc +++ b/src/madness/chem/CCPotentials.cc @@ -28,8 +28,8 @@ CCPotentials::CCPotentials(World& world_, std::shared_ptr nemo, const CCP corrfac(world, param.gamma(), 1.e-7, nemo->get_calc()->molecule), get_potentials(world, param), output(world) { - g12=std::shared_ptr(new CCConvolutionOperator(world,OT_G12,param)); - f12=std::shared_ptr(new CCConvolutionOperator(world,OT_F12,param)); + g12=std::shared_ptr(new CCConvolutionOperator(world,OpType::OT_G12,param)); + f12=std::shared_ptr(new CCConvolutionOperator(world,OpType::OT_F12,param)); output.debug = parameters.debug(); // reset_nemo(nemo); // g12.update_elements(mo_bra_, mo_ket_); @@ -1886,11 +1886,11 @@ CCPotentials::make_xy_op_u(const CCFunction& x, const CCFunction& y, const CCCon result = inner(u.get_function(), xy_op); } else if (u.component->is_decomposed()) { if (u.component->has_operator()) { - if (op.type() == OT_G12 and u.decomposed().get_operator_ptr()->type() == OT_F12) + if (op.type() == OpType::OT_G12 and u.decomposed().get_operator_ptr()->type() == OpType::OT_F12) result = make_xy_gf_ab(x, y, u.decomposed().get_a()[0], u.decomposed().get_b()[0]); - else if (op.type() == OT_F12 and u.decomposed().get_operator_ptr()->type() == OT_G12) + else if (op.type() == OpType::OT_F12 and u.decomposed().get_operator_ptr()->type() == OpType::OT_G12) result = make_xy_gf_ab(x, y, u.decomposed().get_a()[0], u.decomposed().get_b()[0]); - else if (op.type() == OT_F12 and u.decomposed().get_operator_ptr()->type() == OT_F12) + else if (op.type() == OpType::OT_F12 and u.decomposed().get_operator_ptr()->type() == OpType::OT_F12) result = make_xy_ff_ab(x, y, u.decomposed().get_a()[0], u.decomposed().get_b()[0]); else MADNESS_EXCEPTION(("xy_" + op.name() + u.name() + " not implemented").c_str(), 1); } else { @@ -3209,7 +3209,7 @@ real_function_6d CCPotentials::make_6D_pair(const CCPair& pair) const { result += ab; } } else if (f.is_op_decomposed()) { - MADNESS_ASSERT(f.get_operator().type() == OT_F12); + MADNESS_ASSERT(f.get_operator().type() == OpType::OT_F12); real_function_6d fxy = make_f_xy(f.get_a()[0], f.get_b()[0]); result += fxy; } else MADNESS_EXCEPTION("Unknown type of CCPairFunction", 1); @@ -3415,7 +3415,7 @@ void CCPotentials::test_singles_potential() const { void CCPotentials::test() { output.section("Testing enums"); CalcType test2 = CT_MP2; - OpType test3 = OT_G12; + OpType test3 = OpType::OT_G12; FuncType test4 = HOLE; CCState test5 = GROUND_STATE; PotentialType test6 = POT_F3D_; diff --git a/src/madness/chem/CCStructures.cc b/src/madness/chem/CCStructures.cc index 97d60d6d6c1..998ad8cd05a 100644 --- a/src/madness/chem/CCStructures.cc +++ b/src/madness/chem/CCStructures.cc @@ -322,7 +322,7 @@ CCConvolutionOperator::operator()(const CCFunction& bra, const CCFunction& ket, real_function_6d CCConvolutionOperator::operator()(const real_function_6d& u, const size_t particle) const { MADNESS_ASSERT(particle == 1 or particle == 2); - MADNESS_ASSERT(operator_type == OT_G12); + MADNESS_ASSERT(operator_type == OpType::OT_G12); MADNESS_ASSERT(op); op->particle() = particle; return (*op)(u); @@ -331,7 +331,7 @@ real_function_6d CCConvolutionOperator::operator()(const real_function_6d& u, co real_function_3d CCConvolutionOperator::operator()(const CCFunction& bra, const real_function_6d& u, const size_t particle) const { MADNESS_ASSERT(particle == 1 or particle == 2); - MADNESS_ASSERT(operator_type == OT_G12); + MADNESS_ASSERT(operator_type == OpType::OT_G12); MADNESS_ASSERT(op); const real_function_6d tmp = multiply(copy(u), copy(bra.function), particle); op->particle() = particle; @@ -409,43 +409,43 @@ CCConvolutionOperator::init_op(const OpType& type, const Parameters& parameters) bool debug=false; bool printme=(world.rank()==0) and debug; switch (type) { - case OT_G12 : { + case OpType::OT_G12 : { if (printme) std::cout << "Creating " << assign_name(type) << " Operator with thresh=" << parameters.thresh_op << " and lo=" << parameters.lo << std::endl; return CoulombOperatorPtr(world, parameters.lo, parameters.thresh_op); } - case OT_F12 : { + case OpType::OT_F12 : { if (printme) std::cout << "Creating " << assign_name(type) << " Operator with thresh=" << parameters.thresh_op << " and lo=" << parameters.lo << " and Gamma=" << parameters.gamma << std::endl; return SlaterF12OperatorPtr(world, parameters.gamma, parameters.lo, parameters.thresh_op); } - case OT_SLATER : { + case OpType::OT_SLATER : { if (printme) std::cout << "Creating " << assign_name(type) << " Operator with thresh=" << parameters.thresh_op << " and lo=" << parameters.lo << " and Gamma=" << parameters.gamma << std::endl; return SlaterOperatorPtr(world, parameters.gamma, parameters.lo, parameters.thresh_op); } - case OT_BSH : { + case OpType::OT_BSH : { if (printme) std::cout << "Creating " << assign_name(type) << " Operator with thresh=" << parameters.thresh_op << " and lo=" << parameters.lo << " and Gamma=" << parameters.gamma << std::endl; return BSHOperatorPtr3D(world, parameters.gamma, parameters.lo, parameters.thresh_op); } - case OT_FG12: { + case OpType::OT_FG12: { if (printme) std::cout << "Creating " << assign_name(type) << " Operator with thresh=" << parameters.thresh_op << " and lo=" << parameters.lo << " and Gamma=" << parameters.gamma << std::endl; return FGOperatorPtr(world, parameters.gamma, parameters.lo, parameters.thresh_op); } - case OT_F2G12: { + case OpType::OT_F2G12: { if (printme) std::cout << "Creating " << assign_name(type) << " Operator with thresh=" << parameters.thresh_op << " and lo=" << parameters.lo << " and Gamma=" << parameters.gamma << std::endl; return F2GOperatorPtr(world, parameters.gamma, parameters.lo, parameters.thresh_op); } - case OT_ONE : { + case OpType::OT_ONE : { if (printme) std::cout << "Creating " << assign_name(type) << " Operator " << std::endl; return nullptr; @@ -479,17 +479,17 @@ assign_name(const CCState& input) { std::string assign_name(const OpType& input) { switch (input) { - case OT_G12: + case OpType::OT_G12: return "g12"; - case OT_F12: + case OpType::OT_F12: return "f12"; - case OT_SLATER: + case OpType::OT_SLATER: return "slater"; - case OT_FG12: + case OpType::OT_FG12: return "fg12"; - case OT_BSH: + case OpType::OT_BSH: return "bsh"; - case OT_ONE: + case OpType::OT_ONE: return "identity"; default: { MADNESS_EXCEPTION("Unvalid enum assignement!", 1); diff --git a/src/madness/chem/CCStructures.h b/src/madness/chem/CCStructures.h index 13bd019ab82..58c5db3a382 100644 --- a/src/madness/chem/CCStructures.h +++ b/src/madness/chem/CCStructures.h @@ -11,6 +11,7 @@ #define CCSTRUCTURES_H_ #include + #include #include #include @@ -21,19 +22,6 @@ namespace madness { -/// Operatortypes used by the CCConvolutionOperator Class -enum OpType { - OT_UNDEFINED, - OT_ONE, /// indicates the identity - OT_G12, /// 1/r - OT_SLATER, /// exp(-r) - OT_F12, /// 1-exp(-r) - OT_FG12, /// (1-exp(-r))/r - OT_F212, /// (1-exp(-r))^2 - OT_F2G12, /// (1-exp(-r))^2/r = 1/r + exp(-2r)/r - 2 exp(-r)/r - OT_BSH /// exp(-r)/r -}; - /// Calculation Types used by CC2 enum CalcType { CT_UNDEFINED, CT_MP2, CT_CC2, CT_LRCCS, CT_LRCC2, CT_CISPD, CT_ADC2, CT_TDHF, CT_TEST @@ -741,87 +729,22 @@ struct CCConvolutionOperator { CCConvolutionOperator(const CCConvolutionOperator& other) = default; - friend bool can_combine(const CCConvolutionOperator& left, const CCConvolutionOperator& right) { - return (combine_OT(left,right).first!=OT_UNDEFINED); - } - - friend std::pair combine_OT(const CCConvolutionOperator& left, const CCConvolutionOperator& right) { - OpType type=OT_UNDEFINED; - Parameters param=left.parameters; - if ((left.type()==OT_F12) and (right.type()==OT_G12)) { - type=OT_FG12; - } - if ((left.type()==OT_G12) and (right.type()==OT_F12)) { - type=OT_FG12; - param.gamma=right.parameters.gamma; - } - if ((left.type()==OT_G12) and (right.type()==OT_F212)) { - type=OT_F2G12; - param.gamma=right.parameters.gamma; - } - if (((left.type()==OT_F212) and (right.type()==OT_G12)) or - ((left.type()==OT_F12) and (right.type()==OT_FG12)) or - ((left.type()==OT_FG12) and (right.type()==OT_F12))) { - type=OT_F2G12; - if (right.type()!=OT_G12) MADNESS_CHECK(right.parameters.gamma == left.parameters.gamma); - param.gamma=right.parameters.gamma; - } - if ((left.type()==OT_F12) and (right.type()==OT_F12)) { - type=OT_F212; - // keep the original gamma - // (f12)^2 = (1- slater12)^2 = 1/(4 gamma) (1 - 2 exp(-gamma) + exp(-2 gamma)) - MADNESS_CHECK(right.parameters.gamma == left.parameters.gamma); - } - return std::make_pair(type,param); - } - - - /// combine 2 convolution operators to one +protected: - /// @return a vector of pairs: factor and convolution operator - friend std::vector> combine(const std::shared_ptr left, - const std::shared_ptr right) { - std::vector> result; - if (left and right) return combine(*left,*right); - if (left) { - result.push_back(std::make_pair(1.0,CCConvolutionOperator(*left))); - } else if (right) { - result.push_back(std::make_pair(1.0,CCConvolutionOperator(*right))); - } - return result; + friend CCConvolutionOperator combine(const CCConvolutionOperator& a, const CCConvolutionOperator& b) { + auto info= SeparatedConvolution::combine_OT((*a.get_op()),(*b.get_op())); + Parameters param; + param.gamma=info.mu; + param.thresh_op=info.thresh; + param.lo=info.lo; + param.freeze=a.parameters.freeze; + return CCConvolutionOperator(a.world, info.type, param); } -protected: - /// combine 2 convolution operators to one - - /// @return a vector of pairs: factor and convolution operator - friend std::vector> combine(const CCConvolutionOperator& left, const CCConvolutionOperator& right) { - MADNESS_CHECK(can_combine(left,right)); - MADNESS_CHECK(left.world.id()==right.world.id()); - auto [type,param]=combine_OT(left,right); - std::vector> result; - if (type==OT_FG12) { - // fg = (1 - exp(-gamma r12)) / r12 = 1/r12 - exp(-gamma r12)/r12 = coulomb - bsh - result.push_back(std::make_pair(1.0, CCConvolutionOperator(left.world, OT_FG12, param))); - - } else if (type==OT_F2G12) { - result.push_back(std::make_pair(1.0, CCConvolutionOperator(left.world, OT_F2G12, param))); - - } else if (type==OT_F212) { -// we use the slater operator which is S = e^(-y*r12), y=gamma -// the f12 operator is: 1/2y*(1-e^(-y*r12)) = 1/2y*(1-S) -// so the squared f12 operator is: f*f = 1/(4*y*y)(1-2S+S*S), S*S = S(2y) = e(-2y*r12) -// we have then: = 1/(4*y*y)*( - 2* + ) -// we have then: =( - 1/(4*y*y)*2* - MADNESS_CHECK(left.parameters.gamma==right.parameters.gamma); - const double prefactor = 1.0 / (4.0 * param.gamma); // Slater has no 1/(2 gamma) per se. - Parameters param2=param; - param2.gamma*=2.0; - result.push_back(std::make_pair(1.0*prefactor,CCConvolutionOperator(left.world, OT_ONE, param))); - result.push_back(std::make_pair(-2.0*prefactor,CCConvolutionOperator(left.world, OT_SLATER, left.parameters))); - result.push_back(std::make_pair(1.0*prefactor,CCConvolutionOperator(left.world, OT_SLATER, param2))); - } - return result; + friend std::shared_ptr combine(const std::shared_ptr& a, + const std::shared_ptr& b) { + auto bla=combine(*a,*b); + return std::shared_ptr(new CCConvolutionOperator(combine(*a,*b))); } public: @@ -912,10 +835,10 @@ struct CCConvolutionOperator { /// create a TwoElectronFactory with the operatorkernel TwoElectronFactory get_kernel() const { - if (type() == OT_G12) return TwoElectronFactory(world).dcut(1.e-7); - else if (type() == OT_F12) return TwoElectronFactory(world).dcut(1.e-7).f12().gamma(parameters.gamma); - else if (type() == OT_FG12) return TwoElectronFactory(world).dcut(1.e-7).BSH().gamma(parameters.gamma); - else if (type() == OT_SLATER) return TwoElectronFactory(world).dcut(1.e-7).slater().gamma(parameters.gamma); + if (type() == OpType::OT_G12) return TwoElectronFactory(world).dcut(1.e-7); + else if (type() == OpType::OT_F12) return TwoElectronFactory(world).dcut(1.e-7).f12().gamma(parameters.gamma); + else if (type() == OpType::OT_FG12) return TwoElectronFactory(world).dcut(1.e-7).BSH().gamma(parameters.gamma); + else if (type() == OpType::OT_SLATER) return TwoElectronFactory(world).dcut(1.e-7).slater().gamma(parameters.gamma); else error("no kernel of type " + name() + " implemented"); return TwoElectronFactory(world); } @@ -930,7 +853,7 @@ struct CCConvolutionOperator { /// the world World& world; /// the operatortype, currently this can be g12_ or f12_ - const OpType operator_type = OT_UNDEFINED; + const OpType operator_type = OpType::OT_UNDEFINED; /// @param[in] optype: can be f12_ or g12_ depending on which operator shall be intitialzied /// @param[in] parameters: parameters (thresholds etc) diff --git a/src/madness/chem/TDHF.cc b/src/madness/chem/TDHF.cc index 764896ece0b..a21e282ebf4 100644 --- a/src/madness/chem/TDHF.cc +++ b/src/madness/chem/TDHF.cc @@ -69,7 +69,7 @@ void TDHF::initialize() { msg.section("Initialize TDHF Class"); msg.debug = parameters.debug(); - g12=std::make_shared(world, OT_G12, parameters.get_ccc_parameters(get_calcparam().lo())); + g12=std::make_shared(world, OpType::OT_G12, parameters.get_ccc_parameters(get_calcparam().lo())); const double old_thresh = FunctionDefaults<3>::get_thresh(); if (old_thresh > parameters.thresh() * 0.1 and old_thresh > 1.e-5) { diff --git a/src/madness/chem/ccpairfunction.cc b/src/madness/chem/ccpairfunction.cc index dc5f8eb7641..2c645534bff 100644 --- a/src/madness/chem/ccpairfunction.cc +++ b/src/madness/chem/ccpairfunction.cc @@ -21,7 +21,7 @@ CCPairFunction::invert_sign() { bool CCPairFunction::is_convertible_to_pure_no_op() const { if (has_operator()) { const auto type=get_operator().type(); - if (not (type==OT_SLATER or type==OT_F12)) return false; + if (not (type==OpType::OT_SLATER or type==OpType::OT_F12)) return false; } if (is_decomposed() and (get_a().size()>1)) return false; return true; @@ -103,10 +103,7 @@ CCPairFunction multiply(const CCPairFunction& other, const real_function_3d& f, /// multiplication with a 2-particle function CCPairFunction& CCPairFunction::multiply_with_op_inplace(const std::shared_ptr op) { if (has_operator()) { - auto ops=combine(get_operator_ptr(),op); - MADNESS_CHECK(ops.size()==1); - MADNESS_CHECK(ops.front().first==1.0); - auto newop=std::make_shared(ops.front().second); + auto newop=combine(get_operator_ptr(),op); reset_operator(newop); } else { reset_operator(op); @@ -407,24 +404,25 @@ double CCPairFunction::inner_internal(const CCPairFunction& other, const real_fu // } // include the operator(s), if any if (f1.has_operator() or f2.has_operator()) { - auto ops=combine(f1.get_operator_ptr(),f2.get_operator_ptr()); - for (const auto& single_op : ops) { - auto fac=single_op.first; - auto op=single_op.second; - double bla=0.0; - if (op.get_op()) { - real_function_6d tmp1; - if (R2.is_initialized()) { - tmp1= CompositeFactory(world()).g12(op.get_kernel()).ket(ket).particle1(R2).particle2(R2); - } else { - tmp1= CompositeFactory(world()).g12(op.get_kernel()).ket(ket); - } - bla=fac*inner(bra,tmp1); - } else { - bla=fac*inner(bra,ket); - } - result+=bla; - } + MADNESS_EXCEPTION("still to debug",1); +// auto ops=combine(f1.get_operator_ptr(),f2.get_operator_ptr()); +// for (const auto& single_op : ops) { +// auto fac=single_op.first; +// auto op=single_op.second; +// double bla=0.0; +// if (op.get_op()) { +// real_function_6d tmp1; +// if (R2.is_initialized()) { +// tmp1= CompositeFactory(world()).g12(op.get_kernel()).ket(ket).particle1(R2).particle2(R2); +// } else { +// tmp1= CompositeFactory(world()).g12(op.get_kernel()).ket(ket); +// } +// bla=fac*inner(bra,tmp1); +// } else { +// bla=fac*inner(bra,ket); +// } +// result+=bla; +// } } else { // no operators result=inner(bra,ket); @@ -435,28 +433,29 @@ double CCPairFunction::inner_internal(const CCPairFunction& other, const real_fu const pureT& bra=f1.get_function(); auto ops=combine(f1.get_operator_ptr(),f2.get_operator_ptr()); - if (ops.size()>0) { - for (const auto& single_op : ops) { - auto fac = single_op.first; - auto op = single_op.second; - double bla=0.0; - for (int i=0; i(world()).g12(op.get_kernel()).particle1(a[i]).particle2(b[i]); - bla += fac * inner(bra, tmp); - } else { - real_function_6d tmp = CompositeFactory(world()).particle1(a[i]).particle2(b[i]); - bla += fac * inner(bra,tmp); - } - } - result+=bla; - } - } else { // no operators + MADNESS_EXCEPTION("still to debug",1); +// if (ops.size()>0) { +// for (const auto& single_op : ops) { +// auto fac = single_op.first; +// auto op = single_op.second; +// double bla=0.0; +// for (int i=0; i(world()).g12(op.get_kernel()).particle1(a[i]).particle2(b[i]); +// bla += fac * inner(bra, tmp); +// } else { +// real_function_6d tmp = CompositeFactory(world()).particle1(a[i]).particle2(b[i]); +// bla += fac * inner(bra,tmp); +// } +// } +// result+=bla; +// } +// } else { // no operators for (int i=0; i(world()).particle1(a[i]).particle2(b[i]); result+=inner(bra,tmp); } - } +// } } else if (f1.is_decomposed() and f2.is_pure()) { // with or without op result= f2.inner_internal(f1,R2); @@ -470,30 +469,31 @@ double CCPairFunction::inner_internal(const CCPairFunction& other, const real_fu const vector_real_function_3d b2 = R2.is_initialized() ? R2* f2.get_b() : f2.get_b(); + MADNESS_EXCEPTION("still to debug",1); auto ops=combine(f1.get_operator_ptr(),f2.get_operator_ptr()); - if (ops.size()==0) { - // = \sum_ij = \sum_ij - result = (matrix_inner(world(), a1, a2)).trace(matrix_inner(world(),b1,b2)); - } else { - // = - for (const auto& single_op : ops) { - auto fac = single_op.first; - auto op = single_op.second; - - double bla=0.0; - if (op.get_op()) { - for (size_t i = 0; i < a1.size(); i++) { - vector_real_function_3d aa = truncate(a1[i] * a2); - vector_real_function_3d bb = truncate(b1[i] * b2); - vector_real_function_3d aopx = op(aa); - bla += fac * inner(bb, aopx); - } - } else { - bla += fac*(matrix_inner(world(), a1, a2)).trace(matrix_inner(world(),b1,b2)); - } - result+=bla; - } - } +// if (ops.size()==0) { +// // = \sum_ij = \sum_ij +// result = (matrix_inner(world(), a1, a2)).trace(matrix_inner(world(),b1,b2)); +// } else { +// // = +// for (const auto& single_op : ops) { +// auto fac = single_op.first; +// auto op = single_op.second; +// +// double bla=0.0; +// if (op.get_op()) { +// for (size_t i = 0; i < a1.size(); i++) { +// vector_real_function_3d aa = truncate(a1[i] * a2); +// vector_real_function_3d bb = truncate(b1[i] * b2); +// vector_real_function_3d aopx = op(aa); +// bla += fac * inner(bb, aopx); +// } +// } else { +// bla += fac*(matrix_inner(world(), a1, a2)).trace(matrix_inner(world(),b1,b2)); +// } +// result+=bla; +// } +// } } else MADNESS_EXCEPTION( ("CCPairFunction Overlap not supported for combination " + f1.name() + " and " + f2.name()).c_str(), 1) ; return result; diff --git a/src/madness/chem/lowrankfunction.h b/src/madness/chem/lowrankfunction.h index 649061d2d52..f14c23bc89d 100644 --- a/src/madness/chem/lowrankfunction.h +++ b/src/madness/chem/lowrankfunction.h @@ -7,6 +7,7 @@ #include +#include #include #include #include @@ -99,16 +100,22 @@ namespace madness { }; + /// LowRankFunction represents a hi-dimensional (NDIM) function as a sum of products of low-dimensional (LDIM) functions + + /// f(1,2) = \sum_i g_i(1) h_i(2) + /// a LowRankFunction can be created from a hi-dim function directly, or from a composite like f(1,2) phi(1) psi(2), + /// where f(1,2) is a two-particle function (e.g. a Slater function) template class LowRank { public: + /// what the LowRankFunction will represent struct LRFunctor { LRFunctor() = default; - Function f; - std::shared_ptr> f12; - Function a,b; + Function f; ///< a hi-dim function + std::shared_ptr> f12; ///< a two-particle function + Function a,b; ///< the lo-dim functions bool has_f() const { return f.is_initialized(); } @@ -273,7 +280,8 @@ namespace madness { World& world; - double tol; // rrcd tol + double rank_revealing_tol; // rrcd tol + bool do_print=true; bool stable_power_iteration=true; std::vector> g,h; LRFunctor lrfunctor; @@ -341,7 +349,7 @@ namespace madness { void project(const double volume_per_point, const double radius, const std::string gridtype, std::string rhsfunctiontype, double tol1) { - tol=tol1; + rank_revealing_tol=tol1; long rank=0; if (gridtype=="random") { // number of points within radius = variance: 0.67 * #total points = 0.67*rank @@ -362,6 +370,7 @@ namespace madness { /// Y_i(1) = \int f(1,2) Omega_i(2) d2 && g_i(1) = QR(Y_i(1)) && h_i(2) = \int g_i^*(1) f(1,2) d1 void project(const long rank, const double radius, const std::string gridtype, std::string rhsfunctiontype) { timer t1(world); + t1.do_print=do_print; // make grid std::vector> grid; @@ -376,33 +385,39 @@ namespace madness { if (not is_in_cell(tmp)) continue; grid.push_back(tmp); } - double volume = 4.0/3.0*constants::pi * std::pow(radius,3.0); - print("volume element in random grid",volume/(0.67*rank)); + if (world.rank()==0 and do_print) { + double volume = 4.0/3.0*constants::pi * std::pow(radius,3.0); + print("volume element in random grid",volume/(0.67*rank)); + } } else if (gridtype=="cartesian") { long nperdim=std::lround(std::pow(double(rank),1.0/3.0)); cartesian_grid cg(nperdim,-radius,radius); for (cg.index=0; cg(); ++cg) grid.push_back(cg.get_coordinates()); - print("volume element in cartesian grid",cg.volume_per_gridpoint()); + if (world.rank()==0 and do_print) print("volume element in cartesian grid",cg.volume_per_gridpoint()); } else { MADNESS_EXCEPTION("unknown grid type in project",1); } - print("grid is",gridtype,"with radius",radius,"and",grid.size(),"gridpoints"); - print("rhs functions are",rhsfunctiontype); + if (world.rank()==0 and do_print) { + print("grid is",gridtype,"with radius",radius,"and",grid.size(),"gridpoints"); + print("rhs functions are",rhsfunctiontype); + } auto Y=Yformer(grid,rhsfunctiontype); t1.tag("Yforming"); std::ostringstream oss; - oss << std::scientific << std::setprecision(1) << tol; + oss << std::scientific << std::setprecision(1) << rank_revealing_tol; std::string scientificString = oss.str(); - g=orthonormalize_rrcd(Y,tol); - t1.tag("Y orthonormalizing with tol "+scientificString); + g=orthonormalize_rrcd(Y,rank_revealing_tol); + t1.tag("Y orthonormalizing with rank_revealing_tol "+scientificString); - print("Y.size()",Y.size()); - print("g.size()",g.size()); + if (world.rank()==0 and do_print) { + print("Y.size()",Y.size()); + print("g.size()",g.size()); + } h=truncate(inner(lrfunctor,g,p1,p1)); t1.tag("Y backprojection with truncation"); @@ -442,98 +457,21 @@ namespace madness { return fapprox; } - Tensor orthonormalize(const bool s_in_h) { - return orthonormalize_svd(s_in_h); - } - - - /// @return the singular values s - Tensor orthonormalize_svd(const bool s_in_h) { - timer t(world); - /** - * |g >< h| = |g_ortho> < h | h_ortho > gg hh U s VT > g_ortho=orthonormalize_rrcd(g,1.e-8); - t.tag("ortho1"); - std::vector> h_ortho=orthonormalize_rrcd(h,1.e-8); - t.tag("ortho2"); - auto gg=matrix_inner(world,g_ortho,g); - auto hh=matrix_inner(world,h,h_ortho); - auto ovlp=madness::inner(gg,hh); - Tensor U,VT; - Tensor s; - svd(ovlp,U,s,VT); - auto V=transpose(VT); - - - t.tag("svd"); - g=transform(world,g_ortho,U); - t.tag("transform1"); - h=transform(world,h_ortho,V); - t.tag("transform2"); - - - // include singular values into h - if (s_in_h) for (int i=0; i>& to_ortho) { - MADNESS_CHECK((&to_ortho == &h) or(&to_ortho == &g)) ; - /** - * |g >< h| = |g_ortho> < h | - * = |g_ortho> gg < h | - * = |g_ortho> gg=matrix_inner(world,ortho,to_ortho); - t.tag("ortho_cd matrix_inner"); - /// Transforms a vector of functions according to new[i] = sum[j] old[j]*c[j,i] - if (&to_ortho == &h) { - g=(transform(world,g,transpose(gg))); - h=(ortho); - } else { - g=(ortho); - h=(transform(world,h,transpose(gg))); - } - t.tag("ortho_cd ortho_second"); - } - - void optimize(const long nopt=2) { - optimize_fast(nopt); - } - /// optimize using Cholesky decomposition /// if stable_power_iteration is true, orthonormalize in between applications of the kernel (Alg. 4.4 in Halko) /// @param[in] nopt number of iterations (wrt to Alg. 4.3 in Halko) - void optimize_fast(const long nopt) { + void optimize(const long nopt=1) { timer t(world); + t.do_print=do_print; double tight_thresh=FunctionDefaults<3>::get_thresh()*0.1; for (int i=0; iorthonormalize_cd(h); // h orthonormal, g not - t.tag("ortho1"); - auto gtmp=inner(lrfunctor,h,p2,p1); - t.tag("inner1"); - g=orthonormalize_rrcd(gtmp,tol); - t.tag("ortho2"); - h=inner(lrfunctor,g,p1,p1); - t.tag("inner2"); - - if (iopt%2==1) { - double err=error(); - print("optimization iteration",iopt,", error in f_approx_opt",err); - } - } - t.tag("optimize"); - } - - /// assumes g and h to be orthonormal -> simple projection - void optimize_svd(const long nopt=2) { - - timer t(world); - for (int iopt=0; iopt not normalized any more - std::vector> gtmp(g.size()); - /// remove singular values from h again -> normalized - if constexpr (LDIM == 1) gtmp= inner(lrfunctor, h, {1}, {0}); - if constexpr (LDIM == 2) gtmp= inner(lrfunctor, h, {2, 3}, {0, 1}); - if constexpr (LDIM == 3) gtmp= inner(lrfunctor, h, {3, 4, 5}, {0, 1, 2}); - std::vector sinv(s.size()); - for (int i=0; i> htmp(g.size()); - if constexpr (LDIM==1) htmp=inner(lrfunctor,g,{0},{0}); - if constexpr (LDIM==2) htmp=inner(lrfunctor,g,{0,1},{0,1}); - if constexpr (LDIM==3) htmp=inner(lrfunctor,g,{0,1,2},{0,1,2}); - h=htmp; - -// if (g.size()>1) s=orthonormalize(true); - - if (iopt%2==1) { - double err=error(); - print("optimization iteration",iopt,", error in f_approx_opt",err); - } - } - t.tag("optimize"); + double check_orthonormality(const std::vector>& v) const { + Tensor ovlp=matrix_inner(world,v,v); + for (int i=0; i one=FunctionFactory(world).f([](const Vector& r){return 1.0;}); + const Function pre=(lrfunctor.a.is_initialized()) ? lrfunctor.a : one; + const Function post=(lrfunctor.b.is_initialized()) ? lrfunctor.b : one; + const SeparatedConvolution& f12=*lrfunctor.f12; + const SeparatedConvolution f12sq= SeparatedConvolution::combine(f12,f12); + + // \int f(1,2)^2 d1d2 = \int f(1,2)^2 pre(1)^2 post(2)^2 d1 d2 + double term1 =madness::inner(post*post,f12sq(pre*pre)); + t.tag("computing term1"); + + // \int f(1,2) pre(1) post(2) \sum_i g(1) h(2) d1d2 + double term2=madness::inner(pre*g,f12(post*h)); + t.tag("computing term2"); + + // g functions are orthonormal + // \int gh(1,2)^2 d1d2 = \int \sum_{ij} g_i(1) g_j(1) h_i(2) h_j(2) d1d2 + // = \sum_{ij} \int g_i(1) g_j(1) d1 \int h_i(2) h_j(2) d2 + // = \sum_{ij} delta_{ij} \int h_i(2) h_j(2) d2 + // = \sum_{i} \int h_i(2) h_i(2) d2 + double zero=check_orthonormality(g); + if (zero>1.e-10) print("g is not orthonormal",zero); + double term3=madness::inner(h,h); + t.tag("computing term3"); + + double error=sqrt(term1-2.0*term2+term3)/term1; + if (world.rank()==0 and do_print) { + print("term1,2,3, error",term1, term2, term3, " --",error); + } + + return error; + } + }; // This interface is necessary to compute inner products diff --git a/src/madness/chem/mp2.cc b/src/madness/chem/mp2.cc index 440b446ed94..d726e490f75 100644 --- a/src/madness/chem/mp2.cc +++ b/src/madness/chem/mp2.cc @@ -299,7 +299,7 @@ double MP2::mp3() const { CCConvolutionOperator::Parameters cparam; cparam.thresh_op*=0.1; - auto f12=CCConvolutionOperatorPtr(world,OT_F12,cparam); + auto f12=CCConvolutionOperatorPtr(world,OpType::OT_F12,cparam); auto vfij=Q12(std::vector({f12*ij})); for (auto& p : vfij) tmp.push_back(p); @@ -313,7 +313,7 @@ double MP2::mp3() const { CCTimer t2(world,"recompute MP2"); // recompute MP2 energy CCConvolutionOperator::Parameters cparam; - auto g12=CCConvolutionOperatorPtr(world,OT_G12,cparam); + auto g12=CCConvolutionOperatorPtr(world,OpType::OT_G12,cparam); for (int i = param.freeze(); i < hf->nocc(); ++i) { for (int j = i; j < hf->nocc(); ++j) { auto bra=g12*CCPairFunction(hf->R2orbital(i),hf->R2orbital(j)); @@ -800,8 +800,8 @@ double MP2::compute_gQf(const int i, const int j, ElectronPair& pair) const { CCTimer timer(world,"gQf with ccpairfunction"); CCConvolutionOperator::Parameters param; - auto f=CCConvolutionOperatorPtr(world,OT_F12,param); - auto g=CCConvolutionOperatorPtr(world,OT_G12,param); + auto f=CCConvolutionOperatorPtr(world,OpType::OT_F12,param); + auto g=CCConvolutionOperatorPtr(world,OpType::OT_G12,param); // print("operator constructor",timer.reset()); CCPairFunction fij(f,ket_i,ket_j); diff --git a/src/madness/chem/test_low_rank_function.cc b/src/madness/chem/test_low_rank_function.cc index d53bd8e31cf..af3b14dc0ac 100644 --- a/src/madness/chem/test_low_rank_function.cc +++ b/src/madness/chem/test_low_rank_function.cc @@ -21,6 +21,7 @@ struct LowRankFunctionParameters : QCCalculationParametersBase { // initialize with: key, value, comment (optional), allowed values (optional) initialize("radius",2.0,"the radius"); + initialize("gamma",1.0,"the exponent of the correlation factor"); initialize("volume_element",0.1,"volume covered by each grid point"); initialize("rank",500,"the number of grid points in random grids"); initialize("stable_power_iteration",true,"use stable power iteration algorithm (orthonormalize)"); @@ -35,6 +36,7 @@ struct LowRankFunctionParameters : QCCalculationParametersBase { } double radius() const {return get("radius");} + double gamma() const {return get("gamma");} double volume_element() const {return get("volume_element");} double tol() const {return get("tol");} long rank() const {return get("rank");} @@ -51,13 +53,30 @@ int test_lowrank_function(World& world, LowRankFunctionParameters& parameters) { t1.set_cout_to_terminal(); madness::default_random_generator.setstate(int(cpu_time())%4149); madness::default_random_generator.setstate(int(cpu_time())%4149); + std::string id=unique_fileid(); constexpr std::size_t LDIM=3; constexpr std::size_t NDIM=2*LDIM; - print("eps, k, NDIM",FunctionDefaults::get_thresh(),FunctionDefaults::get_k(),NDIM); + print("eps, k, NDIM, id",FunctionDefaults::get_thresh(),FunctionDefaults::get_k(),NDIM,id); parameters.print("grid","end"); + json j; + std::string jsonfilename="test_low_rank_function."+id+".json"; + j["radius"]=parameters.radius(); + j["f12type"]="SlaterF12"; + j["gamma"]=parameters.gamma(); + j["volume_element"]=parameters.volume_element(); + j["tol"]=parameters.tol(); + j["rank"]=parameters.rank(); + j["stable_power_iteration"]=parameters.stable_power_iteration(); + j["gridtype"]=parameters.gridtype(); + j["rhsfunctiontype"]=parameters.rhsfunctiontype(); + j["optimize"]=parameters.optimize(); + std::ofstream of(jsonfilename,std::ios::out); + of< offset; offset.fill(0.0); // Function phi1=FunctionFactory(world).functor([](const Vector& r) @@ -69,13 +88,8 @@ int test_lowrank_function(World& world, LowRankFunctionParameters& parameters) { Function one=FunctionFactory(world) .functor([](const Vector& r) { return 1.0;}); - std::shared_ptr f12(SlaterOperatorPtr(world,1.0,1.e-6,FunctionDefaults::get_thresh())); -// auto f = [](const coord_6d& r) { -// coord_3d r1={r[0],r[1],r[2]}; -// coord_3d r2={r[3],r[4],r[5]}; -// return exp(-(r1-r2).normf() -r2.normf()); -// }; + std::shared_ptr f12(SlaterF12OperatorPtr(world,parameters.gamma(),1.e-6,FunctionDefaults::get_thresh())); auto compute_result = [&world, &one](const auto& lrf) { real_function_3d result=real_factory_3d(world); @@ -100,15 +114,20 @@ int test_lowrank_function(World& world, LowRankFunctionParameters& parameters) { // \phi(1) \bar \phi(1) = \intn phi(1) \phi(2) f(1,2) d2 auto reference = phi1* (*f12)(phi2); + plot_plane<3>(world,reference,"reference."+id,PlotParameters(world).set_plane({"x1","x2"})); + double n2=reference.norm2(); + print("reference.norm2() = int f12 phi2 d2",n2); output(0.0,0.0,0.0,0.0,0.0,0.0); LowRank lrf(f12,copy(phi1),copy(phi2)); lrf.stable_power_iteration=parameters.stable_power_iteration(); -// plot_plane<6>(world,lrf.lrfunctor,"plot_f12_r2",PlotParameters(world).set_plane({"x1","x4"})); -// lrf.project(parameters.rank(),parameters.radius(),parameters.gridtype(),parameters.rhsfunctiontype()); + plot_plane<6>(world,lrf.lrfunctor,"plot_original."+id,PlotParameters(world).set_plane({"x1","x4"})); double cpu0=cpu_time(); lrf.project(parameters.volume_element(),parameters.radius(),parameters.gridtype(),parameters.rhsfunctiontype(),parameters.tol()); double cpu1=cpu_time(); + double error1=lrf.l2error(); + print("l2error projection",error1); + plot_plane<6>(world,lrf,"plot_lrf_projection."+id,PlotParameters(world).set_plane({"x1","x4"})); // compare // \phi(1) \bar \phi(1) = \int phi(1) \phi(2) f(1,2) d2 @@ -116,16 +135,37 @@ int test_lowrank_function(World& world, LowRankFunctionParameters& parameters) { // = \sum_r g_r(1) <\phi|h_r> real_function_3d result=compute_result(lrf); double projection_error=compute_relative_error(reference,result,lrf); + auto diff=reference-result; + plot_plane<3>(world,diff,"plot_diff_int_projection."+id,PlotParameters(world).set_plane({"x1","x2"})); + plot_plane<3>(world,result,"plot_lrf_int_projection."+id,PlotParameters(world).set_plane({"x1","x2"})); output(projection_error,lrf.rank(),cpu1-cpu0,0.0,0.0,0.0); + j["projection_error_integrated"]=projection_error; + j["projection_error_l2"]=error1; + j["projection_time"]=cpu1-cpu0; + std::ofstream of1(jsonfilename,std::ios::out); + of1<(world,diff,"plot_diff_int_optimization."+id,PlotParameters(world).set_plane({"x1","x2"})); + plot_plane<3>(world,result,"plot_lrf_int_optimization."+id,PlotParameters(world).set_plane({"x1","x2"})); double optimization_error=compute_relative_error(reference,result,lrf); output(projection_error,lrf.rank(),cpu1-cpu0,optimization_error,lrf.rank(),cpu3-cpu2); bool success=(projection_error<5.e-2) and (optimization_error<1.e-2); + j["optimization_error_integrated"]=optimization_error; + j["optimization_error_l2"]=error2; + j["optimization_time"]=cpu3-cpu2; + + std::ofstream of2(jsonfilename,std::ios::out); + of2< +#include + +namespace madness { + +std::string unique_fileid() { + std::string uniqueFileName; + + // Check if the PBS_JOBID environment variable is set + const char* pbsId = std::getenv("PBS_JOBID"); + if (pbsId != nullptr) { + uniqueFileName =std::string(pbsId); + } else { + // If PBS_ID is not available, generate a random number + int randomNumber = RandomValue(); + uniqueFileName = std::to_string(randomNumber); + } + + return uniqueFileName; +} +} diff --git a/src/madness/mra/gfit.h b/src/madness/mra/gfit.h index cba73a8633a..72427deb12e 100644 --- a/src/madness/mra/gfit.h +++ b/src/madness/mra/gfit.h @@ -57,7 +57,17 @@ class GFit { public: /// default ctor does nothing - GFit() {} + GFit() = default; + + /// copy constructor + GFit(const GFit& other) = default; + + /// assignment operator + GFit& operator=(const GFit& other) { + coeffs_ = other.coeffs_; + exponents_ = other.exponents_; + return *this; + } /// return a fit for the Coulomb function @@ -114,7 +124,7 @@ class GFit { /// return a fit for the F12 correlation factor /// the Slater function is defined by - /// f(r) = 1 - exp(-\gamma r) + /// f(r) = 1/(2 gamma) * (1 - exp(-\gamma r)) /// @param[in] gamma the exponent of the Slater function /// @param[in] lo the smallest length scale that needs to be precisely represented /// @param[in] hi the largest length scale that needs to be precisely represented @@ -123,14 +133,37 @@ class GFit { static GFit F12Fit(double gamma, double lo, double hi, double eps, bool prnt=false) { GFit fit; f12_fit(gamma,lo*0.1,hi,eps*0.01,fit.coeffs_,fit.exponents_,false); + fit.coeffs_*=(0.5/gamma); if (prnt) { print("f12 fit"); - auto exact=[&gamma](const double r) -> double {return 1.0-exp(-gamma*r);}; + auto exact=[&gamma](const double r) -> double {return 0.5/gamma*(1.0-exp(-gamma*r));}; + fit.print_accuracy(exact,lo,hi); + } + return fit; + } + + /// return a fit for the F12^2 correlation factor + + /// the Slater function square is defined by + /// f(r) = [ 1/(2 gamma) * (1 - exp(-\gamma r)) ] ^2 + /// @param[in] gamma the exponent of the Slater function + /// @param[in] lo the smallest length scale that needs to be precisely represented + /// @param[in] hi the largest length scale that needs to be precisely represented + /// @param[in] eps the precision threshold + /// @parma[in] prnt print level + static GFit F12sqFit(double gamma, double lo, double hi, double eps, bool prnt=false) { + GFit fit; + f12sq_fit(gamma,lo*0.1,hi,eps*0.01,fit.coeffs_,fit.exponents_,false); + fit.coeffs_*=(0.25/(gamma*gamma)); + if (prnt) { + print("f12sq fit"); + auto exact=[&gamma](const double r) -> double {return std::pow(0.5/gamma*(1.0-exp(-gamma*r)),2.0);}; fit.print_accuracy(exact,lo,hi); } return fit; } + /// return a fit for the FG function /// fg = 1/(2 mu) * (1 - exp(-gamma r12)) / r12 @@ -493,6 +526,7 @@ class GFit { static void slater_fit(double gamma, double lo, double hi, double eps, Tensor& pcoeff, Tensor& pexpnt, bool prnt) { + MADNESS_CHECK(gamma >0.0); // empirical number TT for the upper integration limit double TT; if (eps >= 1e-2) TT = 5; @@ -504,6 +538,7 @@ class GFit { else TT = 30; // integration limits for quadrature over s: slo and shi + // slo and shi must not depend on gamma!!! double slo=0.5 * log(eps) - 1.0; double shi=log(TT/(lo*lo))*0.5; @@ -532,32 +567,6 @@ class GFit { expnt[i] = 0.25*exp(-2.0*s); } - // Prune large exponents from the fit ... never necessary due to construction - - // Prune small exponents from Coulomb fit. Evaluate a gaussian at - // the range midpoint, and replace it there with the next most - // diffuse gaussian. Then examine the resulting error at the two - // end points ... if this error is less than the desired - // precision, can discard the diffuse gaussian. - - if (gamma == 0.0) { - double mid = lo + (hi-lo)*0.5; - long i; - for (i=npt-1; i>0; --i) { - double cnew = coeff[i]*exp(-(expnt[i]-expnt[i-1])*mid*mid); - double errlo = coeff[i]*exp(-expnt[i]*lo*lo) - - cnew*exp(-expnt[i-1]*lo*lo); - double errhi = coeff[i]*exp(-expnt[i]*hi*hi) - - cnew*exp(-expnt[i-1]*hi*hi); - if (std::max(std::abs(errlo),std::abs(errhi)) > 0.03*eps) break; - npt--; - coeff[i-1] = coeff[i-1] + cnew; - } - coeff = coeff(Slice(0,npt-1)); - expnt = expnt(Slice(0,npt-1)); - } - - if (prnt) { std::cout << "weights and roots for a Slater function with gamma=" << gamma << std::endl; for (int i=0; i& pcoeff, Tensor& pexpnt, bool prnt) { + Tensor coeff1,expnt1, coeff2, expnt2; + slater_fit(gamma, lo, hi, eps, coeff1, expnt1, prnt); + slater_fit(2.0*gamma, lo, hi, eps, coeff2, expnt2, prnt); + + // check exponents are the same + MADNESS_CHECK((expnt1-expnt2).normf()/expnt1.size()<1.e-12); + + // add exponential terms + auto coeff=coeff2-2.0*coeff1; + pcoeff=Tensor(coeff1.size()+1); + pcoeff(Slice(1,-1,1))=coeff(_); + pexpnt=Tensor(expnt1.size()+1); + pexpnt(Slice(1,-1,1))=expnt1(_); + + // add constant term + pcoeff(0l)=1.0; + pexpnt(0l)=1.e-10; + } + + + void static bsh_fit_ndim(int ndim, double mu, double lo, double hi, double eps, Tensor& pcoeff, Tensor& pexpnt, bool prnt) { if (mu > 0) { diff --git a/src/madness/mra/operator.h b/src/madness/mra/operator.h index 883fcb90eb9..84dc8ec6e04 100644 --- a/src/madness/mra/operator.h +++ b/src/madness/mra/operator.h @@ -59,7 +59,12 @@ namespace madness { template std::vector apply(const SeparatedConvolution& op, const std::vector& argument); - template + template + std::vector< Function > + apply(const SeparatedConvolution& op, const std::vector< Function > f); + + + template CCPairFunction apply(const SeparatedConvolution& op, const CCPairFunction& argument); /// SeparatedConvolutionInternal keeps data for 1 term and all dimensions and 1 displacement @@ -120,11 +125,38 @@ namespace madness { */ + /// operator types + enum OpType { + OT_UNDEFINED, + OT_ONE, /// indicates the identity + OT_G12, /// 1/r + OT_SLATER, /// exp(-r) + OT_F12, /// 1-exp(-r) + OT_FG12, /// (1-exp(-r))/r + OT_F212, /// (1-exp(-r))^2 + OT_F2G12, /// (1-exp(-r))^2/r = 1/r + exp(-2r)/r - 2 exp(-r)/r + OT_BSH /// exp(-r)/r + }; + + struct OperatorInfo { + OperatorInfo() = default; +// template +// OperatorInfo(double mu, double lo=1.e-5, double thresh=FunctionDefaults::get_thresh()) : mu(mu), thresh(thresh), lo(lo) {} + OperatorInfo(double mu, double lo, double thresh, OpType type) : mu(mu), thresh(thresh), lo(lo), type(type) {} + OpType type=OT_UNDEFINED; ///< introspection + double mu=0.0; ///< some introspection + double thresh=1.e-4; + double lo=1.e-5; + }; template class SeparatedConvolution : public WorldObject< SeparatedConvolution > { public: + typedef Q opT; ///< The apply function uses this to infer resultT=opT*inputT + + OperatorInfo info; + bool doleaves; ///< If should be applied to leaf coefficients ... false by default bool isperiodicsum;///< If true the operator 1D kernels have been summed over lattice translations ///< and may be non-zero at both ends of the unit cell @@ -140,9 +172,6 @@ namespace madness { Timer timer_low_accumulate; Timer timer_stats_accumulate; - // if this is a Slater-type convolution kernel: 1-exp(-mu r12)/(2 mu) - double mu_=0.0; ///< some introspection - private: @@ -150,7 +179,7 @@ namespace madness { const BoundaryConditions bc; const int k; const FunctionCommonData& cdata; - const int rank; + int rank; const std::vector vk; const std::vector v2k; const std::vector s0; @@ -170,8 +199,8 @@ namespace madness { bool& destructive() {return destructive_;} const bool& destructive() const {return destructive_;} - const double& gamma() const {return mu_;} - const double& mu() const {return mu_;} + const double& gamma() const {return info.mu;} + const double& mu() const {return info.mu;} private: @@ -190,6 +219,42 @@ namespace madness { const Q* VT; }; + static inline std::pair,Tensor> + make_coeff_for_operator(World& world, double mu, double lo, double eps, OpType type, + const BoundaryConditions& bc=FunctionDefaults::get_bc()) { + + const Tensor& cell_width = FunctionDefaults<3>::get_cell_width(); + double hi = cell_width.normf(); // Diagonal width of cell + if (bc(0,0) == BC_PERIODIC) hi *= 100; // Extend range for periodic summation + + GFit fit; + if (type==OT_G12) {fit=GFit::CoulombFit(lo,hi,eps,false); + } else if (type==OT_SLATER) {fit=GFit::SlaterFit(mu,lo,hi,eps,false); + } else if (type==OT_F12) {fit=GFit::F12Fit(mu,lo,hi,eps,false); + } else if (type==OT_FG12) {fit=GFit::FGFit(mu,lo,hi,eps,false); + } else if (type==OT_F212) {fit=GFit::F12sqFit(mu,lo,hi,eps,false); + } else if (type==OT_F2G12) {fit=GFit::F2GFit(mu,lo,hi,eps,false); + } else if (type==OT_BSH) {fit=GFit::BSHFit(mu,lo,hi,eps,false); + } else { + MADNESS_EXCEPTION("Operator type not implemented",1); + } + + Tensor coeff=fit.coeffs(); + Tensor expnt=fit.exponents(); + + if (bc(0,0) == BC_PERIODIC) { + fit.truncate_periodic_expansion(coeff, expnt, cell_width.max(), false); + } + + return std::make_pair(coeff,expnt); + } + + static inline std::pair,Tensor> + make_coeff_for_operator(World& world, OperatorInfo info, + const BoundaryConditions& bc=FunctionDefaults::get_bc()) { + return make_coeff_for_operator(world,info.mu,info.lo,info.thresh,info.type,bc); + } + // /// return the right block of the upsampled operator (modified NS only) // // /// unlike the operator matrices on the natural level the upsampled operator @@ -891,7 +956,7 @@ namespace madness { , modified_(false) , particle_(1) , destructive_(false) - , mu_(0.0) + , info() , bc(bc) , k(k) , cdata(FunctionCommonData::get(k)) @@ -925,7 +990,7 @@ namespace madness { , modified_(false) , particle_(1) , destructive_(false) - , mu_(0.0) + , info() , ops(argops) , bc(bc) , k(k) @@ -942,9 +1007,23 @@ namespace madness { this->process_pending(); } + /// Constructor for Gaussian Convolutions (mostly for backward compatability) + SeparatedConvolution(World& world, const OperatorInfo info1, + const BoundaryConditions& bc = FunctionDefaults::get_bc(), + int k=FunctionDefaults::get_k(), + bool doleaves = false) + : SeparatedConvolution(world,Tensor(0l),Tensor(0l),info1.lo,info1.thresh,bc,k,doleaves,info1.mu) { + info.type=info1.type; + auto [coeff, expnt] =make_coeff_for_operator(world, info1, bc); + rank=coeff.dim(0); + ops.resize(rank); + initialize(coeff,expnt); + } + /// Constructor for Gaussian Convolutions (mostly for backward compatability) SeparatedConvolution(World& world, const Tensor& coeff, const Tensor& expnt, + double lo, double thresh, const BoundaryConditions& bc = FunctionDefaults::get_bc(), int k=FunctionDefaults::get_k(), bool doleaves = false, @@ -952,10 +1031,7 @@ namespace madness { : WorldObject< SeparatedConvolution >(world) , doleaves(doleaves) , isperiodicsum(bc(0,0)==BC_PERIODIC) - , modified_(false) - , particle_(1) - , destructive_(false) - , mu_(mu) + , info(mu,lo,thresh,OT_UNDEFINED) , ops(coeff.dim(0)) , bc(bc) , k(k) @@ -963,8 +1039,11 @@ namespace madness { , rank(coeff.dim(0)) , vk(NDIM,k) , v2k(NDIM,2*k) - , s0(std::max(2,NDIM),Slice(0,k-1)) - { + , s0(std::max(2,NDIM),Slice(0,k-1)) { + initialize(coeff,expnt); + } + + void initialize(const Tensor& coeff, const Tensor& expnt) { // Presently we must have periodic or non-periodic in all dimensions. for (std::size_t d=1; d + std::vector> operator()(const std::vector>& f) const { + return madness::apply(*this, f); + } + /// apply this operator on a separable function f(1,2) = f(1) f(2) /// @param[in] f1 a function of dim LDIM @@ -1562,6 +1647,69 @@ namespace madness { return tt; } + + static bool can_combine(const SeparatedConvolution& left, const SeparatedConvolution& right) { + return (combine_OT(left,right).type!=OT_UNDEFINED); + } + + /// return operator type and other info of the combined operator (e.g. fg = f(1,2)* g(1,2) + static OperatorInfo combine_OT(const SeparatedConvolution& left, const SeparatedConvolution& right) { + OperatorInfo info=left.info; + if ((left.info.type==OT_F12) and (right.info.type==OT_G12)) { + info.type=OT_FG12; + } else if ((left.info.type==OT_SLATER) and (right.info.type==OT_SLATER)) { + info=right.info; + info.type=OT_SLATER; + info.mu=2.0*right.info.mu; + } else if ((left.info.type==OT_G12) and (right.info.type==OT_F12)) { + info=right.info; + info.type=OT_FG12; + } else if ((left.info.type==OT_G12) and (right.info.type==OT_F212)) { + info=right.info; + info.type=OT_F2G12; + } else if (((left.info.type==OT_F212) and (right.info.type==OT_G12)) or + ((left.info.type==OT_F12) and (right.info.type==OT_FG12)) or + ((left.info.type==OT_FG12) and (right.info.type==OT_F12))) { + info=right.info; + info.type=OT_F2G12; + if (right.info.type!=OT_G12) MADNESS_CHECK(right.info.mu == left.info.mu); + } else if ((left.info.type==OT_F12) and (right.info.type==OT_F12)) { + info.type=OT_F212; + // keep the original gamma + // (f12)^2 = (1- slater12)^2 = 1/(4 gamma) (1 - 2 exp(-gamma) + exp(-2 gamma)) + MADNESS_CHECK(right.info.mu == left.info.mu); + } else { + MADNESS_EXCEPTION("unknown combination of SeparatedConvolutions: feel free to extend in operator.h",1); + } + return info; + } + + + /// combine 2 convolution operators to one + static SeparatedConvolution combine(const SeparatedConvolution& left, + const SeparatedConvolution& right) { + MADNESS_CHECK(can_combine(left,right)); + MADNESS_CHECK(left.get_world().id()==right.get_world().id()); + + auto info=combine_OT(left,right); + return SeparatedConvolution(left.get_world(),info,left.bc,left.k); + } + + /// combine 2 convolution operators to one + friend SeparatedConvolution combine(const std::shared_ptr> left, + const std::shared_ptr> right) { + SeparatedConvolution result; + if (left and right) { + return combine(*left, *right); + } else if (left) { + return *left; + } else if (right) { + return *right; + } else { + MADNESS_EXCEPTION("can't combine empty SeparatedConvolutions",1); + } + return result; + } }; @@ -1615,7 +1763,7 @@ namespace madness { if (bc(0,0) == BC_PERIODIC) { fit.truncate_periodic_expansion(coeff, expnt, cell_width.max(), true); } - return SeparatedConvolution(world, coeff, expnt, bc, k); + return SeparatedConvolution(world, coeff, expnt, lo, eps, bc, k); } @@ -1638,94 +1786,45 @@ namespace madness { if (bc(0,0) == BC_PERIODIC) { fit.truncate_periodic_expansion(coeff, expnt, cell_width.max(), true); } - return new SeparatedConvolution(world, coeff, expnt, bc, k); + return new SeparatedConvolution(world, coeff, expnt, lo, eps, bc, k); } /// Factory function generating separated kernel for convolution with BSH kernel in general NDIM template - static - inline - SeparatedConvolution BSHOperator(World& world, - double mu, - double lo, - double eps, - const BoundaryConditions& bc=FunctionDefaults::get_bc(), - int k=FunctionDefaults::get_k()) - { + static inline + SeparatedConvolution + BSHOperator(World& world, double mu, double lo, double eps, + const BoundaryConditions& bc=FunctionDefaults::get_bc(), + int k=FunctionDefaults::get_k()) { if (eps>1.e-4) { if (world.rank()==0) print("the accuracy in BSHOperator is too small, tighten the threshold",eps); MADNESS_EXCEPTION("0",1); } - const Tensor& cell_width = FunctionDefaults::get_cell_width(); - double hi = cell_width.normf(); // Diagonal width of cell - if (bc(0,0) == BC_PERIODIC) hi *= 100; // Extend range for periodic summation - - GFit fit=GFit::BSHFit(mu,lo,hi,eps,false); - Tensor coeff=fit.coeffs(); - Tensor expnt=fit.exponents(); - - if (bc(0,0) == BC_PERIODIC) { - fit.truncate_periodic_expansion(coeff, expnt, cell_width.max(), false); - } - - return SeparatedConvolution(world, coeff, expnt, bc, k); + return SeparatedConvolution(world,OperatorInfo(mu,lo,eps,OT_BSH),bc,k); } /// Factory function generating separated kernel for convolution with BSH kernel in general NDIM template - static - inline - SeparatedConvolution* BSHOperatorPtr(World& world, - double mu, - double lo, - double eps, - const BoundaryConditions& bc=FunctionDefaults::get_bc(), - int k=FunctionDefaults::get_k()) - { - if (eps>1.e-4) { - if (world.rank()==0) print("the accuracy in BSHOperator is too small, tighten the threshold",eps); - MADNESS_EXCEPTION("0",1); - } - const Tensor& cell_width = FunctionDefaults::get_cell_width(); - double hi = cell_width.normf(); // Diagonal width of cell - if (bc(0,0) == BC_PERIODIC) hi *= 100; // Extend range for periodic summation - - GFit fit=GFit::BSHFit(mu,lo,hi,eps,false); - Tensor coeff=fit.coeffs(); - Tensor expnt=fit.exponents(); - - if (bc(0,0) == BC_PERIODIC) { - fit.truncate_periodic_expansion(coeff, expnt, cell_width.max(), false); + static inline + SeparatedConvolution* + BSHOperatorPtr(World& world, double mu, double lo, double eps, + const BoundaryConditions& bc=FunctionDefaults::get_bc(), + int k=FunctionDefaults::get_k()) { + if (eps>1.e-4) { + if (world.rank()==0) print("the accuracy in BSHOperator is too small, tighten the threshold",eps); + MADNESS_EXCEPTION("0",1); } - - return new SeparatedConvolution(world, coeff, expnt, bc, k); + return new SeparatedConvolution(world,OperatorInfo(mu,lo,eps,OT_BSH),bc,k); } /// Factory function generating separated kernel for convolution with exp(-mu*r)/(4*pi*r) in 3D - static - inline - SeparatedConvolution BSHOperator3D(World& world, - double mu, - double lo, - double eps, - const BoundaryConditions<3>& bc=FunctionDefaults<3>::get_bc(), - int k=FunctionDefaults<3>::get_k()) - - { - const Tensor& cell_width = FunctionDefaults<3>::get_cell_width(); - double hi = cell_width.normf(); // Diagonal width of cell - if (bc(0,0) == BC_PERIODIC) hi *= 100; // Extend range for periodic summation - - GFit fit=GFit::BSHFit(mu,lo,hi,eps,false); - Tensor coeff=fit.coeffs(); - Tensor expnt=fit.exponents(); - - if (bc(0,0) == BC_PERIODIC) { - fit.truncate_periodic_expansion(coeff, expnt, cell_width.max(), false); - } - return SeparatedConvolution(world, coeff, expnt, bc, k); + static inline SeparatedConvolution + BSHOperator3D(World& world, double mu, double lo, double eps, + const BoundaryConditions<3>& bc=FunctionDefaults<3>::get_bc(), + int k=FunctionDefaults<3>::get_k()) { + return SeparatedConvolution(world,OperatorInfo(mu,lo,eps,OT_BSH),bc,k); } /// Factory function generating separated kernel for convolution with exp(-mu*r)/(4*pi*r) in 3D @@ -1755,8 +1854,7 @@ namespace madness { } /// Factory function generating separated kernel for convolution with exp(-mu*r)/(4*pi*r) in 3D - static - inline + static inline SeparatedConvolution* PeriodicBSHOperatorPtr3D(World& world, Vector args, double mu, @@ -1780,28 +1878,18 @@ namespace madness { return new SeparatedConvolution(world, args, coeff, expnt, bc, k); } - /// Factory function generating separated kernel for convolution with (1 - exp(-mu*r))/(2 mu) in 3D - /// includes the factor 1/(2 mu) - static inline SeparatedConvolution SlaterF12Operator(World& world, + static inline SeparatedConvolution + SlaterF12Operator(World& world, double mu, double lo, double eps, + const BoundaryConditions<3>& bc=FunctionDefaults<3>::get_bc(), int k=FunctionDefaults<3>::get_k()) { + return SeparatedConvolution(world,OperatorInfo(mu,lo,eps,OT_F12),bc,k); + } + + static inline SeparatedConvolution SlaterF12sqOperator(World& world, double mu, double lo, double eps, const BoundaryConditions<3>& bc=FunctionDefaults<3>::get_bc(), int k=FunctionDefaults<3>::get_k()) { - - const Tensor& cell_width = FunctionDefaults<3>::get_cell_width(); - double hi = cell_width.normf(); // Diagonal width of cell - if (bc(0,0) == BC_PERIODIC) hi *= 100; // Extend range for periodic summation - - GFit fit=GFit::F12Fit(mu,lo,hi,eps,false); - Tensor coeff=0.5/mu*fit.coeffs(); - Tensor expnt=fit.exponents(); - - if (bc(0,0) == BC_PERIODIC) { - fit.truncate_periodic_expansion(coeff, expnt, cell_width.max(), false); - } - - auto sepop=SeparatedConvolution(world, coeff, expnt, bc, k, false, mu); - return sepop; + return SeparatedConvolution(world,OperatorInfo(mu,lo,eps,OT_F212),bc,k); } /// Factory function generating separated kernel for convolution with exp(-mu*r) in 3D @@ -1809,20 +1897,7 @@ namespace madness { double mu, double lo, double eps, const BoundaryConditions<3>& bc=FunctionDefaults<3>::get_bc(), int k=FunctionDefaults<3>::get_k()) { - - const Tensor& cell_width = FunctionDefaults<3>::get_cell_width(); - double hi = cell_width.normf(); // Diagonal width of cell - if (bc(0,0) == BC_PERIODIC) hi *= 100; // Extend range for periodic summation - - GFit fit=GFit::SlaterFit(mu,lo,hi,eps,false); - Tensor coeff=fit.coeffs(); - Tensor expnt=fit.exponents(); - - if (bc(0,0) == BC_PERIODIC) { - fit.truncate_periodic_expansion(coeff, expnt, cell_width.max(), false); - } - SeparatedConvolution tmp(world, coeff, expnt, bc, k, false, mu); - return tmp; + return SeparatedConvolution(world,OperatorInfo(mu,lo,eps,OT_SLATER),bc,k); } /// Factory function generating separated kernel for convolution with exp(-mu*r) in 3D @@ -1831,20 +1906,7 @@ namespace madness { double mu, double lo, double eps, const BoundaryConditions<3>& bc = FunctionDefaults<3>::get_bc(), int k = FunctionDefaults<3>::get_k()) { - - const Tensor& cell_width = FunctionDefaults<3>::get_cell_width(); - double hi = cell_width.normf(); // Diagonal width of cell - if (bc(0,0) == BC_PERIODIC) hi *= 100; // Extend range for periodic summation - - GFit fit=GFit::SlaterFit(mu,lo,hi,eps,false); - Tensor coeff=fit.coeffs(); - Tensor expnt=fit.exponents(); - - if (bc(0,0) == BC_PERIODIC) { - fit.truncate_periodic_expansion(coeff, expnt, cell_width.max(), false); - } - SeparatedConvolution* tmp=new SeparatedConvolution(world, coeff, expnt, bc, k, false, mu); - return tmp; + return new SeparatedConvolution(world,OperatorInfo(mu,lo,eps,OT_SLATER),bc,k); } /// Factory function generating separated kernel for convolution with (1 - exp(-mu*r))/(2 mu) in 3D @@ -1854,44 +1916,30 @@ namespace madness { double mu, double lo, double eps, const BoundaryConditions<3>& bc=FunctionDefaults<3>::get_bc(), int k=FunctionDefaults<3>::get_k()) { + return new SeparatedConvolution(world,OperatorInfo(mu,lo,eps,OT_F12),bc,k); + } - const Tensor& cell_width = FunctionDefaults<3>::get_cell_width(); - double hi = cell_width.normf(); // Diagonal width of cell - if (bc(0,0) == BC_PERIODIC) hi *= 100; // Extend range for periodic summation - - GFit fit=GFit::F12Fit(mu,lo,hi,eps,false); - Tensor coeff=0.5/mu*fit.coeffs(); - Tensor expnt=fit.exponents(); - if (bc(0,0) == BC_PERIODIC) { - fit.truncate_periodic_expansion(coeff, expnt, cell_width.max(), false); - } + /// Factory function generating separated kernel for convolution with 1/(2 mu)*(1 - exp(-mu*r))/r in 3D - return new SeparatedConvolution(world, coeff, expnt, bc, k, false, mu); + /// fg = (1 - exp(-gamma r12)) / r12 = 1/r12 - exp(-gamma r12)/r12 = coulomb - bsh + /// includes the factor 1/(2 mu) + static inline SeparatedConvolution + FGOperator(World& world, double mu, double lo, double eps, + const BoundaryConditions<3>& bc=FunctionDefaults<3>::get_bc(), + int k=FunctionDefaults<3>::get_k()) { + return SeparatedConvolution(world,OperatorInfo(mu,lo,eps,OT_FG12),bc,k); } /// Factory function generating separated kernel for convolution with 1/(2 mu)*(1 - exp(-mu*r))/r in 3D /// fg = (1 - exp(-gamma r12)) / r12 = 1/r12 - exp(-gamma r12)/r12 = coulomb - bsh /// includes the factor 1/(2 mu) - static inline SeparatedConvolution* FGOperatorPtr(World& world, - double mu, double lo, double eps, - const BoundaryConditions<3>& bc=FunctionDefaults<3>::get_bc(), - int k=FunctionDefaults<3>::get_k()) { - - const Tensor& cell_width = FunctionDefaults<3>::get_cell_width(); - double hi = cell_width.normf(); // Diagonal width of cell - if (bc(0,0) == BC_PERIODIC) hi *= 100; // Extend range for periodic summation - - GFit fit=GFit::FGFit(mu,lo,hi,eps,false); - Tensor coeff=fit.coeffs(); - Tensor expnt=fit.exponents(); - - if (bc(0,0) == BC_PERIODIC) { - fit.truncate_periodic_expansion(coeff, expnt, cell_width.max(), false); - } - - return new SeparatedConvolution(world, coeff, expnt, bc, k, false, mu); + static inline SeparatedConvolution* + FGOperatorPtr(World& world, double mu, double lo, double eps, + const BoundaryConditions<3>& bc=FunctionDefaults<3>::get_bc(), + int k=FunctionDefaults<3>::get_k()) { + return new SeparatedConvolution(world,OperatorInfo(mu,lo,eps,OT_FG12),bc,k); } /// Factory function generating separated kernel for convolution with (1/(2 mu)*(1 - exp(-mu*r)))^2/r in 3D @@ -1899,24 +1947,23 @@ namespace madness { /// f2g = (1/(2 gamma) (1 - exp(-gamma r12)))^2 / r12 /// = 1/(4 gamma) * [ 1/r12 - 2 exp(-gamma r12)/r12 + exp(-2 gamma r12)/r12 ] /// includes the factor 1/(2 mu)^2 - static inline SeparatedConvolution* F2GOperatorPtr(World& world, - double mu, double lo, double eps, - const BoundaryConditions<3>& bc=FunctionDefaults<3>::get_bc(), - int k=FunctionDefaults<3>::get_k()) { - - const Tensor& cell_width = FunctionDefaults<3>::get_cell_width(); - double hi = cell_width.normf(); // Diagonal width of cell - if (bc(0,0) == BC_PERIODIC) hi *= 100; // Extend range for periodic summation - - GFit fit=GFit::F2GFit(mu,lo,hi,eps,false); - Tensor coeff=fit.coeffs(); - Tensor expnt=fit.exponents(); + static inline SeparatedConvolution* + F2GOperatorPtr(World& world, double mu, double lo, double eps, + const BoundaryConditions<3>& bc=FunctionDefaults<3>::get_bc(), + int k=FunctionDefaults<3>::get_k()) { + return new SeparatedConvolution(world,OperatorInfo(mu,lo,eps,OT_F2G12),bc,k); + } - if (bc(0,0) == BC_PERIODIC) { - fit.truncate_periodic_expansion(coeff, expnt, cell_width.max(), false); - } + /// Factory function generating separated kernel for convolution with (1/(2 mu)*(1 - exp(-mu*r)))^2/r in 3D - return new SeparatedConvolution(world, coeff, expnt, bc, k, false, mu); + /// f2g = (1/(2 gamma) (1 - exp(-gamma r12)))^2 / r12 + /// = 1/(4 gamma) * [ 1/r12 - 2 exp(-gamma r12)/r12 + exp(-2 gamma r12)/r12 ] + /// includes the factor 1/(2 mu)^2 + static inline SeparatedConvolution + F2GOperator(World& world, double mu, double lo, double eps, + const BoundaryConditions<3>& bc=FunctionDefaults<3>::get_bc(), + int k=FunctionDefaults<3>::get_k()) { + return SeparatedConvolution(world,OperatorInfo(mu,lo,eps,OT_F2G12),bc,k); } @@ -1931,7 +1978,7 @@ namespace madness { Tensor coeffs(1), exponents(1); exponents(0L) = exponent; coeffs(0L)=pow(exponent/M_PI,0.5*3.0); // norm of the gaussian - return SeparatedConvolution(world, coeffs, exponents); + return SeparatedConvolution(world, coeffs, exponents, 1.e-8, eps); } @@ -1947,7 +1994,7 @@ namespace madness { Tensor coeffs(1), exponents(1); exponents(0L) = exponent; coeffs(0L)=pow(exponent/M_PI,0.5*NDIM); // norm of the gaussian - return SeparatedConvolution(world, coeffs, exponents); + return SeparatedConvolution(world, coeffs, exponents, 1.e-8, eps); } /// Factory function generating separated kernel for convolution with exp(-mu*r)/(4*pi*r) in 3D @@ -1971,7 +2018,7 @@ namespace madness { if (bc(0,0) == BC_PERIODIC) { fit.truncate_periodic_expansion(coeff, expnt, cell_width.max(), false); } - return new SeparatedConvolution(world, coeff, expnt, bc, k); + return new SeparatedConvolution(world, coeff, expnt, lo, eps, bc, k); } @@ -2083,6 +2130,7 @@ namespace madness { } + namespace archive { template struct ArchiveLoadImpl*> { diff --git a/src/madness/mra/vmra.h b/src/madness/mra/vmra.h index 2a56975b41d..bf8568c0371 100644 --- a/src/madness/mra/vmra.h +++ b/src/madness/mra/vmra.h @@ -1395,6 +1395,15 @@ namespace madness { } + /// Applies an operator to a vector of functions --- q[i] = apply(op,f[i]) + template + std::vector< Function > + apply(const SeparatedConvolution& op, + const std::vector< Function > f) { + return apply(op.get_world(),op,f); + } + + /// Applies an operator to a vector of functions --- q[i] = apply(op,f[i]) template std::vector< Function > From c33a65ab94ec8e5aeff5b5808cb78a8c20366318 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Fri, 8 Sep 2023 16:21:06 +0200 Subject: [PATCH 047/109] repeated orthonormalization of the initial Y projection --- src/madness/chem/lowrankfunction.h | 105 ++++++++++++++------- src/madness/chem/test_low_rank_function.cc | 34 +++++-- 2 files changed, 96 insertions(+), 43 deletions(-) diff --git a/src/madness/chem/lowrankfunction.h b/src/madness/chem/lowrankfunction.h index f14c23bc89d..bb6ee4bf237 100644 --- a/src/madness/chem/lowrankfunction.h +++ b/src/madness/chem/lowrankfunction.h @@ -106,7 +106,7 @@ namespace madness { /// a LowRankFunction can be created from a hi-dim function directly, or from a composite like f(1,2) phi(1) psi(2), /// where f(1,2) is a two-particle function (e.g. a Slater function) template - class LowRank { + class LowRankFunction { public: /// what the LowRankFunction will represent @@ -123,14 +123,20 @@ namespace madness { return (f12.get()); } T operator()(const Vector& r) const { - Vector first, second; - for (int i=0; iinfo.type==OT_SLATER) { + double gamma=f12->info.mu; + Vector first, second; + for (int i=0; iinfo.type==OT_SLATER); // functor is now a(1) b(2) f12 // result(1) = \int a(1) f(1,2) b(2) delta(R-2) d2 // = a(1) f(1,R) b(R) @@ -280,7 +287,7 @@ namespace madness { World& world; - double rank_revealing_tol; // rrcd tol + double rank_revealing_tol=1.e-12; // rrcd tol bool do_print=true; bool stable_power_iteration=true; std::vector> g,h; @@ -288,33 +295,34 @@ namespace madness { particle p1=particle::particle1(); particle p2=particle::particle2(); - LowRank(World& world) : world(world) {} + LowRankFunction(World& world) : world(world) {} /// construct from the hi-dim function f - LowRank(const Function& f) : LowRank(f.world()) { + LowRankFunction(const Function& f) : LowRankFunction(f.world()) { lrfunctor.f=f; } /// construct from the hi-dim function f12*a(1)(b(2) - LowRank(const std::shared_ptr> f12, const Function& a, - const Function& b) : LowRank(a.world()) { + LowRankFunction(const std::shared_ptr> f12, const Function& a, + const Function& b) : LowRankFunction(a.world()) { lrfunctor.a=a; lrfunctor.b=b; lrfunctor.f12=f12; } - LowRank(std::vector> g, std::vector> h) + LowRankFunction(std::vector> g, std::vector> h) : world(g.front().world()), g(g), h(h) {} - LowRank(const LowRank& a) : world(a.world), g(copy(world,a.g)), h(copy(world,a.h)) {} // Copy constructor necessary + LowRankFunction(const LowRankFunction& a) : world(a.world), g(copy(world, a.g)), h(copy(world, a.h)) {} // Copy constructor necessary - LowRank& operator=(const LowRank& f) { // Assignment required for storage in vector - LowRank ff(f); + LowRankFunction& operator=(const LowRankFunction& f) { // Assignment required for storage in vector + LowRankFunction ff(f); std::swap(ff.g,g); std::swap(ff.h,h); return *this; } + /// function evaluation T operator()(const Vector& r) const { Vector first, second; for (int i=0; i>& vec, const long particle) { - auto result=*this; // deep copy - if (particle==0) result.g=g*vec; - if (particle==1) result.h=h*vec; - return *this; + /// scale by a scalar + template + LowRankFunction operator*(const Q a) const { + return LowRankFunction,NDIM>(g * a, Q(h)); + } + + /// in-place scale by a scalar (no type conversion) + LowRankFunction operator*(const T a) const { + return LowRankFunction(g * a, h); } void project(const double volume_per_point, const double radius, const std::string gridtype, std::string rhsfunctiontype, @@ -411,8 +436,16 @@ namespace madness { std::ostringstream oss; oss << std::scientific << std::setprecision(1) << rank_revealing_tol; std::string scientificString = oss.str(); - g=orthonormalize_rrcd(Y,rank_revealing_tol); - t1.tag("Y orthonormalizing with rank_revealing_tol "+scientificString); + double err=1.0; + double tight_thresh=FunctionDefaults<3>::get_thresh()*0.1; + g=Y; + while (err>1.e-10) { + g=truncate(orthonormalize_rrcd(g,rank_revealing_tol),std::min(1.e-3,tight_thresh*100.0)); + err=check_orthonormality(g); + print("error of non-orthonormality",err); + t1.tag("Y orthonormalizing with rank_revealing_tol loose_thresh "+scientificString); + } + g=truncate(g); if (world.rank()==0 and do_print) { print("Y.size()",Y.size()); @@ -482,7 +515,7 @@ namespace madness { double check_orthonormality(const std::vector>& v) const { Tensor ovlp=matrix_inner(world,v,v); for (int i=0; i - double inner(const LowRank& a, const LowRank& b) { + double inner(const LowRankFunction& a, const LowRankFunction& b) { World& world=a.world; return (matrix_inner(world,a.g,b.g).emul(matrix_inner(world,a.h,b.h))).sum(); } @@ -551,11 +584,11 @@ namespace madness { template - LowRank inner(const Function& lhs, const LowRank& rhs, const std::tuple v1, const std::tuple v2) { + LowRankFunction inner(const Function& lhs, const LowRankFunction& rhs, const std::tuple v1, const std::tuple v2) { World& world=rhs.world; // int lhs(1,2) rhs(2,3) d2 = \sum \int lhs(1,2) g_i(2) h_i(3) d2 // = \sum \int lhs(1,2) g_i(2) d2 h_i(3) - LowRank result(world); + LowRankFunction result(world); result.h=rhs.h; decltype(rhs.g) g; for (int i=0; i - LowRank inner(const LowRank& f, const Function& g, const std::tuple v1, const std::tuple v2) { + LowRankFunction inner(const LowRankFunction& f, const Function& g, const std::tuple v1, const std::tuple v2) { World& world=f.world; // int f(1,2) k(2,3) d2 = \sum \int g_i(1) h_i(2) k(2,3) d2 // = \sum g_i(1) \int h_i(2) k(2,3) d2 - LowRank result(world); + LowRankFunction result(world); result.g=f.g; decltype(f.h) h; for (int i=0; i #include -#include #include @@ -25,7 +24,9 @@ struct LowRankFunctionParameters : QCCalculationParametersBase { initialize("volume_element",0.1,"volume covered by each grid point"); initialize("rank",500,"the number of grid points in random grids"); initialize("stable_power_iteration",true,"use stable power iteration algorithm (orthonormalize)"); - initialize("tol",1.e-12,"rank-reduced choleski tolerance"); + initialize("tol",1.e-12,"rank-reduced cholesky tolerance"); + initialize("f12type","Slater","correlation factor",{"Slater","SlaterF12"}); + initialize("transpose","slater2","transpose of the matrix",{"slater1","slater2"}); initialize("gridtype","random","the grid type",{"random","cartesian"}); initialize("rhsfunctiontype","exponential","the type of function",{"delta","exponential"}); initialize("optimize",1,"number of optimization iterations"); @@ -60,15 +61,18 @@ int test_lowrank_function(World& world, LowRankFunctionParameters& parameters) { print("eps, k, NDIM, id",FunctionDefaults::get_thresh(),FunctionDefaults::get_k(),NDIM,id); parameters.print("grid","end"); + std::string f12type=parameters.get("f12type"); + std::string transpose=parameters.get("transpose"); json j; std::string jsonfilename="test_low_rank_function."+id+".json"; j["radius"]=parameters.radius(); - j["f12type"]="SlaterF12"; + j["f12type"]=parameters.get("f12type"); j["gamma"]=parameters.gamma(); j["volume_element"]=parameters.volume_element(); j["tol"]=parameters.tol(); j["rank"]=parameters.rank(); + j["transpose"]=transpose; j["stable_power_iteration"]=parameters.stable_power_iteration(); j["gridtype"]=parameters.gridtype(); j["rhsfunctiontype"]=parameters.rhsfunctiontype(); @@ -79,17 +83,33 @@ int test_lowrank_function(World& world, LowRankFunctionParameters& parameters) { Vector offset; offset.fill(0.0); -// Function phi1=FunctionFactory(world).functor([](const Vector& r) -// { return exp(-r.normf());}); Function phi1=FunctionFactory(world).functor([](const Vector& r) { return 1.0;}); Function phi2=FunctionFactory(world).functor([&offset](const Vector& r) { return exp(-1.0*(r-offset).normf());}); + if (transpose=="slater1") std::swap(phi1,phi2); + { + double n1 = phi1.norm2(); + double n2 = phi2.norm2(); + bool first_one = (fabs(phi1({1, 1, 1}) - 1.0) < 1.e-6); + if (world.rank() == 0) { + if (first_one) print("1(1) phi(2)"); + else print("phi(1) 1(2)"); + print("norms", n1, n2); + } + } + Function one=FunctionFactory(world) .functor([](const Vector& r) { return 1.0;}); - std::shared_ptr f12(SlaterF12OperatorPtr(world,parameters.gamma(),1.e-6,FunctionDefaults::get_thresh())); + std::shared_ptr f12; + if (f12type=="slaterf12") f12.reset(SlaterF12OperatorPtr(world,parameters.gamma(),1.e-6,FunctionDefaults::get_thresh())); + else if (f12type=="slater") f12.reset(SlaterOperatorPtr(world,parameters.gamma(),1.e-6,FunctionDefaults::get_thresh())); + else { + MADNESS_EXCEPTION(std::string("unknown f12type"+f12type).c_str(),1); + } + auto compute_result = [&world, &one](const auto& lrf) { real_function_3d result=real_factory_3d(world); @@ -119,7 +139,7 @@ int test_lowrank_function(World& world, LowRankFunctionParameters& parameters) { print("reference.norm2() = int f12 phi2 d2",n2); output(0.0,0.0,0.0,0.0,0.0,0.0); - LowRank lrf(f12,copy(phi1),copy(phi2)); + LowRankFunction lrf(f12, copy(phi1), copy(phi2)); lrf.stable_power_iteration=parameters.stable_power_iteration(); plot_plane<6>(world,lrf.lrfunctor,"plot_original."+id,PlotParameters(world).set_plane({"x1","x4"})); double cpu0=cpu_time(); From cbbc6b73c857126bdd4cd6f95a35f33b020ec99f Mon Sep 17 00:00:00 2001 From: fbischoff Date: Mon, 18 Sep 2023 13:37:20 +0200 Subject: [PATCH 048/109] low-rank function seems to work for exchange operator --- src/madness/chem/lowrankfunction.h | 239 ++++++++++++++++----- src/madness/chem/test_low_rank_function.cc | 205 ++++++++++++++---- src/madness/mra/vmra.h | 18 +- src/madness/world/timing_utilities.h | 7 +- 4 files changed, 369 insertions(+), 100 deletions(-) diff --git a/src/madness/chem/lowrankfunction.h b/src/madness/chem/lowrankfunction.h index bb6ee4bf237..8486d04352b 100644 --- a/src/madness/chem/lowrankfunction.h +++ b/src/madness/chem/lowrankfunction.h @@ -15,6 +15,88 @@ namespace madness { + struct LowRankFunctionParameters : QCCalculationParametersBase { + + LowRankFunctionParameters() : QCCalculationParametersBase() { + + // initialize with: key, value, comment (optional), allowed values (optional) + initialize("radius",2.0,"the radius"); + initialize("gamma",1.0,"the exponent of the correlation factor"); + initialize("volume_element",0.1,"volume covered by each grid point"); + initialize("hard_shell",true,"radius is hard"); + initialize("tol",1.e-8,"rank-reduced cholesky tolerance"); + initialize("f12type","Slater","correlation factor",{"Slater","SlaterF12"}); + initialize("orthomethod","cholesky","orthonormalization",{"cholesky","canonical","symmetric"}); + initialize("transpose","slater2","transpose of the matrix",{"slater1","slater2"}); + initialize("gridtype","random","the grid type",{"random","cartesian","spherical"}); + initialize("rhsfunctiontype","exponential","the type of function",{"delta","exponential"}); + initialize("optimize",1,"number of optimization iterations"); + } + + void read_and_set_derived_values(World& world, const commandlineparser& parser, std::string tag) { + read_input_and_commandline_options(world,parser,tag); + } + + double radius() const {return get("radius");} + double gamma() const {return get("gamma");} + double volume_element() const {return get("volume_element");} + double tol() const {return get("tol");} + bool hard_shell() const {return get("hard_shell");} + int optimize() const {return get("optimize");} + std::string gridtype() const {return get("gridtype");} + std::string orthomethod() const {return get("orthomethod");} + std::string rhsfunctiontype() const {return get("rhsfunctiontype");} + std::string f12type() const {return get("f12type");} + }; + + + + template + class cgrid { + public: + double volume_element=0.1; + double radius=3; + bool hard_shell=true; + + cgrid(const double volume_element, const double radius, bool hard_shell) + :volume_element(volume_element), radius(radius), hard_shell(hard_shell) { + }; + + std::vector> get_coordinates() const { + // 1D grid + double volume_element_1d=std::pow(volume_element,1./NDIM); + long ngrid=std::ceil(radius/volume_element_1d); + double stepsize=radius/ngrid; + double scale=1.0; + if (not hard_shell) scale=std::pow(2.0,1.0/(ngrid+1)); + print("scale",scale); + + std::vector coord1d; + print("volume element, stepsize, ngrid" ,volume_element, std::pow(stepsize,NDIM),stepsize,ngrid); + for (int i=0; i> result; + for (int i=0; i c{coord1d[i],coord1d[j],coord1d[k]}; + double cutoff = hard_shell ? radius : 2.0*radius; + if (c.normf() struct cartesian_grid { @@ -25,14 +107,19 @@ namespace madness { long total_n; Vector increment; + cartesian_grid(const double volume_per_gridpoint, const double radius) { + double length_per_gridpoint=std::pow(volume_per_gridpoint,1.0/NDIM); + n_per_dim=ceil(2.0*radius/length_per_gridpoint); + print("length per gridpoint, n_per_dim",length_per_gridpoint,n_per_dim); + print("volume_per_gridpoint",std::pow(length_per_gridpoint,NDIM)); + initialize(-radius,radius); + print("increment",increment); + } + + cartesian_grid(const long n_per_dim, const double lo, const double hi) : n_per_dim(n_per_dim) { - lovec.fill(lo); - hivec.fill(hi); - increment=(hivec-lovec)*(1.0/double(n_per_dim-1)); - stride=std::vector(NDIM,1l); - total_n=std::pow(n_per_dim,NDIM); - for (long i=NDIM-2; i>=0; --i) stride[i]=n_per_dim*stride[i+1]; + initialize(lo,hi); } cartesian_grid(const cartesian_grid& other) : lovec(other.lovec), @@ -46,6 +133,16 @@ namespace madness { return *this; } + void initialize(const double lo, const double hi) { + lovec.fill(lo); + hivec.fill(hi); + increment=(hivec-lovec)*(1.0/double(n_per_dim-1)); + stride=std::vector(NDIM,1l); + total_n=std::pow(n_per_dim,NDIM); + for (long i=NDIM-2; i>=0; --i) stride[i]=n_per_dim*stride[i+1]; + + } + double volume_per_gridpoint() const{ double volume=1.0; for (int i=0; i> g,h; LRFunctor lrfunctor; particle p1=particle::particle1(); @@ -372,36 +469,26 @@ namespace madness { return LowRankFunction(g * a, h); } - void project(const double volume_per_point, const double radius, const std::string gridtype, std::string rhsfunctiontype, - double tol1) { - rank_revealing_tol=tol1; - long rank=0; - if (gridtype=="random") { - // number of points within radius = variance: 0.67 * #total points = 0.67*rank - // volume of sphere 4/3 pi *r^3 - // volume per point=volume/#points in radius = volume / (0.67 * rank) - // rank= volume/(0.67/volume_per_point) - double volume=4.0/3.0*constants::pi *std::pow(radius,3.0); - rank = lround(volume/(0.67*volume_per_point )); - } - project(rank,radius,gridtype,rhsfunctiontype); - } - /// following Halko /// ||A - Q Q^T A||< epsilon /// Y = A Omega && Q = QR(Y) /// || f(1,2) - \sum_i g_i(1) h_i(2) || < epsilon /// Y_i(1) = \int f(1,2) Omega_i(2) d2 && g_i(1) = QR(Y_i(1)) && h_i(2) = \int g_i^*(1) f(1,2) d1 - void project(const long rank, const double radius, const std::string gridtype, std::string rhsfunctiontype) { + void project(const LowRankFunctionParameters& params) { timer t1(world); t1.do_print=do_print; + orthomethod=params.orthomethod(); + rank_revealing_tol=params.tol(); + // make grid std::vector> grid; - if (gridtype=="random") { + if (params.gridtype()=="random") { + double volume=4.0/3.0*constants::pi *std::pow(params.radius(),3.0); + long rank = lround(volume/(0.67*params.volume_element() )); for (int i=0; i::gaussian_random_distribution(0,radius); + auto tmp=randomgaussian::gaussian_random_distribution(0,params.radius()); auto cell=FunctionDefaults::get_cell(); auto is_in_cell = [&cell](const Vector& r) { for (int d=0; dcell(d,1)) return false; @@ -411,39 +498,57 @@ namespace madness { grid.push_back(tmp); } if (world.rank()==0 and do_print) { - double volume = 4.0/3.0*constants::pi * std::pow(radius,3.0); + double volume = 4.0/3.0*constants::pi * std::pow(params.radius(),3.0); print("volume element in random grid",volume/(0.67*rank)); } - } else if (gridtype=="cartesian") { - long nperdim=std::lround(std::pow(double(rank),1.0/3.0)); - cartesian_grid cg(nperdim,-radius,radius); - for (cg.index=0; cg(); ++cg) grid.push_back(cg.get_coordinates()); - if (world.rank()==0 and do_print) print("volume element in cartesian grid",cg.volume_per_gridpoint()); +// } else if (gridtype=="cartesian") { +// long nperdim=std::lround(std::pow(double(rank),1.0/3.0)); +// cartesian_grid cg(nperdim,-radius,radius); +// for (cg.index=0; cg(); ++cg) grid.push_back(cg.get_coordinates()); +// if (world.rank()==0 and do_print) print("volume element in cartesian grid",cg.volume_per_gridpoint()); + } else if (params.gridtype()=="spherical") { + cgrid cg(params.volume_element(),params.radius(),params.hard_shell()); + grid=cg.get_coordinates(); +// cartesian_grid cg(volume_per_point,radius); +// for (cg.index=0; cg(); ++cg) grid.push_back(cg.get_coordinates()); +// if (world.rank()==0 and do_print) print("volume element in cartesian grid",cg.volume_per_gridpoint()); } else { MADNESS_EXCEPTION("unknown grid type in project",1); } - if (world.rank()==0 and do_print) { - print("grid is",gridtype,"with radius",radius,"and",grid.size(),"gridpoints"); - print("rhs functions are",rhsfunctiontype); - } - auto Y=Yformer(grid,rhsfunctiontype); + auto Y=Yformer(grid,params.rhsfunctiontype()); t1.tag("Yforming"); + auto norms=norm2s(world,Y); + for (int i=0; irank_revealing_tol) g.push_back(Y[i]); + normalize(world,g); + print("g.size after normalization",g.size()); std::ostringstream oss; oss << std::scientific << std::setprecision(1) << rank_revealing_tol; std::string scientificString = oss.str(); double err=1.0; - double tight_thresh=FunctionDefaults<3>::get_thresh()*0.1; - g=Y; - while (err>1.e-10) { - g=truncate(orthonormalize_rrcd(g,rank_revealing_tol),std::min(1.e-3,tight_thresh*100.0)); + // need only approximate orthonormality here, as we will re-orthonormalize in the optimization step + while (err>1.e-1) { + double tight_thresh=FunctionDefaults<3>::get_thresh()*0.1; + err=check_orthonormality(g); + t1.tag("check orthonormality"); + auto ovlp=matrix_inner(world,g,g); + t1.tag("compute ovlp"); +// g=truncate(orthonormalize_rrcd(g,ovlp,rank_revealing_tol),tight_thresh); + g=truncate(orthonormalize_rrcd(g,ovlp,rank_revealing_tol)); + t1.tag("rrcd/truncate/thresh"); +// ovlp=matrix_inner(world,g,g); +// t1.tag("compute ovlp"); +// g=truncate(madness::orthonormalize(g)); +// t1.tag("ortho/symmetric/truncate"); + auto sz=get_size(world,g); + print("gsize",sz); + t1.tag("Y orthonormalizing rrcd "); err=check_orthonormality(g); - print("error of non-orthonormality",err); - t1.tag("Y orthonormalizing with rank_revealing_tol loose_thresh "+scientificString); + t1.tag("Y orthonormalizing with rank_revealing_tol normal thresh "+scientificString); } g=truncate(g); @@ -467,12 +572,13 @@ namespace madness { } else if (rhsfunctiontype=="exponential") { std::vector> omega; + double coeff=std::pow(2.0*exponent/constants::pi,0.25*LDIM); for (const auto& point : grid) { omega.push_back(FunctionFactory(world) - .functor([&point,&exponent](const Vector& r) + .functor([&point,&exponent,&coeff](const Vector& r) { auto r_rel=r-point; - return exp(-exponent*madness::inner(r_rel,r_rel)); + return coeff*exp(-exponent*madness::inner(r_rel,r_rel)); })); } Y=inner(lrfunctor,omega,p2,p1); @@ -490,31 +596,58 @@ namespace madness { return fapprox; } + + std::vector> orthonormalize(const std::vector>& g) const { + + double tol=rank_revealing_tol; + print("orthonormalizing with method/tol",orthomethod,tol); + std::vector> g2; + auto ovlp=matrix_inner(world,g,g); + if (orthomethod=="symmetric") g2=orthonormalize_symmetric(g,ovlp); + else if (orthomethod=="canonical") g2=orthonormalize_canonical(g,ovlp,tol); + else if (orthomethod=="cholesky") g2=orthonormalize_rrcd(g,ovlp,tol); + else { + MADNESS_EXCEPTION("no such orthomethod",1); + } + double tight_thresh=FunctionDefaults<3>::get_thresh()*0.1; + return truncate(g2,tight_thresh); + } + + /// optimize using Cholesky decomposition - /// if stable_power_iteration is true, orthonormalize in between applications of the kernel (Alg. 4.4 in Halko) /// @param[in] nopt number of iterations (wrt to Alg. 4.3 in Halko) void optimize(const long nopt=1) { timer t(world); t.do_print=do_print; - double tight_thresh=FunctionDefaults<3>::get_thresh()*0.1; + double tight_thresh=FunctionDefaults<3>::get_thresh(); + print("tight_thresh",tight_thresh); for (int i=0; i>& v) const { + timer t(world); Tensor ovlp=matrix_inner(world,v,v); for (int i=0; i("radius",2.0,"the radius"); - initialize("gamma",1.0,"the exponent of the correlation factor"); - initialize("volume_element",0.1,"volume covered by each grid point"); - initialize("rank",500,"the number of grid points in random grids"); - initialize("stable_power_iteration",true,"use stable power iteration algorithm (orthonormalize)"); - initialize("tol",1.e-12,"rank-reduced cholesky tolerance"); - initialize("f12type","Slater","correlation factor",{"Slater","SlaterF12"}); - initialize("transpose","slater2","transpose of the matrix",{"slater1","slater2"}); - initialize("gridtype","random","the grid type",{"random","cartesian"}); - initialize("rhsfunctiontype","exponential","the type of function",{"delta","exponential"}); - initialize("optimize",1,"number of optimization iterations"); - } - - void read_and_set_derived_values(World& world, const commandlineparser& parser, std::string tag) { - read_input_and_commandline_options(world,parser,tag); - } - - double radius() const {return get("radius");} - double gamma() const {return get("gamma");} - double volume_element() const {return get("volume_element");} - double tol() const {return get("tol");} - long rank() const {return get("rank");} - bool stable_power_iteration() const {return get("stable_power_iteration");} - int optimize() const {return get("optimize");} - std::string gridtype() const {return get("gridtype");} - std::string rhsfunctiontype() const {return get("rhsfunctiontype");} -}; - int test_lowrank_function(World& world, LowRankFunctionParameters& parameters) { @@ -61,19 +28,19 @@ int test_lowrank_function(World& world, LowRankFunctionParameters& parameters) { print("eps, k, NDIM, id",FunctionDefaults::get_thresh(),FunctionDefaults::get_k(),NDIM,id); parameters.print("grid","end"); - std::string f12type=parameters.get("f12type"); + std::string f12type=parameters.f12type(); std::string transpose=parameters.get("transpose"); json j; std::string jsonfilename="test_low_rank_function."+id+".json"; j["radius"]=parameters.radius(); - j["f12type"]=parameters.get("f12type"); + j["f12type"]=parameters.f12type(); j["gamma"]=parameters.gamma(); j["volume_element"]=parameters.volume_element(); j["tol"]=parameters.tol(); - j["rank"]=parameters.rank(); + j["hard_shell"]=parameters.hard_shell(); j["transpose"]=transpose; - j["stable_power_iteration"]=parameters.stable_power_iteration(); + j["orthomethod"]=parameters.orthomethod(); j["gridtype"]=parameters.gridtype(); j["rhsfunctiontype"]=parameters.rhsfunctiontype(); j["optimize"]=parameters.optimize(); @@ -140,14 +107,13 @@ int test_lowrank_function(World& world, LowRankFunctionParameters& parameters) { output(0.0,0.0,0.0,0.0,0.0,0.0); LowRankFunction lrf(f12, copy(phi1), copy(phi2)); - lrf.stable_power_iteration=parameters.stable_power_iteration(); plot_plane<6>(world,lrf.lrfunctor,"plot_original."+id,PlotParameters(world).set_plane({"x1","x4"})); double cpu0=cpu_time(); - lrf.project(parameters.volume_element(),parameters.radius(),parameters.gridtype(),parameters.rhsfunctiontype(),parameters.tol()); + lrf.project(parameters); double cpu1=cpu_time(); double error1=lrf.l2error(); print("l2error projection",error1); - plot_plane<6>(world,lrf,"plot_lrf_projection."+id,PlotParameters(world).set_plane({"x1","x4"})); +// plot_plane<6>(world,lrf,"plot_lrf_projection."+id,PlotParameters(world).set_plane({"x1","x4"})); // compare // \phi(1) \bar \phi(1) = \int phi(1) \phi(2) f(1,2) d2 @@ -156,8 +122,8 @@ int test_lowrank_function(World& world, LowRankFunctionParameters& parameters) { real_function_3d result=compute_result(lrf); double projection_error=compute_relative_error(reference,result,lrf); auto diff=reference-result; - plot_plane<3>(world,diff,"plot_diff_int_projection."+id,PlotParameters(world).set_plane({"x1","x2"})); - plot_plane<3>(world,result,"plot_lrf_int_projection."+id,PlotParameters(world).set_plane({"x1","x2"})); +// plot_plane<3>(world,diff,"plot_diff_int_projection."+id,PlotParameters(world).set_plane({"x1","x2"})); +// plot_plane<3>(world,result,"plot_lrf_int_projection."+id,PlotParameters(world).set_plane({"x1","x2"})); output(projection_error,lrf.rank(),cpu1-cpu0,0.0,0.0,0.0); j["projection_error_integrated"]=projection_error; j["projection_error_l2"]=error1; @@ -191,6 +157,154 @@ int test_lowrank_function(World& world, LowRankFunctionParameters& parameters) { } +/// test the K commutator of the He atom + +/// < ij | K f12 | ij > +int test_Kcommutator(World& world, LowRankFunctionParameters& parameters) { + test_output t1("CCPairFunction::low exchange commutator"); + t1.set_cout_to_terminal(); + madness::default_random_generator.setstate(int(cpu_time())%4149); + std::string id=unique_fileid(); + + constexpr std::size_t LDIM=3; + constexpr std::size_t NDIM=2*LDIM; + print("eps, k, NDIM, id",FunctionDefaults::get_thresh(),FunctionDefaults::get_k(),NDIM,id); + parameters.print("grid"); + + real_convolution_3d g12=(CoulombOperator(world,1.e-6,FunctionDefaults::get_thresh())); + std::shared_ptr f12ptr; + std::string f12type=parameters.f12type(); + if (f12type=="slaterf12") f12ptr.reset(SlaterF12OperatorPtr(world,parameters.gamma(),1.e-6,FunctionDefaults::get_thresh())); + else if (f12type=="slater") f12ptr.reset(SlaterOperatorPtr(world,parameters.gamma(),1.e-6,FunctionDefaults::get_thresh())); + else { + MADNESS_EXCEPTION(std::string("unknown f12type"+f12type).c_str(),1); + } + real_convolution_3d& f12=*f12ptr; + + real_function_3d phi=real_factory_3d(world).f([](const coord_3d& r){return exp(-r.normf());}); + double n=phi.norm2(); + phi.scale(1/n); + real_function_3d phi_k=phi; // lookys silly, helps reading. + + + // reference term ( < ij | K(1) ) = = < Ki(1) j(2) | f12 | i(1) j(2) > = ",reference); + + json j; + std::string jsonfilename="test_kcommuntator."+id+".json"; + j["radius"]=parameters.radius(); + j["f12type"]=parameters.f12type(); + j["gamma"]=parameters.gamma(); + j["thresh"]=FunctionDefaults<3>::get_thresh(); + j["volume_element"]=parameters.volume_element(); + j["tol"]=parameters.tol(); + j["hard_shell"]=parameters.hard_shell(); + j["orthomethod"]=parameters.orthomethod(); + j["gridtype"]=parameters.gridtype(); + j["rhsfunctiontype"]=parameters.rhsfunctiontype(); + j["optimize"]=parameters.optimize(); + j["reference"]=reference; + + auto json2file= [](const json& j, const std::string& jsonfilename) { + std::ofstream of(jsonfilename, std::ios::out); + of << j; + of.close(); + }; + + json2file(j,jsonfilename); + timer t(world); + + { + // lowrankfunction left phi: lrf(1',2) = f12(1',2) i(1') + // K f12 ij = \sum_k k(1) \int g(1,1') f12(1'2) i(1') j(2) k(1') d1' + // = \sum_kr k(1) j(2) \int g(1,1') g_r(1') h_r(2) k(1') d1' + // = \sum_r j(2) h_r(2) \sum_k k(1) \int g(1,1') g_r(1') k(1') d1' + real_function_3d one = real_factory_3d(world).f([](const coord_3d& r) { return 1.0; }); + LowRankFunction fi_one(f12ptr, copy(phi), copy(one)); + fi_one.project(parameters); + j["left_project_time"]=t.tag("left_project_time"); + json2file(j,jsonfilename); + + { + auto gk = mul(world, phi_k, g12(fi_one.g * phi_k)); // function of 1 + auto hj = fi_one.h * phi; // function of 2 + Tensor j_hj = inner(world, phi, hj); + Tensor i_gk = inner(world, phi, gk); + double result_left = j_hj.trace(i_gk); + print("result_left, project only", result_left); + j["left_project"]=result_left-reference; + j["left_project_rank"]=fi_one.rank(); + j["left_project_compute_time"]=t.tag("left_project_compute_time"); + } + json2file(j,jsonfilename); + + fi_one.optimize(); + j["left_optimize_time"]=t.tag("left_optimize_time"); + json2file(j,jsonfilename); + { + auto gk = mul(world, phi_k, g12(fi_one.g * phi_k)); // function of 1 + auto hj = fi_one.h * phi; // function of 2 + Tensor j_hj = inner(world, phi, hj); + Tensor i_gk = inner(world, phi, gk); + double result_left = j_hj.trace(i_gk); + print("result_left, optimize", result_left); + j["left_optimize"]=result_left-reference; + j["left_optimize_rank"]=fi_one.rank(); + j["left_optimize_compute_time"]=t.tag("left_optimize_compute_time"); + } + json2file(j,jsonfilename); + } + + // lowrankfunction right phi: lrf(1',2) = f12(1',2) i(1') + { + real_function_3d one = real_factory_3d(world).f([](const coord_3d &r) { return 1.0; }); + LowRankFunction fi_one(f12ptr, copy(one), copy(phi)); + fi_one.project(parameters); + std::swap(fi_one.g,fi_one.h); + j["right_project_time"]=t.tag("right_project_time"); + json2file(j,jsonfilename); + + + { + auto gk = mul(world, phi_k, g12(fi_one.g * phi_k)); // function of 1 + auto hj = fi_one.h * phi; // function of 2 + Tensor j_hj = inner(world, phi, hj); + Tensor i_gk = inner(world, phi, gk); + double result_right = j_hj.trace(i_gk); + print("result_right, project only", result_right); + j["right_project"]=result_right-reference; + j["right_project_rank"]=fi_one.rank(); + j["left_optimize_compute_time"]=t.tag("left_optimize_compute_time"); + j["right_project_compute_time"]=t.tag("right_project_compute_time"); + } + json2file(j,jsonfilename); + std::swap(fi_one.g,fi_one.h); + fi_one.optimize(); + std::swap(fi_one.g,fi_one.h); + { + auto gk = mul(world, phi_k, g12(fi_one.g * phi_k)); // function of 1 + auto hj = fi_one.h * phi; // function of 2 + Tensor j_hj = inner(world, phi, hj); + Tensor i_gk = inner(world, phi, gk); + double result_right = j_hj.trace(i_gk); + print("result_right, optimize", result_right); + j["right_optimize"]=result_right-reference; + j["right_optimize_rank"]=fi_one.rank(); + j["right_optimize_compute_time"]=t.tag("right_optimize_compute_time"); + } + json2file(j,jsonfilename); + + } + + + return 0; + +} + + int main(int argc, char **argv) { madness::World& world = madness::initialize(argc, argv); @@ -221,19 +335,24 @@ int main(int argc, char **argv) { FunctionDefaults<5>::set_cubic_cell(-10.,10.); FunctionDefaults<6>::set_cubic_cell(-10.,10.); + FunctionDefaults<2>::set_tensor_type(TT_FULL); print("numerical parameters: k, eps(3D), eps(6D)", FunctionDefaults<3>::get_k(), FunctionDefaults<3>::get_thresh(), FunctionDefaults<6>::get_thresh()); LowRankFunctionParameters parameters; parameters.read_and_set_derived_values(world,parser,"grid"); + parameters.print("grid"); int isuccess=0; #ifdef USE_GENTENSOR + try { parser.set_keyval("geometry", "he"); parser.print_map(); - isuccess+=test_lowrank_function(world,parameters); + +// isuccess+=test_lowrank_function(world,parameters); + isuccess+=test_Kcommutator(world,parameters); } catch (std::exception& e) { madness::print("an error occured"); madness::print(e.what()); diff --git a/src/madness/mra/vmra.h b/src/madness/mra/vmra.h index bf8568c0371..de50bce735d 100644 --- a/src/madness/mra/vmra.h +++ b/src/madness/mra/vmra.h @@ -518,9 +518,12 @@ namespace madness { return v; } + auto sv=copy(ovlp); rr_cholesky(ovlp,tol,piv,rank); // destroys ovlp and gives back Upper ∆ Matrix from CCD + // ovlp zeroed such that input = inner(transpose(output),output). - // rearrange and truncate the functions according to the pivoting of the rr_cholesky + + // rearrange and truncate the functions according to the pivoting of the rr_cholesky std::vector > pv(rank); for(integer i=0;i Linv = inverse(L); Tensor U = transpose(Linv); +// // L L^T = ovlp +// // Linv ovlp LT inv = 1 +// Tensor LTinv=inverse(ovlp); +// Tensor test=inner(LTinv, inner(sv,Linv)); +// print("LTinv, inner(sv,Linv)"); +// print(test); +// +// print("ovlp - LLt"); +// print(sv-inner(L,L,1,0)); +// print("Linv ovlp Ltinv",inner(Linv, inner(sv,LTinv)).normf()); +// +// +// throw; World& world=v.front().world(); return transform(world, pv, U,tol); } diff --git a/src/madness/world/timing_utilities.h b/src/madness/world/timing_utilities.h index 8b2a80266fd..35b443b12ed 100644 --- a/src/madness/world/timing_utilities.h +++ b/src/madness/world/timing_utilities.h @@ -17,7 +17,7 @@ struct timer { sss = cpu_time(); } - void tag(const std::string msg) { + double tag(const std::string msg) { world.gop.fence(); double tt1 = wall_time() - ttt; double ss1 = cpu_time() - sss; @@ -29,10 +29,11 @@ struct timer { } ttt = wall_time(); sss = cpu_time(); + return ss1; } - void end(const std::string msg) { - tag(msg); + double end(const std::string msg) { + return tag(msg); // world.gop.fence(); // double tt1 = wall_time() - ttt; // double ss1 = cpu_time() - sss; From 600012488d9e7c0be370447863adac204612898a Mon Sep 17 00:00:00 2001 From: fbischoff Date: Mon, 18 Sep 2023 22:50:09 +0200 Subject: [PATCH 049/109] implemented reorthogonalization using svd --- src/madness/chem/lowrankfunction.h | 182 ++++++++++++++------- src/madness/chem/test_low_rank_function.cc | 17 ++ src/madness/tensor/tensor_lapack.h | 14 ++ 3 files changed, 154 insertions(+), 59 deletions(-) diff --git a/src/madness/chem/lowrankfunction.h b/src/madness/chem/lowrankfunction.h index 8486d04352b..c529d1e9ecd 100644 --- a/src/madness/chem/lowrankfunction.h +++ b/src/madness/chem/lowrankfunction.h @@ -503,17 +503,9 @@ namespace madness { } -// } else if (gridtype=="cartesian") { -// long nperdim=std::lround(std::pow(double(rank),1.0/3.0)); -// cartesian_grid cg(nperdim,-radius,radius); -// for (cg.index=0; cg(); ++cg) grid.push_back(cg.get_coordinates()); -// if (world.rank()==0 and do_print) print("volume element in cartesian grid",cg.volume_per_gridpoint()); } else if (params.gridtype()=="spherical") { cgrid cg(params.volume_element(),params.radius(),params.hard_shell()); grid=cg.get_coordinates(); -// cartesian_grid cg(volume_per_point,radius); -// for (cg.index=0; cg(); ++cg) grid.push_back(cg.get_coordinates()); -// if (world.rank()==0 and do_print) print("volume element in cartesian grid",cg.volume_per_gridpoint()); } else { MADNESS_EXCEPTION("unknown grid type in project",1); } @@ -521,36 +513,14 @@ namespace madness { auto Y=Yformer(grid,params.rhsfunctiontype()); t1.tag("Yforming"); - auto norms=norm2s(world,Y); - for (int i=0; irank_revealing_tol) g.push_back(Y[i]); - normalize(world,g); - print("g.size after normalization",g.size()); - - std::ostringstream oss; - oss << std::scientific << std::setprecision(1) << rank_revealing_tol; - std::string scientificString = oss.str(); - double err=1.0; - // need only approximate orthonormality here, as we will re-orthonormalize in the optimization step - while (err>1.e-1) { - double tight_thresh=FunctionDefaults<3>::get_thresh()*0.1; - err=check_orthonormality(g); - t1.tag("check orthonormality"); - auto ovlp=matrix_inner(world,g,g); - t1.tag("compute ovlp"); -// g=truncate(orthonormalize_rrcd(g,ovlp,rank_revealing_tol),tight_thresh); - g=truncate(orthonormalize_rrcd(g,ovlp,rank_revealing_tol)); - t1.tag("rrcd/truncate/thresh"); -// ovlp=matrix_inner(world,g,g); -// t1.tag("compute ovlp"); -// g=truncate(madness::orthonormalize(g)); -// t1.tag("ortho/symmetric/truncate"); - auto sz=get_size(world,g); - print("gsize",sz); - t1.tag("Y orthonormalizing rrcd "); - err=check_orthonormality(g); - t1.tag("Y orthonormalizing with rank_revealing_tol normal thresh "+scientificString); - } - g=truncate(g); + + auto ovlp=matrix_inner(world,Y,Y); // error in symmetric matrix_inner, use non-symmetric form here! + t1.tag("compute ovlp"); + g=truncate(orthonormalize_rrcd(Y,ovlp,rank_revealing_tol)); + t1.tag("rrcd/truncate/thresh"); + auto sz=get_size(world,g); + print("gsize",sz); + check_orthonormality(g); if (world.rank()==0 and do_print) { print("Y.size()",Y.size()); @@ -585,7 +555,12 @@ namespace madness { } else { MADNESS_EXCEPTION("confused rhsfunctiontype",1); } - return Y; + auto norms=norm2s(world,Y); + std::vector> Ynormalized; + + for (int i=0; irank_revealing_tol) Ynormalized.push_back(Y[i]); + normalize(world,Ynormalized); + return Ynormalized; } long rank() const {return g.size();} @@ -600,12 +575,19 @@ namespace madness { std::vector> orthonormalize(const std::vector>& g) const { double tol=rank_revealing_tol; - print("orthonormalizing with method/tol",orthomethod,tol); std::vector> g2; auto ovlp=matrix_inner(world,g,g); - if (orthomethod=="symmetric") g2=orthonormalize_symmetric(g,ovlp); - else if (orthomethod=="canonical") g2=orthonormalize_canonical(g,ovlp,tol); - else if (orthomethod=="cholesky") g2=orthonormalize_rrcd(g,ovlp,tol); + if (orthomethod=="symmetric") { + print("orthonormalizing with method/tol",orthomethod,tol); + g2=orthonormalize_symmetric(g,ovlp); + } else if (orthomethod=="canonical") { + tol*=0.01; + print("orthonormalizing with method/tol",orthomethod,tol); + g2=orthonormalize_canonical(g,ovlp,tol); + } else if (orthomethod=="cholesky") { + print("orthonormalizing with method/tol",orthomethod,tol); + g2=orthonormalize_rrcd(g,ovlp,tol); + } else { MADNESS_EXCEPTION("no such orthomethod",1); } @@ -620,35 +602,117 @@ namespace madness { void optimize(const long nopt=1) { timer t(world); t.do_print=do_print; - double tight_thresh=FunctionDefaults<3>::get_thresh(); - print("tight_thresh",tight_thresh); for (int i=0; i ovlp_g = matrix_inner(world, g, g); + Tensor ovlp_h = matrix_inner(world, h, h); + auto [eval_g, evec_g] = syev(ovlp_g); + auto [eval_h, evec_h] = syev(ovlp_h); + Tensor Xplus=copy(evec_g); + Tensor Xminus=copy(evec_g); + Tensor Yplus=copy(evec_h); + Tensor Yminus=copy(evec_h); +// print("eval_g",eval_g); +// print("eval_h",eval_h); + for (int i=0; i M=madness::inner(Xplus,Yplus,0,0); // (X+)^T Y+ + auto [U,s,VT]=svd(M); +// print("s",s); + + // truncate + typename Tensor::scalar_type s_accumulated=0.0; + int i=s.size()-1; + for (;i>=0; i--) { + s_accumulated+=s[i]; + if (s_accumulated>thresh) { + i++; + break; + } + } + print("accumulated s",s_accumulated,thresh,s.size(),i); + for (int j=0; j XX=madness::inner(Xminus,U,1,0); + Tensor YY=madness::inner(Yminus,VT,1,1); + + g=truncate(transform(world,g,XX)); + h=truncate(transform(world,h,YY)); +// { +// auto one=matrix_inner(world,g,g); +// check_orthonormality(one); +// } +// { +// auto one=matrix_inner(world,h,h); +// check_orthonormality(one); +// } + + + + } + + double check_orthonormality(const std::vector>& v) const { - timer t(world); Tensor ovlp=matrix_inner(world,v,v); - for (int i=0; i& ovlp) const { + timer t(world); + Tensor ovlp2=ovlp; + for (int i=0; i i_gk = inner(world, phi, gk); double result_left = j_hj.trace(i_gk); print("result_left, optimize", result_left); + print("left optimize rank",fi_one.rank()); j["left_optimize"]=result_left-reference; j["left_optimize_rank"]=fi_one.rank(); j["left_optimize_compute_time"]=t.tag("left_optimize_compute_time"); } json2file(j,jsonfilename); + + fi_one.reorthonormalize(); + j["left_reorthonormalize"]=t.tag("left_reorthonormalize"); + print("left reorthonormalize rank",fi_one.rank()); + { + auto gk = mul(world, phi_k, g12(fi_one.g * phi_k)); // function of 1 + auto hj = fi_one.h * phi; // function of 2 + Tensor j_hj = inner(world, phi, hj); + Tensor i_gk = inner(world, phi, gk); + double result_left = j_hj.trace(i_gk); + print("result_left, reorthonormalize", result_left); + j["left_project"]=result_left-reference; + j["left_project_rank"]=fi_one.rank(); + j["left_project_compute_time"]=t.tag("left_project_compute_time"); + } + j["left_reorthonormalize_compute_time"]=t.tag("left_reorthonormalize_compute_time"); } // lowrankfunction right phi: lrf(1',2) = f12(1',2) i(1') diff --git a/src/madness/tensor/tensor_lapack.h b/src/madness/tensor/tensor_lapack.h index f446236a5b0..1215aebbb9a 100644 --- a/src/madness/tensor/tensor_lapack.h +++ b/src/madness/tensor/tensor_lapack.h @@ -60,6 +60,20 @@ namespace madness { void svd_result(Tensor& a, Tensor& U, Tensor< typename Tensor::scalar_type >& s, Tensor& VT, Tensor& work); + /// SVD - MATLAB syntax + + /// call as + /// auto [U,s,VT] = svd(A); + /// with A=U*S*VT + template + std::tuple, Tensor< typename Tensor::scalar_type >, Tensor> + svd(const Tensor& A) { + Tensor U,VT; + Tensor< typename Tensor::scalar_type > s; + svd(A,U,s,VT); + return std::make_tuple(U,s,VT); + } + /// Solves linear equations /// \ingroup linalg From 336c96686aa8c1e18ba3c861168199b1828f6fac Mon Sep 17 00:00:00 2001 From: fbischoff Date: Tue, 19 Sep 2023 10:19:20 +0200 Subject: [PATCH 050/109] some cleanup --- src/madness/chem/lowrankfunction.h | 187 ++++++--------------- src/madness/chem/test_low_rank_function.cc | 140 +++++++-------- 2 files changed, 113 insertions(+), 214 deletions(-) diff --git a/src/madness/chem/lowrankfunction.h b/src/madness/chem/lowrankfunction.h index c529d1e9ecd..d2eb6cc601f 100644 --- a/src/madness/chem/lowrankfunction.h +++ b/src/madness/chem/lowrankfunction.h @@ -174,11 +174,8 @@ namespace madness { double exponent; double radius=2; randomgaussian(double exponent, double radius) : exponent(exponent), radius(radius) { -// Vector ran; // [0,1] -// RandomVector(NDIM,ran.data()); Vector ran= this->gaussian_random_distribution(0,radius); random_origin=2.0*radius*ran-Vector(radius); -// print("origin at ",random_origin, ", exponent",exponent); } double operator()(const Vector& r) const { // return exp(-exponent*inner(r-random_origin,r-random_origin)); @@ -328,64 +325,11 @@ namespace madness { } - /// inner product: result(1) = \int f(1,2) delta(2) d2 - - /// @param[in] functor the hidim function - /// @param[in] grid grid points with delta functions - /// @param[in] p1 the variable in f(1,2) to be integrated over - /// @param[in] p2 the variable in rhs to be integrated over (usually all of them) - static std::vector> inner(LRFunctor& functor, const std::vector>& grid, - const particle p1, const particle p2) { - std::vector> result; - MADNESS_CHECK(functor.has_f() xor functor.has_f12()); - MADNESS_CHECK(p1.is_first() xor p1.is_last()); - MADNESS_CHECK(p2.is_first()); - - if (functor.has_f()) { - MADNESS_EXCEPTION("no grid points with an explicit hi-dim function",1); - - } else if (functor.has_f12()) { - MADNESS_CHECK(functor.f12->info.type==OT_SLATER); - // functor is now a(1) b(2) f12 - // result(1) = \int a(1) f(1,2) b(2) delta(R-2) d2 - // = a(1) f(1,R) b(R) - World& world=functor.f12->get_world(); - auto premultiply= p1.is_first() ? functor.a : functor.b; - auto postmultiply= p1.is_first() ? functor.b : functor.a; - - std::vector> f1R= slater_functions_on_grid(world,grid); - print("bla1"); - if (premultiply.is_initialized()) { - for (int i=0; i> slater_functions_on_grid(World& world, const std::vector>& grid) { - std::vector> result; - for (const auto& point : grid) { - auto sl=[&point](const Vector& r) { - return exp(-sqrt(madness::inner(r-point,r-point)+1.e-8)); - }; - result.push_back(FunctionFactory(world).functor(sl)); - } - return result; - } World& world; double rank_revealing_tol=1.e-8; // rrcd tol - std::string orthomethod="symmetric"; + std::string orthomethod="canonical"; bool do_print=true; std::vector> g,h; LRFunctor lrfunctor; @@ -481,36 +425,8 @@ namespace madness { orthomethod=params.orthomethod(); rank_revealing_tol=params.tol(); - - // make grid - std::vector> grid; - if (params.gridtype()=="random") { - double volume=4.0/3.0*constants::pi *std::pow(params.radius(),3.0); - long rank = lround(volume/(0.67*params.volume_element() )); - for (int i=0; i::gaussian_random_distribution(0,params.radius()); - auto cell=FunctionDefaults::get_cell(); - auto is_in_cell = [&cell](const Vector& r) { - for (int d=0; dcell(d,1)) return false; - return true; - }; - if (not is_in_cell(tmp)) continue; - grid.push_back(tmp); - } - if (world.rank()==0 and do_print) { - double volume = 4.0/3.0*constants::pi * std::pow(params.radius(),3.0); - print("volume element in random grid",volume/(0.67*rank)); - } - - - } else if (params.gridtype()=="spherical") { - cgrid cg(params.volume_element(),params.radius(),params.hard_shell()); - grid=cg.get_coordinates(); - } else { - MADNESS_EXCEPTION("unknown grid type in project",1); - } - - + // get sampling grid + std::vector> grid=make_grid(params); auto Y=Yformer(grid,params.rhsfunctiontype()); t1.tag("Yforming"); @@ -519,7 +435,7 @@ namespace madness { g=truncate(orthonormalize_rrcd(Y,ovlp,rank_revealing_tol)); t1.tag("rrcd/truncate/thresh"); auto sz=get_size(world,g); - print("gsize",sz); + if (world.rank()==0 and do_print) print("gsize",sz); check_orthonormality(g); if (world.rank()==0 and do_print) { @@ -537,10 +453,7 @@ namespace madness { const double exponent=30.0) { std::vector> Y; - if (rhsfunctiontype=="delta") { - Y=inner(lrfunctor,grid,p2,p1); - - } else if (rhsfunctiontype=="exponential") { + if (rhsfunctiontype=="exponential") { std::vector> omega; double coeff=std::pow(2.0*exponent/constants::pi,0.25*LDIM); for (const auto& point : grid) { @@ -565,6 +478,13 @@ namespace madness { long rank() const {return g.size();} + /// return the size in GByte + double size() const { + double sz=get_size(world,g); + sz+=get_size(world,h); + return sz; + } + Function reconstruct() const { auto fapprox=hartree_product(g[0],h[0]); for (int i=1; i> orthonormalize(const std::vector>& g) const { double tol=rank_revealing_tol; @@ -596,7 +517,7 @@ namespace madness { } - /// optimize using Cholesky decomposition + /// optimize the lrf using the lrfunctor /// @param[in] nopt number of iterations (wrt to Alg. 4.3 in Halko) void optimize(const long nopt=1) { @@ -615,7 +536,7 @@ namespace madness { } } - /// after external operations g might not be orthonormal and/or optimal + /// after external operations g might not be orthonormal and/or optimal -- reorthonormalize /// orthonormalization similar to Bischoff, Harrison, Valeev, JCP 137 104103 (2012), Sec II C 3 /// f =\sum_i g_i h_i @@ -634,34 +555,13 @@ namespace madness { Tensor Xminus=copy(evec_g); Tensor Yplus=copy(evec_h); Tensor Yminus=copy(evec_h); -// print("eval_g",eval_g); -// print("eval_h",eval_h); for (int i=0; i M=madness::inner(Xplus,Yplus,0,0); // (X+)^T Y+ auto [U,s,VT]=svd(M); -// print("s",s); // truncate typename Tensor::scalar_type s_accumulated=0.0; @@ -673,33 +573,47 @@ namespace madness { break; } } - print("accumulated s",s_accumulated,thresh,s.size(),i); for (int j=0; j XX=madness::inner(Xminus,U,1,0); Tensor YY=madness::inner(Yminus,VT,1,1); g=truncate(transform(world,g,XX)); h=truncate(transform(world,h,YY)); -// { -// auto one=matrix_inner(world,g,g); -// check_orthonormality(one); -// } -// { -// auto one=matrix_inner(world,h,h); -// check_orthonormality(one); -// } + } + + /// make a sampling grid Omega_i(r) for the Halko algorithm + std::vector> make_grid(const LowRankFunctionParameters& params) const { + + std::vector> grid; + if (params.gridtype()=="random") { + double volume=4.0/3.0*constants::pi *std::pow(params.radius(),3.0); + long rank = lround(volume/(0.67*params.volume_element() )); + for (int i=0; i::gaussian_random_distribution(0,params.radius()); + auto cell=FunctionDefaults::get_cell(); + auto is_in_cell = [&cell](const Vector& r) { + for (int d=0; dcell(d,1)) return false; + return true; + }; + if (not is_in_cell(tmp)) continue; + grid.push_back(tmp); + } + if (world.rank()==0 and do_print) { + double volume = 4.0/3.0*constants::pi * std::pow(params.radius(),3.0); + print("volume element in random grid",volume/(0.67*rank)); + } + } else if (params.gridtype()=="spherical") { + cgrid cg(params.volume_element(),params.radius(),params.hard_shell()); + grid=cg.get_coordinates(); + } else { + MADNESS_EXCEPTION("unknown grid type in project",1); + } + return grid; } - double check_orthonormality(const std::vector>& v) const { Tensor ovlp=matrix_inner(world,v,v); return check_orthonormality(ovlp); @@ -707,10 +621,13 @@ namespace madness { double check_orthonormality(const Tensor& ovlp) const { timer t(world); + t.do_print=do_print; Tensor ovlp2=ovlp; for (int i=0; i1.e-10) print("g is not orthonormal",zero); +// double zero=check_orthonormality(g); +// if (zero>1.e-10) print("g is not orthonormal",zero); double term3=madness::inner(h,h); t.tag("computing term3"); diff --git a/src/madness/chem/test_low_rank_function.cc b/src/madness/chem/test_low_rank_function.cc index 60e9ac26e2a..dbf25701f49 100644 --- a/src/madness/chem/test_low_rank_function.cc +++ b/src/madness/chem/test_low_rank_function.cc @@ -216,6 +216,19 @@ int test_Kcommutator(World& world, LowRankFunctionParameters& parameters) { json2file(j,jsonfilename); timer t(world); + auto compute_error = [&](const std::string msg, const LowRankFunction& lrf) { + auto gk = mul(world, phi_k, g12(lrf.g * phi_k)); // function of 1 + auto hj = lrf.h * phi; // function of 2 + Tensor j_hj = inner(world, phi, hj); + Tensor i_gk = inner(world, phi, gk); + double result_right = j_hj.trace(i_gk); + print(msg, result_right); + j[msg]=result_right-reference; + j[msg+"_rank"]=lrf.rank(); + j[msg+"_compute_time"]=t.tag(msg+"_compute_time"); + json2file(j,jsonfilename); + }; + { // lowrankfunction left phi: lrf(1',2) = f12(1',2) i(1') @@ -225,97 +238,66 @@ int test_Kcommutator(World& world, LowRankFunctionParameters& parameters) { real_function_3d one = real_factory_3d(world).f([](const coord_3d& r) { return 1.0; }); LowRankFunction fi_one(f12ptr, copy(phi), copy(one)); fi_one.project(parameters); - j["left_project_time"]=t.tag("left_project_time"); - json2file(j,jsonfilename); + double l2error=fi_one.l2error(); + print("left_project_l2error",l2error); - { - auto gk = mul(world, phi_k, g12(fi_one.g * phi_k)); // function of 1 - auto hj = fi_one.h * phi; // function of 2 - Tensor j_hj = inner(world, phi, hj); - Tensor i_gk = inner(world, phi, gk); - double result_left = j_hj.trace(i_gk); - print("result_left, project only", result_left); - j["left_project"]=result_left-reference; - j["left_project_rank"]=fi_one.rank(); - j["left_project_compute_time"]=t.tag("left_project_compute_time"); - } + j["left_project_time"]=t.tag("left_project_time"); json2file(j,jsonfilename); + compute_error("left_project",fi_one); fi_one.optimize(); + l2error=fi_one.l2error(); + print("left_optimize_l2error",l2error); j["left_optimize_time"]=t.tag("left_optimize_time"); json2file(j,jsonfilename); - { - auto gk = mul(world, phi_k, g12(fi_one.g * phi_k)); // function of 1 - auto hj = fi_one.h * phi; // function of 2 - Tensor j_hj = inner(world, phi, hj); - Tensor i_gk = inner(world, phi, gk); - double result_left = j_hj.trace(i_gk); - print("result_left, optimize", result_left); - print("left optimize rank",fi_one.rank()); - j["left_optimize"]=result_left-reference; - j["left_optimize_rank"]=fi_one.rank(); - j["left_optimize_compute_time"]=t.tag("left_optimize_compute_time"); - } - json2file(j,jsonfilename); + compute_error("left_optimize",fi_one); fi_one.reorthonormalize(); j["left_reorthonormalize"]=t.tag("left_reorthonormalize"); - print("left reorthonormalize rank",fi_one.rank()); - { - auto gk = mul(world, phi_k, g12(fi_one.g * phi_k)); // function of 1 - auto hj = fi_one.h * phi; // function of 2 - Tensor j_hj = inner(world, phi, hj); - Tensor i_gk = inner(world, phi, gk); - double result_left = j_hj.trace(i_gk); - print("result_left, reorthonormalize", result_left); - j["left_project"]=result_left-reference; - j["left_project_rank"]=fi_one.rank(); - j["left_project_compute_time"]=t.tag("left_project_compute_time"); - } - j["left_reorthonormalize_compute_time"]=t.tag("left_reorthonormalize_compute_time"); - } - - // lowrankfunction right phi: lrf(1',2) = f12(1',2) i(1') - { - real_function_3d one = real_factory_3d(world).f([](const coord_3d &r) { return 1.0; }); - LowRankFunction fi_one(f12ptr, copy(one), copy(phi)); - fi_one.project(parameters); - std::swap(fi_one.g,fi_one.h); - j["right_project_time"]=t.tag("right_project_time"); - json2file(j,jsonfilename); - - - { - auto gk = mul(world, phi_k, g12(fi_one.g * phi_k)); // function of 1 - auto hj = fi_one.h * phi; // function of 2 - Tensor j_hj = inner(world, phi, hj); - Tensor i_gk = inner(world, phi, gk); - double result_right = j_hj.trace(i_gk); - print("result_right, project only", result_right); - j["right_project"]=result_right-reference; - j["right_project_rank"]=fi_one.rank(); - j["left_optimize_compute_time"]=t.tag("left_optimize_compute_time"); - j["right_project_compute_time"]=t.tag("right_project_compute_time"); - } - json2file(j,jsonfilename); - std::swap(fi_one.g,fi_one.h); - fi_one.optimize(); - std::swap(fi_one.g,fi_one.h); - { - auto gk = mul(world, phi_k, g12(fi_one.g * phi_k)); // function of 1 - auto hj = fi_one.h * phi; // function of 2 - Tensor j_hj = inner(world, phi, hj); - Tensor i_gk = inner(world, phi, gk); - double result_right = j_hj.trace(i_gk); - print("result_right, optimize", result_right); - j["right_optimize"]=result_right-reference; - j["right_optimize_rank"]=fi_one.rank(); - j["right_optimize_compute_time"]=t.tag("right_optimize_compute_time"); - } json2file(j,jsonfilename); - + compute_error("left_reorthonormalize",fi_one); } +// // lowrankfunction right phi: lrf(1',2) = f12(1',2) i(1') +// { +// real_function_3d one = real_factory_3d(world).f([](const coord_3d &r) { return 1.0; }); +// LowRankFunction fi_one(f12ptr, copy(one), copy(phi)); +// fi_one.project(parameters); +// std::swap(fi_one.g,fi_one.h); +// j["right_project_time"]=t.tag("right_project_time"); +// json2file(j,jsonfilename); +// +// +// { +// auto gk = mul(world, phi_k, g12(fi_one.g * phi_k)); // function of 1 +// auto hj = fi_one.h * phi; // function of 2 +// Tensor j_hj = inner(world, phi, hj); +// Tensor i_gk = inner(world, phi, gk); +// double result_right = j_hj.trace(i_gk); +// print("result_right, project only", result_right); +// j["right_project"]=result_right-reference; +// j["right_project_rank"]=fi_one.rank(); +// j["left_optimize_compute_time"]=t.tag("left_optimize_compute_time"); +// j["right_project_compute_time"]=t.tag("right_project_compute_time"); +// } +// json2file(j,jsonfilename); +// std::swap(fi_one.g,fi_one.h); +// fi_one.optimize(); +// std::swap(fi_one.g,fi_one.h); +// { +// auto gk = mul(world, phi_k, g12(fi_one.g * phi_k)); // function of 1 +// auto hj = fi_one.h * phi; // function of 2 +// Tensor j_hj = inner(world, phi, hj); +// Tensor i_gk = inner(world, phi, gk); +// double result_right = j_hj.trace(i_gk); +// print("result_right, optimize", result_right); +// j["right_optimize"]=result_right-reference; +// j["right_optimize_rank"]=fi_one.rank(); +// j["right_optimize_compute_time"]=t.tag("right_optimize_compute_time"); +// } +// json2file(j,jsonfilename); +// +// } return 0; From 31706ad74ed2fa30a080dfd994bc0eed46f495da Mon Sep 17 00:00:00 2001 From: fbischoff Date: Tue, 19 Sep 2023 15:00:20 +0200 Subject: [PATCH 051/109] working on the grid --- src/madness/chem/lowrankfunction.h | 111 +++++++++++++++------ src/madness/chem/test_low_rank_function.cc | 42 +++++++- src/madness/mra/funcplot.h | 4 +- 3 files changed, 119 insertions(+), 38 deletions(-) diff --git a/src/madness/chem/lowrankfunction.h b/src/madness/chem/lowrankfunction.h index d2eb6cc601f..a56388d333f 100644 --- a/src/madness/chem/lowrankfunction.h +++ b/src/madness/chem/lowrankfunction.h @@ -50,15 +50,88 @@ namespace madness { }; + class gridbase { + protected: + double volume_element=0.1; + double radius=3; + }; + + template + class randomgrid : public gridbase { + public: + randomgrid(const double volume_element, const double radius) : gridbase() { + this->volume_element=volume_element; + this->radius=radius; + } + + std::vector> get_grid() const { + std::vector> grid; + long npoint_within_volume=volume()/volume_element; + print("npoint_within_volume",npoint_within_volume); + + auto cell = FunctionDefaults::get_cell(); + auto is_in_cell = [&cell](const Vector& r) { + for (int d = 0; d < NDIM; ++d) if (r[d] < cell(d, 0) or r[d] > cell(d, 1)) return false; + return true; + }; + double rad=radius; + auto is_in_sphere = [&rad](const Vector& r) { + return (r.normf()0 and NDIM<4); + if (NDIM==1) return 2.0*radius; + if (NDIM==2) return constants::pi*radius*radius; + if (NDIM==3) return 4.0 / 3.0 * constants::pi * std::pow(radius, 3.0); + } + + static Vector gaussian_random_distribution(double mean, double variance) { + std::random_device rd{}; + std::mt19937 gen{rd()}; + std::normal_distribution<> d{mean, variance}; + Vector result; + for (int i = 0; i < NDIM; ++i) result[i]=d(gen); + return result; + } + +// double computed_volume_element() const { +// double volume = 4.0 / 3.0 * constants::pi * std::pow(radius, 3.0); +// print("volume element in random grid", volume / (0.67 * rank)); +// } + + }; template - class cgrid { + class sphericalgrid : public gridbase { public: double volume_element=0.1; double radius=3; bool hard_shell=true; - cgrid(const double volume_element, const double radius, bool hard_shell) + sphericalgrid(const double volume_element, const double radius, bool hard_shell) :volume_element(volume_element), radius(radius), hard_shell(hard_shell) { }; @@ -584,34 +657,8 @@ namespace madness { /// make a sampling grid Omega_i(r) for the Halko algorithm std::vector> make_grid(const LowRankFunctionParameters& params) const { - std::vector> grid; - if (params.gridtype()=="random") { - double volume=4.0/3.0*constants::pi *std::pow(params.radius(),3.0); - long rank = lround(volume/(0.67*params.volume_element() )); - for (int i=0; i::gaussian_random_distribution(0,params.radius()); - auto cell=FunctionDefaults::get_cell(); - auto is_in_cell = [&cell](const Vector& r) { - for (int d=0; dcell(d,1)) return false; - return true; - }; - if (not is_in_cell(tmp)) continue; - grid.push_back(tmp); - } - if (world.rank()==0 and do_print) { - double volume = 4.0/3.0*constants::pi * std::pow(params.radius(),3.0); - print("volume element in random grid",volume/(0.67*rank)); - } - - - } else if (params.gridtype()=="spherical") { - cgrid cg(params.volume_element(),params.radius(),params.hard_shell()); - grid=cg.get_coordinates(); - } else { - MADNESS_EXCEPTION("unknown grid type in project",1); - } - - return grid; + randomgrid grid(params.volume_element(),params.radius()); + return grid.get_grid(); } double check_orthonormality(const std::vector>& v) const { @@ -673,8 +720,8 @@ namespace madness { // = \sum_{ij} \int g_i(1) g_j(1) d1 \int h_i(2) h_j(2) d2 // = \sum_{ij} delta_{ij} \int h_i(2) h_j(2) d2 // = \sum_{i} \int h_i(2) h_i(2) d2 -// double zero=check_orthonormality(g); -// if (zero>1.e-10) print("g is not orthonormal",zero); + double zero=check_orthonormality(g); + if (zero>1.e-10) print("g is not orthonormal",zero); double term3=madness::inner(h,h); t.tag("computing term3"); diff --git a/src/madness/chem/test_low_rank_function.cc b/src/madness/chem/test_low_rank_function.cc index dbf25701f49..8c1593e2730 100644 --- a/src/madness/chem/test_low_rank_function.cc +++ b/src/madness/chem/test_low_rank_function.cc @@ -303,6 +303,35 @@ int test_Kcommutator(World& world, LowRankFunctionParameters& parameters) { } +template +int test_grids(World& world, LowRankFunctionParameters& parameters) { + randomgrid g(parameters.volume_element(),parameters.radius()); + g.get_grid(); + + return 0; +} + +template +int test_construction_optimization(World& world, LowRankFunctionParameters parameters) { + parameters.set_user_defined_value("volume_element",0.05); + constexpr std::size_t NDIM=2*LDIM; + test_output t1("LowRankFunction::construction/optimization in dimension "+std::to_string(NDIM)); + t1.set_cout_to_terminal(); + OperatorInfo info(1.0,1.e-6,FunctionDefaults::get_thresh(),OT_SLATER); + auto slater=std::shared_ptr >(new SeparatedConvolution(world,info)); + Function one=FunctionFactory(world).functor([](const Vector& r){return exp(-0.2*inner(r,r));}); + + LowRankFunction lrf(slater,one,one); + lrf.project(parameters); + double error=lrf.l2error(); + t1.checkpoint(error<2.e-2,"l2 error in projection "+std::to_string(error)); + print("l2 error project ",error); + lrf.optimize(); + error=lrf.l2error(); + print("l2 error optimize",error); + t1.checkpoint(error<1.e-2,"l2 error in optimization "+std::to_string(error)); + return t1.end(); +} int main(int argc, char **argv) { @@ -310,7 +339,7 @@ int main(int argc, char **argv) { startup(world, argc, argv); commandlineparser parser(argc, argv); int k = parser.key_exists("k") ? std::atoi(parser.value("k").c_str()) : 6; - double thresh = parser.key_exists("thresh") ? std::stod(parser.value("thresh")) : 1.e-4; + double thresh = parser.key_exists("thresh") ? std::stod(parser.value("thresh")) : 1.e-5; FunctionDefaults<6>::set_tensor_type(TT_2D); FunctionDefaults<1>::set_thresh(thresh); @@ -346,12 +375,17 @@ int main(int argc, char **argv) { try { - parser.set_keyval("geometry", "he"); - parser.print_map(); + isuccess+=test_grids<1>(world,parameters); + isuccess+=test_grids<2>(world,parameters); + isuccess+=test_grids<3>(world,parameters); + isuccess+=test_construction_optimization<1>(world,parameters); + isuccess+=test_construction_optimization<2>(world,parameters); +// isuccess+=test_arithmetic<1>(world,parameters); +// isuccess+=test_arithmetic<2>(world,parameters); // isuccess+=test_lowrank_function(world,parameters); - isuccess+=test_Kcommutator(world,parameters); + isuccess+=test_Kcommutator(world,parameters); } catch (std::exception& e) { madness::print("an error occured"); madness::print(e.what()); diff --git a/src/madness/mra/funcplot.h b/src/madness/mra/funcplot.h index 4a826b2e82a..c0bc02c9e40 100644 --- a/src/madness/mra/funcplot.h +++ b/src/madness/mra/funcplot.h @@ -55,7 +55,7 @@ namespace madness { // initialize with: key, value, comment (optional), allowed values (optional) initialize("zoom",2,"zoom into the simulation cell"); initialize("npoints",151,"number of plot points per dimension"); - initialize>("origin",{0.0,0.0,0.0},"origin of the plot"); + initialize>("origin",{},"origin of the plot"); initialize>("plane",{"x1","x2"},"plot plane: x1, x2, .., x6"); } @@ -84,7 +84,7 @@ namespace madness { Vector origin() const { auto origin_vec=get>("origin"); // fill in zeros if the default origin has fewer dimensions than the actual origin - std::size_t missing=NDIM-origin_vec.size(); + int missing=NDIM-origin_vec.size(); for (auto i=0; i o(origin_vec); return o; From 716d96354d1d9be8474dd9ed577015eaf6b36e46 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Thu, 21 Sep 2023 12:20:27 +0200 Subject: [PATCH 052/109] fixed failing periodic test --- src/madness/mra/testper.cc | 3 ++- src/madness/mra/vmra.h | 22 +++------------------- 2 files changed, 5 insertions(+), 20 deletions(-) diff --git a/src/madness/mra/testper.cc b/src/madness/mra/testper.cc index 61ba93b6c96..a044756375e 100644 --- a/src/madness/mra/testper.cc +++ b/src/madness/mra/testper.cc @@ -65,7 +65,8 @@ int test_per(World& world) { expnt[0] = 10000.0; coeff[0] = sqrt(expnt[0]/constants::pi); print(coeff,expnt); - SeparatedConvolution op(world, coeff, expnt); + double lo=1.e-6; thresh=1.e-4; // dummy values + SeparatedConvolution op(world, coeff, expnt, lo, thresh); Function f = FunctionFactory(world).f(constant).initial_level(3).norefine(); diff --git a/src/madness/mra/vmra.h b/src/madness/mra/vmra.h index de50bce735d..9fa1515e198 100644 --- a/src/madness/mra/vmra.h +++ b/src/madness/mra/vmra.h @@ -518,12 +518,9 @@ namespace madness { return v; } - auto sv=copy(ovlp); rr_cholesky(ovlp,tol,piv,rank); // destroys ovlp and gives back Upper ∆ Matrix from CCD - // ovlp zeroed such that input = inner(transpose(output),output). - - // rearrange and truncate the functions according to the pivoting of the rr_cholesky + // rearrange and truncate the functions according to the pivoting of the rr_cholesky std::vector > pv(rank); for(integer i=0;i Linv = inverse(L); Tensor U = transpose(Linv); -// // L L^T = ovlp -// // Linv ovlp LT inv = 1 -// Tensor LTinv=inverse(ovlp); -// Tensor test=inner(LTinv, inner(sv,Linv)); -// print("LTinv, inner(sv,Linv)"); -// print(test); -// -// print("ovlp - LLt"); -// print(sv-inner(L,L,1,0)); -// print("Linv ovlp Ltinv",inner(Linv, inner(sv,LTinv)).normf()); -// -// -// throw; World& world=v.front().world(); - return transform(world, pv, U,tol); + return transform(world, pv, U); } /// convenience routine for orthonromalize_cholesky: orthonromalize_cholesky without information on pivoting and rank @@ -572,7 +556,7 @@ namespace madness { } // compute overlap World& world=v.front().world(); - Tensor ovlp = matrix_inner(world, v, v,true); + Tensor ovlp = matrix_inner(world, v, v); return orthonormalize_rrcd(v,ovlp,tol); } From 6628d97fec3fef3863f8d345d0e547ba3b4b55a9 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Thu, 21 Sep 2023 14:45:07 +0200 Subject: [PATCH 053/109] fixed more failing tests --- src/madness/chem/test_low_rank_function.cc | 2 +- src/madness/mra/operator.h | 2 +- src/madness/mra/testsuite.cc | 3 ++- src/madness/tensor/tensor.h | 3 +++ 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/madness/chem/test_low_rank_function.cc b/src/madness/chem/test_low_rank_function.cc index 8c1593e2730..205f5c3cd41 100644 --- a/src/madness/chem/test_low_rank_function.cc +++ b/src/madness/chem/test_low_rank_function.cc @@ -385,7 +385,7 @@ int main(int argc, char **argv) { // isuccess+=test_arithmetic<2>(world,parameters); // isuccess+=test_lowrank_function(world,parameters); - isuccess+=test_Kcommutator(world,parameters); +// isuccess+=test_Kcommutator(world,parameters); } catch (std::exception& e) { madness::print("an error occured"); madness::print(e.what()); diff --git a/src/madness/mra/operator.h b/src/madness/mra/operator.h index 84dc8ec6e04..0ff5fc9eb19 100644 --- a/src/madness/mra/operator.h +++ b/src/madness/mra/operator.h @@ -1043,7 +1043,7 @@ namespace madness { initialize(coeff,expnt); } - void initialize(const Tensor& coeff, const Tensor& expnt) { + void initialize(const Tensor& coeff, const Tensor& expnt) { // Presently we must have periodic or non-periodic in all dimensions. for (std::size_t d=1; d coeffs(1), exponents(1); exponents(0L) = 10.0; coeffs(0L) = pow(exponents(0L)/PI, 0.5*NDIM); - SeparatedConvolution op(world, coeffs, exponents); + double lo=1.e-6, thresh1=1.e-4; + SeparatedConvolution op(world, coeffs, exponents, lo, thresh1); START_TIMER; Function r = madness::apply(op,f); END_TIMER("apply"); diff --git a/src/madness/tensor/tensor.h b/src/madness/tensor/tensor.h index c438f2dcc07..bdb0a77dfad 100644 --- a/src/madness/tensor/tensor.h +++ b/src/madness/tensor/tensor.h @@ -260,6 +260,9 @@ namespace madness { template T mynorm(T t) { return t*t; } + template double mynorm(int t) { + return double(t)*double(t); + } template T mynorm(std::complex t) { return std::norm(t); From d4f15035a2a4a08ff3460c66b494bbb702343fc5 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Tue, 26 Sep 2023 13:02:28 +0200 Subject: [PATCH 054/109] adding a gaussian function to operator.h --- src/madness/chem/CCStructures.h | 1 - src/madness/chem/lowrankfunction.h | 520 +++++++++++---------- src/madness/chem/test_ccpairfunction.cc | 1 - src/madness/chem/test_low_rank_function.cc | 122 ++++- src/madness/mra/gfit.h | 23 + src/madness/mra/operator.h | 31 +- 6 files changed, 423 insertions(+), 275 deletions(-) diff --git a/src/madness/chem/CCStructures.h b/src/madness/chem/CCStructures.h index 58c5db3a382..3189b9c4c98 100644 --- a/src/madness/chem/CCStructures.h +++ b/src/madness/chem/CCStructures.h @@ -11,7 +11,6 @@ #define CCSTRUCTURES_H_ #include - #include #include #include diff --git a/src/madness/chem/lowrankfunction.h b/src/madness/chem/lowrankfunction.h index a56388d333f..4b43295ef74 100644 --- a/src/madness/chem/lowrankfunction.h +++ b/src/madness/chem/lowrankfunction.h @@ -240,195 +240,204 @@ namespace madness { }; +template +struct particle { + std::array dims; + + /// default constructor + particle() = default; + + /// convenience for particle 1 (the left/first particle) + static particle particle1() { + particle p; + for (int i=0; i - struct randomgaussian { - Vector random_origin; - double exponent; - double radius=2; - randomgaussian(double exponent, double radius) : exponent(exponent), radius(radius) { - Vector ran= this->gaussian_random_distribution(0,radius); - random_origin=2.0*radius*ran-Vector(radius); - } - double operator()(const Vector& r) const { - // return exp(-exponent*inner(r-random_origin,r-random_origin)); - double r2=inner(r-random_origin,r-random_origin); - return exp(-exponent*r2); - } - static Vector gaussian_random_distribution(double mean, double variance) { - std::random_device rd{}; - std::mt19937 gen{rd()}; - std::normal_distribution<> d{mean, variance}; - Vector result; - for (int i = 0; i < NDIM; ++i) result[i]=d(gen); - return result; - } - }; + particle(const int p) : particle(std::vector(1,p)) {} + particle(const int p1, const int p2) : particle(std::vector({p1,p2})) {} + particle(const int p1, const int p2,const int p3) : particle(std::vector({p1,p2,p3})) {} + particle(const std::vector p) { + for (int i=0; i + typename std::enable_if_t> + get_tuple() const {return std::tuple(dims[0]);} - /// f(1,2) = \sum_i g_i(1) h_i(2) - /// a LowRankFunction can be created from a hi-dim function directly, or from a composite like f(1,2) phi(1) psi(2), - /// where f(1,2) is a two-particle function (e.g. a Slater function) - template - class LowRankFunction { - public: + template + typename std::enable_if_t> + get_tuple() const {return std::tuple(dims[0],dims[1]);} - /// what the LowRankFunction will represent - struct LRFunctor { - LRFunctor() = default; + template + typename std::enable_if_t> + get_tuple() const {return std::tuple(dims[0],dims[1],dims[2]);} +}; - Function f; ///< a hi-dim function - std::shared_ptr> f12; ///< a two-particle function - Function a,b; ///< the lo-dim functions - bool has_f() const { - return f.is_initialized(); - } - bool has_f12() const { - return (f12.get()); - } - T operator()(const Vector& r) const { - - if (f12->info.type==OT_SLATER) { - double gamma=f12->info.mu; - Vector first, second; - for (int i=0; i - struct particle { - std::array dims; +/// derive from this class : +/// must implement in inner product +/// may implement an operator()(const coord_nd&) +template +struct LRFunctorBase { - /// default constructor - particle() = default; + virtual ~LRFunctorBase() {}; + virtual std::vector> inner(const std::vector>& rhs, + const particle p1, const particle p2) const =0; - /// convenience for particle 1 (the left/first particle) - static particle particle1() { - particle p; - for (int i=0; i inner(const Function& rhs, const particle p1, const particle p2) const { + return inner(std::vector>({rhs}),p1,p2)[0]; + } + virtual T operator()(const Vector& r) const =0; + virtual typename Tensor::scalar_type l2norm() const { + MADNESS_EXCEPTION("L2 norm not implemented",1); + } - particle(const int p) : particle(std::vector(1,p)) {} - particle(const int p1, const int p2) : particle(std::vector({p1,p2})) {} - particle(const int p1, const int p2,const int p3) : particle(std::vector({p1,p2,p3})) {} - particle(const std::vector p) { - for (int i=0; i> inner(const LRFunctorBase& functor, const std::vector>& rhs, + const particle p1, const particle p2) { + return functor.inner(rhs,p1,p2); + } + friend Function inner(const LRFunctorBase& functor, const Function& rhs, + const particle p1, const particle p2) { + return functor.inner(rhs,p1,p2); + } - /// assuming two particles only - bool is_first() const {return dims[0]==0;} - /// assuming two particles only - bool is_last() const {return dims[0]==(PDIM);} +}; - template - typename std::enable_if_t> - get_tuple() const {return std::tuple(dims[0]);} +template +struct LRFunctorF12 : public LRFunctorBase { + LRFunctorF12() = default; + LRFunctorF12(const std::shared_ptr> f12, const Function& a, + const Function& b) : f12(f12), a(a), b(b) {} - template - typename std::enable_if_t> - get_tuple() const {return std::tuple(dims[0],dims[1]);} + std::shared_ptr> f12; ///< a two-particle function + Function a,b; ///< the lo-dim functions - template - typename std::enable_if_t> - get_tuple() const {return std::tuple(dims[0],dims[1],dims[2]);} - }; + World& world() const {return f12->get_world();} + std::vector> inner(const std::vector>& rhs, + const particle p1, const particle p2) const { + std::vector> result; + // functor is now a(1) b(2) f12 + // result(1) = \int a(1) f(1,2) b(2) rhs(2) d2 + World& world=rhs.front().world(); + auto premultiply= p1.is_first() ? a : b; + auto postmultiply= p1.is_first() ? b : a; - /// inner product: result(1) = \int f(1,2) rhs(2) d2 - - /// @param[in] functor the hidim function - /// @param[in] rhs the rhs - /// @param[in] p1 the variable in f(1,2) to be integrated over - /// @param[in] p2 the variable in rhs to be integrated over (usually all of them) - static std::vector> inner(LRFunctor& functor, const std::vector>& rhs, - const particle p1, const particle p2) { - std::vector> result; - MADNESS_CHECK(functor.has_f() xor functor.has_f12()); - MADNESS_CHECK(p1.is_first() xor p1.is_last()); - MADNESS_CHECK(p2.is_first()); - - if (functor.has_f()) { - for (const auto& r : rhs) result.push_back(madness::inner(functor.f,r,p1.get_tuple(),p2.get_tuple())); - - } else if (functor.has_f12()) { - // functor is now a(1) b(2) f12 - // result(1) = \int a(1) f(1,2) b(2) rhs(2) d2 - World& world=rhs.front().world(); - auto premultiply= p1.is_first() ? functor.a : functor.b; - auto postmultiply= p1.is_first() ? functor.b : functor.a; - - const int nbatch=30; - for (int i=0; i> tmp; - auto begin= rhs.begin()+i; - auto end= (i+nbatch)> tmp; + auto begin= rhs.begin()+i; + auto end= (i+nbatch)::scalar_type l2norm() const { + const Function one=FunctionFactory(world()).f([](const Vector& r){return 1.0;}); + const Function pre=(a.is_initialized()) ? a : one; + const Function post=(b.is_initialized()) ? b : one; + const SeparatedConvolution& f12a=*(f12); + const SeparatedConvolution f12sq= SeparatedConvolution::combine(f12a,f12a); + + // \int f(1,2)^2 d1d2 = \int f(1,2)^2 pre(1)^2 post(2)^2 d1 d2 + typename Tensor::scalar_type term1 =madness::inner(post*post,f12sq(pre*pre)); + return term1; + + } + + T operator()(const Vector& r) const { + + if (f12->info.type==OT_SLATER) { + double gamma=f12->info.mu; + Vector first, second; + for (int i=0; i +struct LRFunctorPure : public LRFunctorBase { + LRFunctorPure() = default; + LRFunctorPure(const Function& f) : f(f) {} + World& world() const {return f.world();} + + Function f; ///< a hi-dim function + + std::vector> inner(const std::vector>& rhs, + const particle p1, const particle p2) const { + std::vector> result; + for (const auto& r : rhs) result.push_back(madness::inner(f,r,p1.get_tuple(),p2.get_tuple())); + return result; + } + + T operator()(const Vector& r) const { + return f(r); + } + + typename Tensor::scalar_type l2norm() const { + double n=f.norm2(); + return n*n; + } +}; + /// LowRankFunction represents a hi-dimensional (NDIM) function as a sum of products of low-dimensional (LDIM) functions + + /// f(1,2) = \sum_i g_i(1) h_i(2) + /// a LowRankFunction can be created from a hi-dim function directly, or from a composite like f(1,2) phi(1) psi(2), + /// where f(1,2) is a two-particle function (e.g. a Slater function) + template + class LowRankFunction { + public: + World& world; double rank_revealing_tol=1.e-8; // rrcd tol std::string orthomethod="canonical"; bool do_print=true; std::vector> g,h; - LRFunctor lrfunctor; - particle p1=particle::particle1(); - particle p2=particle::particle2(); + const particle p1=particle::particle1(); + const particle p2=particle::particle2(); LowRankFunction(World& world) : world(world) {} - /// construct from the hi-dim function f - LowRankFunction(const Function& f) : LowRankFunction(f.world()) { - lrfunctor.f=f; - } + LowRankFunction(std::vector> g, std::vector> h, + double tol, std::string orthomethod) : world(g.front().world()), + rank_revealing_tol(tol), orthomethod(orthomethod), g(g), h(h) {} - /// construct from the hi-dim function f12*a(1)(b(2) - LowRankFunction(const std::shared_ptr> f12, const Function& a, - const Function& b) : LowRankFunction(a.world()) { - lrfunctor.a=a; - lrfunctor.b=b; - lrfunctor.f12=f12; + LowRankFunction(const LowRankFunction& other) : world(other.world), g(copy(world, other.g)), + h(copy(world, other.h)), rank_revealing_tol(other.rank_revealing_tol), orthomethod(other.orthomethod) { } - LowRankFunction(std::vector> g, std::vector> h) - : world(g.front().world()), g(g), h(h) {} - - LowRankFunction(const LowRankFunction& a) : world(a.world), g(copy(world, a.g)), h(copy(world, a.h)) {} // Copy constructor necessary - LowRankFunction& operator=(const LowRankFunction& f) { // Assignment required for storage in vector LowRankFunction ff(f); std::swap(ff.g,g); @@ -486,69 +495,6 @@ namespace madness { return LowRankFunction(g * a, h); } - /// following Halko - - /// ||A - Q Q^T A||< epsilon - /// Y = A Omega && Q = QR(Y) - /// || f(1,2) - \sum_i g_i(1) h_i(2) || < epsilon - /// Y_i(1) = \int f(1,2) Omega_i(2) d2 && g_i(1) = QR(Y_i(1)) && h_i(2) = \int g_i^*(1) f(1,2) d1 - void project(const LowRankFunctionParameters& params) { - timer t1(world); - t1.do_print=do_print; - orthomethod=params.orthomethod(); - rank_revealing_tol=params.tol(); - - // get sampling grid - std::vector> grid=make_grid(params); - auto Y=Yformer(grid,params.rhsfunctiontype()); - t1.tag("Yforming"); - - auto ovlp=matrix_inner(world,Y,Y); // error in symmetric matrix_inner, use non-symmetric form here! - t1.tag("compute ovlp"); - g=truncate(orthonormalize_rrcd(Y,ovlp,rank_revealing_tol)); - t1.tag("rrcd/truncate/thresh"); - auto sz=get_size(world,g); - if (world.rank()==0 and do_print) print("gsize",sz); - check_orthonormality(g); - - if (world.rank()==0 and do_print) { - print("Y.size()",Y.size()); - print("g.size()",g.size()); - } - - h=truncate(inner(lrfunctor,g,p1,p1)); - t1.tag("Y backprojection with truncation"); - - } - - /// apply a rhs (delta or exponential) on grid points to the hi-dim function and form Y = A_ij w_j (in Halko's language) - std::vector> Yformer(const std::vector>& grid, const std::string rhsfunctiontype, - const double exponent=30.0) { - - std::vector> Y; - if (rhsfunctiontype=="exponential") { - std::vector> omega; - double coeff=std::pow(2.0*exponent/constants::pi,0.25*LDIM); - for (const auto& point : grid) { - omega.push_back(FunctionFactory(world) - .functor([&point,&exponent,&coeff](const Vector& r) - { - auto r_rel=r-point; - return coeff*exp(-exponent*madness::inner(r_rel,r_rel)); - })); - } - Y=inner(lrfunctor,omega,p2,p1); - } else { - MADNESS_EXCEPTION("confused rhsfunctiontype",1); - } - auto norms=norm2s(world,Y); - std::vector> Ynormalized; - - for (int i=0; irank_revealing_tol) Ynormalized.push_back(Y[i]); - normalize(world,Ynormalized); - return Ynormalized; - } - long rank() const {return g.size();} /// return the size in GByte @@ -564,7 +510,6 @@ namespace madness { return fapprox; } - /// orthonormalize the argument vector std::vector> orthonormalize(const std::vector>& g) const { @@ -593,18 +538,18 @@ namespace madness { /// optimize the lrf using the lrfunctor /// @param[in] nopt number of iterations (wrt to Alg. 4.3 in Halko) - void optimize(const long nopt=1) { + void optimize(const LRFunctorBase& lrfunctor1, const long nopt=1) { timer t(world); t.do_print=do_print; for (int i=0; i> make_grid(const LowRankFunctionParameters& params) const { - - randomgrid grid(params.volume_element(),params.radius()); - return grid.get_grid(); - } double check_orthonormality(const std::vector>& v) const { Tensor ovlp=matrix_inner(world,v,v); @@ -679,40 +618,22 @@ namespace madness { return ovlp.absmax(); } - double explicit_error() const { - auto fapprox=reconstruct(); - return (lrfunctor.f-fapprox).norm2(); - } - - double randomized_error() const { - return 1.e9; - } - - double error() const { - if (LDIM<3) return explicit_error(); - else return randomized_error(); - } - /// compute the l2 error |functor - \sum_i g_ih_i|_2 /// \int (f(1,2) - gh(1,2))^2 = \int f(1,2)^2 - 2\int f(1,2) gh(1,2) + \int gh(1,2)^2 - double l2error() const { - MADNESS_CHECK(lrfunctor.has_f12()); + /// since we are subtracting large numbers the numerics are sensitive, and NaN may be returned.. + double l2error(const LRFunctorBase& lrfunctor1) const { timer t(world); t.do_print=do_print; - const Function one=FunctionFactory(world).f([](const Vector& r){return 1.0;}); - const Function pre=(lrfunctor.a.is_initialized()) ? lrfunctor.a : one; - const Function post=(lrfunctor.b.is_initialized()) ? lrfunctor.b : one; - const SeparatedConvolution& f12=*lrfunctor.f12; - const SeparatedConvolution f12sq= SeparatedConvolution::combine(f12,f12); - - // \int f(1,2)^2 d1d2 = \int f(1,2)^2 pre(1)^2 post(2)^2 d1 d2 - double term1 =madness::inner(post*post,f12sq(pre*pre)); + + // \int f(1,2)^2 d1d2 + double term1 =lrfunctor1.l2norm(); t.tag("computing term1"); // \int f(1,2) pre(1) post(2) \sum_i g(1) h(2) d1d2 - double term2=madness::inner(pre*g,f12(post*h)); +// double term2=madness::inner(pre*g,f12(post*h)); + double term2=madness::inner(g,inner(lrfunctor1,h,p2,p1)); t.tag("computing term2"); // g functions are orthonormal @@ -722,9 +643,15 @@ namespace madness { // = \sum_{i} \int h_i(2) h_i(2) d2 double zero=check_orthonormality(g); if (zero>1.e-10) print("g is not orthonormal",zero); - double term3=madness::inner(h,h); + double term3a=madness::inner(h,h); + auto tmp1=matrix_inner(world,h,h); + auto tmp2=matrix_inner(world,g,g); + double term3=tmp1.trace(tmp2); + print("term3/a/diff",term3a,term3,term3-term3a); t.tag("computing term3"); + double arg=term1-2.0*term2+term3; + if (arg<0.0) throw std::runtime_error("negative argument in l2error"); double error=sqrt(term1-2.0*term2+term3)/sqrt(term1); if (world.rank()==0 and do_print) { print("term1,2,3, error",term1, term2, term3, " --",error); @@ -774,6 +701,97 @@ namespace madness { return result; } + template + class LowRankFunctionFactory { + public: + + const particle p1=particle::particle1(); + const particle p2=particle::particle2(); + LowRankFunctionParameters parameters; + LowRankFunctionFactory() = default; + LowRankFunctionFactory(const LowRankFunctionParameters param) : parameters(param) {} + LowRankFunctionFactory(const LowRankFunctionFactory& other) = default; + + LowRankFunctionFactory& set_radius(const double radius) { + parameters.set_user_defined_value("radius",radius); + return *this; + } + LowRankFunctionFactory& set_volume_element(const double volume_element) { + parameters.set_user_defined_value("volume_element",volume_element); + return *this; + } + LowRankFunctionFactory& set_rank_revealing_tol(const double rrtol) { + parameters.set_user_defined_value("tol",rrtol); + return *this; + } + LowRankFunctionFactory& set_orthomethod(const std::string orthomethod) { + parameters.set_user_defined_value("orthomethod",orthomethod); + return *this; + } + + LowRankFunction project(const LRFunctorBase& lrfunctor) const { + World& world=lrfunctor.world(); + bool do_print=true; + timer t1(world); + t1.do_print=do_print; + auto orthomethod=parameters.orthomethod(); + auto rank_revealing_tol=parameters.tol(); + + // get sampling grid + randomgrid rgrid(parameters.volume_element(),parameters.radius()); + std::vector> grid=rgrid.get_grid(); + auto Y=Yformer(lrfunctor,grid,parameters.rhsfunctiontype()); + t1.tag("Yforming"); + + auto ovlp=matrix_inner(world,Y,Y); // error in symmetric matrix_inner, use non-symmetric form here! + t1.tag("compute ovlp"); + auto g=truncate(orthonormalize_rrcd(Y,ovlp,rank_revealing_tol)); + t1.tag("rrcd/truncate/thresh"); + auto sz=get_size(world,g); + if (world.rank()==0 and do_print) print("gsize",sz); +// check_orthonormality(g); + + if (world.rank()==0 and do_print) { + print("Y.size()",Y.size()); + print("g.size()",g.size()); + } + + auto h=truncate(inner(lrfunctor,g,p1,p1)); + t1.tag("Y backprojection with truncation"); + return LowRankFunction(g,h,parameters.tol(),parameters.orthomethod()); + + } + + /// apply a rhs (delta or exponential) on grid points to the hi-dim function and form Y = A_ij w_j (in Halko's language) + std::vector> Yformer(const LRFunctorBase& lrfunctor1, const std::vector>& grid, + const std::string rhsfunctiontype, const double exponent=30.0) const { + + World& world=lrfunctor1.world(); + std::vector> Y; + if (rhsfunctiontype=="exponential") { + std::vector> omega; + double coeff=std::pow(2.0*exponent/constants::pi,0.25*LDIM); + for (const auto& point : grid) { + omega.push_back(FunctionFactory(world) + .functor([&point,&exponent,&coeff](const Vector& r) + { + auto r_rel=r-point; + return coeff*exp(-exponent*madness::inner(r_rel,r_rel)); + })); + } + Y=inner(lrfunctor1,omega,p2,p1); + } else { + MADNESS_EXCEPTION("confused rhsfunctiontype",1); + } + auto norms=norm2s(world,Y); + std::vector> Ynormalized; + + for (int i=0; iparameters.tol()) Ynormalized.push_back(Y[i]); + normalize(world,Ynormalized); + return Ynormalized; + } + + }; } // namespace madness diff --git a/src/madness/chem/test_ccpairfunction.cc b/src/madness/chem/test_ccpairfunction.cc index 6fcd5d48017..e035e5803b0 100644 --- a/src/madness/chem/test_ccpairfunction.cc +++ b/src/madness/chem/test_ccpairfunction.cc @@ -10,7 +10,6 @@ #include #include #include -#include #include diff --git a/src/madness/chem/test_low_rank_function.cc b/src/madness/chem/test_low_rank_function.cc index 205f5c3cd41..05a7032bb18 100644 --- a/src/madness/chem/test_low_rank_function.cc +++ b/src/madness/chem/test_low_rank_function.cc @@ -106,12 +106,12 @@ int test_lowrank_function(World& world, LowRankFunctionParameters& parameters) { print("reference.norm2() = int f12 phi2 d2",n2); output(0.0,0.0,0.0,0.0,0.0,0.0); - LowRankFunction lrf(f12, copy(phi1), copy(phi2)); - plot_plane<6>(world,lrf.lrfunctor,"plot_original."+id,PlotParameters(world).set_plane({"x1","x4"})); + LRFunctorF12 lrfunctor(f12,phi1,phi1); double cpu0=cpu_time(); - lrf.project(parameters); + auto lrf=LowRankFunctionFactory(parameters).project(lrfunctor); +// plot_plane<6>(world,lrfunctor,"plot_original."+id,PlotParameters(world).set_plane({"x1","x4"})); double cpu1=cpu_time(); - double error1=lrf.l2error(); + double error1=lrf.l2error(lrfunctor); print("l2error projection",error1); // plot_plane<6>(world,lrf,"plot_lrf_projection."+id,PlotParameters(world).set_plane({"x1","x4"})); @@ -133,8 +133,8 @@ int test_lowrank_function(World& world, LowRankFunctionParameters& parameters) { of1.close(); double cpu2=cpu_time(); - lrf.optimize(parameters.optimize()); - double error2=lrf.l2error(); + lrf.optimize(lrfunctor,parameters.optimize()); + double error2=lrf.l2error(lrfunctor); print("l2error optimization",error2); double cpu3=cpu_time(); result=compute_result(lrf); @@ -236,17 +236,19 @@ int test_Kcommutator(World& world, LowRankFunctionParameters& parameters) { // = \sum_kr k(1) j(2) \int g(1,1') g_r(1') h_r(2) k(1') d1' // = \sum_r j(2) h_r(2) \sum_k k(1) \int g(1,1') g_r(1') k(1') d1' real_function_3d one = real_factory_3d(world).f([](const coord_3d& r) { return 1.0; }); - LowRankFunction fi_one(f12ptr, copy(phi), copy(one)); - fi_one.project(parameters); - double l2error=fi_one.l2error(); + LRFunctorF12 lrfunctor(f12ptr,phi,one); +// LowRankFunction fi_one(f12ptr, copy(phi), copy(one)); + auto fi_one=LowRankFunctionFactory(parameters).project(lrfunctor); +// fi_one.project(parameters); + double l2error=fi_one.l2error(lrfunctor); print("left_project_l2error",l2error); j["left_project_time"]=t.tag("left_project_time"); json2file(j,jsonfilename); compute_error("left_project",fi_one); - fi_one.optimize(); - l2error=fi_one.l2error(); + fi_one.optimize(lrfunctor); + l2error=fi_one.l2error(lrfunctor); print("left_optimize_l2error",l2error); j["left_optimize_time"]=t.tag("left_optimize_time"); json2file(j,jsonfilename); @@ -303,6 +305,81 @@ int test_Kcommutator(World& world, LowRankFunctionParameters& parameters) { } +template +int test_full_rank_functor(World& world, LowRankFunctionParameters& parameters) { + + test_output t1("test_full_rank_functor"); +// t1.set_cout_to_terminal(); + print_header2("entering test_full_rank_functor"); + constexpr int NDIM=2*LDIM; + FunctionDefaults::set_thresh(1.e-6); + FunctionDefaults::set_thresh(1.e-6); + double tol=1.e-3; + double gaussexponent=2.0; + + const particle p1=particle::particle1(); + const particle p2=particle::particle2(); + + LRFunctorPure functorpure; + Function gauss=FunctionFactory(world) + .functor([&gaussexponent](const Vector& r){ + Vector a,b; + for (int i=0; i functorf12; + Function b=FunctionFactory(world).functor([](const Vector& r){return exp(-inner(r,r));}); + functorf12.f12.reset(GaussOperatorPtr(world,gaussexponent)); + + auto builder= LowRankFunctionFactory(parameters).set_radius(8) + .set_volume_element(0.1).set_rank_revealing_tol(1.e-10).set_orthomethod("canonical"); + + auto lrfunction1=builder.project(functorf12); + t1.checkpoint(true,"construction f12 functor"); + auto lrfunction2=builder.project(functorpure); + t1.checkpoint(true,"construction full rank functor"); + lrfunction1.optimize(functorf12); + t1.checkpoint(true,"optimization f12 functor"); + lrfunction2.optimize(functorpure); + t1.checkpoint(true,"optimization full rank functor"); + + + try { + double error1=lrfunction1.l2error(functorf12); + t1.checkpoint(error1 int test_grids(World& world, LowRankFunctionParameters& parameters) { randomgrid g(parameters.volume_element(),parameters.radius()); @@ -321,13 +398,15 @@ int test_construction_optimization(World& world, LowRankFunctionParameters param auto slater=std::shared_ptr >(new SeparatedConvolution(world,info)); Function one=FunctionFactory(world).functor([](const Vector& r){return exp(-0.2*inner(r,r));}); - LowRankFunction lrf(slater,one,one); - lrf.project(parameters); - double error=lrf.l2error(); + LRFunctorF12 lrfunctor(slater,one,one); + LowRankFunctionFactory builder(parameters); + auto lrf=builder.project(lrfunctor); + + double error=lrf.l2error(lrfunctor); t1.checkpoint(error<2.e-2,"l2 error in projection "+std::to_string(error)); print("l2 error project ",error); - lrf.optimize(); - error=lrf.l2error(); + lrf.optimize(lrfunctor); + error=lrf.l2error(lrfunctor); print("l2 error optimize",error); t1.checkpoint(error<1.e-2,"l2 error in optimization "+std::to_string(error)); return t1.end(); @@ -376,11 +455,12 @@ int main(int argc, char **argv) { try { - isuccess+=test_grids<1>(world,parameters); - isuccess+=test_grids<2>(world,parameters); - isuccess+=test_grids<3>(world,parameters); - isuccess+=test_construction_optimization<1>(world,parameters); - isuccess+=test_construction_optimization<2>(world,parameters); +// isuccess+=test_grids<1>(world,parameters); +// isuccess+=test_grids<2>(world,parameters); +// isuccess+=test_grids<3>(world,parameters); + isuccess+= test_full_rank_functor<1>(world, parameters); +// isuccess+=test_construction_optimization<1>(world,parameters); +// isuccess+=test_construction_optimization<2>(world,parameters); // isuccess+=test_arithmetic<1>(world,parameters); // isuccess+=test_arithmetic<2>(world,parameters); diff --git a/src/madness/mra/gfit.h b/src/madness/mra/gfit.h index 72427deb12e..33a89ba81f1 100644 --- a/src/madness/mra/gfit.h +++ b/src/madness/mra/gfit.h @@ -121,6 +121,29 @@ class GFit { return fit; } + /// return a (trivial) fit for a single Gauss function + + /// the Gauss function is defined by + /// f(r) = exp(-\gamma r^2) + /// @param[in] gamma the exponent of the Gauss function + /// @param[in] lo the smallest length scale that needs to be precisely represented + /// @param[in] hi the largest length scale that needs to be precisely represented + /// @param[in] eps the precision threshold + /// @parma[in] prnt print level + static GFit GaussFit(double gamma, double lo, double hi, double eps, bool prnt=false) { + GFit fit; + fit.coeffs_=Tensor(1); + fit.exponents_=Tensor(1); + fit.coeffs_=1.0; + fit.exponents_=gamma; + if (prnt) { + print("Gauss fit"); + auto exact = [&gamma](const double r) -> double { return exp(-gamma * r*r); }; + fit.print_accuracy(exact, lo, hi); + } + return fit; + } + /// return a fit for the F12 correlation factor /// the Slater function is defined by diff --git a/src/madness/mra/operator.h b/src/madness/mra/operator.h index 0ff5fc9eb19..ce0a0cfe701 100644 --- a/src/madness/mra/operator.h +++ b/src/madness/mra/operator.h @@ -131,6 +131,7 @@ namespace madness { OT_ONE, /// indicates the identity OT_G12, /// 1/r OT_SLATER, /// exp(-r) + OT_GAUSS, /// exp(-r2) OT_F12, /// 1-exp(-r) OT_FG12, /// (1-exp(-r))/r OT_F212, /// (1-exp(-r))^2 @@ -230,6 +231,7 @@ namespace madness { GFit fit; if (type==OT_G12) {fit=GFit::CoulombFit(lo,hi,eps,false); } else if (type==OT_SLATER) {fit=GFit::SlaterFit(mu,lo,hi,eps,false); + } else if (type==OT_GAUSS) {fit=GFit::GaussFit(mu,lo,hi,eps,false); } else if (type==OT_F12) {fit=GFit::F12Fit(mu,lo,hi,eps,false); } else if (type==OT_FG12) {fit=GFit::FGFit(mu,lo,hi,eps,false); } else if (type==OT_F212) {fit=GFit::F12sqFit(mu,lo,hi,eps,false); @@ -1657,6 +1659,10 @@ namespace madness { OperatorInfo info=left.info; if ((left.info.type==OT_F12) and (right.info.type==OT_G12)) { info.type=OT_FG12; + } else if ((left.info.type==OT_GAUSS) and (right.info.type==OT_GAUSS)) { + info=right.info; + info.type=OT_GAUSS; + info.mu=2.0*right.info.mu; } else if ((left.info.type==OT_SLATER) and (right.info.type==OT_SLATER)) { info=right.info; info.type=OT_SLATER; @@ -1900,7 +1906,30 @@ namespace madness { return SeparatedConvolution(world,OperatorInfo(mu,lo,eps,OT_SLATER),bc,k); } - /// Factory function generating separated kernel for convolution with exp(-mu*r) in 3D + /// Factory function generating separated kernel for convolution with exp(-mu*r*r) + + /// lo and eps are not used here + template + static inline SeparatedConvolution GaussOperator(World& world, + double mu, double lo=0.0, double eps=0.0, + const BoundaryConditions& bc=FunctionDefaults::get_bc(), + int k=FunctionDefaults::get_k()) { + return SeparatedConvolution(world,OperatorInfo(mu,lo,eps,OT_GAUSS),bc,k); + } + + /// Factory function generating separated kernel for convolution with exp(-mu*r*r) in 3D + + /// lo and eps are not used here + template + static inline SeparatedConvolution* GaussOperatorPtr(World& world, + double mu, double lo=0.0, double eps=0.0, + const BoundaryConditions& bc = FunctionDefaults::get_bc(), + int k = FunctionDefaults::get_k()) { + return new SeparatedConvolution(world,OperatorInfo(mu,lo,eps,OT_GAUSS),bc,k); + } + + +/// Factory function generating separated kernel for convolution with exp(-mu*r) in 3D /// Note that the 1/(2mu) factor of SlaterF12Operator is not included, this is just the exponential function static inline SeparatedConvolution* SlaterOperatorPtr(World& world, double mu, double lo, double eps, From 8784dee09fa0d5b60cfe210d0965ec3c278ac401 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Wed, 27 Sep 2023 11:10:39 +0200 Subject: [PATCH 055/109] fixing compress for functions with only the root node --- src/madness/mra/mraimpl.h | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/madness/mra/mraimpl.h b/src/madness/mra/mraimpl.h index f6093d5f2fe..aa6ecaab248 100644 --- a/src/madness/mra/mraimpl.h +++ b/src/madness/mra/mraimpl.h @@ -3216,10 +3216,21 @@ template return woT::task(world.rank(),&implT::compress_op, key, v, nonstandard1); } else { - Future result(node.coeff()); - if (!keepleaves) node.clear_coeff(); - node.set_dnorm(0.0); - return result; + // special case: tree has only root node: keep sum coeffs and make zero diff coeffs + if (key.level()==0) { +// if (0) { + Future result(node.coeff()); + coeffT sdcoeff(cdata.v2k,this->get_tensor_type()); + sdcoeff(cdata.s0)+=node.coeff(); + node.coeff()=sdcoeff; + node.set_dnorm(0.0); + return result; + } else { + Future result(node.coeff()); + if (!keepleaves) node.clear_coeff(); + node.set_dnorm(0.0); + return result; + } } } From f436cb86da7c84848aa9e721b95aa9f328cb03ff Mon Sep 17 00:00:00 2001 From: fbischoff Date: Wed, 27 Sep 2023 11:10:52 +0200 Subject: [PATCH 056/109] more testing --- src/madness/chem/lowrankfunction.h | 215 ++++++++++++++++----- src/madness/chem/test_low_rank_function.cc | 124 +++++++++++- src/madness/mra/vmra.h | 15 +- 3 files changed, 301 insertions(+), 53 deletions(-) diff --git a/src/madness/chem/lowrankfunction.h b/src/madness/chem/lowrankfunction.h index 4b43295ef74..96c24318faa 100644 --- a/src/madness/chem/lowrankfunction.h +++ b/src/madness/chem/lowrankfunction.h @@ -260,6 +260,12 @@ struct particle { return p; } + /// return the other particle + particle complement() const { + MADNESS_CHECK(is_first() or is_last()); + if (is_first()) return particle2(); + return particle1(); + } particle(const int p) : particle(std::vector(1,p)) {} particle(const int p1, const int p2) : particle(std::vector({p1,p2})) {} @@ -286,6 +292,14 @@ struct particle { get_tuple() const {return std::tuple(dims[0],dims[1],dims[2]);} }; +template +std::ostream& operator<<(std::ostream& os, const particle& p) { + os << "("; + for (auto i=0; i& r) const =0; - virtual typename Tensor::scalar_type l2norm() const { + virtual typename Tensor::scalar_type norm2() const { MADNESS_EXCEPTION("L2 norm not implemented",1); } @@ -354,7 +368,7 @@ struct LRFunctorF12 : public LRFunctorBase { return result; } - typename Tensor::scalar_type l2norm() const { + typename Tensor::scalar_type norm2() const { const Function one=FunctionFactory(world()).f([](const Vector& r){return 1.0;}); const Function pre=(a.is_initialized()) ? a : one; const Function post=(b.is_initialized()) ? b : one; @@ -403,7 +417,7 @@ struct LRFunctorPure : public LRFunctorBase { return f(r); } - typename Tensor::scalar_type l2norm() const { + typename Tensor::scalar_type norm2() const { double n=f.norm2(); return n*n; @@ -432,10 +446,19 @@ struct LRFunctorPure : public LRFunctorBase { LowRankFunction(std::vector> g, std::vector> h, double tol, std::string orthomethod) : world(g.front().world()), - rank_revealing_tol(tol), orthomethod(orthomethod), g(g), h(h) {} + rank_revealing_tol(tol), orthomethod(orthomethod), g(g), h(h) { + + } - LowRankFunction(const LowRankFunction& other) : world(other.world), g(copy(world, other.g)), - h(copy(world, other.h)), rank_revealing_tol(other.rank_revealing_tol), orthomethod(other.orthomethod) { + /// shallow copy ctor + LowRankFunction(const LowRankFunction& other) : world(other.world), + g(other.g), h(other.h), + rank_revealing_tol(other.rank_revealing_tol), orthomethod(other.orthomethod) { + } + + /// deep copy + friend LowRankFunction copy(const LowRankFunction& other) { + return LowRankFunction(madness::copy(other.g),madness::copy(other.h),other.rank_revealing_tol,other.orthomethod); } LowRankFunction& operator=(const LowRankFunction& f) { // Assignment required for storage in vector @@ -463,38 +486,72 @@ struct LRFunctorPure : public LRFunctorBase { /// addition LowRankFunction operator+(const LowRankFunction& b) const { - return LowRankFunction(g + b.g, h + b.h); + LowRankFunction result=copy(*this); + result+=b; + return result; } /// subtraction LowRankFunction operator-(const LowRankFunction& b) const { - return LowRankFunction(g - b.g, h - b.h); + LowRankFunction result=copy(*this); + result-=b; + return result; } /// in-place addition LowRankFunction& operator+=(const LowRankFunction& b) { - g+=b.g; - h+=b.h; + + g=append(g,copy(b.g)); + h=append(h,copy(b.h)); return *this; } /// in-place subtraction LowRankFunction& operator-=(const LowRankFunction& b) { - g-=b.g; - h-=b.h; + g=append(g,-1.0*b.g); // operator* implies deep copy of b.g + h=append(h,copy(b.h)); return *this; } /// scale by a scalar template LowRankFunction operator*(const Q a) const { - return LowRankFunction,NDIM>(g * a, Q(h)); + return LowRankFunction,NDIM>(g * a, Q(h),rank_revealing_tol,orthomethod); } - /// in-place scale by a scalar (no type conversion) + /// out-of-place scale by a scalar (no type conversion) LowRankFunction operator*(const T a) const { - return LowRankFunction(g * a, h); + return LowRankFunction(g * a, h,rank_revealing_tol,orthomethod); + } + + /// multiplication with a scalar + friend LowRankFunction operator*(const T a, const LowRankFunction& other) { + return other*a; } + /// in-place scale by a scalar (no type conversion) + LowRankFunction& operator*=(const T a) { + g=g*a; + return *this; + } + + /// l2 norm + typename TensorTypeData::scalar_type norm2() const { + auto tmp1=matrix_inner(world,h,h); + auto gg=copy(g); + compress(world,gg); + auto tmp2=matrix_inner(world,gg,g); + return tmp1.trace(tmp2); + } + + std::vector> get_functions(const particle& p) const { + MADNESS_CHECK(p.is_first() or p.is_last()); + if (p.is_first()) return g; + return h; + } + + std::vector> get_g() const {return g;} + std::vector> get_h() const {return h;} + long rank() const {return g.size();} /// return the size in GByte @@ -516,10 +573,7 @@ struct LRFunctorPure : public LRFunctorBase { double tol=rank_revealing_tol; std::vector> g2; auto ovlp=matrix_inner(world,g,g); - if (orthomethod=="symmetric") { - print("orthonormalizing with method/tol",orthomethod,tol); - g2=orthonormalize_symmetric(g,ovlp); - } else if (orthomethod=="canonical") { + if (orthomethod=="canonical") { tol*=0.01; print("orthonormalizing with method/tol",orthomethod,tol); g2=orthonormalize_canonical(g,ovlp,tol); @@ -628,7 +682,7 @@ struct LRFunctorPure : public LRFunctorBase { t.do_print=do_print; // \int f(1,2)^2 d1d2 - double term1 =lrfunctor1.l2norm(); + double term1 = lrfunctor1.norm2(); t.tag("computing term1"); // \int f(1,2) pre(1) post(2) \sum_i g(1) h(2) d1d2 @@ -671,36 +725,109 @@ struct LRFunctorPure : public LRFunctorBase { - template - LowRankFunction inner(const Function& lhs, const LowRankFunction& rhs, const std::tuple v1, const std::tuple v2) { - World& world=rhs.world; - // int lhs(1,2) rhs(2,3) d2 = \sum \int lhs(1,2) g_i(2) h_i(3) d2 - // = \sum \int lhs(1,2) g_i(2) d2 h_i(3) - LowRankFunction result(world); - result.h=rhs.h; - decltype(rhs.g) g; - for (int i=0; i - LowRankFunction inner(const LowRankFunction& f, const Function& g, const std::tuple v1, const std::tuple v2) { - World& world=f.world; +// template +// LowRankFunction inner(const Function& lhs, const LowRankFunction& rhs, +// const std::tuple v1, const std::tuple v2) { +// World& world=rhs.world; +// // int lhs(1,2) rhs(2,3) d2 = \sum \int lhs(1,2) g_i(2) h_i(3) d2 +// // = \sum \int lhs(1,2) g_i(2) d2 h_i(3) +// LowRankFunction result(world); +// result.h=rhs.h; +// decltype(rhs.g) g; +// for (int i=0; i + LowRankFunction inner(const LowRankFunction& f1, const Function& f2, + const particle p1, const particle p2) { + World& world=f1.world; + static_assert(2*PDIM==NDIM); // int f(1,2) k(2,3) d2 = \sum \int g_i(1) h_i(2) k(2,3) d2 // = \sum g_i(1) \int h_i(2) k(2,3) d2 - LowRankFunction result(world); - result.g=f.g; - decltype(f.h) h; - for (int i=0; i result(world); + if (p1.is_last()) { // integrate over 2: result(1,3) = lrf(1,2) f(2,3) + result.g = f1.g; + decltype(f1.h) h; + for (int i=0; i::particle1().get_tuple()),p2.get_tuple())); + result.h=copy(h); + } else if (p1.is_first()) { // integrate over 1: result(2,3) = lrf(1,2) f(1,3) + result.g = f1.h; // correct! second variable of f1 becomes first variable of result + decltype(f1.g) h; + for (int i=0; i::particle1().get_tuple(),p2.get_tuple())); + result.h=copy(h); } - result.h=h; return result; } + /// lrf(1,3) = inner(lrf(1,2), lrf(2,3)) + + /// @param[in] f1 the first function + /// @param[in] f2 the second function + /// @param[in] p1 the integration variable of the first function + /// @param[in] p2 the integration variable of the second function + template + LowRankFunction inner(const LowRankFunction& f1, const LowRankFunction& f2, + const particle p1, const particle p2) { + World& world=f1.world; + static_assert(2*PDIM==NDIM); + + // inner(lrf(1,2) ,lrf(2,3) ) = \sum_ij g1_i(1) h2_j(3) + auto matrix=matrix_inner(world,f2.get_functions(p2),f1.get_functions(p1)); + auto htilde=transform(world,f2.get_functions(p2.complement()),matrix); + print("p1 complement",p1.complement()); + auto gg=copy(world,f1.get_functions(p1.complement())); + return LowRankFunction(gg,htilde,f1.rank_revealing_tol,f1.orthomethod); + } + + /// f(1) = inner(lrf(1,2), f(2)) + + /// @param[in] f1 the first function + /// @param[in] vf vector of the second functions + /// @param[in] p1 the integration variable of the first function + /// @param[in] p2 the integration variable of the second function, dummy variable for consistent notation + template + std::vector> inner(const LowRankFunction& f1, const std::vector>& vf, + const particle p1, const particle p2=particle::particle1()) { + World& world=f1.world; + static_assert(2*PDIM==NDIM); + MADNESS_CHECK(p2.is_first()); + + // inner(lrf(1,2), f_k(2) ) = \sum_i g1_i(1) + auto matrix=matrix_inner(world,vf,f1.get_functions(p1)); + return transform(world,f1.get_functions(p1.complement()),matrix); + } + + /// f(1) = inner(lrf(1,2), f(2)) + + /// @param[in] f1 the first function + /// @param[in] vf the second function + /// @param[in] p1 the integration variable of the first function + /// @param[in] p2 the integration variable of the second function, dummy variable for consistent notation + template + Function inner(const LowRankFunction& f1, const Function& f2, + const particle p1, const particle p2=particle::particle1()) { + return inner(f1,std::vector>({f2}),p1,p2); + } + template class LowRankFunctionFactory { public: diff --git a/src/madness/chem/test_low_rank_function.cc b/src/madness/chem/test_low_rank_function.cc index 05a7032bb18..c09ebb822d1 100644 --- a/src/madness/chem/test_low_rank_function.cc +++ b/src/madness/chem/test_low_rank_function.cc @@ -380,12 +380,107 @@ int test_full_rank_functor(World& world, LowRankFunctionParameters& parameters) return t1.end(); } + template -int test_grids(World& world, LowRankFunctionParameters& parameters) { - randomgrid g(parameters.volume_element(),parameters.radius()); - g.get_grid(); +int test_arithmetic(World& world, LowRankFunctionParameters parameters) { + constexpr std::size_t NDIM = 2 * LDIM; + test_output t1("LowRankFunction::arithmetic in dimension " + std::to_string(NDIM)); + t1.set_cout_to_terminal(); + double thresh=FunctionDefaults::get_thresh(); + Function phi=FunctionFactory(world) + .functor([](const Vector& r){return exp(-4.0*inner(r,r));}); - return 0; + LRFunctorF12 functor1; + functor1.f12.reset(GaussOperatorPtr(world,1.0)); + functor1.a=phi; + LRFunctorF12 functor2; + functor2.f12.reset(GaussOperatorPtr(world,2.0)); + functor2.a=phi; + + auto builder= LowRankFunctionFactory(parameters).set_radius(8) + .set_volume_element(0.1).set_rank_revealing_tol(1.e-10).set_orthomethod("canonical"); + auto lrf1=builder.project(functor1); + auto lrf2=builder.project(functor2); + + Vector r; + r.fill(0.2); + print("lrf1(r)",lrf1(r)); + + // addition/subtraction + { + auto l1=lrf1+lrf1; + t1.checkpoint(fabs(l1(r)-2.0*lrf1(r))> arg(3); + for (int i=0; i<3; ++i) arg[i]=FunctionFactory(world) + .functor([&i](const Vector& r) + {return exp(-r.normf());}); + auto p1=particle::particle1(); + auto p2=particle::particle2(); + + auto fullrank1=lrf1.reconstruct(); + auto fullrank2=lrf2.reconstruct(); + t1.checkpoint(true,"prep inner"); + + for (auto p11 : {p1,p2}) { + for (auto p22 : {p1,p2}) { + auto lhs0=inner(fullrank1,fullrank2,p11.get_tuple(),p22.get_tuple()); + auto lhs1=inner(lrf1,fullrank2,p11,p22); + auto lhs2=inner(lrf1,lrf2,p11,p22); + double l0=lhs0.norm2(); + double l1=lhs1.norm2(); + double l2=lhs2.norm2(); + + print("inner(lrf,full,",p11,p22,"): ",fullrank1.norm2(),lhs1.norm2(),lhs2.norm2()); + + } + } + +// auto lhs1=inner(functor1,arg,p2,p1); +// auto lhs2=inner(lrf1,arg,p2,p1); +// double error=norm2(world,lhs1-lhs2); + } + + // scalar multiplication + { + auto l1=2.0*lrf1; + t1.checkpoint(fabs(l1(r)-2.0*lrf1(r)) @@ -401,14 +496,28 @@ int test_construction_optimization(World& world, LowRankFunctionParameters param LRFunctorF12 lrfunctor(slater,one,one); LowRankFunctionFactory builder(parameters); auto lrf=builder.project(lrfunctor); + t1.checkpoint(lrf.rank()>0,"construction"); double error=lrf.l2error(lrfunctor); - t1.checkpoint(error<2.e-2,"l2 error in projection "+std::to_string(error)); print("l2 error project ",error); + t1.checkpoint(error<2.e-2,"l2 error in projection "+std::to_string(error)); + + auto lrf2(lrf); + error=lrf2.l2error(lrfunctor); + print("l2 error copy ctor ",error); + MADNESS_CHECK(lrf.rank()==lrf2.rank()); + MADNESS_CHECK(&(lrf.g[0]) != &(lrf2.g[0])); // deep copy + t1.checkpoint(error<2.e-2,"l2 error in copy ctor "+std::to_string(error)); + lrf.optimize(lrfunctor); error=lrf.l2error(lrfunctor); print("l2 error optimize",error); t1.checkpoint(error<1.e-2,"l2 error in optimization "+std::to_string(error)); + + lrf.reorthonormalize(); + error=lrf.l2error(lrfunctor); + print("l2 error reorthonormalize",error); + t1.checkpoint(error<1.e-2,"l2 error in reorthonormalization "+std::to_string(error)); return t1.end(); } @@ -442,7 +551,6 @@ int main(int argc, char **argv) { FunctionDefaults<5>::set_cubic_cell(-10.,10.); FunctionDefaults<6>::set_cubic_cell(-10.,10.); - FunctionDefaults<2>::set_tensor_type(TT_FULL); print("numerical parameters: k, eps(3D), eps(6D)", FunctionDefaults<3>::get_k(), FunctionDefaults<3>::get_thresh(), FunctionDefaults<6>::get_thresh()); @@ -458,10 +566,10 @@ int main(int argc, char **argv) { // isuccess+=test_grids<1>(world,parameters); // isuccess+=test_grids<2>(world,parameters); // isuccess+=test_grids<3>(world,parameters); - isuccess+= test_full_rank_functor<1>(world, parameters); +// isuccess+=test_full_rank_functor<1>(world, parameters); // isuccess+=test_construction_optimization<1>(world,parameters); // isuccess+=test_construction_optimization<2>(world,parameters); -// isuccess+=test_arithmetic<1>(world,parameters); + isuccess+=test_arithmetic<1>(world,parameters); // isuccess+=test_arithmetic<2>(world,parameters); // isuccess+=test_lowrank_function(world,parameters); diff --git a/src/madness/mra/vmra.h b/src/madness/mra/vmra.h index 9fa1515e198..b24819fd300 100644 --- a/src/madness/mra/vmra.h +++ b/src/madness/mra/vmra.h @@ -813,7 +813,9 @@ namespace madness { { world.gop.fence(); compress(world, f); - if ((void*)(&f) != (void*)(&g)) compress(world, g); +// if ((void*)(&f) != (void*)(&g)) compress(world, g); + compress(world, g); + std::vector*> left(f.size()); std::vector*> right(g.size()); @@ -1165,6 +1167,17 @@ namespace madness { return r; } + + /// Returns a deep copy of a vector of functions + template + std::vector< Function > + copy(const std::vector< Function >& v, bool fence=true) { + PROFILE_BLOCK(Vcopy); + std::vector< Function > r(v.size()); + if (v.size()>0) r=copy(v.front().world(),v,fence); + return r; + } + /// Returns a vector of `n` deep copies of a function template std::vector< Function > From 3809700ebe8ef11a51a3395c4bbe64b0deeec546 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Wed, 27 Sep 2023 15:56:29 +0200 Subject: [PATCH 057/109] more testing --- src/madness/chem/lowrankfunction.h | 65 +++++--- src/madness/chem/test_low_rank_function.cc | 175 +++++++++++++++++---- src/madness/mra/operator.h | 12 +- 3 files changed, 199 insertions(+), 53 deletions(-) diff --git a/src/madness/chem/lowrankfunction.h b/src/madness/chem/lowrankfunction.h index 96c24318faa..5707f0d7688 100644 --- a/src/madness/chem/lowrankfunction.h +++ b/src/madness/chem/lowrankfunction.h @@ -274,6 +274,12 @@ struct particle { for (int i=0; i { // \int f(1,2)^2 d1d2 = \int f(1,2)^2 pre(1)^2 post(2)^2 d1 d2 typename Tensor::scalar_type term1 =madness::inner(post*post,f12sq(pre*pre)); - return term1; + return sqrt(term1); } T operator()(const Vector& r) const { - if (f12->info.type==OT_SLATER) { - double gamma=f12->info.mu; + auto split = [](const Vector& r) { Vector first, second; for (int i=0; iinfo.mu; + auto [first,second]=split(r); + + double result=1.0; + if (a.is_initialized()) result*=a(first); + if (b.is_initialized()) result*=b(first); + if (f12->info.type==OT_SLATER) result*=exp(-gamma*(first-second).normf()); + else if (f12->info.type==OT_GAUSS) result*=exp(-gamma* madness::inner(first-second,first-second)); + else return 1.0; + return result; + } }; @@ -418,9 +432,7 @@ struct LRFunctorPure : public LRFunctorBase { } typename Tensor::scalar_type norm2() const { - double n=f.norm2(); - return n*n; - + return f.norm2(); } }; @@ -537,10 +549,8 @@ struct LRFunctorPure : public LRFunctorBase { /// l2 norm typename TensorTypeData::scalar_type norm2() const { auto tmp1=matrix_inner(world,h,h); - auto gg=copy(g); - compress(world,gg); - auto tmp2=matrix_inner(world,gg,g); - return tmp1.trace(tmp2); + auto tmp2=matrix_inner(world,g,g); + return sqrt(tmp1.trace(tmp2)); } std::vector> get_functions(const particle& p) const { @@ -750,7 +760,21 @@ struct LRFunctorPure : public LRFunctorBase { * d = inner(lrf(1,2), lrf(1,2)) */ - /// lrf(1,3) = inner(lrf(1,2), lrf(2,3)) + /// lrf(1,3) = inner(full(1,2), lrf(2,3)) + + /// @param[in] f1 the first function + /// @param[in] f2 the second function + /// @param[in] p1 the integration variable of the first function + /// @param[in] p2 the integration variable of the second function + template + LowRankFunction inner(const Function& f1, const LowRankFunction& f2, + const particle p1, const particle p2) { + auto result=inner(f2,f1,p2,p1); + std::swap(result.g,result.h); + return result; + } + + /// lrf(1,3) = inner(lrf(1,2), full(2,3)) /// @param[in] f1 the first function /// @param[in] f2 the second function @@ -793,7 +817,6 @@ struct LRFunctorPure : public LRFunctorBase { // inner(lrf(1,2) ,lrf(2,3) ) = \sum_ij g1_i(1) h2_j(3) auto matrix=matrix_inner(world,f2.get_functions(p2),f1.get_functions(p1)); auto htilde=transform(world,f2.get_functions(p2.complement()),matrix); - print("p1 complement",p1.complement()); auto gg=copy(world,f1.get_functions(p1.complement())); return LowRankFunction(gg,htilde,f1.rank_revealing_tol,f1.orthomethod); } @@ -805,14 +828,14 @@ struct LRFunctorPure : public LRFunctorBase { /// @param[in] p1 the integration variable of the first function /// @param[in] p2 the integration variable of the second function, dummy variable for consistent notation template - std::vector> inner(const LowRankFunction& f1, const std::vector>& vf, + std::vector> inner(const LowRankFunction& f1, const std::vector>& vf, const particle p1, const particle p2=particle::particle1()) { World& world=f1.world; static_assert(2*PDIM==NDIM); MADNESS_CHECK(p2.is_first()); // inner(lrf(1,2), f_k(2) ) = \sum_i g1_i(1) - auto matrix=matrix_inner(world,vf,f1.get_functions(p1)); + auto matrix=matrix_inner(world,f1.get_functions(p1),vf); return transform(world,f1.get_functions(p1.complement()),matrix); } @@ -825,12 +848,12 @@ struct LRFunctorPure : public LRFunctorBase { template Function inner(const LowRankFunction& f1, const Function& f2, const particle p1, const particle p2=particle::particle1()) { - return inner(f1,std::vector>({f2}),p1,p2); + return inner(f1,std::vector>({f2}),p1,p2)[0]; } template class LowRankFunctionFactory { - public: + public: const particle p1=particle::particle1(); const particle p2=particle::particle2(); diff --git a/src/madness/chem/test_low_rank_function.cc b/src/madness/chem/test_low_rank_function.cc index c09ebb822d1..1ebbd506383 100644 --- a/src/madness/chem/test_low_rank_function.cc +++ b/src/madness/chem/test_low_rank_function.cc @@ -387,6 +387,8 @@ int test_arithmetic(World& world, LowRankFunctionParameters parameters) { test_output t1("LowRankFunction::arithmetic in dimension " + std::to_string(NDIM)); t1.set_cout_to_terminal(); double thresh=FunctionDefaults::get_thresh(); + double thresh_ndim=FunctionDefaults::get_thresh(); + print("thresh ldim/ndim",thresh,thresh_ndim); Function phi=FunctionFactory(world) .functor([](const Vector& r){return exp(-4.0*inner(r,r));}); @@ -397,14 +399,16 @@ int test_arithmetic(World& world, LowRankFunctionParameters parameters) { functor2.f12.reset(GaussOperatorPtr(world,2.0)); functor2.a=phi; - auto builder= LowRankFunctionFactory(parameters).set_radius(8) + auto p1=particle::particle1(); + auto p2=particle::particle2(); + + auto builder= LowRankFunctionFactory(parameters).set_radius(4) .set_volume_element(0.1).set_rank_revealing_tol(1.e-10).set_orthomethod("canonical"); auto lrf1=builder.project(functor1); auto lrf2=builder.project(functor2); Vector r; r.fill(0.2); - print("lrf1(r)",lrf1(r)); // addition/subtraction { @@ -438,48 +442,155 @@ int test_arithmetic(World& world, LowRankFunctionParameters parameters) { t1.checkpoint(fabs(n2-refn2)> arg(3); - for (int i=0; i<3; ++i) arg[i]=FunctionFactory(world) - .functor([&i](const Vector& r) - {return exp(-r.normf());}); - auto p1=particle::particle1(); - auto p2=particle::particle2(); + auto l1=2.0*lrf1; + t1.checkpoint(fabs(l1(r)-2.0*lrf1(r)) +int test_inner(World& world, LowRankFunctionParameters parameters) { + + static_assert(LDIM==1 or LDIM==2); + constexpr std::size_t NDIM = 2 * LDIM; + test_output t1("LowRankFunction::test_inner in dimension " + std::to_string(NDIM)); + t1.set_cout_to_terminal(); + double thresh=FunctionDefaults::get_thresh(); + double thresh_ndim=FunctionDefaults::get_thresh(); + print("thresh ldim/ndim",thresh,thresh_ndim); + Function phi=FunctionFactory(world) + .functor([](const Vector& r){return exp(-4.0*inner(r,r));}); + + LRFunctorF12 functor1; +// functor1.f12.reset(GaussOperatorPtr(world,1.0)); + functor1.f12.reset(SlaterOperatorPtr_ND(world,1.0,1.e-4,thresh)); + functor1.a=phi; + LRFunctorF12 functor2; +// functor2.f12.reset(GaussOperatorPtr(world,2.0)); + functor2.f12.reset(SlaterOperatorPtr_ND(world,2.0,1.e-4,thresh)); + functor2.a=phi; - auto fullrank1=lrf1.reconstruct(); - auto fullrank2=lrf2.reconstruct(); - t1.checkpoint(true,"prep inner"); + auto p1=particle::particle1(); + auto p2=particle::particle2(); + auto builder= LowRankFunctionFactory(parameters).set_radius(4) + .set_volume_element(0.1).set_rank_revealing_tol(1.e-10).set_orthomethod("canonical"); + auto lrf1=builder.project(functor1); + auto lrf2=builder.project(functor2); + + // reference numbers: (by mathematica) + // f1(x,y) = exp(-a*x^2) * exp(-(x-y)^2) + // f2(x,y) = exp(-a*x^2) * exp(-g (x-y)^2) + // with a=4, g=2 + // int f1(x,y),f2(x,z) dx = inner(f1,f2,0,0) : norm^2 = Pi^2/(2 Sqrt[2] Sqrt[a gamma] Sqrt[1 + 2 a + gamma]) = 0.37197471167788324677 + // int f1(x,y),f2(z,x) dx = inner(f1,f2,0,1) : norm^2 = 0.32972034117743393239 + // int f1(y,x),f2(x,z) dx = inner(f1,f2,1,0) : norm^2 = 0.26921553123369812300 + // int f1(y,x),f2(z,x) dx = inner(f1,f2,1,1) : norm^2 = 0.35613867236025352322 + + // inner f(1,2) f(2,3) + auto fullrank1=lrf1.reconstruct(); + auto fullrank2=lrf2.reconstruct(); + t1.checkpoint(true,"prep inner"); + { + std::vector reference={ 0.37197471167788324677, 0.32972034117743393239, 0.26921553123369812300, 0.35613867236025352322}; + int counter=0; for (auto p11 : {p1,p2}) { for (auto p22 : {p1,p2}) { - auto lhs0=inner(fullrank1,fullrank2,p11.get_tuple(),p22.get_tuple()); - auto lhs1=inner(lrf1,fullrank2,p11,p22); - auto lhs2=inner(lrf1,lrf2,p11,p22); - double l0=lhs0.norm2(); - double l1=lhs1.norm2(); - double l2=lhs2.norm2(); + double ref=reference[counter]; + if (LDIM==2) ref*=ref; - print("inner(lrf,full,",p11,p22,"): ",fullrank1.norm2(),lhs1.norm2(),lhs2.norm2()); + // full/full + auto lhs1=inner(fullrank1,fullrank2,p11.get_tuple(),p22.get_tuple()); + double l1=lhs1.norm2(); + t1.checkpoint(fabs(l1*l1-ref)::get_thresh()*50.0; + // fresh start + lrf1=builder.project(functor1); + fullrank1=FunctionFactory(world).functor(functor1); - } + std::vector> arg(3); + for (int i=0; i<3; ++i) arg[i]=FunctionFactory(world) + .functor([&i](const Vector& r) + {return exp(-r.normf());}); + std::vector> lhs_full1, lhs_full2,lhs_func1,lhs_func2; + for (auto& a : arg) { + lhs_full1.push_back(inner(fullrank1,a,p1.get_tuple(),p1.get_tuple())); + lhs_full2.push_back(inner(fullrank1,a,p2.get_tuple(),p1.get_tuple())); + + lhs_func1.push_back(inner(functor1,a,p1,p1)); + lhs_func2.push_back(inner(functor1,a,p2,p1)); + } + auto lhs_lrf1=inner(lrf1,arg,p1,p1); + auto lhs_lrf2=inner(lrf1,arg,p2,p1); + + double norm_func1=norm2(world,lhs_func1); + double norm_func2=norm2(world,lhs_func2); + double norm_full1=norm2(world,lhs_full1); + double norm_full2=norm2(world,lhs_full2); + double norm_lrf1=norm2(world,lhs_lrf1); + double norm_lrf2=norm2(world,lhs_lrf2); + print("norms 1",norm_func1,norm_full1,norm_lrf1); + print("norms 2",norm_func2,norm_full2,norm_lrf2); + + double error1=norm2(world,lhs_full1-lhs_func1); + double error2=norm2(world,lhs_full2-lhs_func2); + double error3=norm2(world,lhs_lrf1 -lhs_func1); + double error4=norm2(world,lhs_lrf2 -lhs_func2); + + print("error1/2",error1,error2,error3,error4); +// t1.checkpoint(error1::set_tensor_type(TT_2D); FunctionDefaults<1>::set_thresh(thresh); @@ -570,7 +681,9 @@ int main(int argc, char **argv) { // isuccess+=test_construction_optimization<1>(world,parameters); // isuccess+=test_construction_optimization<2>(world,parameters); isuccess+=test_arithmetic<1>(world,parameters); -// isuccess+=test_arithmetic<2>(world,parameters); + isuccess+=test_arithmetic<2>(world,parameters); + isuccess+=test_inner<1>(world,parameters); + isuccess+=test_inner<2>(world,parameters); // isuccess+=test_lowrank_function(world,parameters); // isuccess+=test_Kcommutator(world,parameters); diff --git a/src/madness/mra/operator.h b/src/madness/mra/operator.h index ce0a0cfe701..5344bd94d94 100644 --- a/src/madness/mra/operator.h +++ b/src/madness/mra/operator.h @@ -1929,7 +1929,17 @@ namespace madness { } -/// Factory function generating separated kernel for convolution with exp(-mu*r) in 3D + /// Factory function generating separated kernel for convolution with exp(-mu*r) in 3D + /// Note that the 1/(2mu) factor of SlaterF12Operator is not included, this is just the exponential function + template + static inline SeparatedConvolution* SlaterOperatorPtr_ND(World& world, + double mu, double lo, double eps, + const BoundaryConditions& bc = FunctionDefaults::get_bc(), + int k = FunctionDefaults::get_k()) { + return new SeparatedConvolution(world,OperatorInfo(mu,lo,eps,OT_SLATER),bc,k); + } + + /// Factory function generating separated kernel for convolution with exp(-mu*r) in 3D /// Note that the 1/(2mu) factor of SlaterF12Operator is not included, this is just the exponential function static inline SeparatedConvolution* SlaterOperatorPtr(World& world, double mu, double lo, double eps, From c5bed7a353b96ad59af5415d61bf515df9c6a277 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Thu, 19 Oct 2023 15:53:20 +0200 Subject: [PATCH 058/109] avoiding unnecessary tree state changes --- src/madness/chem/lowrankfunction.h | 93 ++++++---------------- src/madness/chem/test_low_rank_function.cc | 26 +++--- src/madness/mra/mra.h | 57 ++++++++----- src/madness/mra/vmra.h | 22 ++++- 4 files changed, 99 insertions(+), 99 deletions(-) diff --git a/src/madness/chem/lowrankfunction.h b/src/madness/chem/lowrankfunction.h index 5707f0d7688..d08007afa6e 100644 --- a/src/madness/chem/lowrankfunction.h +++ b/src/madness/chem/lowrankfunction.h @@ -54,6 +54,7 @@ namespace madness { protected: double volume_element=0.1; double radius=3; + bool do_print=false; }; template @@ -67,7 +68,7 @@ namespace madness { std::vector> get_grid() const { std::vector> grid; long npoint_within_volume=volume()/volume_element; - print("npoint_within_volume",npoint_within_volume); + if (do_print) print("npoint_within_volume",npoint_within_volume); auto cell = FunctionDefaults::get_cell(); auto is_in_cell = [&cell](const Vector& r) { @@ -92,10 +93,12 @@ namespace madness { grid.push_back(tmp); if (rank==npoint_within_volume) break; } - print("grid points in volume ",rank); - print("total grid points ",grid.size()); - print("ratio ",rank/double(grid.size())); - print("volume element ",volume()/rank); + if (do_print) { + print("grid points in volume ",rank); + print("total grid points ",grid.size()); + print("ratio ",rank/double(grid.size())); + print("volume element ",volume()/rank); + } return grid; } @@ -117,58 +120,6 @@ namespace madness { return result; } -// double computed_volume_element() const { -// double volume = 4.0 / 3.0 * constants::pi * std::pow(radius, 3.0); -// print("volume element in random grid", volume / (0.67 * rank)); -// } - - }; - - template - class sphericalgrid : public gridbase { - public: - double volume_element=0.1; - double radius=3; - bool hard_shell=true; - - sphericalgrid(const double volume_element, const double radius, bool hard_shell) - :volume_element(volume_element), radius(radius), hard_shell(hard_shell) { - }; - - std::vector> get_coordinates() const { - // 1D grid - double volume_element_1d=std::pow(volume_element,1./NDIM); - long ngrid=std::ceil(radius/volume_element_1d); - double stepsize=radius/ngrid; - double scale=1.0; - if (not hard_shell) scale=std::pow(2.0,1.0/(ngrid+1)); - print("scale",scale); - - std::vector coord1d; - print("volume element, stepsize, ngrid" ,volume_element, std::pow(stepsize,NDIM),stepsize,ngrid); - for (int i=0; i> result; - for (int i=0; i c{coord1d[i],coord1d[j],coord1d[k]}; - double cutoff = hard_shell ? radius : 2.0*radius; - if (c.normf() @@ -280,6 +231,13 @@ struct particle { return ss.str(); } + + /// type conversion to std::array + std::array get_array() const { + return dims; + } + + /// assuming two particles only bool is_first() const {return dims[0]==0;} /// assuming two particles only @@ -422,9 +380,10 @@ struct LRFunctorPure : public LRFunctorBase { std::vector> inner(const std::vector>& rhs, const particle p1, const particle p2) const { - std::vector> result; - for (const auto& r : rhs) result.push_back(madness::inner(f,r,p1.get_tuple(),p2.get_tuple())); - return result; + return madness::innerXX(f,rhs,p1.get_array(),p2.get_array()); +// std::vector> result; +// for (const auto& r : rhs) result.push_back(madness::inner(f,r,p1.get_tuple(),p2.get_tuple())); +// return result; } T operator()(const Vector& r) const { @@ -449,7 +408,7 @@ struct LRFunctorPure : public LRFunctorBase { World& world; double rank_revealing_tol=1.e-8; // rrcd tol std::string orthomethod="canonical"; - bool do_print=true; + bool do_print=false; std::vector> g,h; const particle p1=particle::particle1(); const particle p2=particle::particle2(); @@ -693,6 +652,7 @@ struct LRFunctorPure : public LRFunctorBase { // \int f(1,2)^2 d1d2 double term1 = lrfunctor1.norm2(); + term1=term1*term1; t.tag("computing term1"); // \int f(1,2) pre(1) post(2) \sum_i g(1) h(2) d1d2 @@ -783,6 +743,7 @@ struct LRFunctorPure : public LRFunctorBase { template LowRankFunction inner(const LowRankFunction& f1, const Function& f2, const particle p1, const particle p2) { + static_assert(TensorTypeData::iscomplex==false, "complex inner in LowRankFunction not implemented"); World& world=f1.world; static_assert(2*PDIM==NDIM); // int f(1,2) k(2,3) d2 = \sum \int g_i(1) h_i(2) k(2,3) d2 @@ -790,14 +751,12 @@ struct LRFunctorPure : public LRFunctorBase { LowRankFunction result(world); if (p1.is_last()) { // integrate over 2: result(1,3) = lrf(1,2) f(2,3) result.g = f1.g; - decltype(f1.h) h; - for (int i=0; i::particle1().get_tuple()),p2.get_tuple())); - result.h=copy(h); + change_tree_state(f1.h,reconstructed); + result.h=innerXX(f2,f1.h,p2.get_array(),particle::particle1().get_array()); } else if (p1.is_first()) { // integrate over 1: result(2,3) = lrf(1,2) f(1,3) result.g = f1.h; // correct! second variable of f1 becomes first variable of result - decltype(f1.g) h; - for (int i=0; i::particle1().get_tuple(),p2.get_tuple())); - result.h=copy(h); + change_tree_state(f1.g,reconstructed); + result.h=innerXX(f2,f1.g,p2.get_array(),particle::particle1().get_array()); } return result; } diff --git a/src/madness/chem/test_low_rank_function.cc b/src/madness/chem/test_low_rank_function.cc index 1ebbd506383..2233fdfb514 100644 --- a/src/madness/chem/test_low_rank_function.cc +++ b/src/madness/chem/test_low_rank_function.cc @@ -309,7 +309,7 @@ template int test_full_rank_functor(World& world, LowRankFunctionParameters& parameters) { test_output t1("test_full_rank_functor"); -// t1.set_cout_to_terminal(); + t1.set_cout_to_terminal(); print_header2("entering test_full_rank_functor"); constexpr int NDIM=2*LDIM; FunctionDefaults::set_thresh(1.e-6); @@ -470,12 +470,12 @@ int test_inner(World& world, LowRankFunctionParameters parameters) { .functor([](const Vector& r){return exp(-4.0*inner(r,r));}); LRFunctorF12 functor1; -// functor1.f12.reset(GaussOperatorPtr(world,1.0)); - functor1.f12.reset(SlaterOperatorPtr_ND(world,1.0,1.e-4,thresh)); + functor1.f12.reset(GaussOperatorPtr(world,1.0)); +// functor1.f12.reset(SlaterOperatorPtr_ND(world,1.0,1.e-4,thresh)); functor1.a=phi; LRFunctorF12 functor2; -// functor2.f12.reset(GaussOperatorPtr(world,2.0)); - functor2.f12.reset(SlaterOperatorPtr_ND(world,2.0,1.e-4,thresh)); + functor2.f12.reset(GaussOperatorPtr(world,2.0)); +// functor2.f12.reset(SlaterOperatorPtr_ND(world,2.0,1.e-4,thresh)); functor2.a=phi; auto p1=particle::particle1(); @@ -491,7 +491,7 @@ int test_inner(World& world, LowRankFunctionParameters parameters) { // f2(x,y) = exp(-a*x^2) * exp(-g (x-y)^2) // with a=4, g=2 // int f1(x,y),f2(x,z) dx = inner(f1,f2,0,0) : norm^2 = Pi^2/(2 Sqrt[2] Sqrt[a gamma] Sqrt[1 + 2 a + gamma]) = 0.37197471167788324677 - // int f1(x,y),f2(z,x) dx = inner(f1,f2,0,1) : norm^2 = 0.32972034117743393239 + // int f1(x,y),f2(z,x) dx = inner(f1,f2,0,1) : norm^2 = Pi^2/(2 Sqrt[a (1 + a + gamma) (a + 2 gamma)]) = 0.32972034117743393239 // int f1(y,x),f2(x,z) dx = inner(f1,f2,1,0) : norm^2 = 0.26921553123369812300 // int f1(y,x),f2(z,x) dx = inner(f1,f2,1,1) : norm^2 = 0.35613867236025352322 @@ -509,7 +509,8 @@ int test_inner(World& world, LowRankFunctionParameters parameters) { // full/full auto lhs1=inner(fullrank1,fullrank2,p11.get_tuple(),p22.get_tuple()); - double l1=lhs1.norm2(); + const double l1=lhs1.norm2(); + print("l1",l1,l1*l1,ref); t1.checkpoint(fabs(l1*l1-ref)::get_thresh(),OT_SLATER); auto slater=std::shared_ptr >(new SeparatedConvolution(world,info)); Function one=FunctionFactory(world).functor([](const Vector& r){return exp(-0.2*inner(r,r));}); @@ -677,11 +678,12 @@ int main(int argc, char **argv) { // isuccess+=test_grids<1>(world,parameters); // isuccess+=test_grids<2>(world,parameters); // isuccess+=test_grids<3>(world,parameters); -// isuccess+=test_full_rank_functor<1>(world, parameters); -// isuccess+=test_construction_optimization<1>(world,parameters); -// isuccess+=test_construction_optimization<2>(world,parameters); + isuccess+=test_full_rank_functor<1>(world, parameters); + isuccess+=test_construction_optimization<1>(world,parameters); + isuccess+=test_construction_optimization<2>(world,parameters); isuccess+=test_arithmetic<1>(world,parameters); isuccess+=test_arithmetic<2>(world,parameters); + isuccess+=test_inner<1>(world,parameters); isuccess+=test_inner<2>(world,parameters); diff --git a/src/madness/mra/mra.h b/src/madness/mra/mra.h index ebdea3baf4d..5ca1967d125 100644 --- a/src/madness/mra/mra.h +++ b/src/madness/mra/mra.h @@ -903,7 +903,9 @@ namespace madness { } else { MADNESS_EXCEPTION("unknown/unsupported final tree state",1); } - if (must_fence and world().rank()==0) print("could not respect fence in change_tree_state"); + if (must_fence and world().rank()==0) { + print("could not respect fence in change_tree_state"); + } if (fence && VERIFY_TREE) verify_tree(); // Must be after in case nonstandard return *this; } @@ -2509,8 +2511,8 @@ namespace madness { /// @param[in] task 0: everything, 1; prepare only (fence), 2: work only (no fence), 3: finalize only (fence) template - Function - innerXX(const Function& f, const Function& g, const std::array v1, + std::vector> + innerXX(const Function& f, const std::vector>& vg, const std::array v1, const std::array v2, int task=0) { bool prepare = ((task==0) or (task==1)); bool work = ((task==0) or (task==2)); @@ -2527,8 +2529,8 @@ namespace madness { MADNESS_CHECK((v2[0]==0) or (v2[CDIM-1]==KDIM-1)); MADNESS_CHECK(f.is_initialized()); - MADNESS_CHECK(g.is_initialized()); - MADNESS_CHECK(f.world().id() == g.world().id()); + MADNESS_CHECK(vg[0].is_initialized()); + MADNESS_CHECK(f.world().id() == vg[0].world().id()); // this needs to be run in a single world, so that all coefficients are local. // Use macrotasks if run on multiple processes. World& world=f.world(); @@ -2536,32 +2538,33 @@ namespace madness { if (prepare) { f.change_tree_state(nonstandard); - g.change_tree_state(nonstandard); + change_tree_state(vg,nonstandard); world.gop.fence(); f.get_impl()->compute_snorm_and_dnorm(false); - g.get_impl()->compute_snorm_and_dnorm(false); + for (auto& g : vg) g.get_impl()->compute_snorm_and_dnorm(false); world.gop.fence(); } typedef TENSOR_RESULT_TYPE(T, R) resultT; - Function result; + std::vector> result(vg.size()); if (work) { world.gop.set_forbid_fence(true); - result=FunctionFactory(world) - .k(f.k()).thresh(f.thresh()).empty().nofence(); - result.get_impl()->partial_inner(*f.get_impl(),*g.get_impl(),v1,v2); - result.get_impl()->set_tree_state(nonstandard_after_apply); + for (int i=0; i(world) + .k(f.k()).thresh(f.thresh()).empty().nofence(); + result[i].get_impl()->partial_inner(*f.get_impl(),*(vg[i]).get_impl(),v1,v2); + result[i].get_impl()->set_tree_state(nonstandard_after_apply); + } world.gop.set_forbid_fence(false); } if (finish) { world.gop.fence(); - result.get_impl()->reconstruct(true); - result.reconstruct(); - FunctionImpl& f_nc=const_cast&>(*f.get_impl()); - FunctionImpl& g_nc=const_cast&>(*g.get_impl()); +// result.get_impl()->reconstruct(true); + change_tree_state(result,reconstructed); +// result.reconstruct(); // restore initial state of g and h auto erase_list = [] (const auto& funcimpl) { typedef typename std::decay_t::keyT keyTT; @@ -2574,10 +2577,14 @@ namespace madness { return to_be_erased; }; + FunctionImpl& f_nc=const_cast&>(*f.get_impl()); for (auto& key : erase_list(f_nc)) f_nc.get_coeffs().erase(key); - for (auto& key : erase_list(g_nc)) g_nc.get_coeffs().erase(key); + for (auto& g : vg) { + FunctionImpl& g_nc=const_cast&>(*g.get_impl()); + for (auto& key : erase_list(g_nc)) g_nc.get_coeffs().erase(key); + } world.gop.fence(); - g_nc.reconstruct(false); + change_tree_state(vg,reconstructed); f_nc.reconstruct(false); world.gop.fence(); @@ -2586,6 +2593,20 @@ namespace madness { return result; } + + /// Computes the partial scalar/inner product between two functions, returns a low-dim function + + /// syntax similar to the inner product in tensor.h + /// e.g result=inner<3>(f,g),{0},{1}) : r(x,y) = int f(x1,x) g(y,x1) dx1 + /// @param[in] task 0: everything, 1; prepare only (fence), 2: work only (no fence), 3: finalize only (fence) + template + Function + innerXX(const Function& f, const Function& g, const std::array v1, + const std::array v2, int task=0) { + return innerXX(f,std::vector>({g}),v1,v2,task)[0]; + } + /// Computes the partial scalar/inner product between two functions, returns a low-dim function /// syntax similar to the inner product in tensor.h diff --git a/src/madness/mra/vmra.h b/src/madness/mra/vmra.h index 4ca5cd50bd8..3b7757e38e7 100644 --- a/src/madness/mra/vmra.h +++ b/src/madness/mra/vmra.h @@ -288,6 +288,19 @@ namespace madness { if (not dummy.is_initialized()) return v; World& world=dummy.world(); + // a couple of special cases + if (finalstate==nonstandard) { + bool must_fence=false; + for (auto& f : v) { + if (f.get_impl()->get_tree_state()== reconstructed) continue; + if (f.get_impl()->get_tree_state()!=nonstandard) { + must_fence=true; + f.change_tree_state(reconstructed,false); + } + } + if (must_fence) world.gop.fence(); +// if (world.rank()==0 and must_fence) print("could not respect fence in change_tree_state(vector)"); + } // if (not fence) world.gop.set_forbid_fence(true); // make sure fence is respected for (unsigned int i=0; iget_tensor_type()==TT_2D) { From becd4a7ca1213dbf639c17fea18e0fa009cea6b2 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Wed, 25 Oct 2023 13:36:04 +0200 Subject: [PATCH 059/109] finetuning --- src/madness/chem/lowrankfunction.h | 10 +++- src/madness/chem/test_low_rank_function.cc | 68 +++++++++++++--------- src/madness/world/test_utilities.h | 44 +++++++++++++- 3 files changed, 87 insertions(+), 35 deletions(-) diff --git a/src/madness/chem/lowrankfunction.h b/src/madness/chem/lowrankfunction.h index d08007afa6e..f25ab3d90e7 100644 --- a/src/madness/chem/lowrankfunction.h +++ b/src/madness/chem/lowrankfunction.h @@ -671,12 +671,16 @@ struct LRFunctorPure : public LRFunctorBase { auto tmp1=matrix_inner(world,h,h); auto tmp2=matrix_inner(world,g,g); double term3=tmp1.trace(tmp2); - print("term3/a/diff",term3a,term3,term3-term3a); +// print("term3/a/diff",term3a,term3,term3-term3a); t.tag("computing term3"); double arg=term1-2.0*term2+term3; - if (arg<0.0) throw std::runtime_error("negative argument in l2error"); - double error=sqrt(term1-2.0*term2+term3)/sqrt(term1); + if (arg<0.0) { + print("negative l2 error"); + arg*=-1.0; +// throw std::runtime_error("negative argument in l2error"); + } + double error=sqrt(arg)/sqrt(term1); if (world.rank()==0 and do_print) { print("term1,2,3, error",term1, term2, term3, " --",error); } diff --git a/src/madness/chem/test_low_rank_function.cc b/src/madness/chem/test_low_rank_function.cc index 2233fdfb514..8cdaa6444e3 100644 --- a/src/madness/chem/test_low_rank_function.cc +++ b/src/madness/chem/test_low_rank_function.cc @@ -16,7 +16,7 @@ using namespace madness; -int test_lowrank_function(World& world, LowRankFunctionParameters& parameters) { +int test_lowrank_function(World& world, LowRankFunctionParameters parameters) { test_output t1("CCPairFunction::low rank function"); t1.set_cout_to_terminal(); madness::default_random_generator.setstate(int(cpu_time())%4149); @@ -101,7 +101,7 @@ int test_lowrank_function(World& world, LowRankFunctionParameters& parameters) { // \phi(1) \bar \phi(1) = \intn phi(1) \phi(2) f(1,2) d2 auto reference = phi1* (*f12)(phi2); - plot_plane<3>(world,reference,"reference."+id,PlotParameters(world).set_plane({"x1","x2"})); +// plot_plane<3>(world,reference,"reference."+id,PlotParameters(world).set_plane({"x1","x2"})); double n2=reference.norm2(); print("reference.norm2() = int f12 phi2 d2",n2); output(0.0,0.0,0.0,0.0,0.0,0.0); @@ -306,15 +306,15 @@ int test_Kcommutator(World& world, LowRankFunctionParameters& parameters) { } template -int test_full_rank_functor(World& world, LowRankFunctionParameters& parameters) { +int test_full_rank_functor(World& world, LowRankFunctionParameters parameters) { test_output t1("test_full_rank_functor"); t1.set_cout_to_terminal(); print_header2("entering test_full_rank_functor"); constexpr int NDIM=2*LDIM; - FunctionDefaults::set_thresh(1.e-6); - FunctionDefaults::set_thresh(1.e-6); - double tol=1.e-3; +// FunctionDefaults::set_thresh(1.e-6); +// FunctionDefaults::set_thresh(1.e-6); + double tol=5.e-3; double gaussexponent=2.0; const particle p1=particle::particle1(); @@ -352,25 +352,25 @@ int test_full_rank_functor(World& world, LowRankFunctionParameters& parameters) try { double error1=lrfunction1.l2error(functorf12); - t1.checkpoint(error1 int test_inner(World& world, LowRankFunctionParameters parameters) { static_assert(LDIM==1 or LDIM==2); constexpr std::size_t NDIM = 2 * LDIM; test_output t1("LowRankFunction::test_inner in dimension " + std::to_string(NDIM)); - t1.set_cout_to_terminal(); +// t1.set_cout_to_terminal(); double thresh=FunctionDefaults::get_thresh(); double thresh_ndim=FunctionDefaults::get_thresh(); print("thresh ldim/ndim",thresh,thresh_ndim); @@ -511,32 +519,32 @@ int test_inner(World& world, LowRankFunctionParameters parameters) { auto lhs1=inner(fullrank1,fullrank2,p11.get_tuple(),p22.get_tuple()); const double l1=lhs1.norm2(); print("l1",l1,l1*l1,ref); - t1.checkpoint(fabs(l1*l1-ref)> arg(3); for (int i=0; i<3; ++i) arg[i]=FunctionFactory(world) .functor([&i](const Vector& r) - {return exp(-r.normf());}); + {return exp(-(i+1)*r.normf());}); std::vector> lhs_full1, lhs_full2,lhs_func1,lhs_func2; for (auto& a : arg) { @@ -597,7 +604,6 @@ int test_inner(World& world, LowRankFunctionParameters parameters) { template int test_construction_optimization(World& world, LowRankFunctionParameters parameters) { - parameters.set_user_defined_value("volume_element",0.05); constexpr std::size_t NDIM=2*LDIM; test_output t1("LowRankFunction::construction/optimization in dimension "+std::to_string(NDIM)); // t1.set_cout_to_terminal(); @@ -639,7 +645,7 @@ int main(int argc, char **argv) { startup(world, argc, argv); commandlineparser parser(argc, argv); int k = parser.key_exists("k") ? std::atoi(parser.value("k").c_str()) : 6; - double thresh = parser.key_exists("thresh") ? std::stod(parser.value("thresh")) : 1.e-4; + double thresh = parser.key_exists("thresh") ? std::stod(parser.value("thresh")) : 1.e-5; FunctionDefaults<6>::set_tensor_type(TT_2D); FunctionDefaults<1>::set_thresh(thresh); @@ -668,6 +674,9 @@ int main(int argc, char **argv) { FunctionDefaults<6>::get_thresh()); LowRankFunctionParameters parameters; parameters.read_and_set_derived_values(world,parser,"grid"); + parameters.set_user_defined_value("radius",3.0); + parameters.set_user_defined_value("volume_element",2.e-2); + parameters.set_user_defined_value("tol",1.0e-10); parameters.print("grid"); int isuccess=0; #ifdef USE_GENTENSOR @@ -680,15 +689,16 @@ int main(int argc, char **argv) { // isuccess+=test_grids<3>(world,parameters); isuccess+=test_full_rank_functor<1>(world, parameters); isuccess+=test_construction_optimization<1>(world,parameters); - isuccess+=test_construction_optimization<2>(world,parameters); +// isuccess+=test_construction_optimization<2>(world,parameters); isuccess+=test_arithmetic<1>(world,parameters); - isuccess+=test_arithmetic<2>(world,parameters); +// isuccess+=test_arithmetic<2>(world,parameters); - isuccess+=test_inner<1>(world,parameters); - isuccess+=test_inner<2>(world,parameters); +// isuccess+=test_inner<1>(world,parameters); +// isuccess+=test_inner<2>(world,parameters); -// isuccess+=test_lowrank_function(world,parameters); -// isuccess+=test_Kcommutator(world,parameters); + parameters.set_user_defined_value("volume_element",1.e-1); + isuccess+=test_lowrank_function(world,parameters); + isuccess+=test_Kcommutator(world,parameters); } catch (std::exception& e) { madness::print("an error occured"); madness::print(e.what()); diff --git a/src/madness/world/test_utilities.h b/src/madness/world/test_utilities.h index d87cfe9a1d4..65c4ae7042e 100644 --- a/src/madness/world/test_utilities.h +++ b/src/madness/world/test_utilities.h @@ -37,6 +37,43 @@ struct test_output { logger.clear(); } + void checkpoint(double error, double tol, + std::string message, double time=-1.0) { + bool use_logger=cout_set_to_logger; + set_cout_to_terminal(); + bool success=error=0.0) os << " error " << error; os << std::endl; } @@ -70,7 +108,7 @@ struct test_output { if (have_checkpoints) std::cout << ltrim_to_length("--> final result -->",70); success = success and final_success; double time_end=cpu_time(); - print_success_fail(std::cout,success,time_end-time_begin); + print_success_fail(std::cout,success,time_end-time_begin,-1.0); if (not success) print_and_clear_log(); return (success) ? 0 : 1; } From 9ff2820cbcd67ee84f0cee1da4f2aa5781909151 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Fri, 27 Oct 2023 15:20:02 +0200 Subject: [PATCH 060/109] exchange operator apply working in low rank form and is faster --- src/madness/chem/CCStructures.cc | 12 ++ src/madness/chem/CCStructures.h | 4 +- src/madness/chem/ccpairfunction.cc | 70 ++++----- src/madness/chem/test_low_rank_function.cc | 162 ++++++++++++++------- src/madness/mra/funcimpl.h | 2 + src/madness/mra/function_interface.h | 44 +++--- src/madness/mra/mra.h | 153 ++----------------- src/madness/mra/mraimpl.h | 107 +++++++++++++- src/madness/mra/operator.h | 33 ++--- 9 files changed, 300 insertions(+), 287 deletions(-) diff --git a/src/madness/chem/CCStructures.cc b/src/madness/chem/CCStructures.cc index 998ad8cd05a..7181a6b8acf 100644 --- a/src/madness/chem/CCStructures.cc +++ b/src/madness/chem/CCStructures.cc @@ -421,6 +421,12 @@ CCConvolutionOperator::init_op(const OpType& type, const Parameters& parameters) << " and lo=" << parameters.lo << " and Gamma=" << parameters.gamma << std::endl; return SlaterF12OperatorPtr(world, parameters.gamma, parameters.lo, parameters.thresh_op); } + case OpType::OT_F212 : { + if (printme) + std::cout << "Creating " << assign_name(type) << " Operator with thresh=" << parameters.thresh_op + << " and lo=" << parameters.lo << " and Gamma=" << parameters.gamma << std::endl; + return SlaterF12sqOperatorPtr(world, parameters.gamma, parameters.lo, parameters.thresh_op); + } case OpType::OT_SLATER : { if (printme) std::cout << "Creating " << assign_name(type) << " Operator with thresh=" << parameters.thresh_op @@ -491,6 +497,12 @@ assign_name(const OpType& input) { return "bsh"; case OpType::OT_ONE: return "identity"; + case OpType::OT_GAUSS: /// exp(-r2) + return "gauss"; + case OpType::OT_F212: /// (1-exp(-r))^2 + return "f12^2"; + case OpType::OT_F2G12: /// (1-exp(-r))^2/r = 1/r + exp(-2r)/r - 2 exp(-r)/r + return "f12^2g"; default: { MADNESS_EXCEPTION("Unvalid enum assignement!", 1); return "undefined"; diff --git a/src/madness/chem/CCStructures.h b/src/madness/chem/CCStructures.h index 3189b9c4c98..d214a2f996d 100644 --- a/src/madness/chem/CCStructures.h +++ b/src/madness/chem/CCStructures.h @@ -742,7 +742,9 @@ struct CCConvolutionOperator { friend std::shared_ptr combine(const std::shared_ptr& a, const std::shared_ptr& b) { - auto bla=combine(*a,*b); + if (a and (not b)) return a; + if ((not a) and b) return b; + if ((not a) and (not b)) return nullptr; return std::shared_ptr(new CCConvolutionOperator(combine(*a,*b))); } diff --git a/src/madness/chem/ccpairfunction.cc b/src/madness/chem/ccpairfunction.cc index 2c645534bff..81a99235dc1 100644 --- a/src/madness/chem/ccpairfunction.cc +++ b/src/madness/chem/ccpairfunction.cc @@ -432,30 +432,20 @@ double CCPairFunction::inner_internal(const CCPairFunction& other, const real_fu const vector_real_function_3d b = R2.is_initialized() ? R2 * f2.get_b() : copy(world(), f2.get_b()); const pureT& bra=f1.get_function(); - auto ops=combine(f1.get_operator_ptr(),f2.get_operator_ptr()); - MADNESS_EXCEPTION("still to debug",1); -// if (ops.size()>0) { -// for (const auto& single_op : ops) { -// auto fac = single_op.first; -// auto op = single_op.second; -// double bla=0.0; -// for (int i=0; i(world()).g12(op.get_kernel()).particle1(a[i]).particle2(b[i]); -// bla += fac * inner(bra, tmp); -// } else { -// real_function_6d tmp = CompositeFactory(world()).particle1(a[i]).particle2(b[i]); -// bla += fac * inner(bra,tmp); -// } -// } -// result+=bla; -// } -// } else { // no operators + auto op=combine(f1.get_operator_ptr(),f2.get_operator_ptr()); + if (op) { + double bla=0.0; + for (int i=0; i(world()).g12(op->get_kernel()).particle1(a[i]).particle2(b[i]); + bla += inner(bra, tmp); + } + result+=bla; + } else { // no operators for (int i=0; i(world()).particle1(a[i]).particle2(b[i]); result+=inner(bra,tmp); } -// } + } } else if (f1.is_decomposed() and f2.is_pure()) { // with or without op result= f2.inner_internal(f1,R2); @@ -469,31 +459,21 @@ double CCPairFunction::inner_internal(const CCPairFunction& other, const real_fu const vector_real_function_3d b2 = R2.is_initialized() ? R2* f2.get_b() : f2.get_b(); - MADNESS_EXCEPTION("still to debug",1); - auto ops=combine(f1.get_operator_ptr(),f2.get_operator_ptr()); -// if (ops.size()==0) { -// // = \sum_ij = \sum_ij -// result = (matrix_inner(world(), a1, a2)).trace(matrix_inner(world(),b1,b2)); -// } else { -// // = -// for (const auto& single_op : ops) { -// auto fac = single_op.first; -// auto op = single_op.second; -// -// double bla=0.0; -// if (op.get_op()) { -// for (size_t i = 0; i < a1.size(); i++) { -// vector_real_function_3d aa = truncate(a1[i] * a2); -// vector_real_function_3d bb = truncate(b1[i] * b2); -// vector_real_function_3d aopx = op(aa); -// bla += fac * inner(bb, aopx); -// } -// } else { -// bla += fac*(matrix_inner(world(), a1, a2)).trace(matrix_inner(world(),b1,b2)); -// } -// result+=bla; -// } -// } +// MADNESS_EXCEPTION("still to debug",1); + auto op=combine(f1.get_operator_ptr(),f2.get_operator_ptr()); + if (not op) { + // = \sum_ij = \sum_ij + result = (matrix_inner(world(), a1, a2)).trace(matrix_inner(world(),b1,b2)); + } else { + // = + result=0.0; + for (size_t i = 0; i < a1.size(); i++) { + vector_real_function_3d aa = truncate(a1[i] * a2); + vector_real_function_3d bb = truncate(b1[i] * b2); + vector_real_function_3d aopx = (*op)(aa); + result += inner(bb, aopx); + } + } } else MADNESS_EXCEPTION( ("CCPairFunction Overlap not supported for combination " + f1.name() + " and " + f2.name()).c_str(), 1) ; return result; diff --git a/src/madness/chem/test_low_rank_function.cc b/src/madness/chem/test_low_rank_function.cc index 8cdaa6444e3..f77f8bdcd1a 100644 --- a/src/madness/chem/test_low_rank_function.cc +++ b/src/madness/chem/test_low_rank_function.cc @@ -109,6 +109,7 @@ int test_lowrank_function(World& world, LowRankFunctionParameters parameters) { LRFunctorF12 lrfunctor(f12,phi1,phi1); double cpu0=cpu_time(); auto lrf=LowRankFunctionFactory(parameters).project(lrfunctor); + lrf.do_print=true; // plot_plane<6>(world,lrfunctor,"plot_original."+id,PlotParameters(world).set_plane({"x1","x4"})); double cpu1=cpu_time(); double error1=lrf.l2error(lrfunctor); @@ -172,6 +173,7 @@ int test_Kcommutator(World& world, LowRankFunctionParameters& parameters) { parameters.print("grid"); real_convolution_3d g12=(CoulombOperator(world,1.e-6,FunctionDefaults::get_thresh())); + g12.particle()=1; std::shared_ptr f12ptr; std::string f12type=parameters.f12type(); if (f12type=="slaterf12") f12ptr.reset(SlaterF12OperatorPtr(world,parameters.gamma(),1.e-6,FunctionDefaults::get_thresh())); @@ -184,7 +186,7 @@ int test_Kcommutator(World& world, LowRankFunctionParameters& parameters) { real_function_3d phi=real_factory_3d(world).f([](const coord_3d& r){return exp(-r.normf());}); double n=phi.norm2(); phi.scale(1/n); - real_function_3d phi_k=phi; // lookys silly, helps reading. + real_function_3d phi_k=phi; // looks silly, helps reading. // reference term ( < ij | K(1) ) = j_hj = inner(world, phi, hj); Tensor i_gk = inner(world, phi, gk); double result_right = j_hj.trace(i_gk); - print(msg, result_right); + print(msg,"norm ", result_right); + print(msg,"error", result_right-reference); + print(msg,"rank ", lrf.rank()); j[msg]=result_right-reference; j[msg+"_rank"]=lrf.rank(); j[msg+"_compute_time"]=t.tag(msg+"_compute_time"); @@ -230,7 +234,7 @@ int test_Kcommutator(World& world, LowRankFunctionParameters& parameters) { }; - { + if (1) { // lowrankfunction left phi: lrf(1',2) = f12(1',2) i(1') // K f12 ij = \sum_k k(1) \int g(1,1') f12(1'2) i(1') j(2) k(1') d1' // = \sum_kr k(1) j(2) \int g(1,1') g_r(1') h_r(2) k(1') d1' @@ -254,54 +258,101 @@ int test_Kcommutator(World& world, LowRankFunctionParameters& parameters) { json2file(j,jsonfilename); compute_error("left_optimize",fi_one); - fi_one.reorthonormalize(); - j["left_reorthonormalize"]=t.tag("left_reorthonormalize"); - json2file(j,jsonfilename); - compute_error("left_reorthonormalize",fi_one); +// fi_one.reorthonormalize(); +// j["left_reorthonormalize"]=t.tag("left_reorthonormalize"); +// json2file(j,jsonfilename); +// compute_error("left_reorthonormalize",fi_one); + + LowRankFunction phi0(world); + phi0.g={phi}; + phi0.h={phi}; + + timer t2(world); + // this is f12|ij> + auto f12ij=copy(fi_one); + f12ij.h=f12ij.h*phi; + double result1=inner(phi0,f12ij); + print("",result1); + t2.tag("multiply 1(1)* phi(1))"); + + // this is f12|(ki) j> + auto f12kij=copy(f12ij); + f12kij.g=f12kij.g*phi; + double result3=inner(phi0,f12kij); + print("",result3); + t2.tag("multiply 1"); + + // this is g(f12|(ki) j>); + auto gf12kij=copy(f12kij); + gf12kij.g=g12(f12kij.g); + double result2=inner(phi0,gf12kij); + print(")",result2); + t2.tag("apply g "); + + // this is kg(f12|(ki) j>); + auto kgf12kij=copy(gf12kij); + kgf12kij.g=gf12kij.g * phi; + double result4=inner(phi0,kgf12kij); + print(")",result4); + t2.tag("apply g "); } -// // lowrankfunction right phi: lrf(1',2) = f12(1',2) i(1') -// { -// real_function_3d one = real_factory_3d(world).f([](const coord_3d &r) { return 1.0; }); -// LowRankFunction fi_one(f12ptr, copy(one), copy(phi)); -// fi_one.project(parameters); -// std::swap(fi_one.g,fi_one.h); -// j["right_project_time"]=t.tag("right_project_time"); -// json2file(j,jsonfilename); -// -// -// { -// auto gk = mul(world, phi_k, g12(fi_one.g * phi_k)); // function of 1 -// auto hj = fi_one.h * phi; // function of 2 -// Tensor j_hj = inner(world, phi, hj); -// Tensor i_gk = inner(world, phi, gk); -// double result_right = j_hj.trace(i_gk); -// print("result_right, project only", result_right); -// j["right_project"]=result_right-reference; -// j["right_project_rank"]=fi_one.rank(); -// j["left_optimize_compute_time"]=t.tag("left_optimize_compute_time"); -// j["right_project_compute_time"]=t.tag("right_project_compute_time"); -// } -// json2file(j,jsonfilename); -// std::swap(fi_one.g,fi_one.h); -// fi_one.optimize(); -// std::swap(fi_one.g,fi_one.h); -// { -// auto gk = mul(world, phi_k, g12(fi_one.g * phi_k)); // function of 1 -// auto hj = fi_one.h * phi; // function of 2 -// Tensor j_hj = inner(world, phi, hj); -// Tensor i_gk = inner(world, phi, gk); -// double result_right = j_hj.trace(i_gk); -// print("result_right, optimize", result_right); -// j["right_optimize"]=result_right-reference; -// j["right_optimize_rank"]=fi_one.rank(); -// j["right_optimize_compute_time"]=t.tag("right_optimize_compute_time"); -// } -// json2file(j,jsonfilename); -// -// } - return 0; + // apply exchange operator in 6d +// if (f12type=="slaterf12") { + if (1) { +// FunctionDefaults<3>::print(); +// FunctionDefaults<6>::print(); + real_function_6d phi0=CompositeFactory(world).particle1(phi).particle2(phi); + + double thresh=FunctionDefaults<3>::get_thresh(); + double dcut=1.e-6; + real_function_6d tmp=TwoElectronFactory(world).dcut(dcut).gamma(parameters.gamma()).f12().thresh(thresh); + real_function_6d f12ij=CompositeFactory(world).g12(tmp).particle1(copy(phi)).particle2(copy(phi)); + + timer t(world); + f12ij.fill_tree(); + t.tag("exchange: fill_tree"); + f12ij.print_size("f12ij"); + + auto result1=madness::inner(phi0,f12ij); + print("", result1); + double reference1=inner(phi*phi,f12(phi*phi)); + print("reference ",reference1); + + + real_function_6d kf12ij=multiply(f12ij,copy(phi_k),1); + kf12ij.print_size("kf12ij"); + t.tag("exchange: multiply 1"); + + auto result2=madness::inner(phi0,kf12ij); + print("", result2); + double reference2=inner(phi*phi,f12(phi*phi*phi)); + print("reference ",reference2); + + kf12ij.change_tree_state(reconstructed); + real_function_6d gkf12ij=g12(kf12ij).truncate(); + gkf12ij.print_size("gkf12ij"); + t.tag("exchange: apply g"); + + auto result3=madness::inner(phi0,gkf12ij); + print("", result3); + double reference3=inner(phi*phi,f12(phi*phi*g12(copy(phi)))); + print("reference ",reference3); + + + auto exf12ij=multiply(gkf12ij,copy(phi_k),1).truncate(); + exf12ij.print_size("exf12ij"); + t.tag("exchange: multiply 2"); + + auto result=madness::inner(phi0,exf12ij); + print("", result); + print("error",result-reference); + + + } + + return t1.end(); } @@ -648,12 +699,17 @@ int main(int argc, char **argv) { double thresh = parser.key_exists("thresh") ? std::stod(parser.value("thresh")) : 1.e-5; FunctionDefaults<6>::set_tensor_type(TT_2D); + + FunctionDefaults<3>::set_truncate_mode(1); + FunctionDefaults<6>::set_truncate_mode(1); + FunctionDefaults<1>::set_thresh(thresh); FunctionDefaults<2>::set_thresh(thresh); FunctionDefaults<3>::set_thresh(thresh); FunctionDefaults<4>::set_thresh(thresh); FunctionDefaults<5>::set_thresh(thresh); FunctionDefaults<6>::set_thresh(thresh); + FunctionDefaults<6>::set_thresh(1.e-3); FunctionDefaults<1>::set_k(k); FunctionDefaults<2>::set_k(k); @@ -674,9 +730,9 @@ int main(int argc, char **argv) { FunctionDefaults<6>::get_thresh()); LowRankFunctionParameters parameters; parameters.read_and_set_derived_values(world,parser,"grid"); - parameters.set_user_defined_value("radius",3.0); - parameters.set_user_defined_value("volume_element",2.e-2); - parameters.set_user_defined_value("tol",1.0e-10); +// parameters.set_user_defined_value("radius",3.0); +// parameters.set_user_defined_value("volume_element",2.e-2); +// parameters.set_user_defined_value("tol",1.0e-10); parameters.print("grid"); int isuccess=0; #ifdef USE_GENTENSOR @@ -696,8 +752,8 @@ int main(int argc, char **argv) { // isuccess+=test_inner<1>(world,parameters); // isuccess+=test_inner<2>(world,parameters); - parameters.set_user_defined_value("volume_element",1.e-1); - isuccess+=test_lowrank_function(world,parameters); +// parameters.set_user_defined_value("volume_element",1.e-1); +// isuccess+=test_lowrank_function(world,parameters); isuccess+=test_Kcommutator(world,parameters); } catch (std::exception& e) { madness::print("an error occured"); diff --git a/src/madness/mra/funcimpl.h b/src/madness/mra/funcimpl.h index c27c1ee5670..2f4f4d39315 100644 --- a/src/madness/mra/funcimpl.h +++ b/src/madness/mra/funcimpl.h @@ -4444,6 +4444,8 @@ namespace madness { /// reconstruct this tree -- respects fence void reconstruct(bool fence); + void change_tree_state(const TreeState finalstate, bool fence=true); + // Invoked on node where key is local // void reconstruct_op(const keyT& key, const tensorT& s); void reconstruct_op(const keyT& key, const coeffT& s, const bool accumulate_NS=true); diff --git a/src/madness/mra/function_interface.h b/src/madness/mra/function_interface.h index b0c498730c1..2f9b4063767 100644 --- a/src/madness/mra/function_interface.h +++ b/src/madness/mra/function_interface.h @@ -201,15 +201,15 @@ namespace madness { void make_redundant(const bool fence) { // prepare base functions that make this function - if (impl_ket and (not impl_ket->is_on_demand())) impl_ket->make_redundant(false); + if (impl_ket and (not impl_ket->is_on_demand())) impl_ket->change_tree_state(redundant,false); if (impl_eri) { - if (not impl_eri->is_on_demand()) impl_eri->make_redundant(false); + if (not impl_eri->is_on_demand()) impl_eri->change_tree_state(redundant,false); } - if (impl_m1 and (not impl_m1->is_on_demand())) impl_m1->make_redundant(false); - if (impl_m2 and (not impl_m2->is_on_demand())) impl_m2->make_redundant(false); + if (impl_m1 and (not impl_m1->is_on_demand())) impl_m1->change_tree_state(redundant,false); + if (impl_m2 and (not impl_m2->is_on_demand())) impl_m2->change_tree_state(redundant,false); - if (impl_p1 and (not impl_p1->is_on_demand())) impl_p1->make_redundant(false); - if (impl_p2 and (not impl_p2->is_on_demand())) impl_p2->make_redundant(false); + if (impl_p1 and (not impl_p1->is_on_demand())) impl_p1->change_tree_state(redundant,false); + if (impl_p2 and (not impl_p2->is_on_demand())) impl_p2->change_tree_state(redundant,false); if (fence) world.gop.fence(); } @@ -522,28 +522,28 @@ namespace madness { initialize(eps); } - /// overload the function of the base class - coeffT coeff(const Key<6>& key) const { - - Tensor c=make_coeff(key); - - // subtract 1 from the (0,0,..,0) element of the tensor, - // which is the 0th order polynomial coefficient - double one_coeff1=1.0*sqrt(FunctionDefaults<6>::get_cell_volume()) - *pow(0.5,0.5*6*key.level()); - std::vector v0(6,0L); - c(v0)-=one_coeff1; - - c.scale(-0.5/mu); - return coeffT(map_coeff(c),FunctionDefaults<6>::get_thresh(),TT_FULL); - } +// /// overload the function of the base class +// coeffT coeff(const Key<6>& key) const { +// +// Tensor c=make_coeff(key); +// +// // subtract 1 from the (0,0,..,0) element of the tensor, +// // which is the 0th order polynomial coefficient +// double one_coeff1=1.0*sqrt(FunctionDefaults<6>::get_cell_volume()) +// *pow(0.5,0.5*6*key.level()); +// std::vector v0(6,0L); +// c(v0)-=one_coeff1; +// +// c.scale(-0.5/mu); +// return coeffT(map_coeff(c),FunctionDefaults<6>::get_thresh(),TT_FULL); +// } private: double mu; GFit fit(const double eps) const { - return GFit::SlaterFit(mu,lo,hi,eps,false); + return GFit::F12Fit(mu,lo,hi,eps,false); } }; diff --git a/src/madness/mra/mra.h b/src/madness/mra/mra.h index 5ca1967d125..8f22a2c311a 100644 --- a/src/madness/mra/mra.h +++ b/src/madness/mra/mra.h @@ -716,15 +716,7 @@ namespace madness { /// Since reconstruction/compression do not discard information we define them /// as const ... "logical constness" not "bitwise constness". const Function& compress(bool fence = true) const { - PROFILE_MEMBER_FUNC(Function); - if (!impl || is_compressed()) return *this; - if (VERIFY_TREE) verify_tree(); - if (impl->is_nonstandard() or impl->is_nonstandard_with_leaves()) { - impl->standard(fence); - } else { - const_cast*>(this)->impl->compress(TreeState::compressed, fence); - } - return *this; + return change_tree_state(compressed,fence); } @@ -737,21 +729,12 @@ namespace madness { /// /// Noop if already compressed or if not initialized. void make_nonstandard(bool keepleaves, bool fence=true) const { - PROFILE_MEMBER_FUNC(Function); - verify(); - if (impl->is_nonstandard()) return; - if (impl->is_nonstandard_with_leaves()) return; - - if (VERIFY_TREE) verify_tree(); - if (!is_reconstructed()) reconstruct(); TreeState newstate=TreeState::nonstandard; if (keepleaves) newstate=nonstandard_with_leaves; -// impl->compress(true, keepleaves, false, fence); - const_cast*>(this)->impl->compress(newstate, fence); - + change_tree_state(newstate,fence); } - /// Converts the function from nonstandard form to standard form. Possible non-blocking comm. + /// Converts the function standard compressed form. Possible non-blocking comm. /// By default fence=true meaning that this operation completes before returning, /// otherwise if fence=false it returns without fencing and the user must invoke @@ -760,11 +743,7 @@ namespace madness { /// /// Must be already compressed. void standard(bool fence = true) { - PROFILE_MEMBER_FUNC(Function); - verify(); - MADNESS_ASSERT(impl->is_nonstandard() or impl->is_nonstandard_with_leaves()); - impl->standard(fence); - if (fence && VERIFY_TREE) verify_tree(); + change_tree_state(compressed,fence); } /// Converts the function to redundant form, i.e. sum coefficients on all levels @@ -776,10 +755,7 @@ namespace madness { /// /// Must be already compressed. void make_redundant(bool fence = true) { - PROFILE_MEMBER_FUNC(Function); - verify(); change_tree_state(redundant, fence); - if (fence && VERIFY_TREE) verify_tree(); } /// Reconstructs the function, transforming into scaling function basis. Possible non-blocking comm. @@ -794,11 +770,7 @@ namespace madness { /// Since reconstruction/compression do not discard information we define them /// as const ... "logical constness" not "bitwise constness". const Function& reconstruct(bool fence = true) const { - PROFILE_MEMBER_FUNC(Function); - if (!impl || impl->is_reconstructed()) return *this; - change_tree_state(reconstructed, fence); - if (fence && VERIFY_TREE) verify_tree(); // Must be after in case nonstandard - return *this; + return change_tree_state(reconstructed, fence); } /// changes tree state to given state @@ -810,107 +782,15 @@ namespace madness { const Function& change_tree_state(const TreeState finalstate, bool fence = true) const { PROFILE_MEMBER_FUNC(Function); if (not impl) return *this; - TreeState current_state=impl->get_tree_state(); - if (finalstate==current_state) return *this; - MADNESS_CHECK_THROW(current_state!=TreeState::unknown,"unknown tree state"); - - // very special case - if (impl->get_tree_state()==nonstandard_after_apply) { - MADNESS_CHECK(finalstate==reconstructed); - impl->reconstruct(fence); - current_state=impl->get_tree_state(); - } - MADNESS_CHECK_THROW(current_state!=TreeState::nonstandard_after_apply,"unknown tree state"); - bool must_fence=false; - - if (finalstate==reconstructed) { - if (current_state==reconstructed) return *this; - if (current_state==compressed) impl->reconstruct(fence); - if (current_state==nonstandard) impl->reconstruct(fence); - if (current_state==nonstandard_with_leaves) impl->remove_internal_coefficients(fence); - if (current_state==redundant) impl->remove_internal_coefficients(fence); - impl->set_tree_state(reconstructed); - } else if (finalstate==compressed) { - if (current_state==reconstructed) impl->compress(compressed,fence); - if (current_state==compressed) return *this; - if (current_state==nonstandard) impl->standard(fence); - if (current_state==nonstandard_with_leaves) impl->standard(fence); - if (current_state==redundant) { - impl->remove_internal_coefficients(true); - must_fence=true; - impl->set_tree_state(reconstructed); - impl->compress(compressed,fence); - } - impl->set_tree_state(compressed); - } else if (finalstate==nonstandard) { - if (current_state==reconstructed) impl->compress(nonstandard,fence); - if (current_state==compressed) { - impl->reconstruct(true); - must_fence=true; - impl->compress(nonstandard,fence); - } - if (current_state==nonstandard) return *this; - if (current_state==nonstandard_with_leaves) impl->remove_leaf_coefficients(fence); - if (current_state==redundant) { - impl->remove_internal_coefficients(true); - must_fence=true; - impl->set_tree_state(reconstructed); - impl->compress(nonstandard,fence); - } - impl->set_tree_state(nonstandard); - } else if (finalstate==nonstandard_with_leaves) { - if (current_state==reconstructed) impl->compress(nonstandard_with_leaves,fence); - if (current_state==compressed) { - impl->reconstruct(true); - must_fence=true; - impl->compress(nonstandard_with_leaves,fence); - } - if (current_state==nonstandard) { - impl->standard(true); - must_fence=true; - impl->reconstruct(true); - impl->compress(nonstandard_with_leaves,fence); - } - if (current_state==nonstandard_with_leaves) return *this; - if (current_state==redundant) { - impl->remove_internal_coefficients(true); - must_fence=true; - impl->set_tree_state(reconstructed); - impl->compress(nonstandard_with_leaves,fence); - } - impl->set_tree_state(nonstandard_with_leaves); - } else if (finalstate==redundant) { - if (current_state==reconstructed) impl->make_redundant(fence); - if (current_state==compressed) { - impl->reconstruct(true); - must_fence=true; - impl->make_redundant(fence); - } - if (current_state==nonstandard) { - impl->standard(true); - must_fence=true; - impl->reconstruct(true); - impl->make_redundant(fence); - } - if (current_state==nonstandard_with_leaves) { - impl->remove_internal_coefficients(true); - must_fence=true; - impl->set_tree_state(reconstructed); - impl->make_redundant(fence); - } - if (current_state==redundant) return *this; - impl->set_tree_state(redundant); - } else { - MADNESS_EXCEPTION("unknown/unsupported final tree state",1); - } - if (must_fence and world().rank()==0) { - print("could not respect fence in change_tree_state"); - } - if (fence && VERIFY_TREE) verify_tree(); // Must be after in case nonstandard + TreeState current_state = impl->get_tree_state(); + if (finalstate == current_state) return *this; + MADNESS_CHECK_THROW(current_state != TreeState::unknown, "unknown tree state"); + + impl->change_tree_state(finalstate, fence); + if (fence && VERIFY_TREE) verify_tree(); return *this; } - /// Sums scaling coeffs down tree restoring state with coeffs only at leaves. Optional fence. Possible non-blocking comm. void sum_down(bool fence = true) const { PROFILE_MEMBER_FUNC(Function); @@ -2233,16 +2113,6 @@ namespace madness { //result.get_impl()->recursive_apply(op, f.get_impl().get(), // r1.get_impl().get(),true); // will fence here -// result.world().gop.fence(); -// result.print_size("result before finalization"); -// double time=result.get_impl()->finalize_apply(fence); // need fence before reconstruction -// result.world().gop.fence(); -// if (print_timings) { -// result.get_impl()->print_timer(); -// op.print_timer(); -// if (result.world().rank()==0) print("time in finlize_apply", time); -// } - } return result; @@ -2287,6 +2157,7 @@ namespace madness { fff.get_impl()->timer_compress_svd.print("compress_svd"); } result = apply_only(op, fff, fence); + result.get_impl()->set_tree_state(nonstandard_after_apply); ff.world().gop.fence(); if (print_timings) result.print_size("result after apply_only"); diff --git a/src/madness/mra/mraimpl.h b/src/madness/mra/mraimpl.h index c1f54f7729b..333dfb16d59 100644 --- a/src/madness/mra/mraimpl.h +++ b/src/madness/mra/mraimpl.h @@ -1505,6 +1505,111 @@ namespace madness { } } + /// change the tree state of this function, might or might not respect fence! + template + void FunctionImpl::change_tree_state(const TreeState finalstate, bool fence) { + + TreeState current_state=get_tree_state(); + if (current_state==finalstate) return; + + // very special case + if (get_tree_state()==nonstandard_after_apply) { + MADNESS_CHECK(finalstate==reconstructed); + reconstruct(fence); + return; + } + MADNESS_CHECK_THROW(current_state!=TreeState::nonstandard_after_apply,"unknown tree state"); + bool must_fence=false; + + if (finalstate==reconstructed) { + if (current_state==reconstructed) return; + if (current_state==compressed) reconstruct(fence); + if (current_state==nonstandard) reconstruct(fence); + if (current_state==nonstandard_with_leaves) remove_internal_coefficients(fence); + if (current_state==redundant) remove_internal_coefficients(fence); + set_tree_state(reconstructed); + } else if (finalstate==compressed) { + if (current_state==reconstructed) compress(compressed,fence); + if (current_state==compressed) return; + if (current_state==nonstandard) standard(fence); + if (current_state==nonstandard_with_leaves) standard(fence); + if (current_state==redundant) { + remove_internal_coefficients(true); + must_fence=true; + set_tree_state(reconstructed); + compress(compressed,fence); + } + set_tree_state(compressed); + } else if (finalstate==nonstandard) { + if (current_state==reconstructed) compress(nonstandard,fence); + if (current_state==compressed) { + reconstruct(true); + must_fence=true; + compress(nonstandard,fence); + } + if (current_state==nonstandard) return; + if (current_state==nonstandard_with_leaves) remove_leaf_coefficients(fence); + if (current_state==redundant) { + remove_internal_coefficients(true); + must_fence=true; + set_tree_state(reconstructed); + compress(nonstandard,fence); + } + set_tree_state(nonstandard); + } else if (finalstate==nonstandard_with_leaves) { + if (current_state==reconstructed) compress(nonstandard_with_leaves,fence); + if (current_state==compressed) { + reconstruct(true); + must_fence=true; + compress(nonstandard_with_leaves,fence); + } + if (current_state==nonstandard) { + standard(true); + must_fence=true; + reconstruct(true); + compress(nonstandard_with_leaves,fence); + } + if (current_state==nonstandard_with_leaves) return; + if (current_state==redundant) { + remove_internal_coefficients(true); + must_fence=true; + set_tree_state(reconstructed); + compress(nonstandard_with_leaves,fence); + } + set_tree_state(nonstandard_with_leaves); + } else if (finalstate==redundant) { + if (current_state==reconstructed) make_redundant(fence); + if (current_state==compressed) { + reconstruct(true); + must_fence=true; + make_redundant(fence); + } + if (current_state==nonstandard) { + standard(true); + must_fence=true; + reconstruct(true); + make_redundant(fence); + } + if (current_state==nonstandard_with_leaves) { + remove_internal_coefficients(true); + must_fence=true; + set_tree_state(reconstructed); + make_redundant(fence); + } + if (current_state==redundant) return; + set_tree_state(redundant); + } else { + MADNESS_EXCEPTION("unknown/unsupported final tree state",1); + } + if (must_fence and world.rank()==0) { + print("could not respect fence in change_tree_state"); + } + if (fence && VERIFY_TREE) verify_tree(); // Must be after in case nonstandard + return; + } + + + template void FunctionImpl::reconstruct(bool fence) { @@ -1841,7 +1946,7 @@ namespace madness { double end=wall_time(); double elapsed=end-begin; - set_tree_state(nonstandard); + set_tree_state(nonstandard_after_apply); if (fence) world.gop.fence(); return elapsed; } diff --git a/src/madness/mra/operator.h b/src/madness/mra/operator.h index 5344bd94d94..b76e12a7f07 100644 --- a/src/madness/mra/operator.h +++ b/src/madness/mra/operator.h @@ -1757,19 +1757,7 @@ namespace madness { int k=FunctionDefaults<3>::get_k()) { - const Tensor& cell_width = FunctionDefaults<3>::get_cell_width(); - double hi = cell_width.normf(); // Diagonal width of cell - if (bc(0,0) == BC_PERIODIC) hi *= 100; // Extend range for periodic summation - - GFit fit=GFit::CoulombFit(lo,hi,eps,false); - Tensor coeff=fit.coeffs(); - Tensor expnt=fit.exponents(); - - - if (bc(0,0) == BC_PERIODIC) { - fit.truncate_periodic_expansion(coeff, expnt, cell_width.max(), true); - } - return SeparatedConvolution(world, coeff, expnt, lo, eps, bc, k); + return SeparatedConvolution(world,OperatorInfo(0.0,lo,eps,OT_G12),bc,k); } @@ -1782,17 +1770,7 @@ namespace madness { const BoundaryConditions<3>& bc=FunctionDefaults<3>::get_bc(), int k=FunctionDefaults<3>::get_k()) { - const Tensor& cell_width = FunctionDefaults<3>::get_cell_width(); - double hi = cell_width.normf(); // Diagonal width of cell - if (bc(0,0) == BC_PERIODIC) hi *= 100; // Extend range for periodic summation - GFit fit=GFit::CoulombFit(lo,hi,eps,false); - Tensor coeff=fit.coeffs(); - Tensor expnt=fit.exponents(); - - if (bc(0,0) == BC_PERIODIC) { - fit.truncate_periodic_expansion(coeff, expnt, cell_width.max(), true); - } - return new SeparatedConvolution(world, coeff, expnt, lo, eps, bc, k); + return new SeparatedConvolution(world,OperatorInfo(0.0,lo,eps,OT_G12),bc,k); } @@ -1898,6 +1876,13 @@ namespace madness { return SeparatedConvolution(world,OperatorInfo(mu,lo,eps,OT_F212),bc,k); } + static inline SeparatedConvolution* SlaterF12sqOperatorPtr(World& world, + double mu, double lo, double eps, + const BoundaryConditions<3>& bc=FunctionDefaults<3>::get_bc(), + int k=FunctionDefaults<3>::get_k()) { + return new SeparatedConvolution(world,OperatorInfo(mu,lo,eps,OT_F212),bc,k); + } + /// Factory function generating separated kernel for convolution with exp(-mu*r) in 3D static inline SeparatedConvolution SlaterOperator(World& world, double mu, double lo, double eps, From ed21aa1a4401c7cff73d4bee65eea615a22537fb Mon Sep 17 00:00:00 2001 From: fbischoff Date: Fri, 27 Oct 2023 23:41:28 +0200 Subject: [PATCH 061/109] making mp2 work again --- src/apps/mp2/mp2.cc | 1 + src/madness/chem/CCPotentials.cc | 1 - src/madness/chem/CCStructures.cc | 101 +++---------------------------- src/madness/chem/CCStructures.h | 25 ++++---- src/madness/mra/operator.h | 35 ++++++++++- 5 files changed, 53 insertions(+), 110 deletions(-) diff --git a/src/apps/mp2/mp2.cc b/src/apps/mp2/mp2.cc index b15de2ba34c..154919f1f76 100644 --- a/src/apps/mp2/mp2.cc +++ b/src/apps/mp2/mp2.cc @@ -88,6 +88,7 @@ int main(int argc, char** argv) { hf_energy,mp2_energy,hf_energy+mp2_energy); } double mp3_correction=mp2.mp3(); + print("mp3 correction",mp3_correction); double mp3_energy=mp3_correction+mp2_energy; if(world.rank() == 0) { diff --git a/src/madness/chem/CCPotentials.cc b/src/madness/chem/CCPotentials.cc index b5de6c1b837..0bb0d150d1b 100644 --- a/src/madness/chem/CCPotentials.cc +++ b/src/madness/chem/CCPotentials.cc @@ -3420,7 +3420,6 @@ void CCPotentials::test() { CCState test5 = GROUND_STATE; PotentialType test6 = POT_F3D_; assign_name(test2); - assign_name(test3); assign_name(test4); assign_name(test5); assign_name(test6); diff --git a/src/madness/chem/CCStructures.cc b/src/madness/chem/CCStructures.cc index 7181a6b8acf..44cbed09443 100644 --- a/src/madness/chem/CCStructures.cc +++ b/src/madness/chem/CCStructures.cc @@ -304,7 +304,7 @@ CCConvolutionOperator::operator()(const CCFunction& bra, const CCFunction& ket, real_function_3d result; if (not use_im) { if (world.rank() == 0) - std::cout << "Recalculating <" << bra.name() << "|" << assign_name(operator_type) << "|" << ket.name() + std::cout << "Recalculating <" << bra.name() << "|" << name() << "|" << ket.name() << ">\n"; result = ((*op)(bra.function * ket.function)).truncate(); } else if (bra.type == HOLE and ket.type == HOLE and not imH.allpairs.empty()) result = imH(bra.i, ket.i); @@ -321,18 +321,16 @@ CCConvolutionOperator::operator()(const CCFunction& bra, const CCFunction& ket, } real_function_6d CCConvolutionOperator::operator()(const real_function_6d& u, const size_t particle) const { - MADNESS_ASSERT(particle == 1 or particle == 2); - MADNESS_ASSERT(operator_type == OpType::OT_G12); - MADNESS_ASSERT(op); + MADNESS_CHECK(particle == 1 or particle == 2); + MADNESS_CHECK(op); op->particle() = particle; return (*op)(u); } real_function_3d CCConvolutionOperator::operator()(const CCFunction& bra, const real_function_6d& u, const size_t particle) const { - MADNESS_ASSERT(particle == 1 or particle == 2); - MADNESS_ASSERT(operator_type == OpType::OT_G12); - MADNESS_ASSERT(op); + MADNESS_CHECK(particle == 1 or particle == 2); + MADNESS_CHECK(op); const real_function_6d tmp = multiply(copy(u), copy(bra.function), particle); op->particle() = particle; const real_function_6d g_tmp = (*op)(tmp); @@ -348,7 +346,7 @@ void CCConvolutionOperator::update_elements(const CC_vecfunction& bra, const CC_ << std::endl; if (bra.type != HOLE) error("Can not create intermediate of type " + operation_name + " , bra-element has to be of type HOLE"); - op.reset(init_op(operator_type, parameters)); + op.reset(init_op(type(), parameters)); intermediateT xim; for (auto tmpk : bra.functions) { const CCFunction& k = tmpk.second; @@ -408,60 +406,8 @@ SeparatedConvolution * CCConvolutionOperator::init_op(const OpType& type, const Parameters& parameters) const { bool debug=false; bool printme=(world.rank()==0) and debug; - switch (type) { - case OpType::OT_G12 : { - if (printme) - std::cout << "Creating " << assign_name(type) << " Operator with thresh=" << parameters.thresh_op - << " and lo=" << parameters.lo << std::endl; - return CoulombOperatorPtr(world, parameters.lo, parameters.thresh_op); - } - case OpType::OT_F12 : { - if (printme) - std::cout << "Creating " << assign_name(type) << " Operator with thresh=" << parameters.thresh_op - << " and lo=" << parameters.lo << " and Gamma=" << parameters.gamma << std::endl; - return SlaterF12OperatorPtr(world, parameters.gamma, parameters.lo, parameters.thresh_op); - } - case OpType::OT_F212 : { - if (printme) - std::cout << "Creating " << assign_name(type) << " Operator with thresh=" << parameters.thresh_op - << " and lo=" << parameters.lo << " and Gamma=" << parameters.gamma << std::endl; - return SlaterF12sqOperatorPtr(world, parameters.gamma, parameters.lo, parameters.thresh_op); - } - case OpType::OT_SLATER : { - if (printme) - std::cout << "Creating " << assign_name(type) << " Operator with thresh=" << parameters.thresh_op - << " and lo=" << parameters.lo << " and Gamma=" << parameters.gamma << std::endl; - return SlaterOperatorPtr(world, parameters.gamma, parameters.lo, parameters.thresh_op); - } - case OpType::OT_BSH : { - if (printme) - std::cout << "Creating " << assign_name(type) << " Operator with thresh=" << parameters.thresh_op - << " and lo=" << parameters.lo << " and Gamma=" << parameters.gamma << std::endl; - return BSHOperatorPtr3D(world, parameters.gamma, parameters.lo, parameters.thresh_op); - } - case OpType::OT_FG12: { - if (printme) - std::cout << "Creating " << assign_name(type) << " Operator with thresh=" << parameters.thresh_op - << " and lo=" << parameters.lo << " and Gamma=" << parameters.gamma << std::endl; - return FGOperatorPtr(world, parameters.gamma, parameters.lo, parameters.thresh_op); - } - case OpType::OT_F2G12: { - if (printme) - std::cout << "Creating " << assign_name(type) << " Operator with thresh=" << parameters.thresh_op - << " and lo=" << parameters.lo << " and Gamma=" << parameters.gamma << std::endl; - return F2GOperatorPtr(world, parameters.gamma, parameters.lo, parameters.thresh_op); - } - case OpType::OT_ONE : { - if (printme) - std::cout << "Creating " << assign_name(type) << " Operator " << std::endl; - return nullptr; - } - default : { - error("Unknown operatorype " + assign_name(type)); - MADNESS_EXCEPTION("error", 1); - } - } - + print("init_op: creating",type,"with thresh, lo, gamma",parameters.thresh_op,parameters.gamma,parameters.lo); + return new SeparatedConvolution(world,OperatorInfo(parameters.gamma,parameters.lo,parameters.thresh_op,type)); } /// Assigns strings to enums for formated output @@ -481,37 +427,6 @@ assign_name(const CCState& input) { return "unknown pairtype"; } -/// Assigns strings to enums for formated output -std::string -assign_name(const OpType& input) { - switch (input) { - case OpType::OT_G12: - return "g12"; - case OpType::OT_F12: - return "f12"; - case OpType::OT_SLATER: - return "slater"; - case OpType::OT_FG12: - return "fg12"; - case OpType::OT_BSH: - return "bsh"; - case OpType::OT_ONE: - return "identity"; - case OpType::OT_GAUSS: /// exp(-r2) - return "gauss"; - case OpType::OT_F212: /// (1-exp(-r))^2 - return "f12^2"; - case OpType::OT_F2G12: /// (1-exp(-r))^2/r = 1/r + exp(-2r)/r - 2 exp(-r)/r - return "f12^2g"; - default: { - MADNESS_EXCEPTION("Unvalid enum assignement!", 1); - return "undefined"; - } - } - MADNESS_EXCEPTION("assign_name:optype, should not end up here", 1); - return "unknown operatortype"; -} - /// Assigns enum to string CalcType assign_calctype(const std::string name) { diff --git a/src/madness/chem/CCStructures.h b/src/madness/chem/CCStructures.h index d214a2f996d..4210e491313 100644 --- a/src/madness/chem/CCStructures.h +++ b/src/madness/chem/CCStructures.h @@ -54,10 +54,6 @@ enum PotentialType { std::string assign_name(const CCState& input); -/// Assigns strings to enums for formated output -std::string -assign_name(const OpType& input); - /// Assigns enum to string CalcType assign_calctype(const std::string name); @@ -722,8 +718,7 @@ struct CCConvolutionOperator { /// @param[in] optype: the operatortype (can be g12_ or f12_) /// @param[in] param: the parameters of the current CC-Calculation (including function and operator thresholds and the exponent for f12) CCConvolutionOperator(World& world, const OpType type, Parameters param) : parameters(param), world(world), - operator_type(type), - op(init_op(operator_type, parameters)) { + op(init_op(type, parameters)) { } CCConvolutionOperator(const CCConvolutionOperator& other) = default; @@ -806,7 +801,11 @@ struct CCConvolutionOperator { void update_elements(const CC_vecfunction& bra, const CC_vecfunction& ket); /// @param[out] prints the name of the operator (convenience) which is g12 or f12 or maybe other things like gf in the future - std::string name() const { return assign_name(operator_type); } + std::string name() const { + std::stringstream ss; + ss << type(); + return ss.str(); + } /// @param[in] the type of which intermediates will be deleted /// e.g if(type==HOLE) then all intermediates of type will be deleted @@ -822,15 +821,15 @@ struct CCConvolutionOperator { void print_intermediate(const FuncType type) const { if (type == HOLE) for (const auto& tmp:imH.allpairs) - tmp.second.print_size(" intermediate"); else if (type == PARTICLE) for (const auto& tmp:imP.allpairs) - tmp.second.print_size(" intermediate"); else if (type == RESPONSE) for (const auto& tmp:imR.allpairs) - tmp.second.print_size(" intermediate"); } @@ -844,7 +843,7 @@ struct CCConvolutionOperator { return TwoElectronFactory(world); } - OpType type() const { return operator_type; } + OpType type() const { return get_op()->info.type; } const Parameters parameters; @@ -853,8 +852,6 @@ struct CCConvolutionOperator { private: /// the world World& world; - /// the operatortype, currently this can be g12_ or f12_ - const OpType operator_type = OpType::OT_UNDEFINED; /// @param[in] optype: can be f12_ or g12_ depending on which operator shall be intitialzied /// @param[in] parameters: parameters (thresholds etc) @@ -870,7 +867,7 @@ struct CCConvolutionOperator { /// the function will throw an MADNESS_EXCEPTION void error(const std::string& msg) const { if (world.rank() == 0) - std::cout << "\n\n!!!!ERROR in CCConvolutionOperator " << assign_name(operator_type) << ": " << msg + std::cout << "\n\n!!!!ERROR in CCConvolutionOperator " << name() << ": " << msg << "!!!!!\n\n" << std::endl; MADNESS_EXCEPTION(msg.c_str(), 1); } diff --git a/src/madness/mra/operator.h b/src/madness/mra/operator.h index b76e12a7f07..91f0573b177 100644 --- a/src/madness/mra/operator.h +++ b/src/madness/mra/operator.h @@ -139,10 +139,41 @@ namespace madness { OT_BSH /// exp(-r)/r }; + /// operator type to string + template // dummy template argument to avoid ambiguity with the other operator<< + std::ostream& operator<<(std::ostream& os, const OpType type) { + auto name = [](OpType type) { + switch (type) { + case OpType::OT_UNDEFINED: + return "undefined"; + case OpType::OT_ONE: + return "identity"; + case OpType::OT_G12: + return "g12"; + case OpType::OT_SLATER: + return "slater"; + case OpType::OT_GAUSS: + return "gauss"; + case OpType::OT_F12: + return "f12"; + case OpType::OT_FG12: + return "fg12"; + case OpType::OT_F212: + return "f12^2"; + case OpType::OT_F2G12: + return "f12^2g"; + case OpType::OT_BSH: + return "bsh"; + default: + return "undefined"; + } + }; + os << name(type); + return os; + } + struct OperatorInfo { OperatorInfo() = default; -// template -// OperatorInfo(double mu, double lo=1.e-5, double thresh=FunctionDefaults::get_thresh()) : mu(mu), thresh(thresh), lo(lo) {} OperatorInfo(double mu, double lo, double thresh, OpType type) : mu(mu), thresh(thresh), lo(lo), type(type) {} OpType type=OT_UNDEFINED; ///< introspection double mu=0.0; ///< some introspection From 349d21c09c9a07a0633272c8e3563a594c085841 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Sat, 28 Oct 2023 23:48:42 +0200 Subject: [PATCH 062/109] fix compilation error --- src/examples/heat.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/examples/heat.cc b/src/examples/heat.cc index 8e154b1570e..a9e59fa3de2 100644 --- a/src/examples/heat.cc +++ b/src/examples/heat.cc @@ -130,7 +130,9 @@ int main(int argc, char** argv) { expnt[0] = 1.0/(4.0*c*tstep); coeff[0] = pow(4.0*constants::pi*c*tstep,-1.5); - operatorT G(world, coeff, expnt); + double lo_dummy=1.e-4; + double thresh_dummy=1.e-6; + operatorT G(world, coeff, expnt, lo_dummy, thresh_dummy); functionT ut = G(u0); From 1d8085544f076858890c703f24f473eaf1c434f1 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Sun, 29 Oct 2023 20:59:16 +0100 Subject: [PATCH 063/109] fix compilation error --- src/examples/heat2.cc | 2 +- src/examples/tdse_example.cc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/examples/heat2.cc b/src/examples/heat2.cc index d7e9f1d1040..6d2cfdfec04 100644 --- a/src/examples/heat2.cc +++ b/src/examples/heat2.cc @@ -147,7 +147,7 @@ int main(int argc, char** argv) { real_tensor expnt(1), coeff(1); expnt[0] = 1.0/(4.0*c*tstep*0.5); coeff[0] = pow(4.0*constants::pi*c*tstep*0.5,-1.5); - real_convolution_3d G(world, coeff, expnt); + real_convolution_3d G(world, coeff, expnt, 1.e-4, 1.e-4); // Propagate forward 50 time steps real_function_3d u = u0; diff --git a/src/examples/tdse_example.cc b/src/examples/tdse_example.cc index 49a71c56373..fbc08fdc099 100644 --- a/src/examples/tdse_example.cc +++ b/src/examples/tdse_example.cc @@ -175,7 +175,7 @@ void converge(World& world, functionT& potn, functionT& psi, double& eps) { Tensor coeff(1); coeff[0] = 1.0/pow(constants::pi*tmax,1.5); Tensor expnt(1); expnt[0] = 1.0/tmax; - operatorT* op = new operatorT(world,coeff,expnt); + operatorT* op = new operatorT(world,coeff,expnt,0.0,0.0); for (int iter=0; iter<20; iter++) { if (world.rank() == 0) print("ITER",iter); @@ -197,7 +197,7 @@ void converge(World& world, functionT& potn, functionT& psi, double& eps) { delete op; coeff[0] = 1.0/sqrt(constants::pi*tmax); expnt[0] = 1.0/tmax; - op = new operatorT(world,coeff,expnt); + op = new operatorT(world,coeff,expnt,0.0,0.0); } } delete op; From 2ea3722678f057ed7e98527d4facb671d8c8c9a1 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Sat, 18 Nov 2023 21:38:09 +0100 Subject: [PATCH 064/109] more on mp3 --- src/madness/chem/CCStructures.cc | 2 +- src/madness/chem/ccpairfunction.cc | 56 +- src/madness/chem/ccpairfunction.h | 26 +- src/madness/chem/mp2.cc | 201 ++++--- src/madness/mra/CMakeLists.txt | 2 +- src/madness/mra/function_factory.h | 839 ++++++++++++++------------- src/madness/mra/function_interface.h | 32 + src/madness/mra/gfit.h | 25 + src/madness/mra/mra.h | 46 +- src/madness/mra/operator.h | 73 +-- src/madness/mra/operatorinfo.h | 70 +++ 11 files changed, 757 insertions(+), 615 deletions(-) create mode 100644 src/madness/mra/operatorinfo.h diff --git a/src/madness/chem/CCStructures.cc b/src/madness/chem/CCStructures.cc index 44cbed09443..e67e92e17e5 100644 --- a/src/madness/chem/CCStructures.cc +++ b/src/madness/chem/CCStructures.cc @@ -404,7 +404,7 @@ size_t CCConvolutionOperator::info() const { SeparatedConvolution * CCConvolutionOperator::init_op(const OpType& type, const Parameters& parameters) const { - bool debug=false; + bool debug=true; bool printme=(world.rank()==0) and debug; print("init_op: creating",type,"with thresh, lo, gamma",parameters.thresh_op,parameters.gamma,parameters.lo); return new SeparatedConvolution(world,OperatorInfo(parameters.gamma,parameters.lo,parameters.thresh_op,type)); diff --git a/src/madness/chem/ccpairfunction.cc b/src/madness/chem/ccpairfunction.cc index 81a99235dc1..54d83236d13 100644 --- a/src/madness/chem/ccpairfunction.cc +++ b/src/madness/chem/ccpairfunction.cc @@ -195,6 +195,19 @@ CCPairFunction inner(const CCPairFunction& c1, const CCPairFunction& c2, return c1.partial_inner(c2,v11,v22); } +std::vector inner(const std::vector& c1, + const std::vector& c2, + const std::tuple v1, const std::tuple v2) { + std::vector result; + for (const auto& cc1 : c1) { + for (const auto& cc2 : c2) { + print("inner of ",cc1.name(), cc2.name()); + result.push_back(inner(cc1,cc2,v1,v2)); + } + } + return result; +} + CCPairFunction CCPairFunction::partial_inner(const CCPairFunction& other, const std::array& v1, const std::array& v2) const { @@ -397,36 +410,23 @@ double CCPairFunction::inner_internal(const CCPairFunction& other, const real_fu if (f1.is_pure() and f2.is_pure()) { // these are 4 combinations pure/pure pureT bra=f1.get_function(); pureT ket=f2.get_function(); -// if (R2.is_initialized()) { -// real_function_6d R1u = multiply(::copy(f1.pure().get_function()), ::copy(R2), 1); -// real_function_6d R1R2u = multiply(R1u, ::copy(R2), 2); // R1u function now broken -// bra = R1R2u; -// } // include the operator(s), if any - if (f1.has_operator() or f2.has_operator()) { - MADNESS_EXCEPTION("still to debug",1); -// auto ops=combine(f1.get_operator_ptr(),f2.get_operator_ptr()); -// for (const auto& single_op : ops) { -// auto fac=single_op.first; -// auto op=single_op.second; -// double bla=0.0; -// if (op.get_op()) { -// real_function_6d tmp1; -// if (R2.is_initialized()) { -// tmp1= CompositeFactory(world()).g12(op.get_kernel()).ket(ket).particle1(R2).particle2(R2); -// } else { -// tmp1= CompositeFactory(world()).g12(op.get_kernel()).ket(ket); -// } -// bla=fac*inner(bra,tmp1); -// } else { -// bla=fac*inner(bra,ket); -// } -// result+=bla; -// } + auto op=combine(f1.get_operator_ptr(),f2.get_operator_ptr()); + real_function_6d tmp1; + if (op) { + if (R2.is_initialized()) { + tmp1 = CompositeFactory(world()).g12(op->get_kernel()).ket(ket).particle1(R2).particle2(R2); + } else { + tmp1 = CompositeFactory(world()).g12(op->get_kernel()).ket(ket); + } } else { - // no operators - result=inner(bra,ket); + if (R2.is_initialized()) { + tmp1 = CompositeFactory(world()).ket(ket).particle1(R2).particle2(R2); + } else { + tmp1 = CompositeFactory(world()).ket(ket); + } } + result=inner(bra,tmp1); } else if (f1.is_pure() and f2.is_decomposed()) { // with or without operator const vector_real_function_3d a = R2.is_initialized() ? R2 * f2.get_a() : copy(world(), f2.get_a()); const vector_real_function_3d b = R2.is_initialized() ? R2 * f2.get_b() : copy(world(), f2.get_b()); @@ -593,6 +593,7 @@ std::vector apply(const SeparatedConvolution& op, const if (argument.size()==0) return argument; World& world=argument.front().world(); std::vector result; + timer t(world); for (const auto& arg : argument) { if (arg.is_pure()) { result.push_back(CCPairFunction(op(arg.get_function()))); @@ -612,6 +613,7 @@ std::vector apply(const SeparatedConvolution& op, const auto tmp=arg.to_pure(); result.push_back(apply(op,tmp)); } + t.tag("applying op to CCPairFunction "+arg.name()); } return result; diff --git a/src/madness/chem/ccpairfunction.h b/src/madness/chem/ccpairfunction.h index 32d13fc2e60..56bc10bface 100644 --- a/src/madness/chem/ccpairfunction.h +++ b/src/madness/chem/ccpairfunction.h @@ -8,6 +8,7 @@ #include +#include #include #include #include @@ -427,7 +428,13 @@ using pureT=Function; friend std::vector multiply(const std::vector& other, const real_function_3d f, const std::array& v1) { std::vector result; - for (auto& o : other) result.push_back(multiply(o,f,v1)); + for (auto& o : other) { + double cpu0=cpu_time(); + std::cout << "multiply " << o.name(); + result.push_back(multiply(o,f,v1)); + double cpu1=cpu_time(); + std::cout << " done after " << cpu1-cpu0 << std::endl; + } return result; } @@ -602,22 +609,25 @@ using pureT=Function; template friend CCPairFunction apply(const SeparatedConvolution& G, const CCPairFunction& argument) { + CCPairFunction result; + timer t1(argument.world()); if (argument.is_pure()) { - return CCPairFunction(G(argument.get_function())); + result=CCPairFunction(G(argument.get_function())); } else if (argument.is_decomposed_no_op()) { - real_function_6d result=real_factory_6d(argument.world()).compressed(); + real_function_6d result1=real_factory_6d(argument.world()).compressed(); MADNESS_ASSERT(argument.get_a().size() == argument.get_b().size()); for (size_t k = 0; k < argument.get_a().size(); k++) { const real_function_6d tmp = G(argument.get_a()[k], argument.get_b()[k]); - result += tmp; + result1 += tmp; } - return CCPairFunction(result); + result=CCPairFunction(result1); } else { MADNESS_EXCEPTION("unknown type in CCPairFunction::apply",1); } - return CCPairFunction(); + t1.end("applying G to " + argument.name()); + return result; }; real_function_3d partial_inner(const real_function_3d& f, @@ -655,6 +665,10 @@ real_function_3d inner(const CCPairFunction& c, const real_function_3d& f, CCPairFunction inner(const CCPairFunction& c1, const CCPairFunction& c2, const std::tuple v1, const std::tuple v2); +std::vector inner(const std::vector& c1, + const std::vector& c2, + const std::tuple v1, const std::tuple v2); + } // namespace madness #endif //MADNESS_CCPAIRFUNCTION_H diff --git a/src/madness/chem/mp2.cc b/src/madness/chem/mp2.cc index d726e490f75..863f95812e6 100644 --- a/src/madness/chem/mp2.cc +++ b/src/madness/chem/mp2.cc @@ -236,27 +236,12 @@ double MP2::value(const Tensor& x) { return correlation_energy; } - // DEBUG: INTEGRAL TEST - for (int i = param.freeze(); i < hf->nocc(); ++i) { - for (int j = i; j < hf->nocc(); ++j) { - ElectronPair test = make_pair(i, j); - if (world.rank() == 0) { - std::cout << "\n-----------------------------------------\n"; - std::cout << "<" << i << j << "|gQf|" << i << j << "> =" << test.ij_gQf_ij << std::endl; - std::cout << "<" << j << i << "|gQf|" << i << j << "> =" << test.ji_gQf_ij << std::endl; - } - } - } - // DEBUG END - // compute the 0th order term and do some coarse pre-iterations for (int i = param.freeze(); i < hf->nocc(); ++i) { for (int j = i; j < hf->nocc(); ++j) { pairs(i, j) = make_pair(i, j); // initialize - solve_residual_equations(pairs(i, j), param.econv() * 0.5, - param.dconv()); - correlation_energy += pairs(i, j).e_singlet - + pairs(i, j).e_triplet; + solve_residual_equations(pairs(i, j), param.econv() * 0.5, param.dconv()); + correlation_energy += pairs(i, j).e_singlet + pairs(i, j).e_triplet; } } if (world.rank() == 0) { @@ -285,98 +270,137 @@ double MP2::value(const Tensor& x) { double MP2::mp3() const { + print_header2("computing the MP3 correlation energy"); + print_header3("prepare the cluster function"); typedef std::vector ClusterFunction; Pairs clusterfunctions; - double mp3_energy=0.0; - CCTimer t1(world,"make pairs"); + + double mp3_energy = 0.0; + CCTimer t1(world, "make pairs"); // load converged MP1 wave functions for (int i = param.freeze(); i < hf->nocc(); ++i) { for (int j = i; j < hf->nocc(); ++j) { // pairs(i, j) = make_pair(i, j); // initialize ClusterFunction tmp; - tmp.push_back(CCPairFunction(pairs(i,j).function)); - CCPairFunction ij(hf->nemo(i),hf->nemo(j)); + tmp.push_back(CCPairFunction(pairs(i, j).function)); + CCPairFunction ij(hf->nemo(i), hf->nemo(j)); CCConvolutionOperator::Parameters cparam; - cparam.thresh_op*=0.1; - auto f12=CCConvolutionOperatorPtr(world,OpType::OT_F12,cparam); - auto vfij=Q12(std::vector({f12*ij})); - for (auto& p : vfij) tmp.push_back(p); - - clusterfunctions(i,j)=tmp; - print("prep pairs",t1.reset()); + cparam.thresh_op *= 0.1; + auto f12 = CCConvolutionOperatorPtr(world, OpType::OT_F12, cparam); + auto vfij = Q12(std::vector({f12 * ij})); + for (auto& p: vfij) tmp.push_back(p); + + clusterfunctions(i, j) = tmp; + if (i!=j) { + for (const auto& t : clusterfunctions(i,j)) { + clusterfunctions(j, i).push_back(t.swap_particles()); + } + } } } t1.print(); + + for (int i = param.freeze(); i < hf->nocc(); ++i) { + for (int j = i; j < hf->nocc(); ++j) { + print("info of clusterfunction ", i, j); + for (auto& c: clusterfunctions(i, j)) c.info(); + } + } + + print_header3("recompute the MP2 energy"); auto R2 = hf->nemo_ptr->ncf->square(); - CCTimer t2(world,"recompute MP2"); - // recompute MP2 energy CCConvolutionOperator::Parameters cparam; auto g12=CCConvolutionOperatorPtr(world,OpType::OT_G12,cparam); + CCTimer t2(world,"recompute MP2"); + + // recompute MP2 energy + double mp2_energy=0.0; for (int i = param.freeze(); i < hf->nocc(); ++i) { for (int j = i; j < hf->nocc(); ++j) { - auto bra=g12*CCPairFunction(hf->R2orbital(i),hf->R2orbital(j)); - double energy1=inner(bra,clusterfunctions(i,j).front()); - double energy=energy1+pairs(i,j).ij_gQf_ij; - print("MP2 energy: gQf, u",pairs(i,j).ij_gQf_ij,energy1,energy); - print("time compute ",t2.reset()); - - double energy2=inner({bra},clusterfunctions(i,j)); - printf("MP2 energy: cluster %12.8f\n",energy2); - print("time clusterfunction",t2.reset()); + +// auto bra=g12*CCPairFunction(hf->R2orbital(i),hf->R2orbital(j)); +// auto bra=g12*CCPairFunction(hf->nemo(i),hf->nemo(j)); + auto bra=CCPairFunction(hf->nemo(i),hf->nemo(j)); + double direct=inner({bra},g12*clusterfunctions(i,j),R2); + double exchange=inner({bra},g12*clusterfunctions(j,i),R2); + double fac=(i==j) ? 0.5: 1.0; + double pair_energy=fac*(4.0*direct-2.0*exchange); + printf("MP2 energy: cluster %2d %2d: %12.8f\n",i,j,pair_energy); + mp2_energy+=pair_energy; } } + printf("total mp2 energy %12.8f\n",mp2_energy); + print("time clusterfunction",t2.reset()); + +// auto bra0=multiply(clusterfunctions(0,0),hf->nemo_ptr->R_square,{0,1,2}); +// auto G2_tmp=inner(bra0,clusterfunctions(0,0),{0,1,2},{0,1,2}); +// auto bra=g12*CCPairFunction(hf->R2orbital(0),hf->R2orbital(0)); +// double G2=inner({bra},G2_tmp); +// print("G2 ",G2); + + print_header3("compute the MP3 energy"); CCTimer t3(world,"MP3"); // compute the term (2) madness::Pairs gij; for (int i = param.freeze(); i < hf->nocc(); ++i) { - for (int j = i; j < hf->nocc(); ++j) { + for (int j = param.freeze(); j < hf->nocc(); ++j) { gij.insert(i,j,(*g12)(hf->nemo(i)*hf->R2orbital(j))); } } - print("\n compute term1 of the MP3 energy\n"); + print_header3("compute term1 of the MP3 energy"); // compute the MP3 energy double term1=0.0; - if (0) { + if (1) { for (int i = param.freeze(); i < hf->nocc(); ++i) { for (int j = i; j < hf->nocc(); ++j) { auto bra = clusterfunctions(i, j); - double tmp1 = inner(bra, g12 * clusterfunctions(i, j), R2); - double tmp2 = inner(bra, g12 * clusterfunctions(j, i), R2); + double tmp1 = inner(bra, g12 * clusterfunctions(i, j),R2); + double tmp2 = inner(bra, g12 * clusterfunctions(j, i),R2); double fac = (i == j) ? 0.5 : 1.0; double tmp = fac * (4.0 * tmp1 - 2.0 * tmp2); - print("mp3 energy: term1", i, j, tmp); + printf("mp3 energy: term1 %2d %2d: %12.8f\n", i, j, tmp); term1 += tmp; } } } printf("MP3 energy: term1 %12.8f\n",term1); print("time term1",t3.reset()); + print(""); // compute intermediates for terms G, I, H, and J // \sum_j tau_ij(1,2) * phi_j(2) std::vector tau_i_jj(hf->nocc()-param.freeze()); + std::vector tau_i_jj_R2(hf->nocc()-param.freeze()); // \sum_j tau_ij(1,2) * phi_j(1) std::vector tau_ij_j(hf->nocc()-param.freeze()); + std::vector tau_ij_j_R2(hf->nocc()-param.freeze()); for (int i = param.freeze(); i < hf->nocc(); ++i) { for (int j = param.freeze(); j < hf->nocc(); ++j) { auto tmp2=multiply(clusterfunctions(i,j),hf->R2orbital(j),{3,4,5}); - for (auto& t : tmp2) tau_i_jj[i].push_back(t); + for (auto& t : tmp2) tau_i_jj_R2[i].push_back(t); auto tmp4=multiply(clusterfunctions(i,j),hf->R2orbital(j),{0,1,2}); - for (auto& t : tmp4) tau_ij_j[i].push_back(t); + for (auto& t : tmp4) tau_ij_j_R2[i].push_back(t); + + auto tmp1=multiply(clusterfunctions(i,j),hf->nemo(j),{3,4,5}); + for (auto& t : tmp1) tau_i_jj[i].push_back(t); + + auto tmp3=multiply(clusterfunctions(i,j),hf->nemo(j),{0,1,2}); + for (auto& t : tmp3) tau_ij_j[i].push_back(t); } } - print("info on tau_i_jj and tau_ij_j"); + print("info on tau_i_jj"); for (int i = param.freeze(); i < hf->nocc(); ++i) { for (auto& c: tau_i_jj[i]) c.info(); } + print("info on tau_ij_j"); for (int i = param.freeze(); i < hf->nocc(); ++i) { for (auto& c: tau_ij_j[i]) c.info(); } @@ -385,46 +409,69 @@ double MP2::mp3() const { // terms G, I, H, J of Bartlett/Silver 1975 double term2a=0.0; real_convolution_3d& g=*(g12->get_op()); - g.particle()=2; for (int i = param.freeze(); i < hf->nocc(); ++i) { - auto gtau=g(tau_i_jj[i]); - print("info on gtau_i_jj"); - for (auto& g :gtau) g.info(); - double G=inner(gtau,tau_i_jj[i],R2); + timer t4(world,"gtau"); + g.particle()=2; + auto gtau_same=g(tau_i_jj_R2[i]); // < tau_ij(1,2) j(2) | g(2,2') | + t4.tag("compute gtau_same"); + g.particle()=1; + auto gtau_other=g(tau_ij_j_R2[i]); // < tau_ij(1,2) j(1) | g(2,2') | + t4.tag("compute gtau_other"); + +// auto tmp0=multiply(gtau_same,hf->nemo_ptr->R_square,{0,1,2}); +// auto gtau_same_R2=multiply(tmp0,hf->nemo_ptr->R_square,{3,4,5}); +// auto tmp1=multiply(gtau_other,hf->nemo_ptr->R_square,{0,1,2}); +// auto gtau_other_R2=multiply(tmp1,hf->nemo_ptr->R_square,{3,4,5}); + + + double G=inner(gtau_same,tau_i_jj[i],R2); print("G",G); -// double G=inner(tau_i_jj[i],g12*tau_i_jj[i],R2); - double I=inner(tau_i_jj[i],g12*tau_ij_j[i],R2); +// double G2=inner(gtau_same_R2,tau_i_jj[i]); +// print("G_R2",G2); + double I=inner(gtau_same,tau_ij_j[i],R2); print("I",I); - double H=inner(tau_ij_j[i],g12*tau_i_jj[i],R2); +// double I2=inner(gtau_same_R2,tau_ij_j[i]); +// print("I_R2",I2); + double H=inner(gtau_other,tau_i_jj[i],R2); print("H",H); - double J=inner(tau_ij_j[i],g12*tau_ij_j[i],R2); + double J=inner(gtau_other,tau_ij_j[i],R2); print("J",J); + + t4.tag("compute inner products"); double tmp = (8.0 *G - 4.0*I + 2.0* H - 4.0*J); - print("mp3 energy: term2",i,tmp); + printf("mp3 energy: term2a %2d %12.8f\n",i,tmp); term2a+=tmp; } + printf("MP3 energy: term2 (GHIJ) %12.8f\n",term2a); print("time GHIJ ",t3.reset()); double term2=0.0; for (int i = param.freeze(); i < hf->nocc(); ++i) { for (int j = param.freeze(); j < hf->nocc(); ++j) { - auto bra_ij=clusterfunctions(i,j); - double tmp=0.0; for (int k=param.freeze(); knocc(); ++k) { - auto tau_ij_gik = multiply(bra_ij,gij(i,k),{3,4,5}); - auto tau_ij_gjk = multiply(bra_ij,gij(j,k),{3,4,5}); - - double tmp1=2.0*inner(tau_ij_gik,clusterfunctions(k,j),R2) - - inner(tau_ij_gik,clusterfunctions(j,k),R2) - +2.0* inner(tau_ij_gjk,clusterfunctions(i,k),R2) - - inner(tau_ij_gjk,clusterfunctions(k,i),R2); - tmp-=2.0*tmp1; + auto tau_ik=clusterfunctions(i,k); + auto tau_kj=clusterfunctions(k,j); + auto tau_ij=clusterfunctions(i,j); + auto tau_ji=clusterfunctions(j,i); + auto tau_ik_gkj = multiply(tau_ik,gij(k,j),{3,4,5}); + auto tau_kj_gki = multiply(tau_kj,gij(k,i),{3,4,5}); +// auto tau_ik_gkj = multiply(tau_ik,gij(k,j),{0,1,2}); +// auto tau_kj_gki = multiply(tau_kj,gij(k,i),{0,1,2}); + + double K=inner(tau_ij,tau_ik_gkj,R2); + double L=inner(tau_ij,tau_kj_gki,R2); + double M=inner(tau_ji,tau_kj_gki,R2); + double N=inner(tau_ji,tau_ik_gkj,R2); + print("K,L,M,N",K,L,M,N); + + tmp+=-4*K-4*L + 2*M +2*N; } - print("mp3 energy: term2",i,j,tmp); + printf("mp3 energy: term2 %2d %2d %12.8f\n",i,j,tmp); term2+=tmp; } } + printf("MP3 energy: term2 (KLMN) %12.8f\n",term2); print("time term2",t3.reset()); double term3=0.0; @@ -433,23 +480,25 @@ double MP2::mp3() const { double tmp=0.0; for (int k=param.freeze(); knocc(); ++k) { for (int l=param.freeze(); lnocc(); ++l) { - auto bra = clusterfunctions(i,k); - double ovlp1=inner(bra,clusterfunctions(j,l),R2); - double ovlp2=inner(bra,clusterfunctions(l,j),R2); + auto bra_ik = clusterfunctions(i,k); + auto bra_ki = clusterfunctions(k,i); + double ovlp_E=inner(bra_ik,clusterfunctions(j,l),R2); + double ovlp_F=inner(bra_ki,clusterfunctions(j,l),R2); auto ket_i=hf->nemo(i); auto ket_k=hf->nemo(k); auto bra_j=hf->R2orbital(j); auto bra_l=hf->R2orbital(l); double g_jlik=inner(bra_j*ket_i, (*g12)(bra_l*ket_k)); - double g_jlki=inner(bra_j*ket_k, (*g12)(bra_l*ket_i)); - tmp+=(2.0*ovlp1 - ovlp2)*g_jlik; + print("",g_jlik); + tmp+=(2.0*ovlp_E - ovlp_F)*g_jlik; } } - print("mp3 energy: term3",i,j,tmp); + printf("mp3 energy: term3 %2d %2d %12.8f\n",i,j,tmp); term3+=tmp; } } + printf("MP3 energy: term3 %12.8f\n",term3); print("time term3",t3.reset()); t3.print(); printf("term1 %12.8f\n",term1); @@ -468,7 +517,7 @@ void MP2::solve_residual_equations(ElectronPair& result, const double econv, const double dconv) const { - if (result.converged) { + if (result.converged or param.no_compute()) { result.print_energy(); return; } diff --git a/src/madness/mra/CMakeLists.txt b/src/madness/mra/CMakeLists.txt index 454320d44b7..b2ff07c8d8d 100644 --- a/src/madness/mra/CMakeLists.txt +++ b/src/madness/mra/CMakeLists.txt @@ -10,7 +10,7 @@ set(MADMRA_HEADERS function_interface.h gfit.h convolution1d.h simplecache.h derivative.h displacements.h functypedefs.h sdf_shape_3D.h sdf_domainmask.h vmra1.h leafop.h nonlinsol.h macrotaskq.h macrotaskpartitioner.h QCCalculationParametersBase.h - commandlineparser.h) + commandlineparser.h operatorinfo.h) set(MADMRA_SOURCES mra1.cc mra2.cc mra3.cc mra4.cc mra5.cc mra6.cc startup.cc legendre.cc twoscale.cc qmprop.cc QCCalculationParametersBase.cc) diff --git a/src/madness/mra/function_factory.h b/src/madness/mra/function_factory.h index d77749fab04..f134ffe244c 100644 --- a/src/madness/mra/function_factory.h +++ b/src/madness/mra/function_factory.h @@ -50,47 +50,50 @@ #include #include #include +#include namespace madness { - // needed for the CompositeFactory - template - class FunctionImpl; - - template - class Function; - - template - Tensor fcube(const Key&, T (*f)(const Vector&), const Tensor&); - - template - Tensor fcube(const Key& key, const FunctionFunctorInterface& f, const Tensor& qx); - - /// FunctionFactory implements the named-parameter idiom for Function - - /// C++ does not provide named arguments (as does, e.g., Python). - /// This class provides something very close. Create functions as follows - /// \code - /// double myfunc(const double x[]); - /// Function f = FunctionFactory(world).f(myfunc).k(11).thresh(1e-9).debug() - /// \endcode - /// where the methods of function factory, which specify the non-default - /// arguments eventually passed to the \c Function constructor, can be - /// used in any order. - /// - /// Need to add a general functor for initial projection with a standard interface. - template - class FunctionFactory { - friend class FunctionImpl ; +// needed for the CompositeFactory +template +class FunctionImpl; + +template +class Function; + +template +Tensor fcube(const Key&, T (*f)(const Vector&), const Tensor&); + +template +Tensor fcube(const Key& key, const FunctionFunctorInterface& f, const Tensor& qx); + + +/// FunctionFactory implements the named-parameter idiom for Function + +/// C++ does not provide named arguments (as does, e.g., Python). +/// This class provides something very close. Create functions as follows +/// \code +/// double myfunc(const double x[]); +/// Function f = FunctionFactory(world).f(myfunc).k(11).thresh(1e-9).debug() +/// \endcode +/// where the methods of function factory, which specify the non-default +/// arguments eventually passed to the \c Function constructor, can be +/// used in any order. +/// +/// Need to add a general functor for initial projection with a standard interface. +template +class FunctionFactory { + friend class FunctionImpl; + typedef Vector coordT; ///< Type of vector holding coordinates - protected: +protected: World& _world; int _k; double _thresh; - int _initial_level=FunctionDefaults::get_initial_level(); - int _special_level=FunctionDefaults::get_special_level(); - std::vector > _special_points; + int _initial_level = FunctionDefaults::get_initial_level(); + int _special_level = FunctionDefaults::get_special_level(); + std::vector > _special_points; int _max_refine_level; int _truncate_mode; bool _refine; @@ -104,7 +107,7 @@ namespace madness { //Tensor _bc; std::shared_ptr > > _pmap; - private: +private: // need to keep this private, access only via get_functor(); // reason is that the functor must only be constructed when the actual // FuncImpl is constructed, otherwise we might depend on the ordering @@ -112,32 +115,32 @@ namespace madness { // of after the threshold is changed) std::shared_ptr > _functor; - public: +public: FunctionFactory(World& world) : - _world(world), - _k(FunctionDefaults::get_k()), - _thresh(FunctionDefaults::get_thresh()), - _initial_level(FunctionDefaults::get_initial_level()), - _special_level(FunctionDefaults::get_special_level()), - _special_points(std::vector >()), - _max_refine_level(FunctionDefaults::get_max_refine_level()), - _truncate_mode(FunctionDefaults::get_truncate_mode()), - _refine(FunctionDefaults::get_refine()), - _empty(false), - _autorefine(FunctionDefaults::get_autorefine()), - _truncate_on_project(FunctionDefaults::get_truncate_on_project()), - _fence(true), // _bc(FunctionDefaults::get_bc()), - _tree_state(reconstructed), - _pmap(FunctionDefaults::get_pmap()), _functor() { + _world(world), + _k(FunctionDefaults::get_k()), + _thresh(FunctionDefaults::get_thresh()), + _initial_level(FunctionDefaults::get_initial_level()), + _special_level(FunctionDefaults::get_special_level()), + _special_points(std::vector >()), + _max_refine_level(FunctionDefaults::get_max_refine_level()), + _truncate_mode(FunctionDefaults::get_truncate_mode()), + _refine(FunctionDefaults::get_refine()), + _empty(false), + _autorefine(FunctionDefaults::get_autorefine()), + _truncate_on_project(FunctionDefaults::get_truncate_on_project()), + _fence(true), // _bc(FunctionDefaults::get_bc()), + _tree_state(reconstructed), + _pmap(FunctionDefaults::get_pmap()), _functor() { } virtual ~FunctionFactory() {}; FunctionFactory& functor(const std::shared_ptr >& f) { - _functor = f; - return self(); + _functor = f; + return self(); } /// pass in a functor that is derived from FunctionFunctorInterface @@ -145,549 +148,559 @@ namespace madness { /// similar to the first version of functor, but easy-to-use /// FunctionFunctorInterface must be a public base of opT template - typename std::enable_if,opT>::value, - FunctionFactory& >::type functor(const opT& op) { - _functor=std::shared_ptr >(new opT(op)); - return self(); + typename std::enable_if, opT>::value, + FunctionFactory&>::type functor(const opT& op) { + _functor = std::shared_ptr >(new opT(op)); + return self(); } /// pass in a functor that is *not* derived from FunctionFunctorInterface /// similar to the first version of functor, but easy-to-use template - typename std::enable_if,opT>::value, - FunctionFactory& >::type functor(const opT& op) { - _functor=std::shared_ptr > - (new FunctionInterface(op)); - return self(); + typename std::enable_if, opT>::value, + FunctionFactory&>::type functor(const opT& op) { + _functor = std::shared_ptr > + (new FunctionInterface(op)); + return self(); } - FunctionFactory& compressed(bool value=true) { - _tree_state= value ? TreeState::compressed : reconstructed; - return self(); + FunctionFactory& compressed(bool value = true) { + _tree_state = value ? TreeState::compressed : reconstructed; + return self(); } FunctionFactory& no_functor() { - _functor.reset(); - return self(); + _functor.reset(); + return self(); } + FunctionFactory& f(T (*f)(const coordT&)) { - functor(std::shared_ptr > ( - new ElementaryInterface(f))); - return self(); + functor(std::shared_ptr >( + new ElementaryInterface(f))); + return self(); } virtual FunctionFactory& k(int k) { - _k = k; - return self(); + _k = k; + return self(); } virtual FunctionFactory& thresh(double thresh) { - _thresh = thresh; - return self(); + _thresh = thresh; + return self(); } FunctionFactory& initial_level(int initial_level) { - _initial_level = initial_level; - return self(); + _initial_level = initial_level; + return self(); } FunctionFactory& special_level(int special_level) { - _special_level=special_level; - return self(); + _special_level = special_level; + return self(); } FunctionFactory& - special_points(std::vector > & special_points) { - _special_points=special_points; - return self(); + special_points(std::vector >& special_points) { + _special_points = special_points; + return self(); } FunctionFactory& max_refine_level(int max_refine_level) { - _max_refine_level = max_refine_level; - return self(); + _max_refine_level = max_refine_level; + return self(); } + FunctionFactory& truncate_mode(int truncate_mode) { - _truncate_mode = truncate_mode; - return self(); + _truncate_mode = truncate_mode; + return self(); } + FunctionFactory& refine(bool refine = true) { - _refine = refine; - return self(); + _refine = refine; + return self(); } + FunctionFactory& norefine(bool norefine = true) { - _refine = !norefine; - return self(); + _refine = !norefine; + return self(); } + FunctionFactory& empty() { - _empty = true; - return self(); + _empty = true; + return self(); } + FunctionFactory& autorefine() { - _autorefine = true; - return self(); + _autorefine = true; + return self(); } + FunctionFactory& noautorefine() { - _autorefine = false; - return self(); + _autorefine = false; + return self(); } + FunctionFactory& truncate_on_project() { - _truncate_on_project = true; - return self(); + _truncate_on_project = true; + return self(); } + FunctionFactory& notruncate_on_project() { - _truncate_on_project = false; - return self(); + _truncate_on_project = false; + return self(); } + FunctionFactory& fence(bool fence = true) { - _fence = fence; - return self(); + _fence = fence; + return self(); } + FunctionFactory& nofence() { - _fence = false; - return self(); + _fence = false; + return self(); } + virtual FunctionFactory& is_on_demand() { - _tree_state = on_demand; - return self(); + _tree_state = on_demand; + return self(); } + FunctionFactory& pmap(const std::shared_ptr > >& pmap) { - _pmap = pmap; - return self(); + _pmap = pmap; + return self(); } - int get_k() const {return _k;}; - double get_thresh() const {return _thresh;}; - World& get_world() const {return _world;}; + int get_k() const { return _k; }; + + double get_thresh() const { return _thresh; }; + + World& get_world() const { return _world; }; /// return the functor; override this if the functor needs deferred construction virtual std::shared_ptr > get_functor() const { - return _functor; + return _functor; } /// implement this in all derived classes for correct chaining - FunctionFactory& self() {return *this;} - - }; - - - /// Factory for facile setup of a CompositeFunctorInterface and its FuncImpl - - /// for the concept of a Factory see base class FunctionFactory - /// here we need to provide two different dimensions, since the main purpose - /// of this is to set up a pair function (6D), consisting of orbitals (3D), - /// and also one- and two-electron potentials - /// - /// This Factory constructs a FuncImpl, and also the functor to it. - /// - /// NOTE: pass in only copies of functions, since use in here will corrupt the - /// tree structure and functions will not pass the VERIFY test after this. - template - class CompositeFactory : public FunctionFactory { - public: - std::shared_ptr > _ket; ///< supposedly a 6D pair function ket - std::shared_ptr > _g12; ///< supposedly a interaction potential - std::shared_ptr > _v1; ///< supposedly a potential for particle 1 - std::shared_ptr > _v2; ///< supposedly a potential for particle 2 - std::shared_ptr > _particle1; ///< supposedly particle 1 - std::shared_ptr > _particle2; ///< supposedly particle 2 - - private: + FunctionFactory& self() { return *this; } + +}; + + +/// Factory for facile setup of a CompositeFunctorInterface and its FuncImpl + +/// for the concept of a Factory see base class FunctionFactory +/// here we need to provide two different dimensions, since the main purpose +/// of this is to set up a pair function (6D), consisting of orbitals (3D), +/// and also one- and two-electron potentials +/// +/// This Factory constructs a FuncImpl, and also the functor to it. +/// +/// NOTE: pass in only copies of functions, since use in here will corrupt the +/// tree structure and functions will not pass the VERIFY test after this. +template +class CompositeFactory : public FunctionFactory { +public: + std::shared_ptr > _ket; ///< supposedly a 6D pair function ket + std::shared_ptr > _g12; ///< supposedly a interaction potential + std::shared_ptr > _v1; ///< supposedly a potential for particle 1 + std::shared_ptr > _v2; ///< supposedly a potential for particle 2 + std::shared_ptr > _particle1; ///< supposedly particle 1 + std::shared_ptr > _particle2; ///< supposedly particle 2 + +private: std::shared_ptr > _func; friend class CompositeFunctorInterface; - public: +public: CompositeFactory(World& world) - : FunctionFactory(world) - , _ket() - , _g12() - , _v1() - , _v2() - , _particle1() - , _particle2() - , _func() { + : FunctionFactory(world), _ket(), _g12(), _v1(), _v2(), _particle1(), _particle2(), _func() { - this->_tree_state=on_demand; + this->_tree_state = on_demand; } /// provide directly the NDIM (6D) pair function ket CompositeFactory& // ket(const std::shared_ptr >& f) { ket(const Function& f) { - _ket = f.get_impl(); - return self(); + _ket = f.get_impl(); + return self(); } /// g12 is the interaction potential (6D) CompositeFactory& g12(const Function& f) { - _g12 = f.get_impl(); - return self(); + _g12 = f.get_impl(); + return self(); } /// a one-particle potential, acting on particle 1 CompositeFactory& V_for_particle1(const Function& f) { - _v1 = f.get_impl(); - return self(); + _v1 = f.get_impl(); + return self(); } /// a one-particle potential, acting on particle 2 CompositeFactory& V_for_particle2(const Function& f) { - _v2 = f.get_impl(); - return self(); + _v2 = f.get_impl(); + return self(); } /// provide particle 1, used with particle 2 to set up a pair function by /// direct product CompositeFactory& particle1(const Function& f) { - _particle1 = f.get_impl(); - return self(); + _particle1 = f.get_impl(); + return self(); } /// provide particle 2, used with particle 1 to set up a pair function by /// direct product CompositeFactory& particle2(const Function& f) { - _particle2 = f.get_impl(); - return self(); + _particle2 = f.get_impl(); + return self(); } // access to the functor *only* via this std::shared_ptr > get_functor() const { - // return if we already have a valid functor - if (this->_func) return this->_func; + // return if we already have a valid functor + if (this->_func) return this->_func; - // construction of the functor is const in spirit, but non-const in sad reality.. - // this Factory not only constructs the Function, but also the functor, so - // pass *this to the interface - const_cast< std::shared_ptr >& >(this->_func)= - std::shared_ptr >( - new CompositeFunctorInterface( - this->_world,_ket,_g12,_v1,_v2,_particle1,_particle2 - )); + // construction of the functor is const in spirit, but non-const in sad reality.. + // this Factory not only constructs the Function, but also the functor, so + // pass *this to the interface + const_cast< std::shared_ptr >& >(this->_func) = + std::shared_ptr >( + new CompositeFunctorInterface( + this->_world, _ket, _g12, _v1, _v2, _particle1, _particle2 + )); - return this->_func; + return this->_func; } - CompositeFactory& self() {return *this;} - }; + CompositeFactory& self() { return *this; } +}; - /// factory for generating TwoElectronInterfaces - class TwoElectronFactory : public FunctionFactory { +/// factory for generating TwoElectronInterfaces +class TwoElectronFactory : public FunctionFactory { - protected: +protected: typedef std::shared_ptr > InterfacePtr; - public: +public: TwoElectronFactory(World& world) - : FunctionFactory(world) - , type_(coulomb_) - , interface_() - , dcut_(FunctionDefaults<3>::get_thresh()) - , gamma_(-1.0) - , bc_(FunctionDefaults<6>::get_bc()) { - _tree_state=on_demand; - this->_thresh=(FunctionDefaults<3>::get_thresh()); - this->_k=(FunctionDefaults<3>::get_k()); + : FunctionFactory(world), interface_(), bc_(FunctionDefaults<6>::get_bc()) { + _tree_state = on_demand; + info.mu=-1.0; + info.type=OT_G12; + info.thresh=FunctionDefaults<3>::get_thresh(); + this->_thresh = (FunctionDefaults<3>::get_thresh()); + this->_k = (FunctionDefaults<3>::get_k()); } /// the smallest length scale to be represented (aka lo) TwoElectronFactory& dcut(double dcut) { - dcut_=dcut; - return self(); + info.lo = dcut; + return self(); } /// the requested precision TwoElectronFactory& thresh(double thresh) { - _thresh=thresh; - return self(); + _thresh=thresh; + info.thresh = thresh; + return self(); } /// the exponent of a slater function TwoElectronFactory& gamma(double g) { - gamma_=g; - return self(); + info.mu = g; + return self(); } /// return the operator (1 - exp(-gamma x) / (2 gamma) TwoElectronFactory& f12() { - type_=f12_; - return self(); + info.type=OT_F12; + return self(); } /// return the operator (1 - exp(-gamma x) / (2 gamma) TwoElectronFactory& slater() { - type_=slater_; - return self(); + info.type=OT_SLATER; + return self(); } /// return the BSH operator TwoElectronFactory& BSH() { - type_=bsh_; - return self(); + info.type=OT_BSH; + return self(); } - // access to the functor *only* via this - InterfacePtr get_functor() const { - - // return if we already have a valid interface - if (this->interface_) return this->interface_; - - // construction of the functor is const in spirit, but non-const in sad reality.. - if (type_==coulomb_) { - const_cast(this->interface_)= - InterfacePtr(new ElectronRepulsionInterface( - dcut_,_thresh,bc_,_k)); - } else if (type_==f12_) { - // make sure gamma is set - MADNESS_ASSERT(gamma_>0); - const_cast(this->interface_)= - InterfacePtr(new SlaterF12Interface( - gamma_,dcut_,_thresh,bc_,_k)); - } else if (type_==slater_) { - // make sure gamma is set - MADNESS_ASSERT(gamma_>0); - const_cast(this->interface_)= - InterfacePtr(new SlaterFunctionInterface( - gamma_,dcut_,_thresh,bc_,_k)); - } else if (type_==bsh_){ - const_cast(this->interface_)= - InterfacePtr(new BSHFunctionInterface( - gamma_,dcut_,_thresh,bc_,_k)); - - } else { - MADNESS_EXCEPTION("unimplemented integral kernel",1); - } - return this->interface_; - } - - TwoElectronFactory& self() {return *this;} - - protected: - - enum operatortype {coulomb_, slater_, f12_, bsh_}; - - operatortype type_; - - /// the interface providing the actual coefficients - InterfacePtr interface_; - - double dcut_; ///< cutoff radius for 1/r12, aka regularization - - double gamma_; - - BoundaryConditions<6> bc_; - - }; - -#if 0 - class ERIFactory : public TwoElectronFactory { - public: - ERIFactory(World& world) : TwoElectronFactory(world) {} - - // access to the functor *only* via this - InterfacePtr get_functor() const { - - // return if we already have a valid interface - if (this->interface_) return this->interface_; - - // construction of the functor is const in spirit, but non-const in sad reality.. - const_cast(this->interface_)= - InterfacePtr(new ElectronRepulsionInterface( - dcut_,thresh_,bc_,k_)); - return this->interface_; - } - - ERIFactory& self() {return *this;} - - }; - - /// a function like f(x) = 1 - exp(-mu x) - class SlaterFunctionFactory : public TwoElectronFactory { - public: - SlaterFunctionFactory(World& world) - : TwoElectronFactory(world), gamma_(-1.0), f12_(false) {} - - /// set the exponent of the Slater function - SlaterFunctionFactory& gamma(double gamma) { - this->gamma_ = gamma; - return self(); - } - - /// do special f12 function - SlaterFunctionFactory& f12() { - this->f12_=true; - return self(); + /// return the BSH operator + TwoElectronFactory& set_info(const OperatorInfo info1) { + info=info1; + return self(); } // access to the functor *only* via this InterfacePtr get_functor() const { - // return if we already have a valid interface - if (this->interface_) return this->interface_; + // return if we already have a valid interface + if (this->interface_) return this->interface_; - // make sure gamma is set - MADNESS_ASSERT(gamma_>0); + const_cast(this->interface_) = + InterfacePtr(new GeneralTwoElectronInterface(info)); - // construction of the functor is const in spirit, but non-const in sad reality.. - if (f12_) { - const_cast(this->interface_)= - InterfacePtr(new SlaterF12Interface( - gamma_,dcut_,this->_thresh,bc_,this->_k)); - } else { - const_cast(this->interface_)= - InterfacePtr(new SlaterFunctionInterface( - gamma_,dcut_,this->_thresh,bc_,this->_k)); - } - return this->interface_; +// // construction of the functor is const in spirit, but non-const in sad reality.. +// if (info.type==OT_G12) { +// const_cast(this->interface_) = +// InterfacePtr(new ElectronRepulsionInterface(info.lo, _thresh, bc_, _k)); +// } else if (info.type == OT_F12) { +// const_cast(this->interface_) = +// InterfacePtr(new SlaterF12Interface(info.mu, info.lo, _thresh, bc_, _k)); +// } else if (info.type == OT_SLATER) { +// const_cast(this->interface_) = +// InterfacePtr(new SlaterFunctionInterface(info.mu,info.lo, _thresh, bc_, _k)); +// } else if (info.type==OT_BSH) { +// const_cast(this->interface_) = +// InterfacePtr(new BSHFunctionInterface(info.mu, info.lo, _thresh, bc_, _k)); +// } else { +// MADNESS_EXCEPTION("unimplemented integral kernel", 1); +// } + return this->interface_; } - SlaterFunctionFactory& self() {return *this;} - - private: - - double gamma_; ///< the exponent of the Slater function f(x)=exp(-gamma x) - bool f12_; ///< use 1-exp(-gamma x) instead of exp(-gamma x) - }; + TwoElectronFactory& self() { return *this; } - /// Factory to set up an ElectronRepulsion Function - template - class ERIFactory : public FunctionFactory { +protected: - private: - std::shared_ptr _eri; +// enum operatortype { +// coulomb_, slater_, f12_, bsh_ +// }; - public: + OperatorInfo info; +// operatortype type_; - /// cutoff radius for 1/r12, aka regularization - double _dcut; - BoundaryConditions _bc; - - public: - ERIFactory(World& world) - : FunctionFactory(world) - , _eri() - , _dcut(FunctionDefaults::get_thresh()) - , _bc(FunctionDefaults::get_bc()) - { - this->_is_on_demand=true; - MADNESS_ASSERT(NDIM==6); - } - - ERIFactory& - thresh(double thresh) { - this->_thresh = thresh; - return *this; - } - - ERIFactory& - dcut(double dcut) { - this->_dcut = dcut; - return *this; - } - - // access to the functor *only* via this - std::shared_ptr > get_functor() const { + /// the interface providing the actual coefficients + InterfacePtr interface_; - // return if we already have a valid eri - if (this->_eri) return this->_eri; +// double dcut_; ///< cutoff radius for 1/r12, aka regularization - // if (this->_world.rank()==0) print("set dcut in ERIFactory to ", _dcut); +// double gamma_; - // construction of the functor is const in spirit, but non-const in sad reality.. - const_cast< std::shared_ptr& >(this->_eri)= - std::shared_ptr( - new ElectronRepulsionInterface(_dcut,this->_thresh, - _bc,this->_k)); + BoundaryConditions<6> bc_; - return this->_eri; - } +}; - }; +#if 0 +class ERIFactory : public TwoElectronFactory { +public: + ERIFactory(World& world) : TwoElectronFactory(world) {} + + // access to the functor *only* via this + InterfacePtr get_functor() const { + + // return if we already have a valid interface + if (this->interface_) return this->interface_; + + // construction of the functor is const in spirit, but non-const in sad reality.. + const_cast(this->interface_)= + InterfacePtr(new ElectronRepulsionInterface( + dcut_,thresh_,bc_,k_)); + return this->interface_; + } + + ERIFactory& self() {return *this;} + +}; + +/// a function like f(x) = 1 - exp(-mu x) +class SlaterFunctionFactory : public TwoElectronFactory { +public: + SlaterFunctionFactory(World& world) +: TwoElectronFactory(world), gamma_(-1.0), f12_(false) {} + + /// set the exponent of the Slater function + SlaterFunctionFactory& gamma(double gamma) { + this->gamma_ = gamma; + return self(); + } + + /// do special f12 function + SlaterFunctionFactory& f12() { + this->f12_=true; + return self(); + } + + // access to the functor *only* via this + InterfacePtr get_functor() const { + + // return if we already have a valid interface + if (this->interface_) return this->interface_; + + // make sure gamma is set + MADNESS_ASSERT(gamma_>0); + + // construction of the functor is const in spirit, but non-const in sad reality.. + if (f12_) { + const_cast(this->interface_)= + InterfacePtr(new SlaterF12Interface( + gamma_,dcut_,this->_thresh,bc_,this->_k)); + } else { + const_cast(this->interface_)= + InterfacePtr(new SlaterFunctionInterface( + gamma_,dcut_,this->_thresh,bc_,this->_k)); + } + return this->interface_; + } + + SlaterFunctionFactory& self() {return *this;} + +private: + + double gamma_; ///< the exponent of the Slater function f(x)=exp(-gamma x) + bool f12_; ///< use 1-exp(-gamma x) instead of exp(-gamma x) +}; + +/// Factory to set up an ElectronRepulsion Function +template +class ERIFactory : public FunctionFactory { + +private: + std::shared_ptr _eri; + +public: + + /// cutoff radius for 1/r12, aka regularization + double _dcut; + BoundaryConditions _bc; + +public: + ERIFactory(World& world) +: FunctionFactory(world) + , _eri() + , _dcut(FunctionDefaults::get_thresh()) + , _bc(FunctionDefaults::get_bc()) + { + this->_is_on_demand=true; + MADNESS_ASSERT(NDIM==6); + } + + ERIFactory& + thresh(double thresh) { + this->_thresh = thresh; + return *this; + } + + ERIFactory& + dcut(double dcut) { + this->_dcut = dcut; + return *this; + } + + // access to the functor *only* via this + std::shared_ptr > get_functor() const { + + // return if we already have a valid eri + if (this->_eri) return this->_eri; + + // if (this->_world.rank()==0) print("set dcut in ERIFactory to ", _dcut); + + // construction of the functor is const in spirit, but non-const in sad reality.. + const_cast< std::shared_ptr& >(this->_eri)= + std::shared_ptr( + new ElectronRepulsionInterface(_dcut,this->_thresh, + _bc,this->_k)); + + return this->_eri; + } + +}; #endif - /// Does not work - // /// Factory to set up an ElectronRepulsion Function - // template - // class FGFactory : public FunctionFactory { - // - // private: - // std::shared_ptr _fg; - // - // public: - // - // /// cutoff radius for 1/r12, aka regularization - // double _dcut; - // double _gamma; - // BoundaryConditions _bc; - // - // public: - // FGFactory(World& world, double gamma) - // : FunctionFactory(world) - // , _fg() - // , _dcut(FunctionDefaults::get_thresh()) - // , _gamma(gamma) - // , _bc(FunctionDefaults::get_bc()) - // { - // this->_is_on_demand=true; - // MADNESS_ASSERT(NDIM==6); - // } - // - // FGFactory& - // thresh(double thresh) { - // this->_thresh = thresh; - // return *this; - // } - // - // FGFactory& - // dcut(double dcut) { - // this->_dcut = dcut; - // return *this; - // } - // - // // access to the functor *only* via this - // std::shared_ptr > get_functor() const { - // - // // return if we already have a valid eri - // if (this->_fg) return this->_fg; - // - // // if (this->_world.rank()==0) print("set dcut in ERIFactory to ", _dcut); - // - // // construction of the functor is const in spirit, but non-const in sad reality.. - // const_cast< std::shared_ptr& >(this->_fg)= - // std::shared_ptr( - // new FGInterface(this->_world,_dcut,this->_thresh, - // _gamma,_bc,this->_k)); - // - // return this->_fg; - // } - // - // }; +/// Does not work +// /// Factory to set up an ElectronRepulsion Function +// template +// class FGFactory : public FunctionFactory { +// +// private: +// std::shared_ptr _fg; +// +// public: +// +// /// cutoff radius for 1/r12, aka regularization +// double _dcut; +// double _gamma; +// BoundaryConditions _bc; +// +// public: +// FGFactory(World& world, double gamma) +// : FunctionFactory(world) +// , _fg() +// , _dcut(FunctionDefaults::get_thresh()) +// , _gamma(gamma) +// , _bc(FunctionDefaults::get_bc()) +// { +// this->_is_on_demand=true; +// MADNESS_ASSERT(NDIM==6); +// } +// +// FGFactory& +// thresh(double thresh) { +// this->_thresh = thresh; +// return *this; +// } +// +// FGFactory& +// dcut(double dcut) { +// this->_dcut = dcut; +// return *this; +// } +// +// // access to the functor *only* via this +// std::shared_ptr > get_functor() const { +// +// // return if we already have a valid eri +// if (this->_fg) return this->_fg; +// +// // if (this->_world.rank()==0) print("set dcut in ERIFactory to ", _dcut); +// +// // construction of the functor is const in spirit, but non-const in sad reality.. +// const_cast< std::shared_ptr& >(this->_fg)= +// std::shared_ptr( +// new FGInterface(this->_world,_dcut,this->_thresh, +// _gamma,_bc,this->_k)); +// +// return this->_fg; +// } +// +// }; } diff --git a/src/madness/mra/function_interface.h b/src/madness/mra/function_interface.h index 2f9b4063767..915f83ea0f0 100644 --- a/src/madness/mra/function_interface.h +++ b/src/madness/mra/function_interface.h @@ -40,9 +40,11 @@ #include // needed for the TwoElectronInterface +#include #include #include #include + namespace madness { // forward declaration needed for CompositeFunctorInterface @@ -431,6 +433,36 @@ namespace madness { }; + + /// a function like f(x)=1/x + class GeneralTwoElectronInterface : public TwoElectronInterface { + public: + + /// constructor: cf the Coulomb kernel + + /// @param[in] lo the smallest length scale to be resolved + /// @param[in] eps the accuracy threshold + GeneralTwoElectronInterface(OperatorInfo info, + const BoundaryConditions<6>& bc=FunctionDefaults<6>::get_bc(), + int kk=FunctionDefaults<6>::get_k()) + : TwoElectronInterface(info.lo,info.thresh,bc,kk), info(info) { + + if (info.hi<0) { + double hi=FunctionDefaults<3>::get_cell_width().normf(); + if (bc(0,0) == BC_PERIODIC) hi *= 100; // Extend range for periodic summation + this->info.hi=hi; + } + initialize(info.thresh); + } + + private: + OperatorInfo info; + + GFit fit(const double eps) const { + return GFit(info); + } + }; + /// a function like f(x)=1/x class ElectronRepulsionInterface : public TwoElectronInterface { public: diff --git a/src/madness/mra/gfit.h b/src/madness/mra/gfit.h index 33a89ba81f1..600a0b5ddc4 100644 --- a/src/madness/mra/gfit.h +++ b/src/madness/mra/gfit.h @@ -48,6 +48,8 @@ #include "../tensor/tensor_lapack.h" #include "../world/madness_exception.h" #include "../world/print.h" +#include + namespace madness { @@ -59,6 +61,29 @@ class GFit { /// default ctor does nothing GFit() = default; + GFit(OperatorInfo info) { + double mu = info.mu; + double lo = info.lo; + double hi = info.hi; + MADNESS_CHECK_THROW(hi>0,"hi must be positive in gfit: U need to set it manually in operator.h"); + double eps = info.thresh; + OpType type = info.type; + + + if (type==OT_G12) {*this=CoulombFit(lo,hi,eps,false); + } else if (type==OT_SLATER) {*this=SlaterFit(mu,lo,hi,eps,false); + } else if (type==OT_GAUSS) {*this=GaussFit(mu,lo,hi,eps,false); + } else if (type==OT_F12) {*this=F12Fit(mu,lo,hi,eps,false); + } else if (type==OT_FG12) {*this=FGFit(mu,lo,hi,eps,false); + } else if (type==OT_F212) {*this=F12sqFit(mu,lo,hi,eps,false); + } else if (type==OT_F2G12) {*this=F2GFit(mu,lo,hi,eps,false); + } else if (type==OT_BSH) {*this=BSHFit(mu,lo,hi,eps,false); + } else { + MADNESS_EXCEPTION("Operator type not implemented",1); + } + + } + /// copy constructor GFit(const GFit& other) = default; diff --git a/src/madness/mra/mra.h b/src/madness/mra/mra.h index 8f22a2c311a..e6f868c4738 100644 --- a/src/madness/mra/mra.h +++ b/src/madness/mra/mra.h @@ -1256,7 +1256,8 @@ namespace madness { // if this and g are the same, use norm2() if (this->get_impl()==g.get_impl()) { - if (this->get_impl()->is_redundant()) this->get_impl()->undo_redundant(true); + TreeState state=this->get_impl()->get_tree_state(); + if (not (state==reconstructed or state==compressed)) change_tree_state(reconstructed); double norm=this->norm2(); return norm*norm; } @@ -1269,16 +1270,18 @@ namespace madness { if (VERIFY_TREE) g.verify_tree(); // compression is more efficient for 3D - if (NDIM==3) { - if (!is_compressed()) compress(false); - if (!g.is_compressed()) g.compress(false); + TreeState state=this->get_impl()->get_tree_state(); + TreeState gstate=g.get_impl()->get_tree_state(); + if (NDIM<=3) { + change_tree_state(compressed,false); + g.change_tree_state(compressed,false); impl->world.gop.fence(); } if (this->is_compressed() and g.is_compressed()) { } else { - if (not this->get_impl()->is_redundant()) this->get_impl()->make_redundant(false); - if (not g.get_impl()->is_redundant()) g.get_impl()->make_redundant(false); + change_tree_state(redundant,false); + g.change_tree_state(redundant,false); impl->world.gop.fence(); } @@ -1287,8 +1290,9 @@ namespace madness { impl->world.gop.sum(local); impl->world.gop.fence(); - if (this->get_impl()->is_redundant()) this->get_impl()->undo_redundant(false); - if (g.get_impl()->is_redundant()) g.get_impl()->undo_redundant(false); + // restore state + change_tree_state(state,false); + g.change_tree_state(gstate,false); impl->world.gop.fence(); return local; @@ -1304,9 +1308,9 @@ namespace madness { /// @return Returns local part of the inner product, i.e. over the domain of all function nodes on this compute node. T inner_ext_local(const std::shared_ptr< FunctionFunctorInterface > f, const bool leaf_refine=true, const bool keep_redundant=false) const { PROFILE_MEMBER_FUNC(Function); - if (not impl->is_redundant()) impl->make_redundant(true); + change_tree_state(redundant); T local = impl->inner_ext_local(f, leaf_refine); - if (not keep_redundant) impl->undo_redundant(true); + if (not keep_redundant) change_tree_state(reconstructed); return local; } @@ -1320,11 +1324,11 @@ namespace madness { /// @return Returns the inner product T inner_ext(const std::shared_ptr< FunctionFunctorInterface > f, const bool leaf_refine=true, const bool keep_redundant=false) const { PROFILE_MEMBER_FUNC(Function); - if (not impl->is_redundant()) impl->make_redundant(true); + change_tree_state(redundant); T local = impl->inner_ext_local(f, leaf_refine); impl->world.gop.sum(local); impl->world.gop.fence(); - if (not keep_redundant) impl->undo_redundant(true); + if (not keep_redundant) change_tree_state(reconstructed); return local; } @@ -1651,14 +1655,14 @@ namespace madness { /// check symmetry of a function by computing the 2nd derivative double check_symmetry() const { - impl->make_redundant(true); + change_tree_state(redundant); if (VERIFY_TREE) verify_tree(); double local = impl->check_symmetry_local(); impl->world.gop.sum(local); impl->world.gop.fence(); double asy=sqrt(local); if (this->world().rank()==0) print("asymmetry wrt particle",asy); - impl->undo_redundant(true); + change_tree_state(reconstructed); return asy; } @@ -1673,9 +1677,9 @@ namespace madness { /// remove all nodes with level higher than n Function& chop_at_level(const int n, const bool fence=true) { verify(); - impl->make_redundant(true); + change_tree_state(redundant); impl->chop_at_level(n,true); - impl->undo_redundant(true); + change_tree_state(reconstructed); return *this; } }; @@ -2334,18 +2338,16 @@ namespace madness { // Function& ff = const_cast< Function& >(f); // Function& gg = const_cast< Function& >(g); + f.change_tree_state(redundant,false); + g.change_tree_state(redundant); FunctionImpl* fimpl=f.get_impl().get(); FunctionImpl* gimpl=g.get_impl().get(); - gimpl->make_redundant(false); - fimpl->make_redundant(false); - result.world().gop.fence(); result.get_impl()->multiply(fimpl,gimpl,particle); result.world().gop.fence(); - fimpl->undo_redundant(false); - gimpl->undo_redundant(false); - result.world().gop.fence(); + f.change_tree_state(reconstructed,false); + g.change_tree_state(reconstructed); return result; } diff --git a/src/madness/mra/operator.h b/src/madness/mra/operator.h index 91f0573b177..a680e820b29 100644 --- a/src/madness/mra/operator.h +++ b/src/madness/mra/operator.h @@ -49,6 +49,7 @@ #include #include #include +#include namespace madness { @@ -124,63 +125,6 @@ namespace madness { */ - - /// operator types - enum OpType { - OT_UNDEFINED, - OT_ONE, /// indicates the identity - OT_G12, /// 1/r - OT_SLATER, /// exp(-r) - OT_GAUSS, /// exp(-r2) - OT_F12, /// 1-exp(-r) - OT_FG12, /// (1-exp(-r))/r - OT_F212, /// (1-exp(-r))^2 - OT_F2G12, /// (1-exp(-r))^2/r = 1/r + exp(-2r)/r - 2 exp(-r)/r - OT_BSH /// exp(-r)/r - }; - - /// operator type to string - template // dummy template argument to avoid ambiguity with the other operator<< - std::ostream& operator<<(std::ostream& os, const OpType type) { - auto name = [](OpType type) { - switch (type) { - case OpType::OT_UNDEFINED: - return "undefined"; - case OpType::OT_ONE: - return "identity"; - case OpType::OT_G12: - return "g12"; - case OpType::OT_SLATER: - return "slater"; - case OpType::OT_GAUSS: - return "gauss"; - case OpType::OT_F12: - return "f12"; - case OpType::OT_FG12: - return "fg12"; - case OpType::OT_F212: - return "f12^2"; - case OpType::OT_F2G12: - return "f12^2g"; - case OpType::OT_BSH: - return "bsh"; - default: - return "undefined"; - } - }; - os << name(type); - return os; - } - - struct OperatorInfo { - OperatorInfo() = default; - OperatorInfo(double mu, double lo, double thresh, OpType type) : mu(mu), thresh(thresh), lo(lo), type(type) {} - OpType type=OT_UNDEFINED; ///< introspection - double mu=0.0; ///< some introspection - double thresh=1.e-4; - double lo=1.e-5; - }; - template class SeparatedConvolution : public WorldObject< SeparatedConvolution > { public: @@ -259,18 +203,9 @@ namespace madness { double hi = cell_width.normf(); // Diagonal width of cell if (bc(0,0) == BC_PERIODIC) hi *= 100; // Extend range for periodic summation - GFit fit; - if (type==OT_G12) {fit=GFit::CoulombFit(lo,hi,eps,false); - } else if (type==OT_SLATER) {fit=GFit::SlaterFit(mu,lo,hi,eps,false); - } else if (type==OT_GAUSS) {fit=GFit::GaussFit(mu,lo,hi,eps,false); - } else if (type==OT_F12) {fit=GFit::F12Fit(mu,lo,hi,eps,false); - } else if (type==OT_FG12) {fit=GFit::FGFit(mu,lo,hi,eps,false); - } else if (type==OT_F212) {fit=GFit::F12sqFit(mu,lo,hi,eps,false); - } else if (type==OT_F2G12) {fit=GFit::F2GFit(mu,lo,hi,eps,false); - } else if (type==OT_BSH) {fit=GFit::BSHFit(mu,lo,hi,eps,false); - } else { - MADNESS_EXCEPTION("Operator type not implemented",1); - } + OperatorInfo info(mu,lo,eps,type); + info.hi=hi; + GFit fit(info); Tensor coeff=fit.coeffs(); Tensor expnt=fit.exponents(); diff --git a/src/madness/mra/operatorinfo.h b/src/madness/mra/operatorinfo.h new file mode 100644 index 00000000000..89cdf0c3051 --- /dev/null +++ b/src/madness/mra/operatorinfo.h @@ -0,0 +1,70 @@ +// +// Created by Florian Bischoff on 11/2/23. +// + +#ifndef MADNESS_OPERATORINFO_H +#define MADNESS_OPERATORINFO_H + +namespace madness { + +/// operator types +enum OpType { + OT_UNDEFINED, + OT_ONE, /// indicates the identity + OT_G12, /// 1/r + OT_SLATER, /// exp(-r) + OT_GAUSS, /// exp(-r2) + OT_F12, /// 1-exp(-r) + OT_FG12, /// (1-exp(-r))/r + OT_F212, /// (1-exp(-r))^2 + OT_F2G12, /// (1-exp(-r))^2/r = 1/r + exp(-2r)/r - 2 exp(-r)/r + OT_BSH /// exp(-r)/r +}; + +/// operator type to string +template // dummy template argument to avoid ambiguity with the other operator<< +std::ostream& operator<<(std::ostream& os, const OpType type) { + auto name = [](OpType type) { + switch (type) { + case OpType::OT_UNDEFINED: + return "undefined"; + case OpType::OT_ONE: + return "identity"; + case OpType::OT_G12: + return "g12"; + case OpType::OT_SLATER: + return "slater"; + case OpType::OT_GAUSS: + return "gauss"; + case OpType::OT_F12: + return "f12"; + case OpType::OT_FG12: + return "fg12"; + case OpType::OT_F212: + return "f12^2"; + case OpType::OT_F2G12: + return "f12^2g"; + case OpType::OT_BSH: + return "bsh"; + default: + return "undefined"; + } + }; + os << name(type); + return os; +} + +struct OperatorInfo { + OperatorInfo() = default; + OperatorInfo(double mu, double lo, double thresh, OpType type) : mu(mu), thresh(thresh), lo(lo), type(type) { } + OpType type=OT_UNDEFINED; ///< introspection + double mu=0.0; ///< some introspection + double thresh=1.e-4; + double lo=1.e-5; + double hi=-1.0; +}; + + + +} +#endif //MADNESS_OPERATORINFO_H From 38b86d5b1d2356fd0df03537878c4a2cb9c49d75 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Sun, 3 Dec 2023 17:19:40 +0100 Subject: [PATCH 065/109] checkpoint --- src/madness/chem/CCStructures.cc | 2 +- src/madness/chem/CCStructures.h | 9 +- src/madness/chem/ccpairfunction.cc | 78 +++-- src/madness/chem/ccpairfunction.h | 16 +- src/madness/chem/mp2.cc | 367 +++++++++++++++--------- src/madness/chem/mp2.h | 6 - src/madness/chem/test_ccpairfunction.cc | 143 +++++++-- src/madness/mra/funcimpl.h | 4 +- src/madness/mra/gfit.h | 3 +- src/madness/mra/mra.h | 7 + src/madness/mra/operator.h | 5 + src/madness/mra/operatorinfo.h | 3 +- src/madness/mra/testopdir.cc | 87 +++++- 13 files changed, 525 insertions(+), 205 deletions(-) diff --git a/src/madness/chem/CCStructures.cc b/src/madness/chem/CCStructures.cc index e67e92e17e5..ab2a1265884 100644 --- a/src/madness/chem/CCStructures.cc +++ b/src/madness/chem/CCStructures.cc @@ -406,7 +406,7 @@ SeparatedConvolution * CCConvolutionOperator::init_op(const OpType& type, const Parameters& parameters) const { bool debug=true; bool printme=(world.rank()==0) and debug; - print("init_op: creating",type,"with thresh, lo, gamma",parameters.thresh_op,parameters.gamma,parameters.lo); + print("init_op: creating",type,"with thresh, lo, gamma",parameters.thresh_op,parameters.lo,parameters.gamma); return new SeparatedConvolution(world,OperatorInfo(parameters.gamma,parameters.lo,parameters.thresh_op,type)); } diff --git a/src/madness/chem/CCStructures.h b/src/madness/chem/CCStructures.h index 4210e491313..a4f4ddeadf1 100644 --- a/src/madness/chem/CCStructures.h +++ b/src/madness/chem/CCStructures.h @@ -835,12 +835,9 @@ struct CCConvolutionOperator { /// create a TwoElectronFactory with the operatorkernel TwoElectronFactory get_kernel() const { - if (type() == OpType::OT_G12) return TwoElectronFactory(world).dcut(1.e-7); - else if (type() == OpType::OT_F12) return TwoElectronFactory(world).dcut(1.e-7).f12().gamma(parameters.gamma); - else if (type() == OpType::OT_FG12) return TwoElectronFactory(world).dcut(1.e-7).BSH().gamma(parameters.gamma); - else if (type() == OpType::OT_SLATER) return TwoElectronFactory(world).dcut(1.e-7).slater().gamma(parameters.gamma); - else error("no kernel of type " + name() + " implemented"); - return TwoElectronFactory(world); + auto factory=TwoElectronFactory(world); + factory.set_info(op->info); + return factory; } OpType type() const { return get_op()->info.type; } diff --git a/src/madness/chem/ccpairfunction.cc b/src/madness/chem/ccpairfunction.cc index 54d83236d13..b3e58df5d1f 100644 --- a/src/madness/chem/ccpairfunction.cc +++ b/src/madness/chem/ccpairfunction.cc @@ -23,7 +23,7 @@ bool CCPairFunction::is_convertible_to_pure_no_op() const { const auto type=get_operator().type(); if (not (type==OpType::OT_SLATER or type==OpType::OT_F12)) return false; } - if (is_decomposed() and (get_a().size()>1)) return false; + if (is_decomposed() and (get_a().size()>2)) return false; return true; }; @@ -40,7 +40,7 @@ void CCPairFunction::convert_to_pure_no_op_inplace() { tmp.fill_tree(); result=tmp; } else if (is_decomposed()) { - MADNESS_CHECK(get_a().size()<3); + MADNESS_CHECK_THROW(get_a().size()<3,"a.size not <3 in convert_to_pure_no_op_inplace"); for (int i=0; i(world()) @@ -231,7 +231,8 @@ CCPairFunction CCPairFunction::partial_inner(const CCPairFunction& other, // \int \sum_i f(1,2) a_i(1) b_i(3) d1 = \sum_i b_i(3) \int a_i(1) f(1,2) d1 vector_real_function_3d tmp; for (auto& a : other.get_vector(integration_index(v2))) { - tmp.push_back(innerXX<3>(this->get_function(),a,v1,a012)); // a012 is correct, referring to 3D function +// tmp.push_back(innerXX<3>(this->get_function(),a,v1,a012)); // a012 is correct, referring to 3D function + tmp.push_back(this->get_function().project_out(a,integration_index(v1))); } return CCPairFunction(tmp,other.get_vector(remaining_index(v2))); @@ -488,8 +489,15 @@ CCPairFunction apply(const ProjectorBase& projector, const CCPairFunction& argum std::vector apply(const ProjectorBase& projector, const std::vector& argument) { if (argument.size()==0) return argument; World& world=argument.front().world(); - if (auto P=dynamic_cast*>(&projector)) MADNESS_CHECK(P->get_particle()==0 or P->get_particle()==1); - if (auto Q=dynamic_cast*>(&projector)) MADNESS_CHECK(Q->get_particle()==0 or Q->get_particle()==1); +// print("apply projector on argument with terms",argument.size()); + if (auto P=dynamic_cast*>(&projector)) { +// print("P->get_particle()",P->get_particle()); + MADNESS_CHECK_THROW(P->get_particle()==0 or P->get_particle()==1,"P Projector particle must be 0 or 1 in CCPairFunction"); + } + if (auto Q=dynamic_cast*>(&projector)) { +// print("Q->get_particle()",Q->get_particle()); + MADNESS_CHECK_THROW(Q->get_particle()==0 or Q->get_particle()==1,"Q Projector particle must be 0 or 1 in CCPairFunction"); + } std::vector result; for (const auto& pf : argument) { if (pf.is_pure()) { @@ -532,20 +540,41 @@ std::vector apply(const ProjectorBase& projector, const std::vec if (auto SO=dynamic_cast*>(&projector)) { // CCTimer t(world,"SO block"); // Q12 = 1 - O1 (1 - 1/2 O2) - O2 (1 - 1/2 O1) +// print("entering SO block"); QProjector Q1(world,SO->bra1(),SO->ket1()); Q1.set_particle(0); QProjector Q2(world,SO->bra2(),SO->ket2()); Q2.set_particle(1); + + Projector O1(SO->bra1(),SO->ket1()); + O1.set_particle(0); + Projector O2(SO->bra2(),SO->ket2()); + O2.set_particle(1); + +// auto arg=std::vector({pf}); +// auto o1arg=O1(arg); +// auto o2arg=O2(arg); +// auto o1o2arg=O1(o2arg); +// +// result.push_back(pf); +// for (auto& t: o1arg) result.push_back(-1.0*t); +// for (auto& t: o2arg) result.push_back(-1.0*t); +// for (auto& t: o1o2arg) result.push_back(t); + + auto tmp=Q1(Q2(std::vector({pf}))); +// auto tmp=Q2(Q1(std::vector({pf}))); + print("result of SO"); +// for (auto& t: tmp) t.print_size(); for (auto& t: tmp) result.push_back(t); -// t.print(); + for (auto& t: result) t.print_size(); } else if (auto P=dynamic_cast*>(&projector)) { // CCTimer t(world,"P block"); - // Q12 = 1 - O1 (1 - 1/2 O2) - O2 (1 - 1/2 O1) +// print("entering P block"); std::vector tmp= zero_functions_compressed(world,P->get_ket_vector().size()); - // per term a_i b_k: + // per term a_i b_i: // P1 f |a b> = \sum_k |k(1)> |f_ak(2)*b(2)> for (std::size_t i=0; i apply(const ProjectorBase& projector, const std::vec tmp+=b_f_ka; } truncate(world,tmp); +// print("size of tmp",tmp.size()); + if (P->get_particle()==0) result.push_back(CCPairFunction(P->get_ket_vector(),tmp)); if (P->get_particle()==1) result.push_back(CCPairFunction(tmp,P->get_ket_vector())); // t.print(); @@ -567,8 +598,10 @@ std::vector apply(const ProjectorBase& projector, const std::vec // CCTimer t(world,"Q block"); // Q1 f12 |a_i b_i> = f12 |a_i b_i> - \sum_k |k(1) a_i(2)*f_(kb_i)(2) > result.push_back(pf); +// print("entering Q block"); // reuse the projector code above std::vector tmp=madness::apply(Q->get_P_projector(),std::vector(1,pf)); + for (auto& t : tmp) t.print_size(); for (auto& t : tmp) { t*=-1.0; result.push_back(t); @@ -588,6 +621,12 @@ std::vector apply(const ProjectorBase& projector, const std::vec return result; }; +/// apply the operator to the argument + +/// the operator is applied to one particle only, the other one is left untouched +/// note the ordering of the particles, cf the corresponding comment in mra.h +/// op.particle==1 : op(f(x,y)) = op(x,x') f(x',y) = result(x,y); +/// op.particle==2 : op(f(x,y)) = op(y,y') f(x,y') = result(y,x); template std::vector apply(const SeparatedConvolution& op, const std::vector& argument) { if (argument.size()==0) return argument; @@ -595,11 +634,16 @@ std::vector apply(const SeparatedConvolution& op, const std::vector result; timer t(world); for (const auto& arg : argument) { - if (arg.is_pure()) { - result.push_back(CCPairFunction(op(arg.get_function()))); - } else if (arg.is_op_pure()) { - auto tmp=arg.to_pure(); - result.push_back(apply(op,tmp)); + bool convert_to_pure=(arg.has_operator() or arg.is_pure()); + + if (convert_to_pure) { + auto tmp=arg.to_pure().get_function(); + tmp=op(tmp); + + // !! confusing ordering of the result variables!! + if (op.particle()==2) tmp=swap_particles(tmp); + result.push_back(CCPairFunction(tmp)); + } else if (arg.is_decomposed_no_op()) { MADNESS_CHECK(op.particle()==1 or op.particle()==2); if (op.particle()==1) { @@ -607,11 +651,11 @@ std::vector apply(const SeparatedConvolution& op, const result.push_back(CCPairFunction(tmp,arg.get_b())); } else if (op.particle()==2) { auto tmp= madness::apply(world,op,arg.get_b()); - result.push_back(CCPairFunction(arg.get_a(),tmp)); + result.push_back(CCPairFunction(tmp,arg.get_a())); } - } else if (arg.is_op_decomposed()) { // sucks.. - auto tmp=arg.to_pure(); - result.push_back(apply(op,tmp)); + + } else { + MADNESS_CHECK_THROW(false,"confused type in apply(CCPairFunction)"); } t.tag("applying op to CCPairFunction "+arg.name()); } diff --git a/src/madness/chem/ccpairfunction.h b/src/madness/chem/ccpairfunction.h index 56bc10bface..7c83e64df76 100644 --- a/src/madness/chem/ccpairfunction.h +++ b/src/madness/chem/ccpairfunction.h @@ -405,7 +405,7 @@ using pureT=Function; /// scalar multiplication: fac*f friend CCPairFunction operator*(const double fac, const CCPairFunction& f) { - return fac*f; + return f*fac; } /// multiplication with a 2-particle function @@ -573,7 +573,10 @@ using pureT=Function; for (auto& b : vb) { double tmp=a.inner_internal(b,R2); double wall1=cpu_time(); - print("result from inner",a.name(true),b.name(),tmp,wall1-wall0,"s"); + std::size_t bufsize=256; + char buf[bufsize]; + snprintf(buf,bufsize,"result from inner %10s %10s %12.8f %4.1fs",a.name(true).c_str(),b.name().c_str(),tmp,wall1-wall0); + print(std::string(buf)); wall0=wall1; result+=tmp; } @@ -582,6 +585,12 @@ using pureT=Function; } + friend std::vector swap_particles(const std::vector& argument) { + std::vector result; + for (auto& a : argument) result.push_back(a.swap_particles()); + return result; + }; + public: /// the 3 types of 6D-function that occur in the CC potential which coupled doubles to singles std::shared_ptr component; @@ -617,6 +626,7 @@ using pureT=Function; real_function_6d result1=real_factory_6d(argument.world()).compressed(); MADNESS_ASSERT(argument.get_a().size() == argument.get_b().size()); + MADNESS_CHECK_THROW(G.particle()==-1,"G must be a two-particle operator in apply(CCPairFunction)"); for (size_t k = 0; k < argument.get_a().size(); k++) { const real_function_6d tmp = G(argument.get_a()[k], argument.get_b()[k]); @@ -659,6 +669,8 @@ std::vector apply(const SeparatedConvolution& op, const template CCPairFunction apply(const SeparatedConvolution& op, const CCPairFunction& argument); +std::vector swap_particles(const std::vector& argument); + real_function_3d inner(const CCPairFunction& c, const real_function_3d& f, const std::tuple v1, const std::tuple v2={0,1,2}); diff --git a/src/madness/chem/mp2.cc b/src/madness/chem/mp2.cc index 863f95812e6..a82e07c367a 100644 --- a/src/madness/chem/mp2.cc +++ b/src/madness/chem/mp2.cc @@ -275,6 +275,9 @@ double MP2::mp3() const { typedef std::vector ClusterFunction; Pairs clusterfunctions; + auto R2 = hf->nemo_ptr->ncf->square(); + auto R = hf->nemo_ptr->ncf->function(); + double mp3_energy = 0.0; CCTimer t1(world, "make pairs"); // load converged MP1 wave functions @@ -300,6 +303,24 @@ double MP2::mp3() const { } } t1.print(); + CCTimer t_R2(world,"make R2 pairs"); + Pairs clusterfunctions_R2; + Pairs clusterfunctions_R; + for (int i=param.freeze(); inocc(); ++i) { + for (int j=i; jnocc(); ++j) { + { + auto tmp1 = multiply(clusterfunctions(i, j), R2, {0, 1, 2}); + auto tmp2 = multiply(tmp1, R2, {3, 4, 5}); + for (auto& t: tmp2) clusterfunctions_R2(i, j).push_back(t); + } + { + auto tmp1 = multiply(clusterfunctions(i, j), R, {0, 1, 2}); + auto tmp2 = multiply(tmp1, R, {3, 4, 5}); + for (auto& t: tmp2) clusterfunctions_R(i, j).push_back(t); + } + } + } + t_R2.print(); for (int i = param.freeze(); i < hf->nocc(); ++i) { for (int j = i; j < hf->nocc(); ++j) { @@ -309,7 +330,7 @@ double MP2::mp3() const { } print_header3("recompute the MP2 energy"); - auto R2 = hf->nemo_ptr->ncf->square(); + CCConvolutionOperator::Parameters cparam; auto g12=CCConvolutionOperatorPtr(world,OpType::OT_G12,cparam); @@ -320,8 +341,6 @@ double MP2::mp3() const { for (int i = param.freeze(); i < hf->nocc(); ++i) { for (int j = i; j < hf->nocc(); ++j) { -// auto bra=g12*CCPairFunction(hf->R2orbital(i),hf->R2orbital(j)); -// auto bra=g12*CCPairFunction(hf->nemo(i),hf->nemo(j)); auto bra=CCPairFunction(hf->nemo(i),hf->nemo(j)); double direct=inner({bra},g12*clusterfunctions(i,j),R2); double exchange=inner({bra},g12*clusterfunctions(j,i),R2); @@ -334,13 +353,6 @@ double MP2::mp3() const { printf("total mp2 energy %12.8f\n",mp2_energy); print("time clusterfunction",t2.reset()); - -// auto bra0=multiply(clusterfunctions(0,0),hf->nemo_ptr->R_square,{0,1,2}); -// auto G2_tmp=inner(bra0,clusterfunctions(0,0),{0,1,2},{0,1,2}); -// auto bra=g12*CCPairFunction(hf->R2orbital(0),hf->R2orbital(0)); -// double G2=inner({bra},G2_tmp); -// print("G2 ",G2); - print_header3("compute the MP3 energy"); CCTimer t3(world,"MP3"); @@ -352,129 +364,217 @@ double MP2::mp3() const { gij.insert(i,j,(*g12)(hf->nemo(i)*hf->R2orbital(j))); } } - print_header3("compute term1 of the MP3 energy"); - // compute the MP3 energy - double term1=0.0; - if (1) { - for (int i = param.freeze(); i < hf->nocc(); ++i) { - for (int j = i; j < hf->nocc(); ++j) { - auto bra = clusterfunctions(i, j); - double tmp1 = inner(bra, g12 * clusterfunctions(i, j),R2); - double tmp2 = inner(bra, g12 * clusterfunctions(j, i),R2); - double fac = (i == j) ? 0.5 : 1.0; - double tmp = fac * (4.0 * tmp1 - 2.0 * tmp2); - printf("mp3 energy: term1 %2d %2d: %12.8f\n", i, j, tmp); - term1 += tmp; + + + if (0) { + print_header3("G with inner products"); + real_convolution_3d& g = *(g12->get_op()); + g.set_particle(1); + real_function_3d one=real_factory_3d(world).functor([](const coord_3d& x){return 1.0;}); + auto one2=std::vector({CCPairFunction(one,one)}); + auto phi0=std::vector({CCPairFunction(hf->orbital(0),hf->orbital(0))}); + { + auto tmp=inner(phi0,phi0,{0,1,2},{0,1,2}); + double H1=inner(tmp,g12*phi0); + printf("H1 = %12.8f\n",H1); + double H1one=inner(tmp,g12*one2); + printf("H1one = %12.8f\n",H1one); + + double na=inner(phi0[0].get_a(),phi0[0].get_a()); + double nb=inner(phi0[0].get_b(),phi0[0].get_a()); + auto tmp1=g(phi0); + auto tmp2=g(phi0[0].get_a()); + double n=inner(tmp2,phi0[0].get_a()); + print("n",n); + double ta=inner(tmp1[0].get_a(),phi0[0].get_a()); + double bb=inner(tmp1[0].get_b(),phi0[0].get_a()); + print("norms (a,b) of phi0",na,nb); + print("norms (a,b) of g(phi0)",ta,bb); + double H2=inner(tmp1,phi0); + printf("H2 = %12.8f\n",H2); } - } - } - printf("MP3 energy: term1 %12.8f\n",term1); - print("time term1",t3.reset()); - print(""); - // compute intermediates for terms G, I, H, and J + const auto& pair00=clusterfunctions_R(0,0); + for (int i=0; i::get_thresh(); + FunctionDefaults<6>::set_thresh(oldthresh*0.001); + + few[0].get_function().print_size("few[0]"); + auto tmp=inner(few,few,{0,1,2},{0,1,2}); + tmp[0].get_function().print_size("tmp[0]"); + +// auto tmp1=inner(few,few,{0,1,2},{3,4,5}); +// tmp1[0].get_function().print_size("tmp1[0]"); +// +// auto tmp2=inner(few,few2,{0,1,2},{0,1,2}); +// tmp2[0].get_function().print_size("tmp2[0]"); +// + FunctionDefaults<6>::set_thresh(oldthresh); + print("finished with inner(tau,tau,0,0)"); + double G1=inner(g12*tmp,{CCPairFunction(hf->orbital(0),hf->orbital(0))}); + printf("G = %12.8f\n",G1); + double G2=inner(g12*tmp,{CCPairFunction(one,one)}); + printf("G = %12.8f\n",G2); + + g.set_particle(2); + auto gtau = g(few); // < tau_ij(1,2) j(2) | g(2,2') | + double G10 = inner(gtau, few); + printf("G convolution %12.8f\n", G10); - // \sum_j tau_ij(1,2) * phi_j(2) - std::vector tau_i_jj(hf->nocc()-param.freeze()); - std::vector tau_i_jj_R2(hf->nocc()-param.freeze()); - // \sum_j tau_ij(1,2) * phi_j(1) - std::vector tau_ij_j(hf->nocc()-param.freeze()); - std::vector tau_ij_j_R2(hf->nocc()-param.freeze()); - for (int i = param.freeze(); i < hf->nocc(); ++i) { - for (int j = param.freeze(); j < hf->nocc(); ++j) { - auto tmp2=multiply(clusterfunctions(i,j),hf->R2orbital(j),{3,4,5}); - for (auto& t : tmp2) tau_i_jj_R2[i].push_back(t); + } + } + print("time extra G", t3.reset()); + + double term_CD=0.0; + double term_GHIJ=0.0; + double term_KLMN=0.0; + double term_EF=0.0; + + if (1) { + print_header3("compute term_CD of the MP3 energy with R2_bra"); + // compute the MP3 energy + if (1) { + for (int i = param.freeze(); i < hf->nocc(); ++i) { + for (int j = i; j < hf->nocc(); ++j) { +// auto bra = clusterfunctions(i, j); +// double tmp1 = inner(bra, g12 * clusterfunctions(i, j), R2); +// double tmp2 = inner(bra, g12 * clusterfunctions(j, i), R2); + auto bra = clusterfunctions_R2(i, j); + double tmp1 = inner(bra, g12 * clusterfunctions(i, j)); + double tmp2 = inner(bra, g12 * clusterfunctions(j, i)); + double fac = (i == j) ? 0.5 : 1.0; + double tmp = fac * (4.0 * tmp1 - 2.0 * tmp2); + printf("mp3 energy: term_CD %2d %2d: %12.8f\n", i, j, tmp); + term_CD += tmp; + } + } + } + printf("MP3 energy: term_CD %12.8f\n", term_CD); + print("time term_CD", t3.reset()); + print(""); - auto tmp4=multiply(clusterfunctions(i,j),hf->R2orbital(j),{0,1,2}); - for (auto& t : tmp4) tau_ij_j_R2[i].push_back(t); - auto tmp1=multiply(clusterfunctions(i,j),hf->nemo(j),{3,4,5}); - for (auto& t : tmp1) tau_i_jj[i].push_back(t); + // compute intermediates for terms G, I, H, and J - auto tmp3=multiply(clusterfunctions(i,j),hf->nemo(j),{0,1,2}); - for (auto& t : tmp3) tau_ij_j[i].push_back(t); + // \sum_j tau_ij(1,2) * phi_j(2) + std::vector tau_i_jj(hf->nocc() - param.freeze()); + std::vector tau_i_jj_R2(hf->nocc() - param.freeze()); + // \sum_j tau_ij(1,2) * phi_j(1) + std::vector tau_ij_j(hf->nocc() - param.freeze()); + std::vector tau_ij_j_R2(hf->nocc() - param.freeze()); + for (int i = param.freeze(); i < hf->nocc(); ++i) { + for (int j = param.freeze(); j < hf->nocc(); ++j) { +// auto tmp2 = multiply(clusterfunctions(i, j), hf->R2orbital(j), {3, 4, 5}); + auto tmp2 = multiply(clusterfunctions(i, j), hf->orbital(j), {3, 4, 5}); + for (auto& t: tmp2) tau_i_jj_R2[i].push_back(t); + +// auto tmp4 = multiply(clusterfunctions(i, j), hf->R2orbital(j), {0, 1, 2}); + auto tmp4 = multiply(clusterfunctions(i, j), hf->orbital(j), {0, 1, 2}); + for (auto& t: tmp4) tau_ij_j_R2[i].push_back(t); + +// auto tmp1 = multiply(clusterfunctions(i, j), hf->nemo(j), {3, 4, 5}); + auto tmp1 = multiply(clusterfunctions(i, j), hf->orbital(j), {3, 4, 5}); + for (auto& t: tmp1) tau_i_jj[i].push_back(t); + +// auto tmp3 = multiply(clusterfunctions(i, j), hf->nemo(j), {0, 1, 2}); + auto tmp3 = multiply(clusterfunctions(i, j), hf->orbital(j), {0, 1, 2}); + for (auto& t: tmp3) tau_ij_j[i].push_back(t); + } + } + print("info on tau_i_jj"); + for (int i = param.freeze(); i < hf->nocc(); ++i) { + for (auto& c: tau_i_jj[i]) c.info(); + } + print("info on tau_ij_j"); + for (int i = param.freeze(); i < hf->nocc(); ++i) { + for (auto& c: tau_ij_j[i]) c.info(); } - } - print("info on tau_i_jj"); - for (int i = param.freeze(); i < hf->nocc(); ++i) { - for (auto& c: tau_i_jj[i]) c.info(); - } - print("info on tau_ij_j"); - for (int i = param.freeze(); i < hf->nocc(); ++i) { - for (auto& c: tau_ij_j[i]) c.info(); - } - print("time GHIJ prep",t3.reset()); - // terms G, I, H, J of Bartlett/Silver 1975 - double term2a=0.0; - real_convolution_3d& g=*(g12->get_op()); - for (int i = param.freeze(); i < hf->nocc(); ++i) { - timer t4(world,"gtau"); - g.particle()=2; - auto gtau_same=g(tau_i_jj_R2[i]); // < tau_ij(1,2) j(2) | g(2,2') | - t4.tag("compute gtau_same"); - g.particle()=1; - auto gtau_other=g(tau_ij_j_R2[i]); // < tau_ij(1,2) j(1) | g(2,2') | - t4.tag("compute gtau_other"); - -// auto tmp0=multiply(gtau_same,hf->nemo_ptr->R_square,{0,1,2}); -// auto gtau_same_R2=multiply(tmp0,hf->nemo_ptr->R_square,{3,4,5}); -// auto tmp1=multiply(gtau_other,hf->nemo_ptr->R_square,{0,1,2}); -// auto gtau_other_R2=multiply(tmp1,hf->nemo_ptr->R_square,{3,4,5}); - - - double G=inner(gtau_same,tau_i_jj[i],R2); - print("G",G); -// double G2=inner(gtau_same_R2,tau_i_jj[i]); -// print("G_R2",G2); - double I=inner(gtau_same,tau_ij_j[i],R2); - print("I",I); -// double I2=inner(gtau_same_R2,tau_ij_j[i]); -// print("I_R2",I2); - double H=inner(gtau_other,tau_i_jj[i],R2); - print("H",H); - double J=inner(gtau_other,tau_ij_j[i],R2); - print("J",J); - - t4.tag("compute inner products"); - double tmp = (8.0 *G - 4.0*I + 2.0* H - 4.0*J); - printf("mp3 energy: term2a %2d %12.8f\n",i,tmp); - term2a+=tmp; - } - printf("MP3 energy: term2 (GHIJ) %12.8f\n",term2a); - print("time GHIJ ",t3.reset()); + print("time GHIJ prep", t3.reset()); - double term2=0.0; - for (int i = param.freeze(); i < hf->nocc(); ++i) { - for (int j = param.freeze(); j < hf->nocc(); ++j) { - double tmp=0.0; - for (int k=param.freeze(); knocc(); ++k) { - auto tau_ik=clusterfunctions(i,k); - auto tau_kj=clusterfunctions(k,j); - auto tau_ij=clusterfunctions(i,j); - auto tau_ji=clusterfunctions(j,i); - auto tau_ik_gkj = multiply(tau_ik,gij(k,j),{3,4,5}); - auto tau_kj_gki = multiply(tau_kj,gij(k,i),{3,4,5}); + // terms G, I, H, J of Bartlett/Silver 1975 + real_convolution_3d& g = *(g12->get_op()); + for (int i = param.freeze(); i < hf->nocc(); ++i) { + timer t4(world, "gtau"); + g.set_particle(2); + auto gtau_same = g(tau_i_jj_R2[i]); // < tau_ij(1,2) j(2) | g(2,2') | +// auto gtau = g(clusterfunctions_R(0,0)); // < tau_ij(1,2) j(2) | g(2,2') | +// auto gtau_same_swap= swap_particles(gtau_same); + t4.tag("compute gtau_same"); + g.set_particle(1); + auto gtau_other = g(tau_ij_j_R2[i]); // < tau_ij(1,2) j(1) | g(1,1') | + t4.tag("compute gtau_other"); + + +// double G = inner(gtau_same, tau_i_jj[i], R2); + double G = inner(gtau_same, tau_i_jj[i]); + printf("G %12.8f\n", G); +// double G1 = inner(gtau, clusterfunctions_R(0,0), R2); +// printf("G1 %12.8f\n", G1); + +// double G_swap = inner(gtau_same_swap, tau_i_jj[i], R2); +// printf("Gswap %12.8f\n", G_swap); +// double G_swap2 = inner(gtau_same_swap, tau_ij_j[i], R2); +// printf("Gswap2 %12.8f\n", G_swap2); + +// double I = inner(gtau_same, tau_ij_j[i], R2); + double I = inner(gtau_same, tau_ij_j[i]); + printf("I %12.8f\n", I); +// double H = inner(gtau_other, tau_i_jj[i], R2); + double H = inner(gtau_other, tau_i_jj[i]); + printf("H %12.8f\n", H); +// double J = inner(gtau_other, tau_ij_j[i], R2); + double J = inner(gtau_other, tau_ij_j[i]); + printf("J %12.8f\n", J); + + t4.tag("compute inner products"); + double tmp = (8.0 * G - 4.0 * I + 2.0 * H - 4.0 * J); + printf("mp3 energy: term_GHIJ %2d %12.8f\n", i, tmp); + term_GHIJ += tmp; + } + printf("MP3 energy: term_GHIJ %12.8f\n", term_GHIJ); + print("time GHIJ ", t3.reset()); + + for (int i = param.freeze(); i < hf->nocc(); ++i) { + for (int j = param.freeze(); j < hf->nocc(); ++j) { + double tmp = 0.0; + for (int k = param.freeze(); k < hf->nocc(); ++k) { + + auto tau_ik = clusterfunctions_R(i, k); + auto tau_kj = clusterfunctions_R(k, j); + auto tau_ij = clusterfunctions_R(i, j); + auto tau_ji = clusterfunctions_R(j, i); + auto tau_ik_gkj = multiply(tau_ik, gij(k, j), {0, 1, 2}); + auto tau_kj_gki = multiply(tau_kj, gij(k, i), {0, 1, 2}); // auto tau_ik_gkj = multiply(tau_ik,gij(k,j),{0,1,2}); // auto tau_kj_gki = multiply(tau_kj,gij(k,i),{0,1,2}); - double K=inner(tau_ij,tau_ik_gkj,R2); - double L=inner(tau_ij,tau_kj_gki,R2); - double M=inner(tau_ji,tau_kj_gki,R2); - double N=inner(tau_ji,tau_ik_gkj,R2); - print("K,L,M,N",K,L,M,N); + double K = inner(tau_ij, tau_ik_gkj);//, R2); + double L = inner(tau_ij, tau_kj_gki);//, R2); + double M = inner(tau_ji, tau_kj_gki);//, R2); + double N = inner(tau_ji, tau_ik_gkj);//, R2); + print("K,L,M,N", K, L, M, N); - tmp+=-4*K-4*L + 2*M +2*N; + tmp += -4 * K - 4 * L + 2 * M + 2 * N; + } + printf("mp3 energy: term_KLMN with particle=1 %2d %2d %12.8f\n", i, j, tmp); + term_KLMN += tmp; } - printf("mp3 energy: term2 %2d %2d %12.8f\n",i,j,tmp); - term2+=tmp; } + printf("MP3 energy: term_KLMN (KLMN) %12.8f\n", term_KLMN); + print("time term_KLMN", t3.reset()); } - printf("MP3 energy: term2 (KLMN) %12.8f\n",term2); - print("time term2",t3.reset()); - - double term3=0.0; + print_header3("computing term EF of the MP3 energy with R2_bra"); for (int i = param.freeze(); i < hf->nocc(); ++i) { for (int j = param.freeze(); j < hf->nocc(); ++j) { double tmp=0.0; @@ -494,18 +594,18 @@ double MP2::mp3() const { tmp+=(2.0*ovlp_E - ovlp_F)*g_jlik; } } - printf("mp3 energy: term3 %2d %2d %12.8f\n",i,j,tmp); - term3+=tmp; + printf("mp3 energy: term_EF %2d %2d %12.8f\n",i,j,tmp); + term_EF+=tmp; } } - printf("MP3 energy: term3 %12.8f\n",term3); - print("time term3",t3.reset()); + printf("MP3 energy: term_EF %12.8f\n",term_EF); + print("time term_EF",t3.reset()); t3.print(); - printf("term1 %12.8f\n",term1); - printf("term2a %12.8f\n",term2a); - printf("term2 %12.8f\n",term2); - printf("term3 %12.8f\n",term3); - mp3_energy=term1+term2a+term2+term3; + printf("term_CD %12.8f\n",term_CD); + printf("term_GHIJ %12.8f\n",term_GHIJ); + printf("term_KLMN %12.8f\n",term_KLMN); + printf("term_EF %12.8f\n",term_EF); + mp3_energy=term_CD+term_GHIJ+term_KLMN+term_EF; printf("MP3 en %12.8f\n",mp3_energy); @@ -730,23 +830,6 @@ void MP2::increment(ElectronPair& pair, real_convolution_6d& green) { } } -/// swap particles 1 and 2 - -/// param[in] f a function of 2 particles f(1,2) -/// return the input function with particles swapped g(1,2) = f(2,1) -real_function_6d MP2::swap_particles(const real_function_6d& f) const { - - // this could be done more efficiently for SVD, but it works decently - std::vector map(6); - map[0] = 3; - map[1] = 4; - map[2] = 5; // 2 -> 1 - map[3] = 0; - map[4] = 1; - map[5] = 2; // 1 -> 2 - return mapdim(f, map); -} - double MP2::asymmetry(const real_function_6d& f, const std::string s) const { return 0.0; const real_function_6d ff = swap_particles(f); diff --git a/src/madness/chem/mp2.h b/src/madness/chem/mp2.h index b60844703f5..d3dd1864373 100644 --- a/src/madness/chem/mp2.h +++ b/src/madness/chem/mp2.h @@ -499,12 +499,6 @@ class MP2 : public OptimizationTargetInterface, public QCPropertyInterface { /// param[in] green the Green's function void increment(ElectronPair& pair, real_convolution_6d& green); - /// swap particles 1 and 2 - - /// param[in] f a function of 2 particles f(1,2) - /// return the input function with particles swapped g(1,2) = f(2,1) - real_function_6d swap_particles(const real_function_6d& f) const; - double asymmetry(const real_function_6d& f, const std::string s) const; /// compute the matrix element diff --git a/src/madness/chem/test_ccpairfunction.cc b/src/madness/chem/test_ccpairfunction.cc index e035e5803b0..0aadc4fb2f1 100644 --- a/src/madness/chem/test_ccpairfunction.cc +++ b/src/madness/chem/test_ccpairfunction.cc @@ -35,6 +35,11 @@ struct data { auto g3 = [](const coord_3d& r) { return exp(-3.0 * inner(r, r)); }; auto g4 = [](const coord_3d& r) { return exp(-4.0 * inner(r, r)); }; auto g5 = [](const coord_3d& r) { return exp(-5.0 * inner(r, r)); }; +// auto g1 = [](const coord_3d& r) { return exp(-1.0 * (r.normf()+1.e-4)); }; +// auto g2 = [](const coord_3d& r) { return exp(-2.0 * (r.normf()+1.e-4)); }; +// auto g3 = [](const coord_3d& r) { return exp(-3.0 * (r.normf()+1.e-4)); }; +// auto g4 = [](const coord_3d& r) { return exp(-4.0 * (r.normf()+1.e-4)); }; +// auto g5 = [](const coord_3d& r) { return exp(-5.0 * (r.normf()+1.e-4)); }; f1=real_factory_3d(world).f(g1); f2=real_factory_3d(world).f(g2); f3=real_factory_3d(world).f(g3); @@ -51,8 +56,21 @@ struct data { double r2=r[3]*r[3] + r[4]*r[4] + r[5]*r[5]; return exp(-1.0*r1 - 2.0*r2) + exp(-2.0*r1 - 3.0*r2); }; - f12 = real_factory_6d(world).f(g); - f23 = real_factory_6d(world).f(g23); + + f12=real_factory_6d(world); + f23=real_factory_6d(world); + try { + load(f12,"test_ccpairfunction_f12"); + } catch (...) { + f12 = real_factory_6d(world).f(g); + save(f12,"test_ccpairfunction_f12"); + } + try { + load(f23,"test_ccpairfunction_f23"); + } catch (...) { + f23 = real_factory_6d(world).f(g23); + save(f23,"test_ccpairfunction_f23"); + } } void clear() { @@ -649,8 +667,46 @@ int test_partial_inner_3d(World& world, std::shared_ptr ncf, const Molecule& molecule, const CCParameters& parameter) { test_output t1("CCPairFunction::test_apply"); + t1.set_cout_to_terminal(); - return (t1.get_final_success()) ? 0 : 1; + /// f12: exp(-r_1^2 - 2 r_2^2) + /// f23: exp(-r_1^2 - 2 r_2^2) + exp(-2 r_1^2 - 3 r_2^2) + /// p1: pure, corresponds to f12 + /// p2: dec, corresponds to f23 + /// p3: op_dec, corresponds to f23 + /// p4: pure, corresponds to f23 + /// p5: op_pure, corresponds to f23 + auto [p1,p2,p3,p4,p5]=data1.get_ccpairfunctions(); + auto [f1,f2,f3,f4,f5,f]=data1.get_functions(); + + auto f12=CCConvolutionOperatorPtr(world, OT_F12, parameter); + auto& op=*(f12->get_op()); + std::vector vp2({p2}); + std::vector vp2ex({p2.swap_particles()}); + + // tmp(2) = \int a(1)b(2') f(1,2) d1 + // result=inner(tmp,f1); + for (auto& p : {p1,p2,p3,p4,p5}) { + print("working on ",p.name()); + std::vector vp({p}); + op.set_particle(1); + auto op1_p=op(vp); + double r1=inner(vp2,op1_p); + double r1ex=inner(vp2ex,op1_p); + printf("r1 %12.8f\n",r1); + printf("r1ex %12.8f\n",r1ex); + op.set_particle(2); + auto op2_p=op(vp); + double r2=inner(vp2,op2_p); + double r2ex=inner(vp2ex,op2_p); + printf("r2 %12.8f\n",r2); + printf("r2ex %12.8f\n",r2ex); + + } + + + + return t1.end(); } int test_scalar_multiplication(World& world, std::shared_ptr ncf, const Molecule& molecule, @@ -774,7 +830,8 @@ int test_projector(World& world, std::shared_ptr ncf, test_output t1("CCPairFunction::test_projector"); CCTimer timer(world, "testing"); - t1.set_cout_to_logger(); +// t1.set_cout_to_logger(); + t1.set_cout_to_terminal(); auto [f1,f2,f3,f4,f5,f] = data1.get_functions(); double nf1=f1.norm2(); double nf2=f2.norm2(); @@ -806,6 +863,47 @@ int test_projector(World& world, std::shared_ptr ncf, StrongOrthogonalityProjector Q12(world); Q12.set_spaces(o); + double thresh=FunctionDefaults<3>::get_thresh(); + + // compute reference values as: ( + // compute result values as: ) + real_function_3d of1=O(f1); + real_function_3d of2=O(f2); + real_function_3d qf1=Q(f1); + real_function_3d qf2=Q(f2); + std::vector> vp({vp1,vp2,vp3}); + for (int i=0; i<3; ++i) { + // O1 + O.set_particle(0); + { + double ref=inner({CCPairFunction({of1},{f2})},vp[i]); + double result=inner({CCPairFunction({f1},{f2})},O(vp[i])); + t1.checkpoint(result,ref,thresh,"O1 p"+std::to_string(i)); + } + + // O2 + O.set_particle(1); + { + double ref=inner({CCPairFunction({f1},{of2})},vp[i]); + double result=inner({CCPairFunction({f1},{f2})},O(vp[i])); + t1.checkpoint(result,ref,thresh,"O2 p"+std::to_string(i)); + } + // Q1 + Q.set_particle(0); + { + double ref=inner({CCPairFunction({qf1},{f2})},vp[i]); + double result=inner({CCPairFunction({f1},{f2})},Q(vp[i])); + t1.checkpoint(result,ref,thresh,"Q1 p"+std::to_string(i)); + } + // Q2 + Q.set_particle(1); + { + double ref=inner({CCPairFunction({f1},{qf2})},vp[i]); + double result=inner({CCPairFunction({f1},{f2})},Q(vp[i])); + t1.checkpoint(result,ref,thresh,"Q2 p"+std::to_string(i)); + } + } + // some hardwire test { // = @@ -817,13 +915,15 @@ int test_projector(World& world, std::shared_ptr ncf, O.set_particle(0); O1.set_particle(0); Projector O2(a,a); - O2.set_particle(0); + O2.set_particle(1); double n1=inner(vp1,O1(vp2)); double n1a=inner(O1(vp1),vp2); + t1.checkpoint(fabs(n1-n1a) ncf, t1.checkpoint(zero < FunctionDefaults<3>::get_thresh(), "SO operator on "+s,timer.reset() ); } } - t1.end(); - - return (t1.get_final_success()) ? 0 : 1; + return t1.end(); } int test_dirac_convolution(World& world, std::shared_ptr ncf, const Molecule& molecule, @@ -1007,19 +1105,20 @@ int main(int argc, char **argv) { std::shared_ptr ncf = create_nuclear_correlation_factor(world, mol, nullptr, std::make_pair("slater", 2.0)); - isuccess+=test_constructor(world, ncf, mol, ccparam); - isuccess+=test_operator_apply(world, ncf, mol, ccparam); - isuccess+=test_transformations(world, ncf, mol, ccparam); - isuccess+=test_inner(world, ncf, mol, ccparam); - isuccess+=test_multiply(world, ncf, mol, ccparam); - isuccess+=test_multiply_with_f12(world, ncf, mol, ccparam); - isuccess+=test_swap_particles(world, ncf, mol, ccparam); - isuccess+=test_scalar_multiplication(world, ncf, mol, ccparam); - isuccess+=test_partial_inner_3d(world, ncf, mol, ccparam); - isuccess+=test_partial_inner_6d(world, ncf, mol, ccparam); - isuccess+=test_projector(world, ncf, mol, ccparam); - FunctionDefaults<3>::set_cubic_cell(-10,10); - isuccess+=test_helium(world,ncf,mol,ccparam); +// isuccess+=test_constructor(world, ncf, mol, ccparam); +// isuccess+=test_operator_apply(world, ncf, mol, ccparam); +// isuccess+=test_transformations(world, ncf, mol, ccparam); +// isuccess+=test_inner(world, ncf, mol, ccparam); +// isuccess+=test_multiply(world, ncf, mol, ccparam); +// isuccess+=test_multiply_with_f12(world, ncf, mol, ccparam); +// isuccess+=test_swap_particles(world, ncf, mol, ccparam); +// isuccess+=test_scalar_multiplication(world, ncf, mol, ccparam); +// isuccess+=test_partial_inner_3d(world, ncf, mol, ccparam); +// isuccess+=test_partial_inner_6d(world, ncf, mol, ccparam); + isuccess+=test_apply(world, ncf, mol, ccparam); +// isuccess+=test_projector(world, ncf, mol, ccparam); +// FunctionDefaults<3>::set_cubic_cell(-10,10); +// isuccess+=test_helium(world,ncf,mol,ccparam); data1.clear(); } catch (std::exception& e) { madness::print("an error occured"); diff --git a/src/madness/mra/funcimpl.h b/src/madness/mra/funcimpl.h index 2f4f4d39315..edcf447babc 100644 --- a/src/madness/mra/funcimpl.h +++ b/src/madness/mra/funcimpl.h @@ -5731,6 +5731,8 @@ namespace madness { } it = it_end; } +// print("thresh ",thresh); +// print("contraction list size",contraction_map.size()); // remove all double entries for (auto& elem: contraction_map) { @@ -5843,7 +5845,7 @@ namespace madness { // print("\nkey, j_this_key", key, j_this_key); const double max_d_norm=j_other_list.find(j_this_key)->second; - const bool sd_norm_product_large = node.get_snorm() * max_d_norm > thresh; + const bool sd_norm_product_large = node.get_snorm() * max_d_norm > truncate_tol(thresh,key); // print("sd_product_norm",node.get_snorm() * max_d_norm, thresh); // end recursion if we have reached the final scale n diff --git a/src/madness/mra/gfit.h b/src/madness/mra/gfit.h index 600a0b5ddc4..37442528bce 100644 --- a/src/madness/mra/gfit.h +++ b/src/madness/mra/gfit.h @@ -79,7 +79,8 @@ class GFit { } else if (type==OT_F2G12) {*this=F2GFit(mu,lo,hi,eps,false); } else if (type==OT_BSH) {*this=BSHFit(mu,lo,hi,eps,false); } else { - MADNESS_EXCEPTION("Operator type not implemented",1); + print("Operator type not implemented: ",type); + MADNESS_EXCEPTION("Operator type not implemented: ",1); } } diff --git a/src/madness/mra/mra.h b/src/madness/mra/mra.h index e6f868c4738..ec870aa74fc 100644 --- a/src/madness/mra/mra.h +++ b/src/madness/mra/mra.h @@ -2127,6 +2127,13 @@ namespace madness { /// Returns a new function with the same distribution /// /// !!! For the moment does NOT respect fence option ... always fences + /// if the operator acts on one particle only the result will be sorted as + /// g.particle=1: g(f) = \int g(x,x') f(x',y) dx' = result(x,y) + /// g.particle=2: g(f) = \int g(y,y') f(x,y') dy' = result(x,y) + /// for the second case it will notably *not* be as it is implemented in the partial inner product! + /// g.particle=2 g(f) = result(x,y) + /// inner(g(y,y'),f(x,y'),1,1) = result(y,x) + /// also note the confusion with the counting of the particles/integration variables template Function apply(const opT& op, const Function& f, bool fence=true) { diff --git a/src/madness/mra/operator.h b/src/madness/mra/operator.h index a680e820b29..1c164d31a33 100644 --- a/src/madness/mra/operator.h +++ b/src/madness/mra/operator.h @@ -171,6 +171,11 @@ namespace madness { int& particle() {return particle_;} const int& particle() const {return particle_;} + SeparatedConvolution& set_particle(const int p) { + if (p!=1 and p!=2) throw std::runtime_error("particle must be 1 or 2"); + particle_=p; + return *this; + } bool& destructive() {return destructive_;} const bool& destructive() const {return destructive_;} diff --git a/src/madness/mra/operatorinfo.h b/src/madness/mra/operatorinfo.h index 89cdf0c3051..fcbce4d8253 100644 --- a/src/madness/mra/operatorinfo.h +++ b/src/madness/mra/operatorinfo.h @@ -18,7 +18,8 @@ enum OpType { OT_FG12, /// (1-exp(-r))/r OT_F212, /// (1-exp(-r))^2 OT_F2G12, /// (1-exp(-r))^2/r = 1/r + exp(-2r)/r - 2 exp(-r)/r - OT_BSH /// exp(-r)/r + OT_BSH, /// exp(-r)/r + OT_SIZE /// for ending loops }; /// operator type to string diff --git a/src/madness/mra/testopdir.cc b/src/madness/mra/testopdir.cc index 909e9eff04f..829a2aea5e8 100644 --- a/src/madness/mra/testopdir.cc +++ b/src/madness/mra/testopdir.cc @@ -39,6 +39,7 @@ #include #include #include +#include using namespace madness; @@ -294,9 +295,82 @@ int testgradG(World& world) { } + +/// test the various operators following op_type +template +int test_combined_operators(World& world) { + FunctionDefaults::set_cubic_cell(-20,20); + FunctionDefaults::set_k(8); + FunctionDefaults::set_thresh(1.e-5); + + test_output t("testing combined operators"); +// t.set_cout_to_terminal(); + + // parameters for the convolutions + double mu=1.0; + double lo=1.e-6; + double thresh=FunctionDefaults::get_thresh(); + + // we assume these three are actually working and correct + auto slater=SeparatedConvolution(world,OperatorInfo(mu,lo,thresh,OT_SLATER)); + auto slater2=SeparatedConvolution(world,OperatorInfo(2.0*mu,lo,thresh,OT_SLATER)); + auto bsh=SeparatedConvolution(world,OperatorInfo(mu,lo,thresh,OT_BSH)); + auto bsh2=SeparatedConvolution(world,OperatorInfo(2.0*mu,lo,thresh,OT_BSH)); + auto coulomb=SeparatedConvolution(world,OperatorInfo(mu,lo,thresh,OT_G12)); + + for (int itype=int(OT_ONE); itype::get_thresh(); + OperatorInfo info(mu,lo,thresh,type); + SeparatedConvolution op(world,info); + + // argument is a Gaussian function exp(-r^2) in any dimension + Function arg=FunctionFactory(world) + .functor([](const Vector& r){return exp(-inner(r,r));}); + + // test application + Function result=op(arg); + Function ref; + print("result norm",result.norm2()); + double fourpi=4.0*constants::pi; + + // numerical checks + if (type==OT_F12) { // (1 - Slater)/(2 mu) + ref=0.5*(arg.trace() - slater(arg)); + } else if (type==OT_F212) { // ((1 - Slater)/(2 mu) )^2 = 1/(4 mu^2) (1 - 2 Slater + Slater2 ) + ref=0.25*(arg.trace() - 2*slater(arg) + slater2(arg)); + } else if (type==OT_F2G12) { // ((1 - Slater)/(2 mu))^2 1/g = 1/(4 mu^2) (g12 - 2 bsh + bsh2 ) + ref=0.25*(coulomb(arg)- 2*fourpi*bsh(arg) + fourpi*bsh2(arg)); + } else if (type==OT_FG12) { // (1 - Slater)/(2 mu) 1/g = 1/(2 mu) (g12 - bsh ) + ref=0.5*(coulomb(arg)- fourpi*bsh(arg)); + } + double error=(ref-result).norm2()/ref.norm2(); + print("refnorm",ref.norm2()); + print("diff norm ",(ref-result).norm2()); + + t.checkpoint(error,thresh,type_str); + } + + return t.end(); + +} + + int main(int argc, char**argv) { - initialize(argc,argv); - World world(SafeMPI::COMM_WORLD); + World& world=initialize(argc,argv); int success=0; try { @@ -307,6 +381,7 @@ int main(int argc, char**argv) { std::cout << "small test : " << smalltest << std::endl; success+=test_opdir(world); + success+=test_combined_operators<3>(world); if (!smalltest) success+=testgradG(world); } catch (const SafeMPI::Exception& e) { @@ -325,10 +400,10 @@ int main(int argc, char**argv) { print(s); error("caught a c-string exception"); } - catch (const char* s) { - print(s); - error("caught a c-string exception"); - } +// catch (const char* s) { +// print(s); +// error("caught a c-string exception"); +// } catch (const std::string& s) { print(s); error("caught a string (class) exception"); From 681a3159761a4a53ce3b2db4c286f952cd4628e8 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Tue, 5 Dec 2023 14:30:14 -0500 Subject: [PATCH 066/109] mp3 working for the he atom without R2 --- src/madness/chem/mp2.cc | 55 ++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 31 deletions(-) diff --git a/src/madness/chem/mp2.cc b/src/madness/chem/mp2.cc index a82e07c367a..e314c0c04ad 100644 --- a/src/madness/chem/mp2.cc +++ b/src/madness/chem/mp2.cc @@ -467,7 +467,7 @@ double MP2::mp3() const { // compute intermediates for terms G, I, H, and J // \sum_j tau_ij(1,2) * phi_j(2) - std::vector tau_i_jj(hf->nocc() - param.freeze()); + std::vector tau_kk_i(hf->nocc() - param.freeze()); std::vector tau_i_jj_R2(hf->nocc() - param.freeze()); // \sum_j tau_ij(1,2) * phi_j(1) std::vector tau_ij_j(hf->nocc() - param.freeze()); @@ -475,25 +475,25 @@ double MP2::mp3() const { for (int i = param.freeze(); i < hf->nocc(); ++i) { for (int j = param.freeze(); j < hf->nocc(); ++j) { // auto tmp2 = multiply(clusterfunctions(i, j), hf->R2orbital(j), {3, 4, 5}); - auto tmp2 = multiply(clusterfunctions(i, j), hf->orbital(j), {3, 4, 5}); + auto tmp2 = multiply(clusterfunctions_R(i, j), hf->orbital(j), {3, 4, 5}); for (auto& t: tmp2) tau_i_jj_R2[i].push_back(t); // auto tmp4 = multiply(clusterfunctions(i, j), hf->R2orbital(j), {0, 1, 2}); - auto tmp4 = multiply(clusterfunctions(i, j), hf->orbital(j), {0, 1, 2}); + auto tmp4 = multiply(clusterfunctions_R(i, j), hf->orbital(j), {0, 1, 2}); for (auto& t: tmp4) tau_ij_j_R2[i].push_back(t); // auto tmp1 = multiply(clusterfunctions(i, j), hf->nemo(j), {3, 4, 5}); - auto tmp1 = multiply(clusterfunctions(i, j), hf->orbital(j), {3, 4, 5}); - for (auto& t: tmp1) tau_i_jj[i].push_back(t); + auto tmp1 = multiply(clusterfunctions_R(i, j), hf->orbital(j), {0, 1, 2}); + for (auto& t: tmp1) tau_kk_i[i].push_back(t); // auto tmp3 = multiply(clusterfunctions(i, j), hf->nemo(j), {0, 1, 2}); - auto tmp3 = multiply(clusterfunctions(i, j), hf->orbital(j), {0, 1, 2}); + auto tmp3 = multiply(clusterfunctions_R(i, j), hf->orbital(j), {0, 1, 2}); for (auto& t: tmp3) tau_ij_j[i].push_back(t); } } - print("info on tau_i_jj"); + print("info on tau_kk_i"); for (int i = param.freeze(); i < hf->nocc(); ++i) { - for (auto& c: tau_i_jj[i]) c.info(); + for (auto& c: tau_kk_i[i]) c.info(); } print("info on tau_ij_j"); for (int i = param.freeze(); i < hf->nocc(); ++i) { @@ -505,36 +505,29 @@ double MP2::mp3() const { // terms G, I, H, J of Bartlett/Silver 1975 real_convolution_3d& g = *(g12->get_op()); for (int i = param.freeze(); i < hf->nocc(); ++i) { + + // tmp(1,2) = g(1,1') | tau_ij(1',2) j(2) > timer t4(world, "gtau"); - g.set_particle(2); - auto gtau_same = g(tau_i_jj_R2[i]); // < tau_ij(1,2) j(2) | g(2,2') | -// auto gtau = g(clusterfunctions_R(0,0)); // < tau_ij(1,2) j(2) | g(2,2') | -// auto gtau_same_swap= swap_particles(gtau_same); + g.set_particle(1); + auto gtau_same = g(tau_kk_i[i]); t4.tag("compute gtau_same"); + + // tmp(1',2) = g(1',1) | tau_ij(1,2) j(1) > g.set_particle(1); auto gtau_other = g(tau_ij_j_R2[i]); // < tau_ij(1,2) j(1) | g(1,1') | t4.tag("compute gtau_other"); -// double G = inner(gtau_same, tau_i_jj[i], R2); - double G = inner(gtau_same, tau_i_jj[i]); + double G = inner(tau_kk_i[i], gtau_same); printf("G %12.8f\n", G); -// double G1 = inner(gtau, clusterfunctions_R(0,0), R2); -// printf("G1 %12.8f\n", G1); -// double G_swap = inner(gtau_same_swap, tau_i_jj[i], R2); -// printf("Gswap %12.8f\n", G_swap); -// double G_swap2 = inner(gtau_same_swap, tau_ij_j[i], R2); -// printf("Gswap2 %12.8f\n", G_swap2); + double H = inner(tau_ij_j[i], gtau_other); + printf("H %12.8f\n", H); -// double I = inner(gtau_same, tau_ij_j[i], R2); - double I = inner(gtau_same, tau_ij_j[i]); + double I = inner(tau_kk_i[i], gtau_other); printf("I %12.8f\n", I); -// double H = inner(gtau_other, tau_i_jj[i], R2); - double H = inner(gtau_other, tau_i_jj[i]); - printf("H %12.8f\n", H); -// double J = inner(gtau_other, tau_ij_j[i], R2); - double J = inner(gtau_other, tau_ij_j[i]); + + double J = inner(tau_ij_j[i], gtau_same); printf("J %12.8f\n", J); t4.tag("compute inner products"); @@ -580,10 +573,10 @@ double MP2::mp3() const { double tmp=0.0; for (int k=param.freeze(); knocc(); ++k) { for (int l=param.freeze(); lnocc(); ++l) { - auto bra_ik = clusterfunctions(i,k); - auto bra_ki = clusterfunctions(k,i); - double ovlp_E=inner(bra_ik,clusterfunctions(j,l),R2); - double ovlp_F=inner(bra_ki,clusterfunctions(j,l),R2); + auto bra_ik = clusterfunctions_R(i,k); + auto bra_ki = clusterfunctions_R(k,i); + double ovlp_E=inner(bra_ik,clusterfunctions_R(j,l)); + double ovlp_F=inner(bra_ki,clusterfunctions_R(j,l)); auto ket_i=hf->nemo(i); auto ket_k=hf->nemo(k); auto bra_j=hf->R2orbital(j); From 6e324321099f02ca7e477962d8b997874fb63872 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Wed, 6 Dec 2023 09:41:03 -0500 Subject: [PATCH 067/109] mp3 working for the he dimer, canonical and localized orbitals --- src/madness/chem/mp2.cc | 139 ++++++++++------------------------------ 1 file changed, 35 insertions(+), 104 deletions(-) diff --git a/src/madness/chem/mp2.cc b/src/madness/chem/mp2.cc index e314c0c04ad..83d4f5ac5ae 100644 --- a/src/madness/chem/mp2.cc +++ b/src/madness/chem/mp2.cc @@ -365,76 +365,6 @@ double MP2::mp3() const { } } - - if (0) { - print_header3("G with inner products"); - real_convolution_3d& g = *(g12->get_op()); - g.set_particle(1); - real_function_3d one=real_factory_3d(world).functor([](const coord_3d& x){return 1.0;}); - auto one2=std::vector({CCPairFunction(one,one)}); - auto phi0=std::vector({CCPairFunction(hf->orbital(0),hf->orbital(0))}); - { - auto tmp=inner(phi0,phi0,{0,1,2},{0,1,2}); - double H1=inner(tmp,g12*phi0); - printf("H1 = %12.8f\n",H1); - double H1one=inner(tmp,g12*one2); - printf("H1one = %12.8f\n",H1one); - - double na=inner(phi0[0].get_a(),phi0[0].get_a()); - double nb=inner(phi0[0].get_b(),phi0[0].get_a()); - auto tmp1=g(phi0); - auto tmp2=g(phi0[0].get_a()); - double n=inner(tmp2,phi0[0].get_a()); - print("n",n); - double ta=inner(tmp1[0].get_a(),phi0[0].get_a()); - double bb=inner(tmp1[0].get_b(),phi0[0].get_a()); - print("norms (a,b) of phi0",na,nb); - print("norms (a,b) of g(phi0)",ta,bb); - double H2=inner(tmp1,phi0); - printf("H2 = %12.8f\n",H2); - } - - - const auto& pair00=clusterfunctions_R(0,0); - for (int i=0; i::get_thresh(); - FunctionDefaults<6>::set_thresh(oldthresh*0.001); - - few[0].get_function().print_size("few[0]"); - auto tmp=inner(few,few,{0,1,2},{0,1,2}); - tmp[0].get_function().print_size("tmp[0]"); - -// auto tmp1=inner(few,few,{0,1,2},{3,4,5}); -// tmp1[0].get_function().print_size("tmp1[0]"); -// -// auto tmp2=inner(few,few2,{0,1,2},{0,1,2}); -// tmp2[0].get_function().print_size("tmp2[0]"); -// - FunctionDefaults<6>::set_thresh(oldthresh); - print("finished with inner(tau,tau,0,0)"); - double G1=inner(g12*tmp,{CCPairFunction(hf->orbital(0),hf->orbital(0))}); - printf("G = %12.8f\n",G1); - double G2=inner(g12*tmp,{CCPairFunction(one,one)}); - printf("G = %12.8f\n",G2); - - g.set_particle(2); - auto gtau = g(few); // < tau_ij(1,2) j(2) | g(2,2') | - double G10 = inner(gtau, few); - printf("G convolution %12.8f\n", G10); - - } - } - print("time extra G", t3.reset()); - double term_CD=0.0; double term_GHIJ=0.0; double term_KLMN=0.0; @@ -446,12 +376,12 @@ double MP2::mp3() const { if (1) { for (int i = param.freeze(); i < hf->nocc(); ++i) { for (int j = i; j < hf->nocc(); ++j) { -// auto bra = clusterfunctions(i, j); -// double tmp1 = inner(bra, g12 * clusterfunctions(i, j), R2); -// double tmp2 = inner(bra, g12 * clusterfunctions(j, i), R2); - auto bra = clusterfunctions_R2(i, j); - double tmp1 = inner(bra, g12 * clusterfunctions(i, j)); - double tmp2 = inner(bra, g12 * clusterfunctions(j, i)); + auto bra = clusterfunctions(i, j); + double tmp1 = inner(bra, g12 * clusterfunctions(i, j), R2); + double tmp2 = inner(bra, g12 * clusterfunctions(j, i), R2); +// auto bra = clusterfunctions_R2(i, j); +// double tmp1 = inner(bra, g12 * clusterfunctions(i, j)); +// double tmp2 = inner(bra, g12 * clusterfunctions(j, i)); double fac = (i == j) ? 0.5 : 1.0; double tmp = fac * (4.0 * tmp1 - 2.0 * tmp2); printf("mp3 energy: term_CD %2d %2d: %12.8f\n", i, j, tmp); @@ -468,26 +398,24 @@ double MP2::mp3() const { // \sum_j tau_ij(1,2) * phi_j(2) std::vector tau_kk_i(hf->nocc() - param.freeze()); - std::vector tau_i_jj_R2(hf->nocc() - param.freeze()); +// std::vector tau_kk_i_R2(hf->nocc() - param.freeze()); // \sum_j tau_ij(1,2) * phi_j(1) std::vector tau_ij_j(hf->nocc() - param.freeze()); - std::vector tau_ij_j_R2(hf->nocc() - param.freeze()); +// std::vector tau_ij_j_R2(hf->nocc() - param.freeze()); for (int i = param.freeze(); i < hf->nocc(); ++i) { for (int j = param.freeze(); j < hf->nocc(); ++j) { // auto tmp2 = multiply(clusterfunctions(i, j), hf->R2orbital(j), {3, 4, 5}); - auto tmp2 = multiply(clusterfunctions_R(i, j), hf->orbital(j), {3, 4, 5}); - for (auto& t: tmp2) tau_i_jj_R2[i].push_back(t); - +// for (auto& t: tmp2) tau_kk_i_R2[i].push_back(t); +// // auto tmp4 = multiply(clusterfunctions(i, j), hf->R2orbital(j), {0, 1, 2}); - auto tmp4 = multiply(clusterfunctions_R(i, j), hf->orbital(j), {0, 1, 2}); - for (auto& t: tmp4) tau_ij_j_R2[i].push_back(t); +// for (auto& t: tmp4) tau_ij_j_R2[i].push_back(t); // auto tmp1 = multiply(clusterfunctions(i, j), hf->nemo(j), {3, 4, 5}); - auto tmp1 = multiply(clusterfunctions_R(i, j), hf->orbital(j), {0, 1, 2}); + auto tmp1 = multiply(clusterfunctions(i, j), hf->R2orbital(j), {0, 1, 2}); for (auto& t: tmp1) tau_kk_i[i].push_back(t); // auto tmp3 = multiply(clusterfunctions(i, j), hf->nemo(j), {0, 1, 2}); - auto tmp3 = multiply(clusterfunctions_R(i, j), hf->orbital(j), {0, 1, 2}); + auto tmp3 = multiply(clusterfunctions(i, j), hf->R2orbital(j), {0, 1, 2}); for (auto& t: tmp3) tau_ij_j[i].push_back(t); } } @@ -514,20 +442,23 @@ double MP2::mp3() const { // tmp(1',2) = g(1',1) | tau_ij(1,2) j(1) > g.set_particle(1); - auto gtau_other = g(tau_ij_j_R2[i]); // < tau_ij(1,2) j(1) | g(1,1') | + auto gtau_other = g(tau_ij_j[i]); // < tau_ij(1,2) j(1) | g(1,1') | t4.tag("compute gtau_other"); - double G = inner(tau_kk_i[i], gtau_same); + auto bra_kk_i = multiply(tau_kk_i[i],R2,{3,4,5}); + auto bra_ij_j = multiply(tau_ij_j[i],R2,{3,4,5}); + + double G = inner(bra_kk_i, gtau_same); printf("G %12.8f\n", G); - double H = inner(tau_ij_j[i], gtau_other); + double H = inner(bra_ij_j, gtau_other); printf("H %12.8f\n", H); - double I = inner(tau_kk_i[i], gtau_other); + double I = inner(bra_kk_i, gtau_other); printf("I %12.8f\n", I); - double J = inner(tau_ij_j[i], gtau_same); + double J = inner(bra_ij_j, gtau_same); printf("J %12.8f\n", J); t4.tag("compute inner products"); @@ -543,19 +474,19 @@ double MP2::mp3() const { double tmp = 0.0; for (int k = param.freeze(); k < hf->nocc(); ++k) { - auto tau_ik = clusterfunctions_R(i, k); - auto tau_kj = clusterfunctions_R(k, j); - auto tau_ij = clusterfunctions_R(i, j); - auto tau_ji = clusterfunctions_R(j, i); - auto tau_ik_gkj = multiply(tau_ik, gij(k, j), {0, 1, 2}); - auto tau_kj_gki = multiply(tau_kj, gij(k, i), {0, 1, 2}); + auto tau_ik = clusterfunctions(i, k); + auto tau_kj = clusterfunctions(k, j); + auto tau_ij = clusterfunctions(i, j); + auto tau_ji = clusterfunctions(j, i); + auto tau_ik_gkj = multiply(tau_ik, gij(k, j), {3, 4, 5}); + auto tau_kj_gki = multiply(tau_kj, gij(k, i), {3, 4, 5}); // auto tau_ik_gkj = multiply(tau_ik,gij(k,j),{0,1,2}); // auto tau_kj_gki = multiply(tau_kj,gij(k,i),{0,1,2}); - double K = inner(tau_ij, tau_ik_gkj);//, R2); - double L = inner(tau_ij, tau_kj_gki);//, R2); - double M = inner(tau_ji, tau_kj_gki);//, R2); - double N = inner(tau_ji, tau_ik_gkj);//, R2); + double K = inner(tau_ij, tau_ik_gkj, R2); + double L = inner(tau_ij, tau_kj_gki, R2); + double M = inner(tau_ji, tau_kj_gki, R2); + double N = inner(tau_ji, tau_ik_gkj, R2); print("K,L,M,N", K, L, M, N); tmp += -4 * K - 4 * L + 2 * M + 2 * N; @@ -573,10 +504,10 @@ double MP2::mp3() const { double tmp=0.0; for (int k=param.freeze(); knocc(); ++k) { for (int l=param.freeze(); lnocc(); ++l) { - auto bra_ik = clusterfunctions_R(i,k); - auto bra_ki = clusterfunctions_R(k,i); - double ovlp_E=inner(bra_ik,clusterfunctions_R(j,l)); - double ovlp_F=inner(bra_ki,clusterfunctions_R(j,l)); + auto bra_ik = clusterfunctions(i,k); + auto bra_ki = clusterfunctions(k,i); + double ovlp_E=inner(bra_ik,clusterfunctions(j,l),R2); + double ovlp_F=inner(bra_ki,clusterfunctions(j,l),R2); auto ket_i=hf->nemo(i); auto ket_k=hf->nemo(k); auto bra_j=hf->R2orbital(j); From 8b692ba3bff432b185fe9d8e195c04fb8ad9ff23 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Wed, 6 Dec 2023 14:15:32 -0500 Subject: [PATCH 068/109] less output --- src/madness/chem/CCStructures.cc | 2 +- src/madness/chem/ccpairfunction.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/madness/chem/CCStructures.cc b/src/madness/chem/CCStructures.cc index ab2a1265884..9cb8c2017b5 100644 --- a/src/madness/chem/CCStructures.cc +++ b/src/madness/chem/CCStructures.cc @@ -404,7 +404,7 @@ size_t CCConvolutionOperator::info() const { SeparatedConvolution * CCConvolutionOperator::init_op(const OpType& type, const Parameters& parameters) const { - bool debug=true; + bool debug=false; bool printme=(world.rank()==0) and debug; print("init_op: creating",type,"with thresh, lo, gamma",parameters.thresh_op,parameters.lo,parameters.gamma); return new SeparatedConvolution(world,OperatorInfo(parameters.gamma,parameters.lo,parameters.thresh_op,type)); diff --git a/src/madness/chem/ccpairfunction.h b/src/madness/chem/ccpairfunction.h index 7c83e64df76..c00f31f8947 100644 --- a/src/madness/chem/ccpairfunction.h +++ b/src/madness/chem/ccpairfunction.h @@ -430,10 +430,10 @@ using pureT=Function; std::vector result; for (auto& o : other) { double cpu0=cpu_time(); - std::cout << "multiply " << o.name(); +// std::cout << "multiply " << o.name(); result.push_back(multiply(o,f,v1)); double cpu1=cpu_time(); - std::cout << " done after " << cpu1-cpu0 << std::endl; +// std::cout << " done after " << cpu1-cpu0 << std::endl; } return result; } @@ -576,7 +576,7 @@ using pureT=Function; std::size_t bufsize=256; char buf[bufsize]; snprintf(buf,bufsize,"result from inner %10s %10s %12.8f %4.1fs",a.name(true).c_str(),b.name().c_str(),tmp,wall1-wall0); - print(std::string(buf)); +// print(std::string(buf)); wall0=wall1; result+=tmp; } From 7ecf9e9e675d94f4c7d125fe0e71534d167ba23a Mon Sep 17 00:00:00 2001 From: fbischoff Date: Wed, 6 Dec 2023 14:44:55 -0500 Subject: [PATCH 069/109] less output --- src/apps/mp2/mp2.cc | 5 ++-- src/madness/chem/CCStructures.cc | 2 +- src/madness/chem/ccpairfunction.cc | 6 ++-- src/madness/chem/mp2.cc | 45 ++++++++---------------------- 4 files changed, 18 insertions(+), 40 deletions(-) diff --git a/src/apps/mp2/mp2.cc b/src/apps/mp2/mp2.cc index 154919f1f76..e81c475293d 100644 --- a/src/apps/mp2/mp2.cc +++ b/src/apps/mp2/mp2.cc @@ -89,11 +89,10 @@ int main(int argc, char** argv) { } double mp3_correction=mp2.mp3(); - print("mp3 correction",mp3_correction); double mp3_energy=mp3_correction+mp2_energy; if(world.rank() == 0) { - printf("final hf/mp3/total energy %12.8f %12.8f %12.8f\n", - hf_energy,mp3_energy,hf_energy+mp3_energy); + printf("final hf/mp2/mp3/total energy %12.8f %12.8f %12.8f\n", + hf_energy,mp2_energy,mp3_correction,hf_energy+mp3_energy); } } catch (std::exception& e) { diff --git a/src/madness/chem/CCStructures.cc b/src/madness/chem/CCStructures.cc index 9cb8c2017b5..9a80c260cfc 100644 --- a/src/madness/chem/CCStructures.cc +++ b/src/madness/chem/CCStructures.cc @@ -406,7 +406,7 @@ SeparatedConvolution * CCConvolutionOperator::init_op(const OpType& type, const Parameters& parameters) const { bool debug=false; bool printme=(world.rank()==0) and debug; - print("init_op: creating",type,"with thresh, lo, gamma",parameters.thresh_op,parameters.lo,parameters.gamma); + if (printme) print("init_op: creating",type,"with thresh, lo, gamma",parameters.thresh_op,parameters.lo,parameters.gamma); return new SeparatedConvolution(world,OperatorInfo(parameters.gamma,parameters.lo,parameters.thresh_op,type)); } diff --git a/src/madness/chem/ccpairfunction.cc b/src/madness/chem/ccpairfunction.cc index b3e58df5d1f..0412f64fee0 100644 --- a/src/madness/chem/ccpairfunction.cc +++ b/src/madness/chem/ccpairfunction.cc @@ -564,10 +564,10 @@ std::vector apply(const ProjectorBase& projector, const std::vec auto tmp=Q1(Q2(std::vector({pf}))); // auto tmp=Q2(Q1(std::vector({pf}))); - print("result of SO"); +// print("result of SO"); // for (auto& t: tmp) t.print_size(); for (auto& t: tmp) result.push_back(t); - for (auto& t: result) t.print_size(); +// for (auto& t: result) t.print_size(); } else if (auto P=dynamic_cast*>(&projector)) { // CCTimer t(world,"P block"); @@ -657,7 +657,7 @@ std::vector apply(const SeparatedConvolution& op, const } else { MADNESS_CHECK_THROW(false,"confused type in apply(CCPairFunction)"); } - t.tag("applying op to CCPairFunction "+arg.name()); +// t.tag("applying op to CCPairFunction "+arg.name()); } return result; diff --git a/src/madness/chem/mp2.cc b/src/madness/chem/mp2.cc index 83d4f5ac5ae..2e90d382531 100644 --- a/src/madness/chem/mp2.cc +++ b/src/madness/chem/mp2.cc @@ -279,7 +279,6 @@ double MP2::mp3() const { auto R = hf->nemo_ptr->ncf->function(); double mp3_energy = 0.0; - CCTimer t1(world, "make pairs"); // load converged MP1 wave functions for (int i = param.freeze(); i < hf->nocc(); ++i) { for (int j = i; j < hf->nocc(); ++j) { @@ -302,10 +301,7 @@ double MP2::mp3() const { } } } - t1.print(); - CCTimer t_R2(world,"make R2 pairs"); Pairs clusterfunctions_R2; - Pairs clusterfunctions_R; for (int i=param.freeze(); inocc(); ++i) { for (int j=i; jnocc(); ++j) { { @@ -313,14 +309,8 @@ double MP2::mp3() const { auto tmp2 = multiply(tmp1, R2, {3, 4, 5}); for (auto& t: tmp2) clusterfunctions_R2(i, j).push_back(t); } - { - auto tmp1 = multiply(clusterfunctions(i, j), R, {0, 1, 2}); - auto tmp2 = multiply(tmp1, R, {3, 4, 5}); - for (auto& t: tmp2) clusterfunctions_R(i, j).push_back(t); - } } } - t_R2.print(); for (int i = param.freeze(); i < hf->nocc(); ++i) { for (int j = i; j < hf->nocc(); ++j) { @@ -334,7 +324,7 @@ double MP2::mp3() const { CCConvolutionOperator::Parameters cparam; auto g12=CCConvolutionOperatorPtr(world,OpType::OT_G12,cparam); - CCTimer t2(world,"recompute MP2"); + timer t2(world, "recompute MP2"); // recompute MP2 energy double mp2_energy=0.0; @@ -346,15 +336,14 @@ double MP2::mp3() const { double exchange=inner({bra},g12*clusterfunctions(j,i),R2); double fac=(i==j) ? 0.5: 1.0; double pair_energy=fac*(4.0*direct-2.0*exchange); - printf("MP2 energy: cluster %2d %2d: %12.8f\n",i,j,pair_energy); + printf("MP2 energy for pair %2d %2d: %12.8f\n",i,j,pair_energy); mp2_energy+=pair_energy; } } printf("total mp2 energy %12.8f\n",mp2_energy); - print("time clusterfunction",t2.reset()); + t2.tag("recompute MP2 energy"); print_header3("compute the MP3 energy"); - CCTimer t3(world,"MP3"); // compute the term (2) madness::Pairs gij; @@ -390,31 +379,21 @@ double MP2::mp3() const { } } printf("MP3 energy: term_CD %12.8f\n", term_CD); - print("time term_CD", t3.reset()); - print(""); + t2.tag("CD term"); // compute intermediates for terms G, I, H, and J // \sum_j tau_ij(1,2) * phi_j(2) std::vector tau_kk_i(hf->nocc() - param.freeze()); -// std::vector tau_kk_i_R2(hf->nocc() - param.freeze()); // \sum_j tau_ij(1,2) * phi_j(1) std::vector tau_ij_j(hf->nocc() - param.freeze()); -// std::vector tau_ij_j_R2(hf->nocc() - param.freeze()); for (int i = param.freeze(); i < hf->nocc(); ++i) { for (int j = param.freeze(); j < hf->nocc(); ++j) { -// auto tmp2 = multiply(clusterfunctions(i, j), hf->R2orbital(j), {3, 4, 5}); -// for (auto& t: tmp2) tau_kk_i_R2[i].push_back(t); -// -// auto tmp4 = multiply(clusterfunctions(i, j), hf->R2orbital(j), {0, 1, 2}); -// for (auto& t: tmp4) tau_ij_j_R2[i].push_back(t); -// auto tmp1 = multiply(clusterfunctions(i, j), hf->nemo(j), {3, 4, 5}); auto tmp1 = multiply(clusterfunctions(i, j), hf->R2orbital(j), {0, 1, 2}); for (auto& t: tmp1) tau_kk_i[i].push_back(t); -// auto tmp3 = multiply(clusterfunctions(i, j), hf->nemo(j), {0, 1, 2}); auto tmp3 = multiply(clusterfunctions(i, j), hf->R2orbital(j), {0, 1, 2}); for (auto& t: tmp3) tau_ij_j[i].push_back(t); } @@ -428,7 +407,7 @@ double MP2::mp3() const { for (auto& c: tau_ij_j[i]) c.info(); } - print("time GHIJ prep", t3.reset()); + t2.tag("GHIJ prep"); // terms G, I, H, J of Bartlett/Silver 1975 real_convolution_3d& g = *(g12->get_op()); @@ -467,7 +446,7 @@ double MP2::mp3() const { term_GHIJ += tmp; } printf("MP3 energy: term_GHIJ %12.8f\n", term_GHIJ); - print("time GHIJ ", t3.reset()); + t2.tag("GHIJ term"); for (int i = param.freeze(); i < hf->nocc(); ++i) { for (int j = param.freeze(); j < hf->nocc(); ++j) { @@ -487,7 +466,6 @@ double MP2::mp3() const { double L = inner(tau_ij, tau_kj_gki, R2); double M = inner(tau_ji, tau_kj_gki, R2); double N = inner(tau_ji, tau_ik_gkj, R2); - print("K,L,M,N", K, L, M, N); tmp += -4 * K - 4 * L + 2 * M + 2 * N; } @@ -496,8 +474,9 @@ double MP2::mp3() const { } } printf("MP3 energy: term_KLMN (KLMN) %12.8f\n", term_KLMN); - print("time term_KLMN", t3.reset()); + t2.tag("KLMN term"); } + print_header3("computing term EF of the MP3 energy with R2_bra"); for (int i = param.freeze(); i < hf->nocc(); ++i) { for (int j = param.freeze(); j < hf->nocc(); ++j) { @@ -514,7 +493,7 @@ double MP2::mp3() const { auto bra_l=hf->R2orbital(l); double g_jlik=inner(bra_j*ket_i, (*g12)(bra_l*ket_k)); - print("",g_jlik); +// print("",g_jlik); tmp+=(2.0*ovlp_E - ovlp_F)*g_jlik; } } @@ -523,14 +502,14 @@ double MP2::mp3() const { } } printf("MP3 energy: term_EF %12.8f\n",term_EF); - print("time term_EF",t3.reset()); - t3.print(); + t2.tag("EF term"); + printf("term_CD %12.8f\n",term_CD); printf("term_GHIJ %12.8f\n",term_GHIJ); printf("term_KLMN %12.8f\n",term_KLMN); printf("term_EF %12.8f\n",term_EF); mp3_energy=term_CD+term_GHIJ+term_KLMN+term_EF; - printf("MP3 en %12.8f\n",mp3_energy); + printf("MP3 energy contribution %12.8f\n",mp3_energy); return mp3_energy; From c9886f20591caee8995d7b0f22ae4a4f8a86df35 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Wed, 6 Dec 2023 14:50:42 -0500 Subject: [PATCH 070/109] less output --- src/madness/chem/ccpairfunction.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/madness/chem/ccpairfunction.cc b/src/madness/chem/ccpairfunction.cc index 0412f64fee0..09ebc9abcfd 100644 --- a/src/madness/chem/ccpairfunction.cc +++ b/src/madness/chem/ccpairfunction.cc @@ -601,7 +601,7 @@ std::vector apply(const ProjectorBase& projector, const std::vec // print("entering Q block"); // reuse the projector code above std::vector tmp=madness::apply(Q->get_P_projector(),std::vector(1,pf)); - for (auto& t : tmp) t.print_size(); +// for (auto& t : tmp) t.print_size(); for (auto& t : tmp) { t*=-1.0; result.push_back(t); From 5532e7e81dd9eb3299f3c905df7aaf0664f6617a Mon Sep 17 00:00:00 2001 From: fbischoff Date: Wed, 6 Dec 2023 14:52:15 -0500 Subject: [PATCH 071/109] less output --- src/apps/mp2/mp2.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/apps/mp2/mp2.cc b/src/apps/mp2/mp2.cc index e81c475293d..111f5d7c2b4 100644 --- a/src/apps/mp2/mp2.cc +++ b/src/apps/mp2/mp2.cc @@ -91,7 +91,7 @@ int main(int argc, char** argv) { double mp3_energy=mp3_correction+mp2_energy; if(world.rank() == 0) { - printf("final hf/mp2/mp3/total energy %12.8f %12.8f %12.8f\n", + printf("final hf/mp2/mp3/total energy %12.8f %12.8f %12.8f %12.8f\n", hf_energy,mp2_energy,mp3_correction,hf_energy+mp3_energy); } } catch (std::exception& e) { From c5e62df508b4eb49e3755d941c9313dff5872874 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Sat, 9 Dec 2023 23:10:53 +0100 Subject: [PATCH 072/109] minor changes --- src/madness/chem/CC2.cc | 348 +++++++++++++++++++++++++------ src/madness/chem/CC2.h | 2 + src/madness/chem/CCPotentials.cc | 34 ++- src/madness/chem/CCStructures.h | 10 +- 4 files changed, 310 insertions(+), 84 deletions(-) diff --git a/src/madness/chem/CC2.cc b/src/madness/chem/CC2.cc index f3ddd78e8db..106a3897f1a 100644 --- a/src/madness/chem/CC2.cc +++ b/src/madness/chem/CC2.cc @@ -36,10 +36,10 @@ CC2::solve() { // singles for ground state CC_vecfunction cc2singles; - double mp2_energy, cc2_energy; + double mp2_energy=0.0, cc2_energy=0.0, mp3_energy=0.0; bool need_tdhf=parameters.response(); - bool need_mp2=(ctype==CT_MP2 or ctype==CT_CISPD or ctype==CT_ADC2); + bool need_mp2=(ctype==CT_MP2 or ctype==CT_CISPD or ctype==CT_ADC2 or ctype==CT_MP3); bool need_cc2=(ctype==CT_LRCC2 or ctype==CT_CC2); // check for restart data for CC2, otherwise use MP2 as guess @@ -56,8 +56,12 @@ CC2::solve() { } if (need_mp2) { - initialize_pairs(mp2pairs, GROUND_STATE, CT_MP2, CC_vecfunction(PARTICLE), CC_vecfunction(RESPONSE), 0); - mp2_energy = solve_mp2_coupled(mp2pairs); + bool restarted=initialize_pairs(mp2pairs, GROUND_STATE, CT_MP2, CC_vecfunction(PARTICLE), CC_vecfunction(RESPONSE), 0); + if (restarted and parameters.no_compute_mp2()) { + for (auto& pair : mp2pairs.allpairs) mp2_energy+=CCOPS.compute_pair_correlation_energy(pair.second); + } else { + mp2_energy = solve_mp2_coupled(mp2pairs); + } output_calc_info_schema("mp2",mp2_energy); output.section(assign_name(CT_MP2) + " Calculation Ended !"); if (world.rank() == 0) @@ -94,6 +98,8 @@ CC2::solve() { ; // we're good } else if (ctype == CT_MP2) { ; // we're good + } else if (ctype == CT_MP3) { + mp3_energy=mp3_energy_contribution(mp2pairs); } else if (ctype == CT_CC2) { ; // we're good } else if (ctype == CT_CISPD) { @@ -355,6 +361,260 @@ Tensor CC2::enforce_core_valence_separation(const Tensor& fmat) }; +double CC2::mp3_energy_contribution(const Pairs& mp2pairs) const { + + print_header2("computing the MP3 correlation energy"); + print_header3("prepare the cluster function"); + typedef std::vector ClusterFunction; + Pairs clusterfunctions; + + auto R2 = nemo->ncf->square(); + auto R = nemo->ncf->function(); + std::vector nemo_orbital=CCOPS.mo_ket().get_vecfunction(); + std::vector R2_orbital=CCOPS.mo_bra().get_vecfunction(); + const int nocc=CCOPS.mo_ket().size(); + + + double mp3_energy = 0.0; + // load converged MP1 wave functions + for (int i = parameters.freeze(); i < nocc; ++i) { + for (int j = i; j < nocc; ++j) { +// pairs(i, j) = make_pair(i, j); // initialize + ClusterFunction tmp; + tmp.push_back(CCPairFunction(mp2pairs(i, j).function())); + CCPairFunction ij(nemo->get_calc()->amo[i], nemo->get_calc()->amo[j]); + + CCConvolutionOperator::Parameters cparam; + cparam.thresh_op *= 0.1; + auto f12 = CCConvolutionOperatorPtr(world, OpType::OT_F12, cparam); + StrongOrthogonalityProjector Q12(world); + Q12.set_spaces(R2_orbital, nemo_orbital, R2_orbital, nemo_orbital); + auto vfij = Q12(std::vector({f12 * ij})); + for (auto& p: vfij) tmp.push_back(p); + + clusterfunctions(i, j)=tmp; + if (i!=j) { + for (const auto& t : clusterfunctions(i,j)) { + clusterfunctions(j, i).push_back(t.swap_particles()); + } + } + } + } + Pairs clusterfunctions_R2; + for (int i=parameters.freeze(); i(2) + madness::Pairs gij; + + for (int i = parameters.freeze(); i < nocc; ++i) { + for (int j = parameters.freeze(); j < nocc; ++j) { + gij.insert(i,j,(*g12)(nemo_orbital[i]*R2_orbital[j])); + } + } + + double term_CD=0.0; + double term_GHIJ=0.0; + double term_KLMN=0.0; + double term_EF=0.0; + + if (1) { + print_header3("compute term_CD of the MP3 energy with R2_bra"); + // compute the MP3 energy + if (1) { + for (int i = parameters.freeze(); i < nocc; ++i) { + for (int j = i; j < nocc; ++j) { + auto bra = clusterfunctions(i, j); + double tmp1 = inner(bra, g12 * clusterfunctions(i, j), R2); + double tmp2 = inner(bra, g12 * clusterfunctions(j, i), R2); +// auto bra = clusterfunctions_R2(i, j); +// double tmp1 = inner(bra, g12 * clusterfunctions(i, j)); +// double tmp2 = inner(bra, g12 * clusterfunctions(j, i)); + double fac = (i == j) ? 0.5 : 1.0; + double tmp = fac * (4.0 * tmp1 - 2.0 * tmp2); + printf("mp3 energy: term_CD %2d %2d: %12.8f\n", i, j, tmp); + term_CD += tmp; + } + } + } + printf("MP3 energy: term_CD %12.8f\n", term_CD); + t2.tag("CD term"); + + + // compute intermediates for terms G, I, H, and J + + // \sum_j tau_ij(1,2) * phi_j(2) + std::vector tau_kk_i(nocc - parameters.freeze()); + // \sum_j tau_ij(1,2) * phi_j(1) + std::vector tau_ij_j(nocc - parameters.freeze()); + for (int i = parameters.freeze(); i < nocc; ++i) { + for (int j = parameters.freeze(); j < nocc; ++j) { + + auto tmp1 = multiply(clusterfunctions(i, j), R2_orbital[j], {0, 1, 2}); + for (auto& t: tmp1) tau_kk_i[i].push_back(t); + + auto tmp3 = multiply(clusterfunctions(i, j), R2_orbital[j], {0, 1, 2}); + for (auto& t: tmp3) tau_ij_j[i].push_back(t); + } + } + print("info on tau_kk_i"); + for (int i = parameters.freeze(); i < nocc; ++i) { + for (auto& c: tau_kk_i[i]) c.info(); + } + print("info on tau_ij_j"); + for (int i = parameters.freeze(); i < nocc; ++i) { + for (auto& c: tau_ij_j[i]) c.info(); + } + + t2.tag("GHIJ prep"); + + // terms G, I, H, J of Bartlett/Silver 1975 + real_convolution_3d& g = *(g12->get_op()); + for (int i = parameters.freeze(); i < nocc; ++i) { + + // tmp(1,2) = g(1,1') | tau_ij(1',2) j(2) > + timer t4(world, "gtau"); + g.set_particle(1); + auto gtau_same = g(tau_kk_i[i]); + t4.tag("compute gtau_same"); + + // tmp(1',2) = g(1',1) | tau_ij(1,2) j(1) > + g.set_particle(1); + auto gtau_other = g(tau_ij_j[i]); // < tau_ij(1,2) j(1) | g(1,1') | + t4.tag("compute gtau_other"); + + + auto bra_kk_i = multiply(tau_kk_i[i],R2,{3,4,5}); + auto bra_ij_j = multiply(tau_ij_j[i],R2,{3,4,5}); + + double G = inner(bra_kk_i, gtau_same); + printf("G %12.8f\n", G); + + double H = inner(bra_ij_j, gtau_other); + printf("H %12.8f\n", H); + + double I = inner(bra_kk_i, gtau_other); + printf("I %12.8f\n", I); + + double J = inner(bra_ij_j, gtau_same); + printf("J %12.8f\n", J); + + t4.tag("compute inner products"); + double tmp = (8.0 * G - 4.0 * I + 2.0 * H - 4.0 * J); + printf("mp3 energy: term_GHIJ %2d %12.8f\n", i, tmp); + term_GHIJ += tmp; + } + printf("MP3 energy: term_GHIJ %12.8f\n", term_GHIJ); + t2.tag("GHIJ term"); + + for (int i = parameters.freeze(); i < nocc; ++i) { + for (int j = parameters.freeze(); j < nocc; ++j) { + double tmp = 0.0; + for (int k = parameters.freeze(); k < nocc; ++k) { + + auto tau_ik = clusterfunctions(i, k); + auto tau_kj = clusterfunctions(k, j); + auto tau_ij = clusterfunctions(i, j); + auto tau_ji = clusterfunctions(j, i); + auto tau_ik_gkj = multiply(tau_ik, gij(k, j), {3, 4, 5}); + auto tau_kj_gki = multiply(tau_kj, gij(k, i), {3, 4, 5}); +// auto tau_ik_gkj = multiply(tau_ik,gij(k,j),{0,1,2}); +// auto tau_kj_gki = multiply(tau_kj,gij(k,i),{0,1,2}); + + double K = inner(tau_ij, tau_ik_gkj, R2); + double L = inner(tau_ij, tau_kj_gki, R2); + double M = inner(tau_ji, tau_kj_gki, R2); + double N = inner(tau_ji, tau_ik_gkj, R2); + + tmp += -4 * K - 4 * L + 2 * M + 2 * N; + } + printf("mp3 energy: term_KLMN with particle=1 %2d %2d %12.8f\n", i, j, tmp); + term_KLMN += tmp; + } + } + printf("MP3 energy: term_KLMN (KLMN) %12.8f\n", term_KLMN); + t2.tag("KLMN term"); + } + + print_header3("computing term EF of the MP3 energy with R2_bra"); + for (int i = parameters.freeze(); i < nocc; ++i) { + for (int j = parameters.freeze(); j < nocc; ++j) { + double tmp=0.0; + for (int k=parameters.freeze(); k",g_jlik); + tmp+=(2.0*ovlp_E - ovlp_F)*g_jlik; + } + } + printf("mp3 energy: term_EF %2d %2d %12.8f\n",i,j,tmp); + term_EF+=tmp; + } + } + printf("MP3 energy: term_EF %12.8f\n",term_EF); + t2.tag("EF term"); + + printf("term_CD %12.8f\n",term_CD); + printf("term_GHIJ %12.8f\n",term_GHIJ); + printf("term_KLMN %12.8f\n",term_KLMN); + printf("term_EF %12.8f\n",term_EF); + mp3_energy=term_CD+term_GHIJ+term_KLMN+term_EF; + printf("MP3 energy contribution %12.8f\n",mp3_energy); + + + return mp3_energy; +} + + // Solve the CCS equations for the ground state (debug potential and check HF convergence) std::vector CC2::solve_ccs() { // output.section("SOLVE CCS"); @@ -398,9 +658,6 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { std::vector result_vec = task(pair_vec, CCOPS.mo_ket().get_vecfunction(), CCOPS.mo_bra().get_vecfunction(), parameters, nemo->R_square, nemo->ncf->U1vec(),std::vector({"Ue","KffK"})); -// std::vector Gfij_vec = task(pair_vec, CCOPS.mo_ket().get_vecfunction(), -// CCOPS.mo_bra().get_vecfunction(), parameters, -// nemo->R_square, nemo->ncf->U1vec(),std::vector({"f12phi"})); taskq->print_taskq(); taskq->run_all(); @@ -414,10 +671,12 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { // transform vector back to Pairs structure for (int i = 0; i < pair_vec.size(); i++) { - pair_vec[i].constant_part = result_vec[i];// - coupling_constant_term_vec[i]; - //save(pair_vec[i].constant_part, pair_vec[i].name() + "_const"); + pair_vec[i].constant_part = result_vec[i]; + pair_vec[i].functions[0] = CCPairFunction(result_vec[i]); pair_vec[i].constant_part.truncate().reduce_rank(); pair_vec[i].function().truncate().reduce_rank(); + save(pair_vec[i].constant_part, pair_vec[i].name() + "_const"); + save(pair_vec[i].function(), pair_vec[i].name()); if (pair_vec[i].type == GROUND_STATE) total_energy += CCOPS.compute_pair_correlation_energy(pair_vec[i]); } @@ -466,10 +725,8 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { // coupling_vec[position] = tmp_coupling.second; // } //print coupling vec - if (world.rank()==0) std::cout << "aaaaa coupling vector"; - print_size(world, coupling_vec, "couplingvector"); + if (parameters.debug()) print_size(world, coupling_vec, "couplingvector"); - double total_norm = 0.0; double old_energy = total_energy; total_energy = 0.0; @@ -482,21 +739,16 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { taskq->set_printlevel(3); //taskq->cloud.set_debug(true); MacroTaskMp2UpdatePair t; - MacroTask task(world, t, taskq); - std::vector u_update = task(pair_vec, coupling_vec, parameters, nemo->get_calc()->molecule.get_all_coords_vec(), + MacroTask task1(world, t, taskq); + std::vector u_update = task1(pair_vec, coupling_vec, parameters, nemo->get_calc()->molecule.get_all_coords_vec(), CCOPS.mo_ket().get_vecfunction(), CCOPS.mo_bra().get_vecfunction(), nemo->ncf->U1vec(), nemo->ncf->U2()); taskq->print_taskq(); taskq->run_all(); - if (world.rank()==0) std::cout << std::fixed << std::setprecision(1) << "\nFinished pairs update at time " << wall_time() << std::endl; - - if (world.rank()==0) std::cout << std::fixed << std::setprecision(1) << "\nStarting saving pairs and energy calculation at time " << wall_time() << std::endl; if (parameters.kain()) { if (world.rank()==0) std::cout << "Update with KAIN" << std::endl; - StrongOrthogonalityProjector Q(world); - Q.set_spaces(CCOPS.mo_bra().get_vecfunction(), CCOPS.mo_ket().get_vecfunction(), CCOPS.mo_bra().get_vecfunction(), CCOPS.mo_ket().get_vecfunction()); std::vector u; for (auto p : pair_vec) u.push_back(p.function()); @@ -514,52 +766,36 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { } // calculate energy and error and update pairs + double total_rnorm = 0.0, maxrnorm=0.0; for (int i = 0; i < pair_vec.size(); i++) { - //const real_function_6d residue = pair_vec[i].function() - u_update[i]; const double error = u_update[i].norm2(); if (world.rank()==0) std::cout << "residual " << pair_vec[i].i << " " << pair_vec[i].j << " " << error << std::endl; - total_norm = std::max(total_norm, error); - - // if (parameters.kain()) { - // if (world.rank()==0) std::cout << "Update with KAIN" << std::endl; - // StrongOrthogonalityProjector Q(world); - // Q.set_spaces(CCOPS.mo_bra().get_vecfunction(), CCOPS.mo_ket().get_vecfunction(), CCOPS.mo_bra().get_vecfunction(), CCOPS.mo_ket().get_vecfunction()); - // std::vector kain_update = copy(solver.update(pair_vec[i].function(), u_update[i])); - // kain_update = Q(kain_update); - // kain_update.truncate().reduce_rank(); - // kain_update.print_size("Kain-Update-Function"); - // pair_vec[i].update_u(copy(kain_update)); - // } else { - // if (world.rank()==0) std::cout << "Update without KAIN" << std::endl; - // pair_vec[i].update_u(pair_vec[i].function() - u_update[i]); - // } - - //save(pair_vec[i].function(), pair_vec[i].name()); + maxrnorm = std::max(maxrnorm, error); + total_rnorm+=error; + + save(pair_vec[i].function(), pair_vec[i].name()); double energy = 0.0; if (pair_vec[i].type == GROUND_STATE) energy = CCOPS.compute_pair_correlation_energy(pair_vec[i]); total_energy += energy; } - if (world.rank()==0) std::cout << std::fixed << std::setprecision(1) << "\nFinished saving pairs and energy calculation at time " << wall_time() << std::endl; - - // create new Pairs struc for MP2 pairs, needed for coupling - // only temporary! will be removed when compute_local_coupling is changed - //Pairs updated_pairs; for (auto& tmp_pair : pair_vec) { updated_pairs(tmp_pair.i, tmp_pair.j).update_u(tmp_pair.function()); } - output("\n--Iteration " + stringify(iter) + " ended--"); - if (world.rank()==0) std::cout << std::fixed << std::setprecision(1) << "at time " << wall_time() << std::endl; - // std::cout << "old_energy = " << old_energy << std::endl; - // std::cout << "total_energy = " << total_energy << std::endl; - // std::cout << "total_norm = " << total_norm << std::endl; - // std::cout << "econv = " << parameters.econv() << std::endl; - // std::cout << "dconv_6D = " << parameters.dconv_6D() << std::endl; + if (world.rank()==0) { + std::cout << "convergence: total/max residual, energy/norm change " + << std::scientific << std::setprecision(1) + << maxrnorm << " " << total_rnorm << " " + << std::abs(old_energy - total_energy) << std::endl; + // << std::abs(old_norm - total_norm); + printf("finished iteration %2d at time %8.1fs with energy %12.8f\n", + int(iter), wall_time(), total_energy); + } + bool converged = ((std::abs(old_energy - total_energy) < parameters.econv()) - and (total_norm < parameters.dconv_6D())); + and (maxrnorm < parameters.dconv_6D())); - if (world.rank()==0) std::cout << std::fixed << std::setprecision(1) << "\nStarting final energy calculation at time " << wall_time() << std::endl; //print pair energies if converged if (converged) { if (world.rank() == 0) std::cout << "\nPairs converged!\n"; @@ -573,16 +809,6 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { } if (world.rank() == 0) std::cout << "sum =" << total_energy << "\n"; break; - } else { - if (world.rank() == 0) std::cout << "\nCurrent pair energies:\n"; - for (auto& pair : updated_pairs.allpairs) { - const double pair_energy = CCOPS.compute_pair_correlation_energy(pair.second); - if (world.rank() == 0) { - std::cout << std::fixed << std::setprecision(10) << "omega_" - << pair.second.i << pair.second.j << "=" << pair_energy << "\n"; - } - } - if (world.rank() == 0) std::cout << "sum =" << total_energy << "\n"; } } if (world.rank()==0) { diff --git a/src/madness/chem/CC2.h b/src/madness/chem/CC2.h index f656fdda59c..93bf6fdb9e7 100644 --- a/src/madness/chem/CC2.h +++ b/src/madness/chem/CC2.h @@ -129,6 +129,8 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { /// solve the CC2 ground state equations, returns the correlation energy void solve(); + double mp3_energy_contribution(const Pairs& mp2pairs) const; + std::vector solve_ccs(); diff --git a/src/madness/chem/CCPotentials.cc b/src/madness/chem/CCPotentials.cc index 0bb0d150d1b..99852d919b2 100644 --- a/src/madness/chem/CCPotentials.cc +++ b/src/madness/chem/CCPotentials.cc @@ -643,14 +643,12 @@ CCPotentials::fock_residue_6d_macrotask(World& world, const CCPair& u, const CCP real_function_6d x = CompositeFactory(world).ket(copy(Du)).V_for_particle1(copy(U1_axis)).thresh( tight_thresh).special_points(sp6d); x.fill_nuclear_cuspy_tree(op_mod, 1); - if (x.norm2() < tight_thresh) x.print_size("Un_axis_" + stringify(axis)); - - if (x.norm2() < tight_thresh) print("||Un|u>|| is below the threshold\n"); + if (parameters.debug()) x.print_size("Un_axis_" + stringify(axis)); Un1 += x; - Un1.truncate().reduce_rank(); - if (parameters.debug()) Un1.print_size("Un1"); } + if (parameters.debug()) Un1.print_size("Un1"); + if (u.i == u.j) { print(u.name() + " is a diagonal pair: Exploting permutation symmetry\n"); Un2 = madness::swap_particles(Un1); @@ -662,17 +660,14 @@ CCPotentials::fock_residue_6d_macrotask(World& world, const CCPair& u, const CCP double tight_thresh = parameters.thresh_6D(); real_function_6d x = CompositeFactory(world).ket(copy(Du)).V_for_particle2( copy(U1_axis)).thresh(tight_thresh).special_points(sp6d); - x.fill_nuclear_cuspy_tree(op_mod, 2); - if (x.norm2() < tight_thresh) x.print_size("Un_axis_" + stringify(axis)); - - if (x.norm2() < tight_thresh) print("||Un|u>|| is below the threshold\n"); - + x.fill_nuclear_cuspy_tree(op_mod, 2); + if (parameters.debug()) x.print_size("Un_axis_" + stringify(axis)); Un2 += x; - Un2.truncate().reduce_rank(); - if (parameters.debug()) Un2.print_size("Un2"); } + if (parameters.debug()) Un2.print_size("Un2"); } vphi += (Un1 + Un2); + if (parameters.debug()) vphi.print_size("before truncation (Un + J1 + J2)|u>"); vphi.truncate().reduce_rank(); if (parameters.debug()) vphi.print_size("(Un + J1 + J2)|u>"); @@ -774,9 +769,7 @@ CCPotentials::update_pair_mp2_macrotask(World& world, const CCPair& pair, const if (world.rank()==0) print(assign_name(pair.ctype) + "-Microiteration\n"); CCTimer timer_mp2(world, "MP2-Microiteration of pair " + pair.name()); - //print coupling vector - if (world.rank()==0) std::cout << "aaaaa coupling macrotask of pair" << pair.name() << " "; - mp2_coupling.print_size("coupling in macrotask"); + if (parameters.debug()) mp2_coupling.print_size("coupling in macrotask"); double bsh_eps = pair.bsh_eps; real_convolution_6d G = BSHOperator<6>(world, sqrt(-2.0 * bsh_eps), parameters.lo(), parameters.thresh_bsh_6D()); @@ -799,18 +792,19 @@ CCPotentials::update_pair_mp2_macrotask(World& world, const CCPair& pair, const //CCTimer timer_addup(world, "Add constant parts and update pair " + pair.name()); real_function_6d unew = GVmp2 + pair.constant_part; - unew.print_size("unew"); + if (parameters.debug()) unew.print_size("unew"); StrongOrthogonalityProjector Q(world); Q.set_spaces(mo_bra, mo_ket, mo_bra, mo_ket); unew = Q(unew); - unew.print_size("Q12unew"); - //unew.truncate().reduce_rank(); // already done in Q12 application at the end if (parameters.debug())unew.print_size("truncated-unew"); timer_mp2.info(); - const real_function_6d residue = (pair.function() - unew).truncate(); + real_function_6d residue = (pair.function() - unew); + // if (parameters.debug()) residue.print_size("bsh residual"); + residue.truncate(FunctionDefaults<6>::get_thresh()*0.1); + if (parameters.debug()) residue.print_size("bsh residual, truncated"); return residue; } @@ -2455,7 +2449,7 @@ CCPotentials::K_macrotask(World& world, const std::vector& mo_ result += madness::swap_particles(result); } else result += apply_K_macrotask(world, mo_ket, mo_bra, u, 2, parameters); - result.print_size("K|u>"); + if (parameters.debug()) result.print_size("K|u>"); return (result.truncate(parameters.tight_thresh_6D())); } diff --git a/src/madness/chem/CCStructures.h b/src/madness/chem/CCStructures.h index a4f4ddeadf1..14a8b18fbbb 100644 --- a/src/madness/chem/CCStructures.h +++ b/src/madness/chem/CCStructures.h @@ -23,7 +23,7 @@ namespace madness { /// Calculation Types used by CC2 enum CalcType { - CT_UNDEFINED, CT_MP2, CT_CC2, CT_LRCCS, CT_LRCC2, CT_CISPD, CT_ADC2, CT_TDHF, CT_TEST + CT_UNDEFINED, CT_MP2, CT_MP3, CT_CC2, CT_LRCCS, CT_LRCC2, CT_CISPD, CT_ADC2, CT_TDHF, CT_TEST }; /// Type of Pairs used by CC_Pair2 class enum CCState { @@ -210,10 +210,11 @@ struct CCParameters : public QCCalculationParametersBase { set_derived_values(); }; + void initialize_parameters() { double thresh=1.e-3; double thresh_operators=1.e-6; - initialize < std::string > ("calc_type", "mp2", "the calculation type", {"mp2", "cc2", "cis", "lrcc2", "cispd", "adc2", "test"}); + initialize < std::string > ("calc_type", "mp2", "the calculation type", {"mp2", "mp3", "cc2", "cis", "lrcc2", "cispd", "adc2", "test"}); initialize < double > ("lo", 1.e-7, "the finest length scale to be resolved by 6D operators"); initialize < double > ("dmin", 1.0, "defines the depth of the special level"); initialize < double > ("thresh_6d", thresh, "threshold for the 6D wave function"); @@ -266,6 +267,7 @@ struct CCParameters : public QCCalculationParametersBase { CalcType calc_type() const { std::string value = get("calc_type"); if (value == "mp2") return CT_MP2; + if (value == "mp3") return CT_MP3; if (value == "cc2") return CT_CC2; if (value == "cis") return CT_LRCCS; if (value == "lrcc2") return CT_LRCC2; @@ -455,8 +457,10 @@ struct Pairs { /// getter // at instead of [] operator bc [] inserts new element if nothing is found while at throws out of range error + // back to before T& operator()(int i, int j) { - return allpairs.at(std::make_pair(i, j)); + // return allpairs.at(std::make_pair(i, j)); + return allpairs[std::make_pair(i, j)]; } /// setter From ce9ce21ba55bd2b103e1a54f842c6a70748310db Mon Sep 17 00:00:00 2001 From: fbischoff Date: Mon, 11 Dec 2023 14:48:09 +0100 Subject: [PATCH 073/109] actually return the mp2 doubles; fix segfault for frozen core in mp3 --- src/madness/chem/CC2.cc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/madness/chem/CC2.cc b/src/madness/chem/CC2.cc index 106a3897f1a..52d675f060f 100644 --- a/src/madness/chem/CC2.cc +++ b/src/madness/chem/CC2.cc @@ -483,14 +483,15 @@ double CC2::mp3_energy_contribution(const Pairs& mp2pairs) const { // compute intermediates for terms G, I, H, and J + // note: elements with frozen orbitals are left empty // \sum_j tau_ij(1,2) * phi_j(2) - std::vector tau_kk_i(nocc - parameters.freeze()); + std::vector tau_kk_i(nocc); // was (nocc - nfrozen) // \sum_j tau_ij(1,2) * phi_j(1) - std::vector tau_ij_j(nocc - parameters.freeze()); + std::vector tau_ij_j(nocc); for (int i = parameters.freeze(); i < nocc; ++i) { for (int j = parameters.freeze(); j < nocc; ++j) { - auto tmp1 = multiply(clusterfunctions(i, j), R2_orbital[j], {0, 1, 2}); + auto tmp1 = multiply(clusterfunctions(i, j), R2_orbital[j], {3, 4, 5}); for (auto& t: tmp1) tau_kk_i[i].push_back(t); auto tmp3 = multiply(clusterfunctions(i, j), R2_orbital[j], {0, 1, 2}); @@ -816,6 +817,7 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { print_header2("end computing the MP1 wave function"); } + doubles=Pairs::vector2pairs(pair_vec,triangular_map); return total_energy; } From 7568ce35e705deffaea2895d7945f09e2ffc3faf Mon Sep 17 00:00:00 2001 From: Eduard Valeyev Date: Mon, 11 Dec 2023 09:06:11 -0500 Subject: [PATCH 074/109] try to fix TBB detection issues described in https://github.com/m-a-d-n-e-s-s/madness/issues/510 --- cmake/modules/FindTBB.cmake | 51 ++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/cmake/modules/FindTBB.cmake b/cmake/modules/FindTBB.cmake index b832016b4b6..2199921f0e9 100644 --- a/cmake/modules/FindTBB.cmake +++ b/cmake/modules/FindTBB.cmake @@ -73,32 +73,6 @@ # FindTBB helper functions and macros # -# Use TBBConfig.cmake if possible. - -set(_tbb_find_quiet) -if (TBB_FIND_QUIETLY) - set(_tbb_find_quiet QUIET) -endif () -set(_tbb_find_components) -set(_tbb_find_optional_components) -foreach (_tbb_find_component IN LISTS TBB_FIND_COMPONENTS) - if (TBB_FIND_REQUIRED_${_tbb_find_component}) - list(APPEND _tbb_find_components "${_tbb_find_component}") - else () - list(APPEND _tbb_find_optional_components "${_tbb_find_component}") - endif () -endforeach () -unset(_tbb_find_component) -find_package(TBB CONFIG ${_tbb_find_quiet} - COMPONENTS ${_tbb_find_components} - OPTIONAL_COMPONENTS ${_tbb_find_optional_components}) -unset(_tbb_find_quiet) -unset(_tbb_find_components) -unset(_tbb_find_optional_components) -if (TBB_FOUND) - return () -endif () - #==================================================== # Fix the library path in case it is a linker script #==================================================== @@ -238,6 +212,31 @@ set(TBB_PREFIX_PATH ${TBBROOT} ${ENV_TBBROOT}) set(TBB_INC_SEARCH_PATH "") set(TBB_LIB_SEARCH_PATH "") +# Use TBBConfig.cmake if possible. +set(_tbb_find_quiet) +if (TBB_FIND_QUIETLY) + set(_tbb_find_quiet QUIET) +endif () +set(_tbb_find_components) +set(_tbb_find_optional_components) +foreach (_tbb_find_component IN LISTS TBB_FIND_COMPONENTS) + if (TBB_FIND_REQUIRED_${_tbb_find_component}) + list(APPEND _tbb_find_components "${_tbb_find_component}") + else () + list(APPEND _tbb_find_optional_components "${_tbb_find_component}") + endif () +endforeach () +unset(_tbb_find_component) +find_package(TBB CONFIG ${_tbb_find_quiet} + COMPONENTS ${_tbb_find_components} + OPTIONAL_COMPONENTS ${_tbb_find_optional_components} + HINTS ${TBB_PREFIX_PATH}) +unset(_tbb_find_quiet) +unset(_tbb_find_components) +unset(_tbb_find_optional_components) +if (TBB_FOUND) + return () +endif () # If user built from sources set(TBB_BUILD_PREFIX $ENV{TBB_BUILD_PREFIX}) From cb211b7d5c34acd26edabd3ee717c5e76bbcb06a Mon Sep 17 00:00:00 2001 From: fbischoff Date: Tue, 16 Jan 2024 14:05:11 +0100 Subject: [PATCH 075/109] fixing compilation --- src/madness/mra/funcimpl.h | 140 ++----------------------------------- src/madness/mra/mra.h | 24 ++++--- src/madness/mra/mraimpl.h | 2 +- src/madness/mra/test6.cc | 17 ++--- src/madness/mra/vmra.h | 3 +- 5 files changed, 26 insertions(+), 160 deletions(-) diff --git a/src/madness/mra/funcimpl.h b/src/madness/mra/funcimpl.h index 6d3befe31f8..832f22b4c69 100644 --- a/src/madness/mra/funcimpl.h +++ b/src/madness/mra/funcimpl.h @@ -3814,15 +3814,6 @@ template - /// pointwise multiplication of two tensors, returns result and estimates error - - /// provide one of the two factors upon construction, the other factor upon operator() call. - /// - /// error is estimated by oversampling: pointwise multiplication will result in a coefficient - /// tensor of order 2k, estimate the error through the norm of the k+1 contribution - /// - /// error does not account for inaccurate representation of the input tensors! - /// U need to compute that somewhere else! template struct pointwise_multiplier { coeffT val_lhs, coeff_lhs; @@ -3830,10 +3821,10 @@ template double error=0.0; double lo=0.0, hi=0.0, lo1=0.0, hi1=0.0, lo2=0.0, hi2=0.0; - pointwise_multiplier() : impl(0), gimpl(0) {} - pointwise_multiplier(const Key key, const coeffT& clhs, implT* i, const FunctionImpl* gimpl) - : impl(i), gimpl(gimpl), coeff_lhs(clhs) { - val_lhs=impl->coeffs2values(key,coeff_lhs); + pointwise_multiplier() {} + pointwise_multiplier(const Key key, const coeffT& clhs) : coeff_lhs(clhs) { + const auto& fcf=FunctionCommonFunctionality(coeff_lhs.dim(0)); + val_lhs=fcf.coeffs2values(key,coeff_lhs); error=0.0; implT::tnorm(coeff_lhs,&lo,&hi); if (coeff_lhs.is_svd_tensor()) { @@ -5422,129 +5413,6 @@ template (rangeT(coeffs.begin(),coeffs.end()),do_inner_local(&g, leaves_only)); } - - /// compute the inner product of this range with other - template - struct do_inner_local_on_demand { - const FunctionImpl* ket; - const FunctionImpl* bra; - bool leaves_only=true; - typedef TENSOR_RESULT_TYPE(T,R) resultT; - - do_inner_local_on_demand(const FunctionImpl* bra, const FunctionImpl* ket, - const bool leaves_only=true) - : bra(bra), ket(ket), leaves_only(leaves_only) {} - resultT operator()(typename dcT::const_iterator& it) const { - - constexpr std::size_t LDIM=std::max(NDIM/2,std::size_t(1)); - - const keyT& key=it->first; - const nodeT& fnode = it->second; - if (not fnode.has_coeff()) return resultT(0.0); // probably internal nodes - - // assuming all boxes (esp the low-dim ones) are local, i.e. the functions are replicated - auto find_valid_parent = [](auto& key, auto& impl, auto&& find_valid_parent) { - MADNESS_CHECK(impl->get_coeffs().owner(key)==impl->world.rank()); // make sure everything is local! - if (impl->get_coeffs().probe(key)) return key; - auto parentkey=key.parent(); - return find_valid_parent(parentkey, impl, find_valid_parent); - }; - - // returns coefficients, empty if no functor present - auto get_coeff = [&find_valid_parent](const auto& key, const auto& impl) { - bool have_impl=impl.get(); - if (have_impl) { - auto parentkey = find_valid_parent(key, impl, find_valid_parent); - MADNESS_CHECK(impl->get_coeffs().probe(parentkey)); - typename decltype(impl->coeffs)::accessor acc; - impl->get_coeffs().find(acc,parentkey); - auto parentcoeff=acc->second.coeff(); - auto coeff=impl->parent_to_child(parentcoeff, parentkey, key); - return coeff; - } else { - return GenTensor::typeT>(); - } - }; - - Key key1,key2; - key.break_apart(key1,key2); - - auto func=dynamic_cast* >(ket->functor.get()); - MADNESS_ASSERT(func); - - auto coeff_bra=fnode.coeff(); - auto coeff_ket=get_coeff(key,func->impl_ket); - auto coeff_v1=get_coeff(key1,func->impl_m1); - auto coeff_v2=get_coeff(key2,func->impl_m2); - auto coeff_p1=get_coeff(key1,func->impl_p1); - auto coeff_p2=get_coeff(key2,func->impl_p2); - - // construct |ket(1,2)> or |p(1)p(2)> or |p(1)p(2) ket(1,2)> - double error=0.0; - if (coeff_ket.has_data() and coeff_p1.has_data()) { - pointwise_multiplier pm(key,coeff_ket); - coeff_ket=pm(key,outer(coeff_p1,coeff_p2,TensorArgs(TT_FULL,-1.0)).full_tensor()); - error+=pm.error; - } else if (coeff_ket.has_data() or coeff_p1.has_data()) { - coeff_ket = (coeff_ket.has_data()) ? coeff_ket : outer(coeff_p1,coeff_p2); - } else { // not ket and no p1p2 - MADNESS_EXCEPTION("confused ket/p1p2 in do_inner_local_on_demand",1); - } - - // construct (v(1) + v(2)) |ket(1,2)> - coeffT v1v2ket; - if (coeff_v1.has_data()) { - pointwise_multiplier pm(key,coeff_ket); - v1v2ket = pm(key,coeff_v1.full_tensor(), 1); - error+=pm.error; - v1v2ket+= pm(key,coeff_v2.full_tensor(), 2); - error+=pm.error; - } else { - v1v2ket = coeff_ket; - } - - resultT result; - if (func->impl_eri) { // project bra*ket onto eri, avoid multiplication with eri - MADNESS_CHECK(func->impl_eri->get_functor()->provides_coeff()); - coeffT coeff_eri=func->impl_eri->get_functor()->coeff(key).full_tensor(); - pointwise_multiplier pm(key,v1v2ket); - tensorT braket=pm(key,coeff_bra.full_tensor_copy().conj()); - error+=pm.error; - if (error>1.e-3) print("error in key",key,error); - result=coeff_eri.full_tensor().trace(braket); - - } else { // no eri, project ket onto bra - result=coeff_bra.full_tensor_copy().trace_conj(v1v2ket.full_tensor_copy()); - } - return result; - } - - resultT operator()(resultT a, resultT b) const { - return (a+b); - } - - template void serialize(const Archive& ar) { - throw "NOT IMPLEMENTED"; - } - }; - - /// Returns the inner product of this with function g constructed on-the-fly - - /// the leaf boxes of this' MRA tree defines the inner product - template - TENSOR_RESULT_TYPE(T,R) inner_local_on_demand(const FunctionImpl& gimpl) const { - PROFILE_MEMBER_FUNC(FunctionImpl); - typedef TENSOR_RESULT_TYPE(T,R) resultT; - typedef FunctionImpl implR; - - MADNESS_CHECK(this->is_reconstructed()); - - typedef Range rangeT; - rangeT range(coeffs.begin(), coeffs.end()); - return world.taskq.reduce>(range, - do_inner_local_on_demand(this, &gimpl)); - } - /// Type of the entry in the map returned by make_key_vec_map typedef std::vector< std::pair > mapvecT; diff --git a/src/madness/mra/mra.h b/src/madness/mra/mra.h index 34766436905..c82f4d45224 100644 --- a/src/madness/mra/mra.h +++ b/src/madness/mra/mra.h @@ -1376,19 +1376,24 @@ namespace madness { TENSOR_RESULT_TYPE(T, R) inner_on_demand(const Function& g) const { MADNESS_ASSERT(g.is_on_demand() and (not this->is_on_demand())); - constexpr std::size_t LDIM=std::max(NDIM/2,std::size_t(1)); - auto func=dynamic_cast* >(g.get_impl()->get_functor().get()); - MADNESS_ASSERT(func); - func->make_redundant(true); - func->replicate_low_dim_functions(true); - this->reconstruct(); // if this == &g we don't need g to be redundant + this->reconstruct(); - if (VERIFY_TREE) verify_tree(); + // save for later, will be removed by make_Vphi + std::shared_ptr< FunctionFunctorInterface > func=g.get_impl()->get_functor(); + //leaf_op fnode_is_leaf(this->get_impl().get()); + Leaf_op_other fnode_is_leaf(this->get_impl().get()); + g.get_impl()->make_Vphi(fnode_is_leaf,true); // fence here - TENSOR_RESULT_TYPE(T, R) local = impl->inner_local_on_demand(*g.get_impl()); + if (VERIFY_TREE) verify_tree(); + TENSOR_RESULT_TYPE(T,R) local = impl->inner_local(*g.get_impl()); impl->world.gop.sum(local); impl->world.gop.fence(); + // restore original state + g.get_impl()->set_functor(func); + g.get_impl()->get_coeffs().clear(); + g.get_impl()->set_tree_state(on_demand); + return local; } @@ -2163,7 +2168,8 @@ namespace madness { if (op.modified()) { - ff.get_impl()->make_redundant(true); + ff.change_tree_state(redundant); +// ff.get_impl()->make_redundant(true); result = apply_only(op, ff, fence); ff.get_impl()->undo_redundant(false); result.get_impl()->trickle_down(true); diff --git a/src/madness/mra/mraimpl.h b/src/madness/mra/mraimpl.h index 2353d7b6e31..f366e4668bb 100644 --- a/src/madness/mra/mraimpl.h +++ b/src/madness/mra/mraimpl.h @@ -1952,7 +1952,7 @@ namespace madness { double end=wall_time(); double elapsed=end-begin; set_tree_state(nonstandard_after_apply); - if (fence) world.gop.fence(); + world.gop.fence(); return elapsed; } diff --git a/src/madness/mra/test6.cc b/src/madness/mra/test6.cc index 9a9894a8c83..07337c69633 100644 --- a/src/madness/mra/test6.cc +++ b/src/madness/mra/test6.cc @@ -801,7 +801,6 @@ int main(int argc, char**argv) { FunctionDefaults<6>::set_k(k); FunctionDefaults<6>::set_cubic_cell(-L/2,L/2); FunctionDefaults<6>::set_tensor_type(tt); - FunctionDefaults<6>::set_truncate_mode(3); print("entering testsuite for 6-dimensional functions\n"); print("k ",k); @@ -813,16 +812,10 @@ int main(int argc, char**argv) { int error=0; - real_function_3d phi=real_factory_3d(world).f(gauss_3d); - double norm=phi.norm2(); - if (world.rank()==0) printf("phi.norm2() %12.8f\n",norm); - - real_function_3d phi2=2.0*phi*phi; - norm=phi2.norm2(); - if (world.rank()==0) printf("phi2.norm2() %12.8f\n",norm); - - test(world,k,thresh); - error+=test_hartree_product(world,k,thresh); + error+=test_vector_composite(world,k,thresh); +// test(world,k,thresh); + error+=test_hartree_product(world,k,thresh); + error+=test_hartree_product(world,k,thresh); error+=test_convolution(world,k,thresh); error+=test_multiply(world,k,thresh); error+=test_add(world,k,thresh); @@ -832,8 +825,6 @@ int main(int argc, char**argv) { print(ok(error==0),error,"finished test suite\n"); world.gop.fence(); - } - finalize(); return error; diff --git a/src/madness/mra/vmra.h b/src/madness/mra/vmra.h index 93ed9f477c6..eb2ad18c42b 100644 --- a/src/madness/mra/vmra.h +++ b/src/madness/mra/vmra.h @@ -1124,7 +1124,8 @@ namespace madness { for (auto& r : result) r.set_impl(f, false); FunctionImpl* fimpl=f.get_impl().get(); - fimpl->make_redundant(false); +// fimpl->make_redundant(false); + fimpl->change_tree_state(redundant,false); make_redundant(world,g,false); world.gop.fence(); From 8b6f3501c4f35398a457122e1e6bdd2b583d8dab Mon Sep 17 00:00:00 2001 From: fbischoff Date: Thu, 18 Jan 2024 13:03:20 +0100 Subject: [PATCH 076/109] fixing compilation --- src/madness/chem/test_ccpairfunction.cc | 50 ++++++++++++++----------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/src/madness/chem/test_ccpairfunction.cc b/src/madness/chem/test_ccpairfunction.cc index 0aadc4fb2f1..94ed8f7b228 100644 --- a/src/madness/chem/test_ccpairfunction.cc +++ b/src/madness/chem/test_ccpairfunction.cc @@ -59,18 +59,18 @@ struct data { f12=real_factory_6d(world); f23=real_factory_6d(world); - try { - load(f12,"test_ccpairfunction_f12"); - } catch (...) { +// try { +// load(f12,"test_ccpairfunction_f12"); +// } catch (...) { f12 = real_factory_6d(world).f(g); - save(f12,"test_ccpairfunction_f12"); - } - try { - load(f23,"test_ccpairfunction_f23"); - } catch (...) { +// save(f12,"test_ccpairfunction_f12"); +// } +// try { +// load(f23,"test_ccpairfunction_f23"); +// } catch (...) { f23 = real_factory_6d(world).f(g23); - save(f23,"test_ccpairfunction_f23"); - } +// save(f23,"test_ccpairfunction_f23"); +// } } void clear() { @@ -1084,6 +1084,8 @@ int main(int argc, char **argv) { madness::World& world = madness::initialize(argc, argv); startup(world, argc, argv); commandlineparser parser(argc, argv); + FunctionDefaults<3>::set_k(5); + FunctionDefaults<6>::set_k(5); FunctionDefaults<6>::set_tensor_type(TT_2D); FunctionDefaults<3>::set_thresh(1.e-5); FunctionDefaults<3>::set_cubic_cell(-1.0,1.0); @@ -1105,18 +1107,22 @@ int main(int argc, char **argv) { std::shared_ptr ncf = create_nuclear_correlation_factor(world, mol, nullptr, std::make_pair("slater", 2.0)); -// isuccess+=test_constructor(world, ncf, mol, ccparam); -// isuccess+=test_operator_apply(world, ncf, mol, ccparam); -// isuccess+=test_transformations(world, ncf, mol, ccparam); -// isuccess+=test_inner(world, ncf, mol, ccparam); -// isuccess+=test_multiply(world, ncf, mol, ccparam); -// isuccess+=test_multiply_with_f12(world, ncf, mol, ccparam); -// isuccess+=test_swap_particles(world, ncf, mol, ccparam); -// isuccess+=test_scalar_multiplication(world, ncf, mol, ccparam); -// isuccess+=test_partial_inner_3d(world, ncf, mol, ccparam); -// isuccess+=test_partial_inner_6d(world, ncf, mol, ccparam); - isuccess+=test_apply(world, ncf, mol, ccparam); -// isuccess+=test_projector(world, ncf, mol, ccparam); + isuccess+=test_constructor(world, ncf, mol, ccparam); + isuccess+=test_operator_apply(world, ncf, mol, ccparam); + isuccess+=test_transformations(world, ncf, mol, ccparam); + isuccess+=test_inner(world, ncf, mol, ccparam); + isuccess+=test_multiply(world, ncf, mol, ccparam); + isuccess+=test_multiply_with_f12(world, ncf, mol, ccparam); + isuccess+=test_swap_particles(world, ncf, mol, ccparam); + isuccess+=test_scalar_multiplication(world, ncf, mol, ccparam); + isuccess+=test_partial_inner_3d(world, ncf, mol, ccparam); + isuccess+=test_partial_inner_6d(world, ncf, mol, ccparam); + FunctionDefaults<3>::set_thresh(1.e-5); + FunctionDefaults<3>::set_cubic_cell(-10.,10.); + FunctionDefaults<6>::set_thresh(1.e-3); + FunctionDefaults<6>::set_cubic_cell(-10.,10.); +// isuccess+=test_apply(world, ncf, mol, ccparam); + isuccess+=test_projector(world, ncf, mol, ccparam); // FunctionDefaults<3>::set_cubic_cell(-10,10); // isuccess+=test_helium(world,ncf,mol,ccparam); data1.clear(); From b9663fd60fe614dbb63454fe9140ca9f8a78831d Mon Sep 17 00:00:00 2001 From: fbischoff Date: Fri, 19 Jan 2024 17:55:38 +0100 Subject: [PATCH 077/109] fixing inner_local_on_demand --- src/madness/mra/funcimpl.h | 141 +++++++++++++++++++++++++++++++++++++ src/madness/mra/mra.h | 21 +++--- 2 files changed, 149 insertions(+), 13 deletions(-) diff --git a/src/madness/mra/funcimpl.h b/src/madness/mra/funcimpl.h index 832f22b4c69..3972886dff8 100644 --- a/src/madness/mra/funcimpl.h +++ b/src/madness/mra/funcimpl.h @@ -5413,6 +5413,147 @@ template (rangeT(coeffs.begin(),coeffs.end()),do_inner_local(&g, leaves_only)); } + + /// compute the inner product of this range with other + template + struct do_inner_local_on_demand { + const FunctionImpl* ket; + const FunctionImpl* bra; + bool leaves_only=true; + typedef TENSOR_RESULT_TYPE(T,R) resultT; + + do_inner_local_on_demand(const FunctionImpl* bra, const FunctionImpl* ket, + const bool leaves_only=true) + : bra(bra), ket(ket), leaves_only(leaves_only) {} + resultT operator()(typename dcT::const_iterator& it) const { + + constexpr std::size_t LDIM=std::max(NDIM/2,std::size_t(1)); + + const keyT& key=it->first; + const nodeT& fnode = it->second; + if (not fnode.has_coeff()) return resultT(0.0); // probably internal nodes + + // assuming all boxes (esp the low-dim ones) are local, i.e. the functions are replicated + auto find_valid_parent = [](auto& key, auto& impl, auto&& find_valid_parent) { + MADNESS_CHECK(impl->get_coeffs().owner(key)==impl->world.rank()); // make sure everything is local! + if (impl->get_coeffs().probe(key)) return key; + auto parentkey=key.parent(); + return find_valid_parent(parentkey, impl, find_valid_parent); + }; + + // returns coefficients, empty if no functor present + auto get_coeff = [&find_valid_parent](const auto& key, const auto& v_impl) { + if ((v_impl.size()>0) and v_impl.front().get()) { + auto impl=v_impl.front(); + +// bool have_impl=impl.get(); +// if (have_impl) { + auto parentkey = find_valid_parent(key, impl, find_valid_parent); + MADNESS_CHECK(impl->get_coeffs().probe(parentkey)); + typename decltype(impl->coeffs)::accessor acc; + impl->get_coeffs().find(acc,parentkey); + auto parentcoeff=acc->second.coeff(); + auto coeff=impl->parent_to_child(parentcoeff, parentkey, key); + return coeff; + } else { + // get type of vector elements + typedef typename std::decay_t::value_type::element_type::typeT S; +// typedef typename std::decay_t::value_type S; + return GenTensor(); +// return GenTensor::typeT>(); + } + }; + + auto make_vector = [](auto& arg) { + return std::vector>(1,arg); + }; + + + Key key1,key2; + key.break_apart(key1,key2); + + auto func=dynamic_cast* >(ket->functor.get()); + MADNESS_ASSERT(func); + + MADNESS_CHECK_THROW(func->impl_ket_vector.size()==0 or func->impl_ket_vector.size()==1, + "only one ket function supported in inner_on_demand"); + MADNESS_CHECK_THROW(func->impl_p1_vector.size()==0 or func->impl_p1_vector.size()==1, + "only one p1 function supported in inner_on_demand"); + MADNESS_CHECK_THROW(func->impl_p2_vector.size()==0 or func->impl_p2_vector.size()==1, + "only one p2 function supported in inner_on_demand"); + auto coeff_bra=fnode.coeff(); + auto coeff_ket=get_coeff(key,func->impl_ket_vector); + auto coeff_v1=get_coeff(key1,make_vector(func->impl_m1)); + auto coeff_v2=get_coeff(key2,make_vector(func->impl_m2)); + auto coeff_p1=get_coeff(key1,func->impl_p1_vector); + auto coeff_p2=get_coeff(key2,func->impl_p2_vector); + + // construct |ket(1,2)> or |p(1)p(2)> or |p(1)p(2) ket(1,2)> + double error=0.0; + if (coeff_ket.has_data() and coeff_p1.has_data()) { + pointwise_multiplier pm(key,coeff_ket); + coeff_ket=pm(key,outer(coeff_p1,coeff_p2,TensorArgs(TT_FULL,-1.0)).full_tensor()); + error+=pm.error; + } else if (coeff_ket.has_data() or coeff_p1.has_data()) { + coeff_ket = (coeff_ket.has_data()) ? coeff_ket : outer(coeff_p1,coeff_p2); + } else { // not ket and no p1p2 + MADNESS_EXCEPTION("confused ket/p1p2 in do_inner_local_on_demand",1); + } + + // construct (v(1) + v(2)) |ket(1,2)> + coeffT v1v2ket; + if (coeff_v1.has_data()) { + pointwise_multiplier pm(key,coeff_ket); + v1v2ket = pm(key,coeff_v1.full_tensor(), 1); + error+=pm.error; + v1v2ket+= pm(key,coeff_v2.full_tensor(), 2); + error+=pm.error; + } else { + v1v2ket = coeff_ket; + } + + resultT result; + if (func->impl_eri) { // project bra*ket onto eri, avoid multiplication with eri + MADNESS_CHECK(func->impl_eri->get_functor()->provides_coeff()); + coeffT coeff_eri=func->impl_eri->get_functor()->coeff(key).full_tensor(); + pointwise_multiplier pm(key,v1v2ket); + tensorT braket=pm(key,coeff_bra.full_tensor_copy().conj()); + error+=pm.error; + if (error>1.e-3) print("error in key",key,error); + result=coeff_eri.full_tensor().trace(braket); + + } else { // no eri, project ket onto bra + result=coeff_bra.full_tensor_copy().trace_conj(v1v2ket.full_tensor_copy()); + } + return result; + } + + resultT operator()(resultT a, resultT b) const { + return (a+b); + } + + template void serialize(const Archive& ar) { + throw "NOT IMPLEMENTED"; + } + }; + + /// Returns the inner product of this with function g constructed on-the-fly + + /// the leaf boxes of this' MRA tree defines the inner product + template + TENSOR_RESULT_TYPE(T,R) inner_local_on_demand(const FunctionImpl& gimpl) const { + PROFILE_MEMBER_FUNC(FunctionImpl); + typedef TENSOR_RESULT_TYPE(T,R) resultT; + typedef FunctionImpl implR; + + MADNESS_CHECK(this->is_reconstructed()); + + typedef Range rangeT; + rangeT range(coeffs.begin(), coeffs.end()); + return world.taskq.reduce>(range, + do_inner_local_on_demand(this, &gimpl)); + } + /// Type of the entry in the map returned by make_key_vec_map typedef std::vector< std::pair > mapvecT; diff --git a/src/madness/mra/mra.h b/src/madness/mra/mra.h index c82f4d45224..2aaac174f08 100644 --- a/src/madness/mra/mra.h +++ b/src/madness/mra/mra.h @@ -1376,24 +1376,19 @@ namespace madness { TENSOR_RESULT_TYPE(T, R) inner_on_demand(const Function& g) const { MADNESS_ASSERT(g.is_on_demand() and (not this->is_on_demand())); - this->reconstruct(); - - // save for later, will be removed by make_Vphi - std::shared_ptr< FunctionFunctorInterface > func=g.get_impl()->get_functor(); - //leaf_op fnode_is_leaf(this->get_impl().get()); - Leaf_op_other fnode_is_leaf(this->get_impl().get()); - g.get_impl()->make_Vphi(fnode_is_leaf,true); // fence here + constexpr std::size_t LDIM=std::max(NDIM/2,std::size_t(1)); + auto func=dynamic_cast* >(g.get_impl()->get_functor().get()); + MADNESS_ASSERT(func); + func->make_redundant(true); + func->replicate_low_dim_functions(true); + this->reconstruct(); // if this == &g we don't need g to be redundant if (VERIFY_TREE) verify_tree(); - TENSOR_RESULT_TYPE(T,R) local = impl->inner_local(*g.get_impl()); + + TENSOR_RESULT_TYPE(T, R) local = impl->inner_local_on_demand(*g.get_impl()); impl->world.gop.sum(local); impl->world.gop.fence(); - // restore original state - g.get_impl()->set_functor(func); - g.get_impl()->get_coeffs().clear(); - g.get_impl()->set_tree_state(on_demand); - return local; } From fb7e17927cdd622930aa8d79c787be6d67c0f20c Mon Sep 17 00:00:00 2001 From: fbischoff Date: Tue, 23 Jan 2024 22:58:06 +0100 Subject: [PATCH 078/109] change ccpairfunction to templated with T, NDIM for faster testing --- src/madness/chem/CC2.cc | 20 +- src/madness/chem/CC2.h | 4 +- src/madness/chem/CCPotentials.cc | 420 ++++++++++++------------ src/madness/chem/CCPotentials.h | 70 ++-- src/madness/chem/CCStructures.cc | 130 ++++---- src/madness/chem/CCStructures.h | 133 ++++---- src/madness/chem/TDHF.cc | 2 +- src/madness/chem/TDHF.h | 6 +- src/madness/chem/ccpairfunction.cc | 419 ++++++++++------------- src/madness/chem/ccpairfunction.h | 388 +++++++++++++++------- src/madness/chem/mp2.cc | 34 +- src/madness/chem/projector.h | 9 +- src/madness/chem/test_ccpairfunction.cc | 222 ++++++------- src/madness/mra/function_factory.h | 23 +- src/madness/mra/function_interface.h | 119 ++++--- src/madness/mra/mra.h | 5 +- src/madness/mra/operator.h | 15 +- 17 files changed, 1067 insertions(+), 952 deletions(-) diff --git a/src/madness/chem/CC2.cc b/src/madness/chem/CC2.cc index 837c511b565..e776f410303 100644 --- a/src/madness/chem/CC2.cc +++ b/src/madness/chem/CC2.cc @@ -367,7 +367,7 @@ double CC2::mp3_energy_contribution(const Pairs& mp2pairs) const { print_header2("computing the MP3 correlation energy"); print_header3("prepare the cluster function"); - typedef std::vector ClusterFunction; + typedef std::vector> ClusterFunction; Pairs clusterfunctions; auto R2 = nemo->ncf->square(); @@ -386,12 +386,12 @@ double CC2::mp3_energy_contribution(const Pairs& mp2pairs) const { tmp.push_back(CCPairFunction(mp2pairs(i, j).function())); CCPairFunction ij(nemo->get_calc()->amo[i], nemo->get_calc()->amo[j]); - CCConvolutionOperator::Parameters cparam; + CCConvolutionOperator::Parameters cparam; cparam.thresh_op *= 0.1; - auto f12 = CCConvolutionOperatorPtr(world, OpType::OT_F12, cparam); + auto f12 = CCConvolutionOperatorPtr(world, OpType::OT_F12, cparam); StrongOrthogonalityProjector Q12(world); Q12.set_spaces(R2_orbital, nemo_orbital, R2_orbital, nemo_orbital); - auto vfij = Q12(std::vector({f12 * ij})); + auto vfij = Q12(std::vector>({f12 * ij})); for (auto& p: vfij) tmp.push_back(p); clusterfunctions(i, j)=tmp; @@ -423,8 +423,8 @@ double CC2::mp3_energy_contribution(const Pairs& mp2pairs) const { print_header3("recompute the MP2 energy"); - CCConvolutionOperator::Parameters cparam; - auto g12=CCConvolutionOperatorPtr(world,OpType::OT_G12,cparam); + CCConvolutionOperator::Parameters cparam; + auto g12=CCConvolutionOperatorPtr(world,OpType::OT_G12,cparam); timer t2(world, "recompute MP2"); // recompute MP2 energy @@ -432,7 +432,7 @@ double CC2::mp3_energy_contribution(const Pairs& mp2pairs) const { for (int i = parameters.freeze(); i < nocc; ++i) { for (int j = i; j < nocc; ++j) { - auto bra=CCPairFunction(R2_orbital[i],R2_orbital[j]); + auto bra=CCPairFunction(R2_orbital[i],R2_orbital[j]); double direct=inner({bra},g12*clusterfunctions(i,j)); double exchange=inner({bra},g12*clusterfunctions(j,i)); double fac=(i==j) ? 0.5: 1.0; @@ -675,7 +675,7 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { // transform vector back to Pairs structure for (int i = 0; i < pair_vec.size(); i++) { pair_vec[i].constant_part = result_vec[i]; - pair_vec[i].functions[0] = CCPairFunction(result_vec[i]); + pair_vec[i].functions[0] = CCPairFunction(result_vec[i]); pair_vec[i].constant_part.truncate().reduce_rank(); pair_vec[i].function().truncate().reduce_rank(); save(pair_vec[i].constant_part, pair_vec[i].name() + "_const"); @@ -1175,9 +1175,9 @@ CC2::initialize_singles(CC_vecfunction& singles, const FuncType type, const int MADNESS_ASSERT(singles.size() == 0); bool restarted = false; - std::vector vs; + std::vector> vs; for (size_t i = parameters.freeze(); i < CCOPS.mo_ket().size(); i++) { - CCFunction single_i; + CCFunction single_i; single_i.type = type; single_i.i = i; std::string name; diff --git a/src/madness/chem/CC2.h b/src/madness/chem/CC2.h index 916515b4593..ea2a3c995f4 100644 --- a/src/madness/chem/CC2.h +++ b/src/madness/chem/CC2.h @@ -420,8 +420,8 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { parameters.lo(), parameters.thresh_bsh_6D()); Gscreen.modified() = true; - const CCFunction& moi = CCOPS.mo_ket(pair.i); - const CCFunction& moj = CCOPS.mo_ket(pair.j); + const CCFunction& moi = CCOPS.mo_ket(pair.i); + const CCFunction& moj = CCOPS.mo_ket(pair.j); pair.constant_part = CCOPS.make_constant_part_mp2(moi, moj, &Gscreen); save(pair.constant_part, pair.name() + "_const"); diff --git a/src/madness/chem/CCPotentials.cc b/src/madness/chem/CCPotentials.cc index e85aa5dc6f4..cd9027401ae 100644 --- a/src/madness/chem/CCPotentials.cc +++ b/src/madness/chem/CCPotentials.cc @@ -28,8 +28,8 @@ CCPotentials::CCPotentials(World& world_, std::shared_ptr nemo, const CCP corrfac(world, param.gamma(), 1.e-7, nemo->get_calc()->molecule), get_potentials(world, param), output(world) { - g12=std::shared_ptr(new CCConvolutionOperator(world,OpType::OT_G12,param)); - f12=std::shared_ptr(new CCConvolutionOperator(world,OpType::OT_F12,param)); + g12=std::shared_ptr>(new CCConvolutionOperator(world,OpType::OT_G12,param)); + f12=std::shared_ptr>(new CCConvolutionOperator(world,OpType::OT_F12,param)); output.debug = parameters.debug(); // reset_nemo(nemo); // g12.update_elements(mo_bra_, mo_ket_); @@ -85,16 +85,16 @@ CCPotentials::make_pair_gs(const real_function_6d& u, const CC_vecfunction& tau, else { pt = make_full_t_intermediate(tau); } - std::vector functions; - CCPairFunction u_part(u); + std::vector> functions; + CCPairFunction u_part(u); functions.push_back(u_part); if (parameters.decompose_Q()) { - CCPairFunction f_part(f12, t(i), t(j)); + CCPairFunction f_part(f12, t(i), t(j)); functions.push_back(f_part); - CCPairFunction Ot1 = apply_Ot(f_part, pt, 1); - CCPairFunction Ot2 = apply_Ot(f_part, pt, 2); - CCPairFunction PQ = apply_Qt(Ot1, pt, 2, 0.5); - CCPairFunction QP = apply_Qt(Ot2, pt, 1, 0.5); + CCPairFunction Ot1 = apply_Ot(f_part, pt, 1); + CCPairFunction Ot2 = apply_Ot(f_part, pt, 2); + CCPairFunction PQ = apply_Qt(Ot1, pt, 2, 0.5); + CCPairFunction QP = apply_Qt(Ot2, pt, 1, 0.5); // assign signs PQ.invert_sign(); QP.invert_sign(); @@ -105,7 +105,7 @@ CCPotentials::make_pair_gs(const real_function_6d& u, const CC_vecfunction& tau, real_function_6d ftt = make_f_xy(t(i), t(j)); real_function_6d Qftt = apply_Q12t(ftt, pt); Qftt.truncate(); - CCPairFunction residual(Qftt); + CCPairFunction residual(Qftt); functions.push_back(residual); } CalcType ctype = CT_CC2; @@ -230,41 +230,41 @@ CCPotentials::make_pair_ex(const real_function_6d& u, const CC_vecfunction& tau, pt = make_full_t_intermediate(tau).copy(); } MADNESS_ASSERT(pt.size() == mo_ket_.size()); - std::vector functions; - CCPairFunction u_part(u); + std::vector> functions; + CCPairFunction u_part(u); functions.push_back(u_part); if (parameters.decompose_Q()) { - CCPairFunction f_xt(f12, x(i), t(j)); + CCPairFunction f_xt(f12, x(i), t(j)); functions.push_back(f_xt); - CCPairFunction f_tx(f12, t(i), x(j)); + CCPairFunction f_tx(f12, t(i), x(j)); functions.push_back(f_tx); { - CCPairFunction Ot1_xt = apply_Ot(f_xt, pt, 1); // O1t(f|xt>) - CCPairFunction OtQt_xt = apply_Qt(Ot1_xt, pt, 2, 0.5); // O1t(1-0.5*O2t)f|xt> + CCPairFunction Ot1_xt = apply_Ot(f_xt, pt, 1); // O1t(f|xt>) + CCPairFunction OtQt_xt = apply_Qt(Ot1_xt, pt, 2, 0.5); // O1t(1-0.5*O2t)f|xt> functions.push_back(OtQt_xt.invert_sign()); // - " } { - CCPairFunction Ot2_xt = apply_Ot(f_xt, pt, 2); // O2t(f|xt>) - CCPairFunction QtOt_xt = apply_Qt(Ot2_xt, pt, 1, 0.5); // (1-0.5*O1t)O2t(f|xt>) + CCPairFunction Ot2_xt = apply_Ot(f_xt, pt, 2); // O2t(f|xt>) + CCPairFunction QtOt_xt = apply_Qt(Ot2_xt, pt, 1, 0.5); // (1-0.5*O1t)O2t(f|xt>) functions.push_back(QtOt_xt.invert_sign()); // - " } { - CCPairFunction Ot1_tx = apply_Ot(f_tx, pt, 1); // O1t(f|tx>) - CCPairFunction OtQt_tx = apply_Qt(Ot1_tx, pt, 2, 0.5); // O1t(1-0.5*O2t)f|tx> + CCPairFunction Ot1_tx = apply_Ot(f_tx, pt, 1); // O1t(f|tx>) + CCPairFunction OtQt_tx = apply_Qt(Ot1_tx, pt, 2, 0.5); // O1t(1-0.5*O2t)f|tx> functions.push_back(OtQt_tx.invert_sign()); // - " } { - CCPairFunction Ot2_tx = apply_Ot(f_tx, pt, 2); // O2t(f|tx>) - CCPairFunction QtOt_tx = apply_Qt(Ot2_tx, pt, 1, 0.5); // (1-0.5*O1t)O2t(f|tx>) + CCPairFunction Ot2_tx = apply_Ot(f_tx, pt, 2); // O2t(f|tx>) + CCPairFunction QtOt_tx = apply_Qt(Ot2_tx, pt, 1, 0.5); // (1-0.5*O1t)O2t(f|tx>) functions.push_back(QtOt_tx.invert_sign()); // - " } if (parameters.QtAnsatz()) { - CCPairFunction ftt(f12, t(i), t(j)); // f|tt> - CCPairFunction O1x_tt = apply_Ot(ftt, x, 1); // O1x(f|tt>) - CCPairFunction OxQt_tt = apply_Qt(O1x_tt, pt, 2); // O1xQt(f|tt>) + CCPairFunction ftt(f12, t(i), t(j)); // f|tt> + CCPairFunction O1x_tt = apply_Ot(ftt, x, 1); // O1x(f|tt>) + CCPairFunction OxQt_tt = apply_Qt(O1x_tt, pt, 2); // O1xQt(f|tt>) functions.push_back(OxQt_tt.invert_sign()); // - " - CCPairFunction O2x_tt = apply_Ot(ftt, x, 2); // O2x(f|tt>) - CCPairFunction QtOx_tt = apply_Qt(O2x_tt, pt, 1); // Q1tO2x(f|tt>) + CCPairFunction O2x_tt = apply_Ot(ftt, x, 2); // O2x(f|tt>) + CCPairFunction QtOx_tt = apply_Qt(O2x_tt, pt, 1); // Q1tO2x(f|tt>) functions.push_back(QtOx_tt.invert_sign()); // - " } } else { @@ -283,7 +283,7 @@ CCPotentials::make_pair_ex(const real_function_6d& u, const CC_vecfunction& tau, real_function_6d OxOt = Ot(O1x, 2); real_function_6d projector_part = (O1x - OxOt + O2x - OtOx); real_function_6d residual = function_part - projector_part; - CCPairFunction res(residual); + CCPairFunction res(residual); functions.push_back(res); } else { real_function_6d ftx = make_f_xy(t(i), x(j)); @@ -291,7 +291,7 @@ CCPotentials::make_pair_ex(const real_function_6d& u, const CC_vecfunction& tau, real_function_6d tmp = ftx + fxt; real_function_6d residual = apply_Q12t(tmp, mo_ket_); residual.truncate(); - CCPairFunction res(residual); + CCPairFunction res(residual); functions.push_back(res); } } @@ -317,8 +317,8 @@ CCPotentials::compute_pair_correlation_energy(const CCPair& u, const CC_vecfunct output("Compute pair-correlation energy of pair " + u.name()); double result = 0.0; - const CCFunction& mobi = mo_bra_(u.i); - const CCFunction& mobj = mo_bra_(u.j); + const CCFunction& mobi = mo_bra_(u.i); + const CCFunction& mobj = mo_bra_(u.j); const bool symmetric = (u.i == u.j); @@ -407,8 +407,8 @@ CCPotentials::compute_cis_expectation_value(const CC_vecfunction& x, const vecto double CCPotentials::compute_excited_pair_energy(const CCPair& d, const CC_vecfunction& x) const { const CC_vecfunction xbra(make_bra(x), RESPONSE, parameters.freeze()); - const CCFunction& xbi = xbra(d.i); - const CCFunction& mobj = mo_bra_(d.j); + const CCFunction& xbi = xbra(d.i); + const CCFunction& mobj = mo_bra_(d.j); double result = 0.0; double s2b = 2.0 * make_xy_op_u(xbi, mobj, *g12, d.functions) - make_xy_op_u(mobj, xbi, *g12, d.functions); double s2c = 0.0; @@ -679,7 +679,7 @@ CCPotentials::fock_residue_6d_macrotask(World& world, const CCPair& u, const CCP } madness::real_function_6d -CCPotentials::make_constant_part_mp2(const CCFunction& ti, const CCFunction& tj, +CCPotentials::make_constant_part_mp2(const CCFunction& ti, const CCFunction& tj, const real_convolution_6d *Gscreen) const { output.section("Calculating Constant Part of MP2 pair " + ti.name() + tj.name()); CCTimer time(world, "Calculating Constant Part of MP2"); @@ -824,8 +824,8 @@ CCPotentials::make_constant_part_cc2_gs(const CCPair& u, const CC_vecfunction& t const size_t j = u.j; const bool symmetric = (i == j); // make ti intermediates - const CCFunction ti = make_t_intermediate(tau(i)); - const CCFunction tj = make_t_intermediate(tau(j)); + const CCFunction ti = make_t_intermediate(tau(i)); + const CCFunction tj = make_t_intermediate(tau(j)); real_function_6d GV; real_convolution_6d G = BSHOperator<6>(world, sqrt(-2.0 * get_epsilon(ti.i, tj.i)), parameters.lo(), parameters.thresh_bsh_6D()); @@ -849,12 +849,12 @@ CCPotentials::make_constant_part_cc2_gs(const CCPair& u, const CC_vecfunction& t CCTimer time_Vcc(world, "G(Coulomb Coupling Potential)"); real_function_6d GVcc = real_factory_6d(world); // make the g12|titj> function as op_decomposed function (not constructed in 6D) - CCPairFunction gtt(g12, ti, tj); + CCPairFunction gtt(g12, ti, tj); // make Otau(1)(g12|titj>) - CCPairFunction Otau1_gtt = apply_Ot(gtt, tau, 1); + CCPairFunction Otau1_gtt = apply_Ot(gtt, tau, 1); // make Otau1Q2 part and the Otau1Otau2. Otau1Otau2 part IS NOT used in the symmetry exploit - CCPairFunction OtauQ = apply_Qt(Otau1_gtt, mo_ket_, 2); - CCPairFunction OtauOtau = apply_Ot(Otau1_gtt, tau, 2); + CCPairFunction OtauQ = apply_Qt(Otau1_gtt, mo_ket_, 2); + CCPairFunction OtauOtau = apply_Ot(Otau1_gtt, tau, 2); // apply the Greens Operator const real_function_6d GVcc_1 = -2.0 * apply_G(OtauQ, G); const real_function_6d GVcc_3 = -2.0 * apply_G(OtauOtau, G); @@ -862,8 +862,8 @@ CCPotentials::make_constant_part_cc2_gs(const CCPair& u, const CC_vecfunction& t real_function_6d GVcc_2; if (symmetric) GVcc_2 = swap_particles(GVcc_1); else { - CCPairFunction Otau2_gtt = apply_Ot(gtt, tau, 2); - CCPairFunction QOtau = apply_Qt(Otau2_gtt, mo_ket_, 1); + CCPairFunction Otau2_gtt = apply_Ot(gtt, tau, 2); + CCPairFunction QOtau = apply_Qt(Otau2_gtt, mo_ket_, 1); GVcc_2 = -2.0 * apply_G(QOtau, G); } if (parameters.debug()) print_size(GVcc, "GVcc", parameters.debug()); @@ -901,8 +901,8 @@ CCPotentials::make_constant_part_cc2_Qt_gs(const CCPair& u, const CC_vecfunction const size_t j = u.j; const bool symmetric = (i == j); // make ti intermediates - const CCFunction ti = make_t_intermediate(tau(i)); - const CCFunction tj = make_t_intermediate(tau(j)); + const CCFunction ti = make_t_intermediate(tau(i)); + const CCFunction tj = make_t_intermediate(tau(j)); const CC_vecfunction t = make_full_t_intermediate(tau); MADNESS_ASSERT(t.size() == mo_ket_.size()); MADNESS_ASSERT(t.type == MIXED); @@ -916,15 +916,15 @@ CCPotentials::make_constant_part_cc2_Qt_gs(const CCPair& u, const CC_vecfunction CCTimer time_comm(world, "commutator"); const vector_real_function_3d Vtmp = get_potentials(tau, POT_singles_); const CC_vecfunction V(Vtmp, UNDEFINED, parameters.freeze()); - const CCPairFunction ftt(f12, ti, tj); - const CCPairFunction O1ftt = apply_Ot(ftt, V, 1); - const CCPairFunction O1Q2ftt = apply_Qt(O1ftt, t, 2); + const CCPairFunction ftt(f12, ti, tj); + const CCPairFunction O1ftt = apply_Ot(ftt, V, 1); + const CCPairFunction O1Q2ftt = apply_Qt(O1ftt, t, 2); const real_function_6d part1 = -2.0 * apply_G(O1Q2ftt, G); real_function_6d part2; if (symmetric) part2 = swap_particles(part1); else { - const CCPairFunction O2ftt = apply_Ot(ftt, V, 2); - const CCPairFunction Q1O2ftt = apply_Qt(O2ftt, t, 1); + const CCPairFunction O2ftt = apply_Ot(ftt, V, 2); + const CCPairFunction Q1O2ftt = apply_Qt(O2ftt, t, 1); part2 = -2.0 * apply_G(Q1O2ftt, G); } const real_function_6d commutator = part1 + part2; @@ -959,10 +959,10 @@ CCPotentials::make_constant_part_cispd(const CCPair& u, const CC_vecfunction& x, MADNESS_ASSERT(u.ctype == CT_CISPD || u.ctype == CT_ADC2); const size_t i = u.i; const size_t j = u.j; - const CCFunction& xi = x(i); - const CCFunction& xj = x(j); - const CCFunction& moi = mo_ket_(i); - const CCFunction& moj = mo_ket_(j); + const CCFunction& xi = x(i); + const CCFunction& xj = x(j); + const CCFunction& moi = mo_ket_(i); + const CCFunction& moj = mo_ket_(j); const bool symmetric = (i == j); MADNESS_ASSERT(x.type == RESPONSE); MADNESS_ASSERT(u.bsh_eps == get_epsilon(i, j) + x.omega); @@ -995,14 +995,14 @@ CCPotentials::make_constant_part_cispd(const CCPair& u, const CC_vecfunction& x, real_function_6d GVcc; { time_cr.start(); - const CCPairFunction gij(g12, moi, moj); - const CCPairFunction O1x_gij = apply_Ot(gij, x, 1); - const CCPairFunction OQ_part = apply_Qt(O1x_gij, mo_ket_, 2); + const CCPairFunction gij(g12, moi, moj); + const CCPairFunction O1x_gij = apply_Ot(gij, x, 1); + const CCPairFunction OQ_part = apply_Qt(O1x_gij, mo_ket_, 2); const real_function_6d GOQ = -2.0 * apply_G(OQ_part, G); if (symmetric) GVcc = GOQ + swap_particles(GOQ); else { - const CCPairFunction O2x_gij = apply_Ot(gij, x, 2); - const CCPairFunction QO_part = apply_Qt(O2x_gij, mo_ket_, 1); + const CCPairFunction O2x_gij = apply_Ot(gij, x, 2); + const CCPairFunction QO_part = apply_Qt(O2x_gij, mo_ket_, 1); const real_function_6d GQO = -2.0 * apply_G(QO_part, G); GVcc = GOQ + GQO; } @@ -1028,10 +1028,10 @@ CCPotentials::make_constant_part_cispd_Qt(const CCPair& u, const CC_vecfunction& MADNESS_ASSERT(u.ctype == CT_CISPD || u.ctype == CT_ADC2); const size_t i = u.i; const size_t j = u.j; - const CCFunction& xi = x(i); - const CCFunction& xj = x(j); - const CCFunction& moi = mo_ket_(i); - const CCFunction& moj = mo_ket_(j); + const CCFunction& xi = x(i); + const CCFunction& xj = x(j); + const CCFunction& moi = mo_ket_(i); + const CCFunction& moj = mo_ket_(j); const bool symmetric = (i == j); MADNESS_ASSERT(x.type == RESPONSE); MADNESS_ASSERT(u.bsh_eps == get_epsilon(i, j) + x.omega); @@ -1062,14 +1062,14 @@ CCPotentials::make_constant_part_cispd_Qt(const CCPair& u, const CC_vecfunction& Vtmp.truncate().reduce_rank(); if (parameters.debug()) Vtmp.print_size("Vreg-omega*f12|ij>"); - const CCPairFunction V(Vtmp); - const CCPairFunction O1x_V = apply_Ot(V, x, 1); - const CCPairFunction O1xQ2_V = apply_Qt(O1x_V, mo_ket_, 2); + const CCPairFunction V(Vtmp); + const CCPairFunction O1x_V = apply_Ot(V, x, 1); + const CCPairFunction O1xQ2_V = apply_Qt(O1x_V, mo_ket_, 2); const real_function_6d GOQ = -2.0 * apply_G(O1xQ2_V, G); if (symmetric) PR = GOQ + swap_particles(GOQ); else { - const CCPairFunction O2x_V = apply_Ot(V, x, 2); - const CCPairFunction Q1O2x_V = apply_Qt(O2x_V, mo_ket_, 1); + const CCPairFunction O2x_V = apply_Ot(V, x, 2); + const CCPairFunction Q1O2x_V = apply_Qt(O2x_V, mo_ket_, 1); const real_function_6d GQO = -2.0 * apply_G(Q1O2x_V, G); PR = GOQ + GQO; } @@ -1118,19 +1118,19 @@ CCPotentials::make_constant_part_cispd_Qt(const CCPair& u, const CC_vecfunction& const vector_real_function_3d Vxtmp = sub(world, get_potentials(x, POT_singles_), x.omega * x.get_vecfunction()); const CC_vecfunction Vx(Vxtmp, UNDEFINED, parameters.freeze()); - CCPairFunction ftt(f12, moi, moj); + CCPairFunction ftt(f12, moi, moj); real_function_6d tmp1; real_function_6d tmp2; { - CCPairFunction OVx = apply_Ot(ftt, Vx, 1); - CCPairFunction OVxQt = apply_Qt(OVx, mo_ket_, 2); + CCPairFunction OVx = apply_Ot(ftt, Vx, 1); + CCPairFunction OVxQt = apply_Qt(OVx, mo_ket_, 2); real_function_6d part2 = -2.0 * apply_G(OVxQt, G); tmp1 = part2; } if (symmetric) tmp2 = swap_particles(tmp1); else { - CCPairFunction OVx = apply_Ot(ftt, Vx, 2); - CCPairFunction OVxQt = apply_Qt(OVx, mo_ket_, 1); + CCPairFunction OVx = apply_Ot(ftt, Vx, 2); + CCPairFunction OVxQt = apply_Qt(OVx, mo_ket_, 1); real_function_6d part2 = -2.0 * apply_G(OVxQt, G); tmp2 = part2; } @@ -1166,10 +1166,10 @@ CCPotentials::make_constant_part_cc2_ex(const CCPair& u, const CC_vecfunction& t const size_t i = u.i; const size_t j = u.j; const CC_vecfunction t = make_full_t_intermediate(tau); - const CCFunction& ti = t(i); - const CCFunction& tj = t(j); - const CCFunction& xi = x(i); - const CCFunction& xj = x(j); + const CCFunction& ti = t(i); + const CCFunction& tj = t(j); + const CCFunction& xi = x(i); + const CCFunction& xj = x(j); // use pair symmetry for diagonal pairs const bool symmetric = (i == j); // the Greens operator @@ -1208,43 +1208,43 @@ CCPotentials::make_constant_part_cc2_ex(const CCPair& u, const CC_vecfunction& t real_function_6d tmp2; // make the xt parts of the functional and the QtOx part of the projector response { - CCPairFunction gxt(g12, xi, tj); + CCPairFunction gxt(g12, xi, tj); // make QOtau*g*|xt> - CCPairFunction O2tmp = apply_Ot(gxt, tau, 2); - CCPairFunction QO = apply_Qt(O2tmp, mo_ket_, 1); + CCPairFunction O2tmp = apply_Ot(gxt, tau, 2); + CCPairFunction QO = apply_Qt(O2tmp, mo_ket_, 1); const real_function_6d part1 = -2.0 * apply_G(QO, G); // make OtauQ*g*|xt> - CCPairFunction O1tmp = apply_Ot(gxt, tau, 1); - CCPairFunction OQ = apply_Qt(O1tmp, mo_ket_, 2); + CCPairFunction O1tmp = apply_Ot(gxt, tau, 1); + CCPairFunction OQ = apply_Qt(O1tmp, mo_ket_, 2); const real_function_6d part2 = -2.0 * apply_G(OQ, G); // OtauOtau*g*|xt> - CCPairFunction OO = apply_Ot(O1tmp, tau, 2); + CCPairFunction OO = apply_Ot(O1tmp, tau, 2); const real_function_6d part3 = -2.0 * apply_G(OO, G); // QtOx*g|titj> - CCPairFunction gtt(g12, ti, tj); - CCPairFunction O2x = apply_Ot(gtt, x, 2); - CCPairFunction QtOx = apply_Qt(O2x, t, 1); + CCPairFunction gtt(g12, ti, tj); + CCPairFunction O2x = apply_Ot(gtt, x, 2); + CCPairFunction QtOx = apply_Qt(O2x, t, 1); const real_function_6d part4 = -2.0 * apply_G(QtOx, G); tmp1 = part1 + part2 - part3 + part4; // overall minus sign applied in the end } if (symmetric) tmp2 = swap_particles(tmp1); else { - CCPairFunction gtx(g12, ti, xj); + CCPairFunction gtx(g12, ti, xj); // make QOtau*g*|tx> - CCPairFunction O2tmp = apply_Ot(gtx, tau, 2); - CCPairFunction QO = apply_Qt(O2tmp, mo_ket_, 1); + CCPairFunction O2tmp = apply_Ot(gtx, tau, 2); + CCPairFunction QO = apply_Qt(O2tmp, mo_ket_, 1); const real_function_6d part1 = -2.0 * apply_G(QO, G); // make OtauQ*g*|tx> - CCPairFunction O1tmp = apply_Ot(gtx, tau, 1); - CCPairFunction OQ = apply_Qt(O1tmp, mo_ket_, 2); + CCPairFunction O1tmp = apply_Ot(gtx, tau, 1); + CCPairFunction OQ = apply_Qt(O1tmp, mo_ket_, 2); const real_function_6d part2 = -2.0 * apply_G(OQ, G); // OtauOtau*g*|tx> - CCPairFunction OO = apply_Ot(O1tmp, tau, 2); + CCPairFunction OO = apply_Ot(O1tmp, tau, 2); const real_function_6d part3 = -2.0 * apply_G(OO, G); // OxQt*g|titj> - CCPairFunction gtt(g12, ti, tj); - CCPairFunction O1x = apply_Ot(gtt, x, 1); - CCPairFunction OxQt = apply_Qt(O1x, t, 2); + CCPairFunction gtt(g12, ti, tj); + CCPairFunction O1x = apply_Ot(gtt, x, 1); + CCPairFunction OxQt = apply_Qt(O1x, t, 2); const real_function_6d part4 = -2.0 * apply_G(OxQt, G); tmp1 = part1 + part2 - part3 + part4; // overall minus sign applied in the end } @@ -1283,10 +1283,10 @@ CCPotentials::make_constant_part_cc2_Qt_ex(const CCPair& u, const CC_vecfunction const CC_vecfunction t = make_full_t_intermediate(tau); MADNESS_ASSERT(t.type == MIXED); MADNESS_ASSERT(t.size() == mo_ket_.size()); - const CCFunction& ti = t(i); - const CCFunction& tj = t(j); - const CCFunction& xi = x(i); - const CCFunction& xj = x(j); + const CCFunction& ti = t(i); + const CCFunction& tj = t(j); + const CCFunction& xi = x(i); + const CCFunction& xj = x(j); // use pair symmetry for diagonal pairs const bool symmetric = (i == j); // the Greens operator @@ -1323,18 +1323,18 @@ CCPotentials::make_constant_part_cc2_Qt_ex(const CCPair& u, const CC_vecfunction real_function_6d Vtt_tmp = apply_Vreg(ti, tj, Gscreen); real_function_6d titj = make_f_xy(ti, tj); Vtt_tmp = Vtt_tmp - x.omega * titj; - CCPairFunction Vtt(Vtt_tmp); + CCPairFunction Vtt(Vtt_tmp); real_function_6d tmp1; real_function_6d tmp2; { - CCPairFunction Ox = apply_Ot(Vtt, x, 1); - CCPairFunction OxQt = apply_Qt(Ox, t, 2); + CCPairFunction Ox = apply_Ot(Vtt, x, 1); + CCPairFunction OxQt = apply_Qt(Ox, t, 2); tmp1 = -2.0 * apply_G(OxQt, G); } if (symmetric) tmp2 = swap_particles(tmp1); else { - CCPairFunction Ox = apply_Ot(Vtt, x, 2); - CCPairFunction QtOx = apply_Qt(Ox, t, 1); + CCPairFunction Ox = apply_Ot(Vtt, x, 2); + CCPairFunction QtOx = apply_Qt(Ox, t, 1); tmp2 = -2.0 * apply_G(QtOx, G); } projector_response = tmp1 + tmp2; @@ -1348,11 +1348,11 @@ CCPotentials::make_constant_part_cc2_Qt_ex(const CCPair& u, const CC_vecfunction const vector_real_function_3d Vtmp = get_potentials(tau, POT_singles_); const CC_vecfunction V(Vtmp, UNDEFINED, parameters.freeze()); { - const CCPairFunction fxt(f12, xi, tj); - const CCPairFunction O1V = apply_Ot(fxt, V, 1); - const CCPairFunction OQ = apply_Qt(O1V, t, 2); - const CCPairFunction O2V = apply_Ot(fxt, V, 2); - const CCPairFunction QO = apply_Qt(O2V, t, 1); + const CCPairFunction fxt(f12, xi, tj); + const CCPairFunction O1V = apply_Ot(fxt, V, 1); + const CCPairFunction OQ = apply_Qt(O1V, t, 2); + const CCPairFunction O2V = apply_Ot(fxt, V, 2); + const CCPairFunction QO = apply_Qt(O2V, t, 1); const real_function_6d tmp1 = -2.0 * apply_G(OQ, G); const real_function_6d tmp2 = -2.0 * apply_G(QO, G); part1 = tmp1 + tmp2; @@ -1360,11 +1360,11 @@ CCPotentials::make_constant_part_cc2_Qt_ex(const CCPair& u, const CC_vecfunction real_function_6d part2; // the tx parts if (symmetric) part2 = swap_particles(part1); else { - const CCPairFunction ftx(f12, ti, xj); - const CCPairFunction O1V = apply_Ot(ftx, V, 1); - const CCPairFunction OQ = apply_Qt(O1V, t, 2); - const CCPairFunction O2V = apply_Ot(ftx, V, 2); - const CCPairFunction QO = apply_Qt(O2V, t, 1); + const CCPairFunction ftx(f12, ti, xj); + const CCPairFunction O1V = apply_Ot(ftx, V, 1); + const CCPairFunction OQ = apply_Qt(O1V, t, 2); + const CCPairFunction O2V = apply_Ot(ftx, V, 2); + const CCPairFunction QO = apply_Qt(O2V, t, 1); const real_function_6d tmp1 = -2.0 * apply_G(OQ, G); const real_function_6d tmp2 = -2.0 * apply_G(QO, G); part2 = tmp1 + tmp2; @@ -1388,25 +1388,25 @@ CCPotentials::make_constant_part_cc2_Qt_ex(const CCPair& u, const CC_vecfunction const vector_real_function_3d Vttmp = get_potentials(tau, POT_singles_); const CC_vecfunction Vx(Vxtmp, UNDEFINED, parameters.freeze()); const CC_vecfunction Vt(Vttmp, UNDEFINED, parameters.freeze()); - CCPairFunction ftt(f12, ti, tj); + CCPairFunction ftt(f12, ti, tj); real_function_6d tmp1; real_function_6d tmp2; { - CCPairFunction Ox = apply_Ot(ftt, x, 1); - CCPairFunction OxOVt = apply_Ot(Ox, Vt, 2); + CCPairFunction Ox = apply_Ot(ftt, x, 1); + CCPairFunction OxOVt = apply_Ot(Ox, Vt, 2); real_function_6d part1 = -2.0 * apply_G(OxOVt, G); - CCPairFunction OVx = apply_Ot(ftt, Vx, 1); - CCPairFunction OVxQt = apply_Qt(OVx, t, 2); + CCPairFunction OVx = apply_Ot(ftt, Vx, 1); + CCPairFunction OVxQt = apply_Qt(OVx, t, 2); real_function_6d part2 = -2.0 * apply_G(OVxQt, G); tmp1 = part2 - part1; } if (symmetric) tmp2 = swap_particles(tmp1); else { - CCPairFunction Ox = apply_Ot(ftt, x, 2); - CCPairFunction OxOVt = apply_Ot(Ox, Vt, 1); + CCPairFunction Ox = apply_Ot(ftt, x, 2); + CCPairFunction OxOVt = apply_Ot(Ox, Vt, 1); real_function_6d part1 = -2.0 * apply_G(OxOVt, G); - CCPairFunction OVx = apply_Ot(ftt, Vx, 2); - CCPairFunction OVxQt = apply_Qt(OVx, t, 1); + CCPairFunction OVx = apply_Ot(ftt, Vx, 2); + CCPairFunction OVxQt = apply_Qt(OVx, t, 1); real_function_6d part2 = -2.0 * apply_G(OVxQt, G); tmp2 = part2 - part1; } @@ -1426,7 +1426,7 @@ CCPotentials::make_constant_part_cc2_Qt_ex(const CCPair& u, const CC_vecfunction } madness::real_function_6d -CCPotentials::apply_Vreg(const CCFunction& ti, const CCFunction& tj, const real_convolution_6d *Gscreen) const { +CCPotentials::apply_Vreg(const CCFunction& ti, const CCFunction& tj, const real_convolution_6d *Gscreen) const { output("Applying Vreg to |" + ti.name() + tj.name() + ">"); CCTimer timer(world, "Vreg|" + ti.name() + tj.name() + ">"); CCTimer time_f(world, "F-Part"); @@ -1514,7 +1514,7 @@ CCPotentials::apply_Vreg_macrotask(World& world, const std::vector& ti, const CCFunction& tj, const real_convolution_6d *Gscreen) const { //CC_Timer time(world,"(F-eij)|"+ti.name()+tj.name()+">"); // get singles potential const bool symmetric = (ti.type == tj.type && ti.i == tj.i); @@ -1533,7 +1533,7 @@ CCPotentials::apply_reduced_F(const CCFunction& ti, const CCFunction& tj, const madness::real_function_6d -CCPotentials::apply_transformed_Ue(const CCFunction& x, const CCFunction& y, const real_convolution_6d *Gscreen) const { +CCPotentials::apply_transformed_Ue(const CCFunction& x, const CCFunction& y, const real_convolution_6d *Gscreen) const { if (parameters.debug()) output("\nComputing Ue|" + x.name() + y.name() + ">\n"); const bool symmetric = (x.type == y.type && x.i == y.i); @@ -1791,7 +1791,7 @@ CCPotentials::apply_exchange_commutator_macrotask(World& world, const std::vecto madness::real_function_6d -CCPotentials::apply_exchange_commutator(const CCFunction& x, const CCFunction& y, +CCPotentials::apply_exchange_commutator(const CCFunction& x, const CCFunction& y, const real_convolution_6d *Gscreen) const { real_function_6d result = apply_exchange_commutator1(x, y, Gscreen); { @@ -1819,7 +1819,7 @@ CCPotentials::apply_exchange_commutator(const CCFunction& x, const CCFunction& y } madness::real_function_6d -CCPotentials::apply_exchange_commutator1(const CCFunction& x, const CCFunction& y, +CCPotentials::apply_exchange_commutator1(const CCFunction& x, const CCFunction& y, const real_convolution_6d *Gscreen) const { if (parameters.debug()) output("\nComputing [K,f]|" + x.name() + y.name() + ">\n"); @@ -1845,7 +1845,7 @@ CCPotentials::apply_exchange_commutator1(const CCFunction& x, const CCFunction& } double -CCPotentials::make_xy_gf_ab(const CCFunction& x, const CCFunction& y, const CCFunction& a, const CCFunction& b) const { +CCPotentials::make_xy_gf_ab(const CCFunction& x, const CCFunction& y, const CCFunction& a, const CCFunction& b) const { const real_function_3d xa = (x.function * a.function).truncate(); const real_function_3d x_gf_a = apply_gf(xa); const double result = y.function.inner(x_gf_a * b.function); @@ -1862,7 +1862,7 @@ CCPotentials::apply_gf(const real_function_3d& f) const { } double -CCPotentials::make_xy_u(const CCFunction& x, const CCFunction& y, const std::vector& u) const { +CCPotentials::make_xy_u(const CCFunction& x, const CCFunction& y, const std::vector>& u) const { double result = 0.0; for (size_t mm = 0; mm < u.size(); mm++) { result += u[mm].make_xy_u(x, y); @@ -1871,8 +1871,8 @@ CCPotentials::make_xy_u(const CCFunction& x, const CCFunction& y, const std::vec } double -CCPotentials::make_xy_op_u(const CCFunction& x, const CCFunction& y, const CCConvolutionOperator& op, - const CCPairFunction& u) const { +CCPotentials::make_xy_op_u(const CCFunction& x, const CCFunction& y, const CCConvolutionOperator& op, + const CCPairFunction& u) const { double result = 0.0; if (u.component->is_pure()) { real_function_6d xy_op = CompositeFactory(world).particle1(copy(x.function)).particle2( @@ -1897,8 +1897,8 @@ CCPotentials::make_xy_op_u(const CCFunction& x, const CCFunction& y, const CCCon } double -CCPotentials::make_xy_op_u(const CCFunction& x, const CCFunction& y, const CCConvolutionOperator& op, - const std::vector& u) const { +CCPotentials::make_xy_op_u(const CCFunction& x, const CCFunction& y, const CCConvolutionOperator& op, + const std::vector>& u) const { double result = 0.0; for (size_t mm = 0; mm < u.size(); mm++) { const double tmp = make_xy_op_u(x, y, op, u[mm]); @@ -1908,8 +1908,8 @@ CCPotentials::make_xy_op_u(const CCFunction& x, const CCFunction& y, const CCCon } double -CCPotentials::make_xy_op_ab(const CCFunction& x, const CCFunction& y, const CCConvolutionOperator& op, - const CCFunction& a, const CCFunction& b) const { +CCPotentials::make_xy_op_ab(const CCFunction& x, const CCFunction& y, const CCConvolutionOperator& op, + const CCFunction& a, const CCFunction& b) const { double result = 0.0; if (x.type == HOLE) { real_function_3d xopa = op(x, a); @@ -1921,7 +1921,7 @@ CCPotentials::make_xy_op_ab(const CCFunction& x, const CCFunction& y, const CCCo return result; } -std::vector +std::vector> CCPotentials::get_pair_function(const Pairs& pairs, const size_t i, const size_t j) const { if (i > j) { return swap_particles(pairs(j, i).functions); @@ -1931,7 +1931,7 @@ CCPotentials::get_pair_function(const Pairs& pairs, const size_t i, cons } madness::real_function_3d -CCPotentials::apply_s2b_operation(const CCFunction& bra, const CCPairFunction& u, const size_t particle) const { +CCPotentials::apply_s2b_operation(const CCFunction& bra, const CCPairFunction& u, const size_t particle) const { real_function_3d result; MADNESS_ASSERT(particle == 1 || particle == 2); if (u.is_pure()) { @@ -1940,8 +1940,8 @@ CCPotentials::apply_s2b_operation(const CCFunction& bra, const CCPairFunction& u result = u.dirac_convolution(bra, *g12, particle); } else if (u.is_op_decomposed()) { // retunrns _particle - CCFunction a; - CCFunction b; + CCFunction a; + CCFunction b; if (particle == 1) { a = u.get_a()[0]; b = u.get_b()[0]; @@ -2003,15 +2003,15 @@ CCPotentials::apply_Q12t(const real_function_6d& f, const CC_vecfunction& t) con return Q(f); } -madness::CCPairFunction -CCPotentials::apply_Qt(const CCPairFunction& f, const CC_vecfunction& t, const size_t particle, const double c) const { +madness::CCPairFunction +CCPotentials::apply_Qt(const CCPairFunction& f, const CC_vecfunction& t, const size_t particle, const double c) const { MADNESS_ASSERT(particle == 1 || particle == 2); MADNESS_ASSERT(f.is_decomposed_no_op()); // pure type is not needed and op_deomposed type can not be because the result would be (1-Ot)f12|xy> = f12|xy> - \sum_a|a1a2> a subtraction with different types if (particle == 1) { - CCPairFunction result(apply_Qt(f.get_a(), t, c), f.get_b()); + CCPairFunction result(apply_Qt(f.get_a(), t, c), f.get_b()); return result; } else { - CCPairFunction result(f.get_a(), apply_Qt(f.get_b(), t, c)); + CCPairFunction result(f.get_a(), apply_Qt(f.get_b(), t, c)); return result; } } @@ -2027,8 +2027,8 @@ CCPotentials::apply_Qt(const CC_vecfunction& f, const CC_vecfunction& ket_, cons return result; } -madness::CCPairFunction -CCPotentials::apply_Ot(const CCPairFunction& f, const CC_vecfunction& t, const size_t particle) const { +madness::CCPairFunction +CCPotentials::apply_Ot(const CCPairFunction& f, const CC_vecfunction& t, const size_t particle) const { MADNESS_ASSERT(particle == 1 || particle == 2); // get the right bra CC_vecfunction mbra; @@ -2039,38 +2039,38 @@ CCPotentials::apply_Ot(const CCPairFunction& f, const CC_vecfunction& t, const s if (f.is_pure()) { vector_real_function_3d projected; for (const auto& ktmp : t.functions) { - const CCFunction& bra = mbra(ktmp.first); + const CCFunction& bra = mbra(ktmp.first); const real_function_3d kf = f.project_out(bra, particle); projected.push_back(kf); } if (particle == 1) { - return CCPairFunction(copy(world, t.get_vecfunction()), projected); + return CCPairFunction(copy(world, t.get_vecfunction()), projected); } else { - return CCPairFunction(projected, copy(world, t.get_vecfunction())); + return CCPairFunction(projected, copy(world, t.get_vecfunction())); } } else if (f.is_decomposed_no_op()) { - if (particle == 1) return CCPairFunction(apply_projector(f.get_a(), t), f.get_b()); - else return CCPairFunction(f.get_a(), apply_projector(f.get_b(), t)); + if (particle == 1) return CCPairFunction(apply_projector(f.get_a(), t), f.get_b()); + else return CCPairFunction(f.get_a(), apply_projector(f.get_b(), t)); } else if (f.is_op_decomposed()) { if (particle == 1) { const vector_real_function_3d a = copy(world, t.get_vecfunction()); // const vector_real_function_3d b = mul(world, f.get_b()[0], f.op->operator()(mbra, f.get_a()[0])); const vector_real_function_3d b = mul(world, f.get_b()[0], f.decomposed().get_operator_ptr()->operator()(mbra, f.get_a()[0])); - return CCPairFunction(a, b); + return CCPairFunction(a, b); } else { const vector_real_function_3d a = mul(world, f.get_a()[0], f.decomposed().get_operator_ptr()->operator()(mbra, f.get_b()[0])); const vector_real_function_3d b = copy(world, t.get_vecfunction()); - return CCPairFunction(a, b); + return CCPairFunction(a, b); } } else MADNESS_EXCEPTION("Should not end up here", 1) ; - return CCPairFunction(vector_real_function_3d(), vector_real_function_3d()); + return CCPairFunction(vector_real_function_3d(), vector_real_function_3d()); } madness::real_function_6d -CCPotentials::apply_G(const CCPairFunction& u, const real_convolution_6d& G) const { +CCPotentials::apply_G(const CCPairFunction& u, const real_convolution_6d& G) const { CCTimer time(world, "Applying G on " + u.name()); return apply(G,u).get_function(); // real_function_6d result = real_function_6d(world); @@ -2084,7 +2084,7 @@ CCPotentials::apply_G(const CCPairFunction& u, const real_convolution_6d& G) con // const real_function_6d tmp = G(u.get_a()[k], u.get_b()[k]); // result += tmp; // } -// } else error("Apply_G to CCPairFunction of type other than pure or decomposed"); +// } else error("Apply_G to CCPairFunction of type other than pure or decomposed"); // // time.info(true, result.norm2()); // if (result.norm2() == 0.0) output.warning("Gab is Zero"); @@ -2397,7 +2397,7 @@ CCPotentials::fock_residue_closed_shell(const CC_vecfunction& singles) const { // vecfuncT J = mul(world, intermediates_.get_hartree_potential(), tau); vector_real_function_3d J; for (const auto& tmpi : singles.functions) { - const CCFunction& taui = tmpi.second; + const CCFunction& taui = tmpi.second; real_function_3d hartree_potential = real_function_3d(world); for (const auto& tmpk : mo_ket_.functions) hartree_potential += (*g12)(mo_bra_(tmpk.first), tmpk.second); @@ -2410,7 +2410,7 @@ CCPotentials::fock_residue_closed_shell(const CC_vecfunction& singles) const { CCTimer timer_K(world, "K"); vector_real_function_3d vK; for (const auto& tmpi : singles.functions) { - const CCFunction& taui = tmpi.second; + const CCFunction& taui = tmpi.second; const real_function_3d Ki = K(taui); vK.push_back(Ki); } @@ -2454,7 +2454,7 @@ CCPotentials::K_macrotask(World& world, const std::vector& mo_ } madness::real_function_3d -CCPotentials::K(const CCFunction& f) const { +CCPotentials::K(const CCFunction& f) const { real_function_3d result = real_factory_3d(world); for (const auto& k_iterator : mo_ket_.functions) { result += (*g12)(mo_bra_(k_iterator.first), f) * mo_ket_(k_iterator.first).function; @@ -2513,7 +2513,7 @@ CCPotentials::apply_K_macrotask(World& world, const std::vector& x, const CCFunction& y) const { bool symmetric = false; if ((x.type == y.type) && (x.i == y.i)) symmetric = true; @@ -2526,22 +2526,22 @@ CCPotentials::apply_Kf(const CCFunction& x, const CCFunction& y) const { } madness::real_function_6d -CCPotentials::apply_fK(const CCFunction& x, const CCFunction& y, const real_convolution_6d *Gscreen) const { +CCPotentials::apply_fK(const CCFunction& x, const CCFunction& y, const real_convolution_6d *Gscreen) const { const bool symmetric = (x.type == y.type && x.i == y.i); const real_function_3d Kx = K(x); - const real_function_6d fKphi0b = make_f_xy(CCFunction(Kx, x.i, UNDEFINED), y, Gscreen); + const real_function_6d fKphi0b = make_f_xy(CCFunction(Kx, x.i, UNDEFINED), y, Gscreen); real_function_6d fKphi0a; if (symmetric) fKphi0a = swap_particles(fKphi0b); else { real_function_3d Ky = K(y); - fKphi0a = make_f_xy(x, CCFunction(Ky, y.i, UNDEFINED), Gscreen); + fKphi0a = make_f_xy(x, CCFunction(Ky, y.i, UNDEFINED), Gscreen); } const real_function_6d fKphi0 = (fKphi0a + fKphi0b); return fKphi0; } madness::real_function_6d -CCPotentials::make_f_xy(const CCFunction& x, const CCFunction& y, const real_convolution_6d *Gscreen) const { +CCPotentials::make_f_xy(const CCFunction& x, const CCFunction& y, const real_convolution_6d *Gscreen) const { std::string screen = ""; if (Gscreen != NULL) screen = "screened "; @@ -2853,7 +2853,7 @@ CCPotentials::s2b(const CC_vecfunction& singles, const Pairs& doubles) c real_function_3d resulti_r = real_factory_3d(world); for (const auto& ktmp : singles.functions) { const size_t k = ktmp.first; - std::vector uik = get_pair_function(doubles, i, k); + std::vector> uik = get_pair_function(doubles, i, k); // check if the first function in the vector is really the pure 6D part MADNESS_ASSERT(uik[0].is_pure()); if (recalc_u_part) { @@ -2897,7 +2897,7 @@ CCPotentials::s2c(const CC_vecfunction& singles, const Pairs& doubles) c for (const auto& ltmp : singles.functions) { const size_t l = ltmp.first; const real_function_3d l_kgi = mo_bra_(l).function * kgi; - std::vector ukl = get_pair_function(doubles, k, l); + std::vector> ukl = get_pair_function(doubles, k, l); // check if the first function in the vector is really the pure 6D part MADNESS_ASSERT(ukl[0].is_pure()); if (recalc_u_part) { @@ -2962,7 +2962,7 @@ CCPotentials::s4b(const CC_vecfunction& singles, const Pairs& doubles) c truncate(world, l_kgi); for (const auto& ltmp : singles.functions) { const size_t l = ltmp.first; - const std::vector ukl = get_pair_function(doubles, k, l); + const std::vector> ukl = get_pair_function(doubles, k, l); for (size_t mm = 0; mm < ukl.size(); mm++) { resulti += -2.0 * ukl[mm].project_out(l_kgi[l - parameters.freeze()], 2); resulti += ukl[mm].project_out(l_kgi[l - parameters.freeze()], 1); @@ -2994,7 +2994,7 @@ CCPotentials::s4c(const CC_vecfunction& singles, const Pairs& doubles) c truncate(world, l_kgtauk); for (const auto& ltmp : singles.functions) { const size_t l = ltmp.first; - const std::vector uil = get_pair_function(doubles, i, l); + const std::vector> uil = get_pair_function(doubles, i, l); for (size_t mm = 0; mm < uil.size(); mm++) { part1 += uil[mm].project_out(l_kgtauk[l - parameters.freeze()], 2); part2 += uil[mm].project_out(l_kgtauk[l - parameters.freeze()], 1); @@ -3047,7 +3047,7 @@ CC_vecfunction CCPotentials::make_t_intermediate(const CC_vecfunction& tau, cons CC_vecfunction result(returntype); for (const auto& itmp:tau.functions) { const size_t i = itmp.first; - CCFunction t(mo_ket_(i).function + factor * tau(i).function, i, MIXED); + CCFunction t(mo_ket_(i).function + factor * tau(i).function, i, MIXED); result.insert(i, t); } @@ -3074,7 +3074,7 @@ CC_vecfunction CCPotentials::make_full_t_intermediate(const CC_vecfunction& tau) if (i < parameters.freeze()) { result.insert(i, mo_ket_(i)); } else { - CCFunction t(mo_ket_(i).function + tau(i).function, i, MIXED); + CCFunction t(mo_ket_(i).function + tau(i).function, i, MIXED); result.insert(i, t); } } @@ -3084,30 +3084,30 @@ CC_vecfunction CCPotentials::make_full_t_intermediate(const CC_vecfunction& tau) /// makes the t intermediates /// t_i = mo_ket_(i) + tau /// i = tau.i -CCFunction CCPotentials::make_t_intermediate(const CCFunction& tau) const { +CCFunction CCPotentials::make_t_intermediate(const CCFunction& tau) const { MADNESS_ASSERT(tau.type == PARTICLE); - const CCFunction t(mo_ket_(tau.i).function + tau.function, tau.i, MIXED); + const CCFunction t(mo_ket_(tau.i).function + tau.function, tau.i, MIXED); return t; } /// forms the regularized functions from Q and Qt Ansatz for CIS(D) where tau=0 and t=mo so that Qt=Q -void CCPotentials::test_pair_consistency(const CCPairFunction& u, const size_t i, const size_t j, +void CCPotentials::test_pair_consistency(const CCPairFunction& u, const size_t i, const size_t j, const CC_vecfunction& x) const { if (parameters.QtAnsatz()) { // u(QAnsatz) = u(QtAnsatz) - OxQftt - QOxftt - std::vector v1; + std::vector> v1; v1.push_back(u); - std::vector v2; + std::vector> v2; v2.push_back(u); - CCPairFunction ftt(f12, mo_ket_(i), mo_ket_(j)); - CCPairFunction O1xftt = apply_Ot(ftt, x, 1); - CCPairFunction OxQftt = apply_Qt(O1xftt, mo_ket_, 2); - CCPairFunction OxQ = OxQftt.invert_sign(); + CCPairFunction ftt(f12, mo_ket_(i), mo_ket_(j)); + CCPairFunction O1xftt = apply_Ot(ftt, x, 1); + CCPairFunction OxQftt = apply_Qt(O1xftt, mo_ket_, 2); + CCPairFunction OxQ = OxQftt.invert_sign(); v2.push_back(OxQ); - CCPairFunction O2xftt = apply_Ot(ftt, x, 2); - CCPairFunction QOxftt = apply_Qt(O2xftt, mo_ket_, 1); - CCPairFunction QOx = QOxftt.invert_sign(); + CCPairFunction O2xftt = apply_Ot(ftt, x, 2); + CCPairFunction QOxftt = apply_Qt(O2xftt, mo_ket_, 1); + CCPairFunction QOx = QOxftt.invert_sign(); v2.push_back(QOx); CCPair p1(i, j, EXCITED_STATE, CT_CISPD, v1); @@ -3121,16 +3121,16 @@ void CCPotentials::test_pair_consistency(const CCPairFunction& u, const size_t i } else { // u(QtAnsatz) = u(QAnsatz) + OxQftt - QOxftt - std::vector v1; + std::vector> v1; v1.push_back(u); - std::vector v2; + std::vector> v2; v2.push_back(u); - CCPairFunction ftt(f12, mo_ket_(i), mo_ket_(j)); - CCPairFunction O1xftt = apply_Ot(ftt, x, 1); - CCPairFunction OxQftt = apply_Qt(O1xftt, mo_ket_, 2); + CCPairFunction ftt(f12, mo_ket_(i), mo_ket_(j)); + CCPairFunction O1xftt = apply_Ot(ftt, x, 1); + CCPairFunction OxQftt = apply_Qt(O1xftt, mo_ket_, 2); v2.push_back(OxQftt); - CCPairFunction O2xftt = apply_Ot(ftt, x, 2); - CCPairFunction QOxftt = apply_Qt(O2xftt, mo_ket_, 1); + CCPairFunction O2xftt = apply_Ot(ftt, x, 2); + CCPairFunction QOxftt = apply_Qt(O2xftt, mo_ket_, 1); v2.push_back(QOxftt); CCPair p1(i, j, EXCITED_STATE, CT_CISPD, v1); @@ -3191,7 +3191,7 @@ bool CCPotentials::test_compare_pairs(const CCPair& pair1, const CCPair& pair2) // make a single 6D functions of the pair real_function_6d CCPotentials::make_6D_pair(const CCPair& pair) const { - std::vector functions = pair.functions; + std::vector> functions = pair.functions; real_function_6d result = real_factory_6d(world); for (const auto& f:functions) { if (f.is_pure()) result += f.pure().get_function(); @@ -3206,7 +3206,7 @@ real_function_6d CCPotentials::make_6D_pair(const CCPair& pair) const { MADNESS_ASSERT(f.get_operator().type() == OpType::OT_F12); real_function_6d fxy = make_f_xy(f.get_a()[0], f.get_b()[0]); result += fxy; - } else MADNESS_EXCEPTION("Unknown type of CCPairFunction", 1); + } else MADNESS_EXCEPTION("Unknown type of CCPairFunction", 1); } return result; } @@ -3231,8 +3231,8 @@ void CCPotentials::test_pairs() { CCPair rr_3D = (make_pair_gs(u, mo_ket_, i, j)); real_function_6d rr_tmp = make_f_xy(t(i), t(j)); real_function_6d rr_6D0 = apply_Q12t(rr_tmp, mo_ket_); - CCPairFunction rr_6D1(rr_6D0); - std::vector rr_6D2(1, rr_6D1); + CCPairFunction rr_6D1(rr_6D0); + std::vector> rr_6D2(1, rr_6D1); CCPair rr_6D(i, j, GROUND_STATE, CT_CC2, rr_6D2); regrestest = test_compare_pairs(rr_3D, rr_6D); } @@ -3276,8 +3276,8 @@ void CCPotentials::test_pairs() { MADNESS_EXCEPTION("No Test for QtAnsatz right now", 1); } } - CCPairFunction rr_6D1(rr_6D0); - std::vector rr_6D2(1, rr_6D1); + CCPairFunction rr_6D1(rr_6D0); + std::vector> rr_6D2(1, rr_6D1); CCPair rr_6D(i, j, GROUND_STATE, CT_MP2, rr_6D2); regrestest = test_compare_pairs(rr_3D, rr_6D); } @@ -3428,8 +3428,8 @@ void CCPotentials::test() { else output.warning("Test Failed: Norm1 = " + std::to_string(norma) + ", Norm2 = " + std::to_string(normb)); } { - CCFunction mo = mo_ket_(0); - CCFunction mo1 = mo * 2.0; + CCFunction mo = mo_ket_(0); + CCFunction mo1 = mo * 2.0; double norma = mo.function.norm2(); double normb = mo1.function.norm2(); if (2.0 * norma == normb) output("Test Passed"); @@ -3454,7 +3454,7 @@ void CCPotentials::test() { } - output.section("Testing Overlaps of CCPairFunction"); + output.section("Testing Overlaps of CCPairFunction"); // f^2 = 1/(4y^2)(1 - 2*f2(y) + f2(2y)) , f2(2y) =f2(y)^2 const double y = parameters.gamma(); SeparatedConvolution f = SlaterF12Operator(world, y, parameters.lo(), parameters.thresh_bsh_3D()); @@ -3483,7 +3483,7 @@ void CCPotentials::test() { const double lo = parameters.thresh_6D(); const double hi = parameters.thresh_3D(); { - CCPairFunction fab(f12, a, b); + CCPairFunction fab(f12, a, b); const double test1 = overlap(fab, fab); const double prefactor = 1.0 / (4 * y * y); const double test2 = prefactor * (aR.inner(a) * bR.inner(b) - 2.0 * bb.inner(af2a) + bb.inner(affa)); @@ -3497,7 +3497,7 @@ void CCPotentials::test() { << ", test=" << test2 << ", diff=" << diff << "\n"; } { - CCPairFunction ab(mo_ket_.get_vecfunction(), mo_ket_.get_vecfunction()); + CCPairFunction ab(mo_ket_.get_vecfunction(), mo_ket_.get_vecfunction()); const double test1 = overlap(ab, ab); const double test2 = double(mo_ket_.size()); // mos are normed const double diff = test1 - test2; @@ -3508,7 +3508,7 @@ void CCPotentials::test() { if (fabs(diff) > hi) passed_hi = false; } { - CCPairFunction ab(ab_6d); + CCPairFunction ab(ab_6d); const double test1 = overlap(ab, ab); const double test2 = double(mo_ket_.size()); // mos are normed const double diff = test1 - test2; @@ -3519,8 +3519,8 @@ void CCPotentials::test() { if (fabs(diff) > hi) passed_hi = false; } { - CCPairFunction ab1(mo_ket_.get_vecfunction(), mo_ket_.get_vecfunction()); - CCPairFunction ab2(ab_6d); + CCPairFunction ab1(mo_ket_.get_vecfunction(), mo_ket_.get_vecfunction()); + CCPairFunction ab2(ab_6d); const double test1 = overlap(ab1, ab2); const double test2 = double(mo_ket_.size()); // mos are normed const double diff = test1 - test2; @@ -3532,8 +3532,8 @@ void CCPotentials::test() { } { // the next tests evaulate in different ways - CCPairFunction fab(fab_6d); - CCPairFunction ab2(mo_ket_.get_vecfunction(), mo_ket_.get_vecfunction()); + CCPairFunction fab(fab_6d); + CCPairFunction ab2(mo_ket_.get_vecfunction(), mo_ket_.get_vecfunction()); const double test1 = overlap(fab, ab2); const double test2 = bb.inner(afa); const double diff = test1 - test2; @@ -3544,8 +3544,8 @@ void CCPotentials::test() { if (fabs(diff) > hi) passed_hi = false; } { - CCPairFunction fab(fab_6d); - CCPairFunction ab2(ab_6d); + CCPairFunction fab(fab_6d); + CCPairFunction ab2(ab_6d); const double test1 = overlap(fab, ab2); const double test2 = bb.inner(afa); const double diff = test1 - test2; @@ -3556,8 +3556,8 @@ void CCPotentials::test() { if (fabs(diff) > hi) passed_hi = false; } { - CCPairFunction fab(f12, a, b); - CCPairFunction ab2(ab_6d); + CCPairFunction fab(f12, a, b); + CCPairFunction ab2(ab_6d); const double test1 = overlap(fab, ab2); const double test2 = bb.inner(afa); const double diff = test1 - test2; @@ -3568,8 +3568,8 @@ void CCPotentials::test() { if (fabs(diff) > hi) passed_hi = false; } { - CCPairFunction fab(f12, a, b); - CCPairFunction ab2(mo_ket_.get_vecfunction(), mo_ket_.get_vecfunction()); + CCPairFunction fab(f12, a, b); + CCPairFunction ab2(mo_ket_.get_vecfunction(), mo_ket_.get_vecfunction()); const double test1 = overlap(fab, ab2); const double test2 = bb.inner(afa); const double diff = test1 - test2; diff --git a/src/madness/chem/CCPotentials.h b/src/madness/chem/CCPotentials.h index a458e70eeb6..2e5afb3c6ba 100644 --- a/src/madness/chem/CCPotentials.h +++ b/src/madness/chem/CCPotentials.h @@ -33,7 +33,7 @@ class CCPotentials { ~CCPotentials() {}; /// forms the regularized functions from Q and Qt Ansatz for CIS(D) where tau=0 and t=mo so that Qt=Q - void test_pair_consistency(const CCPairFunction& u, const size_t i, const size_t j, const CC_vecfunction& x) const; + void test_pair_consistency(const CCPairFunction& u, const size_t i, const size_t j, const CC_vecfunction& x) const; bool test_compare_pairs(const CCPair& pair1, const CCPair& pair2) const; @@ -109,7 +109,7 @@ class CCPotentials { } /// returns a specific mo - CCFunction mo_ket(const size_t& i) const { + CCFunction mo_ket(const size_t& i) const { return mo_ket_(i); } @@ -119,7 +119,7 @@ class CCPotentials { } /// returns a specific mo multiplied with the squared nuclear correlation factor - CCFunction mo_bra(const size_t& i) const { + CCFunction mo_bra(const size_t& i) const { return mo_bra_(i); } @@ -152,7 +152,7 @@ class CCPotentials { /// makes the t intermediates /// t_i = mo_ket_(i) + tau /// i = tau.i - CCFunction make_t_intermediate(const CCFunction& tau) const; + CCFunction make_t_intermediate(const CCFunction& tau) const; private: /// Helper function to initialize the const mo_bra and ket elements adn orbital energies @@ -265,7 +265,7 @@ class CCPotentials { /// @param[in] tj, second particle -> should be HOLE state /// @param[in] Gscreen pointer to bsh operator (in order to screen), has to be in modified NS form real_function_6d - make_constant_part_mp2(const CCFunction& ti, const CCFunction& tj, const real_convolution_6d *Gscreen = NULL) const; + make_constant_part_mp2(const CCFunction& ti, const CCFunction& tj, const real_convolution_6d *Gscreen = NULL) const; /// Static version of make_constant_part_mp2 to be called from macrotask. static madness::real_function_6d @@ -337,7 +337,7 @@ class CCPotentials { /// @param[in] pointer to bsh operator (in order to screen) /// @param[out] the regularization potential (unprojected), see equation above real_function_6d - apply_Vreg(const CCFunction& ti, const CCFunction& tj, const real_convolution_6d *Gscreen = NULL) const; + apply_Vreg(const CCFunction& ti, const CCFunction& tj, const real_convolution_6d *Gscreen = NULL) const; /// Static version of apply_Vreg to be used from a macrotask. Will eventually replace former. madness::real_function_6d @@ -359,7 +359,7 @@ class CCPotentials { /// @param[in] tj, second function in the ket ... /// @param[in] pointer to bsh operator (in order to screen) real_function_6d - apply_reduced_F(const CCFunction& ti, const CCFunction& tj, const real_convolution_6d *Gscreen = NULL) const; + apply_reduced_F(const CCFunction& ti, const CCFunction& tj, const real_convolution_6d *Gscreen = NULL) const; /// Apply Ue on a tensor product of two 3d functions: Ue(1,2) |x(1)y(2)> (will be either |ij> or |\tau_i\tau_j> or mixed forms) @@ -373,7 +373,7 @@ class CCPotentials { /// @param[in] The BSH operator to screen: Has to be in NS form, Gscreen->modified == true /// @return R^-1U_eR|x,y> the transformed electronic smoothing potential applied on |x,y> : real_function_6d - apply_transformed_Ue(const CCFunction& x, const CCFunction& y, const real_convolution_6d *Gscreen = NULL) const; + apply_transformed_Ue(const CCFunction& x, const CCFunction& y, const real_convolution_6d *Gscreen = NULL) const; /// Static version of apply_transformed_Ue for the use in a macrotask. /// Will eventually replace the former. @@ -396,7 +396,7 @@ class CCPotentials { /// the f12K|xy> part will be screened with the BSH while the Kf12|xy> can not be screened with the BSH operator but maybe with the coulomb /// @return R^-1U_eR|x,y> the transformed electronic smoothing potential applied on |x,y> : real_function_6d - apply_exchange_commutator(const CCFunction& x, const CCFunction& y, + apply_exchange_commutator(const CCFunction& x, const CCFunction& y, const real_convolution_6d *Gscreen = NULL) const; real_function_6d @@ -408,7 +408,7 @@ class CCPotentials { /// This applies the exchange commutator, see apply_exchange_commutator function for information real_function_6d - apply_exchange_commutator1(const CCFunction& x, const CCFunction& y, + apply_exchange_commutator1(const CCFunction& x, const CCFunction& y, const real_convolution_6d *Gscreen = NULL) const; /// Helper Function which performs the operation \f$ \f$ @@ -417,9 +417,9 @@ class CCPotentials { /// @param[in] function a, /// @param[in] function b, double - make_xy_gf_ab(const CCFunction& x, const CCFunction& y, const CCFunction& a, const CCFunction& b) const; + make_xy_gf_ab(const CCFunction& x, const CCFunction& y, const CCFunction& a, const CCFunction& b) const; - double make_xy_ff_ab(const CCFunction& x, const CCFunction& y, const CCFunction& a, const CCFunction& b) const { + double make_xy_ff_ab(const CCFunction& x, const CCFunction& y, const CCFunction& a, const CCFunction& b) const { error("xy_ff_ab not yet implemented"); return 0.0; } @@ -433,22 +433,22 @@ class CCPotentials { /// loops over every entry in the vector and accumulates results /// helper function for CIS(D) energy double - make_xy_op_u(const CCFunction& x, const CCFunction& y, const CCConvolutionOperator& op, - const std::vector& u) const; + make_xy_op_u(const CCFunction& x, const CCFunction& y, const CCConvolutionOperator& op, + const std::vector>& u) const; /// returns for a vector of CCPairFunction /// the result is accumulated for every vercotr /// helper functions for CIS(D) energy double - make_xy_u(const CCFunction& x, const CCFunction& y, const std::vector& u) const; + make_xy_u(const CCFunction& x, const CCFunction& y, const std::vector>& u) const; /// Functions which operate with the CCPairFunction structure /// @param[in] function x, if nuclear correlation is used make sure this is the correct bra function /// @param[in] function y, if nuclear correlation is used make sure this is the correct bra function /// @param[in] CCPairFunction u, double - make_xy_op_u(const CCFunction& x, const CCFunction& y, const CCConvolutionOperator& op, - const CCPairFunction& u) const; + make_xy_op_u(const CCFunction& x, const CCFunction& y, const CCConvolutionOperator& op, + const CCPairFunction& u) const; /// Helper Function which returns /// @return @@ -457,19 +457,19 @@ class CCPotentials { /// @param[in] function a, /// @param[in] function b, double - make_xy_op_ab(const CCFunction& x, const CCFunction& y, const CCConvolutionOperator& op, const CCFunction& a, - const CCFunction& b) const; + make_xy_op_ab(const CCFunction& x, const CCFunction& y, const CCConvolutionOperator& op, const CCFunction& a, + const CCFunction& b) const; /// get the correct pair function as vector of CCPairFunction functions /// @param[in] The pair functions /// @param[out] The demanded pair function as vector of CCPairFunction functions (includes regularization tails) - std::vector + std::vector> get_pair_function(const Pairs& pairs, const size_t i, const size_t j) const; /// returns _2 real_function_3d - apply_s2b_operation(const CCFunction& bra, const CCPairFunction& u, const size_t particle) const; + apply_s2b_operation(const CCFunction& bra, const CCPairFunction& u, const size_t particle) const; /// dummy to avoid confusion and for convenience real_function_6d swap_particles(const real_function_6d& f) const { @@ -477,8 +477,8 @@ class CCPotentials { } /// swap the particles of the CCPairFunction and return a new vector of swapped functions - std::vector swap_particles(const std::vector& f) const { - std::vector swapped; + std::vector> swap_particles(const std::vector>& f) const { + std::vector> swapped; for (size_t i = 0; i < f.size(); i++) swapped.push_back(f[i].swap_particles()); return swapped; } @@ -487,7 +487,7 @@ class CCPotentials { /// @param[in] 6D function 1 /// @param[in] 6D function 2 double - overlap(const CCPairFunction& f1, const CCPairFunction& f2) const { + overlap(const CCPairFunction& f1, const CCPairFunction& f2) const { return inner(f1,f2,nemo_->ncf->square()); }; @@ -521,8 +521,8 @@ class CCPotentials { /// Apply the Qt projector on a CCPairFunction /// works in principle like apply_Ot - CCPairFunction - apply_Qt(const CCPairFunction& f, const CC_vecfunction& t, const size_t particle, const double c = 1.0) const; + CCPairFunction + apply_Qt(const CCPairFunction& f, const CC_vecfunction& t, const size_t particle, const double c = 1.0) const; /// Apply Ot projector on decomposed or op_decomposed 6D function /// The function does not work with type==pure right now (not needed) @@ -533,14 +533,14 @@ class CCPotentials { /// for CCPairFunction type == op_decomposd the function si f=op|xy> and we have for particle==1 /// \f$ a_k = t_k \f$ /// \f$ b_k = *y \f$ - CCPairFunction - apply_Ot(const CCPairFunction& f, const CC_vecfunction& t, const size_t particle) const; + CCPairFunction + apply_Ot(const CCPairFunction& f, const CC_vecfunction& t, const size_t particle) const; /// Apply the Greens Operator to a CCPairFunction /// For CCPairFunction only type pure and type decomposed is supported /// for the op_decomposed type a pure function can be constructed (not needed therefore not implemented yet) real_function_6d - apply_G(const CCPairFunction& u, const real_convolution_6d& G) const; + apply_G(const CCPairFunction& u, const real_convolution_6d& G) const; /// Apply BSH Operator and count time real_function_6d apply_G(const real_function_6d& f, const real_convolution_6d& G) const { @@ -637,7 +637,7 @@ class CCPotentials { /// the K operator runs over ALL orbitals (also the frozen ones) real_function_3d - K(const CCFunction& f) const; + K(const CCFunction& f) const; /// static version of k above for access from macrotask. will eventually replace former. real_function_3d @@ -675,7 +675,7 @@ class CCPotentials { /// Apply the Exchange operator on a tensor product multiplied with f12 /// !!! Prefactor of (-1) is not inclued in K here !!!! real_function_6d - apply_Kf(const CCFunction& x, const CCFunction& y) const; + apply_Kf(const CCFunction& x, const CCFunction& y) const; /// Apply fK on a tensor product of two 3D functions /// fK|xy> = fK_1|xy> + fK_2|xy> @@ -683,11 +683,11 @@ class CCPotentials { /// @param[in] y, the second 3D function in |xy> structure holds index i and type (HOLE, PARTICLE, MIXED, UNDEFINED) /// @param[in] BSH operator to screen, has to be in modified NS form, Gscreen->modified()==true; real_function_6d - apply_fK(const CCFunction& x, const CCFunction& y, const real_convolution_6d *Gscreen = NULL) const; + apply_fK(const CCFunction& x, const CCFunction& y, const real_convolution_6d *Gscreen = NULL) const; /// Creates a 6D function with the correlation factor and two given CCFunctions real_function_6d - make_f_xy(const CCFunction& x, const CCFunction& y, const real_convolution_6d *Gscreen = NULL) const; + make_f_xy(const CCFunction& x, const CCFunction& y, const real_convolution_6d *Gscreen = NULL) const; real_function_6d static make_f_xy_macrotask( World& world, const real_function_3d& x_ket, const real_function_3d& y_ket, @@ -829,9 +829,9 @@ class CCPotentials { std::vector orbital_energies_; /// the coulomb operator with all intermediates public: - std::shared_ptr g12; + std::shared_ptr> g12; /// the f12 operator with all intermediates - std::shared_ptr f12; + std::shared_ptr> f12; /// the correlation factor, holds necessary regularized potentials CorrelationFactor corrfac; /// Manager for stored intermediate potentials which are s2c, s2b and the whole singles potentials without fock-residue for GS and EX state diff --git a/src/madness/chem/CCStructures.cc b/src/madness/chem/CCStructures.cc index 9a80c260cfc..a72c383bae2 100644 --- a/src/madness/chem/CCStructures.cc +++ b/src/madness/chem/CCStructures.cc @@ -63,36 +63,12 @@ CCTimer::info(const bool debug, const double norm) { } } -void -CCFunction::info(World& world, const std::string& msg) const { - if (world.rank() == 0) { - std::cout << "Information about 3D function: " << name() << " " << msg << std::endl; - std::cout << std::setw(10) << std::setfill(' ') << std::setw(50) << " |f| : " << function.norm2() - << std::endl; - std::cout << std::setw(10) << std::setfill(' ') << std::setw(50) << " |error|: " << current_error << std::endl; - } -} - -std::string -CCFunction::name() const { - if (type == HOLE) { - return "phi" + stringify(i); - } else if (type == PARTICLE) { - return "tau" + stringify(i); - } else if (type == MIXED) { - return "t" + stringify(i); - } else if (type == RESPONSE) { - return "x" + stringify(i); - } else { - return "function" + stringify(i); - } -} madness::CC_vecfunction CC_vecfunction::copy() const { - std::vector vn; + std::vector> vn; for (auto x : functions) { - const CCFunction fn(madness::copy(x.second.function), x.second.i, x.second.type); + const CCFunction fn(madness::copy(x.second.function), x.second.i, x.second.type); vn.push_back(fn); } CC_vecfunction result(vn, type); @@ -161,7 +137,7 @@ CCIntermediatePotentials::operator()(const CC_vecfunction& f, const PotentialTyp } madness::real_function_3d -CCIntermediatePotentials::operator()(const CCFunction& f, const PotentialType& type) const { +CCIntermediatePotentials::operator()(const CCFunction& f, const PotentialType& type) const { output("Getting " + assign_name(type) + " for " + f.name()); real_function_3d result = real_factory_3d(world); if (type == POT_singles_ and (f.type == PARTICLE or f.type == MIXED)) @@ -299,9 +275,10 @@ void CCParameters::sanity_check(World& world) const { } } -real_function_3d -CCConvolutionOperator::operator()(const CCFunction& bra, const CCFunction& ket, const bool use_im) const { - real_function_3d result; +template +Function +CCConvolutionOperator::operator()(const CCFunction& bra, const CCFunction& ket, const bool use_im) const { + Function result; if (not use_im) { if (world.rank() == 0) std::cout << "Recalculating <" << bra.name() << "|" << name() << "|" << ket.name() @@ -320,52 +297,60 @@ CCConvolutionOperator::operator()(const CCFunction& bra, const CCFunction& ket, return result; } -real_function_6d CCConvolutionOperator::operator()(const real_function_6d& u, const size_t particle) const { +template +Function CCConvolutionOperator::operator()(const Function& u, const size_t particle) const { MADNESS_CHECK(particle == 1 or particle == 2); MADNESS_CHECK(op); op->particle() = particle; return (*op)(u); } -real_function_3d -CCConvolutionOperator::operator()(const CCFunction& bra, const real_function_6d& u, const size_t particle) const { +template +Function +CCConvolutionOperator::operator()(const CCFunction& bra, const Function& u, const size_t particle) const { MADNESS_CHECK(particle == 1 or particle == 2); MADNESS_CHECK(op); - const real_function_6d tmp = multiply(copy(u), copy(bra.function), particle); + const Function tmp = multiply(copy(u), copy(bra.function), particle); op->particle() = particle; - const real_function_6d g_tmp = (*op)(tmp); - const real_function_3d result = g_tmp.dirac_convolution<3>(); + const Function g_tmp = (*op)(tmp); + const Function result = g_tmp.dirac_convolution(); return result; } - -void CCConvolutionOperator::update_elements(const CC_vecfunction& bra, const CC_vecfunction& ket) { - const std::string operation_name = "<" + assign_name(bra.type) + "|" + name() + "|" + assign_name(ket.type) + ">"; - if (world.rank() == 0) - std::cout << "updating operator elements: " << operation_name << " (" << bra.size() << "x" << ket.size() << ")" - << std::endl; - if (bra.type != HOLE) - error("Can not create intermediate of type " + operation_name + " , bra-element has to be of type HOLE"); - op.reset(init_op(type(), parameters)); - intermediateT xim; - for (auto tmpk : bra.functions) { - const CCFunction& k = tmpk.second; - for (auto tmpl : ket.functions) { - const CCFunction& l = tmpl.second; - real_function_3d kl = (bra(k).function * l.function); - real_function_3d result = ((*op)(kl)).truncate(); - result.reconstruct(); // for sparse multiplication - xim.insert(k.i, l.i, result); +template +void CCConvolutionOperator::update_elements(const CC_vecfunction& bra, const CC_vecfunction& ket) { + if constexpr (NDIM==6) { + const std::string operation_name = "<" + assign_name(bra.type) + "|" + name() + "|" + assign_name(ket.type) + ">"; + if (world.rank() == 0) + std::cout << "updating operator elements: " << operation_name << " (" << bra.size() << "x" << ket.size() << ")" + << std::endl; + if (bra.type != HOLE) + error("Can not create intermediate of type " + operation_name + " , bra-element has to be of type HOLE"); + op.reset(init_op(type(), parameters)); + intermediateT xim; + for (auto tmpk : bra.functions) { + const CCFunction& k = tmpk.second; + for (auto tmpl : ket.functions) { + const CCFunction& l = tmpl.second; + Function kl = (bra(k).function * l.function); + Function result = ((*op)(kl)).truncate(); + result.reconstruct(); // for sparse multiplication + xim.insert(k.i, l.i, result); + } } + if (ket.type == HOLE) imH = xim; + else if (ket.type == PARTICLE) imP = xim; + else if (ket.type == RESPONSE) imR = xim; + else error("Can not create intermediate of type <" + assign_name(bra.type) + "|op|" + assign_name(ket.type) + ">"); + } else { + std::string msg="update_elements not implemented for NDIM="+std::to_string(NDIM); + MADNESS_EXCEPTION(msg.c_str(),1); } - if (ket.type == HOLE) imH = xim; - else if (ket.type == PARTICLE) imP = xim; - else if (ket.type == RESPONSE) imR = xim; - else error("Can not create intermediate of type <" + assign_name(bra.type) + "|op|" + assign_name(ket.type) + ">"); } -void CCConvolutionOperator::clear_intermediates(const FuncType& type) { +template +void CCConvolutionOperator::clear_intermediates(const FuncType& type) { if (world.rank() == 0) std::cout << "Deleting all intermediates \n"; switch (type) { @@ -386,7 +371,8 @@ void CCConvolutionOperator::clear_intermediates(const FuncType& type) { } } -size_t CCConvolutionOperator::info() const { +template +size_t CCConvolutionOperator::info() const { const size_t size_imH = size_of(imH); const size_t size_imP = size_of(imP); const size_t size_imR = size_of(imR); @@ -402,12 +388,13 @@ size_t CCConvolutionOperator::info() const { return size_imH + size_imP + size_imR; } -SeparatedConvolution * -CCConvolutionOperator::init_op(const OpType& type, const Parameters& parameters) const { +template +SeparatedConvolution * +CCConvolutionOperator::init_op(const OpType& type, const CCConvolutionOperator::Parameters& parameters) const { bool debug=false; bool printme=(world.rank()==0) and debug; if (printme) print("init_op: creating",type,"with thresh, lo, gamma",parameters.thresh_op,parameters.lo,parameters.gamma); - return new SeparatedConvolution(world,OperatorInfo(parameters.gamma,parameters.lo,parameters.thresh_op,type)); + return new SeparatedConvolution(world,OperatorInfo(parameters.gamma,parameters.lo,parameters.thresh_op,type)); } /// Assigns strings to enums for formated output @@ -538,15 +525,6 @@ assign_name(const FuncType& inp) { return "???"; } -/// Returns the size of an intermediate -double -size_of(const intermediateT& im) { - double size = 0.0; - for (const auto& tmp : im.allpairs) { - size += get_size(tmp.second); - } - return size; -} std::vector MacroTaskMp2ConstantPart::operator() (const std::vector& pair, const std::vector& mo_ket, @@ -581,6 +559,14 @@ MacroTaskMp2UpdatePair::operator() (const std::vector &pair, return result; } +template class CCConvolutionOperator; +template class CCConvolutionOperator; +template class CCConvolutionOperator; + +template class CCFunction; +template class CCFunction; +template class CCFunction; + }// end namespace madness diff --git a/src/madness/chem/CCStructures.h b/src/madness/chem/CCStructures.h index 0835cca9945..dc23ed9a159 100644 --- a/src/madness/chem/CCStructures.h +++ b/src/madness/chem/CCStructures.h @@ -482,11 +482,22 @@ struct Pairs { }; /// f12 and g12 intermediates of the form (with op=f12 or op=g12) will be saved using the pair structure -typedef Pairs intermediateT; +template +using intermediateT = Pairs>; /// Returns the size of an intermediate +//double +//size_of(const intermediateT& im); +/// Returns the size of an intermediate +template double -size_of(const intermediateT& im); +size_of(const intermediateT& im) { + double size = 0.0; + for (const auto& tmp : im.allpairs) { + size += get_size(tmp.second); + } + return size; +} @@ -500,12 +511,12 @@ struct CC_vecfunction : public archive::ParallelSerializableObject { CC_vecfunction(const vector_real_function_3d& v) : type(UNDEFINED), omega(0.0), current_error(99.9), delta(0.0) { for (size_t i = 0; i < v.size(); i++) { - CCFunction tmp(v[i], i, type); + CCFunction tmp(v[i], i, type); functions.insert(std::make_pair(i, tmp)); } } - CC_vecfunction(const std::vector& v) : type(UNDEFINED), omega(0.0), current_error(99.9), delta(0.0) { + CC_vecfunction(const std::vector>& v) : type(UNDEFINED), omega(0.0), current_error(99.9), delta(0.0) { for (size_t i = 0; i < v.size(); i++) { functions.insert(std::make_pair(v[i].i, v[i])); } @@ -514,7 +525,7 @@ struct CC_vecfunction : public archive::ParallelSerializableObject { CC_vecfunction(const vector_real_function_3d& v, const FuncType& type) : type(type), omega(0.0), current_error(99.9), delta(0.0) { for (size_t i = 0; i < v.size(); i++) { - CCFunction tmp(v[i], i, type); + CCFunction tmp(v[i], i, type); functions.insert(std::make_pair(i, tmp)); } } @@ -524,12 +535,12 @@ struct CC_vecfunction : public archive::ParallelSerializableObject { current_error(99.9), delta(0.0) { for (size_t i = 0; i < v.size(); i++) { - CCFunction tmp(v[i], freeze + i, type); + CCFunction tmp(v[i], freeze + i, type); functions.insert(std::make_pair(freeze + i, tmp)); } } - CC_vecfunction(const std::vector& v, const FuncType type_) + CC_vecfunction(const std::vector>& v, const FuncType type_) : type(type_), omega(0.0), current_error(99.9), delta(0.0) { for (auto x:v) functions.insert(std::make_pair(x.i, x)); } @@ -573,7 +584,7 @@ struct CC_vecfunction : public archive::ParallelSerializableObject { template void serialize(const Archive& ar) { - typedef std::vector> CC_functionvec; + typedef std::vector>> CC_functionvec; auto map2vector = [] (const CC_functionmap& map) { return CC_functionvec(map.begin(), map.end()); @@ -597,7 +608,7 @@ struct CC_vecfunction : public archive::ParallelSerializableObject { } } - typedef std::map CC_functionmap; + typedef std::map> CC_functionmap; CC_functionmap functions; FuncType type; @@ -614,27 +625,27 @@ struct CC_vecfunction : public archive::ParallelSerializableObject { } /// getter - const CCFunction& operator()(const CCFunction& i) const { + const CCFunction& operator()(const CCFunction& i) const { return functions.find(i.i)->second; } /// getter - const CCFunction& operator()(const size_t& i) const { + const CCFunction& operator()(const size_t& i) const { return functions.find(i)->second; } /// getter - CCFunction& operator()(const CCFunction& i) { + CCFunction& operator()(const CCFunction& i) { return functions[i.i]; } /// getter - CCFunction& operator()(const size_t& i) { + CCFunction& operator()(const size_t& i) { return functions[i]; } /// setter - void insert(const size_t& i, const CCFunction& f) { + void insert(const size_t& i, const CCFunction& f) { functions.insert(std::make_pair(i, f)); } @@ -642,7 +653,7 @@ struct CC_vecfunction : public archive::ParallelSerializableObject { void set_functions(const vector_real_function_3d& v, const FuncType& type, const size_t& freeze) { functions.clear(); for (size_t i = 0; i < v.size(); i++) { - CCFunction tmp(v[i], freeze + i, type); + CCFunction tmp(v[i], freeze + i, type); functions.insert(std::make_pair(freeze + i, tmp)); } } @@ -695,6 +706,7 @@ struct CC_vecfunction : public archive::ParallelSerializableObject { /// The structure can hold intermediates for g12 and f12 of type : with type=HOLE,PARTICLE or RESPONSE /// some 6D operations are also included /// The structure does not know if nuclear correlation facors are used, so the corresponding bra states have to be prepared beforehand +template struct CCConvolutionOperator { /// parameter class @@ -730,7 +742,7 @@ struct CCConvolutionOperator { protected: friend CCConvolutionOperator combine(const CCConvolutionOperator& a, const CCConvolutionOperator& b) { - auto info= SeparatedConvolution::combine_OT((*a.get_op()),(*b.get_op())); + auto info= SeparatedConvolution::combine_OT((*a.get_op()),(*b.get_op())); Parameters param; param.gamma=info.mu; param.thresh_op=info.thresh; @@ -750,7 +762,7 @@ struct CCConvolutionOperator { public: /// @param[in] f: a 3D function /// @param[out] the convolution op(f), no intermediates are used - real_function_3d operator()(const real_function_3d& f) const { + Function operator()(const Function& f) const { if (op) return ((*op)(f)).truncate(); return f; } @@ -758,46 +770,51 @@ struct CCConvolutionOperator { /// @param[in] bra a CC_vecfunction /// @param[in] ket a CC_function /// @param[out] vector[i] = - vector_real_function_3d operator()(const CC_vecfunction& bra, const CCFunction& ket) const { + std::vector> operator()(const CC_vecfunction& bra, const CCFunction& ket) const { MADNESS_CHECK(op); - vector_real_function_3d result; - if (bra.type == HOLE) { - for (const auto& ktmp:bra.functions) { - const CCFunction& brai = ktmp.second; - const real_function_3d tmpi = this->operator()(brai, ket); - result.push_back(tmpi); + std::vector> result; + if constexpr (NDIM == 3) { + if (bra.type == HOLE) { + for (const auto& ktmp: bra.functions) { + const CCFunction& brai = ktmp.second; + const Function tmpi = this->operator()(brai, ket); + result.push_back(tmpi); + } + } else { + std::vector> tmp = mul(world, ket.function, bra.get_vecfunction()); + result = apply(world, (*op), tmp); + truncate(world, result); } } else { - vector_real_function_3d tmp = mul(world, ket.function, bra.get_vecfunction()); - result = apply(world, (*op), tmp); - truncate(world, result); + MADNESS_EXCEPTION("not implemented", 1); } + return result; } // @param[in] f: a vector of 3D functions // @param[out] the convolution of op with each function, no intermeditates are used - vector_real_function_3d operator()(const vector_real_function_3d& f) const { + std::vector> operator()(const std::vector>& f) const { MADNESS_CHECK(op); - return apply(world, (*op), f); + return apply(world, (*op), f); } // @param[in] bra: a 3D CC_function, if nuclear-correlation factors are used they have to be applied before // @param[in] ket: a 3D CC_function, // @param[in] use_im: default is true, if false then no intermediates are used // @param[out] the convolution = op(bra*ket), if intermediates were calculated before the operator uses them - real_function_3d operator()(const CCFunction& bra, const CCFunction& ket, const bool use_im = true) const; + Function operator()(const CCFunction& bra, const CCFunction& ket, const bool use_im = true) const; // @param[in] u: a 6D-function // @param[out] the convolution \int g(r,r') u(r,r') dr' (if particle==2) and g(r,r') u(r',r) dr' (if particle==1) // @param[in] particle: specifies on which particle of u the operator will act (particle ==1 or particle==2) - real_function_6d operator()(const real_function_6d& u, const size_t particle) const; + Function operator()(const Function& u, const size_t particle) const; // @param[in] bra: a 3D-CC_function, if nuclear-correlation factors are used they have to be applied before // @param[in] u: a 6D-function // @param[in] particle: specifies on which particle of u the operator will act (particle ==1 or particle==2) // @param[out] the convolution _particle - real_function_3d operator()(const CCFunction& bra, const real_function_6d& u, const size_t particle) const; + Function operator()(const CCFunction& bra, const Function& u, const size_t particle) const; /// @param[in] bra: a vector of CC_functions, the type has to be HOLE /// @param[in] ket: a vector of CC_functions, the type can be HOLE,PARTICLE,RESPONSE @@ -838,8 +855,8 @@ struct CCConvolutionOperator { } /// create a TwoElectronFactory with the operatorkernel - TwoElectronFactory get_kernel() const { - auto factory=TwoElectronFactory(world); + TwoElectronFactory get_kernel() const { + auto factory=TwoElectronFactory(world); factory.set_info(op->info); return factory; } @@ -848,7 +865,7 @@ struct CCConvolutionOperator { const Parameters parameters; - std::shared_ptr get_op() const {return op;}; + std::shared_ptr> get_op() const {return op;}; private: /// the world @@ -857,12 +874,12 @@ struct CCConvolutionOperator { /// @param[in] optype: can be f12_ or g12_ depending on which operator shall be intitialzied /// @param[in] parameters: parameters (thresholds etc) /// initializes the operators - SeparatedConvolution *init_op(const OpType& type, const Parameters& parameters) const; + SeparatedConvolution *init_op(const OpType& type, const Parameters& parameters) const; - std::shared_ptr op; - intermediateT imH; - intermediateT imP; - intermediateT imR; + std::shared_ptr> op; + intermediateT imH; + intermediateT imP; + intermediateT imR; /// @param[in] msg: output message /// the function will throw an MADNESS_EXCEPTION @@ -875,10 +892,10 @@ struct CCConvolutionOperator { public: }; -template -std::shared_ptr CCConvolutionOperatorPtr(World& world, const OpType type, - CCConvolutionOperator::Parameters param) { - return std::shared_ptr(new CCConvolutionOperator(world,type,param)); +template +std::shared_ptr> CCConvolutionOperatorPtr(World& world, const OpType type, + typename CCConvolutionOperator::Parameters param) { + return std::shared_ptr>(new CCConvolutionOperator(world,type,param)); } @@ -889,7 +906,7 @@ class CCPair : public archive::ParallelSerializableObject { CCPair(const size_t ii, const size_t jj, const CCState t, const CalcType c) : type(t), ctype(c), i(ii), j(jj), bsh_eps(12345.6789) {}; - CCPair(const size_t ii, const size_t jj, const CCState t, const CalcType c, const std::vector& f) + CCPair(const size_t ii, const size_t jj, const CCState t, const CalcType c, const std::vector>& f) : type(t), ctype(c), i(ii), j(jj), functions(f), bsh_eps(12345.6789) {}; CCPair(const CCPair& other) : type(other.type), ctype(other.ctype), i(other.i), j(other.j), @@ -968,7 +985,7 @@ class CCPair : public archive::ParallelSerializableObject { } /// the functions which belong to the pair - std::vector functions; + std::vector> functions; /// the constant part real_function_6d constant_part; @@ -999,8 +1016,8 @@ struct CCIntermediatePotentials { operator()(const CC_vecfunction& f, const PotentialType& type) const; /// fetch the potential for a single function - real_function_3d - operator()(const CCFunction& f, const PotentialType& type) const; + Function + operator()(const CCFunction& f, const PotentialType& type) const; /// deltes all stored potentials void clear_all() { @@ -1069,9 +1086,9 @@ class MacroTaskMp2ConstantPart : public MacroTaskOperationBase { public: MacroTaskMp2ConstantPart(){partitioner.reset(new ConstantPartPartitioner());} - typedef std::tuple&, const std::vector&, - const std::vector&, const CCParameters&, const real_function_3d&, - const std::vector&, const std::vector& > argtupleT; + typedef std::tuple&, const std::vector>&, + const std::vector>&, const CCParameters&, const Function&, + const std::vector>&, const std::vector& > argtupleT; using resultT = std::vector; @@ -1081,9 +1098,9 @@ class MacroTaskMp2ConstantPart : public MacroTaskOperationBase { return result; } - resultT operator() (const std::vector& pair, const std::vector& mo_ket, - const std::vector& mo_bra, const CCParameters& parameters, - const real_function_3d& Rsquare, const std::vector& U1, + resultT operator() (const std::vector& pair, const std::vector>& mo_ket, + const std::vector>& mo_bra, const CCParameters& parameters, + const Function& Rsquare, const std::vector>& U1, const std::vector& argument) const; }; @@ -1110,8 +1127,8 @@ class MacroTaskMp2UpdatePair : public MacroTaskOperationBase { typedef std::tuple&, const std::vector&, const CCParameters&, const std::vector< madness::Vector >&, - const std::vector&, const std::vector&, - const std::vector&, const real_function_3d&> argtupleT; + const std::vector>&, const std::vector>&, + const std::vector>&, const Function&> argtupleT; using resultT = std::vector; @@ -1123,8 +1140,8 @@ class MacroTaskMp2UpdatePair : public MacroTaskOperationBase { resultT operator() (const std::vector& pair, const std::vector& mp2_coupling, const CCParameters& parameters, const std::vector< madness::Vector >& all_coords_vec, - const std::vector& mo_ket, const std::vector& mo_bra, - const std::vector& U1, const real_function_3d& U2) const; + const std::vector>& mo_ket, const std::vector>& mo_bra, + const std::vector>& U1, const Function& U2) const; }; }//namespace madness diff --git a/src/madness/chem/TDHF.cc b/src/madness/chem/TDHF.cc index 4db95c875ba..2e0653ecd96 100644 --- a/src/madness/chem/TDHF.cc +++ b/src/madness/chem/TDHF.cc @@ -69,7 +69,7 @@ void TDHF::initialize() { msg.section("Initialize TDHF Class"); msg.debug = parameters.debug(); - g12=std::make_shared(world, OpType::OT_G12, parameters.get_ccc_parameters(get_calcparam().lo())); + g12=std::make_shared>(world, OpType::OT_G12, parameters.get_ccc_parameters(get_calcparam().lo())); const double old_thresh = FunctionDefaults<3>::get_thresh(); if (old_thresh > parameters.thresh() * 0.1 and old_thresh > 1.e-5) { diff --git a/src/madness/chem/TDHF.h b/src/madness/chem/TDHF.h index 107a2b5de2b..ec98cdb2fcf 100644 --- a/src/madness/chem/TDHF.h +++ b/src/madness/chem/TDHF.h @@ -196,8 +196,8 @@ class TDHF : public QCPropertyInterface { std::size_t guess_maxiter() const { return get("guess_maxiter"); } /// make parameters for convolution operator - typename CCConvolutionOperator::Parameters get_ccc_parameters(const double lo) const { - typename CCConvolutionOperator::Parameters result; + typename CCConvolutionOperator::Parameters get_ccc_parameters(const double lo) const { + typename CCConvolutionOperator::Parameters result; result.freeze = freeze(); result.lo = lo; result.thresh_op = thresh(); @@ -514,7 +514,7 @@ class TDHF : public QCPropertyInterface { TDHFParameters parameters; /// Operator Structure which can handle intermediates (use for exchange with GS orbitals) /// Can be replaced by another potential manager - std::shared_ptr g12; + std::shared_ptr> g12; /// MO bra and ket CC_vecfunction mo_ket_; CC_vecfunction mo_bra_; diff --git a/src/madness/chem/ccpairfunction.cc b/src/madness/chem/ccpairfunction.cc index 09ebc9abcfd..e785c2c3fe1 100644 --- a/src/madness/chem/ccpairfunction.cc +++ b/src/madness/chem/ccpairfunction.cc @@ -11,14 +11,15 @@ using namespace madness; namespace madness { - -madness::CCPairFunction -CCPairFunction::invert_sign() { +template +madness::CCPairFunction +CCPairFunction::invert_sign() { (*this)*=(-1.0); return *this; } -bool CCPairFunction::is_convertible_to_pure_no_op() const { +template +bool CCPairFunction::is_convertible_to_pure_no_op() const { if (has_operator()) { const auto type=get_operator().type(); if (not (type==OpType::OT_SLATER or type==OpType::OT_F12)) return false; @@ -28,13 +29,14 @@ bool CCPairFunction::is_convertible_to_pure_no_op() const { }; -void CCPairFunction::convert_to_pure_no_op_inplace() { +template +void CCPairFunction::convert_to_pure_no_op_inplace() { pureT tmp; - pureT result=real_factory_6d(world()); + pureT result=FunctionFactory(world()); if (is_pure_no_op()) { return; } else if (is_pure()) { - tmp= CompositeFactory(world()) + tmp= CompositeFactory(world()) .g12(get_operator().get_kernel()) .ket(get_function()); tmp.fill_tree(); @@ -43,12 +45,12 @@ void CCPairFunction::convert_to_pure_no_op_inplace() { MADNESS_CHECK_THROW(get_a().size()<3,"a.size not <3 in convert_to_pure_no_op_inplace"); for (int i=0; i(world()) + tmp= CompositeFactory(world()) .g12(get_operator().get_kernel()) .particle1(get_a()[i]) .particle2(get_b()[i]); } else if (is_decomposed_no_op()) { - tmp= CompositeFactory(world()) + tmp= CompositeFactory(world()) .particle1(get_a()[i]) .particle2(get_b()[i]); } @@ -56,13 +58,14 @@ void CCPairFunction::convert_to_pure_no_op_inplace() { result+=tmp; } } - component.reset(new TwoBodyFunctionPureComponent(result)); + component.reset(new TwoBodyFunctionPureComponent(result)); }; -std::vector consolidate(const std::vector& other) { +template +std::vector> consolidate(const std::vector>& other) { - std::vector result; - std::vector all_pure; + std::vector> result; + std::vector> all_pure; for (auto& c : other) { if (c.is_pure_no_op()) all_pure.push_back(c.get_function()); else result.push_back(c); @@ -70,38 +73,15 @@ std::vector consolidate(const std::vector& other if (not all_pure.empty()) { for (std::size_t i=1; i(all_pure.front())); } return result; } -CCPairFunction multiply(const CCPairFunction& other, const real_function_3d& f, const std::array& v1) { - auto a012=std::array{0,1,2}; - auto a345=std::array{3,4,5}; - int particle=-1; - if (v1== a012) particle=0; - if (v1== a345) particle=1; - MADNESS_CHECK(particle==0 or particle==1); - World& world=other.world(); - - if (other.is_decomposed()) { - if (particle == 0) { - return CCPairFunction(other.get_operator_ptr(), f * other.get_a(), copy(world, other.get_b())); - } else { - return CCPairFunction(other.get_operator_ptr(), copy(world, other.get_a()), f * other.get_b()); - } - } else if (other.is_pure()) { - auto tmp=multiply(other.get_function(),f,particle+1); - return CCPairFunction(other.get_operator_ptr(),tmp); - } else { - MADNESS_EXCEPTION("confused CCPairFunction in multiply",1); - } -}; - - /// multiplication with a 2-particle function -CCPairFunction& CCPairFunction::multiply_with_op_inplace(const std::shared_ptr op) { +template +CCPairFunction& CCPairFunction::multiply_with_op_inplace(const std::shared_ptr::LDIM>> op) { if (has_operator()) { auto newop=combine(get_operator_ptr(),op); reset_operator(newop); @@ -111,46 +91,50 @@ CCPairFunction& CCPairFunction::multiply_with_op_inplace(const std::shared_ptr double -CCPairFunction::make_xy_u(const CCFunction& xx, const CCFunction& yy) const { - double result = 0.0; +CCPairFunction::make_xy_u(const CCFunction& xx, const CCFunction& yy) const { + T result = 0.0; if (is_pure()) { World& world=xx.function.world(); - real_function_6d ij = CompositeFactory(world).particle1(madness::copy(xx.function)) + Function ij = CompositeFactory(world).particle1(madness::copy(xx.function)) .particle2( madness::copy(yy.function)); result = inner(pure().get_function(), ij); } else if (is_decomposed_no_op()) { for (size_t i = 0; i < get_a().size(); i++) result += (xx.function.inner(get_a()[i])) * (yy.function.inner(get_b()[i])); } else if (is_op_decomposed()) { - const CCConvolutionOperator& op=*decomposed().get_operator_ptr(); + const CCConvolutionOperator& op=*decomposed().get_operator_ptr(); result = yy.function.inner(op(xx, get_a()[0]) * get_b()[0]); } return result; } -real_function_3d CCPairFunction::project_out(const CCFunction& f, const size_t particle) const { +template +Function::LDIM> +CCPairFunction::project_out(const CCFunction& f, const size_t particle) const { MADNESS_ASSERT(particle == 1 or particle == 2); - real_function_3d result; + Function result; if (is_pure_no_op()) { result = pure().get_function().project_out(f.function, particle - 1); // this needs 0 or 1 for particle but we give 1 or 2 } else if (is_op_pure()) { - MADNESS_EXCEPTION("implement CCPairFunction::project_out for op_pure",1); + MADNESS_EXCEPTION("implement CCPairFunction::project_out for op_pure",1); } else if (is_decomposed_no_op()) { result = project_out_decomposed(f.function, particle); } else if (is_op_decomposed()) { result = project_out_op_decomposed(f, particle); } - if (not result.is_initialized()) MADNESS_EXCEPTION("Result of project out on CCPairFunction was not initialized", + if (not result.is_initialized()) MADNESS_EXCEPTION("Result of project out on CCPairFunction was not initialized", 1); return result; } // result is: _particle -real_function_3d -CCPairFunction::dirac_convolution(const CCFunction& x, const CCConvolutionOperator& op, const size_t particle) const { - real_function_3d result; +template +Function::LDIM> +CCPairFunction::dirac_convolution(const CCFunction& x, const CCConvolutionOperator::LDIM>& op, const size_t particle) const { + Function::LDIM> result; if (is_pure()) { result = op(x, pure().get_function(), particle); } else if (is_decomposed_no_op()) { @@ -161,58 +145,16 @@ CCPairFunction::dirac_convolution(const CCFunction& x, const CCConvolutionOperat return result; } -// CCPairFunction CCPairFunction::swap_particles() const { -// switch (type) { -// default: MADNESS_EXCEPTION("Undefined enum", 1); -// case PT_FULL: -// return swap_particles_pure(); -// break; -// case PT_DECOMPOSED: -// return swap_particles_decomposed(); -// break; -// case PT_OP_DECOMPOSED: -// return swap_particles_op_decomposed(); -// break; -// } -// MADNESS_EXCEPTION("swap_particles in CCPairFunction: we should not end up here", 1); -// } - - - -real_function_3d inner(const CCPairFunction& c, const real_function_3d& f, - const std::tuple v1, const std::tuple v2) { - auto v11=std::array({std::get<0>(v1),std::get<1>(v1),std::get<2>(v1)}); - auto v22=std::array({std::get<0>(v2),std::get<1>(v2),std::get<2>(v2)}); - - return c.partial_inner(f,v11,v22); -} - -CCPairFunction inner(const CCPairFunction& c1, const CCPairFunction& c2, - const std::tuple v1, const std::tuple v2) { - auto v11=std::array({std::get<0>(v1),std::get<1>(v1),std::get<2>(v1)}); - auto v22=std::array({std::get<0>(v2),std::get<1>(v2),std::get<2>(v2)}); - - return c1.partial_inner(c2,v11,v22); -} - -std::vector inner(const std::vector& c1, - const std::vector& c2, - const std::tuple v1, const std::tuple v2) { - std::vector result; - for (const auto& cc1 : c1) { - for (const auto& cc2 : c2) { - print("inner of ",cc1.name(), cc2.name()); - result.push_back(inner(cc1,cc2,v1,v2)); - } +template +CCPairFunction CCPairFunction::partial_inner(const CCPairFunction& other, + const std::array::LDIM>& v1, + const std::array::LDIM>& v2) const { + auto a012=std::array(); + auto a345=std::array(); + for (int i=0; i& v1, - const std::array& v2) const { - auto a012=std::array{0,1,2}; - auto a345=std::array{3,4,5}; MADNESS_CHECK(v1==a012 or v1== a345); MADNESS_CHECK(v2==a012 or v2== a345); MADNESS_CHECK(not this->is_op_pure()); // not implemented yet @@ -221,20 +163,20 @@ CCPairFunction CCPairFunction::partial_inner(const CCPairFunction& other, auto integration_index=[&a012,&a345](auto v) {return (v==a012) ? 0l : 1l;}; auto remaining_index=[&integration_index](auto v) {return (integration_index(v)+1)%2;}; - CCPairFunction result; + CCPairFunction result; if (this->is_pure()) { if (other.is_pure()) { - real_function_6d tmp=madness::innerXX<6>(this->get_function(),other.get_function(),v1,v2); - return CCPairFunction(tmp); + Function tmp=madness::innerXX(this->get_function(),other.get_function(),v1,v2); + return CCPairFunction(tmp); } else if (other.is_decomposed_no_op()) { // \int \sum_i f(1,2) a_i(1) b_i(3) d1 = \sum_i b_i(3) \int a_i(1) f(1,2) d1 - vector_real_function_3d tmp; + std::vector> tmp; for (auto& a : other.get_vector(integration_index(v2))) { // tmp.push_back(innerXX<3>(this->get_function(),a,v1,a012)); // a012 is correct, referring to 3D function tmp.push_back(this->get_function().project_out(a,integration_index(v1))); } - return CCPairFunction(tmp,other.get_vector(remaining_index(v2))); + return CCPairFunction(tmp,other.get_vector(remaining_index(v2))); } else if (other.is_op_decomposed()) { @@ -247,16 +189,16 @@ CCPairFunction CCPairFunction::partial_inner(const CCPairFunction& other, auto& op=*(other.get_operator().get_op()); op.particle()=integration_index(v1)+1; - const vector_real_function_6d tmp=partial_mul(h,c,integration_index(v1)+1); - auto H=apply(world(),op,tmp); - real_function_6d result=real_factory_6d(world()); + const std::vector> tmp=partial_mul(h,c,integration_index(v1)+1); + auto H=madness::apply(world(),op,tmp); + Function result=FunctionFactory(world()); // const vector_real_function_6d result=partial_mul(H,d,integration_index(v1)+1); for (int i=0; i(result); } else { - MADNESS_EXCEPTION("confused CCPairfunction",1); + MADNESS_EXCEPTION("confused CCPairFunction",1); } } else if (this->is_decomposed_no_op()) { @@ -273,7 +215,7 @@ CCPairFunction CCPairFunction::partial_inner(const CCPairFunction& other, for (int i=0; iget_vector(remaining_index(v1)),U); auto right=transform(world(),other.get_vector(remaining_index(v2)),transpose(VT)); - return CCPairFunction(left,right); + return CCPairFunction(left,right); } else if (other.is_op_decomposed()) { // \int \sum_ij a_i(1) b_i(2) f(1,3) c_j(1) d_j(3) d1 @@ -291,9 +233,9 @@ CCPairFunction CCPairFunction::partial_inner(const CCPairFunction& other, const auto g=madness::apply(world(),op,ac); h[i]=dot(world(),d,g); } - return CCPairFunction(b,h); + return CCPairFunction(b,h); } else { - MADNESS_EXCEPTION("confused CCPairfunction",1); + MADNESS_EXCEPTION("confused CCPairFunction",1); } } else if (this->is_op_decomposed()) { @@ -303,31 +245,39 @@ CCPairFunction CCPairFunction::partial_inner(const CCPairFunction& other, return other.partial_inner(*this,v2,v1); } else if (other.is_op_decomposed()) { if (this->is_convertible_to_pure_no_op()) { - CCPairFunction tmp=copy(*this); + CCPairFunction tmp=copy(*this); tmp.convert_to_pure_no_op_inplace(); return tmp.partial_inner(other,v1,v2); } else if (other.is_convertible_to_pure_no_op()) { - CCPairFunction tmp=copy(other); + CCPairFunction tmp=copy(other); tmp.convert_to_pure_no_op_inplace(); return this->partial_inner(tmp,v1,v2); } else { MADNESS_EXCEPTION("no partial_inner for this combination: ",1); } } else { - MADNESS_EXCEPTION("confused CCPairfunction",1); + MADNESS_EXCEPTION("confused CCPairFunction",1); } } else { - MADNESS_EXCEPTION("confused CCPairfunction",1); + MADNESS_EXCEPTION("confused CCPairFunction",1); } return result; } -real_function_3d CCPairFunction::partial_inner(const real_function_3d& f, - const std::array& v1, - const std::array& v2) const { - auto a012=std::array{0,1,2}; - auto a345=std::array{3,4,5}; +template +Function::LDIM> CCPairFunction::partial_inner( + const Function::LDIM>& f, + const std::array::LDIM>& v1, + const std::array::LDIM >& v2) const { +// auto a012=std::array{0,1,2}; +// auto a345=std::array{3,4,5}; + auto a012=std::array(); + auto a345=std::array(); + for (int i=0; iis_op_pure()); // not implemented yet @@ -335,7 +285,7 @@ real_function_3d CCPairFunction::partial_inner(const real_function_3d& f, if (v1== a012) particle=0; if (v1== a345) particle=1; - real_function_3d result; + Function::LDIM> result; if (is_pure()) { result = pure().get_function().project_out(f, particle); @@ -344,23 +294,26 @@ real_function_3d CCPairFunction::partial_inner(const real_function_3d& f, } else if (is_op_decomposed()) { result = project_out_op_decomposed(f, particle+1); } else { - MADNESS_EXCEPTION("confused state in CCPairFunction::partial_inner",1); + MADNESS_EXCEPTION("confused state in CCPairFunction::partial_inner",1); } return result; } -real_function_3d CCPairFunction::project_out_decomposed(const real_function_3d& f, const size_t particle) const { +template +Function::LDIM> CCPairFunction::project_out_decomposed( + const Function& f, const size_t particle) const { World& world=f.world(); - real_function_3d result = real_factory_3d(world); - const std::pair decompf = assign_particles(particle); + Function result = FunctionFactory(world); + const std::pair>, std::vector>> decompf = assign_particles(particle); Tensor c = inner(world, f, decompf.first); for (size_t i = 0; i < get_a().size(); i++) result += c(i) * decompf.second[i]; return result; } -real_function_3d CCPairFunction::project_out_op_decomposed(const CCFunction& f, const size_t particle) const { +template +Function::LDIM> CCPairFunction::project_out_op_decomposed(const CCFunction& f, const size_t particle) const { World& world=f.get().world(); - const CCConvolutionOperator& op=*decomposed().get_operator_ptr(); + const CCConvolutionOperator& op=*decomposed().get_operator_ptr(); if (particle == 1) { // return op(f, get_a()[0]) * get_b()[0]; // result(2) = < f(1) | op(1,2) | a_i(1) b_i(2) > @@ -370,24 +323,27 @@ real_function_3d CCPairFunction::project_out_op_decomposed(const CCFunction& f, return sum(world,mul(world,op(f.f()* get_b()),get_a())); } else { MADNESS_EXCEPTION("project_out_op_decomposed: particle must be 1 or 2", 1); - return real_factory_3d(world); + return FunctionFactory(world); } } -real_function_3d CCPairFunction::dirac_convolution_decomposed(const CCFunction& bra, const CCConvolutionOperator& op, +template +Function::LDIM> CCPairFunction::dirac_convolution_decomposed(const CCFunction& bra, + const CCConvolutionOperator& op, const size_t particle) const { World& world=bra.function.world(); - const std::pair f = assign_particles(particle); - const vector_real_function_3d braa = mul(world, bra.function, f.first); - const vector_real_function_3d braga = op(braa); - real_function_3d result = real_factory_3d(world); + const std::pair>, std::vector>> f = assign_particles(particle); + const std::vector> braa = mul(world, bra.function, f.first); + const std::vector> braga = op(braa); + Function result = FunctionFactory(world); for (size_t i = 0; i < braga.size(); i++) result += braga[i] * f.second[i]; return result; } -const std::pair -CCPairFunction::assign_particles(const size_t particle) const { +template +const std::pair::LDIM>>, std::vector::LDIM>>> +CCPairFunction::assign_particles(const size_t particle) const { if (particle == 1) { return std::make_pair(get_a(), get_b()); } else if (particle == 2) { @@ -401,9 +357,10 @@ CCPairFunction::assign_particles(const size_t particle) const { /// compute the inner product of this and other /// there are 4 possible components: pure/decomposed with and without operator, gives us 16 pair combinations.. -double CCPairFunction::inner_internal(const CCPairFunction& other, const real_function_3d& R2) const { - const CCPairFunction& f1=*this; - const CCPairFunction& f2=other; +template +double CCPairFunction::inner_internal(const CCPairFunction& other, const Function& R2) const { + const CCPairFunction& f1=*this; + const CCPairFunction& f2=other; double thresh=FunctionDefaults<6>::get_thresh()*0.1; @@ -413,37 +370,37 @@ double CCPairFunction::inner_internal(const CCPairFunction& other, const real_fu pureT ket=f2.get_function(); // include the operator(s), if any auto op=combine(f1.get_operator_ptr(),f2.get_operator_ptr()); - real_function_6d tmp1; + Function tmp1; if (op) { if (R2.is_initialized()) { - tmp1 = CompositeFactory(world()).g12(op->get_kernel()).ket(ket).particle1(R2).particle2(R2); + tmp1 = CompositeFactory(world()).g12(op->get_kernel()).ket(ket).particle1(R2).particle2(R2); } else { - tmp1 = CompositeFactory(world()).g12(op->get_kernel()).ket(ket); + tmp1 = CompositeFactory(world()).g12(op->get_kernel()).ket(ket); } } else { if (R2.is_initialized()) { - tmp1 = CompositeFactory(world()).ket(ket).particle1(R2).particle2(R2); + tmp1 = CompositeFactory(world()).ket(ket).particle1(R2).particle2(R2); } else { - tmp1 = CompositeFactory(world()).ket(ket); + tmp1 = CompositeFactory(world()).ket(ket); } } result=inner(bra,tmp1); } else if (f1.is_pure() and f2.is_decomposed()) { // with or without operator - const vector_real_function_3d a = R2.is_initialized() ? R2 * f2.get_a() : copy(world(), f2.get_a()); - const vector_real_function_3d b = R2.is_initialized() ? R2 * f2.get_b() : copy(world(), f2.get_b()); + const std::vector> a = R2.is_initialized() ? R2 * f2.get_a() : copy(world(), f2.get_a()); + const std::vector> b = R2.is_initialized() ? R2 * f2.get_b() : copy(world(), f2.get_b()); const pureT& bra=f1.get_function(); auto op=combine(f1.get_operator_ptr(),f2.get_operator_ptr()); if (op) { double bla=0.0; for (int i=0; i(world()).g12(op->get_kernel()).particle1(a[i]).particle2(b[i]); + Function tmp = CompositeFactory(world()).g12(op->get_kernel()).particle1(a[i]).particle2(b[i]); bla += inner(bra, tmp); } result+=bla; } else { // no operators for (int i=0; i(world()).particle1(a[i]).particle2(b[i]); + Function tmp = CompositeFactory(world()).particle1(a[i]).particle2(b[i]); result+=inner(bra,tmp); } } @@ -454,10 +411,10 @@ double CCPairFunction::inner_internal(const CCPairFunction& other, const real_fu MADNESS_ASSERT(f1.get_a().size() == f1.get_b().size()); MADNESS_ASSERT(f2.get_a().size() == f2.get_b().size()); - const vector_real_function_3d& a1 = f1.get_a(); - const vector_real_function_3d& b1 = f1.get_b(); - const vector_real_function_3d a2 = R2.is_initialized() ? R2* f2.get_a() : f2.get_a(); - const vector_real_function_3d b2 = R2.is_initialized() ? R2* f2.get_b() : f2.get_b(); + const std::vector>& a1 = f1.get_a(); + const std::vector>& b1 = f1.get_b(); + const std::vector> a2 = R2.is_initialized() ? R2* f2.get_a() : f2.get_a(); + const std::vector> b2 = R2.is_initialized() ? R2* f2.get_b() : f2.get_b(); // MADNESS_EXCEPTION("still to debug",1); @@ -469,89 +426,85 @@ double CCPairFunction::inner_internal(const CCPairFunction& other, const real_fu // = result=0.0; for (size_t i = 0; i < a1.size(); i++) { - vector_real_function_3d aa = truncate(a1[i] * a2); - vector_real_function_3d bb = truncate(b1[i] * b2); - vector_real_function_3d aopx = (*op)(aa); + std::vector> aa = truncate(a1[i] * a2); + std::vector> bb = truncate(b1[i] * b2); + std::vector> aopx = (*op)(aa); result += inner(bb, aopx); } } } else MADNESS_EXCEPTION( - ("CCPairFunction Overlap not supported for combination " + f1.name() + " and " + f2.name()).c_str(), 1) ; + ("CCPairFunction Overlap not supported for combination " + f1.name() + " and " + f2.name()).c_str(), 1) ; return result; } -CCPairFunction apply(const ProjectorBase& projector, const CCPairFunction& argument) { - auto result=madness::apply(projector,std::vector (1,argument)); - MADNESS_CHECK(result.size()==1); - return result[0]; -} - -std::vector apply(const ProjectorBase& projector, const std::vector& argument) { +template +std::vector> CCPairFunction::apply(const ProjectorBase& projector, const std::vector>& argument) { if (argument.size()==0) return argument; World& world=argument.front().world(); + constexpr std::size_t LDIM=CCPairFunction::LDIM; // print("apply projector on argument with terms",argument.size()); - if (auto P=dynamic_cast*>(&projector)) { + if (auto P=dynamic_cast*>(&projector)) { // print("P->get_particle()",P->get_particle()); - MADNESS_CHECK_THROW(P->get_particle()==0 or P->get_particle()==1,"P Projector particle must be 0 or 1 in CCPairFunction"); + MADNESS_CHECK_THROW(P->get_particle()==0 or P->get_particle()==1,"P Projector particle must be 0 or 1 in CCPairFunction"); } - if (auto Q=dynamic_cast*>(&projector)) { + if (auto Q=dynamic_cast*>(&projector)) { // print("Q->get_particle()",Q->get_particle()); - MADNESS_CHECK_THROW(Q->get_particle()==0 or Q->get_particle()==1,"Q Projector particle must be 0 or 1 in CCPairFunction"); + MADNESS_CHECK_THROW(Q->get_particle()==0 or Q->get_particle()==1,"Q Projector particle must be 0 or 1 in CCPairFunction"); } - std::vector result; + std::vector> result; for (const auto& pf : argument) { if (pf.is_pure()) { MADNESS_CHECK(not pf.has_operator()); // not yet implemented - if (auto SO=dynamic_cast*>(&projector)) { + if (auto SO=dynamic_cast*>(&projector)) { auto tmp=(*SO)(pf.get_function()); - auto tmp2=CCPairFunction(tmp); + auto tmp2=CCPairFunction(tmp); result.push_back(tmp2); - } else if (auto P=dynamic_cast*>(&projector)) { - result.push_back(CCPairFunction((*P)(pf.get_function(),P->get_particle()+1))); + } else if (auto P=dynamic_cast*>(&projector)) { + result.push_back(CCPairFunction((*P)(pf.get_function(),P->get_particle()+1))); - } else if (auto Q=dynamic_cast*>(&projector)) { - result.push_back(CCPairFunction((*Q)(pf.get_function(),Q->get_particle()+1))); + } else if (auto Q=dynamic_cast*>(&projector)) { + result.push_back(CCPairFunction((*Q)(pf.get_function(),Q->get_particle()+1))); } else { - MADNESS_EXCEPTION("CCPairFunction: unknown projector type",1); + MADNESS_EXCEPTION("CCPairFunction: unknown projector type",1); } } else if (pf.is_decomposed_no_op()) { // pair function is sum_i | a_i b_i > - if (auto SO=dynamic_cast*>(&projector)) { + if (auto SO=dynamic_cast*>(&projector)) { // Q12 | kl > = (1-O1)(1-O2) |kl> = |(1-O1)k (1-O2)l> - QProjector Q1(world,SO->bra1(),SO->ket1()); - QProjector Q2(world,SO->bra2(),SO->ket2()); - result.push_back(CCPairFunction(Q1(pf.get_a()),Q2(pf.get_b()))); + QProjector Q1(world,SO->bra1(),SO->ket1()); + QProjector Q2(world,SO->bra2(),SO->ket2()); + result.push_back(CCPairFunction(Q1(pf.get_a()),Q2(pf.get_b()))); - } else if (auto P=dynamic_cast*>(&projector)) { + } else if (auto P=dynamic_cast*>(&projector)) { // P1 | kl > = P1 |kl> = |P1 k l> - if (P->get_particle()==0) result.push_back(CCPairFunction((*P)(pf.get_a()),pf.get_b())); + if (P->get_particle()==0) result.push_back(CCPairFunction((*P)(pf.get_a()),pf.get_b())); // P2 | kl > = P2 |kl> = |k P2 l> - if (P->get_particle()==1) result.push_back(CCPairFunction(pf.get_a(),(*P)(pf.get_b()))); + if (P->get_particle()==1) result.push_back(CCPairFunction(pf.get_a(),(*P)(pf.get_b()))); - } else if (auto Q=dynamic_cast*>(&projector)) { + } else if (auto Q=dynamic_cast*>(&projector)) { // Q1 | kl > = Q1 |kl> = |Q1 k l> - if (Q->get_particle()==0) result.push_back(CCPairFunction((*Q)(pf.get_a()),pf.get_b())); + if (Q->get_particle()==0) result.push_back(CCPairFunction((*Q)(pf.get_a()),pf.get_b())); // P2 | kl > = Q2 |kl> = |k Q2 l> - if (Q->get_particle()==1) result.push_back(CCPairFunction(pf.get_a(),(*Q)(pf.get_b()))); + if (Q->get_particle()==1) result.push_back(CCPairFunction(pf.get_a(),(*Q)(pf.get_b()))); } else { - MADNESS_EXCEPTION("CCPairFunction: unknown projector type",1); + MADNESS_EXCEPTION("CCPairFunction: unknown projector type",1); } } else if (pf.is_op_decomposed()) { - if (auto SO=dynamic_cast*>(&projector)) { + if (auto SO=dynamic_cast*>(&projector)) { // CCTimer t(world,"SO block"); // Q12 = 1 - O1 (1 - 1/2 O2) - O2 (1 - 1/2 O1) // print("entering SO block"); - QProjector Q1(world,SO->bra1(),SO->ket1()); + QProjector Q1(world,SO->bra1(),SO->ket1()); Q1.set_particle(0); - QProjector Q2(world,SO->bra2(),SO->ket2()); + QProjector Q2(world,SO->bra2(),SO->ket2()); Q2.set_particle(1); - Projector O1(SO->bra1(),SO->ket1()); + Projector O1(SO->bra1(),SO->ket1()); O1.set_particle(0); - Projector O2(SO->bra2(),SO->ket2()); + Projector O2(SO->bra2(),SO->ket2()); O2.set_particle(1); -// auto arg=std::vector({pf}); +// auto arg=std::vector>({pf}); // auto o1arg=O1(arg); // auto o2arg=O2(arg); // auto o1o2arg=O1(o2arg); @@ -562,45 +515,45 @@ std::vector apply(const ProjectorBase& projector, const std::vec // for (auto& t: o1o2arg) result.push_back(t); - auto tmp=Q1(Q2(std::vector({pf}))); -// auto tmp=Q2(Q1(std::vector({pf}))); + auto tmp=Q1(Q2(std::vector>({pf}))); +// auto tmp=Q2(Q1(std::vector>({pf}))); // print("result of SO"); // for (auto& t: tmp) t.print_size(); for (auto& t: tmp) result.push_back(t); // for (auto& t: result) t.print_size(); - } else if (auto P=dynamic_cast*>(&projector)) { + } else if (auto P=dynamic_cast*>(&projector)) { // CCTimer t(world,"P block"); // print("entering P block"); - std::vector tmp= zero_functions_compressed(world,P->get_ket_vector().size()); + std::vector> tmp= zero_functions_compressed(world,P->get_ket_vector().size()); // per term a_i b_i: // P1 f |a b> = \sum_k |k(1)> |f_ak(2)*b(2)> for (std::size_t i=0; i a=pf.get_a()[i]; + Function b=pf.get_b()[i]; if (P->get_particle()==1) std::swap(a,b); - std::vector ka=a*P->get_bra_vector(); - real_convolution_3d& op=*(pf.get_operator().get_op()); - std::vector f_ka=apply(world,op,ka); - std::vector b_f_ka=f_ka*b; + std::vector> ka=a*P->get_bra_vector(); + SeparatedConvolution& op=*(pf.get_operator().get_op()); + std::vector> f_ka=madness::apply(world,op,ka); + std::vector> b_f_ka=f_ka*b; tmp+=b_f_ka; } truncate(world,tmp); // print("size of tmp",tmp.size()); - if (P->get_particle()==0) result.push_back(CCPairFunction(P->get_ket_vector(),tmp)); - if (P->get_particle()==1) result.push_back(CCPairFunction(tmp,P->get_ket_vector())); + if (P->get_particle()==0) result.push_back(CCPairFunction(P->get_ket_vector(),tmp)); + if (P->get_particle()==1) result.push_back(CCPairFunction(tmp,P->get_ket_vector())); // t.print(); - } else if (auto Q=dynamic_cast*>(&projector)) { + } else if (auto Q=dynamic_cast*>(&projector)) { // CCTimer t(world,"Q block"); // Q1 f12 |a_i b_i> = f12 |a_i b_i> - \sum_k |k(1) a_i(2)*f_(kb_i)(2) > result.push_back(pf); // print("entering Q block"); // reuse the projector code above - std::vector tmp=madness::apply(Q->get_P_projector(),std::vector(1,pf)); + std::vector> tmp=madness::apply(Q->get_P_projector(),std::vector>(1,pf)); // for (auto& t : tmp) t.print_size(); for (auto& t : tmp) { t*=-1.0; @@ -609,11 +562,11 @@ std::vector apply(const ProjectorBase& projector, const std::vec // t.print(); } else { - MADNESS_EXCEPTION("CCPairFunction: unknown projector type",1); + MADNESS_EXCEPTION("CCPairFunction: unknown projector type",1); } } else { - MADNESS_EXCEPTION("confused type in CCPairFunction",1); + MADNESS_EXCEPTION("confused type in CCPairFunction",1); } } @@ -621,49 +574,9 @@ std::vector apply(const ProjectorBase& projector, const std::vec return result; }; -/// apply the operator to the argument - -/// the operator is applied to one particle only, the other one is left untouched -/// note the ordering of the particles, cf the corresponding comment in mra.h -/// op.particle==1 : op(f(x,y)) = op(x,x') f(x',y) = result(x,y); -/// op.particle==2 : op(f(x,y)) = op(y,y') f(x,y') = result(y,x); -template -std::vector apply(const SeparatedConvolution& op, const std::vector& argument) { - if (argument.size()==0) return argument; - World& world=argument.front().world(); - std::vector result; - timer t(world); - for (const auto& arg : argument) { - bool convert_to_pure=(arg.has_operator() or arg.is_pure()); - - if (convert_to_pure) { - auto tmp=arg.to_pure().get_function(); - tmp=op(tmp); - - // !! confusing ordering of the result variables!! - if (op.particle()==2) tmp=swap_particles(tmp); - result.push_back(CCPairFunction(tmp)); - - } else if (arg.is_decomposed_no_op()) { - MADNESS_CHECK(op.particle()==1 or op.particle()==2); - if (op.particle()==1) { - auto tmp= madness::apply(world,op,arg.get_a()); - result.push_back(CCPairFunction(tmp,arg.get_b())); - } else if (op.particle()==2) { - auto tmp= madness::apply(world,op,arg.get_b()); - result.push_back(CCPairFunction(tmp,arg.get_a())); - } - - } else { - MADNESS_CHECK_THROW(false,"confused type in apply(CCPairFunction)"); - } -// t.tag("applying op to CCPairFunction "+arg.name()); - } - - return result; -} - -template std::vector apply(const SeparatedConvolution& op, const std::vector& argument); +template class CCPairFunction; +template class CCPairFunction; +template class CCPairFunction; } // namespace madness \ No newline at end of file diff --git a/src/madness/chem/ccpairfunction.h b/src/madness/chem/ccpairfunction.h index 7735387402d..85320c6484b 100644 --- a/src/madness/chem/ccpairfunction.h +++ b/src/madness/chem/ccpairfunction.h @@ -17,6 +17,7 @@ namespace madness { +template struct CCConvolutionOperator; class ProjectorBase; @@ -26,45 +27,65 @@ enum FuncType { UNDEFINED, HOLE, PARTICLE, MIXED, RESPONSE }; /// structure for a CC Function 3D which holds an index and a type // the type is defined by the enum FuncType (definition at the start of this file) +template struct CCFunction : public archive::ParallelSerializableObject { CCFunction() : current_error(99), i(99), type(UNDEFINED) {}; - CCFunction(const real_function_3d& f) : current_error(99), function(f), i(99), type(UNDEFINED) {}; + CCFunction(const Function& f) : current_error(99), function(f), i(99), type(UNDEFINED) {}; - CCFunction(const real_function_3d& f, const size_t& ii) : current_error(99), function(f), i(ii), type(UNDEFINED) {}; + CCFunction(const Function& f, const size_t& ii) : current_error(99), function(f), i(ii), type(UNDEFINED) {}; - CCFunction(const real_function_3d& f, const size_t& ii, const FuncType& type_) : current_error(99), function(f), + CCFunction(const Function& f, const size_t& ii, const FuncType& type_) : current_error(99), function(f), i(ii), type(type_) {}; CCFunction(const CCFunction& other) : current_error(other.current_error), function(other.function), i(other.i), type(other.type) {}; double current_error; - real_function_3d function; + Function function; - real_function_3d get() const { return function; } + Function get() const { return function; } - real_function_3d f() const { return function; } + Function f() const { return function; } - void set(const real_function_3d& other) { function = other; } + void set(const Function& other) { function = other; } size_t i; FuncType type; - void info(World& world, const std::string& msg = " ") const; + void info(World& world, const std::string& msg = " ") const { + if (world.rank() == 0) { + std::cout << "Information about 3D function: " << name() << " " << msg << std::endl; + std::cout << std::setw(10) << std::setfill(' ') << std::setw(50) << " |f| : " << function.norm2() + << std::endl; + std::cout << std::setw(10) << std::setfill(' ') << std::setw(50) << " |error|: " << current_error << std::endl; + } + }; - std::string name() const; + std::string name() const { + if (type == HOLE) { + return "phi" + stringify(i); + } else if (type == PARTICLE) { + return "tau" + stringify(i); + } else if (type == MIXED) { + return "t" + stringify(i); + } else if (type == RESPONSE) { + return "x" + stringify(i); + } else { + return "function" + stringify(i); + } + }; double inner(const CCFunction& f) const { return inner(f.function); } - double inner(const real_function_3d& f) const { + double inner(const Function& f) const { return function.inner(f); } /// scalar multiplication CCFunction operator*(const double& fac) const { - real_function_3d fnew = fac * function; + Function fnew = fac * function; return CCFunction(fnew, i, type); } @@ -92,8 +113,8 @@ class TwoBodyFunctionComponentBase { virtual bool is_pure() const {return false;} virtual bool is_decomposed() const {return false;} virtual bool has_operator() const = 0; - virtual void set_operator(const std::shared_ptr op) = 0; - virtual const std::shared_ptr get_operator_ptr() const = 0; +// virtual void set_operator(const std::shared_ptr op) = 0; +// virtual const std::shared_ptr get_operator_ptr() const = 0; virtual void print_size() const = 0; virtual std::string name(const bool transpose=false) const = 0; virtual World& world() const =0; @@ -102,20 +123,22 @@ class TwoBodyFunctionComponentBase { }; /// a two-body, explicitly 6-dimensional function -template +template class TwoBodyFunctionPureComponent : public TwoBodyFunctionComponentBase { + static constexpr std::size_t LDIM=NDIM/2; + static_assert(NDIM%2==0,"NDIM must be even"); public: TwoBodyFunctionPureComponent() = default; - explicit TwoBodyFunctionPureComponent(const Function& f) : u(f) {} - explicit TwoBodyFunctionPureComponent(const std::shared_ptr op, const Function& f) + explicit TwoBodyFunctionPureComponent(const Function& f) : u(f) {} + explicit TwoBodyFunctionPureComponent(const std::shared_ptr> op, const Function& f) : u(f), op(op) {} /// deep copy std::shared_ptr clone() override { - TwoBodyFunctionPureComponent result(op,madness::copy(u)); - return std::make_shared>(result); + TwoBodyFunctionPureComponent result(op,madness::copy(u)); + return std::make_shared>(result); } template @@ -154,45 +177,48 @@ class TwoBodyFunctionPureComponent : public TwoBodyFunctionComponentBase { /// return f(2,1) void swap_particles_inplace() override { - u=swap_particles(u); + if constexpr (NDIM==6) u=swap_particles(u); + else MADNESS_EXCEPTION("swap_particles_inplace not implemented for NDIM!=6",1); } - const std::shared_ptr get_operator_ptr() const override {return op;}; + const std::shared_ptr> get_operator_ptr() const {return op;}; - void set_operator(const std::shared_ptr op1) override {op=op1;} + void set_operator(const std::shared_ptr> op1) {op=op1;} - real_function_6d& get_function() { + Function& get_function() { return u; } private: /// pure 6D function - real_function_6d u; - std::shared_ptr op; + Function u; + std::shared_ptr> op; }; /// holds two vectors a and b of low-dimensional functions forming a high-dim function by a sum of outer products /// f(1,2) = sum_i |a_i b_i > -template +template class TwoBodyFunctionSeparatedComponent : public TwoBodyFunctionComponentBase { + static constexpr std::size_t LDIM=NDIM/2; + static_assert(NDIM%2==0,"NDIM must be even"); public: TwoBodyFunctionSeparatedComponent() = default; - TwoBodyFunctionSeparatedComponent(const std::vector>& a, - const std::vector>& b) : a(a), b(b), op(nullptr) {}; + TwoBodyFunctionSeparatedComponent(const std::vector>& a, + const std::vector>& b) : a(a), b(b), op(nullptr) {}; - TwoBodyFunctionSeparatedComponent(const std::vector>& a, - const std::vector>& b, - const std::shared_ptr op) : a(a), b(b), op(op) {}; + TwoBodyFunctionSeparatedComponent(const std::vector>& a, + const std::vector>& b, + const std::shared_ptr> op) : a(a), b(b), op(op) {}; TwoBodyFunctionSeparatedComponent(const TwoBodyFunctionSeparatedComponent& other) = default; /// deep copy std::shared_ptr clone() override { - TwoBodyFunctionSeparatedComponent result(madness::copy(world(),a),madness::copy(world(),b),op); - return std::make_shared>(result); + TwoBodyFunctionSeparatedComponent result(madness::copy(world(),a),madness::copy(world(),b),op); + return std::make_shared>(result); } template @@ -229,7 +255,7 @@ class TwoBodyFunctionSeparatedComponent : public TwoBodyFunctionComponentBase { void serialize() {} template - TwoBodyFunctionPureComponent apply(const SeparatedConvolution* op, const int particle=0) { + TwoBodyFunctionPureComponent apply(const SeparatedConvolution* op, const int particle=0) { MADNESS_EXCEPTION("TwoBodyFunctionPureComponent apply not yet implemented",1); } @@ -243,9 +269,9 @@ class TwoBodyFunctionSeparatedComponent : public TwoBodyFunctionComponentBase { return a.size(); } - std::vector> get_a() const {return a;} - std::vector> get_b() const {return b;} - std::vector> get_vector(const int i) const { + std::vector> get_a() const {return a;} + std::vector> get_b() const {return b;} + std::vector> get_vector(const int i) const { MADNESS_CHECK(i==0 or i==1); if (i==0) return a; else if (i==1) return b; @@ -254,15 +280,15 @@ class TwoBodyFunctionSeparatedComponent : public TwoBodyFunctionComponentBase { } } - const std::shared_ptr get_operator_ptr() const override {return op;}; + const std::shared_ptr> get_operator_ptr() const {return op;}; - void set_operator(const std::shared_ptr op1) override {op=op1;} + void set_operator(const std::shared_ptr> op1) {op=op1;} private: - std::vector> a; - std::vector> b; - std::shared_ptr op; + std::vector> a; + std::vector> b; + std::shared_ptr> op; }; @@ -302,10 +328,12 @@ class TwoBodyFunctionSeparatedComponent : public TwoBodyFunctionComponentBase { * - op_decomposed: as above, with an 2-particle function: f(1,2) \sum_i |a_i b_i> * **/ +template struct CCPairFunction { + static constexpr std::size_t LDIM=NDIM/2; + static_assert(NDIM%2==0,"NDIM must be even"); -using T=double; -using pureT=Function; +using pureT=Function; public: @@ -313,47 +341,47 @@ using pureT=Function; CCPairFunction() = default; /// takes a deep copy of the argument function - explicit CCPairFunction(const real_function_6d& ket) { - component.reset(new TwoBodyFunctionPureComponent(copy(ket))); + explicit CCPairFunction(const Function& ket) { + component.reset(new TwoBodyFunctionPureComponent(copy(ket))); } /// takes a deep copy of the argument function - explicit CCPairFunction(const std::shared_ptr op_, const real_function_6d& ket) { - component.reset(new TwoBodyFunctionPureComponent(op_,copy(ket))); + explicit CCPairFunction(const std::shared_ptr> op_, const Function& ket) { + component.reset(new TwoBodyFunctionPureComponent(op_,copy(ket))); } /// takes a deep copy of the argument functions - explicit CCPairFunction(const vector_real_function_3d& f1, const vector_real_function_3d& f2) { + explicit CCPairFunction(const std::vector>& f1, const std::vector>& f2) { World& world=f1.front().world(); - component.reset(new TwoBodyFunctionSeparatedComponent(copy(world,f1),copy(world,f2))); + component.reset(new TwoBodyFunctionSeparatedComponent(copy(world,f1),copy(world,f2))); } /// takes a deep copy of the argument functions - explicit CCPairFunction(const real_function_3d& f1, const real_function_3d& f2) : - CCPairFunction(std::vector({f1}),std::vector({f2})) { + explicit CCPairFunction(const Function& f1, const Function& f2) : + CCPairFunction(std::vector>({f1}),std::vector>({f2})) { } /// takes a deep copy of the argument functions - explicit CCPairFunction(const std::pair& f) : + explicit CCPairFunction(const std::pair>, std::vector>>& f) : CCPairFunction(f.first,f.second) { } /// takes a deep copy of the argument functions - explicit CCPairFunction(const std::shared_ptr op_, const CCFunction& f1, const CCFunction& f2) : - CCPairFunction(op_,std::vector({f1.function}),std::vector({f2.function})) { + explicit CCPairFunction(const std::shared_ptr> op_, const CCFunction& f1, const CCFunction& f2) : + CCPairFunction(op_,std::vector>({f1.function}),std::vector>({f2.function})) { } /// takes a deep copy of the argument functions - explicit CCPairFunction(const std::shared_ptr op_, const std::vector& f1, - const std::vector& f2) { + explicit CCPairFunction(const std::shared_ptr> op_, const std::vector>& f1, + const std::vector>& f2) { World& world=f1.front().world(); - component.reset(new TwoBodyFunctionSeparatedComponent(copy(world,f1),copy(world,f2),op_)); + component.reset(new TwoBodyFunctionSeparatedComponent(copy(world,f1),copy(world,f2),op_)); } /// takes a deep copy of the argument functions - explicit CCPairFunction(const std::shared_ptr op_, const real_function_3d& f1, - const real_function_3d& f2) : CCPairFunction(op_,std::vector({f1}), - std::vector({f2})) { + explicit CCPairFunction(const std::shared_ptr> op_, const Function& f1, + const Function& f2) : CCPairFunction(op_,std::vector>({f1}), + std::vector>({f2})) { }; /// shallow assignment operator @@ -383,12 +411,12 @@ using pureT=Function; return component->world(); } - Function& get_function() { + Function& get_function() { MADNESS_CHECK(component and (component->is_pure())); return pure().get_function(); } - Function& get_function() const { + Function& get_function() const { MADNESS_CHECK(component and (component->is_pure())); return pure().get_function(); } @@ -410,13 +438,13 @@ using pureT=Function; } /// multiplication with a 2-particle function - friend CCPairFunction operator*(const std::shared_ptr op, const CCPairFunction& f) { + friend CCPairFunction operator*(const std::shared_ptr> op, const CCPairFunction& f) { CCPairFunction result=copy(f); return result.multiply_with_op_inplace(op); } /// multiplication with a 2-particle function - friend std::vector operator*(const std::shared_ptr op, + friend std::vector operator*(const std::shared_ptr> op, const std::vector& f) { std::vector result; for (auto& ff : f) { @@ -426,8 +454,8 @@ using pureT=Function; return result; } - friend std::vector multiply(const std::vector& other, const real_function_3d f, - const std::array& v1) { + friend std::vector multiply(const std::vector& other, const Function f, + const std::array& v1) { std::vector result; for (auto& o : other) { double cpu0=cpu_time(); @@ -440,12 +468,12 @@ using pureT=Function; } /// multiplication with a 2-particle function - CCPairFunction operator*(const std::shared_ptr op) { + CCPairFunction operator*(const std::shared_ptr> op) { CCPairFunction result=copy(*this); return result.multiply_with_op_inplace(op); } - CCPairFunction& multiply_with_op_inplace(const std::shared_ptr op); + CCPairFunction& multiply_with_op_inplace(const std::shared_ptr> op); bool has_operator() const {return component->has_operator();} @@ -456,44 +484,54 @@ using pureT=Function; bool is_op_decomposed() const {return component->is_decomposed() and component->has_operator();} bool is_decomposed_no_op() const {return component->is_decomposed() and (not component->has_operator());} - TwoBodyFunctionPureComponent& pure() const { - if (auto ptr=dynamic_cast*>(component.get())) return *ptr; + TwoBodyFunctionPureComponent& pure() const { + if (auto ptr=dynamic_cast*>(component.get())) return *ptr; MADNESS_EXCEPTION("bad cast in TwoBodyFunction",1); } - TwoBodyFunctionSeparatedComponent& decomposed() const { - if (auto ptr=dynamic_cast*>(component.get())) return *ptr; + TwoBodyFunctionSeparatedComponent& decomposed() const { + if (auto ptr=dynamic_cast*>(component.get())) return *ptr; MADNESS_EXCEPTION("bad cast in TwoBodyFunction",1); } - vector_real_function_3d get_a() const { + std::vector> get_a() const { MADNESS_CHECK(component->is_decomposed()); return decomposed().get_a(); } - vector_real_function_3d get_b() const { + std::vector> get_b() const { MADNESS_CHECK(component->is_decomposed()); return decomposed().get_b(); } - std::vector> get_vector(const int i) const { + std::vector> get_vector(const int i) const { MADNESS_CHECK(component->is_decomposed()); return decomposed().get_vector(i); } - const CCConvolutionOperator& get_operator() const { + const CCConvolutionOperator& get_operator() const { MADNESS_CHECK(component and component->has_operator()); - return *(component->get_operator_ptr()); + if (is_pure()) return *(pure().get_operator_ptr()); + if (is_decomposed()) return *(decomposed().get_operator_ptr()); + MADNESS_EXCEPTION("bad cast in TwoBodyFunction",1); + return *(decomposed().get_operator_ptr()); } - const std::shared_ptr get_operator_ptr() const { + const std::shared_ptr> get_operator_ptr() const { MADNESS_CHECK(component); - return component->get_operator_ptr(); + if (is_pure()) return (pure().get_operator_ptr()); + if (is_decomposed()) return (decomposed().get_operator_ptr()); + MADNESS_EXCEPTION("bad cast in TwoBodyFunction",1); +// return component->get_operator_ptr(); } - void reset_operator(const std::shared_ptr op) { + void reset_operator(const std::shared_ptr> op) { MADNESS_CHECK(component); - component->set_operator(op); + if (is_pure()) pure().set_operator(op); + else if (is_decomposed()) decomposed().set_operator(op); + else { + MADNESS_EXCEPTION("bad cast in TwoBodyFunction",1); + } } /// can this be converted to a pure representation (depends on the operator, if present) @@ -527,12 +565,38 @@ using pureT=Function; } /// multiply CCPairFunction with a 3D function of one of the two particles - friend CCPairFunction multiply(const CCPairFunction& other, const real_function_3d& f, const std::array& v1); + friend CCPairFunction multiply(const CCPairFunction& other, const Function& f, + const std::array& v1) { + auto a012=std::array(); + auto a345=std::array(); + for (int i=0; i(other.get_operator_ptr(), f * other.get_a(), copy(world, other.get_b())); + } else { + return CCPairFunction(other.get_operator_ptr(), copy(world, other.get_a()), f * other.get_b()); + } + } else if (other.is_pure()) { + auto tmp=multiply(other.get_function(),f,particle+1); + return CCPairFunction(other.get_operator_ptr(),tmp); + } else { + MADNESS_EXCEPTION("confused CCPairFunction in multiply",1); + } + }; /// @param[in] f: a 3D-CC_function /// @param[in] particle: the particle on which the operation acts /// @param[out] _particle (projection from 6D to 3D) - real_function_3d project_out(const CCFunction& f, const size_t particle) const; + Function project_out(const CCFunction& f, const size_t particle) const; /// result is: _particle @@ -540,8 +604,8 @@ using pureT=Function; /// @param[in] op: a CC_convoltion_operator which is currently either f12 or g12 /// @param[in] particle: the particle on which the operation acts (can be 1 or 2) /// @param[out] the operator is applied and afterwards a convolution with the delta function makes a 3D-function: _particle - real_function_3d - dirac_convolution(const CCFunction& x, const CCConvolutionOperator& op, const size_t particle) const; + Function + dirac_convolution(const CCFunction& x, const CCConvolutionOperator& op, const size_t particle) const; /// @param[out] particles are interchanged, if the function was u(1,2) the result is u(2,1) CCPairFunction swap_particles() const { @@ -551,24 +615,24 @@ using pureT=Function; }; double - make_xy_u(const CCFunction& xx, const CCFunction& yy) const; + make_xy_u(const CCFunction& xx, const CCFunction& yy) const; /// compute the inner product of this and other - double inner_internal(const CCPairFunction& other, const real_function_3d& R2) const; + double inner_internal(const CCPairFunction& other, const Function& R2) const; - friend double inner(const CCPairFunction& a, const CCPairFunction& b, const real_function_3d& R2) { + friend double inner(const CCPairFunction& a, const CCPairFunction& b, const Function& R2) { return a.inner_internal(b,R2); } friend double inner(const CCPairFunction& a, const CCPairFunction& b) { - real_function_3d R2; + Function R2; return a.inner_internal(b,R2); } friend double inner(const std::vector& va, const std::vector& vb, - const real_function_3d R2=real_function_3d()) { + const Function R2=Function()) { double wall0=cpu_time(); -// real_function_3d R2; +// Function R2; double result=0.0; for (auto& a : va) { for (auto& b : vb) { @@ -599,38 +663,43 @@ using pureT=Function; /// @param[in] f: a 3D-CC_function /// @param[in] particle: the particle on which the operation acts /// @param[out] _particle (projection from 6D to 3D) for the case that u=|ab> so _particle = *|b> if particle==1 - real_function_3d project_out_decomposed(const real_function_3d& f, const size_t particle) const; + Function project_out_decomposed(const Function& f, const size_t particle) const; /// @param[in] f: a 3D-CC_function /// @param[in] particle: the particle on which the operation acts /// @param[out] _particle (projection from 6D to 3D) for the case that u=op|xy> so _particle = *|y> if particle==1 - real_function_3d project_out_op_decomposed(const CCFunction& f, const size_t particle) const; + Function project_out_op_decomposed(const CCFunction& f, const size_t particle) const; /// @param[in] x: a 3D-CC_function /// @param[in] op: a CC_convoltion_operator which is currently either f12 or g12 /// @param[in] particle: the particle on which the operation acts (can be 1 or 2) /// @param[out] the operator is applied and afterwards a convolution with the delta function makes a 3D-function: _particle /// in this case u=|ab> and the result is _1 = *|b> for particle==1 - real_function_3d - dirac_convolution_decomposed(const CCFunction& x, const CCConvolutionOperator& op, const size_t particle) const; + Function + dirac_convolution_decomposed(const CCFunction& x, const CCConvolutionOperator& op, const size_t particle) const; /// small helper function that gives back (a,b) or (b,a) depending on the value of particle - const std::pair assign_particles(const size_t particle) const; + const std::pair>, std::vector>> assign_particles(const size_t particle) const; - template - friend CCPairFunction apply(const SeparatedConvolution& G, const CCPairFunction& argument) { + static std::vector> apply(const ProjectorBase& P, const std::vector>& argument); + + /// apply the operator on a CCPairfunction, both with the same dimension + + /// note there is another function, where the operator works only on some dimensions of the CCPairFunction! + /// @return result(x) = \int op(x,x') arg(x') dx': a CCPairfunction with the same dimension as the argument + friend CCPairFunction apply(const SeparatedConvolution& G, const CCPairFunction& argument) { CCPairFunction result; timer t1(argument.world()); if (argument.is_pure()) { result=CCPairFunction(G(argument.get_function())); } else if (argument.is_decomposed_no_op()) { - real_function_6d result1=real_factory_6d(argument.world()).compressed(); + Function result1=real_factory_6d(argument.world()).compressed(); MADNESS_ASSERT(argument.get_a().size() == argument.get_b().size()); MADNESS_CHECK_THROW(G.particle()==-1,"G must be a two-particle operator in apply(CCPairFunction)"); for (size_t k = 0; k < argument.get_a().size(); k++) { - const real_function_6d tmp = G(argument.get_a()[k], argument.get_b()[k]); + const Function tmp = G(argument.get_a()[k], argument.get_b()[k]); result1 += tmp; } result=CCPairFunction(result1); @@ -641,46 +710,123 @@ using pureT=Function; return result; }; - real_function_3d partial_inner(const real_function_3d& f, - const std::array& v1, - const std::array& v2) const; + + Function partial_inner(const Function& f, + const std::array& v1, + const std::array& v2) const; CCPairFunction partial_inner(const CCPairFunction& other, - const std::array& v1, - const std::array& v2) const; + const std::array& v1, + const std::array& v2) const; }; +//template +//std::vector> swap_particles(const std::vector>& argument); + +/// apply the operator to the argument + +/// the operator is applied to one particle only, the other one is left untouched +/// note the ordering of the particles, cf the corresponding comment in mra.h +/// op.particle==1 : op(f(x,y)) = op(x,x') f(x',y) = result(x,y); +/// op.particle==2 : op(f(x,y)) = op(y,y') f(x,y') = result(y,x); +template +CCPairFunction apply(const SeparatedConvolution& op, const CCPairFunction& arg) { + bool convert_to_pure=(arg.has_operator() or arg.is_pure()); + CCPairFunction result; + World& world = arg.world(); + + if (convert_to_pure) { + auto tmp=arg.to_pure().get_function(); + tmp=op(tmp); + + result=(CCPairFunction(tmp)); + // !! confusing ordering of the result variables!! + if (op.particle()==2) result.swap_particles(); + + } else if (arg.is_decomposed_no_op()) { + MADNESS_CHECK(op.particle()==1 or op.particle()==2); + if (op.particle()==1) { + auto tmp= madness::apply(world,op,arg.get_a()); + result=(CCPairFunction(tmp,arg.get_b())); + } else if (op.particle()==2) { + auto tmp= madness::apply(world,op,arg.get_b()); + result=(CCPairFunction(tmp,arg.get_a())); + } + + } else { + MADNESS_CHECK_THROW(false,"confused type in apply(CCPairFunction)"); + } + + return result; +} + +/// apply the operator to the argument + +/// the operator is applied to one particle only, the other one is left untouched +/// note the ordering of the particles, cf the corresponding comment in mra.h +/// op.particle==1 : op(f(x,y)) = op(x,x') f(x',y) = result(x,y); +/// op.particle==2 : op(f(x,y)) = op(y,y') f(x,y') = result(y,x); +template +std::vector> apply(const SeparatedConvolution& op, const std::vector>& argument) { + std::vector> result; + for (const auto& arg : argument) result.push_back(madness::apply(op, arg)); + return result; +} + +template +CCPairFunction apply(const ProjectorBase& projector, const CCPairFunction& argument) { + auto result=madness::apply(projector,std::vector> (1,argument)); + MADNESS_CHECK(result.size()==1); + return result[0]; +} + /// apply the projector on the argument function, potentially yielding a vector of CCPairfunctions as result /// result can be /// Q12 f12 |ij> = (1 - O1) (1 - O2) f12 i(1) j(2) /// = f12 ij - \sum_k k(1) f_ik(2) j(2) - \sum_k k(2) f_ij(1)j(1) /// which is a pure function and a decomposed function -std::vector apply(const ProjectorBase& P, const std::vector& argument); +template +std::vector> apply(const ProjectorBase& projector, const std::vector>& argument) { + return CCPairFunction::apply(projector,argument); +} -/// convenience function -CCPairFunction apply(const ProjectorBase& P, const CCPairFunction& argument); -/// apply the convolution operator on the argument function, potentially yielding a vector of CCPairfunctions as result -template -std::vector apply(const SeparatedConvolution& op, const std::vector& argument); -/// convenience function template -CCPairFunction apply(const SeparatedConvolution& op, const CCPairFunction& argument); +Function::LDIM>inner(const CCPairFunction& c, const Function::LDIM>& f, + const std::tuple v1, const std::tuple v2) { + constexpr std::size_t LDIM=CCPairFunction::LDIM; + auto v11=std::array({std::get<0>(v1),std::get<1>(v1),std::get<2>(v1)}); + auto v22=std::array({std::get<0>(v2),std::get<1>(v2),std::get<2>(v2)}); -std::vector swap_particles(const std::vector& argument); + return c.partial_inner(f,v11,v22); +} -real_function_3d inner(const CCPairFunction& c, const real_function_3d& f, - const std::tuple v1, const std::tuple v2={0,1,2}); +template +CCPairFunction inner(const CCPairFunction& c1, const CCPairFunction& c2, + const std::tuple v1, const std::tuple v2) { + constexpr std::size_t LDIM=CCPairFunction::LDIM; + auto v11=std::array({std::get<0>(v1),std::get<1>(v1),std::get<2>(v1)}); + auto v22=std::array({std::get<0>(v2),std::get<1>(v2),std::get<2>(v2)}); -CCPairFunction inner(const CCPairFunction& c1, const CCPairFunction& c2, - const std::tuple v1, const std::tuple v2); + return c1.partial_inner(c2,v11,v22); +} -std::vector inner(const std::vector& c1, - const std::vector& c2, - const std::tuple v1, const std::tuple v2); +template +std::vector> inner(const std::vector>& c1, + const std::vector>& c2, + const std::tuple v1, const std::tuple v2) { + std::vector> result; + for (const auto& cc1 : c1) { + for (const auto& cc2 : c2) { + print("inner of ",cc1.name(), cc2.name()); + result.push_back(inner(cc1,cc2,v1,v2)); + } + } + return result; +} } // namespace madness diff --git a/src/madness/chem/mp2.cc b/src/madness/chem/mp2.cc index 7521ae607b6..0282c28db52 100644 --- a/src/madness/chem/mp2.cc +++ b/src/madness/chem/mp2.cc @@ -272,7 +272,7 @@ double MP2::mp3() const { print_header2("computing the MP3 correlation energy"); print_header3("prepare the cluster function"); - typedef std::vector ClusterFunction; + typedef std::vector> ClusterFunction; Pairs clusterfunctions; auto R2 = hf->nemo_ptr->ncf->square(); @@ -284,13 +284,13 @@ double MP2::mp3() const { for (int j = i; j < hf->nocc(); ++j) { // pairs(i, j) = make_pair(i, j); // initialize ClusterFunction tmp; - tmp.push_back(CCPairFunction(pairs(i, j).function)); - CCPairFunction ij(hf->nemo(i), hf->nemo(j)); + tmp.push_back(CCPairFunction(pairs(i, j).function)); + CCPairFunction ij(hf->nemo(i), hf->nemo(j)); - CCConvolutionOperator::Parameters cparam; + CCConvolutionOperator::Parameters cparam; cparam.thresh_op *= 0.1; - auto f12 = CCConvolutionOperatorPtr(world, OpType::OT_F12, cparam); - auto vfij = Q12(std::vector({f12 * ij})); + auto f12 = CCConvolutionOperatorPtr(world, OpType::OT_F12, cparam); + auto vfij = Q12(std::vector>({f12 * ij})); for (auto& p: vfij) tmp.push_back(p); clusterfunctions(i, j) = tmp; @@ -322,8 +322,8 @@ double MP2::mp3() const { print_header3("recompute the MP2 energy"); - CCConvolutionOperator::Parameters cparam; - auto g12=CCConvolutionOperatorPtr(world,OpType::OT_G12,cparam); + CCConvolutionOperator::Parameters cparam; + auto g12=CCConvolutionOperatorPtr(world,OpType::OT_G12,cparam); timer t2(world, "recompute MP2"); // recompute MP2 energy @@ -331,7 +331,7 @@ double MP2::mp3() const { for (int i = param.freeze(); i < hf->nocc(); ++i) { for (int j = i; j < hf->nocc(); ++j) { - auto bra=CCPairFunction(hf->nemo(i),hf->nemo(j)); + auto bra=CCPairFunction(hf->nemo(i),hf->nemo(j)); double direct=inner({bra},g12*clusterfunctions(i,j),R2); double exchange=inner({bra},g12*clusterfunctions(j,i),R2); double fac=(i==j) ? 0.5: 1.0; @@ -834,22 +834,22 @@ double MP2::compute_gQf(const int i, const int j, ElectronPair& pair) const { print("gQf old",t1.reset()); CCTimer timer(world,"gQf with ccpairfunction"); - CCConvolutionOperator::Parameters param; - auto f=CCConvolutionOperatorPtr(world,OpType::OT_F12,param); - auto g=CCConvolutionOperatorPtr(world,OpType::OT_G12,param); + CCConvolutionOperator::Parameters param; + auto f=CCConvolutionOperatorPtr(world,OpType::OT_F12,param); + auto g=CCConvolutionOperatorPtr(world,OpType::OT_G12,param); // print("operator constructor",timer.reset()); - CCPairFunction fij(f,ket_i,ket_j); - CCPairFunction gij(g,bra_k,bra_l); + CCPairFunction fij(f,ket_i,ket_j); + CCPairFunction gij(g,bra_k,bra_l); // CCPairFunction ij({psi},{psi}); - std::vector vfij={fij}; - std::vector vgij={gij}; + std::vector> vfij={fij}; + std::vector> vgij={gij}; // std::vector vij={ij}; // print("g/f ij constructor",timer.reset()); // StrongOrthogonalityProjector SO(world); // SO.set_spaces({psi},{psi},{psi},{psi}); - std::vector Qfij=Q12(vfij); + std::vector> Qfij=Q12(vfij); // std::vector Qgij=Q12(vgij); // print("SO application",timer.reset()); diff --git a/src/madness/chem/projector.h b/src/madness/chem/projector.h index 35d039a3295..ce8b5a201cc 100644 --- a/src/madness/chem/projector.h +++ b/src/madness/chem/projector.h @@ -25,10 +25,13 @@ namespace madness { virtual std::string type() const = 0; }; + template struct CCPairFunction; - std::vector apply(const ProjectorBase& P, const std::vector& argument); -/// simple projector class + template + std::vector> apply(const ProjectorBase& P, const std::vector>& argument); + + /// simple projector class /// use this class to project a function or a set of functions on /// another space of function. The projector can handle different sets of @@ -181,7 +184,7 @@ namespace madness { return result; } - real_function_6d operator()(const real_function_6d& f, const size_t particle) const { + Function operator()(const Function& f, const size_t particle) const { return f-O(f,particle); } diff --git a/src/madness/chem/test_ccpairfunction.cc b/src/madness/chem/test_ccpairfunction.cc index 94ed8f7b228..4d1b931c633 100644 --- a/src/madness/chem/test_ccpairfunction.cc +++ b/src/madness/chem/test_ccpairfunction.cc @@ -21,7 +21,7 @@ struct data { real_function_3d f1,f2,f3,f4,f5; real_function_6d f12,f23; - std::shared_ptr f12_op; + std::shared_ptr> f12_op; data() {} data(World& world, CCParameters& parameters) { @@ -105,11 +105,11 @@ struct data { /// p4: pure, corresponds to f23 /// p5: op_pure, corresponds to f23 auto get_ccpairfunctions() const { - CCPairFunction p1(f12); - CCPairFunction p2({f1,f2},{f2,f3}); - CCPairFunction p3(f12_op,{f1,f2},{f2,f3}); - CCPairFunction p4(f23); // two-term, corresponds to p2 - CCPairFunction p5(f12_op,f23); // two-term, corresponds to p2 + CCPairFunction p1(f12); + CCPairFunction p2({f1,f2},{f2,f3}); + CCPairFunction p3(f12_op,{f1,f2},{f2,f3}); + CCPairFunction p4(f23); // two-term, corresponds to p2 + CCPairFunction p5(f12_op,f23); // two-term, corresponds to p2 return std::make_tuple(p1,p2,p3,p4,p5); } @@ -151,20 +151,20 @@ class GaussianPotential : public FunctionFunctorInterface { int test_constructor(World& world, std::shared_ptr ncf, const Molecule& molecule, const CCParameters& parameter) { - test_output t1("CCPairFunction::constructor"); + test_output t1("CCPairFunction::constructor"); real_function_6d f=real_factory_6d(world); auto [f1,f2,f3,f4,f5,ff]=data1.get_functions(); vector_real_function_3d a= zero_functions(world,3); vector_real_function_3d b= zero_functions(world,3); - auto f12=CCConvolutionOperatorPtr(world, OT_F12, parameter); + auto f12=CCConvolutionOperatorPtr(world, OT_F12, parameter); t1.checkpoint(true,"preparation"); - CCPairFunction p1; - CCPairFunction p2(f); - CCPairFunction p3({f1,f2},{f1,f3}); - CCPairFunction p4(f12,{f1,f2},{f2,f3}); + CCPairFunction p1; + CCPairFunction p2(f); + CCPairFunction p3({f1,f2},{f1,f3}); + CCPairFunction p4(f12,{f1,f2},{f2,f3}); t1.checkpoint(true,"construction"); { @@ -197,7 +197,7 @@ int test_constructor(World& world, std::shared_ptr ncf t1.checkpoint(true,"checks on op_decomposed"); { - CCPairFunction tmp; + CCPairFunction tmp; tmp=p2; MADNESS_CHECK(tmp.is_pure()); MADNESS_CHECK(tmp.component==p2.component); @@ -214,7 +214,7 @@ int test_constructor(World& world, std::shared_ptr ncf int test_operator_apply(World& world, std::shared_ptr ncf, const Molecule& molecule, const CCParameters& parameter) { - test_output t1("CCPairFunction::test_operator_apply"); + test_output t1("CCPairFunction::test_operator_apply"); // t1.set_cout_to_terminal(); double exponent=1.0; // corresponds to the exponent of data::f1 and data::ff @@ -236,9 +236,9 @@ int test_operator_apply(World& world, std::shared_ptr real_function_3d b=real_factory_3d(world).functor(Gaussian); auto [f1,f2,f3,f4,f5,ff]=data1.get_functions(); - CCPairFunction c1(a,b); - CCPairFunction c2(f1,f2); -// CCPairFunction ref(op_a,b); + CCPairFunction c1(a,b); + CCPairFunction c2(f1,f2); +// CCPairFunction ref(op_a,b); auto op= CoulombOperator(world,1.e-5,FunctionDefaults<3>::get_thresh()); op.print_timings=false; op.particle()=1; @@ -257,37 +257,37 @@ int test_operator_apply(World& world, std::shared_ptr int test_transformations(World& world, std::shared_ptr ncf, const Molecule& molecule, const CCParameters& parameter) { - test_output t1("CCPairFunction::test_transformations"); + test_output t1("CCPairFunction::test_transformations"); real_function_6d f=real_factory_6d(world); auto [f1,f2,f3,f4,f5,ff]=data1.get_functions(); - auto f12=CCConvolutionOperatorPtr(world, OT_F12, parameter); - auto g12=CCConvolutionOperatorPtr(world, OT_G12, parameter); + auto f12=CCConvolutionOperatorPtr(world, OT_F12, parameter); + auto g12=CCConvolutionOperatorPtr(world, OT_G12, parameter); - CCPairFunction p1(ff); + CCPairFunction p1(ff); t1.checkpoint(p1.is_pure(),"is_pure"); t1.checkpoint(p1.is_pure_no_op(),"is_pure_no_op"); - CCPairFunction p2(f12,ff); + CCPairFunction p2(f12,ff); t1.checkpoint(p2.is_pure(),"is_pure"); t1.checkpoint(p2.is_op_pure(),"is_op_pure"); t1.checkpoint(p2.is_convertible_to_pure_no_op(),"is_convertible_to_pure_no_op"); - CCPairFunction p3=copy(p2); + CCPairFunction p3=copy(p2); p3.convert_to_pure_no_op_inplace(); t1.checkpoint(p2.is_op_pure(),"is_op_pure"); t1.checkpoint(p3.is_pure_no_op(),"is_pure_no_op"); - CCPairFunction p4(g12,ff); + CCPairFunction p4(g12,ff); t1.checkpoint(p4.is_pure(),"is_pure"); t1.checkpoint(p4.is_op_pure(),"is_op_pure"); t1.checkpoint(not p4.is_convertible_to_pure_no_op(),"not is_convertible_to_pure_no_op"); - CCPairFunction p5(f12,f1,f2); + CCPairFunction p5(f12,f1,f2); t1.checkpoint(not p5.is_pure(),"is_pure"); t1.checkpoint(p5.is_op_decomposed(),"is_op_decomposed"); t1.checkpoint(p5.is_convertible_to_pure_no_op(),"is_convertible_to_pure_no_op"); - CCPairFunction p6=copy(p5); + CCPairFunction p6=copy(p5); p6.convert_to_pure_no_op_inplace(); t1.checkpoint(p6.is_pure_no_op(),"is_pure_no_op"); @@ -296,7 +296,7 @@ int test_transformations(World& world, std::shared_ptr int test_multiply_with_f12(World& world, std::shared_ptr ncf, const Molecule& molecule, const CCParameters& parameters) { - test_output t1("CCPairFunction::test_multiply_with_f12"); + test_output t1("CCPairFunction::test_multiply_with_f12"); // p1: pure, corresponds to f12 // p2: dec, corresponds to f23 @@ -309,8 +309,8 @@ int test_multiply_with_f12(World& world, std::shared_ptr::get_thresh(); // decomposed - CCPairFunction tmp1=f12*p2; // should now be identical to p3 - CCPairFunction tmp2=p2*f12; // should now be identical to p3 + CCPairFunction tmp1=f12*p2; // should now be identical to p3 + CCPairFunction tmp2=p2*f12; // should now be identical to p3 double ref=inner(p2,p3); double r1=inner(p2,tmp1); @@ -338,18 +338,18 @@ int test_multiply_with_f12(World& world, std::shared_ptr ncf, const Molecule& molecule, const CCParameters& parameters) { - test_output t1("CCPairFunction::test_multiply"); + test_output t1("CCPairFunction::test_multiply"); - // consistency check, relies on CCPairFunction::inner to work correctly + // consistency check, relies on CCPairFunction::inner to work correctly double thresh=FunctionDefaults<3>::get_thresh(); auto [p1,p2,p3,p4,p5]=data1.get_ccpairfunctions(); // p2-p5 correspond to f23 auto [f1,f2,f3,f4,f5,f]=data1.get_functions(); // reference value is = - CCPairFunction bra(f1,f2); - CCPairFunction bra1(f1*f2,f2); - CCPairFunction bra2(f1,f2*f2); + CCPairFunction bra(f1,f2); + CCPairFunction bra1(f1*f2,f2); + CCPairFunction bra2(f1,f2*f2); for (auto& p : {p2,p3,p4,p5}) { auto tmp1=multiply(p,f2,{0,1,2}); @@ -371,7 +371,7 @@ int test_multiply(World& world, std::shared_ptr ncf, c } int test_inner(World& world, std::shared_ptr ncf, const Molecule& molecule, const CCParameters& parameters) { - test_output t1("CCPairFunction::test_inner"); + test_output t1("CCPairFunction::test_inner"); t1.set_cout_to_terminal(); /// f1: exp(-1.0 r^2) @@ -451,18 +451,18 @@ int test_partial_inner_6d(World& world, std::shared_ptr::test_partial_inner_6d"); t1.set_cout_to_terminal(); auto [f1,f2,f3,f4,f5,f] = data1.get_functions(); std::vector a = {f1, f2}; std::vector b = {f2, f3}; - auto f12=CCConvolutionOperatorPtr(world, OT_F12, parameter); + auto f12=CCConvolutionOperatorPtr(world, OT_F12, parameter); auto [p1,p2,p3,p4,nil]=data1.get_ccpairfunctions(); - CCPairFunction p11({f1},{f1}); - CCPairFunction p12({f1},{f2}); + CCPairFunction p11({f1},{f1}); + CCPairFunction p12({f1},{f2}); double g11=inner(f1,f1); double g22=inner(f2,f2); @@ -483,10 +483,10 @@ int test_partial_inner_6d(World& world, std::shared_ptr r1=inner(test_p1,test_p2,{0,1,2},{0,1,2}); + CCPairFunction r2=inner(test_p1,test_p2,{0,1,2},{3,4,5}); + CCPairFunction r3=inner(test_p1,test_p2,{3,4,5},{0,1,2}); + CCPairFunction r4=inner(test_p1,test_p2,{3,4,5},{3,4,5}); double n1=inner(r1,p11); double n2=inner(r2,p11); @@ -511,14 +511,14 @@ int test_partial_inner_6d(World& world, std::shared_ptr - // CCPairFunction p2({f1,f2},{f2,f3}); - // CCPairFunction p4(f23); // two-term, corresponds to p2 - CCPairFunction p5(f12,std::vector({f1}),std::vector({f2})); + // CCPairFunction p2({f1,f2},{f2,f3}); + // CCPairFunction p4(f23); // two-term, corresponds to p2 + CCPairFunction p5(f12,std::vector({f1}),std::vector({f2})); for (auto& test_p1 : {p2, p4}) { - CCPairFunction r1=inner(test_p1,p5,{0,1,2},{0,1,2}); - CCPairFunction r2=inner(test_p1,p5,{0,1,2},{3,4,5}); - CCPairFunction r3=inner(test_p1,p5,{3,4,5},{0,1,2}); - CCPairFunction r4=inner(test_p1,p5,{3,4,5},{3,4,5}); + CCPairFunction r1=inner(test_p1,p5,{0,1,2},{0,1,2}); + CCPairFunction r2=inner(test_p1,p5,{0,1,2},{3,4,5}); + CCPairFunction r3=inner(test_p1,p5,{3,4,5},{0,1,2}); + CCPairFunction r4=inner(test_p1,p5,{3,4,5},{3,4,5}); double ref_n1=inner(gf11,f2*f1) * g12 + inner(gf12,f1*f2) * g13; double ref_n2=inner(gf12,f1*f1) * g12 + inner(gf22,f1*f1) * g13; @@ -546,25 +546,25 @@ int test_partial_inner_6d(World& world, std::shared_ptr - // CCPairFunction p3(f12_op.get(),{f1,f2},{f2,f3}); - // CCPairFunction p5(&f12,{f1},{f2}); + // CCPairFunction p3(f12_op.get(),{f1,f2},{f2,f3}); + // CCPairFunction p5(&f12,{f1},{f2}); if (longtest) { - CCPairFunction r1=inner(p3,p5,{0,1,2},{0,1,2}); + CCPairFunction r1=inner(p3,p5,{0,1,2},{0,1,2}); print("time after r1 ", timer.reset()); double n1=inner(r1,p11); p3.convert_to_pure_no_op_inplace(); p5.convert_to_pure_no_op_inplace(); print("n1",n1); print("time after r2a ", timer.reset()); - CCPairFunction r1a=inner(p3,p5,{0,1,2},{0,1,2}); + CCPairFunction r1a=inner(p3,p5,{0,1,2},{0,1,2}); double n1a=inner(r1a,p11); print("n1a",n1a); print("diff",n1-n1a); - CCPairFunction r2=inner(p3,p5,{0,1,2},{3,4,5}); + CCPairFunction r2=inner(p3,p5,{0,1,2},{3,4,5}); print("time after r2 ", timer.reset()); - CCPairFunction r3=inner(p3,p5,{3,4,5},{0,1,2}); + CCPairFunction r3=inner(p3,p5,{3,4,5},{0,1,2}); print("time after r3 ", timer.reset()); - CCPairFunction r4=inner(p3,p5,{3,4,5},{3,4,5}); + CCPairFunction r4=inner(p3,p5,{3,4,5},{3,4,5}); print("time after r4 ", timer.reset()); } @@ -576,19 +576,19 @@ int test_partial_inner_3d(World& world, std::shared_ptr::test_partial_inner"); auto [f1,f2,f3,f4,f5,f] = data1.get_functions(); std::vector a = {f1, f2}; std::vector b = {f2, f3}; - auto f12=CCConvolutionOperatorPtr(world, OT_F12, parameter); + auto f12=CCConvolutionOperatorPtr(world, OT_F12, parameter); - CCPairFunction p1(f); // e(-r1 - 2r2) - CCPairFunction p2(a,b); - CCPairFunction p3(f12,a,b); - CCPairFunction p11({f1},{f1}); - CCPairFunction p12({f1},{f2}); + CCPairFunction p1(f); // e(-r1 - 2r2) + CCPairFunction p2(a,b); + CCPairFunction p3(f12,a,b); + CCPairFunction p11({f1},{f1}); + CCPairFunction p12({f1},{f2}); double g11=inner(f1,f1); double g22=inner(f2,f2); @@ -679,16 +679,16 @@ int test_apply(World& world, std::shared_ptr ncf, cons auto [p1,p2,p3,p4,p5]=data1.get_ccpairfunctions(); auto [f1,f2,f3,f4,f5,f]=data1.get_functions(); - auto f12=CCConvolutionOperatorPtr(world, OT_F12, parameter); + auto f12=CCConvolutionOperatorPtr(world, OT_F12, parameter); auto& op=*(f12->get_op()); - std::vector vp2({p2}); - std::vector vp2ex({p2.swap_particles()}); + std::vector> vp2({p2}); + std::vector> vp2ex({p2.swap_particles()}); // tmp(2) = \int a(1)b(2') f(1,2) d1 // result=inner(tmp,f1); for (auto& p : {p1,p2,p3,p4,p5}) { print("working on ",p.name()); - std::vector vp({p}); + std::vector> vp({p}); op.set_particle(1); auto op1_p=op(vp); double r1=inner(vp2,op1_p); @@ -712,7 +712,7 @@ int test_apply(World& world, std::shared_ptr ncf, cons int test_scalar_multiplication(World& world, std::shared_ptr ncf, const Molecule& molecule, const CCParameters& parameter) { CCTimer timer(world, "testing"); - test_output t1("CCPairFunction::test_scalar_multiplication"); + test_output t1("CCPairFunction::test_scalar_multiplication"); auto [f1,f2,f3,f4,f5,f] = data1.get_functions(); @@ -722,8 +722,8 @@ int test_scalar_multiplication(World& world, std::shared_ptr p(f); + CCPairFunction p1(a,b); double norm1=inner(p,p1); double pnorm=inner(p,p); double p1norm=inner(p1,p1); @@ -753,7 +753,7 @@ int test_scalar_multiplication(World& world, std::shared_ptr ncf, const Molecule& molecule, const CCParameters& parameters) { - test_output t1("CCPairFunction::swap_particles"); + test_output t1("CCPairFunction::swap_particles"); CCTimer timer(world, "testing swap_particles"); // prepare @@ -766,8 +766,8 @@ int test_swap_particles(World& world, std::shared_ptr // test decomposed { - CCPairFunction p1(a, b); - CCPairFunction p2(b, a); + CCPairFunction p1(a, b); + CCPairFunction p2(b, a); double norm1 = inner(p1, p2.swap_particles(), R2); double norm1a = inner(p1, p1, R2); @@ -781,14 +781,14 @@ int test_swap_particles(World& world, std::shared_ptr // test pure { - CCPairFunction p(f); - CCPairFunction p_swapped=p.swap_particles(); + CCPairFunction p(f); + CCPairFunction p_swapped=p.swap_particles(); double pnorm=p.get_function().norm2(); double psnorm=p_swapped.get_function().norm2(); print("p/s norm",pnorm,psnorm); - CCPairFunction p1({f1}, {f2}); - CCPairFunction p2({f2}, {f1}); + CCPairFunction p1({f1}, {f2}); + CCPairFunction p2({f2}, {f1}); double ref1=inner(f1,f1)*inner(f2,f2); double ref2=inner(f1,f2)*inner(f2,f1); print("ref1/2",ref1,ref2); @@ -827,7 +827,7 @@ int test_swap_particles(World& world, std::shared_ptr int test_projector(World& world, std::shared_ptr ncf, const Molecule& molecule, const CCParameters& parameter) { - test_output t1("CCPairFunction::test_projector"); + test_output t1("CCPairFunction::test_projector"); CCTimer timer(world, "testing"); // t1.set_cout_to_logger(); @@ -841,7 +841,7 @@ int test_projector(World& world, std::shared_ptr ncf, std::vector b = {f3, f1, f2}; std::vector o = orthonormalize_cd({f1-f3, f5}); // projects on an orthonormal basis a = orthonormalize_cd(a); // projects on an orthonormal basis - auto f12=CCConvolutionOperatorPtr(world, OT_F12, parameter); + auto f12=CCConvolutionOperatorPtr(world, OT_F12, parameter); { double n1=inner(f1,o[0]); @@ -850,13 +850,13 @@ int test_projector(World& world, std::shared_ptr ncf, print("", ovlp); } - CCPairFunction p1(a,b); - CCPairFunction p2(f12,a,b); - CCPairFunction p3(f); // outer (f1,f2) + CCPairFunction p1(a,b); + CCPairFunction p2(f12,a,b); + CCPairFunction p3(f); // outer (f1,f2) - std::vector vp1({p1}); - std::vector vp2({p2}); - std::vector vp3({p3}); + std::vector> vp1({p1}); + std::vector> vp2({p2}); + std::vector> vp3({p3}); Projector O(o,o); QProjector Q(world,o,o); @@ -871,35 +871,35 @@ int test_projector(World& world, std::shared_ptr ncf, real_function_3d of2=O(f2); real_function_3d qf1=Q(f1); real_function_3d qf2=Q(f2); - std::vector> vp({vp1,vp2,vp3}); + std::vector>> vp({vp1,vp2,vp3}); for (int i=0; i<3; ++i) { // O1 O.set_particle(0); { - double ref=inner({CCPairFunction({of1},{f2})},vp[i]); - double result=inner({CCPairFunction({f1},{f2})},O(vp[i])); + double ref=inner({CCPairFunction({of1},{f2})},vp[i]); + double result=inner({CCPairFunction({f1},{f2})},O(vp[i])); t1.checkpoint(result,ref,thresh,"O1 p"+std::to_string(i)); } // O2 O.set_particle(1); { - double ref=inner({CCPairFunction({f1},{of2})},vp[i]); - double result=inner({CCPairFunction({f1},{f2})},O(vp[i])); + double ref=inner({CCPairFunction({f1},{of2})},vp[i]); + double result=inner({CCPairFunction({f1},{f2})},O(vp[i])); t1.checkpoint(result,ref,thresh,"O2 p"+std::to_string(i)); } // Q1 Q.set_particle(0); { - double ref=inner({CCPairFunction({qf1},{f2})},vp[i]); - double result=inner({CCPairFunction({f1},{f2})},Q(vp[i])); + double ref=inner({CCPairFunction({qf1},{f2})},vp[i]); + double result=inner({CCPairFunction({f1},{f2})},Q(vp[i])); t1.checkpoint(result,ref,thresh,"Q1 p"+std::to_string(i)); } // Q2 Q.set_particle(1); { - double ref=inner({CCPairFunction({f1},{qf2})},vp[i]); - double result=inner({CCPairFunction({f1},{f2})},Q(vp[i])); + double ref=inner({CCPairFunction({f1},{qf2})},vp[i]); + double result=inner({CCPairFunction({f1},{f2})},Q(vp[i])); t1.checkpoint(result,ref,thresh,"Q2 p"+std::to_string(i)); } } @@ -929,12 +929,12 @@ int test_projector(World& world, std::shared_ptr ncf, timer.reset(); - // test {O,Q} with particles 1,2 on all three CCPairFunction types + // test {O,Q} with particles 1,2 on all three CCPairFunction types { int i=0; for (auto p : {p1,p2,p3}) { - std::string s="CCPairFunction p"+std::to_string(++i); - std::vector vp({p}); + std::string s="CCPairFunction p"+std::to_string(++i); + std::vector> vp({p}); for (int particle : {0,1}) { O.set_particle(particle); Q.set_particle(particle); @@ -981,7 +981,7 @@ int test_projector(World& world, std::shared_ptr ncf, int test_dirac_convolution(World& world, std::shared_ptr ncf, const Molecule& molecule, const CCParameters& parameter) { - test_output t1("CCPairFunction::test_dirac_convolution"); + test_output t1("CCPairFunction::test_dirac_convolution"); return (t1.get_final_success()) ? 0 : 1; } @@ -990,7 +990,7 @@ int test_dirac_convolution(World& world, std::shared_ptr ncf, const Molecule& molecule, const CCParameters& parameters) { - test_output t1("CCPairFunction::test_helium"); + test_output t1("CCPairFunction::test_helium"); CCTimer timer(world, "testing"); real_function_3d Vnuc = real_factory_3d(world).f([](const coord_3d& r) {return -2.0/(r.normf()+1.e-8);}); @@ -1035,21 +1035,21 @@ int test_helium(World& world, std::shared_ptr ncf, con print("ke, total", kinetic_energy, total_energy); - CCConvolutionOperator::Parameters param; - auto f=CCConvolutionOperatorPtr(world,OT_F12,param); - auto g=CCConvolutionOperatorPtr(world,OT_G12,param); + CCConvolutionOperator::Parameters param; + auto f=CCConvolutionOperatorPtr(world,OT_F12,param); + auto g=CCConvolutionOperatorPtr(world,OT_G12,param); - CCPairFunction fij(f,psi,psi); - CCPairFunction gij(g,psi,psi); - CCPairFunction ij({psi},{psi}); - std::vector vfij={fij}; - std::vector vgij={gij}; - std::vector vij={ij}; + CCPairFunction fij(f,psi,psi); + CCPairFunction gij(g,psi,psi); + CCPairFunction ij({psi},{psi}); + std::vector> vfij={fij}; + std::vector> vgij={gij}; + std::vector> vij={ij}; StrongOrthogonalityProjector SO(world); SO.set_spaces({psi},{psi},{psi},{psi}); - std::vector Qfij=SO(vfij); - std::vector Qgij=SO(vgij); + std::vector> Qfij=SO(vfij); + std::vector> Qgij=SO(vgij); double result1=inner(vgij,Qfij); print(")",result1); diff --git a/src/madness/mra/function_factory.h b/src/madness/mra/function_factory.h index b0e3e5d6589..61c16b8d72a 100644 --- a/src/madness/mra/function_factory.h +++ b/src/madness/mra/function_factory.h @@ -432,20 +432,23 @@ class CompositeFactory : public FunctionFactory { }; /// factory for generating TwoElectronInterfaces -class TwoElectronFactory : public FunctionFactory { +template +class TwoElectronFactory : public FunctionFactory { protected: - typedef std::shared_ptr > InterfacePtr; + typedef std::shared_ptr > InterfacePtr; public: TwoElectronFactory(World& world) - : FunctionFactory(world), interface_(), bc_(FunctionDefaults<6>::get_bc()) { - _tree_state = on_demand; + : FunctionFactory(world), interface_(), bc_(FunctionDefaults::get_bc()) { + this->_tree_state = on_demand; info.mu=-1.0; info.type=OT_G12; - info.thresh=FunctionDefaults<3>::get_thresh(); - this->_thresh = (FunctionDefaults<3>::get_thresh()); - this->_k = (FunctionDefaults<3>::get_k()); + constexpr std::size_t LDIM=NDIM/2; + static_assert(NDIM==2*LDIM, "NDIM must be even"); + info.thresh=FunctionDefaults::get_thresh(); + this->_thresh = (FunctionDefaults::get_thresh()); + this->_k = (FunctionDefaults::get_k()); } @@ -457,7 +460,7 @@ class TwoElectronFactory : public FunctionFactory { /// the requested precision TwoElectronFactory& thresh(double thresh) { - _thresh=thresh; + this->_thresh=thresh; info.thresh = thresh; return self(); } @@ -499,7 +502,7 @@ class TwoElectronFactory : public FunctionFactory { if (this->interface_) return this->interface_; const_cast(this->interface_) = - InterfacePtr(new GeneralTwoElectronInterface(info)); + InterfacePtr(new GeneralTwoElectronInterface(info)); // // construction of the functor is const in spirit, but non-const in sad reality.. // if (info.type==OT_G12) { @@ -538,7 +541,7 @@ class TwoElectronFactory : public FunctionFactory { // double gamma_; - BoundaryConditions<6> bc_; + BoundaryConditions bc_; }; diff --git a/src/madness/mra/function_interface.h b/src/madness/mra/function_interface.h index 8b9bedd2723..d6b7d414c96 100644 --- a/src/madness/mra/function_interface.h +++ b/src/madness/mra/function_interface.h @@ -322,6 +322,8 @@ namespace madness { /// functions is imprecise and slow. template class TwoElectronInterface : public FunctionFunctorInterface { + protected: + static constexpr std::size_t LDIM=NDIM/2; public: typedef GenTensor coeffT; @@ -331,14 +333,14 @@ namespace madness { /// @param[in] lo the smallest length scale to be resolved /// @param[in] eps the accuracy threshold TwoElectronInterface(double lo, double eps, - const BoundaryConditions<6>& bc=FunctionDefaults<6>::get_bc(), - int kk=FunctionDefaults<6>::get_k()) + const BoundaryConditions& bc=FunctionDefaults::get_bc(), + int kk=FunctionDefaults::get_k()) :rank(), k(kk), lo(lo), hi(1.0) { // Presently we must have periodic or non-periodic in all dimensions. for (std::size_t d=1; d<6; ++d) {MADNESS_ASSERT(bc(d,0)==bc(0,0));} - const Tensor& width = FunctionDefaults<6>::get_cell_width(); + const Tensor& width = FunctionDefaults::get_cell_width(); hi = width.normf(); // Diagonal width of cell if (bc(0,0) == BC_PERIODIC) hi *= 100; // Extend range for periodic summation @@ -351,7 +353,7 @@ namespace madness { /// return the coefficients of the function in 6D (x1,y1,z1, x2,y2,z2) coeffT coeff(const Key& key) const { Tensor c=make_coeff(key); - return coeffT(map_coeff(c),FunctionDefaults<6>::get_thresh(),TT_FULL); + return coeffT(map_coeff(c),FunctionDefaults::get_thresh(),TT_FULL); } T operator()(const Vector& x) const { @@ -363,45 +365,77 @@ namespace madness { protected: /// make the coefficients from the 1d convolution - Tensor make_coeff(const Key<6>& key) const { + Tensor make_coeff(const Key& key) const { const Level n=key.level(); - const Vector l=key.translation(); + const Vector l=key.translation(); // get the displacements for all 3 dimensions: x12, y12, z12 - const Translation l0=(l[0]-l[3]); - const Translation l1=(l[1]-l[4]); - const Translation l2=(l[2]-l[5]); + Translation l0, l1, l2; + if (NDIM==2) { + l0=l[0]-l[1]; + } else if (NDIM==4) { + l0=(l[0]-l[2]); + l1=(l[1]-l[3]); + } else if (NDIM==6) { + l0=(l[0]-l[3]); + l1=(l[1]-l[4]); + l2=(l[2]-l[5]); + } else { + MADNESS_EXCEPTION("TwoElectronInterface: NDIM must be 2, 4, or 6",1); + } - Tensor scr1(rank,k*k), scr2(rank,k*k,k*k); + Tensor scr1(rank,k*k), scr2(rank,k*k,k*k), scr3(rank,k*k); // lump all the terms together for (long mu=0; mu r0=(ops[mu].getop(0)->rnlij(n,l0)).reshape(k*k); - const Tensor r1=(ops[mu].getop(1)->rnlij(n,l1)).reshape(k*k); - const Tensor r2=(ops[mu].getop(2)->rnlij(n,l2)).reshape(k*k); + Tensor r0, r1, r2; + if (NDIM>=2) r0=(ops[mu].getop(0)->rnlij(n,l0)).reshape(k*k); + if (NDIM>=4) r1=(ops[mu].getop(1)->rnlij(n,l1)).reshape(k*k); + if (NDIM>=6) r2=(ops[mu].getop(2)->rnlij(n,l2)).reshape(k*k); // include weights in first vector scr1(mu,Slice(_))=r0*ops[mu].getfac(); - // merge second and third vector to scr(r,k1,k2) - scr2(mu,Slice(_),Slice(_))=outer(r1,r2); + if (NDIM==4) { + scr3(mu,Slice(_))=r1; + } else if (NDIM==6) { + // merge second and third vector to scr(r,k1,k2) + scr2(mu,Slice(_),Slice(_))=outer(r1,r2); + } else { + MADNESS_EXCEPTION("TwoElectronInterface: NDIM must be 2, 4, or 6",1); + } } - Tensor c=inner(scr1,scr2,0,0); - return c; + if (NDIM==2) return scr1; + else if (NDIM==4) return inner(scr1,scr3,0,0); + else if (NDIM==6) return inner(scr1,scr2,0,0); + else { + MADNESS_EXCEPTION("TwoElectronInterface: NDIM must be 2, 4, or 6",1); + return Tensor(); + } } /// the dimensions are a bit confused (x1,x2, y1,y2, z1,z2) -> (x1,y1,z1, x2,y2,z2) Tensor map_coeff(const Tensor& c) const { - std::vector map(6); - map[0]=0; map[1]=3; map[2]=1; - map[3]=4; map[4]=2; map[5]=5; - return copy(c.reshape(k,k,k,k,k,k).mapdim(map)); + std::vector map(NDIM); + if (NDIM==2) { + map[0]=0; map[1]=1; + return copy(c); + } else if (NDIM==4) { + map[0]=0; map[1]=2; + map[2]=1; map[3]=3; + return copy(c.reshape(k,k,k,k).mapdim(map)); + } else if (NDIM==6) { + map[0]=0; map[1]=3; map[2]=1; + map[3]=4; map[4]=2; map[5]=5; + return copy(c.reshape(k,k,k,k,k,k).mapdim(map)); + } + return Tensor(); } /// initialize the Gaussian fit; uses the virtual function fit() to fit void initialize(const double eps) { - GFit fit=this->fit(eps); + GFit fit=this->fit(eps); Tensor coeff=fit.coeffs(); Tensor expnt=fit.exponents(); @@ -420,17 +454,17 @@ namespace madness { ops[mu].setfac(coeff(mu)/c); // only 3 dimensions here! - for (std::size_t d=0; d<3; ++d) { + for (std::size_t d=0; d::get(k, expnt(mu)*width[d]*width[d], 0, false)); } } } /// derived classes must implement this -- cf GFit.h - virtual GFit fit(const double eps) const = 0; + virtual GFit fit(const double eps) const = 0; /// storing the coefficients - mutable std::vector< ConvolutionND > ops; + mutable std::vector< ConvolutionND > ops; /// the number of terms in the Gaussian quadrature int rank; @@ -448,7 +482,8 @@ namespace madness { /// a function like f(x)=1/x - class GeneralTwoElectronInterface : public TwoElectronInterface { + template + class GeneralTwoElectronInterface : public TwoElectronInterface { public: /// constructor: cf the Coulomb kernel @@ -456,28 +491,31 @@ namespace madness { /// @param[in] lo the smallest length scale to be resolved /// @param[in] eps the accuracy threshold GeneralTwoElectronInterface(OperatorInfo info, - const BoundaryConditions<6>& bc=FunctionDefaults<6>::get_bc(), - int kk=FunctionDefaults<6>::get_k()) - : TwoElectronInterface(info.lo,info.thresh,bc,kk), info(info) { + const BoundaryConditions& bc=FunctionDefaults::get_bc(), + int kk=FunctionDefaults::get_k()) + : TwoElectronInterface(info.lo,info.thresh,bc,kk), info(info) { if (info.hi<0) { - double hi=FunctionDefaults<3>::get_cell_width().normf(); + double hi=FunctionDefaults::get_cell_width().normf(); if (bc(0,0) == BC_PERIODIC) hi *= 100; // Extend range for periodic summation this->info.hi=hi; } - initialize(info.thresh); + this->initialize(info.thresh); } private: OperatorInfo info; + static constexpr std::size_t LDIM=NDIM/2; - GFit fit(const double eps) const { - return GFit(info); + GFit fit(const double eps) const { + return GFit(info); } }; /// a function like f(x)=1/x - class ElectronRepulsionInterface : public TwoElectronInterface { + template + class ElectronRepulsionInterface : public TwoElectronInterface { + public: /// constructor: cf the Coulomb kernel @@ -485,17 +523,18 @@ namespace madness { /// @param[in] lo the smallest length scale to be resolved /// @param[in] eps the accuracy threshold ElectronRepulsionInterface(double lo,double eps, - const BoundaryConditions<6>& bc=FunctionDefaults<6>::get_bc(), - int kk=FunctionDefaults<6>::get_k()) - : TwoElectronInterface(lo,eps,bc,kk) { + const BoundaryConditions& bc=FunctionDefaults::get_bc(), + int kk=FunctionDefaults::get_k()) + : TwoElectronInterface(lo,eps,bc,kk) { - initialize(eps); + this->initialize(eps); } private: + static constexpr std::size_t LDIM=NDIM/2; - GFit fit(const double eps) const { - return GFit::CoulombFit(lo,hi,eps,false); + GFit fit(const double eps) const { + return GFit::CoulombFit(this->lo,this->hi,eps,false); } }; diff --git a/src/madness/mra/mra.h b/src/madness/mra/mra.h index 2aaac174f08..5efa69a71d3 100644 --- a/src/madness/mra/mra.h +++ b/src/madness/mra/mra.h @@ -1422,8 +1422,9 @@ namespace madness { return result; } - template - Function dirac_convolution(const bool fence=true) const { + Function dirac_convolution(const bool fence=true) const { + constexpr std::size_t LDIM=NDIM/2; + MADNESS_CHECK_THROW(NDIM==2*LDIM,"NDIM must be even"); // // this will be the result function FunctionFactory factory=FunctionFactory(world()).k(this->k()); Function f = factory; diff --git a/src/madness/mra/operator.h b/src/madness/mra/operator.h index 1c164d31a33..f88b354a75e 100644 --- a/src/madness/mra/operator.h +++ b/src/madness/mra/operator.h @@ -56,17 +56,24 @@ namespace madness { template class SeparatedConvolution; - class CCPairFunction; template - std::vector apply(const SeparatedConvolution& op, const std::vector& argument); + class CCPairFunction; template std::vector< Function > apply(const SeparatedConvolution& op, const std::vector< Function > f); + template + std::vector> apply(const SeparatedConvolution& op, const std::vector>& argument); + + template + std::vector> apply(const SeparatedConvolution& op, const std::vector>& argument); + + template + CCPairFunction apply(const SeparatedConvolution& op, const CCPairFunction& argument); - template - CCPairFunction apply(const SeparatedConvolution& op, const CCPairFunction& argument); + template + CCPairFunction apply(const SeparatedConvolution& op, const CCPairFunction& argument); /// SeparatedConvolutionInternal keeps data for 1 term and all dimensions and 1 displacement /// Why is this here?? Why don't you just use ConvolutionND in SeparatedConvolutionData?? From 603a6ecaad264fdbff5c100355ba233ccf5502ec Mon Sep 17 00:00:00 2001 From: fbischoff Date: Thu, 25 Jan 2024 15:21:58 +0100 Subject: [PATCH 079/109] making ccpairfunction.cc tests work again with templates --- src/madness/chem/ccpairfunction.cc | 2 + src/madness/chem/ccpairfunction.h | 5 +- src/madness/chem/projector.h | 4 +- src/madness/chem/test_ccpairfunction.cc | 454 ++++++++++++++---------- src/madness/mra/function_interface.h | 49 +-- src/madness/mra/mra.h | 28 +- src/madness/mra/operator.h | 23 +- src/madness/mra/vmra.h | 49 ++- 8 files changed, 382 insertions(+), 232 deletions(-) diff --git a/src/madness/chem/ccpairfunction.cc b/src/madness/chem/ccpairfunction.cc index e785c2c3fe1..8140a4eb578 100644 --- a/src/madness/chem/ccpairfunction.cc +++ b/src/madness/chem/ccpairfunction.cc @@ -172,6 +172,8 @@ CCPairFunction CCPairFunction::partial_inner(const CCPairFunctio } else if (other.is_decomposed_no_op()) { // \int \sum_i f(1,2) a_i(1) b_i(3) d1 = \sum_i b_i(3) \int a_i(1) f(1,2) d1 std::vector> tmp; + auto avec=other.get_vector(integration_index(v2)); + change_tree_state(avec,redundant); for (auto& a : other.get_vector(integration_index(v2))) { // tmp.push_back(innerXX<3>(this->get_function(),a,v1,a012)); // a012 is correct, referring to 3D function tmp.push_back(this->get_function().project_out(a,integration_index(v1))); diff --git a/src/madness/chem/ccpairfunction.h b/src/madness/chem/ccpairfunction.h index 85320c6484b..75003abcd35 100644 --- a/src/madness/chem/ccpairfunction.h +++ b/src/madness/chem/ccpairfunction.h @@ -177,8 +177,7 @@ class TwoBodyFunctionPureComponent : public TwoBodyFunctionComponentBase { /// return f(2,1) void swap_particles_inplace() override { - if constexpr (NDIM==6) u=swap_particles(u); - else MADNESS_EXCEPTION("swap_particles_inplace not implemented for NDIM!=6",1); + u=swap_particles(u); } const std::shared_ptr> get_operator_ptr() const {return op;}; @@ -641,7 +640,7 @@ using pureT=Function; std::size_t bufsize=256; char buf[bufsize]; snprintf(buf,bufsize,"result from inner %10s %10s %12.8f %4.1fs",a.name(true).c_str(),b.name().c_str(),tmp,wall1-wall0); -// print(std::string(buf)); + print(std::string(buf)); wall0=wall1; result+=tmp; } diff --git a/src/madness/chem/projector.h b/src/madness/chem/projector.h index ce8b5a201cc..488bf7767f6 100644 --- a/src/madness/chem/projector.h +++ b/src/madness/chem/projector.h @@ -116,10 +116,10 @@ namespace madness { operator()(const Function& f, size_t particle1=-1) const { Function result = FunctionFactory(f.world()); if (particle1==-1) particle1=particle; - MADNESS_ASSERT(particle1 == 1 or particle1 == 2); + MADNESS_CHECK_THROW(particle1 == 1 or particle1 == 2, "particle must be 1 or 2"); for (size_t i = 0; i < mo_ket_.size(); i++) { Function tmp1 = mo_ket_[i]; - Function tmp2 = f.project_out(mo_bra_[i], particle - 1); + Function tmp2 = f.project_out(mo_bra_[i], particle1 - 1); Function tmp12; if (particle1 == 1) { tmp12 = CompositeFactory(f.world()).particle1(copy(tmp1)).particle2(copy(tmp2)); diff --git a/src/madness/chem/test_ccpairfunction.cc b/src/madness/chem/test_ccpairfunction.cc index 4d1b931c633..126418d3dfa 100644 --- a/src/madness/chem/test_ccpairfunction.cc +++ b/src/madness/chem/test_ccpairfunction.cc @@ -17,58 +17,65 @@ using namespace madness; bool longtest=false; +template struct data { - real_function_3d f1,f2,f3,f4,f5; - real_function_6d f12,f23; + static constexpr std::size_t LDIM=NDIM/2; + Function f1,f2,f3,f4,f5; + Function f12,f23; - std::shared_ptr> f12_op; + std::shared_ptr> f12_op; data() {} - data(World& world, CCParameters& parameters) { - f12_op.reset(new CCConvolutionOperator(world,OT_F12,parameters)); - if (not f1.is_initialized()) initialize(world); + data(World& world, const CCParameters& parameters) { + if (not is_initialized()) initialize(world,parameters); } - void initialize(World& world) { - auto g1 = [](const coord_3d& r) { return exp(-1.0 * inner(r, r)); }; - auto g2 = [](const coord_3d& r) { return exp(-2.0 * inner(r, r)); }; - auto g3 = [](const coord_3d& r) { return exp(-3.0 * inner(r, r)); }; - auto g4 = [](const coord_3d& r) { return exp(-4.0 * inner(r, r)); }; - auto g5 = [](const coord_3d& r) { return exp(-5.0 * inner(r, r)); }; -// auto g1 = [](const coord_3d& r) { return exp(-1.0 * (r.normf()+1.e-4)); }; -// auto g2 = [](const coord_3d& r) { return exp(-2.0 * (r.normf()+1.e-4)); }; -// auto g3 = [](const coord_3d& r) { return exp(-3.0 * (r.normf()+1.e-4)); }; -// auto g4 = [](const coord_3d& r) { return exp(-4.0 * (r.normf()+1.e-4)); }; -// auto g5 = [](const coord_3d& r) { return exp(-5.0 * (r.normf()+1.e-4)); }; - f1=real_factory_3d(world).f(g1); - f2=real_factory_3d(world).f(g2); - f3=real_factory_3d(world).f(g3); - f4=real_factory_3d(world).f(g4); - f5=real_factory_3d(world).f(g5); - - auto g = [](const coord_6d& r) { - double r1=r[0]*r[0] + r[1]*r[1] + r[2]*r[2]; - double r2=r[3]*r[3] + r[4]*r[4] + r[5]*r[5]; + bool is_initialized() const { + return f1.is_initialized(); + } + + void initialize(World& world, const CCParameters& parameters) { + f12_op.reset(new CCConvolutionOperator(world,OT_F12,parameters)); + auto g1 = [](const Vector& r) { return exp(-1.0 * inner(r, r)); }; + auto g2 = [](const Vector& r) { return exp(-2.0 * inner(r, r)); }; + auto g3 = [](const Vector& r) { return exp(-3.0 * inner(r, r)); }; + auto g4 = [](const Vector& r) { return exp(-4.0 * inner(r, r)); }; + auto g5 = [](const Vector& r) { return exp(-5.0 * inner(r, r)); }; + f1=FunctionFactory(world).f(g1); + f2=FunctionFactory(world).f(g2); + f3=FunctionFactory(world).f(g3); + f4=FunctionFactory(world).f(g4); + f5=FunctionFactory(world).f(g5); + + auto g = [](const Vector& r) { + double r1=0.0, r2=0.0; + for (int i=0; i& r) { + double r1=0.0, r2=0.0; + for (int i=0; i(world); + f23=FunctionFactory(world); // try { // load(f12,"test_ccpairfunction_f12"); // } catch (...) { - f12 = real_factory_6d(world).f(g); + f12 = FunctionFactory(world).f(g); // save(f12,"test_ccpairfunction_f12"); // } // try { // load(f23,"test_ccpairfunction_f23"); // } catch (...) { - f23 = real_factory_6d(world).f(g23); + f23 = FunctionFactory(world).f(g23); // save(f23,"test_ccpairfunction_f23"); // } @@ -105,17 +112,33 @@ struct data { /// p4: pure, corresponds to f23 /// p5: op_pure, corresponds to f23 auto get_ccpairfunctions() const { - CCPairFunction p1(f12); - CCPairFunction p2({f1,f2},{f2,f3}); - CCPairFunction p3(f12_op,{f1,f2},{f2,f3}); - CCPairFunction p4(f23); // two-term, corresponds to p2 - CCPairFunction p5(f12_op,f23); // two-term, corresponds to p2 + CCPairFunction p1(f12); + CCPairFunction p2({f1,f2},{f2,f3}); + CCPairFunction p3(f12_op,{f1,f2},{f2,f3}); + CCPairFunction p4(f23); // two-term, corresponds to p2 + CCPairFunction p5(f12_op,f23); // two-term, corresponds to p2 return std::make_tuple(p1,p2,p3,p4,p5); } }; -data data1; + +template +data& get_data(World& world, const CCParameters& parameters, bool initialize=true) { + static data data1; + if (not data1.is_initialized() and initialize) data1.initialize(world,parameters); + return data1; +} + +template +void clear_data(World& world, const CCParameters& parameters) { + auto data1=get_data(world,parameters,false); + data1.clear(); + world.gop.fence(); +} + + + /// Computes the electrostatic potential due to a Gaussian charge distribution @@ -149,22 +172,28 @@ class GaussianPotential : public FunctionFunctorInterface { } }; -int test_constructor(World& world, std::shared_ptr ncf, const Molecule& molecule, + + + +template +int test_constructor(World& world, std::shared_ptr ncf, const data& data, const CCParameters& parameter) { - test_output t1("CCPairFunction::constructor"); + test_output t1("constructor"); + static_assert(NDIM%2==0, "NDIM must be even"); + constexpr std::size_t LDIM=NDIM/2; - real_function_6d f=real_factory_6d(world); - auto [f1,f2,f3,f4,f5,ff]=data1.get_functions(); + Function f=FunctionFactory(world); + auto [f1,f2,f3,f4,f5,ff]=data.get_functions(); - vector_real_function_3d a= zero_functions(world,3); - vector_real_function_3d b= zero_functions(world,3); - auto f12=CCConvolutionOperatorPtr(world, OT_F12, parameter); + std::vector> a= zero_functions(world,LDIM); + std::vector> b= zero_functions(world,LDIM); + auto f12=CCConvolutionOperatorPtr(world, OT_F12, parameter); t1.checkpoint(true,"preparation"); - CCPairFunction p1; - CCPairFunction p2(f); - CCPairFunction p3({f1,f2},{f1,f3}); - CCPairFunction p4(f12,{f1,f2},{f2,f3}); + CCPairFunction p1; + CCPairFunction p2(f); + CCPairFunction p3({f1,f2},{f1,f3}); + CCPairFunction p4(f12,{f1,f2},{f2,f3}); t1.checkpoint(true,"construction"); { @@ -197,7 +226,7 @@ int test_constructor(World& world, std::shared_ptr ncf t1.checkpoint(true,"checks on op_decomposed"); { - CCPairFunction tmp; + CCPairFunction tmp; tmp=p2; MADNESS_CHECK(tmp.is_pure()); MADNESS_CHECK(tmp.component==p2.component); @@ -212,17 +241,21 @@ int test_constructor(World& world, std::shared_ptr ncf return t1.end(); } -int test_operator_apply(World& world, std::shared_ptr ncf, const Molecule& molecule, +template +int test_operator_apply(World& world, std::shared_ptr ncf, const data& data, const CCParameters& parameter) { - test_output t1("CCPairFunction::test_operator_apply"); + test_output t1("test_operator_apply"); // t1.set_cout_to_terminal(); + static_assert(NDIM%2==0, "NDIM must be even"); + constexpr std::size_t LDIM=NDIM/2; + double exponent=1.0; // corresponds to the exponent of data::f1 and data::ff // double coefficient=pow(1.0/constants::pi*exponent,0.5*3); double coefficient=1.0; - const coord_3d center={0.0,0.0,-0.0}; + const Vector center(0.0); - auto Gaussian = [¢er, &exponent, &coefficient](const coord_3d& r) { + auto Gaussian = [¢er, &exponent, &coefficient](const Vector& r) { return coefficient * exp(-exponent*inner(r-center,r-center)); }; @@ -231,15 +264,15 @@ int test_operator_apply(World& world, std::shared_ptr // GaussianPotential gpot(center, exponent, coefficient); // real_function_3d op_a=real_factory_3d(world).functor(gpot); - real_function_3d a=real_factory_3d(world).functor(Gaussian); + Function a=FunctionFactory(world).functor(Gaussian); exponent=2.0; - real_function_3d b=real_factory_3d(world).functor(Gaussian); + Function b=FunctionFactory(world).functor(Gaussian); - auto [f1,f2,f3,f4,f5,ff]=data1.get_functions(); - CCPairFunction c1(a,b); - CCPairFunction c2(f1,f2); + auto [f1,f2,f3,f4,f5,ff]=data.get_functions(); + CCPairFunction c1(a,b); + CCPairFunction c2(f1,f2); // CCPairFunction ref(op_a,b); - auto op= CoulombOperator(world,1.e-5,FunctionDefaults<3>::get_thresh()); + auto op= CoulombOperator_ndim(world,1.e-5,FunctionDefaults::get_thresh()); op.print_timings=false; op.particle()=1; @@ -249,68 +282,75 @@ int test_operator_apply(World& world, std::shared_ptr double norm1=inner(op_c1,op_c1); double norm2=inner(op_c2,op_c2); print("norm1,norm2",norm1,norm2); - bool good=fabs(norm1-norm2)::get_thresh(); + bool good=fabs(norm1-norm2)::get_thresh(); t1.checkpoint(good,"op(xx)"); return t1.end(); } -int test_transformations(World& world, std::shared_ptr ncf, const Molecule& molecule, +template +int test_transformations(World& world, std::shared_ptr ncf, const data& data, const CCParameters& parameter) { - test_output t1("CCPairFunction::test_transformations"); + test_output t1("test_transformations"); + static_assert(NDIM%2==0, "NDIM must be even"); + constexpr std::size_t LDIM=NDIM/2; - real_function_6d f=real_factory_6d(world); - auto [f1,f2,f3,f4,f5,ff]=data1.get_functions(); - auto f12=CCConvolutionOperatorPtr(world, OT_F12, parameter); - auto g12=CCConvolutionOperatorPtr(world, OT_G12, parameter); +// auto data=get_data(world,parameter); + auto [f1,f2,f3,f4,f5,ff]=data.get_functions(); + auto f12=CCConvolutionOperatorPtr(world, OT_F12, parameter); + auto g12=CCConvolutionOperatorPtr(world, OT_G12, parameter); - CCPairFunction p1(ff); + CCPairFunction p1(ff); t1.checkpoint(p1.is_pure(),"is_pure"); t1.checkpoint(p1.is_pure_no_op(),"is_pure_no_op"); - CCPairFunction p2(f12,ff); + CCPairFunction p2(f12,ff); t1.checkpoint(p2.is_pure(),"is_pure"); t1.checkpoint(p2.is_op_pure(),"is_op_pure"); t1.checkpoint(p2.is_convertible_to_pure_no_op(),"is_convertible_to_pure_no_op"); - CCPairFunction p3=copy(p2); + CCPairFunction p3=copy(p2); p3.convert_to_pure_no_op_inplace(); t1.checkpoint(p2.is_op_pure(),"is_op_pure"); t1.checkpoint(p3.is_pure_no_op(),"is_pure_no_op"); - CCPairFunction p4(g12,ff); + CCPairFunction p4(g12,ff); t1.checkpoint(p4.is_pure(),"is_pure"); t1.checkpoint(p4.is_op_pure(),"is_op_pure"); t1.checkpoint(not p4.is_convertible_to_pure_no_op(),"not is_convertible_to_pure_no_op"); - CCPairFunction p5(f12,f1,f2); + CCPairFunction p5(f12,f1,f2); t1.checkpoint(not p5.is_pure(),"is_pure"); t1.checkpoint(p5.is_op_decomposed(),"is_op_decomposed"); t1.checkpoint(p5.is_convertible_to_pure_no_op(),"is_convertible_to_pure_no_op"); - CCPairFunction p6=copy(p5); + CCPairFunction p6=copy(p5); p6.convert_to_pure_no_op_inplace(); t1.checkpoint(p6.is_pure_no_op(),"is_pure_no_op"); return t1.end(); } -int test_multiply_with_f12(World& world, std::shared_ptr ncf, const Molecule& molecule, +template +int test_multiply_with_f12(World& world, std::shared_ptr ncf, const data& data, const CCParameters& parameters) { - test_output t1("CCPairFunction::test_multiply_with_f12"); + test_output t1("test_multiply_with_f12"); + static_assert(NDIM%2==0, "NDIM must be even"); + constexpr std::size_t LDIM=NDIM/2; // p1: pure, corresponds to f12 // p2: dec, corresponds to f23 // p3: op_dec, corresponds to f23 // p4: pure, corresponds to f23 // p5: op_pure, corresponds to f23 - auto [p1,p2,p3,p4,p5]=data1.get_ccpairfunctions(); // p2-p5 correspond to f23 - auto f12=data1.f12_op; +// auto data=get_data(world,parameters); + auto [p1,p2,p3,p4,p5]=data.get_ccpairfunctions(); // p2-p5 correspond to f23 + auto f12=data.f12_op; - double thresh=FunctionDefaults<3>::get_thresh(); + double thresh=FunctionDefaults::get_thresh(); // decomposed - CCPairFunction tmp1=f12*p2; // should now be identical to p3 - CCPairFunction tmp2=p2*f12; // should now be identical to p3 + CCPairFunction tmp1=f12*p2; // should now be identical to p3 + CCPairFunction tmp2=p2*f12; // should now be identical to p3 double ref=inner(p2,p3); double r1=inner(p2,tmp1); @@ -336,30 +376,40 @@ int test_multiply_with_f12(World& world, std::shared_ptr ncf, const Molecule& molecule, +template +int test_multiply(World& world, std::shared_ptr ncf, const data& data, const CCParameters& parameters) { - test_output t1("CCPairFunction::test_multiply"); + test_output t1("test_multiply<"+std::to_string(NDIM)+">"); + static_assert(NDIM%2==0, "NDIM must be even"); + constexpr std::size_t LDIM=NDIM/2; // consistency check, relies on CCPairFunction::inner to work correctly - - double thresh=FunctionDefaults<3>::get_thresh(); - auto [p1,p2,p3,p4,p5]=data1.get_ccpairfunctions(); // p2-p5 correspond to f23 - auto [f1,f2,f3,f4,f5,f]=data1.get_functions(); + double thresh=FunctionDefaults::get_thresh(); +// auto data=get_data(world,parameters); + auto [p1,p2,p3,p4,p5]=data.get_ccpairfunctions(); // p2-p5 correspond to f23 + auto [f1,f2,f3,f4,f5,f]=data.get_functions(); + + auto particle1=std::array(); + auto particle2=std::array(); + for (int i=0; i = - CCPairFunction bra(f1,f2); - CCPairFunction bra1(f1*f2,f2); - CCPairFunction bra2(f1,f2*f2); + CCPairFunction bra(f1,f2); + CCPairFunction bra1(f1*f2,f2); + CCPairFunction bra2(f1,f2*f2); for (auto& p : {p2,p3,p4,p5}) { - auto tmp1=multiply(p,f2,{0,1,2}); + auto tmp1=multiply(p,f2,particle1); double ovlp1=inner(bra,tmp1); double ref1=p.has_operator() ? inner(bra1,p3) : inner(bra1,p2); bool good=(fabs(ovlp1-ref1) ncf, c return t1.end(); } -int test_inner(World& world, std::shared_ptr ncf, const Molecule& molecule, + +template +int test_inner(World& world, std::shared_ptr ncf, const data& data, const CCParameters& parameters) { - test_output t1("CCPairFunction::test_inner"); + test_output t1("test_inner<"+std::to_string(NDIM)+">"); + static_assert(NDIM%2==0, "NDIM must be even"); + constexpr std::size_t LDIM=NDIM/2; t1.set_cout_to_terminal(); /// f1: exp(-1.0 r^2) @@ -381,19 +435,20 @@ int test_inner(World& world, std::shared_ptr ncf, cons /// f5: exp(-5.0 r^2) /// f: exp(-r_1^2 - 2 r_2^2) /// f23: exp(-r_1^2 - 2 r_2^2) + exp(-2 r_1^2 - 3 r_2^2) - auto [f1,f2,f3,f4,f5,f]=data1.get_functions(); +// auto data=get_data(world,parameters); + auto [f1,f2,f3,f4,f5,f]=data.get_functions(); /// p1: pure, corresponds to f12 /// p2: dec, corresponds to f23 /// p3: op_dec, corresponds to f23 /// p4: pure, corresponds to f23 /// p5: op_pure, corresponds to f23 - auto [p1,p2,p3,p4,p5]=data1.get_ccpairfunctions(); - auto f12 = *(data1.f12_op); + auto [p1,p2,p3,p4,p5]=data.get_ccpairfunctions(); + auto f12 = *(data.f12_op); /// results - auto a=std::vector({f1,f2}); - auto b=std::vector({f2,f3}); - std::vector a_ij_functions, b_ij_functions; + auto a=std::vector>({f1,f2}); + auto b=std::vector>({f2,f3}); + std::vector> a_ij_functions, b_ij_functions; for (int i=0; i ncf, cons // operator apply of SlaterF12Operator includes a factor of 1/(2 gamma) and the identity // operator apply of SlaterOperator has no further terms const double y = parameters.gamma(); - SeparatedConvolution fop= SlaterOperator(world, y, parameters.lo(), parameters.thresh_bsh_3D()); - SeparatedConvolution fsq = SlaterOperator(world, 2.0 * y, parameters.lo(), parameters.thresh_bsh_3D()); + SeparatedConvolution fop= SlaterOperator(world, y, parameters.lo(), parameters.thresh_bsh_3D()); + SeparatedConvolution fsq = SlaterOperator(world, 2.0 * y, parameters.lo(), parameters.thresh_bsh_3D()); const double prefactor = 1.0 / (4 * y * y); const double ab_f2_ab = prefactor*( ab_ab @@ -447,20 +502,22 @@ int test_inner(World& world, std::shared_ptr ncf, cons } -int test_partial_inner_6d(World& world, std::shared_ptr ncf, const Molecule& molecule, +template +int test_partial_inner_6d(World& world, std::shared_ptr ncf, const data& data, const CCParameters& parameter) { CCTimer timer(world, "testing"); test_output t1("CCPairFunction::test_partial_inner_6d"); t1.set_cout_to_terminal(); - auto [f1,f2,f3,f4,f5,f] = data1.get_functions(); +// auto data=get_data<6>(world,parameter); + auto [f1,f2,f3,f4,f5,f] = data.get_functions(); std::vector a = {f1, f2}; std::vector b = {f2, f3}; auto f12=CCConvolutionOperatorPtr(world, OT_F12, parameter); - auto [p1,p2,p3,p4,nil]=data1.get_ccpairfunctions(); + auto [p1,p2,p3,p4,nil]=data.get_ccpairfunctions(); CCPairFunction p11({f1},{f1}); CCPairFunction p12({f1},{f2}); @@ -568,16 +625,18 @@ int test_partial_inner_6d(World& world, std::shared_ptr ncf, const Molecule& molecule, +template +int test_partial_inner_3d(World& world, std::shared_ptr ncf, const data& data, const CCParameters& parameter) { CCTimer timer(world, "testing"); test_output t1("CCPairFunction::test_partial_inner"); - auto [f1,f2,f3,f4,f5,f] = data1.get_functions(); +// auto data=get_data<6>(world,parameter); + auto [f1,f2,f3,f4,f5,f] = data.get_functions(); std::vector a = {f1, f2}; std::vector b = {f2, f3}; @@ -664,7 +723,8 @@ int test_partial_inner_3d(World& world, std::shared_ptr ncf, const Molecule& molecule, +template +int test_apply(World& world, std::shared_ptr ncf, const data& data, const CCParameters& parameter) { test_output t1("CCPairFunction::test_apply"); t1.set_cout_to_terminal(); @@ -676,8 +736,9 @@ int test_apply(World& world, std::shared_ptr ncf, cons /// p3: op_dec, corresponds to f23 /// p4: pure, corresponds to f23 /// p5: op_pure, corresponds to f23 - auto [p1,p2,p3,p4,p5]=data1.get_ccpairfunctions(); - auto [f1,f2,f3,f4,f5,f]=data1.get_functions(); +// auto data=get_data<6>(world,parameter); + auto [p1,p2,p3,p4,p5]=data.get_ccpairfunctions(); + auto [f1,f2,f3,f4,f5,f]=data.get_functions(); auto f12=CCConvolutionOperatorPtr(world, OT_F12, parameter); auto& op=*(f12->get_op()); @@ -704,26 +765,28 @@ int test_apply(World& world, std::shared_ptr ncf, cons } - - return t1.end(); } -int test_scalar_multiplication(World& world, std::shared_ptr ncf, const Molecule& molecule, +template +int test_scalar_multiplication(World& world, std::shared_ptr ncf, const data& data, const CCParameters& parameter) { CCTimer timer(world, "testing"); test_output t1("CCPairFunction::test_scalar_multiplication"); + static_assert(NDIM%2==0, "NDIM must be even"); + constexpr std::size_t LDIM=NDIM/2; - auto [f1,f2,f3,f4,f5,f] = data1.get_functions(); +// auto data=get_data(world,parameter); + auto [f1,f2,f3,f4,f5,f] = data.get_functions(); - std::vector a = {f1, f2}; - std::vector b = {f3, f1}; + std::vector> a = {f1, f2}; + std::vector> b = {f3, f1}; print("time in preparation",timer.reset()); t1.checkpoint(true,"prep"); - CCPairFunction p(f); - CCPairFunction p1(a,b); + CCPairFunction p(f); + CCPairFunction p1(a,b); double norm1=inner(p,p1); double pnorm=inner(p,p); double p1norm=inner(p1,p1); @@ -743,31 +806,32 @@ int test_scalar_multiplication(World& world, std::shared_ptr::get_thresh(); + bool bsuccess=fabs(4.0*norm1-norm2)::get_thresh(); t1.checkpoint(bsuccess,"scaling"); - t1.end(); - return (t1.get_final_success()) ? 0 : 1; + return t1.end(); } -int test_swap_particles(World& world, std::shared_ptr ncf, const Molecule& molecule, +template +int test_swap_particles(World& world, std::shared_ptr ncf, const data& data, const CCParameters& parameters) { - test_output t1("CCPairFunction::swap_particles"); - CCTimer timer(world, "testing swap_particles"); + test_output t1("swap_particles<"+std::to_string(NDIM)+">"); + static_assert(NDIM%2==0, "NDIM must be even"); + constexpr std::size_t LDIM=NDIM/2; // prepare - auto one = [](const coord_3d& r) { return 1.0; }; - real_function_3d R2 = real_factory_3d(world).f(one); + auto one = [](const Vector& r) { return 1.0; }; + Function R2 = FunctionFactory(world).f(one); - auto [f1,f2,f3,f4,f5,f] = data1.get_functions(); - std::vector a = {f1, f2}; - std::vector b = {f3, f1}; +// auto data=get_data(world,parameters); + auto [f1,f2,f3,f4,f5,f] = data.get_functions(); + std::vector> a = {f1, f2}; + std::vector> b = {f3, f1}; // test decomposed { - CCPairFunction p1(a, b); - CCPairFunction p2(b, a); + CCPairFunction p1(a, b); + CCPairFunction p2(b, a); double norm1 = inner(p1, p2.swap_particles(), R2); double norm1a = inner(p1, p1, R2); @@ -776,19 +840,19 @@ int test_swap_particles(World& world, std::shared_ptr print("norm1 ", norm1); print("norm1a", norm1a); print("norm2 ", norm2); - t1.checkpoint(std::abs(norm1 - norm2) < FunctionDefaults<3>::get_thresh(), "swap_particles a,b"); + t1.checkpoint(std::abs(norm1 - norm2) < FunctionDefaults::get_thresh(), "swap_particles a,b"); } // test pure { - CCPairFunction p(f); - CCPairFunction p_swapped=p.swap_particles(); + CCPairFunction p(f); + CCPairFunction p_swapped=p.swap_particles(); double pnorm=p.get_function().norm2(); double psnorm=p_swapped.get_function().norm2(); print("p/s norm",pnorm,psnorm); - CCPairFunction p1({f1}, {f2}); - CCPairFunction p2({f2}, {f1}); + CCPairFunction p1({f1}, {f2}); + CCPairFunction p2({f2}, {f1}); double ref1=inner(f1,f1)*inner(f2,f2); double ref2=inner(f1,f2)*inner(f2,f1); print("ref1/2",ref1,ref2); @@ -820,19 +884,20 @@ int test_swap_particles(World& world, std::shared_ptr t1.checkpoint(total_error < FunctionDefaults<3>::get_thresh(), "swap_particles u"); }; - t1.end(); - return (t1.get_final_success()) ? 0 : 1; + return t1.end(); } -int test_projector(World& world, std::shared_ptr ncf, const Molecule& molecule, + +template +int test_projector(World& world, std::shared_ptr ncf, const data& data, const CCParameters& parameter) { test_output t1("CCPairFunction::test_projector"); - CCTimer timer(world, "testing"); // t1.set_cout_to_logger(); t1.set_cout_to_terminal(); - auto [f1,f2,f3,f4,f5,f] = data1.get_functions(); +// auto data=get_data<6>(world,parameter); + auto [f1,f2,f3,f4,f5,f] = data.get_functions(); double nf1=f1.norm2(); double nf2=f2.norm2(); f1.scale(1.0/nf1); @@ -926,7 +991,6 @@ int test_projector(World& world, std::shared_ptr ncf, print("n2,n2a",n2,n2a); } - timer.reset(); // test {O,Q} with particles 1,2 on all three CCPairFunction types @@ -944,13 +1008,13 @@ int test_projector(World& world, std::shared_ptr ncf, double n1 = inner(Op, vp3) + inner(Qp, vp3); double n2 = inner(vp, vp3); print("n1 (RI), n2", n1, n2, fabs(n1 - n2)); - t1.checkpoint(fabs(n1 - n2) < FunctionDefaults<3>::get_thresh(), "RI with particle "+std::to_string(particle)+" on "+s ,timer.reset()); + t1.checkpoint(fabs(n1 - n2) < FunctionDefaults<3>::get_thresh(), "RI with particle "+std::to_string(particle)+" on "+s); auto Op1 = O(Op); double n3=inner(Op, vp3); double n4=inner(Op1, vp3); print("n3, n4", n3, n4); - t1.checkpoint(fabs(n3-n4) < FunctionDefaults<3>::get_thresh(), "idempotency with particle "+std::to_string(particle)+" on "+s,timer.reset()); + t1.checkpoint(fabs(n3-n4) < FunctionDefaults<3>::get_thresh(), "idempotency with particle "+std::to_string(particle)+" on "+s); } // testing SO projector @@ -973,21 +1037,15 @@ int test_projector(World& world, std::shared_ptr ncf, n1 = inner(SOp, vp3); print("SO: n1, n2, n3", n1, n2, n3, fabs(n1 - n2)); double zero=fabs(n1-n2) + fabs(n1-n3) + fabs(n2-n3); - t1.checkpoint(zero < FunctionDefaults<3>::get_thresh(), "SO operator on "+s,timer.reset() ); + t1.checkpoint(zero < FunctionDefaults<3>::get_thresh(), "SO operator on "+s); } } return t1.end(); } -int test_dirac_convolution(World& world, std::shared_ptr ncf, const Molecule& molecule, - const CCParameters& parameter) { - test_output t1("CCPairFunction::test_dirac_convolution"); - - return (t1.get_final_success()) ? 0 : 1; -} /// testing = 0.032 mEh -int test_helium(World& world, std::shared_ptr ncf, const Molecule& molecule, +int test_helium(World& world, std::shared_ptr ncf, const CCParameters& parameters) { test_output t1("CCPairFunction::test_helium"); @@ -1084,53 +1142,87 @@ int main(int argc, char **argv) { madness::World& world = madness::initialize(argc, argv); startup(world, argc, argv); commandlineparser parser(argc, argv); - FunctionDefaults<3>::set_k(5); - FunctionDefaults<6>::set_k(5); + int k=6; + double thresh=1.e-5; + if (parser.key_exists("k")) k=std::stoi(parser.value("k")); + if (parser.key_exists("thresh")) thresh=std::stod(parser.value("thresh")); + FunctionDefaults<1>::set_k(k); + FunctionDefaults<2>::set_k(k); + FunctionDefaults<3>::set_k(k); + FunctionDefaults<4>::set_k(k); + FunctionDefaults<5>::set_k(k); + FunctionDefaults<6>::set_k(k); + FunctionDefaults<1>::set_thresh(thresh); + FunctionDefaults<2>::set_thresh(thresh); + FunctionDefaults<3>::set_thresh(thresh); + FunctionDefaults<4>::set_thresh(thresh); + FunctionDefaults<5>::set_thresh(thresh); + FunctionDefaults<6>::set_thresh(thresh); FunctionDefaults<6>::set_tensor_type(TT_2D); - FunctionDefaults<3>::set_thresh(1.e-5); - FunctionDefaults<3>::set_cubic_cell(-1.0,1.0); - FunctionDefaults<6>::set_cubic_cell(-1.0,1.0); + FunctionDefaults<1>::set_cubic_cell(-10.,10.); + FunctionDefaults<2>::set_cubic_cell(-10.,10.); + FunctionDefaults<3>::set_cubic_cell(-10.,10.); + FunctionDefaults<4>::set_cubic_cell(-10.,10.); + FunctionDefaults<5>::set_cubic_cell(-10.,10.); + FunctionDefaults<6>::set_cubic_cell(-10.,10.); print("numerical parameters: k, eps(3D), eps(6D)", FunctionDefaults<3>::get_k(), FunctionDefaults<3>::get_thresh(), FunctionDefaults<6>::get_thresh()); int isuccess=0; #ifdef USE_GENTENSOR + CCParameters ccparam(world, parser); try { parser.set_keyval("geometry", "he"); parser.print_map(); Molecule mol(world, parser); mol.print(); - CCParameters ccparam(world, parser); - - data1=data(world,ccparam); - std::shared_ptr ncf = create_nuclear_correlation_factor(world, - mol, nullptr, std::make_pair("slater", 2.0)); - - isuccess+=test_constructor(world, ncf, mol, ccparam); - isuccess+=test_operator_apply(world, ncf, mol, ccparam); - isuccess+=test_transformations(world, ncf, mol, ccparam); - isuccess+=test_inner(world, ncf, mol, ccparam); - isuccess+=test_multiply(world, ncf, mol, ccparam); - isuccess+=test_multiply_with_f12(world, ncf, mol, ccparam); - isuccess+=test_swap_particles(world, ncf, mol, ccparam); - isuccess+=test_scalar_multiplication(world, ncf, mol, ccparam); - isuccess+=test_partial_inner_3d(world, ncf, mol, ccparam); - isuccess+=test_partial_inner_6d(world, ncf, mol, ccparam); + mol, nullptr, std::make_pair("slater", 2.0)); + + auto data2=data(world,ccparam); + auto data4=data(world,ccparam); +// auto data6=data(world,ccparam); + + isuccess+=test_constructor(world, ncf, data2, ccparam); + isuccess+=test_constructor(world, ncf, data4, ccparam); + isuccess+=test_operator_apply(world, ncf, data2, ccparam); + isuccess+=test_operator_apply(world, ncf, data4, ccparam); + isuccess+=test_transformations(world, ncf, data2, ccparam); + isuccess+=test_transformations(world, ncf, data4, ccparam); + isuccess+=test_multiply_with_f12(world, ncf, data2, ccparam); + isuccess+=test_multiply_with_f12(world, ncf, data4, ccparam); + isuccess+=test_inner(world, ncf, data2, ccparam); + isuccess+=test_inner(world, ncf, data4, ccparam); + isuccess+=test_multiply(world, ncf, data2, ccparam); + isuccess+=test_multiply(world, ncf, data4, ccparam); + isuccess+=test_swap_particles(world, ncf, data2, ccparam); + isuccess+=test_swap_particles(world, ncf, data4, ccparam); + isuccess+=test_scalar_multiplication(world, ncf, data2, ccparam); + isuccess+=test_scalar_multiplication(world, ncf, data4, ccparam); + +// isuccess+=test_partial_inner_3d(world, ncf, data2, ccparam); +// isuccess+=test_partial_inner_6d(world, ncf, data4, ccparam); FunctionDefaults<3>::set_thresh(1.e-5); FunctionDefaults<3>::set_cubic_cell(-10.,10.); FunctionDefaults<6>::set_thresh(1.e-3); FunctionDefaults<6>::set_cubic_cell(-10.,10.); -// isuccess+=test_apply(world, ncf, mol, ccparam); - isuccess+=test_projector(world, ncf, mol, ccparam); +// isuccess+=test_apply(world, ncf, data, ccparam); +// isuccess+=test_projector(world, ncf, mol, ccparam); // FunctionDefaults<3>::set_cubic_cell(-10,10); -// isuccess+=test_helium(world,ncf,mol,ccparam); - data1.clear(); +// isuccess+=test_helium(world,ncf,ccparam); + data2.clear(); + data4.clear(); +// data6.clear(); + world.gop.fence(); } catch (std::exception& e) { madness::print("an error occured"); madness::print(e.what()); - data1.clear(); + clear_data<2>(world,ccparam); + clear_data<4>(world,ccparam); + clear_data<6>(world,ccparam); + world.gop.fence(); } + world.gop.fence(); #else print("could not run test_ccpairfunction: U need to compile with ENABLE_GENTENSOR=1"); #endif diff --git a/src/madness/mra/function_interface.h b/src/madness/mra/function_interface.h index d6b7d414c96..6edc2234da8 100644 --- a/src/madness/mra/function_interface.h +++ b/src/madness/mra/function_interface.h @@ -51,9 +51,16 @@ namespace madness { template class FunctionImpl; + template + class Function; + template Tensor fcube(const Key&, T (*f)(const Vector&), const Tensor&); +// template +// const std::vector>& change_tree_state(const std::vector>& v, +// const TreeState finalstate, +// const bool fence); /// Abstract base class interface required for functors used as input to Functions @@ -194,19 +201,12 @@ namespace madness { /// replicate low-dimensional functions over all ranks of this world void replicate_low_dim_functions(const bool fence) { - // prepare base functions that make this function - for (auto& k : impl_ket_vector) if (k and (not k->is_on_demand())) k->change_tree_state(redundant,false); - if (impl_eri) { - if (not impl_eri->is_on_demand()) impl_eri->change_tree_state(redundant,false); - } - if (impl_m1 and (not impl_m1->is_on_demand())) impl_m1->change_tree_state(redundant,false); - if (impl_m2 and (not impl_m2->is_on_demand())) impl_m2->change_tree_state(redundant,false); + if (impl_m1 and (not impl_m1->is_on_demand())) impl_m1->replicate(false); + if (impl_m2 and (not impl_m2->is_on_demand())) impl_m2->replicate(false); - for (auto& k : impl_p1_vector) if (k and (not k->is_on_demand())) k->change_tree_state(redundant,false); - for (auto& k : impl_p2_vector) if (k and (not k->is_on_demand())) k->change_tree_state(redundant,false); -// if (impl_p1 and (not impl_p1->is_on_demand())) impl_p1->make_redundant(false); -// if (impl_p2 and (not impl_p2->is_on_demand())) impl_p2->make_redundant(false); - if (fence) world.gop.fence(); + for (auto& p1 : impl_p1_vector) if (p1 and (not p1->is_on_demand())) p1->replicate(false); + for (auto& p2 : impl_p2_vector) if (p2 and (not p2->is_on_demand())) p2->replicate(false); + if (fence) world.gop.fence(); } void make_redundant(const bool fence) { @@ -218,8 +218,10 @@ namespace madness { if (impl_m1 and (not impl_m1->is_on_demand())) impl_m1->change_tree_state(redundant,false); if (impl_m2 and (not impl_m2->is_on_demand())) impl_m2->change_tree_state(redundant,false); - for (auto& k : impl_p1_vector) if (k and (not k->is_on_demand())) k->change_tree_state(redundant,false); - for (auto& k : impl_p2_vector) if (k and (not k->is_on_demand())) k->change_tree_state(redundant,false); + change_tree_state(impl2function(impl_p1_vector),redundant,false); + change_tree_state(impl2function(impl_p2_vector),redundant,false); +// for (auto& k : impl_p1_vector) if (k and (not k->is_on_demand())) k->change_tree_state(redundant,false); +// for (auto& k : impl_p2_vector) if (k and (not k->is_on_demand())) k->change_tree_state(redundant,false); // if (impl_p1 and (not impl_p1->is_on_demand())) impl_p1->change_tree_state(redundant,false); // if (impl_p2 and (not impl_p2->is_on_demand())) impl_p2->change_tree_state(redundant,false); if (fence) world.gop.fence(); @@ -338,7 +340,7 @@ namespace madness { :rank(), k(kk), lo(lo), hi(1.0) { // Presently we must have periodic or non-periodic in all dimensions. - for (std::size_t d=1; d<6; ++d) {MADNESS_ASSERT(bc(d,0)==bc(0,0));} + for (std::size_t d=1; d& width = FunctionDefaults::get_cell_width(); hi = width.normf(); // Diagonal width of cell @@ -396,7 +398,9 @@ namespace madness { // include weights in first vector scr1(mu,Slice(_))=r0*ops[mu].getfac(); - if (NDIM==4) { + if (NDIM==2) { + ; + } else if (NDIM==4) { scr3(mu,Slice(_))=r1; } else if (NDIM==6) { // merge second and third vector to scr(r,k1,k2) @@ -406,7 +410,12 @@ namespace madness { } } - if (NDIM==2) return scr1; + if (NDIM==2) { + // perform sum over the rank + Tensor result(scr1.dim(1)); + for (long mu=0; mu map(NDIM); if (NDIM==2) { map[0]=0; map[1]=1; - return copy(c); + return copy(c.reshape(k,k)); } else if (NDIM==4) { map[0]=0; map[1]=2; map[2]=1; map[3]=3; @@ -442,12 +451,12 @@ namespace madness { // set some parameters rank=coeff.dim(0); ops.resize(rank); - const Tensor& width = FunctionDefaults<6>::get_cell_width(); + const Tensor& width = FunctionDefaults::get_cell_width(); // construct all the terms for (int mu=0; mu(NDIM)); // Normalization coeff - double c = std::pow(sqrt(expnt(mu)/constants::pi),3); // Normalization coeff + double c = std::pow(sqrt(expnt(mu)/constants::pi),LDIM); // Normalization coeff // We cache the normalized operator so the factor is the value we must multiply // by to recover the coeff we want. diff --git a/src/madness/mra/mra.h b/src/madness/mra/mra.h index 5efa69a71d3..354c35207f2 100644 --- a/src/madness/mra/mra.h +++ b/src/madness/mra/mra.h @@ -1400,7 +1400,7 @@ namespace madness { template Function project_out(const Function& g, const int dim) const { if (NDIM<=LDIM) MADNESS_EXCEPTION("confused dimensions in project_out?",1); - MADNESS_ASSERT(dim==0 or dim==1); + MADNESS_CHECK_THROW(dim==0 or dim==1,"dim must be 0 or 1 in project_out"); verify(); typedef TENSOR_RESULT_TYPE(T,R) resultT; static const size_t KDIM=NDIM-LDIM; @@ -2282,17 +2282,23 @@ namespace madness { /// param[in] f a function of 2 particles f(1,2) /// return the input function with particles swapped g(1,2) = f(2,1) - template - Function - swap_particles(const Function & f){ + template + typename std::enable_if_t> + swap_particles(const Function & f){ // this could be done more efficiently for SVD, but it works decently - std::vector map(6); - map[0]=3; - map[1]=4; - map[2]=5; // 2 -> 1 - map[3]=0; - map[4]=1; - map[5]=2; // 1 -> 2 + std::vector map(NDIM); + constexpr std::size_t LDIM=NDIM/2; + static_assert(LDIM*2==NDIM); + for (auto d=0; d 1 +// map[3]=0; +// map[4]=1; +// map[5]=2; // 1 -> 2 return mapdim(f,map); } diff --git a/src/madness/mra/operator.h b/src/madness/mra/operator.h index f88b354a75e..b42cdfeb6ef 100644 --- a/src/madness/mra/operator.h +++ b/src/madness/mra/operator.h @@ -1725,6 +1725,20 @@ namespace madness { } + /// Factory function generating separated kernel for convolution with 1/r in 3D. + template + static + inline + SeparatedConvolution CoulombOperator_ndim(World& world, + double lo, + double eps, + const BoundaryConditions& bc=FunctionDefaults::get_bc(), + + int k=FunctionDefaults::get_k()) + { + return SeparatedConvolution(world,OperatorInfo(0.0,lo,eps,OT_G12),bc,k); + } + /// Factory function generating separated kernel for convolution with 1/r in 3D. static inline @@ -1862,11 +1876,12 @@ namespace madness { } /// Factory function generating separated kernel for convolution with exp(-mu*r) in 3D - static inline SeparatedConvolution SlaterOperator(World& world, + template + static inline SeparatedConvolution SlaterOperator(World& world, double mu, double lo, double eps, - const BoundaryConditions<3>& bc=FunctionDefaults<3>::get_bc(), - int k=FunctionDefaults<3>::get_k()) { - return SeparatedConvolution(world,OperatorInfo(mu,lo,eps,OT_SLATER),bc,k); + const BoundaryConditions& bc=FunctionDefaults::get_bc(), + int k=FunctionDefaults::get_k()) { + return SeparatedConvolution(world,OperatorInfo(mu,lo,eps,OT_SLATER),bc,k); } /// Factory function generating separated kernel for convolution with exp(-mu*r*r) diff --git a/src/madness/mra/vmra.h b/src/madness/mra/vmra.h index eb2ad18c42b..3d8bf122cff 100644 --- a/src/madness/mra/vmra.h +++ b/src/madness/mra/vmra.h @@ -288,22 +288,42 @@ namespace madness { if (not dummy.is_initialized()) return v; World& world=dummy.world(); - // a couple of special cases - if (finalstate==nonstandard) { - bool must_fence=false; + + // if a tree state cannot directly be changed to finalstate, we need to go via intermediate + auto change_initial_to_intermediate =[](const std::vector>& v, + const TreeState initialstate, + const TreeState intermediatestate) { + int must_fence=0; for (auto& f : v) { - if (f.get_impl()->get_tree_state()== reconstructed) continue; - if (f.get_impl()->get_tree_state()!=nonstandard) { - must_fence=true; - f.change_tree_state(reconstructed,false); + if (f.get_impl()->get_tree_state()==initialstate) { + f.change_tree_state(intermediatestate,false); + must_fence=1; } } - if (must_fence) world.gop.fence(); -// if (world.rank()==0 and must_fence) print("could not respect fence in change_tree_state(vector)"); + return must_fence; + }; + + int do_fence=0; + if (finalstate==compressed) { + do_fence+=change_initial_to_intermediate(v,redundant,TreeState::reconstructed); + } + if (finalstate==nonstandard) { + do_fence+=change_initial_to_intermediate(v,compressed,TreeState::reconstructed); + do_fence+=change_initial_to_intermediate(v,redundant,TreeState::reconstructed); + } + if (finalstate==nonstandard_with_leaves) { + do_fence+=change_initial_to_intermediate(v,compressed,TreeState::reconstructed); + do_fence+=change_initial_to_intermediate(v,nonstandard,TreeState::reconstructed); + do_fence+=change_initial_to_intermediate(v,redundant,TreeState::reconstructed); } -// if (not fence) world.gop.set_forbid_fence(true); // make sure fence is respected + if (finalstate==redundant) { + do_fence+=change_initial_to_intermediate(v,compressed,TreeState::reconstructed); + do_fence+=change_initial_to_intermediate(v,nonstandard,TreeState::reconstructed); + do_fence+=change_initial_to_intermediate(v,nonstandard_with_leaves,TreeState::reconstructed); + } + if (do_fence>0) world.gop.fence(); + for (unsigned int i=0; i + std::vector> impl2function(const std::vector>> vimpl) { + std::vector> v(vimpl.size()); + for (std::size_t i=0; i Date: Fri, 26 Jan 2024 12:27:26 +0100 Subject: [PATCH 080/109] making ccpairfunction.cc tests work again with templates --- src/madness/chem/CCStructures.cc | 3 +- src/madness/chem/ccpairfunction.h | 35 +- src/madness/chem/test_ccpairfunction.cc | 573 +++++++++++------------- src/madness/mra/funcimpl.h | 68 ++- src/madness/mra/gfit.h | 17 +- src/madness/mra/mra.h | 5 +- src/madness/mra/operator.h | 49 +- src/madness/mra/operatorinfo.h | 1 + src/madness/mra/vmra.h | 2 +- 9 files changed, 376 insertions(+), 377 deletions(-) diff --git a/src/madness/chem/CCStructures.cc b/src/madness/chem/CCStructures.cc index a72c383bae2..c07d5e04094 100644 --- a/src/madness/chem/CCStructures.cc +++ b/src/madness/chem/CCStructures.cc @@ -319,7 +319,8 @@ CCConvolutionOperator::operator()(const CCFunction& bra, const F template void CCConvolutionOperator::update_elements(const CC_vecfunction& bra, const CC_vecfunction& ket) { - if constexpr (NDIM==6) { + if constexpr (NDIM==3) { + constexpr std::size_t LDIM=NDIM/2; const std::string operation_name = "<" + assign_name(bra.type) + "|" + name() + "|" + assign_name(ket.type) + ">"; if (world.rank() == 0) std::cout << "updating operator elements: " << operation_name << " (" << bra.size() << "x" << ket.size() << ")" diff --git a/src/madness/chem/ccpairfunction.h b/src/madness/chem/ccpairfunction.h index 75003abcd35..54b799ac55a 100644 --- a/src/madness/chem/ccpairfunction.h +++ b/src/madness/chem/ccpairfunction.h @@ -33,8 +33,8 @@ struct CCFunction : public archive::ParallelSerializableObject { CCFunction(const Function& f) : current_error(99), function(f), i(99), type(UNDEFINED) {}; - CCFunction(const Function& f, const size_t& ii) : current_error(99), function(f), i(ii), type(UNDEFINED) {}; - +// CCFunction(const Function& f, const size_t& ii) : current_error(99), function(f), i(ii), type(UNDEFINED) {}; +// CCFunction(const Function& f, const size_t& ii, const FuncType& type_) : current_error(99), function(f), i(ii), type(type_) {}; @@ -720,9 +720,6 @@ using pureT=Function; }; -//template -//std::vector> swap_particles(const std::vector>& argument); - /// apply the operator to the argument /// the operator is applied to one particle only, the other one is left untouched @@ -741,7 +738,7 @@ CCPairFunction apply(const SeparatedConvolution& op, const CCP result=(CCPairFunction(tmp)); // !! confusing ordering of the result variables!! - if (op.particle()==2) result.swap_particles(); + if (op.particle()==2) result=result.swap_particles(); } else if (arg.is_decomposed_no_op()) { MADNESS_CHECK(op.particle()==1 or op.particle()==2); @@ -792,7 +789,6 @@ std::vector> apply(const ProjectorBase& projector, const } - template Function::LDIM>inner(const CCPairFunction& c, const Function::LDIM>& f, const std::tuple v1, const std::tuple v2) { @@ -803,6 +799,13 @@ Function::LDIM>inner(const CCPairFunction& c, c return c.partial_inner(f,v11,v22); } +template +Function::LDIM>inner(const CCPairFunction& c, const Function::LDIM>& f, + const std::array::LDIM>& v1, + const std::array::LDIM>& v2) { + return c.partial_inner(f,v1,v2); +} + template CCPairFunction inner(const CCPairFunction& c1, const CCPairFunction& c2, const std::tuple v1, const std::tuple v2) { @@ -813,10 +816,28 @@ CCPairFunction inner(const CCPairFunction& c1, const CCPairFunct return c1.partial_inner(c2,v11,v22); } +template +CCPairFunction inner(const CCPairFunction& c1, const CCPairFunction& c2, + const std::array::LDIM>& v1, + const std::array::LDIM>& v2) { + return c1.partial_inner(c2,v1,v2); +} + template std::vector> inner(const std::vector>& c1, const std::vector>& c2, const std::tuple v1, const std::tuple v2) { + constexpr std::size_t LDIM=CCPairFunction::LDIM; + auto v11=std::array({std::get<0>(v1),std::get<1>(v1),std::get<2>(v1)}); + auto v22=std::array({std::get<0>(v2),std::get<1>(v2),std::get<2>(v2)}); + return inner(c1,c2,v11,v22); +} + +template +std::vector> inner(const std::vector>& c1, + const std::vector>& c2, + const std::array::LDIM>& v1, + const std::array::LDIM>& v2) { std::vector> result; for (const auto& cc1 : c1) { for (const auto& cc2 : c2) { diff --git a/src/madness/chem/test_ccpairfunction.cc b/src/madness/chem/test_ccpairfunction.cc index 126418d3dfa..4fc52c5fc00 100644 --- a/src/madness/chem/test_ccpairfunction.cc +++ b/src/madness/chem/test_ccpairfunction.cc @@ -22,19 +22,19 @@ struct data { static constexpr std::size_t LDIM=NDIM/2; Function f1,f2,f3,f4,f5; Function f12,f23; + World& world; + CCParameters parameters; std::shared_ptr> f12_op; - data() {} - data(World& world, const CCParameters& parameters) { - if (not is_initialized()) initialize(world,parameters); - } + data(World& world, const CCParameters& parameters) : world(world), parameters(parameters){} bool is_initialized() const { return f1.is_initialized(); } - void initialize(World& world, const CCParameters& parameters) { + void initialize() { + print("initializing data for NDIM=",NDIM); f12_op.reset(new CCConvolutionOperator(world,OT_F12,parameters)); auto g1 = [](const Vector& r) { return exp(-1.0 * inner(r, r)); }; auto g2 = [](const Vector& r) { return exp(-2.0 * inner(r, r)); }; @@ -66,17 +66,19 @@ struct data { f12=FunctionFactory(world); f23=FunctionFactory(world); + std::string name_f12="test_ccpairfunction_f12_ndim_"+std::to_string(NDIM); + std::string name_f23="test_ccpairfunction_f23_ndim_"+std::to_string(NDIM); // try { -// load(f12,"test_ccpairfunction_f12"); +// load(f12,name_f12); // } catch (...) { f12 = FunctionFactory(world).f(g); -// save(f12,"test_ccpairfunction_f12"); +// save(f12,name_f12); // } // try { -// load(f23,"test_ccpairfunction_f23"); +// load(f23,name_f23); // } catch (...) { f23 = FunctionFactory(world).f(g23); -// save(f23,"test_ccpairfunction_f23"); +// save(f23,name_f23); // } } @@ -100,7 +102,8 @@ struct data { /// f5: exp(-5.0 r^2) /// f12: exp(-r_1^2 - 2 r_2^2) /// f23: exp(-r_1^2 - 2 r_2^2) + exp(-2 r_1^2 - 3 r_2^2) - auto get_functions() const { + auto get_functions() { + if (not is_initialized()) initialize(); return std::make_tuple(f1,f2,f3,f4,f5,f12); } @@ -111,7 +114,8 @@ struct data { /// p3: op_dec, corresponds to f23 /// p4: pure, corresponds to f23 /// p5: op_pure, corresponds to f23 - auto get_ccpairfunctions() const { + auto get_ccpairfunctions() { + if (not is_initialized()) initialize(); CCPairFunction p1(f12); CCPairFunction p2({f1,f2},{f2,f3}); CCPairFunction p3(f12_op,{f1,f2},{f2,f3}); @@ -123,60 +127,8 @@ struct data { }; -template -data& get_data(World& world, const CCParameters& parameters, bool initialize=true) { - static data data1; - if (not data1.is_initialized() and initialize) data1.initialize(world,parameters); - return data1; -} - -template -void clear_data(World& world, const CCParameters& parameters) { - auto data1=get_data(world,parameters,false); - data1.clear(); - world.gop.fence(); -} - - - - -/// Computes the electrostatic potential due to a Gaussian charge distribution - -/// stolen from testsuite.cc -class GaussianPotential : public FunctionFunctorInterface { -public: - typedef Vector coordT; - const coordT center; - const double exponent; - const double coefficient; - - GaussianPotential(const coordT& center, double expnt, double coefficient) - : center(center) - , exponent(sqrt(expnt)) - , coefficient(coefficient*pow(constants::pi/exponent,1.5)*pow(expnt,-0.75)) {} - - double operator()(const coordT& x) const { - double sum = 00; - for (int i=0; i<3; ++i) { - double xx = center[i]-x[i]; - sum += xx*xx; - }; - double r = sqrt(sum); - if (r<1.e-4) { // correct thru order r^3 - const double sqrtpi=sqrt(constants::pi); - const double a=exponent; - return coefficient*(2.0*a/sqrtpi - 2.0*a*a*a*r*r/(3.0*sqrtpi)); - } else { - return coefficient*erf(exponent*r)/r; - } - } -}; - - - - template -int test_constructor(World& world, std::shared_ptr ncf, const data& data, +int test_constructor(World& world, std::shared_ptr ncf, data& data, const CCParameters& parameter) { test_output t1("constructor"); static_assert(NDIM%2==0, "NDIM must be even"); @@ -242,10 +194,10 @@ int test_constructor(World& world, std::shared_ptr ncf } template -int test_operator_apply(World& world, std::shared_ptr ncf, const data& data, +int test_operator_apply(World& world, std::shared_ptr ncf, data& data, const CCParameters& parameter) { test_output t1("test_operator_apply"); -// t1.set_cout_to_terminal(); + t1.set_cout_to_terminal(); static_assert(NDIM%2==0, "NDIM must be even"); constexpr std::size_t LDIM=NDIM/2; @@ -259,37 +211,90 @@ int test_operator_apply(World& world, std::shared_ptr return coefficient * exp(-exponent*inner(r-center,r-center)); }; - // this won't work, the simulation cell is only [-1,1].. - // Normalized Gaussian exponent a produces potential erf(sqrt(a)*r)/r -// GaussianPotential gpot(center, exponent, coefficient); -// real_function_3d op_a=real_factory_3d(world).functor(gpot); + exponent=1.5; + Function i=FunctionFactory(world).functor(Gaussian); + exponent=2.5; + Function j=FunctionFactory(world).functor(Gaussian); - Function a=FunctionFactory(world).functor(Gaussian); - exponent=2.0; - Function b=FunctionFactory(world).functor(Gaussian); + auto gop= BSHOperator(world,0.5,1.e-5,std::min(1.e-4,FunctionDefaults::get_thresh())); auto [f1,f2,f3,f4,f5,ff]=data.get_functions(); - CCPairFunction c1(a,b); - CCPairFunction c2(f1,f2); -// CCPairFunction ref(op_a,b); - auto op= CoulombOperator_ndim(world,1.e-5,FunctionDefaults::get_thresh()); - op.print_timings=false; - op.particle()=1; - - auto op_c1=op(c1); - auto op_c2=op(c2); -// double a1=inner(ref,ref); - double norm1=inner(op_c1,op_c1); - double norm2=inner(op_c2,op_c2); - print("norm1,norm2",norm1,norm2); - bool good=fabs(norm1-norm2)::get_thresh(); - t1.checkpoint(good,"op(xx)"); + auto [p1,p2,p3,p4,p5]=data.get_ccpairfunctions(); // p2-p5 correspond to f23 + // p2: dec, corresponds to f23 + // p3: op_dec, corresponds to f23 + // p4: pure, corresponds to f23 + // p5: op_pure, corresponds to f23 + + // integrate over particle 2: | u(1,3)> = g(1,2) uu(2,3), project u(1,3) onto bra = + // reference for p1, p3: + // = = + // + // note that the ccpairfunctions always have 2 terms + // CCPairFunction p2({f1,f2},{f2,f3}); + // with l=f1, k=f2; and l=f2, k=f3 + + auto& fop=*(data.f12_op->get_op()); + Function gi=gop(i); + + Function k_1=f1; + Function l_1=f2; + Function f_lj_1=fop(l_1*j); + Function f_kj_1=fop(k_1*j); + + Function k_2=f2; + Function l_2=f3; + Function f_lj_2=fop(l_2*j); + Function f_kj_2=fop(k_2*j); + + CCPairFunction bra(i,j); + + double ref_p2p4=(gi*k_1*f_lj_1).trace() + (gi*k_2*f_lj_2).trace(); + double ref_p1p3=(gi*k_1).trace() * (j*l_1).trace() + (gi*k_2).trace() * (j*l_2).trace(); + std::vector reference({ref_p1p3,ref_p2p4,ref_p1p3,ref_p2p4}); + + int counter=0; + + for (auto& p : {p2,p3,p4,p5}) { + gop.particle() = 1; + auto tmp1=gop(p); + double result=inner(bra,tmp1); + double ref=reference[counter++]; + print("p=",p.name(),"result=",result,"reference=",ref); + t1.checkpoint(result,ref,FunctionDefaults::get_thresh(),"op(1) to "+p.name()); + } + + // integrate over particle 3: | u(1,2)> = g(1,3) uu(2,3), project u(1,2) onto bra = + // reference for p1, p3: + // = = + // note the ordering of the indices in the ket! the above line is equivalent to + // = + ref_p2p4=(gi*l_1*f_kj_1).trace() + (gi*l_2*f_kj_2).trace(); + ref_p1p3=(gi*l_1).trace() * (j*k_1).trace() + (gi*l_2).trace() * (j*k_2).trace(); + reference=std::vector({ref_p1p3,ref_p2p4,ref_p1p3,ref_p2p4}); + + counter=0; + CCPairFunction bra_ji(j,i); + for (auto& p : {p2,p3,p4,p5}) { + gop.particle() = 2; + auto tmp1=gop(p); + double result=inner(bra,tmp1); + double ref=reference[counter++]; + print("p=",p.name(),"result=",result,"reference=",ref); + t1.checkpoint(result,ref,FunctionDefaults::get_thresh(),"op(2) to "+p.name()); + } + + + return t1.end(); } template -int test_transformations(World& world, std::shared_ptr ncf, const data& data, +int test_transformations(World& world, std::shared_ptr ncf, data& data, const CCParameters& parameter) { test_output t1("test_transformations"); static_assert(NDIM%2==0, "NDIM must be even"); @@ -331,7 +336,7 @@ int test_transformations(World& world, std::shared_ptr } template -int test_multiply_with_f12(World& world, std::shared_ptr ncf, const data& data, +int test_multiply_with_f12(World& world, std::shared_ptr ncf, data& data, const CCParameters& parameters) { test_output t1("test_multiply_with_f12"); static_assert(NDIM%2==0, "NDIM must be even"); @@ -377,7 +382,7 @@ int test_multiply_with_f12(World& world, std::shared_ptr -int test_multiply(World& world, std::shared_ptr ncf, const data& data, +int test_multiply(World& world, std::shared_ptr ncf, data& data, const CCParameters& parameters) { test_output t1("test_multiply<"+std::to_string(NDIM)+">"); static_assert(NDIM%2==0, "NDIM must be even"); @@ -421,7 +426,7 @@ int test_multiply(World& world, std::shared_ptr ncf, c } template -int test_inner(World& world, std::shared_ptr ncf, const data& data, +int test_inner(World& world, std::shared_ptr ncf, data& data, const CCParameters& parameters) { test_output t1("test_inner<"+std::to_string(NDIM)+">"); static_assert(NDIM%2==0, "NDIM must be even"); @@ -493,9 +498,9 @@ int test_inner(World& world, std::shared_ptr ncf, cons double result=inner(bra,ket); print(bra.name(true)+ket.name(),"ref, result, diff", ref, result, ref-result); - double thresh=FunctionDefaults<3>::get_thresh(); + double thresh=FunctionDefaults::get_thresh(); bool good=(fabs(result-ref) ncf, cons template -int test_partial_inner_6d(World& world, std::shared_ptr ncf, const data& data, +int test_partial_inner_6d(World& world, std::shared_ptr ncf, data& data, const CCParameters& parameter) { - CCTimer timer(world, "testing"); - test_output t1("CCPairFunction::test_partial_inner_6d"); + test_output t1("test_partial_inner6d<"+std::to_string(NDIM)+">"); + static_assert(NDIM%2==0, "NDIM must be even"); + constexpr std::size_t LDIM=NDIM/2; t1.set_cout_to_terminal(); // auto data=get_data<6>(world,parameter); auto [f1,f2,f3,f4,f5,f] = data.get_functions(); - std::vector a = {f1, f2}; - std::vector b = {f2, f3}; + std::vector> a = {f1, f2}; + std::vector> b = {f2, f3}; - auto f12=CCConvolutionOperatorPtr(world, OT_F12, parameter); + auto f12=CCConvolutionOperatorPtr(world, OT_F12, parameter); auto [p1,p2,p3,p4,nil]=data.get_ccpairfunctions(); - CCPairFunction p11({f1},{f1}); - CCPairFunction p12({f1},{f2}); + CCPairFunction p11({f1},{f1}); + CCPairFunction p12({f1},{f2}); double g11=inner(f1,f1); double g22=inner(f2,f2); @@ -527,23 +533,30 @@ int test_partial_inner_6d(World& world, std::shared_ptr gf11=(*f12)(f1*f1); + Function gf12=(*f12)(f1*f2); + Function gf22=(*f12)(f2*f2); + Function gf13=(*f12)(f1*f3); + Function gf23=(*f12)(f2*f3); - t1.checkpoint(true,"prep",timer.reset()); + t1.checkpoint(true,"prep"); + + auto particle1=std::array(); + auto particle2=std::array(); + for (int i=0; i r1=inner(test_p1,test_p2,{0,1,2},{0,1,2}); - CCPairFunction r2=inner(test_p1,test_p2,{0,1,2},{3,4,5}); - CCPairFunction r3=inner(test_p1,test_p2,{3,4,5},{0,1,2}); - CCPairFunction r4=inner(test_p1,test_p2,{3,4,5},{3,4,5}); + CCPairFunction r1=inner(test_p1,test_p2,particle1,particle1); + CCPairFunction r2=inner(test_p1,test_p2,particle1,particle2); + CCPairFunction r3=inner(test_p1,test_p2,particle2,particle1); + CCPairFunction r4=inner(test_p1,test_p2,particle2,particle2); double n1=inner(r1,p11); double n2=inner(r2,p11); @@ -562,7 +575,7 @@ int test_partial_inner_6d(World& world, std::shared_ptr::get_thresh(); t1.checkpoint(good,test_p1.name(true)+test_p2.name()+" -- 3"); good=fabs(n4-ref_n4)::get_thresh(); - t1.checkpoint(good,test_p1.name(true)+test_p2.name()+" -- 4",timer.reset()); + t1.checkpoint(good,test_p1.name(true)+test_p2.name()+" -- 4"); } } @@ -570,12 +583,12 @@ int test_partial_inner_6d(World& world, std::shared_ptr // CCPairFunction p2({f1,f2},{f2,f3}); // CCPairFunction p4(f23); // two-term, corresponds to p2 - CCPairFunction p5(f12,std::vector({f1}),std::vector({f2})); + CCPairFunction p5(f12,std::vector>({f1}),std::vector>({f2})); for (auto& test_p1 : {p2, p4}) { - CCPairFunction r1=inner(test_p1,p5,{0,1,2},{0,1,2}); - CCPairFunction r2=inner(test_p1,p5,{0,1,2},{3,4,5}); - CCPairFunction r3=inner(test_p1,p5,{3,4,5},{0,1,2}); - CCPairFunction r4=inner(test_p1,p5,{3,4,5},{3,4,5}); + CCPairFunction r1=inner(test_p1,p5,particle1,particle1); + CCPairFunction r2=inner(test_p1,p5,particle1,particle2); + CCPairFunction r3=inner(test_p1,p5,particle2,particle1); + CCPairFunction r4=inner(test_p1,p5,particle2,particle2); double ref_n1=inner(gf11,f2*f1) * g12 + inner(gf12,f1*f2) * g13; double ref_n2=inner(gf12,f1*f1) * g12 + inner(gf22,f1*f1) * g13; @@ -598,7 +611,7 @@ int test_partial_inner_6d(World& world, std::shared_ptr::get_thresh(); t1.checkpoint(good,test_p1.name(true)+p5.name()+" -- 3"); good=fabs(n4-ref_n4)::get_thresh(); - t1.checkpoint(good,test_p1.name(true)+p5.name()+" -- 4",timer.reset()); + t1.checkpoint(good,test_p1.name(true)+p5.name()+" -- 4"); } @@ -606,23 +619,18 @@ int test_partial_inner_6d(World& world, std::shared_ptr p3(f12_op.get(),{f1,f2},{f2,f3}); // CCPairFunction p5(&f12,{f1},{f2}); if (longtest) { - CCPairFunction r1=inner(p3,p5,{0,1,2},{0,1,2}); - print("time after r1 ", timer.reset()); + CCPairFunction r1=inner(p3,p5,particle1,particle1); double n1=inner(r1,p11); p3.convert_to_pure_no_op_inplace(); p5.convert_to_pure_no_op_inplace(); print("n1",n1); - print("time after r2a ", timer.reset()); - CCPairFunction r1a=inner(p3,p5,{0,1,2},{0,1,2}); + CCPairFunction r1a=inner(p3,p5,particle1,particle1); double n1a=inner(r1a,p11); print("n1a",n1a); print("diff",n1-n1a); - CCPairFunction r2=inner(p3,p5,{0,1,2},{3,4,5}); - print("time after r2 ", timer.reset()); - CCPairFunction r3=inner(p3,p5,{3,4,5},{0,1,2}); - print("time after r3 ", timer.reset()); - CCPairFunction r4=inner(p3,p5,{3,4,5},{3,4,5}); - print("time after r4 ", timer.reset()); + CCPairFunction r2=inner(p3,p5,particle1,particle2); + CCPairFunction r3=inner(p3,p5,particle2,particle1); + CCPairFunction r4=inner(p3,p5,particle2,particle2); } return t1.end(); @@ -630,103 +638,109 @@ int test_partial_inner_6d(World& world, std::shared_ptr -int test_partial_inner_3d(World& world, std::shared_ptr ncf, const data& data, +int test_partial_inner_3d(World& world, std::shared_ptr ncf, data& data, const CCParameters& parameter) { - CCTimer timer(world, "testing"); - test_output t1("CCPairFunction::test_partial_inner"); -// auto data=get_data<6>(world,parameter); + test_output t1("test_partial_inner<"+std::to_string(NDIM)+">"); + t1.set_cout_to_terminal(); + static_assert(NDIM%2==0, "NDIM must be even"); + constexpr std::size_t LDIM=NDIM/2; auto [f1,f2,f3,f4,f5,f] = data.get_functions(); - std::vector a = {f1, f2}; - std::vector b = {f2, f3}; + auto particle1=std::array(); + auto particle2=std::array(); + for (int i=0; i> a = {f1, f2}; + std::vector> b = {f2, f3}; - auto f12=CCConvolutionOperatorPtr(world, OT_F12, parameter); + auto f12=CCConvolutionOperatorPtr(world, OT_F12, parameter); - CCPairFunction p1(f); // e(-r1 - 2r2) - CCPairFunction p2(a,b); - CCPairFunction p3(f12,a,b); - CCPairFunction p11({f1},{f1}); - CCPairFunction p12({f1},{f2}); + CCPairFunction p1(f); // e(-r1 - 2r2) + CCPairFunction p2(a,b); + CCPairFunction p3(f12,a,b); + CCPairFunction p11({f1},{f1}); + CCPairFunction p12({f1},{f2}); double g11=inner(f1,f1); double g22=inner(f2,f2); double g12=inner(f1,f2); double g13=inner(f1,f3); double g23=inner(f2,f3); - real_function_3d gf11=(*f12)(f1*f1); - real_function_3d gf12=(*f12)(f1*f2); - real_function_3d gf13=(*f12)(f1*f3); + Function gf11=(*f12)(f1*f1); + Function gf12=(*f12)(f1*f2); + Function gf13=(*f12)(f1*f3); print("g11, g22",g11,g22); - print("time in preparation",timer.reset()); + double thresh=FunctionDefaults::get_thresh(); + t1.checkpoint(true,"prep"); // test pure/3d { - real_function_3d r=inner(p1,f1,{0,1,2},{0,1,2}); + double aa=inner(p1,p1); + print("aa",aa); + // < e1 e2 | e1 >_1 = | e2 > ||e1|| + Function r=inner(p1,f1,particle1,particle1); double norm=inner(r,f2); double ref_norm=g11 * g22; - print("norm, ref_norm",norm,ref_norm); - bool good=fabs(norm-ref_norm)::get_thresh(); - t1.checkpoint(good,"pure -- 1"); + print("norm ",norm); + print("ref_norm", ref_norm); + Function r_swap=inner(p1,f1,particle2,particle1); + double norm_swap=inner(r_swap,f2); + print("norm1 swap",norm_swap); + t1.checkpoint(norm,ref_norm,thresh,"pure -- 1"); } // test pure/3d { - real_function_3d r=inner(p1,f1,{3,4,5},{0,1,2}); + Function r=inner(p1,f1,particle2,particle1); double norm=inner(r,f2); double ref_norm=g12 * g12; - print("norm, ref_norm",norm,ref_norm); - bool good=fabs(norm-ref_norm)::get_thresh(); - t1.checkpoint(good,"pure -- 2"); + t1.checkpoint(norm, ref_norm, thresh,"pure -- 2"); } // test decomposed { - real_function_3d r=inner(p2,f1,{0,1,2},{0,1,2}); + Function r=inner(p2,f1,particle1,particle1); double norm=inner(r,f2); double ref_norm=g11 * g22 + g12 * g23; - print("norm, ref_norm",norm,ref_norm); - bool good=fabs(norm-ref_norm)::get_thresh(); - t1.checkpoint(good,"decomposed -- 1"); + t1.checkpoint(norm, ref_norm, thresh,"decomposed -- 1"); } // test decomposed { - real_function_3d r=inner(p2,f1,{3,4,5},{0,1,2}); + Function r=inner(p2,f1,particle2,particle1); double norm=inner(r,f2); double ref_norm=g12 * g12 + g13 * g22; - print("norm, ref_norm",norm,ref_norm); - bool good=fabs(norm-ref_norm)::get_thresh(); - t1.checkpoint(good,"decomposed -- 2"); + t1.checkpoint(norm, ref_norm, thresh,"decomposed -- 2"); } // test op_decomposed { // < f1 f2 | f | f1 f2 > + < f1 f2 | f | f2 f3> - real_function_3d r=inner(p3,f1,{0,1,2},{0,1,2}); + Function r=inner(p3,f1,particle1,particle1); double norm=inner(r,f2); double ref_norm=inner(gf11*f2,f2) + inner(gf12*f2,f3); - print("norm, ref_norm",norm,ref_norm); - bool good=fabs(norm-ref_norm)::get_thresh(); - t1.checkpoint(good,"op_decomposed -- 1"); + t1.checkpoint(norm, ref_norm, thresh,"op_decomposed -- 1"); } // test op_decomposed { // < f1 f2 | f | f2 f1 > + < f1 f2 | f | f3 f2> - real_function_3d r=inner(p3,f1,{3,4,5},{0,1,2}); + Function r=inner(p3,f1,particle2,particle1); double norm=inner(r,f2); double ref_norm=inner(gf12*f1,f2) + inner(gf13*f2,f2); - print("norm, ref_norm",norm,ref_norm); - bool good=fabs(norm-ref_norm)::get_thresh(); - t1.checkpoint(good,"op_decomposed -- 2"); + t1.checkpoint(norm, ref_norm, thresh,"op_decomposed -- 2"); } - - return (t1.get_final_success()) ? 0 : 1; + return t1.end(); } template -int test_apply(World& world, std::shared_ptr ncf, const data& data, +int test_apply(World& world, std::shared_ptr ncf, data& data, const CCParameters& parameter) { test_output t1("CCPairFunction::test_apply"); + static_assert(NDIM%2==0, "NDIM must be even"); + constexpr std::size_t LDIM=NDIM/2; t1.set_cout_to_terminal(); /// f12: exp(-r_1^2 - 2 r_2^2) @@ -740,16 +754,16 @@ int test_apply(World& world, std::shared_ptr ncf, cons auto [p1,p2,p3,p4,p5]=data.get_ccpairfunctions(); auto [f1,f2,f3,f4,f5,f]=data.get_functions(); - auto f12=CCConvolutionOperatorPtr(world, OT_F12, parameter); + auto f12=CCConvolutionOperatorPtr(world, OT_F12, parameter); auto& op=*(f12->get_op()); - std::vector> vp2({p2}); - std::vector> vp2ex({p2.swap_particles()}); + std::vector> vp2({p2}); + std::vector> vp2ex({p2.swap_particles()}); // tmp(2) = \int a(1)b(2') f(1,2) d1 // result=inner(tmp,f1); for (auto& p : {p1,p2,p3,p4,p5}) { print("working on ",p.name()); - std::vector> vp({p}); + std::vector> vp({p}); op.set_particle(1); auto op1_p=op(vp); double r1=inner(vp2,op1_p); @@ -762,14 +776,13 @@ int test_apply(World& world, std::shared_ptr ncf, cons double r2ex=inner(vp2ex,op2_p); printf("r2 %12.8f\n",r2); printf("r2ex %12.8f\n",r2ex); - } return t1.end(); } template -int test_scalar_multiplication(World& world, std::shared_ptr ncf, const data& data, +int test_scalar_multiplication(World& world, std::shared_ptr ncf, data& data, const CCParameters& parameter) { CCTimer timer(world, "testing"); test_output t1("CCPairFunction::test_scalar_multiplication"); @@ -813,7 +826,7 @@ int test_scalar_multiplication(World& world, std::shared_ptr -int test_swap_particles(World& world, std::shared_ptr ncf, const data& data, +int test_swap_particles(World& world, std::shared_ptr ncf, data& data, const CCParameters& parameters) { test_output t1("swap_particles<"+std::to_string(NDIM)+">"); static_assert(NDIM%2==0, "NDIM must be even"); @@ -890,23 +903,26 @@ int test_swap_particles(World& world, std::shared_ptr template -int test_projector(World& world, std::shared_ptr ncf, const data& data, +int test_projector(World& world, std::shared_ptr ncf, data& data, const CCParameters& parameter) { - test_output t1("CCPairFunction::test_projector"); + test_output t1("test_projector<"+std::to_string(NDIM)+">"); + static_assert(NDIM%2==0, "NDIM must be even"); + constexpr std::size_t LDIM=NDIM/2; // t1.set_cout_to_logger(); t1.set_cout_to_terminal(); -// auto data=get_data<6>(world,parameter); - auto [f1,f2,f3,f4,f5,f] = data.get_functions(); + const auto [f11,f22,f3,f4,f5,f] = data.get_functions(); + auto f1=copy(f11); // keep f1, f2 constant for use in other tests! + auto f2=copy(f22); double nf1=f1.norm2(); double nf2=f2.norm2(); f1.scale(1.0/nf1); f2.scale(1.0/nf1); - std::vector a = {f1+f2, f2+f3, f3+f4}; - std::vector b = {f3, f1, f2}; - std::vector o = orthonormalize_cd({f1-f3, f5}); // projects on an orthonormal basis - a = orthonormalize_cd(a); // projects on an orthonormal basis - auto f12=CCConvolutionOperatorPtr(world, OT_F12, parameter); + std::vector> a = {f1+f2, f2+f3, f3+f4}; + std::vector> b = {f3, f1, f2}; + std::vector> o = orthonormalize_cd({f1-f3, f5}); // projects on an orthonormal basis + a = orthonormalize_cd(a); // projects on an orthonormal basis + auto f12=CCConvolutionOperatorPtr(world, OT_F12, parameter); { double n1=inner(f1,o[0]); @@ -915,56 +931,56 @@ int test_projector(World& world, std::shared_ptr ncf, print("", ovlp); } - CCPairFunction p1(a,b); - CCPairFunction p2(f12,a,b); - CCPairFunction p3(f); // outer (f1,f2) + CCPairFunction p1(a,b); + CCPairFunction p2(f12,a,b); + CCPairFunction p3(f); // outer (f1,f2) - std::vector> vp1({p1}); - std::vector> vp2({p2}); - std::vector> vp3({p3}); + std::vector> vp1({p1}); + std::vector> vp2({p2}); + std::vector> vp3({p3}); - Projector O(o,o); - QProjector Q(world,o,o); - StrongOrthogonalityProjector Q12(world); + Projector O(o,o); + QProjector Q(world,o,o); + StrongOrthogonalityProjector Q12(world); Q12.set_spaces(o); - double thresh=FunctionDefaults<3>::get_thresh(); + double thresh=FunctionDefaults::get_thresh(); // compute reference values as: ( // compute result values as: ) - real_function_3d of1=O(f1); - real_function_3d of2=O(f2); - real_function_3d qf1=Q(f1); - real_function_3d qf2=Q(f2); - std::vector>> vp({vp1,vp2,vp3}); + Function of1=O(f1); + Function of2=O(f2); + Function qf1=Q(f1); + Function qf2=Q(f2); + std::vector>> vp({vp1,vp2,vp3}); for (int i=0; i<3; ++i) { // O1 O.set_particle(0); { - double ref=inner({CCPairFunction({of1},{f2})},vp[i]); - double result=inner({CCPairFunction({f1},{f2})},O(vp[i])); + double ref=inner({CCPairFunction({of1},{f2})},vp[i]); + double result=inner({CCPairFunction({f1},{f2})},O(vp[i])); t1.checkpoint(result,ref,thresh,"O1 p"+std::to_string(i)); } // O2 O.set_particle(1); { - double ref=inner({CCPairFunction({f1},{of2})},vp[i]); - double result=inner({CCPairFunction({f1},{f2})},O(vp[i])); + double ref=inner({CCPairFunction({f1},{of2})},vp[i]); + double result=inner({CCPairFunction({f1},{f2})},O(vp[i])); t1.checkpoint(result,ref,thresh,"O2 p"+std::to_string(i)); } // Q1 Q.set_particle(0); { - double ref=inner({CCPairFunction({qf1},{f2})},vp[i]); - double result=inner({CCPairFunction({f1},{f2})},Q(vp[i])); + double ref=inner({CCPairFunction({qf1},{f2})},vp[i]); + double result=inner({CCPairFunction({f1},{f2})},Q(vp[i])); t1.checkpoint(result,ref,thresh,"Q1 p"+std::to_string(i)); } // Q2 Q.set_particle(1); { - double ref=inner({CCPairFunction({f1},{qf2})},vp[i]); - double result=inner({CCPairFunction({f1},{f2})},Q(vp[i])); + double ref=inner({CCPairFunction({f1},{qf2})},vp[i]); + double result=inner({CCPairFunction({f1},{f2})},Q(vp[i])); t1.checkpoint(result,ref,thresh,"Q2 p"+std::to_string(i)); } } @@ -976,10 +992,10 @@ int test_projector(World& world, std::shared_ptr ncf, double ak=ak_tensor.trace(ak_tensor); auto aa=matrix_inner(world,a,a); auto bb=matrix_inner(world,b,b); - Projector O1(a,a); + Projector O1(a,a); O.set_particle(0); O1.set_particle(0); - Projector O2(a,a); + Projector O2(a,a); O2.set_particle(1); double n1=inner(vp1,O1(vp2)); double n1a=inner(O1(vp1),vp2); @@ -997,8 +1013,8 @@ int test_projector(World& world, std::shared_ptr ncf, { int i=0; for (auto p : {p1,p2,p3}) { - std::string s="CCPairFunction p"+std::to_string(++i); - std::vector> vp({p}); + std::string s="CCPairFunction p"+std::to_string(++i); + std::vector> vp({p}); for (int particle : {0,1}) { O.set_particle(particle); Q.set_particle(particle); @@ -1008,13 +1024,13 @@ int test_projector(World& world, std::shared_ptr ncf, double n1 = inner(Op, vp3) + inner(Qp, vp3); double n2 = inner(vp, vp3); print("n1 (RI), n2", n1, n2, fabs(n1 - n2)); - t1.checkpoint(fabs(n1 - n2) < FunctionDefaults<3>::get_thresh(), "RI with particle "+std::to_string(particle)+" on "+s); + t1.checkpoint(fabs(n1 - n2) < FunctionDefaults::get_thresh(), "RI with particle "+std::to_string(particle)+" on "+s); auto Op1 = O(Op); double n3=inner(Op, vp3); double n4=inner(Op1, vp3); print("n3, n4", n3, n4); - t1.checkpoint(fabs(n3-n4) < FunctionDefaults<3>::get_thresh(), "idempotency with particle "+std::to_string(particle)+" on "+s); + t1.checkpoint(fabs(n3-n4) < FunctionDefaults::get_thresh(), "idempotency with particle "+std::to_string(particle)+" on "+s); } // testing SO projector @@ -1044,82 +1060,6 @@ int test_projector(World& world, std::shared_ptr ncf, } -/// testing = 0.032 mEh -int test_helium(World& world, std::shared_ptr ncf, - const CCParameters& parameters) { - - test_output t1("CCPairFunction::test_helium"); - CCTimer timer(world, "testing"); - - real_function_3d Vnuc = real_factory_3d(world).f([](const coord_3d& r) {return -2.0/(r.normf()+1.e-8);}); - real_function_3d psi = real_factory_3d(world).f([](const coord_3d& r) {return exp(-r.normf());}); - - auto iterate=[&world](const real_function_3d& potential, real_function_3d& psi, double& eps) { - real_convolution_3d op = BSHOperator3D(world, sqrt(-2*eps), 0.001, 1e-6); - real_function_3d Vpsi = (potential*psi); - Vpsi.scale(-2.0).truncate(); - real_function_3d tmp = op(Vpsi).truncate(); - double norm = tmp.norm2(); - real_function_3d r = tmp-psi; - double rnorm = r.norm2(); - double eps_new = eps - 0.5*inner(Vpsi,r)/(norm*norm); - if (world.rank() == 0) { - print("norm=",norm," eps=",eps," err(psi)=",rnorm," err(eps)=",eps_new-eps); - } - psi = tmp.scale(1.0/norm); - eps = eps_new; - }; - psi.truncate(); - psi.scale(1.0/psi.norm2()); - double eps = -0.6; - real_convolution_3d op = CoulombOperator(world, 0.001, 1e-6); - for (int iter=0; iter<10; iter++) { - real_function_3d rho = square(psi).truncate(); - real_function_3d potential = Vnuc + op(rho).truncate(); - iterate(potential, psi, eps); - } - double kinetic_energy = 0.0; - for (int axis=0; axis<3; axis++) { - real_derivative_3d D = free_space_derivative(world, axis); - real_function_3d dpsi = D(psi); - kinetic_energy += inner(dpsi,dpsi); - } - real_function_3d rho = square(psi); - double two_electron_energy = inner(op(rho),rho); - double nuclear_attraction_energy = 2.0*inner(Vnuc,rho); - double total_energy = kinetic_energy + two_electron_energy + nuclear_attraction_energy; - - t1.checkpoint(fabs(total_energy+2.8616533)<1.e-4,"helium iterations",timer.reset()); - print("ke, total", kinetic_energy, total_energy); - - - CCConvolutionOperator::Parameters param; - auto f=CCConvolutionOperatorPtr(world,OT_F12,param); - auto g=CCConvolutionOperatorPtr(world,OT_G12,param); - - CCPairFunction fij(f,psi,psi); - CCPairFunction gij(g,psi,psi); - CCPairFunction ij({psi},{psi}); - std::vector> vfij={fij}; - std::vector> vgij={gij}; - std::vector> vij={ij}; - - StrongOrthogonalityProjector SO(world); - SO.set_spaces({psi},{psi},{psi},{psi}); - std::vector> Qfij=SO(vfij); - std::vector> Qgij=SO(vgij); - - double result1=inner(vgij,Qfij); - print(")",result1); - double result2=inner(vfij,Qgij); - print("(",result2); - bool good=fabs(result1-result2)<1.e-5; - good=good and fabs(result1+3.2624783e-02)<1.e-5; - t1.checkpoint(good,"V matrix element",timer.reset()); - - return (t1.get_final_success()) ? 0 : 1; - -} /** functionality * @@ -1142,8 +1082,8 @@ int main(int argc, char **argv) { madness::World& world = madness::initialize(argc, argv); startup(world, argc, argv); commandlineparser parser(argc, argv); - int k=6; - double thresh=1.e-5; + int k=5; + double thresh=1.e-4; if (parser.key_exists("k")) k=std::stoi(parser.value("k")); if (parser.key_exists("thresh")) thresh=std::stod(parser.value("thresh")); FunctionDefaults<1>::set_k(k); @@ -1181,45 +1121,44 @@ int main(int argc, char **argv) { auto data2=data(world,ccparam); auto data4=data(world,ccparam); -// auto data6=data(world,ccparam); + auto data6=data(world,ccparam); isuccess+=test_constructor(world, ncf, data2, ccparam); - isuccess+=test_constructor(world, ncf, data4, ccparam); isuccess+=test_operator_apply(world, ncf, data2, ccparam); - isuccess+=test_operator_apply(world, ncf, data4, ccparam); isuccess+=test_transformations(world, ncf, data2, ccparam); - isuccess+=test_transformations(world, ncf, data4, ccparam); isuccess+=test_multiply_with_f12(world, ncf, data2, ccparam); - isuccess+=test_multiply_with_f12(world, ncf, data4, ccparam); isuccess+=test_inner(world, ncf, data2, ccparam); - isuccess+=test_inner(world, ncf, data4, ccparam); isuccess+=test_multiply(world, ncf, data2, ccparam); - isuccess+=test_multiply(world, ncf, data4, ccparam); isuccess+=test_swap_particles(world, ncf, data2, ccparam); - isuccess+=test_swap_particles(world, ncf, data4, ccparam); isuccess+=test_scalar_multiplication(world, ncf, data2, ccparam); - isuccess+=test_scalar_multiplication(world, ncf, data4, ccparam); - -// isuccess+=test_partial_inner_3d(world, ncf, data2, ccparam); + isuccess+=test_projector(world, ncf, data2, ccparam); + isuccess+=test_partial_inner_3d(world, ncf, data2, ccparam); + isuccess+=test_partial_inner_6d(world, ncf, data2, ccparam); + isuccess+=test_apply(world, ncf, data2, ccparam); + +// isuccess+=test_constructor(world, ncf, data4, ccparam); +// isuccess+=test_operator_apply(world, ncf, data4, ccparam); +// isuccess+=test_transformations(world, ncf, data4, ccparam); +// isuccess+=test_multiply_with_f12(world, ncf, data4, ccparam); +// isuccess+=test_inner(world, ncf, data4, ccparam); +// isuccess+=test_multiply(world, ncf, data4, ccparam); +// isuccess+=test_swap_particles(world, ncf, data4, ccparam); +// isuccess+=test_scalar_multiplication(world, ncf, data4, ccparam); +// isuccess+=test_projector(world, ncf, data4, ccparam); +// isuccess+=test_partial_inner_3d(world, ncf, data4, ccparam); // isuccess+=test_partial_inner_6d(world, ncf, data4, ccparam); - FunctionDefaults<3>::set_thresh(1.e-5); - FunctionDefaults<3>::set_cubic_cell(-10.,10.); - FunctionDefaults<6>::set_thresh(1.e-3); - FunctionDefaults<6>::set_cubic_cell(-10.,10.); // isuccess+=test_apply(world, ncf, data, ccparam); -// isuccess+=test_projector(world, ncf, mol, ccparam); -// FunctionDefaults<3>::set_cubic_cell(-10,10); -// isuccess+=test_helium(world,ncf,ccparam); + + +// isuccess+=test_projector(world, ncf, data6, ccparam); + data2.clear(); data4.clear(); -// data6.clear(); + data6.clear(); world.gop.fence(); } catch (std::exception& e) { madness::print("an error occured"); madness::print(e.what()); - clear_data<2>(world,ccparam); - clear_data<4>(world,ccparam); - clear_data<6>(world,ccparam); world.gop.fence(); } world.gop.fence(); diff --git a/src/madness/mra/funcimpl.h b/src/madness/mra/funcimpl.h index 3972886dff8..0b119e5a035 100644 --- a/src/madness/mra/funcimpl.h +++ b/src/madness/mra/funcimpl.h @@ -6593,27 +6593,57 @@ template if (fcoeff.has_no_data() or gcoeff.has_no_data()) return Future (argT(fnode.is_leaf(),coeffT()));; - // let's specialize for the time being on SVD tensors for f and full tensors of half dim for g - MADNESS_ASSERT(gcoeff.is_full_tensor()); - MADNESS_ASSERT(fcoeff.is_svd_tensor()); - const tensorT gtensor=gcoeff.full_tensor(); + MADNESS_CHECK(gcoeff.is_full_tensor()); tensorT final(result->cdata.vk); - - const int otherdim=(dim+1)%2; const int k=fcoeff.dim(0); - std::vector s(fcoeff.get_svdtensor().dim_per_vector(dim)+1,_); - std::vector other_s(fcoeff.get_svdtensor().dim_per_vector(otherdim)+1,_); - - // do the actual contraction - std::vector shape(LDIM,k); - for (int r=0; r shape(LDIM, k); + + if (fcoeff.is_full_tensor()) { + // result_i = \sum_j g_j f_ji + const tensorT gtensor = gcoeff.full_tensor().reshape(k_ldim); + const tensorT ftensor = fcoeff.full_tensor().reshape(k_ldim,k_ldim); + final=inner(gtensor,ftensor,0,dim).reshape(shape); + + } else if (fcoeff.is_svd_tensor()) { + if (fcoeff.rank()>0) { + + // result_i = \sum_jr g_j a_rj w_r b_ri + const int otherdim = (dim + 1) % 2; + const tensorT gtensor = gcoeff.full_tensor().flat(); + const tensorT atensor = fcoeff.get_svdtensor().flat_vector(dim); // a_rj + const tensorT btensor = fcoeff.get_svdtensor().flat_vector(otherdim); + const tensorT gatensor = inner(gtensor, atensor, 0, 1); // ga_r + tensorT weights = copy(fcoeff.get_svdtensor().weights_); + weights.emul(gatensor); // ga_r * w_r + // sum over all ranks of b, include new weights: + // result_i = \sum_r ga_r * w_r * b_ri + for (int r = 0; r < fcoeff.rank(); ++r) final += weights(r) * btensor(r, _); + final = final.reshape(shape); + } + + } else { + MADNESS_EXCEPTION("unsupported tensor type in project_out_op",1); + } + if (0) { + const tensorT gtensor = gcoeff.full_tensor(); + + const int otherdim = (dim + 1) % 2; + const int k = fcoeff.dim(0); + std::vector s(fcoeff.get_svdtensor().dim_per_vector(dim) + 1, _); + std::vector other_s(fcoeff.get_svdtensor().dim_per_vector(otherdim) + 1, _); + + // do the actual contraction + for (int r = 0; r < fcoeff.rank(); ++r) { + s[0] = Slice(r, r); + other_s[0] = Slice(r, r); + const tensorT contracted_tensor = fcoeff.get_svdtensor().ref_vector(dim)(s).reshape(shape); + const tensorT other_tensor = fcoeff.get_svdtensor().ref_vector(otherdim)(other_s).reshape( + shape); + const double ovlp = gtensor.trace_conj(contracted_tensor); + const double fac = ovlp * fcoeff.get_svdtensor().weights(r); + final += fac * other_tensor; + } } // accumulate the result diff --git a/src/madness/mra/gfit.h b/src/madness/mra/gfit.h index 37442528bce..c457a4af4f7 100644 --- a/src/madness/mra/gfit.h +++ b/src/madness/mra/gfit.h @@ -67,17 +67,18 @@ class GFit { double hi = info.hi; MADNESS_CHECK_THROW(hi>0,"hi must be positive in gfit: U need to set it manually in operator.h"); double eps = info.thresh; + bool debug=info.debug; OpType type = info.type; - if (type==OT_G12) {*this=CoulombFit(lo,hi,eps,false); - } else if (type==OT_SLATER) {*this=SlaterFit(mu,lo,hi,eps,false); - } else if (type==OT_GAUSS) {*this=GaussFit(mu,lo,hi,eps,false); - } else if (type==OT_F12) {*this=F12Fit(mu,lo,hi,eps,false); - } else if (type==OT_FG12) {*this=FGFit(mu,lo,hi,eps,false); - } else if (type==OT_F212) {*this=F12sqFit(mu,lo,hi,eps,false); - } else if (type==OT_F2G12) {*this=F2GFit(mu,lo,hi,eps,false); - } else if (type==OT_BSH) {*this=BSHFit(mu,lo,hi,eps,false); + if (type==OT_G12) {*this=CoulombFit(lo,hi,eps,debug); + } else if (type==OT_SLATER) {*this=SlaterFit(mu,lo,hi,eps,debug); + } else if (type==OT_GAUSS) {*this=GaussFit(mu,lo,hi,eps,debug); + } else if (type==OT_F12) {*this=F12Fit(mu,lo,hi,eps,debug); + } else if (type==OT_FG12) {*this=FGFit(mu,lo,hi,eps,debug); + } else if (type==OT_F212) {*this=F12sqFit(mu,lo,hi,eps,debug); + } else if (type==OT_F2G12) {*this=F2GFit(mu,lo,hi,eps,debug); + } else if (type==OT_BSH) {*this=BSHFit(mu,lo,hi,eps,debug); } else { print("Operator type not implemented: ",type); MADNESS_EXCEPTION("Operator type not implemented: ",1); diff --git a/src/madness/mra/mra.h b/src/madness/mra/mra.h index 354c35207f2..232d7fa0461 100644 --- a/src/madness/mra/mra.h +++ b/src/madness/mra/mra.h @@ -2109,8 +2109,11 @@ namespace madness { apply_only(const opT& op, const Function& f, bool fence=true) { Function result; + constexpr std::size_t OPDIM=opT::opdim; + constexpr bool low_dim=(OPDIM*2==NDIM); // apply on some dimensions only + // specialized version for 3D - if (NDIM <= 3) { + if (NDIM <= 3 and (not low_dim)) { result.set_impl(f, false); result.get_impl()->apply(op, *f.get_impl(), fence); diff --git a/src/madness/mra/operator.h b/src/madness/mra/operator.h index b42cdfeb6ef..9343704b5a3 100644 --- a/src/madness/mra/operator.h +++ b/src/madness/mra/operator.h @@ -211,11 +211,34 @@ namespace madness { make_coeff_for_operator(World& world, double mu, double lo, double eps, OpType type, const BoundaryConditions& bc=FunctionDefaults::get_bc()) { + OperatorInfo info(mu,lo,eps,type); + return make_coeff_for_operator(world, info, bc); +// const Tensor& cell_width = FunctionDefaults<3>::get_cell_width(); +// double hi = cell_width.normf(); // Diagonal width of cell +// if (bc(0,0) == BC_PERIODIC) hi *= 100; // Extend range for periodic summation +// +// OperatorInfo info(mu,lo,eps,type); +// info.hi=hi; +// GFit fit(info); +// +// Tensor coeff=fit.coeffs(); +// Tensor expnt=fit.exponents(); +// +// if (bc(0,0) == BC_PERIODIC) { +// fit.truncate_periodic_expansion(coeff, expnt, cell_width.max(), false); +// } +// +// return std::make_pair(coeff,expnt); + } + + static inline std::pair,Tensor> + make_coeff_for_operator(World& world, OperatorInfo info, + const BoundaryConditions& bc=FunctionDefaults::get_bc()) { + const Tensor& cell_width = FunctionDefaults<3>::get_cell_width(); double hi = cell_width.normf(); // Diagonal width of cell if (bc(0,0) == BC_PERIODIC) hi *= 100; // Extend range for periodic summation - OperatorInfo info(mu,lo,eps,type); info.hi=hi; GFit fit(info); @@ -229,12 +252,6 @@ namespace madness { return std::make_pair(coeff,expnt); } - static inline std::pair,Tensor> - make_coeff_for_operator(World& world, OperatorInfo info, - const BoundaryConditions& bc=FunctionDefaults::get_bc()) { - return make_coeff_for_operator(world,info.mu,info.lo,info.thresh,info.type,bc); - } - // /// return the right block of the upsampled operator (modified NS only) // // /// unlike the operator matrices on the natural level the upsampled operator @@ -1332,8 +1349,8 @@ namespace madness { // get the appropriate singular vector (left or right depends on particle) // and apply the full tensor muopxv_fast on it, term by term s[0]=Slice(r,r); - const Tensor chunk=svdcoeff.ref_vector(particle()-1)(s).reshape(2*k,2*k,2*k); - const Tensor chunk0=f0.get_svdtensor().ref_vector(particle()-1)(s).reshape(k,k,k); + const Tensor chunk=svdcoeff.ref_vector(particle()-1)(s).reshape(v2k); + const Tensor chunk0=f0.get_svdtensor().ref_vector(particle()-1)(s).reshape(vk); // const double weight=std::abs(coeff.config().weights(r)); // accumulate all terms of the operator for a specific term of the function @@ -1725,20 +1742,6 @@ namespace madness { } - /// Factory function generating separated kernel for convolution with 1/r in 3D. - template - static - inline - SeparatedConvolution CoulombOperator_ndim(World& world, - double lo, - double eps, - const BoundaryConditions& bc=FunctionDefaults::get_bc(), - - int k=FunctionDefaults::get_k()) - { - return SeparatedConvolution(world,OperatorInfo(0.0,lo,eps,OT_G12),bc,k); - } - /// Factory function generating separated kernel for convolution with 1/r in 3D. static inline diff --git a/src/madness/mra/operatorinfo.h b/src/madness/mra/operatorinfo.h index fcbce4d8253..7b57acc0d31 100644 --- a/src/madness/mra/operatorinfo.h +++ b/src/madness/mra/operatorinfo.h @@ -63,6 +63,7 @@ struct OperatorInfo { double thresh=1.e-4; double lo=1.e-5; double hi=-1.0; + bool debug=false; }; diff --git a/src/madness/mra/vmra.h b/src/madness/mra/vmra.h index 3d8bf122cff..4b28413649e 100644 --- a/src/madness/mra/vmra.h +++ b/src/madness/mra/vmra.h @@ -295,7 +295,7 @@ namespace madness { const TreeState intermediatestate) { int must_fence=0; for (auto& f : v) { - if (f.get_impl()->get_tree_state()==initialstate) { + if (f.is_initialized() and f.get_impl()->get_tree_state()==initialstate) { f.change_tree_state(intermediatestate,false); must_fence=1; } From c98af2a8a665fc5ffb05971261408ec34958afae Mon Sep 17 00:00:00 2001 From: fbischoff Date: Wed, 31 Jan 2024 12:04:02 +0100 Subject: [PATCH 081/109] mp3 works slightly faster with consolidation of ccpairfunctions --- src/madness/chem/ccpairfunction.cc | 63 +++++++++++++++++++++---- src/madness/chem/ccpairfunction.h | 15 +++++- src/madness/chem/mp2.cc | 12 ++++- src/madness/chem/test_ccpairfunction.cc | 47 +++++++++++++++++- 4 files changed, 124 insertions(+), 13 deletions(-) diff --git a/src/madness/chem/ccpairfunction.cc b/src/madness/chem/ccpairfunction.cc index 8140a4eb578..404bb04f1cd 100644 --- a/src/madness/chem/ccpairfunction.cc +++ b/src/madness/chem/ccpairfunction.cc @@ -62,20 +62,67 @@ void CCPairFunction::convert_to_pure_no_op_inplace() { }; template -std::vector> consolidate(const std::vector>& other) { +std::vector> CCPairFunction::consolidate(const std::vector>& other, + std::vector options) const { + + // return only one term of a hi-dim function + bool one_term=find(options.begin(),options.end(),"one_term")!=options.end(); + // convert op_pure functions to pure + bool op_pure_to_pure=find(options.begin(),options.end(),"op_pure_to_pure")!=options.end(); + // reorthogonalize decomposed functions and op_decomposed functions + bool svd=find(options.begin(),options.end(),"svd")!=options.end(); + std::vector> result; - std::vector> all_pure; + + // sort the terms into pure, decomposed, op_decomposed, op_pure + std::vector> pure; + std::vector>> op_pure(OT_SIZE); for (auto& c : other) { - if (c.is_pure_no_op()) all_pure.push_back(c.get_function()); - else result.push_back(c); + if (c.is_pure_no_op()) { + pure.push_back(c.get_function()); + } else if (c.is_op_pure()) { + int opint=int(c.get_operator().type()); + op_pure[opint].push_back(c.get_function()); + } + + else { + result.push_back(c); + } + } + // accumulate all pure functions + if (pure.size()>0) { + Function pure_result=CompositeFactory(world()).ket(pure); + pure_result.fill_tree(); + result.push_back(CCPairFunction(pure_result)); } - if (not all_pure.empty()) { - for (std::size_t i=1; i(all_pure.front())); + + // accumulate all op_pure functions + for (int opint=OT_G12; opint0) { + auto op=CCConvolutionOperatorPtr(world(),OpType(opint),CCParameters()); + print("consolidating",op->name()); + Function tmp; + if (op_pure_to_pure) { + tmp=CompositeFactory(world()).ket(op_pure[opint]).g12(op->get_kernel()); + tmp.fill_tree(); + result.push_back(CCPairFunction(tmp)); + } else { + tmp=CompositeFactory(world()).ket(op_pure[opint]); + tmp.fill_tree(); + result.push_back(CCPairFunction(op,tmp)); + } + } } + + +// if (not all_pure.empty()) { +// for (std::size_t i=1; i(all_pure.front())); +// } + return result; } diff --git a/src/madness/chem/ccpairfunction.h b/src/madness/chem/ccpairfunction.h index 54b799ac55a..b2cd80a23d8 100644 --- a/src/madness/chem/ccpairfunction.h +++ b/src/madness/chem/ccpairfunction.h @@ -399,8 +399,19 @@ using pureT=Function; return result; } - /// add all like functions up, return *this for chaining - friend std::vector consolidate(const std::vector& other); + std::vector consolidate(const std::vector& other, + std::vector options={}) const; + + /// collect the terms into a compact format + + /// @param[in] other: a vector of CCPairFunctions + /// @param[in] options: a vector of strings which can be "one_term", "op_pure_to_pure", "svd" + friend std::vector consolidate(const std::vector& other, + std::vector options={}) { + + if (other.size()>0) return other.front().consolidate(other,options); // workaround + return other; + }; void info() const { print_size(); } diff --git a/src/madness/chem/mp2.cc b/src/madness/chem/mp2.cc index 0282c28db52..f37b66a6286 100644 --- a/src/madness/chem/mp2.cc +++ b/src/madness/chem/mp2.cc @@ -398,12 +398,14 @@ double MP2::mp3() const { for (auto& t: tmp3) tau_ij_j[i].push_back(t); } } - print("info on tau_kk_i"); + print("info on tau_kk_i, consolidated with op_pure_to_pure"); for (int i = param.freeze(); i < hf->nocc(); ++i) { + tau_kk_i[i]=consolidate(tau_kk_i[i],{"op_pure_to_pure"}); for (auto& c: tau_kk_i[i]) c.info(); } - print("info on tau_ij_j"); + print("info on tau_ij_j, consolidated with op_pure_to_pure"); for (int i = param.freeze(); i < hf->nocc(); ++i) { + tau_ij_j[i]=consolidate(tau_ij_j[i],{"op_pure_to_pure"}); for (auto& c: tau_ij_j[i]) c.info(); } @@ -418,11 +420,17 @@ double MP2::mp3() const { g.set_particle(1); auto gtau_same = g(tau_kk_i[i]); t4.tag("compute gtau_same"); +// gtau_same=consolidate(gtau_same,{"op_pure_to_pure"}); +// t4.tag("consolidate gtau_same"); // tmp(1',2) = g(1',1) | tau_ij(1,2) j(1) > g.set_particle(1); auto gtau_other = g(tau_ij_j[i]); // < tau_ij(1,2) j(1) | g(1,1') | t4.tag("compute gtau_other"); +// gtau_other=consolidate(gtau_other,{"op_pure_to_pure"}); +// t4.tag("consolidate gtau_other"); + + auto bra_kk_i = multiply(tau_kk_i[i],R2,{3,4,5}); diff --git a/src/madness/chem/test_ccpairfunction.cc b/src/madness/chem/test_ccpairfunction.cc index 4fc52c5fc00..bbd2be5eb48 100644 --- a/src/madness/chem/test_ccpairfunction.cc +++ b/src/madness/chem/test_ccpairfunction.cc @@ -735,6 +735,47 @@ int test_partial_inner_3d(World& world, std::shared_ptr +int test_consolidate(World& world, std::shared_ptr ncf, data& data, + const CCParameters& parameter) { + test_output t1("CCPairFunction::test_consolidate"); + static_assert(NDIM % 2 == 0, "NDIM must be even"); + constexpr std::size_t LDIM = NDIM / 2; + t1.set_cout_to_terminal(); + + /// f12: exp(-r_1^2 - 2 r_2^2) + /// f23: exp(-r_1^2 - 2 r_2^2) + exp(-2 r_1^2 - 3 r_2^2) + /// p1: pure, corresponds to f12 + /// p2: dec, corresponds to f23 + /// p3: op_dec, corresponds to f23 + /// p4: pure, corresponds to f23 + /// p5: op_pure, corresponds to f23 + auto [p1,p2,p3,p4,p5]=data.get_ccpairfunctions(); + + for (const auto& p : {p1,p4,p5}) { + auto tmp=std::vector>({p,p}); + + double r1=inner(tmp,{p1}); + print("r1",r1); + auto tmp1=consolidate(tmp,{"sdf"}); + double r2=inner(tmp1,{p1}); + print("r2",r2); + + t1.checkpoint(tmp1.size()==1 && tmp.size()==2,"vector size"); + t1.checkpoint(r1,r2,FunctionDefaults::get_thresh(),"consolidate"); + + } + throw; + + + + + + return t1.end(); +} + + template int test_apply(World& world, std::shared_ptr ncf, data& data, const CCParameters& parameter) { @@ -750,7 +791,6 @@ int test_apply(World& world, std::shared_ptr ncf, data /// p3: op_dec, corresponds to f23 /// p4: pure, corresponds to f23 /// p5: op_pure, corresponds to f23 -// auto data=get_data<6>(world,parameter); auto [p1,p2,p3,p4,p5]=data.get_ccpairfunctions(); auto [f1,f2,f3,f4,f5,f]=data.get_functions(); @@ -1123,6 +1163,9 @@ int main(int argc, char **argv) { auto data4=data(world,ccparam); auto data6=data(world,ccparam); + isuccess+=test_consolidate(world, ncf, data2, ccparam); + + throw; isuccess+=test_constructor(world, ncf, data2, ccparam); isuccess+=test_operator_apply(world, ncf, data2, ccparam); isuccess+=test_transformations(world, ncf, data2, ccparam); @@ -1135,6 +1178,8 @@ int main(int argc, char **argv) { isuccess+=test_partial_inner_3d(world, ncf, data2, ccparam); isuccess+=test_partial_inner_6d(world, ncf, data2, ccparam); isuccess+=test_apply(world, ncf, data2, ccparam); + isuccess+=test_consolidate(world, ncf, data2, ccparam); + // isuccess+=test_constructor(world, ncf, data4, ccparam); // isuccess+=test_operator_apply(world, ncf, data4, ccparam); From ff75fbe2244c44d8ed12e89d7494c6b48383a281 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Fri, 2 Feb 2024 15:23:02 +0100 Subject: [PATCH 082/109] adding lowrankfunction to ccpairfunction to transform f12|ij> to a sum of low-rank function. More to be done --- src/madness/chem/ccpairfunction.cc | 82 ++++++++++++++++++++++ src/madness/chem/ccpairfunction.h | 6 ++ src/madness/chem/mp2.cc | 10 +-- src/madness/chem/test_low_rank_function.cc | 30 ++++---- 4 files changed, 110 insertions(+), 18 deletions(-) diff --git a/src/madness/chem/ccpairfunction.cc b/src/madness/chem/ccpairfunction.cc index 404bb04f1cd..5156990d96b 100644 --- a/src/madness/chem/ccpairfunction.cc +++ b/src/madness/chem/ccpairfunction.cc @@ -5,6 +5,7 @@ #include #include #include +#include #include using namespace madness; @@ -61,6 +62,84 @@ void CCPairFunction::convert_to_pure_no_op_inplace() { component.reset(new TwoBodyFunctionPureComponent(result)); }; +/// turn decomposed functions with operator into decomposed functions using LowRankFunction +template +std::vector> CCPairFunction::op_dec_to_dec(const std::vector>& other) { + LowRankFunctionParameters lrparameters; + auto builder = LowRankFunctionFactory(lrparameters); + builder.set_volume_element(3.e-2); + builder.parameters.print("lrparameters"); + std::vector> result; + for (const auto& c : other) { + if (c.is_op_decomposed()) { + LRFunctorF12 functor(c.get_operator_ptr()->get_op(),c.get_a().front(),c.get_b().front()); + LowRankFunction tmp=builder.project(functor); + double l2error=tmp.l2error(functor); + print("error",l2error); + tmp.optimize(functor); + l2error=tmp.l2error(functor); + print("error after optimization",l2error); + print("rank after optimization",tmp.rank()); + result.push_back(CCPairFunction(tmp.get_g(),tmp.get_h())); + } else { + result.push_back(c); + } + } + return result; + +} + +/// collect all terms with the same operator +template +std::vector> CCPairFunction::collect_same_types(const std::vector>& other) { + + if (other.size()==0) return other; + World& world=other.front().world(); + + /// vector includes OT_ONE, meaning no operator + std::vector>> op_pure(OT_SIZE); + std::vector>> op_decomposed_a(OT_SIZE); + std::vector>> op_decomposed_b(OT_SIZE); + std::vector>> ops(OT_SIZE); + + for (const auto& c : other) { + if (c.has_operator()) { + int iop=int(c.get_operator().type()); + ops[iop]=c.get_operator_ptr(); + } + int iop=int(c.get_operator().type()); + if (c.is_decomposed()) { + op_decomposed_a[iop]=append(op_decomposed_a[iop],c.get_a()); + op_decomposed_b[iop]=append(op_decomposed_a[iop],c.get_b()); + } else if (c.is_pure()) { + op_pure[iop].push_back(c.get_function()); + } + } + + std::vector> result; + // accumulate all op_pure functions + for (int opint=OT_ONE; opint0) { +// auto op=CCConvolutionOperatorPtr(world,OpType(opint),CCParameters()); + auto op=ops[opint]; + Function tmp=CompositeFactory(world).ket(op_pure[opint]); + tmp.fill_tree(); + result.push_back(CCPairFunction(op,tmp)); + } + if (op_decomposed_a[opint].size()>0) { + + if (opint!=OT_ONE) { +// auto op=CCConvolutionOperatorPtr(world,OpType(opint),CCParameters()); + result.push_back(CCPairFunction(ops[opint],op_decomposed_a[opint],op_decomposed_b[opint])); + } else { + result.push_back(CCPairFunction(op_decomposed_a[opint],op_decomposed_b[opint])); + } + } + } + return result; + +} + template std::vector> CCPairFunction::consolidate(const std::vector>& other, std::vector options) const { @@ -69,6 +148,8 @@ std::vector> CCPairFunction::consolidate(const st bool one_term=find(options.begin(),options.end(),"one_term")!=options.end(); // convert op_pure functions to pure bool op_pure_to_pure=find(options.begin(),options.end(),"op_pure_to_pure")!=options.end(); + // convert op_dec functions to dec (via LowRankFunctions + bool op_dec_to_dec=find(options.begin(),options.end(),"op_dec_to_dec")!=options.end(); // reorthogonalize decomposed functions and op_decomposed functions bool svd=find(options.begin(),options.end(),"svd")!=options.end(); @@ -115,6 +196,7 @@ std::vector> CCPairFunction::consolidate(const st } } + if (op_dec_to_dec) result=CCPairFunction::op_dec_to_dec(result); // if (not all_pure.empty()) { diff --git a/src/madness/chem/ccpairfunction.h b/src/madness/chem/ccpairfunction.h index b2cd80a23d8..8bddf32e948 100644 --- a/src/madness/chem/ccpairfunction.h +++ b/src/madness/chem/ccpairfunction.h @@ -402,6 +402,12 @@ using pureT=Function; std::vector consolidate(const std::vector& other, std::vector options={}) const; + /// turn decomposed functions with operator into decomposed functions using LowRankFunction + static std::vector op_dec_to_dec(const std::vector& other); + + static std::vector collect_same_types(const std::vector& other); + + /// collect the terms into a compact format /// @param[in] other: a vector of CCPairFunctions diff --git a/src/madness/chem/mp2.cc b/src/madness/chem/mp2.cc index f37b66a6286..c32726aa80d 100644 --- a/src/madness/chem/mp2.cc +++ b/src/madness/chem/mp2.cc @@ -51,6 +51,7 @@ #include #include #include +#include #include #include @@ -386,6 +387,7 @@ double MP2::mp3() const { // \sum_j tau_ij(1,2) * phi_j(2) std::vector tau_kk_i(hf->nocc() - param.freeze()); + std::vector tau_kk_i_lrf(hf->nocc() - param.freeze()); // low-rank // \sum_j tau_ij(1,2) * phi_j(1) std::vector tau_ij_j(hf->nocc() - param.freeze()); for (int i = param.freeze(); i < hf->nocc(); ++i) { @@ -402,10 +404,13 @@ double MP2::mp3() const { for (int i = param.freeze(); i < hf->nocc(); ++i) { tau_kk_i[i]=consolidate(tau_kk_i[i],{"op_pure_to_pure"}); for (auto& c: tau_kk_i[i]) c.info(); + print("info on tau_kk_i, consolidated with op_dec_to_dec"); + tau_kk_i[i]=consolidate(tau_kk_i[i],{"op_dec_to_dec"}); + for (auto& c: tau_kk_i[i]) c.info(); } print("info on tau_ij_j, consolidated with op_pure_to_pure"); for (int i = param.freeze(); i < hf->nocc(); ++i) { - tau_ij_j[i]=consolidate(tau_ij_j[i],{"op_pure_to_pure"}); + tau_ij_j[i]=consolidate(tau_ij_j[i],{"op_pure_to_pure","op_dec_to_dec"}); for (auto& c: tau_ij_j[i]) c.info(); } @@ -430,9 +435,6 @@ double MP2::mp3() const { // gtau_other=consolidate(gtau_other,{"op_pure_to_pure"}); // t4.tag("consolidate gtau_other"); - - - auto bra_kk_i = multiply(tau_kk_i[i],R2,{3,4,5}); auto bra_ij_j = multiply(tau_ij_j[i],R2,{3,4,5}); diff --git a/src/madness/chem/test_low_rank_function.cc b/src/madness/chem/test_low_rank_function.cc index f77f8bdcd1a..3d3b57145bf 100644 --- a/src/madness/chem/test_low_rank_function.cc +++ b/src/madness/chem/test_low_rank_function.cc @@ -365,7 +365,7 @@ int test_full_rank_functor(World& world, LowRankFunctionParameters parameters) { constexpr int NDIM=2*LDIM; // FunctionDefaults::set_thresh(1.e-6); // FunctionDefaults::set_thresh(1.e-6); - double tol=5.e-3; + double tol=6.e-3; double gaussexponent=2.0; const particle p1=particle::particle1(); @@ -681,12 +681,12 @@ int test_construction_optimization(World& world, LowRankFunctionParameters param lrf.optimize(lrfunctor); error=lrf.l2error(lrfunctor); print("l2 error optimize",error); - t1.checkpoint(error<1.e-2,"l2 error in optimization "+std::to_string(error)); + t1.checkpoint(error,1.1e-2,"l2 error in optimization"); lrf.reorthonormalize(); error=lrf.l2error(lrfunctor); print("l2 error reorthonormalize",error); - t1.checkpoint(error<1.e-2,"l2 error in reorthonormalization "+std::to_string(error)); + t1.checkpoint(error,1.1e-2,"l2 error in reorthonormalization"); return t1.end(); } @@ -695,8 +695,10 @@ int main(int argc, char **argv) { madness::World& world = madness::initialize(argc, argv); startup(world, argc, argv); commandlineparser parser(argc, argv); + bool long_test = parser.key_exists("long_test"); + bool exchange_test = parser.key_exists("exchange_test"); int k = parser.key_exists("k") ? std::atoi(parser.value("k").c_str()) : 6; - double thresh = parser.key_exists("thresh") ? std::stod(parser.value("thresh")) : 1.e-5; + double thresh = parser.key_exists("thresh") ? std::stod(parser.value("thresh")) : 3.e-5; FunctionDefaults<6>::set_tensor_type(TT_2D); @@ -729,9 +731,10 @@ int main(int argc, char **argv) { print("numerical parameters: k, eps(3D), eps(6D)", FunctionDefaults<3>::get_k(), FunctionDefaults<3>::get_thresh(), FunctionDefaults<6>::get_thresh()); LowRankFunctionParameters parameters; + parameters.set_derived_value("f12type",std::string("slaterf12")); parameters.read_and_set_derived_values(world,parser,"grid"); -// parameters.set_user_defined_value("radius",3.0); -// parameters.set_user_defined_value("volume_element",2.e-2); + parameters.set_user_defined_value("radius",2.5); + parameters.set_user_defined_value("volume_element",1.e-1); // parameters.set_user_defined_value("tol",1.0e-10); parameters.print("grid"); int isuccess=0; @@ -740,21 +743,20 @@ int main(int argc, char **argv) { try { -// isuccess+=test_grids<1>(world,parameters); -// isuccess+=test_grids<2>(world,parameters); -// isuccess+=test_grids<3>(world,parameters); isuccess+=test_full_rank_functor<1>(world, parameters); isuccess+=test_construction_optimization<1>(world,parameters); -// isuccess+=test_construction_optimization<2>(world,parameters); isuccess+=test_arithmetic<1>(world,parameters); -// isuccess+=test_arithmetic<2>(world,parameters); + isuccess+=test_inner<1>(world,parameters); -// isuccess+=test_inner<1>(world,parameters); -// isuccess+=test_inner<2>(world,parameters); + if (long_test) { + isuccess+=test_construction_optimization<2>(world,parameters); + isuccess+=test_arithmetic<2>(world,parameters); + isuccess+=test_inner<2>(world,parameters); + } // parameters.set_user_defined_value("volume_element",1.e-1); // isuccess+=test_lowrank_function(world,parameters); - isuccess+=test_Kcommutator(world,parameters); +// isuccess+=test_Kcommutator(world,parameters); } catch (std::exception& e) { madness::print("an error occured"); madness::print(e.what()); From ef1f0f6e36b1167af59e7922bebcea2dda029e63 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Sat, 3 Feb 2024 22:53:29 +0100 Subject: [PATCH 083/109] lowrankfunction with vector of functions for LRFunctorF12 --- src/madness/chem/lowrankfunction.h | 75 ++++++++++++++++------ src/madness/chem/test_low_rank_function.cc | 34 +++++----- 2 files changed, 74 insertions(+), 35 deletions(-) diff --git a/src/madness/chem/lowrankfunction.h b/src/madness/chem/lowrankfunction.h index f25ab3d90e7..f8f44b36c86 100644 --- a/src/madness/chem/lowrankfunction.h +++ b/src/madness/chem/lowrankfunction.h @@ -299,12 +299,36 @@ struct LRFunctorBase { template struct LRFunctorF12 : public LRFunctorBase { - LRFunctorF12() = default; +// LRFunctorF12() = default; + LRFunctorF12(const std::shared_ptr> f12, const std::vector>& a, + const std::vector>& b) : f12(f12), a(a), b(b) { + + // if a or b are missing, they are assumed to be 1 + // you may not provide a or b, but if you do they have to have the same size because they are summed up + if (a.size()>0 and b.size()>0) + MADNESS_CHECK_THROW(a.size()==b.size(), "a and b must have the same size"); + if (a.size()==0) this->a.resize(1); + if (b.size()==0) this->b.resize(1); + MADNESS_CHECK_THROW(this->a.size()==this->b.size(), "a and b must have the same size"); + } + LRFunctorF12(const std::shared_ptr> f12, const Function& a, - const Function& b) : f12(f12), a(a), b(b) {} + const Function& b) : f12(f12), a({a}), b({b}) { + + // if a or b are missing, they are assumed to be 1 + // you may not provide a or b, but if you do they have to have the same size because they are summed up + if (a.size()>0 and b.size()>0) + MADNESS_CHECK_THROW(a.size()==b.size(), "a and b must have the same size"); + if (a.size()==0) this->a.resize(1); + if (b.size()==0) this->b.resize(1); + MADNESS_CHECK_THROW(this->a.size()==this->b.size(), "a and b must have the same size"); + + } +private: std::shared_ptr> f12; ///< a two-particle function - Function a,b; ///< the lo-dim functions + std::vector> a,b; ///< the lo-dim functions +public: World& world() const {return f12->get_world();} std::vector> inner(const std::vector>& rhs, @@ -314,39 +338,50 @@ struct LRFunctorF12 : public LRFunctorBase { // functor is now a(1) b(2) f12 // result(1) = \int a(1) f(1,2) b(2) rhs(2) d2 World& world=rhs.front().world(); - auto premultiply= p1.is_first() ? a : b; - auto postmultiply= p1.is_first() ? b : a; + bool have_a_and_b = (a.size()>0 and b.size()>0); + const int nbatch=30; for (int i=0; i> tmp; + std::vector> tmp, tmp2; auto begin= rhs.begin()+i; auto end= (i+nbatch)(world,tmp.size()); + + for (int ia=0; ia::scalar_type norm2() const { const Function one=FunctionFactory(world()).f([](const Vector& r){return 1.0;}); - const Function pre=(a.is_initialized()) ? a : one; - const Function post=(b.is_initialized()) ? b : one; + std::size_t sz=a.size(); + if (sz==0) return 0.0; + const std::vector> pre=(a.front().is_initialized()) ? a : std::vector>(sz,one); + const std::vector> post=(b.front().is_initialized()) ? b : std::vector>(sz,one); const SeparatedConvolution& f12a=*(f12); const SeparatedConvolution f12sq= SeparatedConvolution::combine(f12a,f12a); // \int f(1,2)^2 d1d2 = \int f(1,2)^2 pre(1)^2 post(2)^2 d1 d2 - typename Tensor::scalar_type term1 =madness::inner(post*post,f12sq(pre*pre)); + // \sum_i || f(1,2) a_i(1) b_i(2) || = \sum_i \int f(1,2)^2 a_i(1)^2 b_i(2)^2 d1d2 + typename Tensor::scalar_type term1 =madness::inner(mul(world(),post,post),f12sq(mul(world(),pre,pre))); return sqrt(term1); } T operator()(const Vector& r) const { + if (a.size()==0) return 0.0; auto split = [](const Vector& r) { Vector first, second; for (int i=0; i { auto [first,second]=split(r); double result=1.0; - if (a.is_initialized()) result*=a(first); - if (b.is_initialized()) result*=b(first); - if (f12->info.type==OT_SLATER) result*=exp(-gamma*(first-second).normf()); - else if (f12->info.type==OT_GAUSS) result*=exp(-gamma* madness::inner(first-second,first-second)); - else return 1.0; + for (std::size_t ia=0; iainfo.type==OT_SLATER) result*=exp(-gamma*(first-second).normf()); + else if (f12->info.type==OT_GAUSS) result*=exp(-gamma* madness::inner(first-second,first-second)); + else { + MADNESS_EXCEPTION("no such operator_type",1); + } + } return result; } diff --git a/src/madness/chem/test_low_rank_function.cc b/src/madness/chem/test_low_rank_function.cc index 3d3b57145bf..c4427e6478f 100644 --- a/src/madness/chem/test_low_rank_function.cc +++ b/src/madness/chem/test_low_rank_function.cc @@ -384,9 +384,9 @@ int test_full_rank_functor(World& world, LowRankFunctionParameters parameters) { functorpure.f=gauss; t1.checkpoint(true,"prep"); - LRFunctorF12 functorf12; - Function b=FunctionFactory(world).functor([](const Vector& r){return exp(-inner(r,r));}); - functorf12.f12.reset(GaussOperatorPtr(world,gaussexponent)); + auto gaussop=std::shared_ptr>(GaussOperatorPtr(world,gaussexponent)); + LRFunctorF12 functorf12(gaussop,std::vector>({}),{}); +// functorf12.f12.reset(GaussOperatorPtr(world,gaussexponent)); auto builder= LowRankFunctionFactory(parameters).set_radius(8) .set_volume_element(0.1).set_rank_revealing_tol(1.e-10).set_orthomethod("canonical"); @@ -443,12 +443,15 @@ int test_arithmetic(World& world, LowRankFunctionParameters parameters) { Function phi=FunctionFactory(world) .functor([](const Vector& r){return exp(-4.0*inner(r,r));}); - LRFunctorF12 functor1; - functor1.f12.reset(GaussOperatorPtr(world,1.0)); - functor1.a=phi; - LRFunctorF12 functor2; - functor2.f12.reset(GaussOperatorPtr(world,2.0)); - functor2.a=phi; + auto gauss1=std::shared_ptr>(GaussOperatorPtr(world,1.0)); + LRFunctorF12 functor1(gauss1,{phi},{}); +// functor1.f12.reset(GaussOperatorPtr(world,1.0)); +// functor1.a={phi}; + auto gauss2=std::shared_ptr>(GaussOperatorPtr(world,2.0)); + LRFunctorF12 functor2(gauss2,{phi},{}); +// LRFunctorF12 functor2; +// functor2.f12.reset(GaussOperatorPtr(world,2.0)); +// functor2.a={phi}; auto p1=particle::particle1(); auto p2=particle::particle2(); @@ -528,14 +531,11 @@ int test_inner(World& world, LowRankFunctionParameters parameters) { Function phi=FunctionFactory(world) .functor([](const Vector& r){return exp(-4.0*inner(r,r));}); - LRFunctorF12 functor1; - functor1.f12.reset(GaussOperatorPtr(world,1.0)); -// functor1.f12.reset(SlaterOperatorPtr_ND(world,1.0,1.e-4,thresh)); - functor1.a=phi; - LRFunctorF12 functor2; - functor2.f12.reset(GaussOperatorPtr(world,2.0)); -// functor2.f12.reset(SlaterOperatorPtr_ND(world,2.0,1.e-4,thresh)); - functor2.a=phi; + auto gauss1=std::shared_ptr>(GaussOperatorPtr(world,1.0)); + LRFunctorF12 functor1(gauss1,{phi},{}); + auto gauss2=std::shared_ptr>(GaussOperatorPtr(world,2.0)); + LRFunctorF12 functor2(gauss2,{phi},{}); +// functor2.a={phi}; auto p1=particle::particle1(); auto p2=particle::particle2(); From 64b58348ec534dde7cf54ac543a7b68078062616 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Mon, 5 Feb 2024 12:31:59 +0100 Subject: [PATCH 084/109] lowrankfunction with vector of functions for LRFunctorF12 --- src/examples/smooth.h | 2 +- src/madness/chem/lowrankfunction.h | 63 ++++++++++++------- src/madness/chem/test_low_rank_function.cc | 71 ++++++++++++---------- 3 files changed, 80 insertions(+), 56 deletions(-) diff --git a/src/examples/smooth.h b/src/examples/smooth.h index 74342bce25d..7a5ec6c90c7 100644 --- a/src/examples/smooth.h +++ b/src/examples/smooth.h @@ -607,7 +607,7 @@ class smooth { Tensor coeffs(1), exponents(1); exponents(0L) = 1.0 / (2.0 * 0.04); coeffs(0L) = pow((1.0 / (2.0 * 0.04)) / M_PI, 0.5); - SeparatedConvolution op(world, coeffs, exponents); + SeparatedConvolution op(world, coeffs, exponents,1.e-5,1.e-5); real_function_1d sf = apply(op, f); double diff = (f - sf).norm2(); output("||f - smoothed_f||_1D=" + stringify(diff)); diff --git a/src/madness/chem/lowrankfunction.h b/src/madness/chem/lowrankfunction.h index f8f44b36c86..7db22de7074 100644 --- a/src/madness/chem/lowrankfunction.h +++ b/src/madness/chem/lowrankfunction.h @@ -307,8 +307,8 @@ struct LRFunctorF12 : public LRFunctorBase { // you may not provide a or b, but if you do they have to have the same size because they are summed up if (a.size()>0 and b.size()>0) MADNESS_CHECK_THROW(a.size()==b.size(), "a and b must have the same size"); - if (a.size()==0) this->a.resize(1); - if (b.size()==0) this->b.resize(1); + if (a.size()==0) this->a.resize(b.size()); + if (b.size()==0) this->b.resize(a.size()); MADNESS_CHECK_THROW(this->a.size()==this->b.size(), "a and b must have the same size"); } @@ -335,24 +335,27 @@ struct LRFunctorF12 : public LRFunctorBase { const particle p1, const particle p2) const { std::vector> result; - // functor is now a(1) b(2) f12 - // result(1) = \int a(1) f(1,2) b(2) rhs(2) d2 + // functor is now \sum_i a_i(1) b_i(2) f12 + // result(1) = \sum_i \int a_i(1) f(1,2) b_i(2) rhs(2) d2 + // = \sum_i a_i(1) \int f(1,2) b_i(2) rhs(2) d2 World& world=rhs.front().world(); - bool have_a_and_b = (a.size()>0 and b.size()>0); - const int nbatch=30; for (int i=0; i> tmp, tmp2; + std::vector> rhs_batch; auto begin= rhs.begin()+i; auto end= (i+nbatch)(world,tmp.size()); + std::copy(begin,end, std::back_inserter(rhs_batch)); + auto tmp2= zero_functions_compressed(world,rhs_batch.size()); + + if (a.size()==0) tmp2=apply(world,*(f12),rhs_batch); for (int ia=0; ia { } typename Tensor::scalar_type norm2() const { - const Function one=FunctionFactory(world()).f([](const Vector& r){return 1.0;}); - std::size_t sz=a.size(); - if (sz==0) return 0.0; - const std::vector> pre=(a.front().is_initialized()) ? a : std::vector>(sz,one); - const std::vector> post=(b.front().is_initialized()) ? b : std::vector>(sz,one); + const Function one = FunctionFactory(world()).f( + [](const Vector& r) { return 1.0; }); + std::vector> pre, post; + std::size_t sz = a.size(); + if (sz == 0) { + pre = std::vector>(1, one); + post = std::vector>(1, one); + } else { + pre = (a.front().is_initialized()) ? a : std::vector>(sz, one); + post = (b.front().is_initialized()) ? b : std::vector>(sz, one); + } + const SeparatedConvolution& f12a=*(f12); const SeparatedConvolution f12sq= SeparatedConvolution::combine(f12a,f12a); // \int f(1,2)^2 d1d2 = \int f(1,2)^2 pre(1)^2 post(2)^2 d1 d2 - // \sum_i || f(1,2) a_i(1) b_i(2) || = \sum_i \int f(1,2)^2 a_i(1)^2 b_i(2)^2 d1d2 - typename Tensor::scalar_type term1 =madness::inner(mul(world(),post,post),f12sq(mul(world(),pre,pre))); + // || \sum_i f(1,2) a_i(1) b_i(2) || = \int ( \sum_{ij} a_i(1) a_j(1) f(1,2)^2 b_i(1) b_j(2) ) d1d2 + std::vector> aa,bb; + for (std::size_t i=0; i::scalar_type term1 =madness::inner(mul(world(),post,post),f12sq(mul(world(),pre,pre))); + typename Tensor::scalar_type term1 =madness::inner(bb,f12sq(aa)); return sqrt(term1); } @@ -394,15 +410,18 @@ struct LRFunctorF12 : public LRFunctorBase { double gamma=f12->info.mu; auto [first,second]=split(r); - double result=1.0; + + double result=0.0; for (std::size_t ia=0; iainfo.type==OT_SLATER) result*=exp(-gamma*(first-second).normf()); - else if (f12->info.type==OT_GAUSS) result*=exp(-gamma* madness::inner(first-second,first-second)); + double result1=1.0; + if (a[ia].is_initialized()) result1*=a[ia](first); + if (b[ia].is_initialized()) result1*=b[ia](first); + if (f12->info.type==OT_SLATER) result1*=exp(-gamma*(first-second).normf()); + else if (f12->info.type==OT_GAUSS) result1*=exp(-gamma* madness::inner(first-second,first-second)); else { MADNESS_EXCEPTION("no such operator_type",1); } + result+=result1; } return result; diff --git a/src/madness/chem/test_low_rank_function.cc b/src/madness/chem/test_low_rank_function.cc index c4427e6478f..12122c38368 100644 --- a/src/madness/chem/test_low_rank_function.cc +++ b/src/madness/chem/test_low_rank_function.cc @@ -445,13 +445,8 @@ int test_arithmetic(World& world, LowRankFunctionParameters parameters) { auto gauss1=std::shared_ptr>(GaussOperatorPtr(world,1.0)); LRFunctorF12 functor1(gauss1,{phi},{}); -// functor1.f12.reset(GaussOperatorPtr(world,1.0)); -// functor1.a={phi}; auto gauss2=std::shared_ptr>(GaussOperatorPtr(world,2.0)); LRFunctorF12 functor2(gauss2,{phi},{}); -// LRFunctorF12 functor2; -// functor2.f12.reset(GaussOperatorPtr(world,2.0)); -// functor2.a={phi}; auto p1=particle::particle1(); auto p2=particle::particle2(); @@ -657,36 +652,46 @@ template int test_construction_optimization(World& world, LowRankFunctionParameters parameters) { constexpr std::size_t NDIM=2*LDIM; test_output t1("LowRankFunction::construction/optimization in dimension "+std::to_string(NDIM)); -// t1.set_cout_to_terminal(); + t1.set_cout_to_terminal(); OperatorInfo info(1.0,1.e-6,FunctionDefaults::get_thresh(),OT_SLATER); auto slater=std::shared_ptr >(new SeparatedConvolution(world,info)); - Function one=FunctionFactory(world).functor([](const Vector& r){return exp(-0.2*inner(r,r));}); - - LRFunctorF12 lrfunctor(slater,one,one); - LowRankFunctionFactory builder(parameters); - auto lrf=builder.project(lrfunctor); - t1.checkpoint(lrf.rank()>0,"construction"); - - double error=lrf.l2error(lrfunctor); - print("l2 error project ",error); - t1.checkpoint(error<2.e-2,"l2 error in projection "+std::to_string(error)); - - auto lrf2(lrf); - error=lrf2.l2error(lrfunctor); - print("l2 error copy ctor ",error); - MADNESS_CHECK(lrf.rank()==lrf2.rank()); - MADNESS_CHECK(&(lrf.g[0]) != &(lrf2.g[0])); // deep copy - t1.checkpoint(error<2.e-2,"l2 error in copy ctor "+std::to_string(error)); - - lrf.optimize(lrfunctor); - error=lrf.l2error(lrfunctor); - print("l2 error optimize",error); - t1.checkpoint(error,1.1e-2,"l2 error in optimization"); - - lrf.reorthonormalize(); - error=lrf.l2error(lrfunctor); - print("l2 error reorthonormalize",error); - t1.checkpoint(error,1.1e-2,"l2 error in reorthonormalization"); + Function one=FunctionFactory(world).functor([](const Vector& r){return exp(-0.4*inner(r,r));}); + Function half=FunctionFactory(world).functor([](const Vector& r){return sqrt(0.5)*exp(-0.4*inner(r,r));}); + + LRFunctorF12 lrfunctor1(slater,one,one); + LRFunctorF12 lrfunctor2(slater,{half,half},{half,half}); + + for (auto& lrfunctor : {lrfunctor1,lrfunctor2}) { + LowRankFunctionFactory builder(parameters); + auto lrf = builder.project(lrfunctor); + t1.checkpoint(lrf.rank() > 0, "construction"); + + // with Slater tol must be relaxed + double tol = 1.e-2; + + double error = lrf.l2error(lrfunctor); + double norm = lrf.norm2(); + print("lrf.norm", norm); + print("l2 error project ", error); + t1.checkpoint(error, tol, "l2 error in projection"); + + auto lrf2(lrf); + error = lrf2.l2error(lrfunctor); + print("l2 error copy ctor ", error); + MADNESS_CHECK(lrf.rank() == lrf2.rank()); + MADNESS_CHECK(&(lrf.g[0]) != &(lrf2.g[0])); // deep copy + t1.checkpoint(error, tol, "l2 error in copy ctor"); + + lrf.optimize(lrfunctor); + error = lrf.l2error(lrfunctor); + print("l2 error optimize", error); + t1.checkpoint(error, tol, "l2 error in optimization"); + + lrf.reorthonormalize(); + error = lrf.l2error(lrfunctor); + print("l2 error reorthonormalize", error); + t1.checkpoint(error, tol, "l2 error in reorthonormalization"); + } return t1.end(); } From 03fe856192bebc7f48500b7026f5c04132eac98e Mon Sep 17 00:00:00 2001 From: fbischoff Date: Mon, 5 Feb 2024 15:44:33 +0100 Subject: [PATCH 085/109] consolidate ccpairfunctions --- src/madness/chem/ccpairfunction.cc | 135 +++++++++++------------- src/madness/chem/ccpairfunction.h | 12 +++ src/madness/chem/lowrankfunction.h | 15 +-- src/madness/chem/test_ccpairfunction.cc | 83 ++++++++++++--- 4 files changed, 149 insertions(+), 96 deletions(-) diff --git a/src/madness/chem/ccpairfunction.cc b/src/madness/chem/ccpairfunction.cc index 5156990d96b..e01a59b65b9 100644 --- a/src/madness/chem/ccpairfunction.cc +++ b/src/madness/chem/ccpairfunction.cc @@ -62,24 +62,40 @@ void CCPairFunction::convert_to_pure_no_op_inplace() { component.reset(new TwoBodyFunctionPureComponent(result)); }; +template +std::vector> CCPairFunction::op_pure_to_pure(const std::vector>& other) { + World& world=other.front().world(); + std::vector> result; + Function pure=FunctionFactory(world); + for (const auto& c : other) { + if (c.is_pure_no_op()) { + pure+=c.get_function(); + } else if (c.is_op_pure()) { + Function tmp=CompositeFactory(world).g12(c.get_operator().get_kernel()).ket(c.get_function()); + tmp.fill_tree(); + pure+=tmp; + } else if (c.is_decomposed()) { + result.push_back(c); + } + } + if (pure.is_initialized()) result.push_back(CCPairFunction(pure)); + return result; +} + /// turn decomposed functions with operator into decomposed functions using LowRankFunction template std::vector> CCPairFunction::op_dec_to_dec(const std::vector>& other) { LowRankFunctionParameters lrparameters; auto builder = LowRankFunctionFactory(lrparameters); - builder.set_volume_element(3.e-2); - builder.parameters.print("lrparameters"); +// builder.set_volume_element(3.e-2); +// builder.parameters.print("lrparameters"); std::vector> result; for (const auto& c : other) { if (c.is_op_decomposed()) { - LRFunctorF12 functor(c.get_operator_ptr()->get_op(),c.get_a().front(),c.get_b().front()); + LRFunctorF12 functor(c.get_operator_ptr()->get_op(),c.get_a(),c.get_b()); LowRankFunction tmp=builder.project(functor); double l2error=tmp.l2error(functor); - print("error",l2error); tmp.optimize(functor); - l2error=tmp.l2error(functor); - print("error after optimization",l2error); - print("rank after optimization",tmp.rank()); result.push_back(CCPairFunction(tmp.get_g(),tmp.get_h())); } else { result.push_back(c); @@ -89,11 +105,13 @@ std::vector> CCPairFunction::op_dec_to_dec(const } -/// collect all terms with the same operator +/// collect all terms with of similiar type: pure, op_pure, decomposed, op_decomposed template std::vector> CCPairFunction::collect_same_types(const std::vector>& other) { if (other.size()==0) return other; + if (is_collected(other)) return other; + World& world=other.front().world(); /// vector includes OT_ONE, meaning no operator @@ -102,43 +120,57 @@ std::vector> CCPairFunction::collect_same_types(c std::vector>> op_decomposed_b(OT_SIZE); std::vector>> ops(OT_SIZE); + // collect terms of the same type for (const auto& c : other) { - if (c.has_operator()) { - int iop=int(c.get_operator().type()); - ops[iop]=c.get_operator_ptr(); - } - int iop=int(c.get_operator().type()); + int iop= (c.has_operator()) ? int(c.get_operator().type()) : OT_ONE; + ops[iop]=c.get_operator_ptr(); if (c.is_decomposed()) { op_decomposed_a[iop]=append(op_decomposed_a[iop],c.get_a()); - op_decomposed_b[iop]=append(op_decomposed_a[iop],c.get_b()); + op_decomposed_b[iop]=append(op_decomposed_b[iop],c.get_b()); } else if (c.is_pure()) { op_pure[iop].push_back(c.get_function()); } } std::vector> result; - // accumulate all op_pure functions + + // accumulate all terms of the same type for (int opint=OT_ONE; opint0) { -// auto op=CCConvolutionOperatorPtr(world,OpType(opint),CCParameters()); auto op=ops[opint]; - Function tmp=CompositeFactory(world).ket(op_pure[opint]); - tmp.fill_tree(); - result.push_back(CCPairFunction(op,tmp)); - } - if (op_decomposed_a[opint].size()>0) { - - if (opint!=OT_ONE) { -// auto op=CCConvolutionOperatorPtr(world,OpType(opint),CCParameters()); - result.push_back(CCPairFunction(ops[opint],op_decomposed_a[opint],op_decomposed_b[opint])); + if (op_pure[opint].size()>1) { + Function tmp=CompositeFactory(world).ket(op_pure[opint]); + tmp.fill_tree(); + result.push_back(CCPairFunction(op,tmp)); } else { - result.push_back(CCPairFunction(op_decomposed_a[opint],op_decomposed_b[opint])); + MADNESS_CHECK_THROW(op_pure[opint].size()==1,"op_pure[opint].size()!=1"); + result.push_back(CCPairFunction(op,op_pure[opint].front())); } } + if (op_decomposed_a[opint].size()>0) { + result.push_back(CCPairFunction(ops[opint],op_decomposed_a[opint],op_decomposed_b[opint])); + } } return result; } +template +bool CCPairFunction::is_collected(const std::vector>& other) { + + // simply count the occurence of each term + std::map counter; + for (const auto& c : other) { + int index=0; + if (c.has_operator()) index=int(c.get_operator().type()) *100; + if (c.is_op_pure()) index+=1; + if (c.is_op_decomposed()) index+=2; + if (c.is_pure_no_op()) index+=3; + if (c.is_decomposed_no_op()) index+=4; + counter[index]++; + } + for (const auto& c : counter) if (c.second>1) return false; + return true; +} template std::vector> CCPairFunction::consolidate(const std::vector>& other, @@ -153,57 +185,14 @@ std::vector> CCPairFunction::consolidate(const st // reorthogonalize decomposed functions and op_decomposed functions bool svd=find(options.begin(),options.end(),"svd")!=options.end(); - - std::vector> result; - - // sort the terms into pure, decomposed, op_decomposed, op_pure - std::vector> pure; - std::vector>> op_pure(OT_SIZE); - for (auto& c : other) { - if (c.is_pure_no_op()) { - pure.push_back(c.get_function()); - } else if (c.is_op_pure()) { - int opint=int(c.get_operator().type()); - op_pure[opint].push_back(c.get_function()); - } - - else { - result.push_back(c); - } - } - // accumulate all pure functions - if (pure.size()>0) { - Function pure_result=CompositeFactory(world()).ket(pure); - pure_result.fill_tree(); - result.push_back(CCPairFunction(pure_result)); - } - - // accumulate all op_pure functions - for (int opint=OT_G12; opint0) { - auto op=CCConvolutionOperatorPtr(world(),OpType(opint),CCParameters()); - print("consolidating",op->name()); - Function tmp; - if (op_pure_to_pure) { - tmp=CompositeFactory(world()).ket(op_pure[opint]).g12(op->get_kernel()); - tmp.fill_tree(); - result.push_back(CCPairFunction(tmp)); - } else { - tmp=CompositeFactory(world()).ket(op_pure[opint]); - tmp.fill_tree(); - result.push_back(CCPairFunction(op,tmp)); - } - } - } + // always collect all terms of the same type + auto result= is_collected(other) ? other : collect_same_types(other); if (op_dec_to_dec) result=CCPairFunction::op_dec_to_dec(result); + if (op_pure_to_pure) result=CCPairFunction::op_pure_to_pure(result); + if (not is_collected(result)) result=collect_same_types(result); -// if (not all_pure.empty()) { -// for (std::size_t i=1; i(all_pure.front())); -// } return result; } diff --git a/src/madness/chem/ccpairfunction.h b/src/madness/chem/ccpairfunction.h index 8bddf32e948..bbe00612706 100644 --- a/src/madness/chem/ccpairfunction.h +++ b/src/madness/chem/ccpairfunction.h @@ -399,14 +399,21 @@ using pureT=Function; return result; } +private: std::vector consolidate(const std::vector& other, std::vector options={}) const; /// turn decomposed functions with operator into decomposed functions using LowRankFunction static std::vector op_dec_to_dec(const std::vector& other); + /// turn pure functions with operator into pure functions without operators + static std::vector op_pure_to_pure(const std::vector& other); + static std::vector collect_same_types(const std::vector& other); +public: + // check if all types (pure. op_pure, decomposed, op_decomposed, with various ops) occur only once + static bool is_collected(const std::vector>& other); /// collect the terms into a compact format @@ -865,6 +872,11 @@ std::vector> inner(const std::vector +bool is_collected(const std::vector>& other) { + return CCPairFunction::is_collected(other); + +} } // namespace madness #endif //MADNESS_CCPAIRFUNCTION_H diff --git a/src/madness/chem/lowrankfunction.h b/src/madness/chem/lowrankfunction.h index 7db22de7074..54390dc4914 100644 --- a/src/madness/chem/lowrankfunction.h +++ b/src/madness/chem/lowrankfunction.h @@ -312,18 +312,11 @@ struct LRFunctorF12 : public LRFunctorBase { MADNESS_CHECK_THROW(this->a.size()==this->b.size(), "a and b must have the same size"); } - LRFunctorF12(const std::shared_ptr> f12, const Function& a, - const Function& b) : f12(f12), a({a}), b({b}) { + /// delegate to the other ctor with vector arguments + LRFunctorF12(const std::shared_ptr> f12, + const Function& a, const Function& b) + : LRFunctorF12(f12,std::vector>({a}), std::vector>({b})) {} - // if a or b are missing, they are assumed to be 1 - // you may not provide a or b, but if you do they have to have the same size because they are summed up - if (a.size()>0 and b.size()>0) - MADNESS_CHECK_THROW(a.size()==b.size(), "a and b must have the same size"); - if (a.size()==0) this->a.resize(1); - if (b.size()==0) this->b.resize(1); - MADNESS_CHECK_THROW(this->a.size()==this->b.size(), "a and b must have the same size"); - - } private: std::shared_ptr> f12; ///< a two-particle function diff --git a/src/madness/chem/test_ccpairfunction.cc b/src/madness/chem/test_ccpairfunction.cc index bbd2be5eb48..d3762c7161b 100644 --- a/src/madness/chem/test_ccpairfunction.cc +++ b/src/madness/chem/test_ccpairfunction.cc @@ -12,6 +12,7 @@ #include #include +#include using namespace madness; @@ -742,7 +743,7 @@ int test_consolidate(World& world, std::shared_ptr ncf test_output t1("CCPairFunction::test_consolidate"); static_assert(NDIM % 2 == 0, "NDIM must be even"); constexpr std::size_t LDIM = NDIM / 2; - t1.set_cout_to_terminal(); +// t1.set_cout_to_terminal(); /// f12: exp(-r_1^2 - 2 r_2^2) /// f23: exp(-r_1^2 - 2 r_2^2) + exp(-2 r_1^2 - 3 r_2^2) @@ -753,24 +754,85 @@ int test_consolidate(World& world, std::shared_ptr ncf /// p5: op_pure, corresponds to f23 auto [p1,p2,p3,p4,p5]=data.get_ccpairfunctions(); + // collect all terms of similar type, no conversions for (const auto& p : {p1,p4,p5}) { auto tmp=std::vector>({p,p}); - + double r0=inner(p,{p1}); double r1=inner(tmp,{p1}); - print("r1",r1); - auto tmp1=consolidate(tmp,{"sdf"}); + auto tmp1=consolidate(tmp,{}); double r2=inner(tmp1,{p1}); - print("r2",r2); - t1.checkpoint(tmp1.size()==1 && tmp.size()==2,"vector size"); - t1.checkpoint(r1,r2,FunctionDefaults::get_thresh(),"consolidate"); - + t1.checkpoint(2.0*r0,r1,FunctionDefaults::get_thresh(),"consolidate"); + t1.checkpoint(2.0*r0,r2,FunctionDefaults::get_thresh(),"consolidate"); } - throw; + // convert op_pure to pure + for (const auto& p : {p5}) { + auto tmp=std::vector>({p}); + t1.checkpoint(tmp.front().is_op_pure(),"correct initial type: op_pure"); + auto tmp1=consolidate(tmp,{"op_pure_to_pure"}); + t1.checkpoint(tmp1.front().is_pure_no_op(),"correct final type: pure"); + t1.checkpoint(is_collected(tmp1),"is_collected"); + + double r0=inner(p,{p1}); + double r1=inner(tmp,{p1}); + t1.checkpoint(r0,r1,FunctionDefaults::get_thresh(),"correct numbers"); + } + // convert op_decomposed to decomposed + for (const auto& p : {p3}) { + auto tmp=std::vector>({p}); + t1.checkpoint(tmp.front().is_op_decomposed(),"correct initial type: op_decomposed"); + auto tmp1=consolidate(tmp,{"op_dec_to_dec"}); + t1.checkpoint(tmp1.front().is_decomposed_no_op(),"correct final type: decomposed"); + double r0=inner(p,{p1}); + double r1=inner(tmp,{p1}); + t1.checkpoint(r0,r1,FunctionDefaults::get_thresh(),"correct numbers"); + } + // some random composition of the above + // a vector of numerically identical terms is created, then a random permutation is applied, and the result is checked + for (int i=0; i<5; ++i) { + std::vector> pvec={p2,p3,p4,p5}; // numerically all the same + + std::random_device rd; // a seed source for the random number engine + std::mt19937 gen(rd()); // mersenne_twister_engine seeded with rd() + std::uniform_int_distribution<> distrib(0, 3); + std::vector mapping(5); + for (int i=0; i<5; ++i) mapping[i]=distrib(gen); + print("mapping",mapping); + + std::vector> tmp; + for (auto m: mapping) tmp.push_back(pvec[m]); + + double n0=inner({p1},tmp); + + auto tmp1=consolidate(tmp,{}); // collect only, no conversions + print("tmp"); + for (auto& c : tmp) c.print_size(); + print("tmp1"); + for (auto& c : tmp1) c.print_size(); + + t1.checkpoint(is_collected(tmp1),"random is_collected"); + double n1=inner({p1},tmp1); + t1.checkpoint(n0,n1,FunctionDefaults::get_thresh(),"random collect numerics"); + + tmp1=consolidate(tmp1,{"op_pure_to_pure"}); // + print("tmp1 after op_pure_to_pure"); + for (auto& c : tmp1) c.print_size(); + t1.checkpoint(is_collected(tmp1),"random is_collected"); + double n2=inner({p1},tmp1); + t1.checkpoint(n0,n2,FunctionDefaults::get_thresh(),"random op_pure_to_pure numerics"); + + tmp1=consolidate(tmp1,{"op_dec_to_dec"}); // + print("tmp1 after op_dec_to_dec"); + for (auto& c : tmp1) c.print_size(); + t1.checkpoint(is_collected(tmp1),"random is_collected"); + double n3=inner({p1},tmp1); + t1.checkpoint(n0,n3,FunctionDefaults::get_thresh(),"random op_dec_to_dec numerics"); + t1.checkpoint(tmp1.size()<=2,"only max. two types of terms after consolidate"); + } return t1.end(); } @@ -1163,9 +1225,6 @@ int main(int argc, char **argv) { auto data4=data(world,ccparam); auto data6=data(world,ccparam); - isuccess+=test_consolidate(world, ncf, data2, ccparam); - - throw; isuccess+=test_constructor(world, ncf, data2, ccparam); isuccess+=test_operator_apply(world, ncf, data2, ccparam); isuccess+=test_transformations(world, ncf, data2, ccparam); From b3e94dcc2ded459ff27f8be2433a9bb040b358b1 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Thu, 8 Feb 2024 15:09:58 +0100 Subject: [PATCH 086/109] mp3 working for he, he2 and maybe h2o --- src/madness/chem/ccpairfunction.h | 9 +++ src/madness/chem/mp2.cc | 98 +++++++++++++++++++++------- src/madness/world/timing_utilities.h | 41 +++++++++--- 3 files changed, 116 insertions(+), 32 deletions(-) diff --git a/src/madness/chem/ccpairfunction.h b/src/madness/chem/ccpairfunction.h index bbe00612706..ce052136752 100644 --- a/src/madness/chem/ccpairfunction.h +++ b/src/madness/chem/ccpairfunction.h @@ -872,6 +872,15 @@ std::vector> inner(const std::vector +std::vector >& operator+=(std::vector >& rhs, + const std::vector >& lhs) { + for (const auto& l : lhs) rhs.push_back(l); + return rhs; +} + + template bool is_collected(const std::vector>& other) { return CCPairFunction::is_collected(other); diff --git a/src/madness/chem/mp2.cc b/src/madness/chem/mp2.cc index c32726aa80d..f4579dbfcae 100644 --- a/src/madness/chem/mp2.cc +++ b/src/madness/chem/mp2.cc @@ -302,16 +302,21 @@ double MP2::mp3() const { } } } - Pairs clusterfunctions_R2; - for (int i=param.freeze(); inocc(); ++i) { - for (int j=i; jnocc(); ++j) { - { - auto tmp1 = multiply(clusterfunctions(i, j), R2, {0, 1, 2}); - auto tmp2 = multiply(tmp1, R2, {3, 4, 5}); - for (auto& t: tmp2) clusterfunctions_R2(i, j).push_back(t); - } - } - } +// Pairs clusterfunctions_R2; +// for (int i=param.freeze(); inocc(); ++i) { +// for (int j=i; jnocc(); ++j) { +// { +// auto tmp1 = multiply(clusterfunctions(i, j), R2, {0, 1, 2}); +// auto tmp2 = multiply(tmp1, R2, {3, 4, 5}); +// for (auto& t: tmp2) clusterfunctions_R2(i, j).push_back(t); +// if (i!=j) { +// for (const auto& t : clusterfunctions_R2(i,j)) { +// clusterfunctions_R2(j, i).push_back(t.swap_particles()); +// } +// } +// } +// } +// } for (int i = param.freeze(); i < hf->nocc(); ++i) { for (int j = i; j < hf->nocc(); ++j) { @@ -386,10 +391,9 @@ double MP2::mp3() const { // compute intermediates for terms G, I, H, and J // \sum_j tau_ij(1,2) * phi_j(2) - std::vector tau_kk_i(hf->nocc() - param.freeze()); - std::vector tau_kk_i_lrf(hf->nocc() - param.freeze()); // low-rank + std::vector tau_kk_i(hf->nocc()); // \sum_j tau_ij(1,2) * phi_j(1) - std::vector tau_ij_j(hf->nocc() - param.freeze()); + std::vector tau_ij_j(hf->nocc()); for (int i = param.freeze(); i < hf->nocc(); ++i) { for (int j = param.freeze(); j < hf->nocc(); ++j) { @@ -402,10 +406,7 @@ double MP2::mp3() const { } print("info on tau_kk_i, consolidated with op_pure_to_pure"); for (int i = param.freeze(); i < hf->nocc(); ++i) { - tau_kk_i[i]=consolidate(tau_kk_i[i],{"op_pure_to_pure"}); - for (auto& c: tau_kk_i[i]) c.info(); - print("info on tau_kk_i, consolidated with op_dec_to_dec"); - tau_kk_i[i]=consolidate(tau_kk_i[i],{"op_dec_to_dec"}); + tau_kk_i[i]=consolidate(tau_kk_i[i],{"op_pure_to_pure","op_dec_to_dec"}); for (auto& c: tau_kk_i[i]) c.info(); } print("info on tau_ij_j, consolidated with op_pure_to_pure"); @@ -414,7 +415,7 @@ double MP2::mp3() const { for (auto& c: tau_ij_j[i]) c.info(); } - t2.tag("GHIJ prep"); + t2.tag("GHIJ term prep"); // terms G, I, H, J of Bartlett/Silver 1975 real_convolution_3d& g = *(g12->get_op()); @@ -425,15 +426,15 @@ double MP2::mp3() const { g.set_particle(1); auto gtau_same = g(tau_kk_i[i]); t4.tag("compute gtau_same"); -// gtau_same=consolidate(gtau_same,{"op_pure_to_pure"}); -// t4.tag("consolidate gtau_same"); + // gtau_same=consolidate(gtau_same,{"op_pure_to_pure"}); + // t4.tag("consolidate gtau_same"); // tmp(1',2) = g(1',1) | tau_ij(1,2) j(1) > g.set_particle(1); auto gtau_other = g(tau_ij_j[i]); // < tau_ij(1,2) j(1) | g(1,1') | t4.tag("compute gtau_other"); -// gtau_other=consolidate(gtau_other,{"op_pure_to_pure"}); -// t4.tag("consolidate gtau_other"); + // gtau_other=consolidate(gtau_other,{"op_pure_to_pure"}); + // t4.tag("consolidate gtau_other"); auto bra_kk_i = multiply(tau_kk_i[i],R2,{3,4,5}); auto bra_ij_j = multiply(tau_ij_j[i],R2,{3,4,5}); @@ -457,7 +458,54 @@ double MP2::mp3() const { } printf("MP3 energy: term_GHIJ %12.8f\n", term_GHIJ); t2.tag("GHIJ term"); + } + + + if (1) { // new KLMN algorithm + timer multiply_KLMN(world,"multiplication in KLMN term"); + multiply_KLMN.interrupt(); + timer inner_KLMN(world,"inner in KLMN term"); + inner_KLMN.interrupt(); + // prepare intermediates for terms K, L, M, N of Bartlett/Silver 1975 + // tau_g_ij(1,2) = \sum_k tau_ik(1,1') g_jk(2) + Pairs tau_ik_g_kj, tau_kj_g_ki; + for (int i = param.freeze(); i < hf->nocc(); ++i) { + for (int j = param.freeze(); j < hf->nocc(); ++j) { + multiply_KLMN.resume(); + std::vector> tmp1, tmp2; + for (int k = param.freeze(); k < hf->nocc(); ++k) { + tmp1+=multiply(clusterfunctions(i,k), gij(k, j), {3, 4, 5}); + tmp2+=multiply(clusterfunctions(k,j), gij(k, i), {3, 4, 5}); + } + tmp1=consolidate(tmp1,{}); + tmp2=consolidate(tmp2,{}); + tau_ik_g_kj(i,j)=tmp1; + tau_kj_g_ki(i,j)=tmp2; + multiply_KLMN.interrupt(); + + inner_KLMN.resume(); + double K = inner(clusterfunctions(i,j), tau_ik_g_kj(i,j), R2); + double L = inner(clusterfunctions(i,j), tau_kj_g_ki(i,j), R2); + double M = inner(clusterfunctions(j,i), tau_kj_g_ki(i,j), R2); + double N = inner(clusterfunctions(j,i), tau_ik_g_kj(i,j), R2); + inner_KLMN.interrupt(); + + double tmp = -4 * K - 4 * L + 2 * M + 2 * N; + printf("mp3 energy: term_KLMN with particle=1 %2d %2d %12.8f\n", i, j, tmp); + term_KLMN += tmp; + } + } + printf("MP3 energy: term_KLMN (KLMN) %12.8f\n", term_KLMN); + multiply_KLMN.print("multiplication in KLMN term"); + inner_KLMN.print("inner in KLMN term"); + t2.tag("KLMN term"); + } + if (0) { // old KLMN algorithm + timer multiply_KLMN(world,"multiplication in KLMN term"); + multiply_KLMN.interrupt(); + timer inner_KLMN(world,"inner in KLMN term"); + inner_KLMN.interrupt(); for (int i = param.freeze(); i < hf->nocc(); ++i) { for (int j = param.freeze(); j < hf->nocc(); ++j) { double tmp = 0.0; @@ -467,15 +515,19 @@ double MP2::mp3() const { auto tau_kj = clusterfunctions(k, j); auto tau_ij = clusterfunctions(i, j); auto tau_ji = clusterfunctions(j, i); + multiply_KLMN.resume(); auto tau_ik_gkj = multiply(tau_ik, gij(k, j), {3, 4, 5}); auto tau_kj_gki = multiply(tau_kj, gij(k, i), {3, 4, 5}); + multiply_KLMN.interrupt(); // auto tau_ik_gkj = multiply(tau_ik,gij(k,j),{0,1,2}); // auto tau_kj_gki = multiply(tau_kj,gij(k,i),{0,1,2}); + inner_KLMN.resume(); double K = inner(tau_ij, tau_ik_gkj, R2); double L = inner(tau_ij, tau_kj_gki, R2); double M = inner(tau_ji, tau_kj_gki, R2); double N = inner(tau_ji, tau_ik_gkj, R2); + inner_KLMN.interrupt(); tmp += -4 * K - 4 * L + 2 * M + 2 * N; } @@ -484,6 +536,8 @@ double MP2::mp3() const { } } printf("MP3 energy: term_KLMN (KLMN) %12.8f\n", term_KLMN); + multiply_KLMN.print("multiplication in KLMN term"); + inner_KLMN.print("inner in KLMN term"); t2.tag("KLMN term"); } diff --git a/src/madness/world/timing_utilities.h b/src/madness/world/timing_utilities.h index 35b443b12ed..db47c7e36db 100644 --- a/src/madness/world/timing_utilities.h +++ b/src/madness/world/timing_utilities.h @@ -8,28 +8,49 @@ namespace madness { struct timer { World &world; - double ttt, sss; + double ttt=0.0, sss=0.0; // duration bool do_print = true; + bool is_running=false; timer(World &world, bool do_print = true) : world(world), do_print(do_print) { world.gop.fence(); - ttt = wall_time(); - sss = cpu_time(); + resume(); } - double tag(const std::string msg) { + void resume() { + if (is_running) print("timer was already running!"); world.gop.fence(); - double tt1 = wall_time() - ttt; - double ss1 = cpu_time() - sss; + ttt-=wall_time(); + sss-=cpu_time(); + is_running=true; + } + + double interrupt() { + world.gop.fence(); + ttt+=wall_time(); + sss+=cpu_time(); + is_running=false; + return sss; + } + + void print(const std::string msg) const { if (world.rank() == 0 and do_print) { std::stringstream ss; ss << "timer:" << std::setw(30) << msg << std::setw(8) << std::setprecision(2) - << std::fixed << ss1 << "s " << tt1 <<"s"; + << std::fixed << sss << "s " << ttt <<"s"; std::cout << ss.str() << std::endl; } - ttt = wall_time(); - sss = cpu_time(); - return ss1; + } + + double tag(const std::string msg) { + world.gop.fence(); + interrupt(); + print(msg); + double cpu=sss; + ttt=0.0; + sss=0.0; + resume(); + return cpu; } double end(const std::string msg) { From f999adf96c66814b651a1846c9f16204f3b852be Mon Sep 17 00:00:00 2001 From: fbischoff Date: Mon, 12 Feb 2024 09:27:01 +0100 Subject: [PATCH 087/109] mp3 working for h2o, but inaccurate due to misplaced random grid --- src/madness/chem/mp2.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/madness/chem/mp2.cc b/src/madness/chem/mp2.cc index f4579dbfcae..0131703ed2a 100644 --- a/src/madness/chem/mp2.cc +++ b/src/madness/chem/mp2.cc @@ -397,8 +397,11 @@ double MP2::mp3() const { for (int i = param.freeze(); i < hf->nocc(); ++i) { for (int j = param.freeze(); j < hf->nocc(); ++j) { - auto tmp1 = multiply(clusterfunctions(i, j), hf->R2orbital(j), {0, 1, 2}); - for (auto& t: tmp1) tau_kk_i[i].push_back(t); + auto tmp2=multiply(clusterfunctions(i,j),hf->R2orbital(i),{0,1,2}); + for (auto& t : tmp2) tau_kk_i[j].push_back(t); + + // auto tmp1 = multiply(clusterfunctions(i, j), hf->R2orbital(j), {0, 1, 2}); + // for (auto& t: tmp1) tau_kk_i[i].push_back(t); auto tmp3 = multiply(clusterfunctions(i, j), hf->R2orbital(j), {0, 1, 2}); for (auto& t: tmp3) tau_ij_j[i].push_back(t); @@ -535,7 +538,7 @@ double MP2::mp3() const { term_KLMN += tmp; } } - printf("MP3 energy: term_KLMN (KLMN) %12.8f\n", term_KLMN); + printf("MP3 energy: term_KLMN (KLMN), old algorithm %12.8f\n", term_KLMN); multiply_KLMN.print("multiplication in KLMN term"); inner_KLMN.print("inner in KLMN term"); t2.tag("KLMN term"); From 8546f594c68f05657be629b2c319fdaea66e7045 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Wed, 14 Feb 2024 10:56:04 +0100 Subject: [PATCH 088/109] move mp3 to cc2 code --- src/madness/chem/CC2.cc | 266 +++++++++++----------------------------- src/madness/chem/CC2.h | 4 + 2 files changed, 76 insertions(+), 194 deletions(-) diff --git a/src/madness/chem/CC2.cc b/src/madness/chem/CC2.cc index e9ac32e2155..236ea9606d7 100644 --- a/src/madness/chem/CC2.cc +++ b/src/madness/chem/CC2.cc @@ -10,6 +10,7 @@ #include #include "MolecularOrbitals.h" #include "localizer.h" +#include namespace madness { @@ -363,38 +364,15 @@ Tensor CC2::enforce_core_valence_separation(const Tensor& fmat) }; -double CC2::mp3_energy_contribution(const Pairs& mp2pairs) const { - - print_header2("computing the MP3 correlation energy"); - print_header3("prepare the cluster function"); +double CC2::compute_mp3_cd(const Pairs& mp2pairs) const { + print_header3("compute term_CD of the MP3 energy with R2_bra"); + // compute the MP3 energy + std::size_t nocc=CCOPS.mo_ket().size(); typedef std::vector> ClusterFunction; Pairs clusterfunctions; - - auto R2 = nemo->ncf->square(); - auto R = nemo->ncf->function(); - std::vector nemo_orbital=CCOPS.mo_ket().get_vecfunction(); - std::vector R2_orbital=CCOPS.mo_bra().get_vecfunction(); - const int nocc=CCOPS.mo_ket().size(); - - - double mp3_energy = 0.0; - // load converged MP1 wave functions for (int i = parameters.freeze(); i < nocc; ++i) { for (int j = i; j < nocc; ++j) { -// pairs(i, j) = make_pair(i, j); // initialize - ClusterFunction tmp; - tmp.push_back(CCPairFunction(mp2pairs(i, j).function())); - CCPairFunction ij(nemo->get_calc()->amo[i], nemo->get_calc()->amo[j]); - - CCConvolutionOperator::Parameters cparam; - cparam.thresh_op *= 0.1; - auto f12 = CCConvolutionOperatorPtr(world, OpType::OT_F12, cparam); - StrongOrthogonalityProjector Q12(world); - Q12.set_spaces(R2_orbital, nemo_orbital, R2_orbital, nemo_orbital); - auto vfij = Q12(std::vector>({f12 * ij})); - for (auto& p: vfij) tmp.push_back(p); - - clusterfunctions(i, j)=tmp; + clusterfunctions(i,j)=mp2pairs(i,j).functions; if (i!=j) { for (const auto& t : clusterfunctions(i,j)) { clusterfunctions(j, i).push_back(t.swap_particles()); @@ -402,188 +380,64 @@ double CC2::mp3_energy_contribution(const Pairs& mp2pairs) const { } } } - Pairs clusterfunctions_R2; - for (int i=parameters.freeze(); iR_square; CCConvolutionOperator::Parameters cparam; auto g12=CCConvolutionOperatorPtr(world,OpType::OT_G12,cparam); - timer t2(world, "recompute MP2"); - // recompute MP2 energy - double mp2_energy=0.0; + timer t2(world); + double result = 0.0; for (int i = parameters.freeze(); i < nocc; ++i) { for (int j = i; j < nocc; ++j) { - - auto bra=CCPairFunction(R2_orbital[i],R2_orbital[j]); - double direct=inner({bra},g12*clusterfunctions(i,j)); - double exchange=inner({bra},g12*clusterfunctions(j,i)); - double fac=(i==j) ? 0.5: 1.0; - double pair_energy=fac*(4.0*direct-2.0*exchange); - printf("MP2 energy for pair %2d %2d: %12.8f\n",i,j,pair_energy); - mp2_energy+=pair_energy; + auto bra = clusterfunctions(i, j); + double tmp1 = inner(bra, g12 * clusterfunctions(i, j), R2); + double tmp2 = inner(bra, g12 * clusterfunctions(j, i), R2); + double fac = (i == j) ? 0.5 : 1.0; + double tmp = fac * (4.0 * tmp1 - 2.0 * tmp2); + printf("mp3 energy: term_CD %2d %2d: %12.8f\n", i, j, tmp); + result+= tmp; } } - printf("total mp2 energy %12.8f\n",mp2_energy); - t2.tag("recompute MP2 energy"); + printf("MP3 energy: term_CD %12.8f\n", result); + t2.tag("CD term"); + return result; +}; - print_header3("compute the MP3 energy"); +double CC2::compute_mp3_ef(const Pairs& mp2pairs) const { - // compute the term (2) - madness::Pairs gij; + // prepare cluster functions + std::size_t nocc=CCOPS.mo_ket().size(); + typedef std::vector> ClusterFunction; + Pairs clusterfunctions; for (int i = parameters.freeze(); i < nocc; ++i) { - for (int j = parameters.freeze(); j < nocc; ++j) { - gij.insert(i,j,(*g12)(nemo_orbital[i]*R2_orbital[j])); - } - } - - double term_CD=0.0; - double term_GHIJ=0.0; - double term_KLMN=0.0; - double term_EF=0.0; - - if (1) { - print_header3("compute term_CD of the MP3 energy with R2_bra"); - // compute the MP3 energy - if (1) { - for (int i = parameters.freeze(); i < nocc; ++i) { - for (int j = i; j < nocc; ++j) { - auto bra = clusterfunctions(i, j); - double tmp1 = inner(bra, g12 * clusterfunctions(i, j), R2); - double tmp2 = inner(bra, g12 * clusterfunctions(j, i), R2); -// auto bra = clusterfunctions_R2(i, j); -// double tmp1 = inner(bra, g12 * clusterfunctions(i, j)); -// double tmp2 = inner(bra, g12 * clusterfunctions(j, i)); - double fac = (i == j) ? 0.5 : 1.0; - double tmp = fac * (4.0 * tmp1 - 2.0 * tmp2); - printf("mp3 energy: term_CD %2d %2d: %12.8f\n", i, j, tmp); - term_CD += tmp; + for (int j = i; j < nocc; ++j) { + clusterfunctions(i,j)=mp2pairs(i,j).functions; + if (i!=j) { + for (const auto& t : clusterfunctions(i,j)) { + clusterfunctions(j, i).push_back(t.swap_particles()); } } } - printf("MP3 energy: term_CD %12.8f\n", term_CD); - t2.tag("CD term"); - - - // compute intermediates for terms G, I, H, and J - - // note: elements with frozen orbitals are left empty - // \sum_j tau_ij(1,2) * phi_j(2) - std::vector tau_kk_i(nocc); // was (nocc - nfrozen) - // \sum_j tau_ij(1,2) * phi_j(1) - std::vector tau_ij_j(nocc); - for (int i = parameters.freeze(); i < nocc; ++i) { - for (int j = parameters.freeze(); j < nocc; ++j) { - - auto tmp1 = multiply(clusterfunctions(i, j), R2_orbital[j], {3, 4, 5}); - for (auto& t: tmp1) tau_kk_i[i].push_back(t); - - auto tmp3 = multiply(clusterfunctions(i, j), R2_orbital[j], {0, 1, 2}); - for (auto& t: tmp3) tau_ij_j[i].push_back(t); - } - } - print("info on tau_kk_i"); - for (int i = parameters.freeze(); i < nocc; ++i) { - for (auto& c: tau_kk_i[i]) c.info(); - } - print("info on tau_ij_j"); - for (int i = parameters.freeze(); i < nocc; ++i) { - for (auto& c: tau_ij_j[i]) c.info(); - } - - t2.tag("GHIJ prep"); - - // terms G, I, H, J of Bartlett/Silver 1975 - real_convolution_3d& g = *(g12->get_op()); - for (int i = parameters.freeze(); i < nocc; ++i) { - - // tmp(1,2) = g(1,1') | tau_ij(1',2) j(2) > - timer t4(world, "gtau"); - g.set_particle(1); - auto gtau_same = g(tau_kk_i[i]); - t4.tag("compute gtau_same"); - - // tmp(1',2) = g(1',1) | tau_ij(1,2) j(1) > - g.set_particle(1); - auto gtau_other = g(tau_ij_j[i]); // < tau_ij(1,2) j(1) | g(1,1') | - t4.tag("compute gtau_other"); - + } - auto bra_kk_i = multiply(tau_kk_i[i],R2,{3,4,5}); - auto bra_ij_j = multiply(tau_ij_j[i],R2,{3,4,5}); - double G = inner(bra_kk_i, gtau_same); - printf("G %12.8f\n", G); - double H = inner(bra_ij_j, gtau_other); - printf("H %12.8f\n", H); + const auto& R2=nemo->R_square; + double result=0.0; + const std::vector& nemo_orbital=CCOPS.mo_ket().get_vecfunction(); + const std::vector& R2_orbital=CCOPS.mo_bra().get_vecfunction(); - double I = inner(bra_kk_i, gtau_other); - printf("I %12.8f\n", I); + CCConvolutionOperator::Parameters cparam; + auto g12=CCConvolutionOperatorPtr(world,OpType::OT_G12,cparam); - double J = inner(bra_ij_j, gtau_same); - printf("J %12.8f\n", J); + timer t2(world); - t4.tag("compute inner products"); - double tmp = (8.0 * G - 4.0 * I + 2.0 * H - 4.0 * J); - printf("mp3 energy: term_GHIJ %2d %12.8f\n", i, tmp); - term_GHIJ += tmp; - } - printf("MP3 energy: term_GHIJ %12.8f\n", term_GHIJ); - t2.tag("GHIJ term"); - - for (int i = parameters.freeze(); i < nocc; ++i) { - for (int j = parameters.freeze(); j < nocc; ++j) { - double tmp = 0.0; - for (int k = parameters.freeze(); k < nocc; ++k) { - - auto tau_ik = clusterfunctions(i, k); - auto tau_kj = clusterfunctions(k, j); - auto tau_ij = clusterfunctions(i, j); - auto tau_ji = clusterfunctions(j, i); - auto tau_ik_gkj = multiply(tau_ik, gij(k, j), {3, 4, 5}); - auto tau_kj_gki = multiply(tau_kj, gij(k, i), {3, 4, 5}); -// auto tau_ik_gkj = multiply(tau_ik,gij(k,j),{0,1,2}); -// auto tau_kj_gki = multiply(tau_kj,gij(k,i),{0,1,2}); - - double K = inner(tau_ij, tau_ik_gkj, R2); - double L = inner(tau_ij, tau_kj_gki, R2); - double M = inner(tau_ji, tau_kj_gki, R2); - double N = inner(tau_ji, tau_ik_gkj, R2); - - tmp += -4 * K - 4 * L + 2 * M + 2 * N; - } - printf("mp3 energy: term_KLMN with particle=1 %2d %2d %12.8f\n", i, j, tmp); - term_KLMN += tmp; - } - } - printf("MP3 energy: term_KLMN (KLMN) %12.8f\n", term_KLMN); - t2.tag("KLMN term"); - } print_header3("computing term EF of the MP3 energy with R2_bra"); for (int i = parameters.freeze(); i < nocc; ++i) { for (int j = parameters.freeze(); j < nocc; ++j) { double tmp=0.0; - for (int k=parameters.freeze(); k& mp2pairs) const { } } printf("mp3 energy: term_EF %2d %2d %12.8f\n",i,j,tmp); - term_EF+=tmp; + result+=tmp; } } - printf("MP3 energy: term_EF %12.8f\n",term_EF); + printf("MP3 energy: term_EF %12.8f\n",result); t2.tag("EF term"); + return result; +}; + +double CC2::compute_mp3_ghij(const Pairs& mp2pairs) const { + + double result=0.0; + return result; +}; +double CC2::compute_mp3_klmn(const Pairs& mp2pairs) const { + double result=0.0; + return result; + +}; - printf("term_CD %12.8f\n",term_CD); - printf("term_GHIJ %12.8f\n",term_GHIJ); - printf("term_KLMN %12.8f\n",term_KLMN); - printf("term_EF %12.8f\n",term_EF); - mp3_energy=term_CD+term_GHIJ+term_KLMN+term_EF; - printf("MP3 energy contribution %12.8f\n",mp3_energy); +double CC2::mp3_energy_contribution(const Pairs& mp2pairs) const { +// print_header2("computing the MP3 correlation energy"); +// print_header3("prepare the cluster function"); +// typedef std::vector> ClusterFunction; +// Pairs clusterfunctions; +// +// auto R2 = nemo->ncf->square(); +// auto R = nemo->ncf->function(); +// std::vector nemo_orbital=CCOPS.mo_ket().get_vecfunction(); +// std::vector R2_orbital=CCOPS.mo_bra().get_vecfunction(); +// const int nocc=CCOPS.mo_ket().size(); + + double result=0.0; + result+=compute_mp3_cd(mp2pairs); + result+=compute_mp3_ef(mp2pairs); + result+=compute_mp3_ghij(mp2pairs); + result+=compute_mp3_klmn(mp2pairs); - return mp3_energy; + return result; } diff --git a/src/madness/chem/CC2.h b/src/madness/chem/CC2.h index ea2a3c995f4..7d98cc0303b 100644 --- a/src/madness/chem/CC2.h +++ b/src/madness/chem/CC2.h @@ -131,6 +131,10 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { /// solve the CC2 ground state equations, returns the correlation energy void solve(); + double compute_mp3_cd(const Pairs& mp2pairs) const; + double compute_mp3_ef(const Pairs& mp2pairs) const; + double compute_mp3_ghij(const Pairs& mp2pairs) const; + double compute_mp3_klmn(const Pairs& mp2pairs) const; double mp3_energy_contribution(const Pairs& mp2pairs) const; std::vector From d4c57e26aa94b78af89e2f9d2b184d65f6f7c6c6 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Thu, 15 Feb 2024 16:16:32 +0100 Subject: [PATCH 089/109] using permutational symmetry for the EF term in MP3 --- src/madness/chem/CC2.cc | 345 ++++++++++++++++++++++++++++++++++++++-- src/madness/chem/CC2.h | 1 + 2 files changed, 334 insertions(+), 12 deletions(-) diff --git a/src/madness/chem/CC2.cc b/src/madness/chem/CC2.cc index 236ea9606d7..3bbb3ee330b 100644 --- a/src/madness/chem/CC2.cc +++ b/src/madness/chem/CC2.cc @@ -384,7 +384,6 @@ double CC2::compute_mp3_cd(const Pairs& mp2pairs) const { CCConvolutionOperator::Parameters cparam; auto g12=CCConvolutionOperatorPtr(world,OpType::OT_G12,cparam); - timer t2(world); double result = 0.0; for (int i = parameters.freeze(); i < nocc; ++i) { for (int j = i; j < nocc; ++j) { @@ -398,13 +397,11 @@ double CC2::compute_mp3_cd(const Pairs& mp2pairs) const { } } printf("MP3 energy: term_CD %12.8f\n", result); - t2.tag("CD term"); return result; }; double CC2::compute_mp3_ef(const Pairs& mp2pairs) const { - // prepare cluster functions std::size_t nocc=CCOPS.mo_ket().size(); typedef std::vector> ClusterFunction; @@ -430,7 +427,6 @@ double CC2::compute_mp3_ef(const Pairs& mp2pairs) const { CCConvolutionOperator::Parameters cparam; auto g12=CCConvolutionOperatorPtr(world,OpType::OT_G12,cparam); - timer t2(world); print_header3("computing term EF of the MP3 energy with R2_bra"); @@ -458,17 +454,331 @@ double CC2::compute_mp3_ef(const Pairs& mp2pairs) const { } } printf("MP3 energy: term_EF %12.8f\n",result); - t2.tag("EF term"); return result; }; + /// permutations in physisists notation: = (ik | jl), loop over ik all_permutations; + /// for (int ik=0; ik make_all_eri_permutations() const{ + permutation p1(i,j,k,l); + permutation p2(k,j,i,l); + permutation p3(i,l,k,j); + permutation p4(k,l,i,j); + permutation p5(j,i,l,k); + permutation p6(l,i,j,k); + permutation p7(j,k,l,i); + permutation p8(l,k,j,i); + std::vector result({p1,p2,p3,p4,p5,p6,p7,p8}); + return remove_duplicates(result); + } + + /// <\tau_{ij} | \tau_{kl}> = <\tau_{ji} | \tau_{lk}> = <\tau_{kl} | \tau_{ij}>= <\tau_{lk} | \tau_{ji}> + std::vector make_all_tau_permutations() const{ + permutation p1(i,j,k,l); + permutation p2(j,i,l,k); + permutation p3(k,l,i,j); + permutation p4(l,k,j,i); + return remove_duplicates({p1,p2,p3,p4}); + } + + bool operator<(const permutation& other) const { + return std::tie(i,j,k,l) < std::tie(other.i,other.j,other.k,other.l); + } + bool operator==(const permutation& other) const { + return std::tie(i,j,k,l) == std::tie(other.i,other.j,other.k,other.l); + } + bool operator!=(const permutation& other) const { + return (not (*this==other)); + } + static std::vector remove_duplicates(std::vector v) { + // remove duplicates + std::sort(v.begin(), v.end(),[](permutation a, permutation b) { return a < b; }); + auto last = std::unique(v.begin(), v.end()); + v.erase(last, v.end()); + return v; + } + }; + std::ostream& operator<<(std::ostream& os, const permutation& p) { + os << "(" << p.i << p.j << p.k << p.l << ")"; + return os; + } +/// compute the EF term of the MP3 energy with permutational symmetry + +/// there is the usual 8-fold permutational symmetry for 2-electron integrals +/// = = = < il | kj > +/// = = = = < kj | il > +/// implemented as loop over (ij) = \sum_i& mp2pairs) const { + // prepare cluster functions + std::size_t nocc=CCOPS.mo_ket().size(); + std::size_t nfrozen=parameters.freeze(); + typedef std::vector> ClusterFunction; + Pairs clusterfunctions; + for (int i = parameters.freeze(); i < nocc; ++i) { + for (int j = i; j < nocc; ++j) { + clusterfunctions(i,j)=mp2pairs(i,j).functions; + if (i!=j) { + for (const auto& t : clusterfunctions(i,j)) { + clusterfunctions(j, i).push_back(t.swap_particles()); + } + } + } + } + + const auto& R2=nemo->R_square; + double result=0.0; + const std::vector& nemo_orbital=CCOPS.mo_ket().get_vecfunction(); + const std::vector& R2_orbital=CCOPS.mo_bra().get_vecfunction(); + + CCConvolutionOperator::Parameters cparam; + auto g12=CCConvolutionOperatorPtr(world,OpType::OT_G12,cparam); + + // number of pairs + auto npair = [&nocc, &nfrozen]() { return (nocc - nfrozen) * (nocc - nfrozen + 1) / 2; }; + + // turn composite index ij into i and j, taking care of frozen orbitals + PairVectorMap map=PairVectorMap::triangular_map(nfrozen,nocc); + auto ij_to_i_and_j = [&map](const int ij) { return map.map[ij]; }; + + /// = (ik | jl) + std::vector all_tau_permutations; + // loop over unique pairs (ij) + for (int ij=0; ij (2* - ) + // = (2*(ik|jl) - (jk|il)) + double ovlp=inner(clusterfunctions(i,j),clusterfunctions(k,l),R2); + const auto& ket_i=nemo_orbital[i]; + const auto& ket_k=nemo_orbital[k]; + const auto& ket_l=nemo_orbital[l]; + const auto& bra_i=R2_orbital[i]; + const auto& bra_j=R2_orbital[j]; + const auto& bra_l=R2_orbital[l]; + double g_ikjl=inner(bra_i*ket_k, (*g12)(bra_j*ket_l)); + double g_jkil=inner(bra_j*ket_k, (*g12)(bra_l*ket_i)); + tmp+=weight*ovlp*(2.0* g_ikjl - g_jkil); + } + } + printf("mp3 energy: term_EF %2d %2d %12.8f\n",i,j,tmp); + result+=tmp; + } + // sanity check + int npermutations=all_tau_permutations.size(); + all_tau_permutations=permutation::remove_duplicates(all_tau_permutations); + int nuniquepermutations=all_tau_permutations.size(); + int ntotalpermutations=std::pow(nocc-nfrozen,4); + MADNESS_CHECK_THROW(npermutations==nuniquepermutations,"incorrect number of unique permutations"); + MADNESS_CHECK_THROW(npermutations==ntotalpermutations,"incorrect number of unique permutations"); + + print_header3("computing term EF of the MP3 energy with R2_bra"); + printf("MP3 energy: term_EF %12.8f\n",result); + return result; +}; + + double CC2::compute_mp3_ghij(const Pairs& mp2pairs) const { + + // prepare cluster functions + std::size_t nocc=CCOPS.mo_ket().size(); + typedef std::vector> ClusterFunction; + Pairs clusterfunctions; + for (int i = parameters.freeze(); i < nocc; ++i) { + for (int j = i; j < nocc; ++j) { + clusterfunctions(i,j)=mp2pairs(i,j).functions; + if (i!=j) { + for (const auto& t : clusterfunctions(i,j)) { + clusterfunctions(j, i).push_back(t.swap_particles()); + } + } + } + } double result=0.0; + + const auto& R2=nemo->R_square; + const std::vector& nemo_orbital=CCOPS.mo_ket().get_vecfunction(); + const std::vector& R2_orbital=CCOPS.mo_bra().get_vecfunction(); + + CCConvolutionOperator::Parameters cparam; + auto g12=CCConvolutionOperatorPtr(world,OpType::OT_G12,cparam); + + timer t2(world); + + + // compute intermediates for terms G, I, H, and J + + // \sum_j tau_ij(1,2) * phi_j(2) + std::vector tau_kk_i(nocc); + // \sum_j tau_ij(1,2) * phi_j(1) + std::vector tau_ij_j(nocc); + for (int i = parameters.freeze(); i < nocc; ++i) { + for (int j = parameters.freeze(); j < nocc; ++j) { + auto tmp2 = multiply(clusterfunctions(i, j), R2_orbital[i], {0, 1, 2}); + for (auto& t: tmp2) tau_kk_i[j].push_back(t); + + auto tmp3 = multiply(clusterfunctions(i, j), R2_orbital[j], {0, 1, 2}); + for (auto& t: tmp3) tau_ij_j[i].push_back(t); + } + } + print("info on tau_kk_i, consolidated with op_pure_to_pure"); + for (int i = parameters.freeze(); i < nocc; ++i) { + tau_kk_i[i] = consolidate(tau_kk_i[i], {"op_pure_to_pure", "op_dec_to_dec"}); + for (auto& c: tau_kk_i[i]) c.info(); + } + print("info on tau_ij_j, consolidated with op_pure_to_pure"); + for (int i = parameters.freeze(); i < nocc; ++i) { + tau_ij_j[i] = consolidate(tau_ij_j[i], {"op_pure_to_pure", "op_dec_to_dec"}); + for (auto& c: tau_ij_j[i]) c.info(); + } + + t2.tag("GHIJ term prep"); + + // terms G, I, H, J of Bartlett/Silver 1975 + real_convolution_3d& g = *(g12->get_op()); + for (int i = parameters.freeze(); i < nocc; ++i) { + // tmp(1,2) = g(1,1') | tau_ij(1',2) j(2) > + timer t4(world, "gtau"); + g.set_particle(1); + auto gtau_same = g(tau_kk_i[i]); + t4.tag("compute gtau_same"); + // gtau_same=consolidate(gtau_same,{"op_pure_to_pure"}); + // t4.tag("consolidate gtau_same"); + + // tmp(1',2) = g(1',1) | tau_ij(1,2) j(1) > + g.set_particle(1); + auto gtau_other = g(tau_ij_j[i]); // < tau_ij(1,2) j(1) | g(1,1') | + t4.tag("compute gtau_other"); + // gtau_other=consolidate(gtau_other,{"op_pure_to_pure"}); + // t4.tag("consolidate gtau_other"); + + auto bra_kk_i = multiply(tau_kk_i[i], R2, {3, 4, 5}); + auto bra_ij_j = multiply(tau_ij_j[i], R2, {3, 4, 5}); + + double G = inner(bra_kk_i, gtau_same); + printf("G %12.8f\n", G); + + double H = inner(bra_ij_j, gtau_other); + printf("H %12.8f\n", H); + + double I = inner(bra_kk_i, gtau_other); + printf("I %12.8f\n", I); + + double J = inner(bra_ij_j, gtau_same); + printf("J %12.8f\n", J); + + t4.tag("compute inner products"); + double tmp = (8.0 * G - 4.0 * I + 2.0 * H - 4.0 * J); + printf("mp3 energy: term_GHIJ %2d %12.8f\n", i, tmp); + result += tmp; + } + printf("MP3 energy: term_GHIJ %12.8f\n", result); + t2.tag("GHIJ term"); return result; }; + double CC2::compute_mp3_klmn(const Pairs& mp2pairs) const { + + + // prepare cluster functions + std::size_t nocc=CCOPS.mo_ket().size(); + typedef std::vector> ClusterFunction; + Pairs clusterfunctions; + for (int i = parameters.freeze(); i < nocc; ++i) { + for (int j = i; j < nocc; ++j) { + clusterfunctions(i,j)=mp2pairs(i,j).functions; + if (i!=j) { + for (const auto& t : clusterfunctions(i,j)) { + clusterfunctions(j, i).push_back(t.swap_particles()); + } + } + } + } double result=0.0; + + const auto& R2=nemo->R_square; + const std::vector& nemo_orbital=CCOPS.mo_ket().get_vecfunction(); + const std::vector& R2_orbital=CCOPS.mo_bra().get_vecfunction(); + + CCConvolutionOperator::Parameters cparam; + auto g12=CCConvolutionOperatorPtr(world,OpType::OT_G12,cparam); + + // compute the term (2) + madness::Pairs gij; + + for (int i = parameters.freeze(); i < nocc; ++i) { + for (int j = parameters.freeze(); j < nocc; ++j) { + gij.insert(i,j,(*g12)(nemo_orbital[i]*R2_orbital[j])); + } + } + + + timer multiply_KLMN(world, "multiplication in KLMN term"); + multiply_KLMN.interrupt(); + timer inner_KLMN(world, "inner in KLMN term"); + inner_KLMN.interrupt(); + // prepare intermediates for terms K, L, M, N of Bartlett/Silver 1975 + // tau_g_ij(1,2) = \sum_k tau_ik(1,1') g_jk(2) + Pairs tau_ik_g_kj, tau_kj_g_ki; + for (int i = parameters.freeze(); i < nocc; ++i) { + for (int j = parameters.freeze(); j < nocc; ++j) { + multiply_KLMN.resume(); + std::vector> tmp1, tmp2; + for (int k = parameters.freeze(); k < nocc; ++k) { + tmp1 += multiply(clusterfunctions(i, k), gij(k, j), {3, 4, 5}); + tmp2 += multiply(clusterfunctions(k, j), gij(k, i), {3, 4, 5}); + } + tmp1 = consolidate(tmp1, {}); + tmp2 = consolidate(tmp2, {}); + tau_ik_g_kj(i, j) = tmp1; + tau_kj_g_ki(i, j) = tmp2; + multiply_KLMN.interrupt(); + + inner_KLMN.resume(); + double K = inner(clusterfunctions(i, j), tau_ik_g_kj(i, j), R2); + double L = inner(clusterfunctions(i, j), tau_kj_g_ki(i, j), R2); + double M = inner(clusterfunctions(j, i), tau_kj_g_ki(i, j), R2); + double N = inner(clusterfunctions(j, i), tau_ik_g_kj(i, j), R2); + inner_KLMN.interrupt(); + + double tmp = -4 * K - 4 * L + 2 * M + 2 * N; + printf("mp3 energy: term_KLMN with particle=1 %2d %2d %12.8f\n", i, j, tmp); + result += tmp; + } + } + printf("MP3 energy: term_KLMN (KLMN) %12.8f\n", result); + multiply_KLMN.print("multiplication in KLMN term"); + inner_KLMN.print("inner in KLMN term"); + return result; }; @@ -486,13 +796,24 @@ double CC2::mp3_energy_contribution(const Pairs& mp2pairs) const { // std::vector R2_orbital=CCOPS.mo_bra().get_vecfunction(); // const int nocc=CCOPS.mo_ket().size(); - double result=0.0; - result+=compute_mp3_cd(mp2pairs); - result+=compute_mp3_ef(mp2pairs); - result+=compute_mp3_ghij(mp2pairs); - result+=compute_mp3_klmn(mp2pairs); - - return result; + double term_CD=0.0, term_EF=0.0, term_GHIJ=0.0, term_KLMN=0.0; + timer t2(world); + // term_CD=compute_mp3_cd(mp2pairs); + t2.tag("CD term"); + term_EF=compute_mp3_ef_with_permutational_symmetry(mp2pairs); + t2.tag("EF term"); + // term_GHIJ=compute_mp3_ghij(mp2pairs); + t2.tag("GHIJ term"); + // term_KLMN=compute_mp3_klmn(mp2pairs); + t2.tag("KLMN term"); + + printf("term_CD %12.8f\n",term_CD); + printf("term_GHIJ %12.8f\n",term_GHIJ); + printf("term_KLMN %12.8f\n",term_KLMN); + printf("term_EF %12.8f\n",term_EF); + double mp3_energy=term_CD+term_GHIJ+term_KLMN+term_EF; + printf("MP3 energy contribution %12.8f\n",mp3_energy); + return mp3_energy; } diff --git a/src/madness/chem/CC2.h b/src/madness/chem/CC2.h index 7d98cc0303b..57490000bc2 100644 --- a/src/madness/chem/CC2.h +++ b/src/madness/chem/CC2.h @@ -133,6 +133,7 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { double compute_mp3_cd(const Pairs& mp2pairs) const; double compute_mp3_ef(const Pairs& mp2pairs) const; + double compute_mp3_ef_with_permutational_symmetry(const Pairs& mp2pairs) const; double compute_mp3_ghij(const Pairs& mp2pairs) const; double compute_mp3_klmn(const Pairs& mp2pairs) const; double mp3_energy_contribution(const Pairs& mp2pairs) const; From 67912e2ff0751fdb47d6e6b2879f19e57064c475 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Thu, 15 Feb 2024 18:20:58 +0100 Subject: [PATCH 090/109] refactoring MP3 into its own class --- src/madness/chem/CC2.cc | 455 +------------------------------ src/madness/chem/CC2.h | 13 +- src/madness/chem/CCPotentials.h | 2 +- src/madness/chem/CMakeLists.txt | 2 + src/madness/chem/mp3.cc | 461 ++++++++++++++++++++++++++++++++ src/madness/chem/mp3.h | 40 +++ 6 files changed, 512 insertions(+), 461 deletions(-) create mode 100644 src/madness/chem/mp3.cc create mode 100644 src/madness/chem/mp3.h diff --git a/src/madness/chem/CC2.cc b/src/madness/chem/CC2.cc index 3bbb3ee330b..c87234bd68a 100644 --- a/src/madness/chem/CC2.cc +++ b/src/madness/chem/CC2.cc @@ -102,7 +102,7 @@ CC2::solve() { } else if (ctype == CT_MP2) { ; // we're good } else if (ctype == CT_MP3) { - mp3_energy=mp3_energy_contribution(mp2pairs); + mp3_energy=compute_mp3(mp2pairs); } else if (ctype == CT_CC2) { ; // we're good } else if (ctype == CT_CISPD) { @@ -364,459 +364,6 @@ Tensor CC2::enforce_core_valence_separation(const Tensor& fmat) }; -double CC2::compute_mp3_cd(const Pairs& mp2pairs) const { - print_header3("compute term_CD of the MP3 energy with R2_bra"); - // compute the MP3 energy - std::size_t nocc=CCOPS.mo_ket().size(); - typedef std::vector> ClusterFunction; - Pairs clusterfunctions; - for (int i = parameters.freeze(); i < nocc; ++i) { - for (int j = i; j < nocc; ++j) { - clusterfunctions(i,j)=mp2pairs(i,j).functions; - if (i!=j) { - for (const auto& t : clusterfunctions(i,j)) { - clusterfunctions(j, i).push_back(t.swap_particles()); - } - } - } - } - const auto& R2=nemo->R_square; - CCConvolutionOperator::Parameters cparam; - auto g12=CCConvolutionOperatorPtr(world,OpType::OT_G12,cparam); - - double result = 0.0; - for (int i = parameters.freeze(); i < nocc; ++i) { - for (int j = i; j < nocc; ++j) { - auto bra = clusterfunctions(i, j); - double tmp1 = inner(bra, g12 * clusterfunctions(i, j), R2); - double tmp2 = inner(bra, g12 * clusterfunctions(j, i), R2); - double fac = (i == j) ? 0.5 : 1.0; - double tmp = fac * (4.0 * tmp1 - 2.0 * tmp2); - printf("mp3 energy: term_CD %2d %2d: %12.8f\n", i, j, tmp); - result+= tmp; - } - } - printf("MP3 energy: term_CD %12.8f\n", result); - return result; -}; - -double CC2::compute_mp3_ef(const Pairs& mp2pairs) const { - - // prepare cluster functions - std::size_t nocc=CCOPS.mo_ket().size(); - typedef std::vector> ClusterFunction; - Pairs clusterfunctions; - for (int i = parameters.freeze(); i < nocc; ++i) { - for (int j = i; j < nocc; ++j) { - clusterfunctions(i,j)=mp2pairs(i,j).functions; - if (i!=j) { - for (const auto& t : clusterfunctions(i,j)) { - clusterfunctions(j, i).push_back(t.swap_particles()); - } - } - } - } - - - - const auto& R2=nemo->R_square; - double result=0.0; - const std::vector& nemo_orbital=CCOPS.mo_ket().get_vecfunction(); - const std::vector& R2_orbital=CCOPS.mo_bra().get_vecfunction(); - - CCConvolutionOperator::Parameters cparam; - auto g12=CCConvolutionOperatorPtr(world,OpType::OT_G12,cparam); - - - - print_header3("computing term EF of the MP3 energy with R2_bra"); - for (int i = parameters.freeze(); i < nocc; ++i) { - for (int j = parameters.freeze(); j < nocc; ++j) { - double tmp=0.0; - for (int k=parameters.freeze(); k< nocc; ++k) { - for (int l=parameters.freeze(); l",g_jlik); - tmp+=(2.0*ovlp_E - ovlp_F)*g_jlik; - } - } - printf("mp3 energy: term_EF %2d %2d %12.8f\n",i,j,tmp); - result+=tmp; - } - } - printf("MP3 energy: term_EF %12.8f\n",result); - return result; -}; - - /// permutations in physisists notation: = (ik | jl), loop over ik all_permutations; - /// for (int ik=0; ik make_all_eri_permutations() const{ - permutation p1(i,j,k,l); - permutation p2(k,j,i,l); - permutation p3(i,l,k,j); - permutation p4(k,l,i,j); - permutation p5(j,i,l,k); - permutation p6(l,i,j,k); - permutation p7(j,k,l,i); - permutation p8(l,k,j,i); - std::vector result({p1,p2,p3,p4,p5,p6,p7,p8}); - return remove_duplicates(result); - } - - /// <\tau_{ij} | \tau_{kl}> = <\tau_{ji} | \tau_{lk}> = <\tau_{kl} | \tau_{ij}>= <\tau_{lk} | \tau_{ji}> - std::vector make_all_tau_permutations() const{ - permutation p1(i,j,k,l); - permutation p2(j,i,l,k); - permutation p3(k,l,i,j); - permutation p4(l,k,j,i); - return remove_duplicates({p1,p2,p3,p4}); - } - - bool operator<(const permutation& other) const { - return std::tie(i,j,k,l) < std::tie(other.i,other.j,other.k,other.l); - } - bool operator==(const permutation& other) const { - return std::tie(i,j,k,l) == std::tie(other.i,other.j,other.k,other.l); - } - bool operator!=(const permutation& other) const { - return (not (*this==other)); - } - static std::vector remove_duplicates(std::vector v) { - // remove duplicates - std::sort(v.begin(), v.end(),[](permutation a, permutation b) { return a < b; }); - auto last = std::unique(v.begin(), v.end()); - v.erase(last, v.end()); - return v; - } - }; - std::ostream& operator<<(std::ostream& os, const permutation& p) { - os << "(" << p.i << p.j << p.k << p.l << ")"; - return os; - } -/// compute the EF term of the MP3 energy with permutational symmetry - -/// there is the usual 8-fold permutational symmetry for 2-electron integrals -/// = = = < il | kj > -/// = = = = < kj | il > -/// implemented as loop over (ij) = \sum_i& mp2pairs) const { - // prepare cluster functions - std::size_t nocc=CCOPS.mo_ket().size(); - std::size_t nfrozen=parameters.freeze(); - typedef std::vector> ClusterFunction; - Pairs clusterfunctions; - for (int i = parameters.freeze(); i < nocc; ++i) { - for (int j = i; j < nocc; ++j) { - clusterfunctions(i,j)=mp2pairs(i,j).functions; - if (i!=j) { - for (const auto& t : clusterfunctions(i,j)) { - clusterfunctions(j, i).push_back(t.swap_particles()); - } - } - } - } - - const auto& R2=nemo->R_square; - double result=0.0; - const std::vector& nemo_orbital=CCOPS.mo_ket().get_vecfunction(); - const std::vector& R2_orbital=CCOPS.mo_bra().get_vecfunction(); - - CCConvolutionOperator::Parameters cparam; - auto g12=CCConvolutionOperatorPtr(world,OpType::OT_G12,cparam); - - // number of pairs - auto npair = [&nocc, &nfrozen]() { return (nocc - nfrozen) * (nocc - nfrozen + 1) / 2; }; - - // turn composite index ij into i and j, taking care of frozen orbitals - PairVectorMap map=PairVectorMap::triangular_map(nfrozen,nocc); - auto ij_to_i_and_j = [&map](const int ij) { return map.map[ij]; }; - - /// = (ik | jl) - std::vector all_tau_permutations; - // loop over unique pairs (ij) - for (int ij=0; ij (2* - ) - // = (2*(ik|jl) - (jk|il)) - double ovlp=inner(clusterfunctions(i,j),clusterfunctions(k,l),R2); - const auto& ket_i=nemo_orbital[i]; - const auto& ket_k=nemo_orbital[k]; - const auto& ket_l=nemo_orbital[l]; - const auto& bra_i=R2_orbital[i]; - const auto& bra_j=R2_orbital[j]; - const auto& bra_l=R2_orbital[l]; - double g_ikjl=inner(bra_i*ket_k, (*g12)(bra_j*ket_l)); - double g_jkil=inner(bra_j*ket_k, (*g12)(bra_l*ket_i)); - tmp+=weight*ovlp*(2.0* g_ikjl - g_jkil); - } - } - printf("mp3 energy: term_EF %2d %2d %12.8f\n",i,j,tmp); - result+=tmp; - } - // sanity check - int npermutations=all_tau_permutations.size(); - all_tau_permutations=permutation::remove_duplicates(all_tau_permutations); - int nuniquepermutations=all_tau_permutations.size(); - int ntotalpermutations=std::pow(nocc-nfrozen,4); - MADNESS_CHECK_THROW(npermutations==nuniquepermutations,"incorrect number of unique permutations"); - MADNESS_CHECK_THROW(npermutations==ntotalpermutations,"incorrect number of unique permutations"); - - print_header3("computing term EF of the MP3 energy with R2_bra"); - printf("MP3 energy: term_EF %12.8f\n",result); - return result; -}; - - -double CC2::compute_mp3_ghij(const Pairs& mp2pairs) const { - - - // prepare cluster functions - std::size_t nocc=CCOPS.mo_ket().size(); - typedef std::vector> ClusterFunction; - Pairs clusterfunctions; - for (int i = parameters.freeze(); i < nocc; ++i) { - for (int j = i; j < nocc; ++j) { - clusterfunctions(i,j)=mp2pairs(i,j).functions; - if (i!=j) { - for (const auto& t : clusterfunctions(i,j)) { - clusterfunctions(j, i).push_back(t.swap_particles()); - } - } - } - } - double result=0.0; - - const auto& R2=nemo->R_square; - const std::vector& nemo_orbital=CCOPS.mo_ket().get_vecfunction(); - const std::vector& R2_orbital=CCOPS.mo_bra().get_vecfunction(); - - CCConvolutionOperator::Parameters cparam; - auto g12=CCConvolutionOperatorPtr(world,OpType::OT_G12,cparam); - - timer t2(world); - - - // compute intermediates for terms G, I, H, and J - - // \sum_j tau_ij(1,2) * phi_j(2) - std::vector tau_kk_i(nocc); - // \sum_j tau_ij(1,2) * phi_j(1) - std::vector tau_ij_j(nocc); - for (int i = parameters.freeze(); i < nocc; ++i) { - for (int j = parameters.freeze(); j < nocc; ++j) { - auto tmp2 = multiply(clusterfunctions(i, j), R2_orbital[i], {0, 1, 2}); - for (auto& t: tmp2) tau_kk_i[j].push_back(t); - - auto tmp3 = multiply(clusterfunctions(i, j), R2_orbital[j], {0, 1, 2}); - for (auto& t: tmp3) tau_ij_j[i].push_back(t); - } - } - print("info on tau_kk_i, consolidated with op_pure_to_pure"); - for (int i = parameters.freeze(); i < nocc; ++i) { - tau_kk_i[i] = consolidate(tau_kk_i[i], {"op_pure_to_pure", "op_dec_to_dec"}); - for (auto& c: tau_kk_i[i]) c.info(); - } - print("info on tau_ij_j, consolidated with op_pure_to_pure"); - for (int i = parameters.freeze(); i < nocc; ++i) { - tau_ij_j[i] = consolidate(tau_ij_j[i], {"op_pure_to_pure", "op_dec_to_dec"}); - for (auto& c: tau_ij_j[i]) c.info(); - } - - t2.tag("GHIJ term prep"); - - // terms G, I, H, J of Bartlett/Silver 1975 - real_convolution_3d& g = *(g12->get_op()); - for (int i = parameters.freeze(); i < nocc; ++i) { - // tmp(1,2) = g(1,1') | tau_ij(1',2) j(2) > - timer t4(world, "gtau"); - g.set_particle(1); - auto gtau_same = g(tau_kk_i[i]); - t4.tag("compute gtau_same"); - // gtau_same=consolidate(gtau_same,{"op_pure_to_pure"}); - // t4.tag("consolidate gtau_same"); - - // tmp(1',2) = g(1',1) | tau_ij(1,2) j(1) > - g.set_particle(1); - auto gtau_other = g(tau_ij_j[i]); // < tau_ij(1,2) j(1) | g(1,1') | - t4.tag("compute gtau_other"); - // gtau_other=consolidate(gtau_other,{"op_pure_to_pure"}); - // t4.tag("consolidate gtau_other"); - - auto bra_kk_i = multiply(tau_kk_i[i], R2, {3, 4, 5}); - auto bra_ij_j = multiply(tau_ij_j[i], R2, {3, 4, 5}); - - double G = inner(bra_kk_i, gtau_same); - printf("G %12.8f\n", G); - - double H = inner(bra_ij_j, gtau_other); - printf("H %12.8f\n", H); - - double I = inner(bra_kk_i, gtau_other); - printf("I %12.8f\n", I); - - double J = inner(bra_ij_j, gtau_same); - printf("J %12.8f\n", J); - - t4.tag("compute inner products"); - double tmp = (8.0 * G - 4.0 * I + 2.0 * H - 4.0 * J); - printf("mp3 energy: term_GHIJ %2d %12.8f\n", i, tmp); - result += tmp; - } - printf("MP3 energy: term_GHIJ %12.8f\n", result); - t2.tag("GHIJ term"); - return result; -}; - -double CC2::compute_mp3_klmn(const Pairs& mp2pairs) const { - - - // prepare cluster functions - std::size_t nocc=CCOPS.mo_ket().size(); - typedef std::vector> ClusterFunction; - Pairs clusterfunctions; - for (int i = parameters.freeze(); i < nocc; ++i) { - for (int j = i; j < nocc; ++j) { - clusterfunctions(i,j)=mp2pairs(i,j).functions; - if (i!=j) { - for (const auto& t : clusterfunctions(i,j)) { - clusterfunctions(j, i).push_back(t.swap_particles()); - } - } - } - } - double result=0.0; - - const auto& R2=nemo->R_square; - const std::vector& nemo_orbital=CCOPS.mo_ket().get_vecfunction(); - const std::vector& R2_orbital=CCOPS.mo_bra().get_vecfunction(); - - CCConvolutionOperator::Parameters cparam; - auto g12=CCConvolutionOperatorPtr(world,OpType::OT_G12,cparam); - - // compute the term (2) - madness::Pairs gij; - - for (int i = parameters.freeze(); i < nocc; ++i) { - for (int j = parameters.freeze(); j < nocc; ++j) { - gij.insert(i,j,(*g12)(nemo_orbital[i]*R2_orbital[j])); - } - } - - - timer multiply_KLMN(world, "multiplication in KLMN term"); - multiply_KLMN.interrupt(); - timer inner_KLMN(world, "inner in KLMN term"); - inner_KLMN.interrupt(); - // prepare intermediates for terms K, L, M, N of Bartlett/Silver 1975 - // tau_g_ij(1,2) = \sum_k tau_ik(1,1') g_jk(2) - Pairs tau_ik_g_kj, tau_kj_g_ki; - for (int i = parameters.freeze(); i < nocc; ++i) { - for (int j = parameters.freeze(); j < nocc; ++j) { - multiply_KLMN.resume(); - std::vector> tmp1, tmp2; - for (int k = parameters.freeze(); k < nocc; ++k) { - tmp1 += multiply(clusterfunctions(i, k), gij(k, j), {3, 4, 5}); - tmp2 += multiply(clusterfunctions(k, j), gij(k, i), {3, 4, 5}); - } - tmp1 = consolidate(tmp1, {}); - tmp2 = consolidate(tmp2, {}); - tau_ik_g_kj(i, j) = tmp1; - tau_kj_g_ki(i, j) = tmp2; - multiply_KLMN.interrupt(); - - inner_KLMN.resume(); - double K = inner(clusterfunctions(i, j), tau_ik_g_kj(i, j), R2); - double L = inner(clusterfunctions(i, j), tau_kj_g_ki(i, j), R2); - double M = inner(clusterfunctions(j, i), tau_kj_g_ki(i, j), R2); - double N = inner(clusterfunctions(j, i), tau_ik_g_kj(i, j), R2); - inner_KLMN.interrupt(); - - double tmp = -4 * K - 4 * L + 2 * M + 2 * N; - printf("mp3 energy: term_KLMN with particle=1 %2d %2d %12.8f\n", i, j, tmp); - result += tmp; - } - } - printf("MP3 energy: term_KLMN (KLMN) %12.8f\n", result); - multiply_KLMN.print("multiplication in KLMN term"); - inner_KLMN.print("inner in KLMN term"); - - return result; - -}; - -double CC2::mp3_energy_contribution(const Pairs& mp2pairs) const { - -// print_header2("computing the MP3 correlation energy"); -// print_header3("prepare the cluster function"); -// typedef std::vector> ClusterFunction; -// Pairs clusterfunctions; -// -// auto R2 = nemo->ncf->square(); -// auto R = nemo->ncf->function(); -// std::vector nemo_orbital=CCOPS.mo_ket().get_vecfunction(); -// std::vector R2_orbital=CCOPS.mo_bra().get_vecfunction(); -// const int nocc=CCOPS.mo_ket().size(); - - double term_CD=0.0, term_EF=0.0, term_GHIJ=0.0, term_KLMN=0.0; - timer t2(world); - // term_CD=compute_mp3_cd(mp2pairs); - t2.tag("CD term"); - term_EF=compute_mp3_ef_with_permutational_symmetry(mp2pairs); - t2.tag("EF term"); - // term_GHIJ=compute_mp3_ghij(mp2pairs); - t2.tag("GHIJ term"); - // term_KLMN=compute_mp3_klmn(mp2pairs); - t2.tag("KLMN term"); - - printf("term_CD %12.8f\n",term_CD); - printf("term_GHIJ %12.8f\n",term_GHIJ); - printf("term_KLMN %12.8f\n",term_KLMN); - printf("term_EF %12.8f\n",term_EF); - double mp3_energy=term_CD+term_GHIJ+term_KLMN+term_EF; - printf("MP3 energy contribution %12.8f\n",mp3_energy); - return mp3_energy; -} - - // Solve the CCS equations for the ground state (debug potential and check HF convergence) std::vector CC2::solve_ccs() { // output.section("SOLVE CCS"); diff --git a/src/madness/chem/CC2.h b/src/madness/chem/CC2.h index 57490000bc2..ef640924314 100644 --- a/src/madness/chem/CC2.h +++ b/src/madness/chem/CC2.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -131,12 +132,6 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { /// solve the CC2 ground state equations, returns the correlation energy void solve(); - double compute_mp3_cd(const Pairs& mp2pairs) const; - double compute_mp3_ef(const Pairs& mp2pairs) const; - double compute_mp3_ef_with_permutational_symmetry(const Pairs& mp2pairs) const; - double compute_mp3_ghij(const Pairs& mp2pairs) const; - double compute_mp3_klmn(const Pairs& mp2pairs) const; - double mp3_energy_contribution(const Pairs& mp2pairs) const; std::vector solve_ccs(); @@ -145,6 +140,12 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { double solve_mp2(Pairs& doubles); + double compute_mp3(const Pairs& mp2pairs) const { + MP3 mp3(CCOPS); + double mp3_contribution=mp3.mp3_energy_contribution(mp2pairs); + return mp3_contribution; + } + double solve_cc2(CC_vecfunction& tau, Pairs& u); diff --git a/src/madness/chem/CCPotentials.h b/src/madness/chem/CCPotentials.h index 2e5afb3c6ba..7d51dbdfadc 100644 --- a/src/madness/chem/CCPotentials.h +++ b/src/madness/chem/CCPotentials.h @@ -813,7 +813,7 @@ class CCPotentials { } } -private: +protected: // member variables /// MPI World World& world; diff --git a/src/madness/chem/CMakeLists.txt b/src/madness/chem/CMakeLists.txt index 2a1441347b3..bf05ce39b9b 100644 --- a/src/madness/chem/CMakeLists.txt +++ b/src/madness/chem/CMakeLists.txt @@ -10,6 +10,7 @@ set(MADCHEM_HEADERS BSHApply.h CalculationParameters.h CC2.h + mp3.h ccpairfunction.h CCPotentials.h CCStructures.h @@ -63,6 +64,7 @@ set(MADCHEM_SOURCES AC.cc atomutil.cc CC2.cc + mp3.cc ccpairfunction.cc CCPotentials.cc CCStructures.cc diff --git a/src/madness/chem/mp3.cc b/src/madness/chem/mp3.cc new file mode 100644 index 00000000000..e5a2fb89ee7 --- /dev/null +++ b/src/madness/chem/mp3.cc @@ -0,0 +1,461 @@ +// +// Created by Florian Bischoff on 2/15/24. +// + +#include "mp3.h" + +namespace madness { +double MP3::compute_mp3_cd(const Pairs& mp2pairs) const { + print_header3("compute term_CD of the MP3 energy with R2_bra"); + // compute the MP3 energy + std::size_t nocc=mo_ket().size(); + print("freeze, nocc",parameters.freeze(),nocc); + typedef std::vector> ClusterFunction; + Pairs clusterfunctions; + for (int i = parameters.freeze(); i < nocc; ++i) { + for (int j = i; j < nocc; ++j) { + clusterfunctions(i,j)=mp2pairs(i,j).functions; + if (i!=j) { + for (const auto& t : clusterfunctions(i,j)) { + clusterfunctions(j, i).push_back(t.swap_particles()); + } + } + } + } + const auto& R2=nemo_->R_square; + CCConvolutionOperator::Parameters cparam; + auto g12=CCConvolutionOperatorPtr(world,OpType::OT_G12,cparam); + + double result = 0.0; + for (int i = parameters.freeze(); i < nocc; ++i) { + for (int j = i; j < nocc; ++j) { + auto bra = clusterfunctions(i, j); + double tmp1 = inner(bra, g12 * clusterfunctions(i, j), R2); + double tmp2 = inner(bra, g12 * clusterfunctions(j, i), R2); + double fac = (i == j) ? 0.5 : 1.0; + double tmp = fac * (4.0 * tmp1 - 2.0 * tmp2); + printf("mp3 energy: term_CD %2d %2d: %12.8f\n", i, j, tmp); + result+= tmp; + } + } + printf("MP3 energy: term_CD %12.8f\n", result); + return result; +}; + +double MP3::compute_mp3_ef(const Pairs& mp2pairs) const { + + // prepare cluster functions + std::size_t nocc=mo_ket().size(); + typedef std::vector> ClusterFunction; + Pairs clusterfunctions; + for (int i = parameters.freeze(); i < nocc; ++i) { + for (int j = i; j < nocc; ++j) { + clusterfunctions(i,j)=mp2pairs(i,j).functions; + if (i!=j) { + for (const auto& t : clusterfunctions(i,j)) { + clusterfunctions(j, i).push_back(t.swap_particles()); + } + } + } + } + + + + const auto& R2=nemo_->R_square; + double result=0.0; + const std::vector& nemo_orbital=mo_ket().get_vecfunction(); + const std::vector& R2_orbital=mo_bra().get_vecfunction(); + + CCConvolutionOperator::Parameters cparam; + auto g12=CCConvolutionOperatorPtr(world,OpType::OT_G12,cparam); + + + + print_header3("computing term EF of the MP3 energy with R2_bra"); + for (int i = parameters.freeze(); i < nocc; ++i) { + for (int j = parameters.freeze(); j < nocc; ++j) { + double tmp=0.0; + for (int k=parameters.freeze(); k< nocc; ++k) { + for (int l=parameters.freeze(); l",g_jlik); + tmp+=(2.0*ovlp_E - ovlp_F)*g_jlik; + } + } + printf("mp3 energy: term_EF %2d %2d %12.8f\n",i,j,tmp); + result+=tmp; + } + } + printf("MP3 energy: term_EF %12.8f\n",result); + return result; +}; + +/// permutations in physisists notation: = (ik | jl), loop over ik all_permutations; +/// for (int ik=0; ik make_all_eri_permutations() const{ + permutation p1(i,j,k,l); + permutation p2(k,j,i,l); + permutation p3(i,l,k,j); + permutation p4(k,l,i,j); + permutation p5(j,i,l,k); + permutation p6(l,i,j,k); + permutation p7(j,k,l,i); + permutation p8(l,k,j,i); + std::vector result({p1,p2,p3,p4,p5,p6,p7,p8}); + return remove_duplicates(result); + } + + /// <\tau_{ij} | \tau_{kl}> = <\tau_{ji} | \tau_{lk}> = <\tau_{kl} | \tau_{ij}>= <\tau_{lk} | \tau_{ji}> + std::vector make_all_tau_permutations() const{ + permutation p1(i,j,k,l); + permutation p2(j,i,l,k); + permutation p3(k,l,i,j); + permutation p4(l,k,j,i); + return remove_duplicates({p1,p2,p3,p4}); + } + + bool operator<(const permutation& other) const { + return std::tie(i,j,k,l) < std::tie(other.i,other.j,other.k,other.l); + } + bool operator==(const permutation& other) const { + return std::tie(i,j,k,l) == std::tie(other.i,other.j,other.k,other.l); + } + bool operator!=(const permutation& other) const { + return (not (*this==other)); + } + static std::vector remove_duplicates(std::vector v) { + // remove duplicates + std::sort(v.begin(), v.end(),[](permutation a, permutation b) { return a < b; }); + auto last = std::unique(v.begin(), v.end()); + v.erase(last, v.end()); + return v; + } +}; +std::ostream& operator<<(std::ostream& os, const permutation& p) { + os << "(" << p.i << p.j << p.k << p.l << ")"; + return os; +} +/// compute the EF term of the MP3 energy with permutational symmetry + +/// there is the usual 8-fold permutational symmetry for 2-electron integrals +/// = = = < il | kj > +/// = = = = < kj | il > +/// implemented as loop over (ij) = \sum_i& mp2pairs) const { + print_header3("computing term EF of the MP3 energy with R2_bra"); + // prepare cluster functions + std::size_t nocc=mo_ket().size(); + std::size_t nfrozen=parameters.freeze(); + typedef std::vector> ClusterFunction; + Pairs clusterfunctions; + for (int i = parameters.freeze(); i < nocc; ++i) { + for (int j = i; j < nocc; ++j) { + clusterfunctions(i,j)=mp2pairs(i,j).functions; + if (i!=j) { + for (const auto& t : clusterfunctions(i,j)) { + clusterfunctions(j, i).push_back(t.swap_particles()); + } + } + } + } + + const auto& R2=nemo_->R_square; + double result=0.0; + const std::vector& nemo_orbital=mo_ket().get_vecfunction(); + const std::vector& R2_orbital=mo_bra().get_vecfunction(); + + CCConvolutionOperator::Parameters cparam; + auto g12=CCConvolutionOperatorPtr(world,OpType::OT_G12,cparam); + + // number of pairs + auto npair = [&nocc, &nfrozen]() { return (nocc - nfrozen) * (nocc - nfrozen + 1) / 2; }; + + // turn composite index ij into i and j, taking care of frozen orbitals + PairVectorMap map=PairVectorMap::triangular_map(nfrozen,nocc); + auto ij_to_i_and_j = [&map](const int ij) { return map.map[ij]; }; + + /// = (ik | jl) + std::vector all_tau_permutations; + // loop over unique pairs (ij) + for (int ij=0; ij (2* - ) + // = (2*(ik|jl) - (jk|il)) + double ovlp=inner(clusterfunctions(i,j),clusterfunctions(k,l),R2); + const auto& ket_i=nemo_orbital[i]; + const auto& ket_k=nemo_orbital[k]; + const auto& ket_l=nemo_orbital[l]; + const auto& bra_i=R2_orbital[i]; + const auto& bra_j=R2_orbital[j]; + const auto& bra_l=R2_orbital[l]; + double g_ikjl=inner(bra_i*ket_k, (*g12)(bra_j*ket_l)); + double g_jkil=inner(bra_j*ket_k, (*g12)(bra_l*ket_i)); + tmp+=weight*ovlp*(2.0* g_ikjl - g_jkil); + } + } + printf("mp3 energy: term_EF %2d %2d %12.8f\n",i,j,tmp); + result+=tmp; + } + // sanity check + int npermutations=all_tau_permutations.size(); + all_tau_permutations=permutation::remove_duplicates(all_tau_permutations); + int nuniquepermutations=all_tau_permutations.size(); + int ntotalpermutations=std::pow(nocc-nfrozen,4); + MADNESS_CHECK_THROW(npermutations==nuniquepermutations,"incorrect number of unique permutations"); + MADNESS_CHECK_THROW(npermutations==ntotalpermutations,"incorrect number of unique permutations"); + + printf("MP3 energy: term_EF %12.8f\n",result); + return result; +}; + + +double MP3::compute_mp3_ghij(const Pairs& mp2pairs) const { + + + // prepare cluster functions + std::size_t nocc=mo_ket().size(); + typedef std::vector> ClusterFunction; + Pairs clusterfunctions; + for (int i = parameters.freeze(); i < nocc; ++i) { + for (int j = i; j < nocc; ++j) { + clusterfunctions(i,j)=mp2pairs(i,j).functions; + if (i!=j) { + for (const auto& t : clusterfunctions(i,j)) { + clusterfunctions(j, i).push_back(t.swap_particles()); + } + } + } + } + double result=0.0; + + const auto& R2=nemo_->R_square; + const std::vector& nemo_orbital=mo_ket().get_vecfunction(); + const std::vector& R2_orbital=mo_bra().get_vecfunction(); + + CCConvolutionOperator::Parameters cparam; + auto g12=CCConvolutionOperatorPtr(world,OpType::OT_G12,cparam); + + timer t2(world); + + + // compute intermediates for terms G, I, H, and J + + // \sum_j tau_ij(1,2) * phi_j(2) + std::vector tau_kk_i(nocc); + // \sum_j tau_ij(1,2) * phi_j(1) + std::vector tau_ij_j(nocc); + for (int i = parameters.freeze(); i < nocc; ++i) { + for (int j = parameters.freeze(); j < nocc; ++j) { + auto tmp2 = multiply(clusterfunctions(i, j), R2_orbital[i], {0, 1, 2}); + for (auto& t: tmp2) tau_kk_i[j].push_back(t); + + auto tmp3 = multiply(clusterfunctions(i, j), R2_orbital[j], {0, 1, 2}); + for (auto& t: tmp3) tau_ij_j[i].push_back(t); + } + } + print("info on tau_kk_i, consolidated with op_pure_to_pure"); + for (int i = parameters.freeze(); i < nocc; ++i) { + tau_kk_i[i] = consolidate(tau_kk_i[i], {"op_pure_to_pure", "op_dec_to_dec"}); + for (auto& c: tau_kk_i[i]) c.info(); + } + print("info on tau_ij_j, consolidated with op_pure_to_pure"); + for (int i = parameters.freeze(); i < nocc; ++i) { + tau_ij_j[i] = consolidate(tau_ij_j[i], {"op_pure_to_pure", "op_dec_to_dec"}); + for (auto& c: tau_ij_j[i]) c.info(); + } + + t2.tag("GHIJ term prep"); + + // terms G, I, H, J of Bartlett/Silver 1975 + real_convolution_3d& g = *(g12->get_op()); + for (int i = parameters.freeze(); i < nocc; ++i) { + // tmp(1,2) = g(1,1') | tau_ij(1',2) j(2) > + timer t4(world, "gtau"); + g.set_particle(1); + auto gtau_same = g(tau_kk_i[i]); + t4.tag("compute gtau_same"); + // gtau_same=consolidate(gtau_same,{"op_pure_to_pure"}); + // t4.tag("consolidate gtau_same"); + + // tmp(1',2) = g(1',1) | tau_ij(1,2) j(1) > + g.set_particle(1); + auto gtau_other = g(tau_ij_j[i]); // < tau_ij(1,2) j(1) | g(1,1') | + t4.tag("compute gtau_other"); + // gtau_other=consolidate(gtau_other,{"op_pure_to_pure"}); + // t4.tag("consolidate gtau_other"); + + auto bra_kk_i = multiply(tau_kk_i[i], R2, {3, 4, 5}); + auto bra_ij_j = multiply(tau_ij_j[i], R2, {3, 4, 5}); + + double G = inner(bra_kk_i, gtau_same); + printf("G %12.8f\n", G); + + double H = inner(bra_ij_j, gtau_other); + printf("H %12.8f\n", H); + + double I = inner(bra_kk_i, gtau_other); + printf("I %12.8f\n", I); + + double J = inner(bra_ij_j, gtau_same); + printf("J %12.8f\n", J); + + t4.tag("compute inner products"); + double tmp = (8.0 * G - 4.0 * I + 2.0 * H - 4.0 * J); + printf("mp3 energy: term_GHIJ %2d %12.8f\n", i, tmp); + result += tmp; + } + printf("MP3 energy: term_GHIJ %12.8f\n", result); + t2.tag("GHIJ term"); + return result; +}; + +double MP3::compute_mp3_klmn(const Pairs& mp2pairs) const { + + + // prepare cluster functions + std::size_t nocc=mo_ket().size(); + typedef std::vector> ClusterFunction; + Pairs clusterfunctions; + for (int i = parameters.freeze(); i < nocc; ++i) { + for (int j = i; j < nocc; ++j) { + clusterfunctions(i,j)=mp2pairs(i,j).functions; + if (i!=j) { + for (const auto& t : clusterfunctions(i,j)) { + clusterfunctions(j, i).push_back(t.swap_particles()); + } + } + } + } + double result=0.0; + + const auto& R2=nemo_->R_square; + const std::vector& nemo_orbital=mo_ket().get_vecfunction(); + const std::vector& R2_orbital=mo_bra().get_vecfunction(); + + CCConvolutionOperator::Parameters cparam; + auto g12=CCConvolutionOperatorPtr(world,OpType::OT_G12,cparam); + + // compute the term (2) + madness::Pairs gij; + + for (int i = parameters.freeze(); i < nocc; ++i) { + for (int j = parameters.freeze(); j < nocc; ++j) { + gij.insert(i,j,(*g12)(nemo_orbital[i]*R2_orbital[j])); + } + } + + + timer multiply_KLMN(world, "multiplication in KLMN term"); + multiply_KLMN.interrupt(); + timer inner_KLMN(world, "inner in KLMN term"); + inner_KLMN.interrupt(); + // prepare intermediates for terms K, L, M, N of Bartlett/Silver 1975 + // tau_g_ij(1,2) = \sum_k tau_ik(1,1') g_jk(2) + Pairs tau_ik_g_kj, tau_kj_g_ki; + for (int i = parameters.freeze(); i < nocc; ++i) { + for (int j = parameters.freeze(); j < nocc; ++j) { + multiply_KLMN.resume(); + std::vector> tmp1, tmp2; + for (int k = parameters.freeze(); k < nocc; ++k) { + tmp1 += multiply(clusterfunctions(i, k), gij(k, j), {3, 4, 5}); + tmp2 += multiply(clusterfunctions(k, j), gij(k, i), {3, 4, 5}); + } + tmp1 = consolidate(tmp1, {}); + tmp2 = consolidate(tmp2, {}); + tau_ik_g_kj(i, j) = tmp1; + tau_kj_g_ki(i, j) = tmp2; + multiply_KLMN.interrupt(); + + inner_KLMN.resume(); + double K = inner(clusterfunctions(i, j), tau_ik_g_kj(i, j), R2); + double L = inner(clusterfunctions(i, j), tau_kj_g_ki(i, j), R2); + double M = inner(clusterfunctions(j, i), tau_kj_g_ki(i, j), R2); + double N = inner(clusterfunctions(j, i), tau_ik_g_kj(i, j), R2); + inner_KLMN.interrupt(); + + double tmp = -4 * K - 4 * L + 2 * M + 2 * N; + printf("mp3 energy: term_KLMN with particle=1 %2d %2d %12.8f\n", i, j, tmp); + result += tmp; + } + } + printf("MP3 energy: term_KLMN (KLMN) %12.8f\n", result); + multiply_KLMN.print("multiplication in KLMN term"); + inner_KLMN.print("inner in KLMN term"); + + return result; + +}; + +double MP3::mp3_energy_contribution(const Pairs& mp2pairs) const { + + print_header2("computing the MP3 correlation energy"); + print("mp2pairs.size()",mp2pairs.allpairs.size()); + // print_header3("prepare the cluster function"); + // typedef std::vector> ClusterFunction; + // Pairs clusterfunctions; + // + // auto R2 = nemo->ncf->square(); + // auto R = nemo->ncf->function(); + // std::vector nemo_orbital=mo_ket().get_vecfunction(); + // std::vector R2_orbital=mo_bra().get_vecfunction(); + // const int nocc=mo_ket().size(); + + double term_CD=0.0, term_EF=0.0, term_GHIJ=0.0, term_KLMN=0.0; + timer t2(world); + term_CD=compute_mp3_cd(mp2pairs); + t2.tag("CD term"); + term_EF=compute_mp3_ef_with_permutational_symmetry(mp2pairs); + t2.tag("EF term"); + term_GHIJ=compute_mp3_ghij(mp2pairs); + t2.tag("GHIJ term"); + term_KLMN=compute_mp3_klmn(mp2pairs); + t2.tag("KLMN term"); + + printf("term_CD %12.8f\n",term_CD); + printf("term_GHIJ %12.8f\n",term_GHIJ); + printf("term_KLMN %12.8f\n",term_KLMN); + printf("term_EF %12.8f\n",term_EF); + double mp3_energy=term_CD+term_GHIJ+term_KLMN+term_EF; + printf("MP3 energy contribution %12.8f\n",mp3_energy); + return mp3_energy; +} +} diff --git a/src/madness/chem/mp3.h b/src/madness/chem/mp3.h new file mode 100644 index 00000000000..af7a7acbc6b --- /dev/null +++ b/src/madness/chem/mp3.h @@ -0,0 +1,40 @@ +// +// Created by Florian Bischoff on 2/15/24. +// + +#ifndef MP3_H +#define MP3_H + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace madness { +class MP3 : public CCPotentials { +public: + + MP3(World& world, const std::shared_ptr nemo, const CCParameters& param) + : CCPotentials(world,nemo,param) {} + MP3(const CCPotentials& ops) : CCPotentials(ops) {} + + + double compute_mp3_cd(const Pairs& mp2pairs) const; + double compute_mp3_ef(const Pairs& mp2pairs) const; + double compute_mp3_ef_with_permutational_symmetry(const Pairs& mp2pairs) const; + double compute_mp3_ghij(const Pairs& mp2pairs) const; + double compute_mp3_klmn(const Pairs& mp2pairs) const; + double mp3_energy_contribution(const Pairs& mp2pairs) const; + +}; +} + + +#endif //MP3_H From df98068830cf126c70bac6468668f244b8ec28eb Mon Sep 17 00:00:00 2001 From: fbischoff Date: Fri, 16 Feb 2024 16:23:17 +0100 Subject: [PATCH 091/109] changing the accumulation of 6d functions in CCPairfunction::consolidate, through gaxpy instead of CompositeFunctionFactory --- src/madness/chem/ccpairfunction.cc | 7 ++- src/madness/chem/ccpairfunction.h | 7 +++ src/madness/chem/mp3.cc | 79 ++++++++++++++++++++++++++++-- src/madness/chem/mp3.h | 1 + src/madness/mra/mra.h | 5 +- src/madness/mra/testvmra.cc | 77 ++++++++++++++++++++++++++--- src/madness/mra/vmra.h | 39 +++++++++++++++ 7 files changed, 201 insertions(+), 14 deletions(-) diff --git a/src/madness/chem/ccpairfunction.cc b/src/madness/chem/ccpairfunction.cc index 41f37e749b6..f0f1dbc9a49 100644 --- a/src/madness/chem/ccpairfunction.cc +++ b/src/madness/chem/ccpairfunction.cc @@ -139,8 +139,11 @@ std::vector> CCPairFunction::collect_same_types(c if (op_pure[opint].size()>0) { auto op=ops[opint]; if (op_pure[opint].size()>1) { - Function tmp=CompositeFactory(world).ket(op_pure[opint]); - tmp.fill_tree(); + // Function tmp=CompositeFactory(world).ket(op_pure[opint]); + // tmp.fill_tree(); + Tensor c(1,op_pure[opint].size()); + c=1.0; + Function tmp=transform_reconstructed(world, op_pure[opint],c,true)[0]; result.push_back(CCPairFunction(op,tmp)); } else { MADNESS_CHECK_THROW(op_pure[opint].size()==1,"op_pure[opint].size()!=1"); diff --git a/src/madness/chem/ccpairfunction.h b/src/madness/chem/ccpairfunction.h index ce052136752..a8ca0c83471 100644 --- a/src/madness/chem/ccpairfunction.h +++ b/src/madness/chem/ccpairfunction.h @@ -880,6 +880,13 @@ std::vector >& operator+=(std::vector +std::vector > operator*(const double fac, const std::vector >& arg) { + std::vector> result; + for (const auto& l : arg) result.push_back(fac*l); + return result; +} + template bool is_collected(const std::vector>& other) { diff --git a/src/madness/chem/mp3.cc b/src/madness/chem/mp3.cc index e5a2fb89ee7..f030a592719 100644 --- a/src/madness/chem/mp3.cc +++ b/src/madness/chem/mp3.cc @@ -348,8 +348,77 @@ double MP3::compute_mp3_ghij(const Pairs& mp2pairs) const { return result; }; -double MP3::compute_mp3_klmn(const Pairs& mp2pairs) const { +double MP3::compute_mp3_klmn_fast(const Pairs& mp2pairs) const { + + // prepare cluster functions + std::size_t nocc=mo_ket().size(); + typedef std::vector> ClusterFunction; + Pairs clusterfunctions; + for (int i = parameters.freeze(); i < nocc; ++i) { + for (int j = i; j < nocc; ++j) { + clusterfunctions(i,j)=mp2pairs(i,j).functions; + if (i!=j) { + for (const auto& t : clusterfunctions(i,j)) { + clusterfunctions(j, i).push_back(t.swap_particles()); + } + } + } + } + double result=0.0; + + const auto& R2=nemo_->R_square; + const std::vector& nemo_orbital=mo_ket().get_vecfunction(); + const std::vector& R2_orbital=mo_bra().get_vecfunction(); + + CCConvolutionOperator::Parameters cparam; + auto g12=CCConvolutionOperatorPtr(world,OpType::OT_G12,cparam); + // compute the term (2) + madness::Pairs gij; + + for (int i = parameters.freeze(); i < nocc; ++i) { + for (int j = parameters.freeze(); j < nocc; ++j) { + gij.insert(i,j,(*g12)(nemo_orbital[i]*R2_orbital[j])); + } + } + + + timer multiply_KLMN(world, "multiplication in KLMN term"); + multiply_KLMN.interrupt(); + timer inner_KLMN(world, "inner in KLMN term"); + inner_KLMN.interrupt(); + // prepare intermediates for terms K, L, M, N of Bartlett/Silver 1975 + // tau_g_ij(1,2) = \sum_k tau_ik(1,1') g_jk(2) + Pairs tau_ik_g_kj, tau_kj_g_ki; + for (int i = parameters.freeze(); i < nocc; ++i) { + for (int j = parameters.freeze(); j < nocc; ++j) { + multiply_KLMN.resume(); + std::vector> rhs; + for (int k = parameters.freeze(); k < nocc; ++k) { + rhs += 4.0 * multiply(clusterfunctions(i, k), gij(k, j), {3, 4, 5}); // K + rhs += 4.0 * multiply(clusterfunctions(k, j), gij(k, i), {3, 4, 5}); // L + rhs += -2.0 * multiply(clusterfunctions(j, k), gij(k, i), {0, 1, 2}); // M + rhs += -2.0 * multiply(clusterfunctions(k, i), gij(k, j), {0, 1, 2}); // N + } + rhs = consolidate(rhs, {}); + multiply_KLMN.interrupt(); + + inner_KLMN.resume(); + double tmp = inner(clusterfunctions(i, j), rhs, R2); + inner_KLMN.interrupt(); + + printf("mp3 energy: term_KLMN with particle=1 %2d %2d %12.8f\n", i, j, tmp); + result += tmp; + } + } + printf("MP3 energy: term_KLMN (KLMN) %12.8f\n", result); + multiply_KLMN.print("multiplication in KLMN term"); + inner_KLMN.print("inner in KLMN term"); + + return result; + +}; +double MP3::compute_mp3_klmn(const Pairs& mp2pairs) const { // prepare cluster functions std::size_t nocc=mo_ket().size(); @@ -441,12 +510,14 @@ double MP3::mp3_energy_contribution(const Pairs& mp2pairs) const { double term_CD=0.0, term_EF=0.0, term_GHIJ=0.0, term_KLMN=0.0; timer t2(world); - term_CD=compute_mp3_cd(mp2pairs); + // term_CD=compute_mp3_cd(mp2pairs); t2.tag("CD term"); - term_EF=compute_mp3_ef_with_permutational_symmetry(mp2pairs); + // term_EF=compute_mp3_ef_with_permutational_symmetry(mp2pairs); t2.tag("EF term"); - term_GHIJ=compute_mp3_ghij(mp2pairs); + // term_GHIJ=compute_mp3_ghij(mp2pairs); t2.tag("GHIJ term"); + term_KLMN=compute_mp3_klmn_fast(mp2pairs); + t2.tag("KLMN term fast"); term_KLMN=compute_mp3_klmn(mp2pairs); t2.tag("KLMN term"); diff --git a/src/madness/chem/mp3.h b/src/madness/chem/mp3.h index af7a7acbc6b..b50b558ebf2 100644 --- a/src/madness/chem/mp3.h +++ b/src/madness/chem/mp3.h @@ -31,6 +31,7 @@ class MP3 : public CCPotentials { double compute_mp3_ef_with_permutational_symmetry(const Pairs& mp2pairs) const; double compute_mp3_ghij(const Pairs& mp2pairs) const; double compute_mp3_klmn(const Pairs& mp2pairs) const; + double compute_mp3_klmn_fast(const Pairs& mp2pairs) const; double mp3_energy_contribution(const Pairs& mp2pairs) const; }; diff --git a/src/madness/mra/mra.h b/src/madness/mra/mra.h index a6203485699..a34d2edd3a5 100644 --- a/src/madness/mra/mra.h +++ b/src/madness/mra/mra.h @@ -795,8 +795,10 @@ namespace madness { void sum_down(bool fence = true) const { PROFILE_MEMBER_FUNC(Function); verify(); - MADNESS_ASSERT(is_reconstructed()); + MADNESS_CHECK_THROW(impl->get_tree_state()==redundant_after_merge, "sum_down requires a redundant_after_merge state"); const_cast*>(this)->impl->sum_down(fence); + const_cast*>(this)->impl->set_tree_state(reconstructed); + if (fence && VERIFY_TREE) verify_tree(); // Must be after in case nonstandard } @@ -2240,6 +2242,7 @@ namespace madness { result.set_impl(ff, false); result.get_impl()->apply_1d_realspace_push(op, ff.get_impl().get(), axis, fence); + result.get_impl()->set_tree_state(redundant_after_merge); return result; } diff --git a/src/madness/mra/testvmra.cc b/src/madness/mra/testvmra.cc index 8bd05e0e4c5..96fe01e1f29 100644 --- a/src/madness/mra/testvmra.cc +++ b/src/madness/mra/testvmra.cc @@ -2,6 +2,7 @@ #include #include #include +#include const double PI = 3.1415926535897932384; @@ -190,6 +191,65 @@ void test_inner(World& world) { print("error norm",(rold-rnew).normf(),"\n"); } +template +int test_transform(World& world) { + test_output to("testing transform"); + to.set_cout_to_terminal(); + typedef std::shared_ptr< FunctionFunctorInterface > ffunctorT; + + + const double thresh=1.e-7; + Tensor cell(NDIM,2); + for (std::size_t i=0; i::set_cell(cell); + FunctionDefaults::set_k(8); + FunctionDefaults::set_thresh(thresh); + FunctionDefaults::set_refine(true); + FunctionDefaults::set_initial_level(3); + FunctionDefaults::set_truncate_mode(1); + + + const int nleft=RandomValue()%10; + const int nright=RandomValue()%10; + print("nleft, nright",nleft,nright); + + START_TIMER; + std::vector< Function > left(nleft); + for (int i=0; i(FunctionDefaults::get_cell(),0.5)); + left[i] = FunctionFactory(world).functor(f); + } + END_TIMER("project"); + to.checkpoint(true,"initial projection"); + + Tensor c(nleft,nright); + auto result1=transform(world,left,c); + to.checkpoint(true,"reference transform"); + + change_tree_state(left,reconstructed); + auto result2=transform_reconstructed(world,left,c,false); + world.gop.fence(); + for (auto& r : result2) MADNESS_CHECK(r.get_impl()->get_tree_state()==redundant_after_merge); + change_tree_state(result2,reconstructed); + double err1=norm2(world, result1-result2); + to.checkpoint(err1,thresh,"reference transform"); + + change_tree_state(left,compressed); + auto result3=transform_reconstructed(world,left,c); + double err2=norm2(world, result1-result3); + to.checkpoint(err2,thresh,"reference transform"); + + + return to.end(); +} + + + + + template void test_cross(World& world) { typedef std::shared_ptr< FunctionFunctorInterface > ffunctorT; @@ -408,13 +468,15 @@ int main(int argc, char**argv) { for (int iarg=1; iarg(world); - test_add,3 >(world); + // test_add(world); + // test_add,3 >(world); test_inner(world); test_inner(world); @@ -425,6 +487,11 @@ int main(int argc, char**argv) { test_cross,double,2>(world); test_cross,std::complex,2>(world); + test_transform(world); + test_transform(world); + test_transform(world); + test_transform(world); + test_rot(world); test_rot,3>(world); @@ -457,10 +524,6 @@ int main(int argc, char**argv) { print(s); error("caught a c-string exception"); } - catch (const char* s) { - print(s); - error("caught a c-string exception"); - } catch (const std::string& s) { print(s); error("caught a string (class) exception"); diff --git a/src/madness/mra/vmra.h b/src/madness/mra/vmra.h index ef1a4b3044a..93950ca49af 100644 --- a/src/madness/mra/vmra.h +++ b/src/madness/mra/vmra.h @@ -710,6 +710,45 @@ namespace madness { return vc; } + /// Transforms a vector of functions according to new[i] = sum[j] old[j]*c[j,i] + + /// all trees are in reconstructed state, final trees have to be summed down if no fence is present + template + std::vector< Function > + transform_reconstructed(World& world, + const std::vector< Function >& v, + const Tensor& c, + bool fence=true) { + + PROFILE_BLOCK(Vtransformsp); + typedef TENSOR_RESULT_TYPE(T,R) resultT; + int n = v.size(); // n is the old dimension + int m = c.dim(1); // m is the new dimension + MADNESS_ASSERT(n==c.dim(0)); + + // if we fence set the right tree state here, otherwise it has to be correct from the start. + if (fence) change_tree_state(v,reconstructed); + for (const auto& vv : v) MADNESS_CHECK_THROW( + vv.get_impl()->get_tree_state()==reconstructed,"trees have to be reconstructed in transform_reconstructed"); + + std::vector< Function > vc = zero_functions(world, m); + + for (int i=0; iset_tree_state(redundant_after_merge); + for (int j=0; jmerge_trees(resultT(1.0),*v[j].get_impl(),resultT(c(j,i)),false); + } + } + + // if we fence we can as well finish the job here. Otherwise no harm done, as the tree state is well-defined. + if (fence) { + world.gop.fence(); + for (auto& r : vc) r.sum_down(false); + world.gop.fence(); + } + return vc; + } + /// this version of transform uses Function::vtransform and screens /// using both elements of `c` and `v` template From a69ed97bdaf2e7e200c0b6a35acfb72bf6949d5d Mon Sep 17 00:00:00 2001 From: fbischoff Date: Tue, 20 Feb 2024 10:21:50 +0100 Subject: [PATCH 092/109] fix restart for MP2, some cleanup --- src/madness/chem/CC2.cc | 133 ++++++++++--------------------- src/madness/chem/CC2.h | 26 ------ src/madness/chem/CCPotentials.cc | 22 ----- src/madness/chem/CCPotentials.h | 8 -- 4 files changed, 42 insertions(+), 147 deletions(-) diff --git a/src/madness/chem/CC2.cc b/src/madness/chem/CC2.cc index c87234bd68a..ca7f0de4918 100644 --- a/src/madness/chem/CC2.cc +++ b/src/madness/chem/CC2.cc @@ -69,7 +69,7 @@ CC2::solve() { if (world.rank() == 0) { printf_msg_energy_time("MP2 correlation energy",mp2_energy,wall_time()); // std::cout << std::fixed << std::setprecision(10) << " MP2 Correlation Energy =" << mp2_energy << "\n"; - } + } } if (need_cc2) { @@ -398,47 +398,55 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { // make vector holding CCPairs for partitioner of MacroTask std::vector pair_vec=Pairs::pairs2vector(doubles,triangular_map); - if (world.rank()==0) std::cout << std::fixed << std::setprecision(1) << "\nStarting constant part at time " << wall_time() << std::endl; - // calc constant part via taskq - auto taskq = std::shared_ptr(new MacroTaskQ(world, world.size())); - taskq->set_printlevel(3); - MacroTaskMp2ConstantPart t; - MacroTask task(world, t, taskq); - std::vector result_vec = task(pair_vec, CCOPS.mo_ket().get_vecfunction(), - CCOPS.mo_bra().get_vecfunction(), parameters, - nemo->R_square, nemo->ncf->U1vec(),std::vector({"Ue","KffK"})); - taskq->print_taskq(); - taskq->run_all(); - - if (world.rank()==0) std::cout << std::fixed << std::setprecision(1) << "\nFinished constant part at time " << wall_time() << std::endl; - if (world.rank()==0) std::cout << std::fixed << std::setprecision(1) << "\nStarting saving pairs and energy calculation at time " << wall_time() << std::endl; - - // compute coupling for the constant term -// Pairs Gfij_pair=Pairs::vector2pairs(Gfij_vec, PairVectorMap::triangular_map(nfreeze,nocc)); -// Pairs coupling_constant_term=compute_local_coupling(Gfij_pair); -// std::vector coupling_constant_term_vec=Pairs::pairs2vector(coupling_constant_term,triangular_map); - - // transform vector back to Pairs structure - for (size_t i = 0; i < pair_vec.size(); i++) { - pair_vec[i].constant_part = result_vec[i]; - pair_vec[i].functions[0] = CCPairFunction(result_vec[i]); - pair_vec[i].constant_part.truncate().reduce_rank(); - pair_vec[i].function().truncate().reduce_rank(); - save(pair_vec[i].constant_part, pair_vec[i].name() + "_const"); - save(pair_vec[i].function(), pair_vec[i].name()); - if (pair_vec[i].type == GROUND_STATE) total_energy += CCOPS.compute_pair_correlation_energy(pair_vec[i]); + // read constant part from file + if (parameters.no_compute_mp2_constantpart()) { + if (world.rank()==0) print("Skipping MP2 constant part calculation"); + for (auto& c : pair_vec) { + MADNESS_CHECK_THROW(c.constant_part.is_initialized(), "could not find constant part"); + // constant part is zero-order guess for pair.function + if (not c.function().is_initialized()) c.update_u(c.constant_part); + } + + } else { + if (world.rank()==0) print("Starting MP2 constant part calculation"); + // calc constant part via taskq + auto taskq = std::shared_ptr(new MacroTaskQ(world, world.size())); + taskq->set_printlevel(3); + MacroTaskMp2ConstantPart t; + MacroTask task(world, t, taskq); + std::vector result_vec = task(pair_vec, CCOPS.mo_ket().get_vecfunction(), + CCOPS.mo_bra().get_vecfunction(), parameters, + nemo->R_square, nemo->ncf->U1vec(),std::vector({"Ue","KffK"})); + taskq->print_taskq(); + taskq->run_all(); + + if (world.rank()==0) std::cout << std::fixed << std::setprecision(1) << "\nFinished constant part at time " << wall_time() << std::endl; + if (world.rank()==0) std::cout << std::fixed << std::setprecision(1) << "\nStarting saving pairs and energy calculation at time " << wall_time() << std::endl; + + // transform vector back to Pairs structure + for (size_t i = 0; i < pair_vec.size(); i++) { + pair_vec[i].constant_part = result_vec[i]; + pair_vec[i].functions[0] = CCPairFunction(result_vec[i]); + pair_vec[i].constant_part.truncate().reduce_rank(); + pair_vec[i].constant_part.print_size("constant_part"); + pair_vec[i].function().truncate().reduce_rank(); + save(pair_vec[i].constant_part, pair_vec[i].name() + "_const"); + // save(pair_vec[i].function(), pair_vec[i].name()); + if (pair_vec[i].type == GROUND_STATE) total_energy += CCOPS.compute_pair_correlation_energy(pair_vec[i]); + } + if (world.rank()==0) { + printf("current decoupled mp2 energy %12.8f\n", total_energy); + std::cout << std::fixed << std::setprecision(1) << "\nFinished saving pairs and energy calculation at time " << wall_time() << std::endl; + } } - if (world.rank()==0) std::cout << std::fixed << std::setprecision(1) << "\nFinished saving pairs and energy calculation at time " << wall_time() << std::endl; // create new pairs structure Pairs updated_pairs; for (auto& tmp_pair : pair_vec) { updated_pairs.insert(tmp_pair.i, tmp_pair.j, tmp_pair); } -// typedef allocator allocT; -// allocT alloc(world, pair_vec.size()); -// XNonlinearSolver, double, allocT> solver(alloc); + auto solver= nonlinear_vector_solver(world,pair_vec.size()); solver.set_maxsub(parameters.kain_subspace()); solver.do_print = (world.rank() == 0); @@ -449,39 +457,11 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { // compute the coupling between the pair functions Pairs coupling=compute_local_coupling(updated_pairs); auto coupling_vec=Pairs::pairs2vector(coupling,triangular_map); - -// if (world.rank()==0) std::cout << std::fixed << std::setprecision(1) << "\nFinished coupling at time " << wall_time() << std::endl; - - -// // make coupling vector that can be stored in cloud -// // pair -> position -// // (i,j) -> j(j+1)+i -// // Pairs struc does not provide access to last element -// int i_max = 0; -// int j_max = 0; -// for (auto& tmp_coupling: coupling.allpairs){ -// if (std::get<0>(tmp_coupling.first) > i_max) i_max = std::get<0>(tmp_coupling.first); -// if (std::get<1>(tmp_coupling.first) > j_max) j_max = std::get<1>(tmp_coupling.first); -// } -// int last_position = j_max*(j_max+1) + i_max; -// std::vector coupling_vec = zero_functions_compressed(world, (last_position+1)); -// -// for (auto& tmp_coupling : coupling.allpairs) { -// int i = std::get<0>(tmp_coupling.first); -// int j = std::get<1>(tmp_coupling.first); -// int position = j*(j+1) + i; -// //if (world.rank() == 0) std::cout << i << " ," << j << " -> "<< position << std::endl; -// coupling_vec[position] = tmp_coupling.second; -// } - //print coupling vec if (parameters.debug()) print_size(world, coupling_vec, "couplingvector"); double old_energy = total_energy; total_energy = 0.0; - //NonlinearSolverND<6> solver(parameters.kain_subspace()); - //solver.do_print = (world.rank() == 0); - if (world.rank()==0) std::cout << std::fixed << std::setprecision(1) << "\nStarting pairs update at time " << wall_time() << std::endl; // calc update for pairs via macrotask auto taskq = std::shared_ptr(new MacroTaskQ(world, world.size())); @@ -569,35 +549,6 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { return total_energy; } -double -CC2::solve_mp2(Pairs& doubles) { -// output.section("Solve MP2"); - double omega = 0.0; - Pairs pair_energies; - for (auto& tmp_pair : doubles.allpairs) { - MADNESS_ASSERT(tmp_pair.second.type == GROUND_STATE); - MADNESS_ASSERT(tmp_pair.second.ctype == CT_MP2); - - if (parameters.no_compute_mp2()) output("Found no_compute_mp2 keyword"); - else { - update_constant_part_mp2(tmp_pair.second); - iterate_pair(tmp_pair.second); - } - save(tmp_pair.second.function(), tmp_pair.second.name()); - const double pair_energy = CCOPS.compute_pair_correlation_energy(tmp_pair.second); - pair_energies.insert(tmp_pair.second.i, tmp_pair.second.j, pair_energy); - omega += pair_energy; - - } - if (world.rank() == 0) std::cout << "\nMP2 Pair Correlation Energies:\n"; - for (auto& a : pair_energies.allpairs) { - if (world.rank() == 0) - std::cout << std::fixed << std::setprecision(10) << "omega_" << a.first.first << a.first.second << "=" - << a.second << "\n"; - } - if (world.rank() == 0) std::cout << "sum =" << omega << "\n"; - return omega; -} /// add the coupling terms for local MP2 diff --git a/src/madness/chem/CC2.h b/src/madness/chem/CC2.h index ef640924314..9f2d23cc709 100644 --- a/src/madness/chem/CC2.h +++ b/src/madness/chem/CC2.h @@ -136,10 +136,6 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { std::vector solve_ccs(); - /// solve the MP2 equations (uncoupled -> Canonical Orbitals) - double - solve_mp2(Pairs& doubles); - double compute_mp3(const Pairs& mp2pairs) const { MP3 mp3(CCOPS); double mp3_contribution=mp3.mp3_energy_contribution(mp2pairs); @@ -412,28 +408,6 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { iterate_lrcc2_pairs(const CC_vecfunction& cc2_s, const Pairs& cc2_d, const CC_vecfunction lrcc2_s, Pairs& lrcc2_d); - bool update_constant_part_mp2(CCPair& pair) { - MADNESS_ASSERT(pair.ctype == CT_MP2); - MADNESS_ASSERT(pair.type == GROUND_STATE); - if (parameters.no_compute_mp2_constantpart()) { - pair.constant_part=real_factory_6d(world); - load(pair.constant_part,pair.name()+"_const"); - } - if (pair.constant_part.is_initialized()) return false; - - // make screening Operator - real_convolution_6d Gscreen = BSHOperator<6>(world, sqrt(-2.0 * CCOPS.get_epsilon(pair.i, pair.j)), - parameters.lo(), parameters.thresh_bsh_6D()); - Gscreen.modified() = true; - - const CCFunction& moi = CCOPS.mo_ket(pair.i); - const CCFunction& moj = CCOPS.mo_ket(pair.j); - - pair.constant_part = CCOPS.make_constant_part_mp2(moi, moj, &Gscreen); - save(pair.constant_part, pair.name() + "_const"); - return true; - } - bool update_constant_part_cc2_gs(const CC_vecfunction& tau, CCPair& pair) { MADNESS_ASSERT(pair.ctype == CT_CC2); MADNESS_ASSERT(pair.type == GROUND_STATE); diff --git a/src/madness/chem/CCPotentials.cc b/src/madness/chem/CCPotentials.cc index 05ec9786f61..09a95aa2d0e 100644 --- a/src/madness/chem/CCPotentials.cc +++ b/src/madness/chem/CCPotentials.cc @@ -678,28 +678,6 @@ CCPotentials::fock_residue_6d_macrotask(World& world, const CCPair& u, const CCP return vphi; } -madness::real_function_6d -CCPotentials::make_constant_part_mp2(const CCFunction& ti, const CCFunction& tj, - const real_convolution_6d *Gscreen) const { - output.section("Calculating Constant Part of MP2 pair " + ti.name() + tj.name()); - CCTimer time(world, "Calculating Constant Part of MP2"); - MADNESS_ASSERT(ti.type == HOLE); - MADNESS_ASSERT(tj.type == HOLE); - real_function_6d V = apply_Vreg(ti, tj, Gscreen); - print_size(V, "Vreg", parameters.debug()); - V = apply_Q12t(V, mo_ket_); - print_size(V, "QVreg"); - real_convolution_6d G = BSHOperator<6>(world, sqrt(-2.0 * get_epsilon(ti.i, tj.i)), parameters.lo(), - parameters.thresh_bsh_6D()); - G.destructive() = true; - real_function_6d GV = -2.0 * G(V); - print_size(GV, "GVreg", parameters.debug()); - GV = apply_Q12t(GV, mo_ket_); - print_size(GV, "GVreg"); - time.info(); - return GV; -} - madness::real_function_6d CCPotentials::make_constant_part_mp2_macrotask(World& world, const CCPair& pair, const std::vector& mo_ket, diff --git a/src/madness/chem/CCPotentials.h b/src/madness/chem/CCPotentials.h index 7d51dbdfadc..05a1fe202d7 100644 --- a/src/madness/chem/CCPotentials.h +++ b/src/madness/chem/CCPotentials.h @@ -259,14 +259,6 @@ class CCPotentials { const std::vector& U1, const real_function_3d& U2); - /// Function evaluates the consant part of the ground state for MP2 - /// @param[out]The result is \f$ Q12(G(Q12(Vreg|titj>))) \f$ - /// @param[in] ti, first particle -> should be HOLE state - /// @param[in] tj, second particle -> should be HOLE state - /// @param[in] Gscreen pointer to bsh operator (in order to screen), has to be in modified NS form - real_function_6d - make_constant_part_mp2(const CCFunction& ti, const CCFunction& tj, const real_convolution_6d *Gscreen = NULL) const; - /// Static version of make_constant_part_mp2 to be called from macrotask. static madness::real_function_6d make_constant_part_mp2_macrotask(World& world, const CCPair& pair, const std::vector& mo_ket, From 749e409b0a1e9a2e1e6775582c34195e690fdc8b Mon Sep 17 00:00:00 2001 From: fbischoff Date: Tue, 20 Feb 2024 10:25:33 +0100 Subject: [PATCH 093/109] fix units in structure_library --- src/madness/chem/structure_library | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/madness/chem/structure_library b/src/madness/chem/structure_library index 74e11333fa5..77ba5c88c25 100644 --- a/src/madness/chem/structure_library +++ b/src/madness/chem/structure_library @@ -301,7 +301,7 @@ end structure=water2 geometry -units angs +units angstrom h -1.958940 -0.032063 0.725554 h -0.607485 0.010955 0.056172 o -1.538963 0.004548 -0.117331 @@ -312,7 +312,7 @@ end structure=water3 geometry -units angs +units angstrom o -0.167787 1.645761 0.108747 h 0.613411 1.102620 0.113724 h -0.093821 2.209720 -0.643619 @@ -326,7 +326,7 @@ end structure=water4 geometry -units angs +units angstrom o 0.216486 -1.989005 0.035297 h -0.603911 -1.505274 -0.033552 h 0.138672 -2.535875 0.799566 @@ -344,7 +344,7 @@ end structure=water5 geometry -units angs +units angstrom o -0.571270 2.322980 -0.003174 o 2.038411 1.261129 -0.102281 o 1.831197 -1.536089 0.156570 From fea7e7a282555288af4c3eaf3a49d59c278bcd7b Mon Sep 17 00:00:00 2001 From: fbischoff Date: Tue, 20 Feb 2024 11:02:04 +0100 Subject: [PATCH 094/109] fix units in structure_library --- src/madness/chem/structure_library | 96 ++++++++++++++---------------- 1 file changed, 46 insertions(+), 50 deletions(-) diff --git a/src/madness/chem/structure_library b/src/madness/chem/structure_library index 77ba5c88c25..d9d24122eec 100644 --- a/src/madness/chem/structure_library +++ b/src/madness/chem/structure_library @@ -300,66 +300,62 @@ h 1.42650808202133 0.00000000000000 -0.35501194545850 end structure=water2 -geometry -units angstrom - h -1.958940 -0.032063 0.725554 - h -0.607485 0.010955 0.056172 - o -1.538963 0.004548 -0.117331 - h 1.727607 0.762122 -0.351887 - h 1.704312 -0.747744 -0.399151 - o 1.430776 -0.003706 0.113495 +geometry + h -3.70186011075500 -0.06059028899871 1.37109835461971 + h -1.14798027983604 0.02070194978576 0.10614969633645 + o -2.90821859864409 0.00859447445236 -0.22172345689761 + h 3.26470409525617 1.44020185984707 -0.66497005972273 + h 3.22068292499060 -1.41303137750844 -0.75428607566744 + o 2.70377479750559 -0.00700332504847 0.21447446745186 end structure=water3 -geometry -units angstrom - o -0.167787 1.645761 0.108747 - h 0.613411 1.102620 0.113724 - h -0.093821 2.209720 -0.643619 - o 1.517569 -0.667424 -0.080674 - h 1.989645 -1.098799 0.612047 - h 0.668397 -1.091798 -0.139744 - o -1.350388 -0.964879 -0.092208 - h -1.908991 -1.211298 0.626207 - h -1.263787 -0.018107 -0.055536 +geometry + o -0.31707147865848 3.11003757018401 0.20550204777292 + h 1.15917879689952 2.08364982864237 0.21490721473629 + h -0.17729599551346 4.17576563036006 -1.21626364392172 + o 2.86778979775713 -1.26124857451507 -0.15245176604442 + h 3.75988415166526 -2.07642918508861 1.15660121045426 + h 1.26308727804237 -2.06319921243228 -0.26407788871397 + o -2.55186349313518 -1.82335706137257 -0.17424786726112 + h -3.60747018014350 -2.28902148531211 1.18335973249592 + h -2.38821132030115 -0.03421727108816 -0.10494783051594 end structure=water4 -geometry -units angstrom - o 0.216486 -1.989005 0.035297 - h -0.603911 -1.505274 -0.033552 - h 0.138672 -2.535875 0.799566 - h 1.505276 -0.603920 0.033505 - o 1.989004 0.216483 -0.035296 - h 2.535922 0.138690 -0.799534 - o -1.989001 -0.216487 -0.035297 - h -2.535947 -0.138688 -0.799513 - h -1.505273 0.603920 0.033493 - o -0.216485 1.989007 0.035294 - h -0.138694 2.535879 0.799565 - h 0.603919 1.505277 -0.033513 +geometry + o 0.40909925160388 -3.75867472694021 0.06670166331246 + h -1.14122639863710 -2.84455561495330 -0.06340409121058 + h 0.26205210229952 -4.79210925723138 1.51096076516684 + h 2.84455939440557 -1.14124340617230 0.06331527408233 + o 3.75867283721408 0.40909358242548 -0.06669977358633 + h 4.79219807435963 0.26208611736991 -1.51090029393059 + o -3.75866716803568 -0.40910114133001 -0.06670166331246 + h -4.79224531751295 -0.26208233791764 -1.51086060968180 + h -2.84455372522717 1.14124340617230 0.06329259736874 + o -0.40909736187775 3.75867850639247 0.06669599413407 + h -0.26209367627444 4.79211681613591 1.51095887544071 + h 1.14124151644616 2.84456128413170 -0.06333039189140 end structure=water5 -geometry -units angstrom - o -0.571270 2.322980 -0.003174 - o 2.038411 1.261129 -0.102281 - o 1.831197 -1.536089 0.156570 - o -0.890568 -2.217987 -0.100067 - o -2.398873 0.159801 -0.005022 - h -0.541626 2.994645 0.657473 - h 2.545757 1.390343 -0.886606 - h 2.127985 -1.971116 0.938635 - h -1.172378 -2.646489 -0.891417 - h -3.019733 0.318743 0.686131 - h 0.319714 1.986524 -0.080413 - h 2.008500 0.316696 0.040400 - h 0.922213 -1.803155 0.031130 - h -1.429035 -1.432872 -0.018620 - h -1.832579 0.928012 -0.044919 +geometry + o -1.07954384793358 4.38979601217069 -0.00599799074578 + o 3.85203853626156 2.38318842823994 -0.19328307859768 + o 3.46046082536179 -2.90278752573817 0.29587442062591 + o -1.68292962271170 -4.19138799630063 -0.18909922493947 + o -4.53321299757378 0.30198012576126 -0.00949020463935 + h -1.02352480645032 5.65905891521533 1.24244390976672 + h 4.81078353087656 2.62736750077462 -1.67544252777321 + h 4.02130886488866 -3.72486941614902 1.77376308874112 + h -2.21547334422020 -5.00113942369439 -1.68453400019852 + h -5.70646836443716 0.60233697677437 1.29659968128296 + h 0.60417190084940 3.75398631640452 -0.15195854752373 + h 3.79551493790081 0.59846870738035 0.07634493576858 + h 1.74273000618687 -3.40746912514341 0.05882717451673 + h -2.70048478430824 -2.70773566348012 -0.03518670059433 + h -3.46307242687744 1.75368852803147 -0.08488460816309 end From 2e9393e52b720566768edcc4ca8d5a7916d645ae Mon Sep 17 00:00:00 2001 From: fbischoff Date: Wed, 21 Feb 2024 13:28:30 +0100 Subject: [PATCH 095/109] clearer output, faster EF term in MP3 --- src/apps/cc2/cc2.cc | 7 +- src/madness/chem/CC2.cc | 25 ++++--- src/madness/chem/CCPotentials.cc | 17 ++--- src/madness/chem/ccpairfunction.cc | 2 +- src/madness/chem/mp3.cc | 103 +++++++++++++++++++++++++---- src/madness/chem/mp3.h | 1 + src/madness/mra/vmra.h | 2 +- 7 files changed, 121 insertions(+), 36 deletions(-) diff --git a/src/apps/cc2/cc2.cc b/src/apps/cc2/cc2.cc index 50b03add557..79f7d3864b7 100644 --- a/src/apps/cc2/cc2.cc +++ b/src/apps/cc2/cc2.cc @@ -93,13 +93,10 @@ int main(int argc, char **argv) { calc->param.print("dft","end"); print("\n"); cc2.tdhf->get_parameters().print("response","end"); + print("\n"); + nemo->molecule().print(); } double hf_energy = nemo->value(); - if (world.rank() == 0) - std::cout << "\n\n\n\n\n\n Reference Calculation Ended\n SCF Energy is: " << hf_energy - << "\n current wall-time: " << wall_time() - << "\n current cpu-time: " << cpu_time() << "\n\n\n"; - cc2.solve(); if (world.rank() == 0) printf("\nfinished at time %.1fs\n\n", wall_time()); diff --git a/src/madness/chem/CC2.cc b/src/madness/chem/CC2.cc index ca7f0de4918..1ce5e797cf5 100644 --- a/src/madness/chem/CC2.cc +++ b/src/madness/chem/CC2.cc @@ -359,7 +359,7 @@ Tensor CC2::enforce_core_valence_separation(const Tensor& fmat) } MADNESS_CHECK(Localizer::check_core_valence_separation(fock2,lmo.get_localize_sets())); - if (world.rank()==0) lmo.pretty_print("localized MOs"); + // if (world.rank()==0) lmo.pretty_print("localized MOs"); return fock2; }; @@ -408,7 +408,7 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { } } else { - if (world.rank()==0) print("Starting MP2 constant part calculation"); + if (world.rank()==0) print_header3("Starting MP2 constant part calculation"); // calc constant part via taskq auto taskq = std::shared_ptr(new MacroTaskQ(world, world.size())); taskq->set_printlevel(3); @@ -432,7 +432,11 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { pair_vec[i].function().truncate().reduce_rank(); save(pair_vec[i].constant_part, pair_vec[i].name() + "_const"); // save(pair_vec[i].function(), pair_vec[i].name()); - if (pair_vec[i].type == GROUND_STATE) total_energy += CCOPS.compute_pair_correlation_energy(pair_vec[i]); + if (pair_vec[i].type == GROUND_STATE) { + double energy = CCOPS.compute_pair_correlation_energy(pair_vec[i]); + if (world.rank()==0) printf("pair energy for pair %zu %zu: %12.8f\n", pair_vec[i].i, pair_vec[i].j, energy); + total_energy += energy; + } } if (world.rank()==0) { printf("current decoupled mp2 energy %12.8f\n", total_energy); @@ -441,19 +445,19 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { } + print_header3("Starting updating MP2 pairs"); + // create new pairs structure Pairs updated_pairs; - for (auto& tmp_pair : pair_vec) { - updated_pairs.insert(tmp_pair.i, tmp_pair.j, tmp_pair); - } + for (auto& tmp_pair : pair_vec) updated_pairs.insert(tmp_pair.i, tmp_pair.j, tmp_pair); auto solver= nonlinear_vector_solver(world,pair_vec.size()); solver.set_maxsub(parameters.kain_subspace()); solver.do_print = (world.rank() == 0); + for (size_t iter = 0; iter < parameters.iter_max_6D(); iter++) { -// if (world.rank()==0) std::cout << std::fixed << std::setprecision(1) << "\nStarting coupling at time " << wall_time() << std::endl; // compute the coupling between the pair functions Pairs coupling=compute_local_coupling(updated_pairs); auto coupling_vec=Pairs::pairs2vector(coupling,triangular_map); @@ -462,7 +466,6 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { double old_energy = total_energy; total_energy = 0.0; - if (world.rank()==0) std::cout << std::fixed << std::setprecision(1) << "\nStarting pairs update at time " << wall_time() << std::endl; // calc update for pairs via macrotask auto taskq = std::shared_ptr(new MacroTaskQ(world, world.size())); taskq->set_printlevel(3); @@ -504,7 +507,11 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { save(pair_vec[i].function(), pair_vec[i].name()); double energy = 0.0; - if (pair_vec[i].type == GROUND_STATE) energy = CCOPS.compute_pair_correlation_energy(pair_vec[i]); + if (pair_vec[i].type == GROUND_STATE) { + double energy = CCOPS.compute_pair_correlation_energy(pair_vec[i]); + if (world.rank()==0) printf("pair energy for pair %zu %zu: %12.8f\n", pair_vec[i].i, pair_vec[i].j, energy); + total_energy += energy; + } total_energy += energy; } diff --git a/src/madness/chem/CCPotentials.cc b/src/madness/chem/CCPotentials.cc index 09a95aa2d0e..64f7b3d7f52 100644 --- a/src/madness/chem/CCPotentials.cc +++ b/src/madness/chem/CCPotentials.cc @@ -315,7 +315,8 @@ CCPotentials::compute_pair_correlation_energy(const CCPair& u, const CC_vecfunct MADNESS_ASSERT(u.type == GROUND_STATE); if (singles.functions.empty()) MADNESS_ASSERT(u.ctype == CT_MP2); - output("Compute pair-correlation energy of pair " + u.name()); + const bool print_details=(world.rank()==0 and parameters.debug()); + if (parameters.debug()) output("Compute pair-correlation energy of pair " + u.name()); double result = 0.0; const CCFunction& mobi = mo_bra_(u.i); const CCFunction& mobj = mo_bra_(u.j); @@ -332,7 +333,7 @@ CCPotentials::compute_pair_correlation_energy(const CCPair& u, const CC_vecfunct tmp = 2.0 * (2.0 * part1 - part2); // non symmetric pairs -> offdiagonal -> count twice } result += tmp; - if (world.rank() == 0) + if (print_details) std::cout << std::setfill(' ') << std::setw(15) << "from " + u.functions[mm].name() + "=" << std::setfill(' ') << std::fixed << std::setprecision(10) << tmp << "\n"; } @@ -340,15 +341,15 @@ CCPotentials::compute_pair_correlation_energy(const CCPair& u, const CC_vecfunct MADNESS_ASSERT(singles.type == PARTICLE); const double omega_s = 2.0 * mobi.inner((*g12)(mobj, singles(u.j)) * singles(u.i).function) - mobi.inner((*g12)(mobj, singles(u.i)) * singles(u.j).function); - if (world.rank() == 0) + if (print_details) std::cout << std::setw(15) << "from singles=" << std::setfill(' ') << std::fixed << std::setprecision(10) << omega_s << "\n\n"; result += omega_s; } - if (world.rank() == 0) std::cout << "------------\n" << std::fixed << std::setprecision(10) << result << "\n\n"; + // if (world.rank() == 0) std::cout << "------------\n" << std::fixed << std::setprecision(10) << result << "\n\n"; - timer.info(); + timer.info(parameters.debug()); return result; } @@ -705,7 +706,7 @@ CCPotentials::make_constant_part_mp2_macrotask(World& world, const CCPair& pair, parameters.lo(), parameters.thresh_bsh_6D()); Gscreen.modified() = true; - print("Calculating Constant Part of MP2 pair " + i_name + j_name); + print("\nCalculating Constant Part of MP2 pair " + i_name + j_name); CCTimer time(world, "Calculating Constant Part of MP2"); MADNESS_ASSERT(i_type == HOLE); MADNESS_ASSERT(j_type == HOLE); @@ -1447,7 +1448,7 @@ CCPotentials::apply_Vreg_macrotask(World& world, const std::vector\n"); + // print("Applying Vreg to |" + x_name + y_name + ">\n"); CCTimer timer(world, "Vreg|" + x_name + y_name + ">"); //CCTimer time_f(world, "F-Part"); //const real_function_6d F_part = apply_reduced_F(ti, tj, Gscreen); @@ -1601,7 +1602,7 @@ CCPotentials::apply_transformed_Ue_macrotask(World& world, const std::vector\n"); + if (parameters.debug()) print("Computing Ue|" + x_name + y_name + ">"); real_function_3d x_function=mo_ket[i]; real_function_3d y_function=mo_ket[j]; diff --git a/src/madness/chem/ccpairfunction.cc b/src/madness/chem/ccpairfunction.cc index f0f1dbc9a49..ac4c8799978 100644 --- a/src/madness/chem/ccpairfunction.cc +++ b/src/madness/chem/ccpairfunction.cc @@ -141,7 +141,7 @@ std::vector> CCPairFunction::collect_same_types(c if (op_pure[opint].size()>1) { // Function tmp=CompositeFactory(world).ket(op_pure[opint]); // tmp.fill_tree(); - Tensor c(1,op_pure[opint].size()); + Tensor c(op_pure[opint].size(),1); c=1.0; Function tmp=transform_reconstructed(world, op_pure[opint],c,true)[0]; result.push_back(CCPairFunction(op,tmp)); diff --git a/src/madness/chem/mp3.cc b/src/madness/chem/mp3.cc index f030a592719..49dc3c57f76 100644 --- a/src/madness/chem/mp3.cc +++ b/src/madness/chem/mp3.cc @@ -216,8 +216,6 @@ double MP3::compute_mp3_ef_with_permutational_symmetry(const Pairs& mp2p for (const auto& p:perms) all_tau_permutations.push_back(p); const double weight=perms.size(); - print("ij, i, j, k, l",ij," -- ", i,j,k,l," - ",perms.size(),perms); - // terms C+D = (2* - ) // = (2*(ik|jl) - (jk|il)) double ovlp=inner(clusterfunctions(i,j),clusterfunctions(k,l),R2); @@ -247,6 +245,72 @@ double MP3::compute_mp3_ef_with_permutational_symmetry(const Pairs& mp2p return result; }; +double MP3::compute_mp3_ef_low_scaling(const Pairs& mp2pairs, + const Pairs>> clusterfunctions) const { + + print_header3("computing term EF of the MP3 energy with R2_bra, low-scaling version"); + + std::size_t nocc=mo_ket().size(); + std::size_t nfrozen=parameters.freeze(); + + const auto& R2=nemo_->R_square; + double result=0.0; + const std::vector& nemo_orbital=mo_ket().get_vecfunction(); + const std::vector& R2_orbital=mo_bra().get_vecfunction(); + + CCConvolutionOperator::Parameters cparam; + auto g12=CCConvolutionOperatorPtr(world,OpType::OT_G12,cparam); + + // number of pairs + auto npair = [&nocc, &nfrozen]() { return (nocc - nfrozen) * (nocc - nfrozen + 1) / 2; }; + + // turn composite index ij into i and j, taking care of frozen orbitals + PairVectorMap map=PairVectorMap::triangular_map(nfrozen,nocc); + auto ij_to_i_and_j = [&map](const int ij) { return map.map[ij]; }; + + timer timer_sum(world); + timer_sum.interrupt(); + timer timer_inner(world); + timer_inner.interrupt(); + + /// = (ik | jl) + std::vector all_tau_permutations; + // loop over unique pairs (ij) + for (int i=nfrozen; i> sigma; + for (int k=nfrozen; k& mp2pairs) const { @@ -395,10 +459,10 @@ double MP3::compute_mp3_klmn_fast(const Pairs& mp2pairs) const { multiply_KLMN.resume(); std::vector> rhs; for (int k = parameters.freeze(); k < nocc; ++k) { - rhs += 4.0 * multiply(clusterfunctions(i, k), gij(k, j), {3, 4, 5}); // K - rhs += 4.0 * multiply(clusterfunctions(k, j), gij(k, i), {3, 4, 5}); // L - rhs += -2.0 * multiply(clusterfunctions(j, k), gij(k, i), {0, 1, 2}); // M - rhs += -2.0 * multiply(clusterfunctions(k, i), gij(k, j), {0, 1, 2}); // N + rhs += +2.0 * multiply(clusterfunctions(j, k), gij(k, i), {0, 1, 2}); // M + rhs += +2.0 * multiply(clusterfunctions(k, i), gij(k, j), {0, 1, 2}); // N + rhs += -4.0 * multiply(clusterfunctions(i, k), gij(k, j), {3, 4, 5}); // K + rhs += -4.0 * multiply(clusterfunctions(k, j), gij(k, i), {3, 4, 5}); // L } rhs = consolidate(rhs, {}); multiply_KLMN.interrupt(); @@ -508,18 +572,33 @@ double MP3::mp3_energy_contribution(const Pairs& mp2pairs) const { // std::vector R2_orbital=mo_bra().get_vecfunction(); // const int nocc=mo_ket().size(); + std::size_t nocc=mo_ket().size(); + typedef std::vector> ClusterFunction; + Pairs clusterfunctions; + for (int i = parameters.freeze(); i < nocc; ++i) { + for (int j = i; j < nocc; ++j) { + clusterfunctions(i,j)=mp2pairs(i,j).functions; + if (i!=j) { + for (const auto& t : clusterfunctions(i,j)) { + clusterfunctions(j, i).push_back(t.swap_particles()); + } + } + } + } + double term_CD=0.0, term_EF=0.0, term_GHIJ=0.0, term_KLMN=0.0; timer t2(world); - // term_CD=compute_mp3_cd(mp2pairs); - t2.tag("CD term"); // term_EF=compute_mp3_ef_with_permutational_symmetry(mp2pairs); - t2.tag("EF term"); - // term_GHIJ=compute_mp3_ghij(mp2pairs); + term_EF=compute_mp3_ef_low_scaling(mp2pairs,clusterfunctions); + t2.tag("EF term, low scaling"); + term_CD=compute_mp3_cd(mp2pairs); + t2.tag("CD term"); + term_GHIJ=compute_mp3_ghij(mp2pairs); t2.tag("GHIJ term"); term_KLMN=compute_mp3_klmn_fast(mp2pairs); t2.tag("KLMN term fast"); - term_KLMN=compute_mp3_klmn(mp2pairs); - t2.tag("KLMN term"); + // term_KLMN=compute_mp3_klmn(mp2pairs); + // t2.tag("KLMN term"); printf("term_CD %12.8f\n",term_CD); printf("term_GHIJ %12.8f\n",term_GHIJ); diff --git a/src/madness/chem/mp3.h b/src/madness/chem/mp3.h index b50b558ebf2..2fc463308b4 100644 --- a/src/madness/chem/mp3.h +++ b/src/madness/chem/mp3.h @@ -29,6 +29,7 @@ class MP3 : public CCPotentials { double compute_mp3_cd(const Pairs& mp2pairs) const; double compute_mp3_ef(const Pairs& mp2pairs) const; double compute_mp3_ef_with_permutational_symmetry(const Pairs& mp2pairs) const; + double compute_mp3_ef_low_scaling(const Pairs& mp2pairs, const Pairs>> clusterfunctions) const; double compute_mp3_ghij(const Pairs& mp2pairs) const; double compute_mp3_klmn(const Pairs& mp2pairs) const; double compute_mp3_klmn_fast(const Pairs& mp2pairs) const; diff --git a/src/madness/mra/vmra.h b/src/madness/mra/vmra.h index 93950ca49af..7b0a2d1512e 100644 --- a/src/madness/mra/vmra.h +++ b/src/madness/mra/vmra.h @@ -724,7 +724,7 @@ namespace madness { typedef TENSOR_RESULT_TYPE(T,R) resultT; int n = v.size(); // n is the old dimension int m = c.dim(1); // m is the new dimension - MADNESS_ASSERT(n==c.dim(0)); + MADNESS_CHECK(n==c.dim(0)); // if we fence set the right tree state here, otherwise it has to be correct from the start. if (fence) change_tree_state(v,reconstructed); From 72e4ef509b4a72c6ede44130d1b2833ef2d53703 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Sun, 25 Feb 2024 22:28:29 +0100 Subject: [PATCH 096/109] fixing merge/accumulate trees, trying to remove linear dependencies from ccpairfunction --- src/madness/chem/ccpairfunction.cc | 41 ++++++++++++++++++++++++- src/madness/chem/ccpairfunction.h | 4 +++ src/madness/chem/mp3.cc | 2 +- src/madness/chem/test_ccpairfunction.cc | 19 ++++++++++++ src/madness/mra/funcimpl.h | 39 +++++++++++++++++++++++ src/madness/mra/vmra.h | 11 ++++--- 6 files changed, 109 insertions(+), 7 deletions(-) diff --git a/src/madness/chem/ccpairfunction.cc b/src/madness/chem/ccpairfunction.cc index ac4c8799978..7dc66caa9f1 100644 --- a/src/madness/chem/ccpairfunction.cc +++ b/src/madness/chem/ccpairfunction.cc @@ -105,6 +105,44 @@ std::vector> CCPairFunction::op_dec_to_dec(const } +/// turn decomposed functions with operator into decomposed functions using LowRankFunction +template +std::vector> CCPairFunction::remove_linearly_dependent_terms(const std::vector>& other, + double thresh) { + if (thresh<0.0) thresh=FunctionDefaults<3>::get_thresh()*0.1; + std::vector> result; + for (const auto& c : other) { + if (c.is_pure()) result.push_back(c); + else if (c.is_decomposed()) { + + LowRankFunction lrf(c.get_a(),c.get_b(),thresh,"canonical"); + lrf.reorthonormalize(); + result.push_back(CCPairFunction(c.get_operator_ptr(),lrf.get_g(),lrf.get_h())); + + +// auto a=c.get_a(); +// auto b=c.get_b(); +// auto ovlp=matrix_inner(c.world(),a,b); +// auto [U,s,VT]=svd(ovlp); +// // truncate the singular values +// auto n=0; +// for (int i=0; ithresh) n++; +// if (n n-1 +// U=U(_,Slice(0,n-1)); +// VT=VT(Slice(0,n-1),_); +// } +// auto UU=transform(c.world(),a,U); +// auto VVT=transform(c.world(),b,transpose(VT)); +// result.push_back(CCPairFunction(c.get_operator_ptr(),UU,VVT)); + } else { + MADNESS_EXCEPTION("you should not be here",1); + } + } + + return result; +} + /// collect all terms with of similiar type: pure, op_pure, decomposed, op_decomposed template std::vector> CCPairFunction::collect_same_types(const std::vector>& other) { @@ -186,10 +224,11 @@ std::vector> CCPairFunction::consolidate(const st // convert op_dec functions to dec (via LowRankFunctions bool op_dec_to_dec=find(options.begin(),options.end(),"op_dec_to_dec")!=options.end(); // reorthogonalize decomposed functions and op_decomposed functions - bool svd=find(options.begin(),options.end(),"svd")!=options.end(); + bool lindep=find(options.begin(),options.end(),"remove_lindep")!=options.end(); // always collect all terms of the same type auto result= is_collected(other) ? other : collect_same_types(other); + if (lindep) result=CCPairFunction::remove_linearly_dependent_terms(result); if (op_dec_to_dec) result=CCPairFunction::op_dec_to_dec(result); if (op_pure_to_pure) result=CCPairFunction::op_pure_to_pure(result); diff --git a/src/madness/chem/ccpairfunction.h b/src/madness/chem/ccpairfunction.h index a8ca0c83471..9dba2193634 100644 --- a/src/madness/chem/ccpairfunction.h +++ b/src/madness/chem/ccpairfunction.h @@ -409,6 +409,10 @@ using pureT=Function; /// turn pure functions with operator into pure functions without operators static std::vector op_pure_to_pure(const std::vector& other); + /// remove linear dependent terms in the low-rank parts + static std::vector remove_linearly_dependent_terms(const std::vector& other, + double thresh=-1.0); + static std::vector collect_same_types(const std::vector& other); public: diff --git a/src/madness/chem/mp3.cc b/src/madness/chem/mp3.cc index 49dc3c57f76..06ccd850e7f 100644 --- a/src/madness/chem/mp3.cc +++ b/src/madness/chem/mp3.cc @@ -294,7 +294,7 @@ double MP3::compute_mp3_ef_low_scaling(const Pairs& mp2pairs, sigma+=g_ijkl*clusterfunctions(k,l); } } - sigma=consolidate(sigma,{}); + sigma=consolidate(sigma,{"remove_lindep"}); timer_sum.interrupt(); timer_inner.resume(); double tmp=inner(clusterfunctions(i,j),sigma,R2); diff --git a/src/madness/chem/test_ccpairfunction.cc b/src/madness/chem/test_ccpairfunction.cc index d3762c7161b..5e8d2955a38 100644 --- a/src/madness/chem/test_ccpairfunction.cc +++ b/src/madness/chem/test_ccpairfunction.cc @@ -791,6 +791,25 @@ int test_consolidate(World& world, std::shared_ptr ncf t1.checkpoint(r0,r1,FunctionDefaults::get_thresh(),"correct numbers"); } + // remove linear dependencies + for (const auto& p : {p3}) { + auto tmp=std::vector>({p}); + tmp+=tmp; + t1.checkpoint(tmp.size()==1,"correct number of terms"); + t1.checkpoint(tmp.front().get_a().size()==2,"correct number of vectors in a"); + t1.checkpoint(tmp.front().is_op_decomposed(),"correct initial type: op_decomposed"); + auto tmp1=consolidate(tmp,{"remove_lindep"}); + t1.checkpoint(tmp1.front().is_decomposed(),"correct final type: decomposed"); + t1.checkpoint(tmp1.size()==1,"correct number of terms"); + t1.checkpoint(tmp1.front().get_a().size()==2,"correct number of vectors in a"); + + double r0=2*inner(p,{p1}); + double r1=inner(tmp,{p1}); + t1.checkpoint(r0,r1,FunctionDefaults::get_thresh(),"correct numbers"); + } + + + // some random composition of the above // a vector of numerically identical terms is created, then a random permutation is applied, and the result is checked for (int i=0; i<5; ++i) { diff --git a/src/madness/mra/funcimpl.h b/src/madness/mra/funcimpl.h index 2e5216edb1e..4282d2472a7 100644 --- a/src/madness/mra/funcimpl.h +++ b/src/madness/mra/funcimpl.h @@ -1151,6 +1151,15 @@ template if (fence) world.gop.fence(); } + /// merge the trees of this and other, while multiplying them with the alpha or beta, resp + + /// result and rhs do not have to have the same distribution or live in the same world + /// result+=alpha* this + /// @param[in] alpha prefactor for this + template + void accumulate_trees(FunctionImpl& result, const R alpha, const bool fence=true) const { + flo_unary_op_node_inplace(do_accumulate_trees(result,alpha),fence); + } /// perform: this= alpha*f + beta*g, invoked by result @@ -2338,6 +2347,36 @@ template }; + /// merge the coefficent boxes of this into result's tree + + /// result+= alpha*this + /// this and result don't have to have the same distribution or live in the same world + /// no comm, and the tree should be in an consistent state by virtue + template + struct do_accumulate_trees{ + typedef Range rangeT; + FunctionImpl* result=0; + T alpha=T(1.0); + do_accumulate_trees() = default; + do_accumulate_trees(FunctionImpl& result, const T alpha) + : result(&result), alpha(alpha) {} + + /// return the norm of the difference of this node and its "mirror" node + bool operator()(typename rangeT::iterator& it) const { + + const keyT& key = it->first; + const nodeT& node = it->second; + if (node.has_coeff()) result->get_coeffs().task(key, &nodeT::accumulate, + alpha*node.coeff(), result->get_coeffs(), key, result->targs); + return true; + } + + template void serialize(const Archive& ar) { + MADNESS_EXCEPTION("no serialization of do_accumulate_trees",1); + } + }; + + /// merge the coefficent boxes of this into other's tree /// no comm, and the tree should be in an consistent state by virtue diff --git a/src/madness/mra/vmra.h b/src/madness/mra/vmra.h index 7b0a2d1512e..037f0b2cf25 100644 --- a/src/madness/mra/vmra.h +++ b/src/madness/mra/vmra.h @@ -731,22 +731,23 @@ namespace madness { for (const auto& vv : v) MADNESS_CHECK_THROW( vv.get_impl()->get_tree_state()==reconstructed,"trees have to be reconstructed in transform_reconstructed"); - std::vector< Function > vc = zero_functions(world, m); + std::vector< Function > result = zero_functions(world, m); for (int i=0; iset_tree_state(redundant_after_merge); + result[i].get_impl()->set_tree_state(redundant_after_merge); for (int j=0; jmerge_trees(resultT(1.0),*v[j].get_impl(),resultT(c(j,i)),false); + if (c(j,i) != R(0.0)) v[j].get_impl()->accumulate_trees(*(result[i].get_impl()),resultT(c(j,i)),true); } } // if we fence we can as well finish the job here. Otherwise no harm done, as the tree state is well-defined. if (fence) { world.gop.fence(); - for (auto& r : vc) r.sum_down(false); + // for (auto& r : vc) r.sum_down(false); + for (auto& r : result) r.get_impl()->finalize_sum(); world.gop.fence(); } - return vc; + return result; } /// this version of transform uses Function::vtransform and screens From 4a54d2763629447f6e427f8b7ec61679976df4fb Mon Sep 17 00:00:00 2001 From: fbischoff Date: Sat, 9 Mar 2024 23:06:55 +0100 Subject: [PATCH 097/109] combining permutational symmetry with low-scaling in EF term --- src/madness/chem/CC2.cc | 2 +- src/madness/chem/lowrankfunction.h | 31 +++++++++++++++++++--- src/madness/chem/mp3.cc | 26 +++++++++++++----- src/madness/chem/test_low_rank_function.cc | 8 ++++++ 4 files changed, 55 insertions(+), 12 deletions(-) diff --git a/src/madness/chem/CC2.cc b/src/madness/chem/CC2.cc index 1ce5e797cf5..c8d24835f9c 100644 --- a/src/madness/chem/CC2.cc +++ b/src/madness/chem/CC2.cc @@ -60,7 +60,7 @@ CC2::solve() { if (need_mp2) { bool restarted=initialize_pairs(mp2pairs, GROUND_STATE, CT_MP2, CC_vecfunction(PARTICLE), CC_vecfunction(RESPONSE), 0); if (restarted and parameters.no_compute_mp2()) { - for (auto& pair : mp2pairs.allpairs) mp2_energy+=CCOPS.compute_pair_correlation_energy(pair.second); +// for (auto& pair : mp2pairs.allpairs) mp2_energy+=CCOPS.compute_pair_correlation_energy(pair.second); } else { mp2_energy = solve_mp2_coupled(mp2pairs); } diff --git a/src/madness/chem/lowrankfunction.h b/src/madness/chem/lowrankfunction.h index 54390dc4914..a646f7bf270 100644 --- a/src/madness/chem/lowrankfunction.h +++ b/src/madness/chem/lowrankfunction.h @@ -643,10 +643,33 @@ struct LRFunctorPure : public LRFunctorBase { Tensor ovlp_h = matrix_inner(world, h, h); auto [eval_g, evec_g] = syev(ovlp_g); auto [eval_h, evec_h] = syev(ovlp_h); - Tensor Xplus=copy(evec_g); - Tensor Xminus=copy(evec_g); - Tensor Yplus=copy(evec_h); - Tensor Yminus=copy(evec_h); + + // get relevant part of the eigenvalues and eigenvectors + // eigenvalues are sorted in ascending order + auto get_slice = [](auto eval, double thresh) { + // remove small/negative eigenvalues + eval.screen(thresh); + Slice s; + for (int i=0; i=0.0,"negative eigenvalues in reorthonormalize"); + if (eval[i]>thresh) { + return s=Slice(i,-1); // from i to the end + break; + } + } + return s; + }; + + Slice gslice=get_slice(eval_g,1.e-14); + Slice hslice=get_slice(eval_h,1.e-14); + + Tensor Xplus=copy(evec_g(_,gslice)); + Tensor Xminus=copy(evec_g(_,gslice)); + Tensor Yplus=copy(evec_h(_,hslice)); + Tensor Yminus=copy(evec_h(_,hslice)); + eval_g=copy(eval_g(gslice)); + eval_h=copy(eval_h(hslice)); + for (int i=0; i& mp2p for (int ij=0; ij> tmp_tau; // loop over all k and l for (int k=nfrozen; k& mp2p // terms C+D = (2* - ) // = (2*(ik|jl) - (jk|il)) - double ovlp=inner(clusterfunctions(i,j),clusterfunctions(k,l),R2); const auto& ket_i=nemo_orbital[i]; const auto& ket_k=nemo_orbital[k]; const auto& ket_l=nemo_orbital[l]; @@ -227,9 +227,13 @@ double MP3::compute_mp3_ef_with_permutational_symmetry(const Pairs& mp2p const auto& bra_l=R2_orbital[l]; double g_ikjl=inner(bra_i*ket_k, (*g12)(bra_j*ket_l)); double g_jkil=inner(bra_j*ket_k, (*g12)(bra_l*ket_i)); - tmp+=weight*ovlp*(2.0* g_ikjl - g_jkil); + // double ovlp=inner(clusterfunctions(i,j),clusterfunctions(k,l),R2); + tmp_tau+=weight*(2.0* g_ikjl - g_jkil)*clusterfunctions(k,l); + // tmp+=weight*ovlp*(2.0* g_ikjl - g_jkil); } } + tmp_tau=consolidate(tmp_tau,{"remove_lindep"}); + tmp=inner(clusterfunctions(i,j),tmp_tau,R2); printf("mp3 energy: term_EF %2d %2d %12.8f\n",i,j,tmp); result+=tmp; } @@ -272,6 +276,8 @@ double MP3::compute_mp3_ef_low_scaling(const Pairs& mp2pairs, timer_sum.interrupt(); timer timer_inner(world); timer_inner.interrupt(); + timer timer_consolidate(world); + timer_consolidate.interrupt(); /// = (ik | jl) std::vector all_tau_permutations; @@ -294,8 +300,10 @@ double MP3::compute_mp3_ef_low_scaling(const Pairs& mp2pairs, sigma+=g_ijkl*clusterfunctions(k,l); } } - sigma=consolidate(sigma,{"remove_lindep"}); timer_sum.interrupt(); + timer_consolidate.resume(); + sigma=consolidate(sigma,{"remove_lindep"}); + timer_consolidate.interrupt(); timer_inner.resume(); double tmp=inner(clusterfunctions(i,j),sigma,R2); printf("mp3 energy: term_EF %2d %2d %12.8f\n",i,j,tmp); @@ -304,7 +312,8 @@ double MP3::compute_mp3_ef_low_scaling(const Pairs& mp2pairs, } } - timer_sum.print("summation/consolidation in EF term"); + timer_sum.print("summation in EF term"); + timer_consolidate.print("consolidation in EF term"); timer_inner.print("inner in EF term"); printf("MP3 energy: term_EF %12.8f\n",result); return result; @@ -588,9 +597,12 @@ double MP3::mp3_energy_contribution(const Pairs& mp2pairs) const { double term_CD=0.0, term_EF=0.0, term_GHIJ=0.0, term_KLMN=0.0; timer t2(world); - // term_EF=compute_mp3_ef_with_permutational_symmetry(mp2pairs); - term_EF=compute_mp3_ef_low_scaling(mp2pairs,clusterfunctions); - t2.tag("EF term, low scaling"); + term_EF=compute_mp3_ef_with_permutational_symmetry(mp2pairs); + t2.tag("EF term, permutational symmetry"); + // term_EF=compute_mp3_ef_low_scaling(mp2pairs,clusterfunctions); + // t2.tag("EF term, low scaling"); + // term_EF=compute_mp3_ef(mp2pairs); + // t2.tag("EF term, naive implementation"); term_CD=compute_mp3_cd(mp2pairs); t2.tag("CD term"); term_GHIJ=compute_mp3_ghij(mp2pairs); diff --git a/src/madness/chem/test_low_rank_function.cc b/src/madness/chem/test_low_rank_function.cc index 12122c38368..22045f27a2f 100644 --- a/src/madness/chem/test_low_rank_function.cc +++ b/src/madness/chem/test_low_rank_function.cc @@ -691,6 +691,14 @@ int test_construction_optimization(World& world, LowRankFunctionParameters param error = lrf.l2error(lrfunctor); print("l2 error reorthonormalize", error); t1.checkpoint(error, tol, "l2 error in reorthonormalization"); + + lrf+=lrf; + lrf*=0.5; + lrf.reorthonormalize(); + error = lrf.l2error(lrfunctor); + print("l2 error reorthonormalize with lindep", error); + t1.checkpoint(error, tol, "l2 error in reorthonormalization with lindep"); + } return t1.end(); } From 30397e0e2a0c1add0963331129ffe3ad35f9152f Mon Sep 17 00:00:00 2001 From: fbischoff Date: Wed, 13 Mar 2024 15:53:23 +0100 Subject: [PATCH 098/109] update, GHIJ varies a lot depending on algorithm --- src/madness/chem/ccpairfunction.cc | 72 +++++++------- src/madness/chem/ccpairfunction.h | 19 +++- src/madness/chem/lowrankfunction.h | 12 ++- src/madness/chem/mp3.cc | 119 ++++++++++++++++-------- src/madness/chem/mp3.h | 4 +- src/madness/chem/test_ccpairfunction.cc | 24 ++++- 6 files changed, 166 insertions(+), 84 deletions(-) diff --git a/src/madness/chem/ccpairfunction.cc b/src/madness/chem/ccpairfunction.cc index 7dc66caa9f1..bd336bbc097 100644 --- a/src/madness/chem/ccpairfunction.cc +++ b/src/madness/chem/ccpairfunction.cc @@ -25,40 +25,27 @@ bool CCPairFunction::is_convertible_to_pure_no_op() const { const auto type=get_operator().type(); if (not (type==OpType::OT_SLATER or type==OpType::OT_F12)) return false; } - if (is_decomposed() and (get_a().size()>2)) return false; return true; }; template void CCPairFunction::convert_to_pure_no_op_inplace() { - pureT tmp; - pureT result=FunctionFactory(world()); + pureT result; if (is_pure_no_op()) { return; } else if (is_pure()) { - tmp= CompositeFactory(world()) + result= CompositeFactory(world()) .g12(get_operator().get_kernel()) .ket(get_function()); - tmp.fill_tree(); - result=tmp; } else if (is_decomposed()) { - MADNESS_CHECK_THROW(get_a().size()<3,"a.size not <3 in convert_to_pure_no_op_inplace"); - for (int i=0; i(world()) - .g12(get_operator().get_kernel()) - .particle1(get_a()[i]) - .particle2(get_b()[i]); - } else if (is_decomposed_no_op()) { - tmp= CompositeFactory(world()) - .particle1(get_a()[i]) - .particle2(get_b()[i]); - } - tmp.fill_tree(); - result+=tmp; - } + result= CompositeFactory(world()) + .g12(get_operator().get_kernel()) + .particle1(get_a()) + .particle2(get_b()); } + result.fill_tree(); + result.truncate(FunctionDefaults::get_thresh()*0.1); component.reset(new TwoBodyFunctionPureComponent(result)); }; @@ -78,7 +65,10 @@ std::vector> CCPairFunction::op_pure_to_pure(cons result.push_back(c); } } - if (pure.is_initialized()) result.push_back(CCPairFunction(pure)); + if (pure.is_initialized()) { + pure.truncate(FunctionDefaults::get_thresh()*0.1); + result.push_back(CCPairFunction(pure)); + } return result; } @@ -102,6 +92,23 @@ std::vector> CCPairFunction::op_dec_to_dec(const } } return result; +} + +/// turn decomposed functions with operator into pure functions +template +std::vector> CCPairFunction::op_dec_to_pure(const std::vector>& other) { + LowRankFunctionParameters lrparameters; + std::vector> result; + for (const auto& c : other) { + if (c.is_op_decomposed()) { + CCPairFunction tmp=copy(c); + tmp.convert_to_pure_no_op_inplace(); + result.push_back(tmp); + } else { + result.push_back(c); + } + } + return result; } @@ -119,22 +126,6 @@ std::vector> CCPairFunction::remove_linearly_depe lrf.reorthonormalize(); result.push_back(CCPairFunction(c.get_operator_ptr(),lrf.get_g(),lrf.get_h())); - -// auto a=c.get_a(); -// auto b=c.get_b(); -// auto ovlp=matrix_inner(c.world(),a,b); -// auto [U,s,VT]=svd(ovlp); -// // truncate the singular values -// auto n=0; -// for (int i=0; ithresh) n++; -// if (n n-1 -// U=U(_,Slice(0,n-1)); -// VT=VT(Slice(0,n-1),_); -// } -// auto UU=transform(c.world(),a,U); -// auto VVT=transform(c.world(),b,transpose(VT)); -// result.push_back(CCPairFunction(c.get_operator_ptr(),UU,VVT)); } else { MADNESS_EXCEPTION("you should not be here",1); } @@ -185,7 +176,7 @@ std::vector> CCPairFunction::collect_same_types(c result.push_back(CCPairFunction(op,tmp)); } else { MADNESS_CHECK_THROW(op_pure[opint].size()==1,"op_pure[opint].size()!=1"); - result.push_back(CCPairFunction(op,op_pure[opint].front())); + result.push_back(CCPairFunction(op,copy(op_pure[opint].front()))); } } if (op_decomposed_a[opint].size()>0) { @@ -223,6 +214,8 @@ std::vector> CCPairFunction::consolidate(const st bool op_pure_to_pure=find(options.begin(),options.end(),"op_pure_to_pure")!=options.end(); // convert op_dec functions to dec (via LowRankFunctions bool op_dec_to_dec=find(options.begin(),options.end(),"op_dec_to_dec")!=options.end(); + // convert op_dec functions to pure (via fill_tree) + bool op_dec_to_pure=find(options.begin(),options.end(),"op_dec_to_pure")!=options.end(); // reorthogonalize decomposed functions and op_decomposed functions bool lindep=find(options.begin(),options.end(),"remove_lindep")!=options.end(); @@ -231,6 +224,7 @@ std::vector> CCPairFunction::consolidate(const st if (lindep) result=CCPairFunction::remove_linearly_dependent_terms(result); if (op_dec_to_dec) result=CCPairFunction::op_dec_to_dec(result); + if (op_dec_to_pure) result=CCPairFunction::op_dec_to_pure(result); if (op_pure_to_pure) result=CCPairFunction::op_pure_to_pure(result); if (not is_collected(result)) result=collect_same_types(result); diff --git a/src/madness/chem/ccpairfunction.h b/src/madness/chem/ccpairfunction.h index 9dba2193634..dfad3e667ce 100644 --- a/src/madness/chem/ccpairfunction.h +++ b/src/madness/chem/ccpairfunction.h @@ -339,14 +339,14 @@ using pureT=Function; /// empty ctor CCPairFunction() = default; - /// takes a deep copy of the argument function + /// takes a shallow copy of the argument function explicit CCPairFunction(const Function& ket) { - component.reset(new TwoBodyFunctionPureComponent(copy(ket))); + component.reset(new TwoBodyFunctionPureComponent(ket)); } - /// takes a deep copy of the argument function + /// takes a shallow copy of the argument function explicit CCPairFunction(const std::shared_ptr> op_, const Function& ket) { - component.reset(new TwoBodyFunctionPureComponent(op_,copy(ket))); + component.reset(new TwoBodyFunctionPureComponent(op_,ket)); } /// takes a deep copy of the argument functions @@ -409,6 +409,9 @@ using pureT=Function; /// turn pure functions with operator into pure functions without operators static std::vector op_pure_to_pure(const std::vector& other); + /// turn decomposed functions with operator into pure functions without operators + static std::vector op_dec_to_pure(const std::vector& other); + /// remove linear dependent terms in the low-rank parts static std::vector remove_linearly_dependent_terms(const std::vector& other, double thresh=-1.0); @@ -423,6 +426,7 @@ using pureT=Function; /// @param[in] other: a vector of CCPairFunctions /// @param[in] options: a vector of strings which can be "one_term", "op_pure_to_pure", "svd" + /// TODO: implement a function for removing linearly dependent terms without orthonormalization friend std::vector consolidate(const std::vector& other, std::vector options={}) { @@ -884,6 +888,13 @@ std::vector >& operator+=(std::vector +std::vector >& operator-=(std::vector >& rhs, + const std::vector >& lhs) { + for (const auto& l : lhs) rhs.push_back(-1.0*l); + return rhs; +} + template std::vector > operator*(const double fac, const std::vector >& arg) { std::vector> result; diff --git a/src/madness/chem/lowrankfunction.h b/src/madness/chem/lowrankfunction.h index a646f7bf270..a26cb770c2d 100644 --- a/src/madness/chem/lowrankfunction.h +++ b/src/madness/chem/lowrankfunction.h @@ -628,6 +628,14 @@ struct LRFunctorPure : public LRFunctorBase { } } + /// remove linear dependencies without orthonormalization + void remove_linear_depdencies(double thresh=-1.0) { + + // use rank-revealing cholesky decomposition to remove linear dependencies + + + } + /// after external operations g might not be orthonormal and/or optimal -- reorthonormalize /// orthonormalization similar to Bischoff, Harrison, Valeev, JCP 137 104103 (2012), Sec II C 3 @@ -660,8 +668,8 @@ struct LRFunctorPure : public LRFunctorBase { return s; }; - Slice gslice=get_slice(eval_g,1.e-14); - Slice hslice=get_slice(eval_h,1.e-14); + Slice gslice=get_slice(eval_g,1.e-13); + Slice hslice=get_slice(eval_h,1.e-13); Tensor Xplus=copy(evec_g(_,gslice)); Tensor Xminus=copy(evec_g(_,gslice)); diff --git a/src/madness/chem/mp3.cc b/src/madness/chem/mp3.cc index aeb90397ecd..eecd5847e2f 100644 --- a/src/madness/chem/mp3.cc +++ b/src/madness/chem/mp3.cc @@ -237,6 +237,8 @@ double MP3::compute_mp3_ef_with_permutational_symmetry(const Pairs& mp2p printf("mp3 energy: term_EF %2d %2d %12.8f\n",i,j,tmp); result+=tmp; } + printf("MP3 energy: term_EF %12.8f\n",result); + // sanity check int npermutations=all_tau_permutations.size(); all_tau_permutations=permutation::remove_duplicates(all_tau_permutations); @@ -245,7 +247,6 @@ double MP3::compute_mp3_ef_with_permutational_symmetry(const Pairs& mp2p MADNESS_CHECK_THROW(npermutations==nuniquepermutations,"incorrect number of unique permutations"); MADNESS_CHECK_THROW(npermutations==ntotalpermutations,"incorrect number of unique permutations"); - printf("MP3 energy: term_EF %12.8f\n",result); return result; }; @@ -320,24 +321,12 @@ double MP3::compute_mp3_ef_low_scaling(const Pairs& mp2pairs, } - -double MP3::compute_mp3_ghij(const Pairs& mp2pairs) const { - +double MP3::compute_mp3_ghij(const Pairs& mp2pairs, + const Pairs>> clusterfunctions) const { + typedef std::vector> ClusterFunction; // prepare cluster functions std::size_t nocc=mo_ket().size(); - typedef std::vector> ClusterFunction; - Pairs clusterfunctions; - for (int i = parameters.freeze(); i < nocc; ++i) { - for (int j = i; j < nocc; ++j) { - clusterfunctions(i,j)=mp2pairs(i,j).functions; - if (i!=j) { - for (const auto& t : clusterfunctions(i,j)) { - clusterfunctions(j, i).push_back(t.swap_particles()); - } - } - } - } double result=0.0; const auto& R2=nemo_->R_square; @@ -365,15 +354,12 @@ double MP3::compute_mp3_ghij(const Pairs& mp2pairs) const { for (auto& t: tmp3) tau_ij_j[i].push_back(t); } } - print("info on tau_kk_i, consolidated with op_pure_to_pure"); + std::vector consolidation={"op_pure_to_pure","remove_lindep"}; + print("consolidating with ",consolidation); for (int i = parameters.freeze(); i < nocc; ++i) { - tau_kk_i[i] = consolidate(tau_kk_i[i], {"op_pure_to_pure", "op_dec_to_dec"}); - for (auto& c: tau_kk_i[i]) c.info(); - } - print("info on tau_ij_j, consolidated with op_pure_to_pure"); - for (int i = parameters.freeze(); i < nocc; ++i) { - tau_ij_j[i] = consolidate(tau_ij_j[i], {"op_pure_to_pure", "op_dec_to_dec"}); - for (auto& c: tau_ij_j[i]) c.info(); + tau_kk_i[i] = consolidate(tau_kk_i[i],consolidation); + tau_ij_j[i] = consolidate(tau_ij_j[i], consolidation); + // for (auto& c: tau_kk_i[i]) c.info(); } t2.tag("GHIJ term prep"); @@ -386,15 +372,11 @@ double MP3::compute_mp3_ghij(const Pairs& mp2pairs) const { g.set_particle(1); auto gtau_same = g(tau_kk_i[i]); t4.tag("compute gtau_same"); - // gtau_same=consolidate(gtau_same,{"op_pure_to_pure"}); - // t4.tag("consolidate gtau_same"); // tmp(1',2) = g(1',1) | tau_ij(1,2) j(1) > g.set_particle(1); auto gtau_other = g(tau_ij_j[i]); // < tau_ij(1,2) j(1) | g(1,1') | t4.tag("compute gtau_other"); - // gtau_other=consolidate(gtau_other,{"op_pure_to_pure"}); - // t4.tag("consolidate gtau_other"); auto bra_kk_i = multiply(tau_kk_i[i], R2, {3, 4, 5}); auto bra_ij_j = multiply(tau_ij_j[i], R2, {3, 4, 5}); @@ -421,6 +403,73 @@ double MP3::compute_mp3_ghij(const Pairs& mp2pairs) const { return result; }; + +double MP3::compute_mp3_ghij_fast(const Pairs& mp2pairs, const Pairs>> clusterfunctions) const { + + print_header3("entering compute_mp3_ghij_fast"); + + // prepare cluster functions + std::size_t nocc=mo_ket().size(); + typedef std::vector> ClusterFunction; + double result=0.0; + + const auto& R2=nemo_->R_square; + const std::vector& nemo_orbital=mo_ket().get_vecfunction(); + const std::vector& R2_orbital=mo_bra().get_vecfunction(); + + CCConvolutionOperator::Parameters cparam; + auto g12=CCConvolutionOperatorPtr(world,OpType::OT_G12,cparam); + + timer t2(world); + + // compute intermediates for terms G, I, H, and J + + // \sum_j tau_ij(1,2) * phi_j(2) + std::vector tau_kk_i(nocc); + // \sum_j tau_ij(1,2) * phi_j(1) + std::vector tau_ij_j(nocc); + + for (int i = parameters.freeze(); i < nocc; ++i) { + for (int j = parameters.freeze(); j < nocc; ++j) { + auto tmp2 = multiply(clusterfunctions(i, j), R2_orbital[i], {0, 1, 2}); + for (auto& t: tmp2) tau_kk_i[j].push_back(t); + + auto tmp3 = multiply(clusterfunctions(i, j), R2_orbital[j], {0, 1, 2}); + for (auto& t: tmp3) tau_ij_j[i].push_back(t); + } + } + + std::vector consolidation={"op_pure_to_pure","remove_lindep","op_dec_to_pure"}; + print("consolidating with ",consolidation); + std::vector intermediate(nocc); + for (int i = parameters.freeze(); i < nocc; ++i) { + intermediate[i]=2.0*tau_kk_i[i]; + intermediate[i]-=tau_ij_j[i]; + intermediate[i]=consolidate(intermediate[i],consolidation); + } + + t2.tag("GHIJ term prep"); + + // terms G, I, H, J of Bartlett/Silver 1975 + real_convolution_3d& g = *(g12->get_op()); + g.set_particle(1); + for (int i = parameters.freeze(); i < nocc; ++i) { + // tmp(1,2) = g(1,1') | tau_ij(1',2) j(2) > + timer t4(world, "gtau"); + auto gintermediate = g(intermediate[i]); + t4.tag("compute gintermediate"); + auto bra_intermediate = multiply(intermediate[i], R2, {3, 4, 5}); + t4.tag("multiply"); + double tmp = 2.0*inner(bra_intermediate, gintermediate); + printf("mp3 energy: term_GHIJ %2d %12.8f\n", i, tmp); + t4.tag("inner"); + result += tmp; + } + printf("MP3 energy: term_GHIJ %12.8f\n", result); + t2.tag("GHIJ term"); + return result; +}; + double MP3::compute_mp3_klmn_fast(const Pairs& mp2pairs) const { // prepare cluster functions @@ -597,15 +646,11 @@ double MP3::mp3_energy_contribution(const Pairs& mp2pairs) const { double term_CD=0.0, term_EF=0.0, term_GHIJ=0.0, term_KLMN=0.0; timer t2(world); - term_EF=compute_mp3_ef_with_permutational_symmetry(mp2pairs); - t2.tag("EF term, permutational symmetry"); - // term_EF=compute_mp3_ef_low_scaling(mp2pairs,clusterfunctions); - // t2.tag("EF term, low scaling"); - // term_EF=compute_mp3_ef(mp2pairs); - // t2.tag("EF term, naive implementation"); - term_CD=compute_mp3_cd(mp2pairs); - t2.tag("CD term"); - term_GHIJ=compute_mp3_ghij(mp2pairs); +// term_EF=compute_mp3_ef_with_permutational_symmetry(mp2pairs); +// t2.tag("EF term, permutational symmetry"); +// term_CD=compute_mp3_cd(mp2pairs); +// t2.tag("CD term"); + term_GHIJ=compute_mp3_ghij_fast(mp2pairs,clusterfunctions); t2.tag("GHIJ term"); term_KLMN=compute_mp3_klmn_fast(mp2pairs); t2.tag("KLMN term fast"); diff --git a/src/madness/chem/mp3.h b/src/madness/chem/mp3.h index 2fc463308b4..ac2ca986c22 100644 --- a/src/madness/chem/mp3.h +++ b/src/madness/chem/mp3.h @@ -30,7 +30,9 @@ class MP3 : public CCPotentials { double compute_mp3_ef(const Pairs& mp2pairs) const; double compute_mp3_ef_with_permutational_symmetry(const Pairs& mp2pairs) const; double compute_mp3_ef_low_scaling(const Pairs& mp2pairs, const Pairs>> clusterfunctions) const; - double compute_mp3_ghij(const Pairs& mp2pairs) const; + double compute_mp3_ef_as_overlap(const Pairs& mp2pairs, const Pairs>> clusterfunctions) const; + double compute_mp3_ghij(const Pairs& mp2pairs, const Pairs>> clusterfunctions) const; + double compute_mp3_ghij_fast(const Pairs& mp2pairs, const Pairs>> clusterfunctions) const; double compute_mp3_klmn(const Pairs& mp2pairs) const; double compute_mp3_klmn_fast(const Pairs& mp2pairs) const; double mp3_energy_contribution(const Pairs& mp2pairs) const; diff --git a/src/madness/chem/test_ccpairfunction.cc b/src/madness/chem/test_ccpairfunction.cc index 5e8d2955a38..8cb1c209b78 100644 --- a/src/madness/chem/test_ccpairfunction.cc +++ b/src/madness/chem/test_ccpairfunction.cc @@ -121,7 +121,7 @@ struct data { CCPairFunction p2({f1,f2},{f2,f3}); CCPairFunction p3(f12_op,{f1,f2},{f2,f3}); CCPairFunction p4(f23); // two-term, corresponds to p2 - CCPairFunction p5(f12_op,f23); // two-term, corresponds to p2 + CCPairFunction p5(f12_op,copy(f23)); // two-term, corresponds to p2 return std::make_tuple(p1,p2,p3,p4,p5); } @@ -306,6 +306,12 @@ int test_transformations(World& world, std::shared_ptr auto f12=CCConvolutionOperatorPtr(world, OT_F12, parameter); auto g12=CCConvolutionOperatorPtr(world, OT_G12, parameter); + auto compute_diff_norm = [](const CCPairFunction& f1, const CCPairFunction f2) { + std::vector> diff; + diff+={f1}; + diff-={f2}; + return sqrt(inner(diff,diff)); + }; CCPairFunction p1(ff); t1.checkpoint(p1.is_pure(),"is_pure"); @@ -325,6 +331,7 @@ int test_transformations(World& world, std::shared_ptr t1.checkpoint(p4.is_op_pure(),"is_op_pure"); t1.checkpoint(not p4.is_convertible_to_pure_no_op(),"not is_convertible_to_pure_no_op"); + // convert f12 f1 f2 to pure_op_op CCPairFunction p5(f12,f1,f2); t1.checkpoint(not p5.is_pure(),"is_pure"); t1.checkpoint(p5.is_op_decomposed(),"is_op_decomposed"); @@ -332,6 +339,21 @@ int test_transformations(World& world, std::shared_ptr CCPairFunction p6=copy(p5); p6.convert_to_pure_no_op_inplace(); t1.checkpoint(p6.is_pure_no_op(),"is_pure_no_op"); + double d6=compute_diff_norm(p5,p6); + t1.checkpoint(d6,FunctionDefaults::get_thresh()*50,"numerics"); + + // convert \sum_i f12 f1_i f2_i to pure_op_op + CCPairFunction p7(f12,{f1,f2,f3},{f1,f2,f3}); + t1.checkpoint(not p7.is_pure(),"is_pure"); + t1.checkpoint(p7.is_op_decomposed(),"is_op_decomposed"); + t1.checkpoint(p7.is_convertible_to_pure_no_op(),"is_convertible_to_pure_no_op"); + CCPairFunction p8=copy(p7); + p8.convert_to_pure_no_op_inplace(); + t1.checkpoint(p8.is_pure_no_op(),"is_pure_no_op"); + double d8=compute_diff_norm(p7,p8); + t1.checkpoint(d8,FunctionDefaults::get_thresh()*50,"numerics"); + + return t1.end(); } From 6deba20cdbaf0bfe995621e762f4a0093d6cea24 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Fri, 15 Mar 2024 11:02:20 +0100 Subject: [PATCH 099/109] added some temporary consistency test --- src/madness/chem/mp3.cc | 53 ++++++++++++++++++++++++++++++++++------- src/madness/chem/mp3.h | 1 + 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/src/madness/chem/mp3.cc b/src/madness/chem/mp3.cc index eecd5847e2f..22d5a4e3d83 100644 --- a/src/madness/chem/mp3.cc +++ b/src/madness/chem/mp3.cc @@ -616,6 +616,41 @@ double MP3::compute_mp3_klmn(const Pairs& mp2pairs) const { }; +double MP3::mp3_test(const Pairs& mp2pairs, const Pairs>> clusterfunctions) const { + print_header2("entering mp3 test"); + + auto R2 = nemo_->ncf->square(); + const int nocc=mo_ket().size(); + std::vector nemo_orbital=mo_ket().get_vecfunction(); + std::vector R2_orbital=mo_bra().get_vecfunction(); + // std::vector nemo_orbital=mo_ket().get_vecfunction(); + std::vector> ij; + int i=1, j=1; + ij.push_back(CCPairFunction(nemo_orbital[i],nemo_orbital[j])); + CCConvolutionOperator::Parameters cparam; + auto g12=CCConvolutionOperatorPtr(world,OpType::OT_G12,cparam); + double eri=0.0; + for (int i=0; i> ii; + ii.push_back(CCPairFunction(nemo_orbital[i], nemo_orbital[j])); + double tmp = inner(ii, g12 * ii, R2); + print("eri for pair", i,j, tmp); + eri += tmp; + } + } + print("total eri",eri); + + print("eri(1,1)",eri); + double mp2_energy=inner(clusterfunctions(i,j),ij,R2); + print("mp2 energy for pair ", i, j, mp2_energy); + + double mp3_contrib=inner(clusterfunctions(i,j),clusterfunctions(i,j),R2); + print("",mp3_contrib); + + return 0.0; +} + double MP3::mp3_energy_contribution(const Pairs& mp2pairs) const { print_header2("computing the MP3 correlation energy"); @@ -630,6 +665,7 @@ double MP3::mp3_energy_contribution(const Pairs& mp2pairs) const { // std::vector R2_orbital=mo_bra().get_vecfunction(); // const int nocc=mo_ket().size(); + timer t2(world); std::size_t nocc=mo_ket().size(); typedef std::vector> ClusterFunction; Pairs clusterfunctions; @@ -644,18 +680,17 @@ double MP3::mp3_energy_contribution(const Pairs& mp2pairs) const { } } + t2.tag("make cluster functions"); + mp3_test(mp2pairs,clusterfunctions); double term_CD=0.0, term_EF=0.0, term_GHIJ=0.0, term_KLMN=0.0; - timer t2(world); -// term_EF=compute_mp3_ef_with_permutational_symmetry(mp2pairs); -// t2.tag("EF term, permutational symmetry"); -// term_CD=compute_mp3_cd(mp2pairs); -// t2.tag("CD term"); - term_GHIJ=compute_mp3_ghij_fast(mp2pairs,clusterfunctions); - t2.tag("GHIJ term"); term_KLMN=compute_mp3_klmn_fast(mp2pairs); t2.tag("KLMN term fast"); - // term_KLMN=compute_mp3_klmn(mp2pairs); - // t2.tag("KLMN term"); + term_GHIJ=compute_mp3_ghij_fast(mp2pairs,clusterfunctions); + t2.tag("GHIJ term"); + term_EF=compute_mp3_ef_with_permutational_symmetry(mp2pairs); + t2.tag("EF term, permutational symmetry"); + term_CD=compute_mp3_cd(mp2pairs); + t2.tag("CD term"); printf("term_CD %12.8f\n",term_CD); printf("term_GHIJ %12.8f\n",term_GHIJ); diff --git a/src/madness/chem/mp3.h b/src/madness/chem/mp3.h index ac2ca986c22..5e7974c294f 100644 --- a/src/madness/chem/mp3.h +++ b/src/madness/chem/mp3.h @@ -36,6 +36,7 @@ class MP3 : public CCPotentials { double compute_mp3_klmn(const Pairs& mp2pairs) const; double compute_mp3_klmn_fast(const Pairs& mp2pairs) const; double mp3_energy_contribution(const Pairs& mp2pairs) const; + double mp3_test(const Pairs& mp2pairs, const Pairs>> clusterfunctions) const; }; } From 45d375b92321374ab2693b9511843b718d4cc589 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Mon, 18 Mar 2024 10:11:43 +0100 Subject: [PATCH 100/109] added multiple centers for lowrankfunction, mp3 working correctly for h2o in 3e-4 econv --- src/madness/chem/ccpairfunction.cc | 12 +-- src/madness/chem/ccpairfunction.h | 12 ++- src/madness/chem/lowrankfunction.h | 99 +++++++++++++++++++--- src/madness/chem/mp3.cc | 9 +- src/madness/chem/test_low_rank_function.cc | 89 ++++++++++++++++++- 5 files changed, 194 insertions(+), 27 deletions(-) diff --git a/src/madness/chem/ccpairfunction.cc b/src/madness/chem/ccpairfunction.cc index bd336bbc097..2bda14f8558 100644 --- a/src/madness/chem/ccpairfunction.cc +++ b/src/madness/chem/ccpairfunction.cc @@ -74,9 +74,10 @@ std::vector> CCPairFunction::op_pure_to_pure(cons /// turn decomposed functions with operator into decomposed functions using LowRankFunction template -std::vector> CCPairFunction::op_dec_to_dec(const std::vector>& other) { +std::vector> CCPairFunction::op_dec_to_dec(const std::vector>& other, + const std::vector::LDIM>>& centers) { LowRankFunctionParameters lrparameters; - auto builder = LowRankFunctionFactory(lrparameters); + auto builder = LowRankFunctionFactory(lrparameters,centers); // builder.set_volume_element(3.e-2); // builder.parameters.print("lrparameters"); std::vector> result; @@ -84,7 +85,7 @@ std::vector> CCPairFunction::op_dec_to_dec(const if (c.is_op_decomposed()) { LRFunctorF12 functor(c.get_operator_ptr()->get_op(),c.get_a(),c.get_b()); LowRankFunction tmp=builder.project(functor); - double l2error=tmp.l2error(functor); +// double l2error=tmp.l2error(functor); tmp.optimize(functor); result.push_back(CCPairFunction(tmp.get_g(),tmp.get_h())); } else { @@ -206,7 +207,8 @@ bool CCPairFunction::is_collected(const std::vector std::vector> CCPairFunction::consolidate(const std::vector>& other, - std::vector options) const { + const std::vector& options, + const std::vector::LDIM>>& centers) const { // return only one term of a hi-dim function bool one_term=find(options.begin(),options.end(),"one_term")!=options.end(); @@ -223,7 +225,7 @@ std::vector> CCPairFunction::consolidate(const st auto result= is_collected(other) ? other : collect_same_types(other); if (lindep) result=CCPairFunction::remove_linearly_dependent_terms(result); - if (op_dec_to_dec) result=CCPairFunction::op_dec_to_dec(result); + if (op_dec_to_dec) result=CCPairFunction::op_dec_to_dec(result,centers); if (op_dec_to_pure) result=CCPairFunction::op_dec_to_pure(result); if (op_pure_to_pure) result=CCPairFunction::op_pure_to_pure(result); diff --git a/src/madness/chem/ccpairfunction.h b/src/madness/chem/ccpairfunction.h index dfad3e667ce..6c957ab7851 100644 --- a/src/madness/chem/ccpairfunction.h +++ b/src/madness/chem/ccpairfunction.h @@ -401,10 +401,12 @@ using pureT=Function; private: std::vector consolidate(const std::vector& other, - std::vector options={}) const; + const std::vector& options, + const std::vector>& centers) const; /// turn decomposed functions with operator into decomposed functions using LowRankFunction - static std::vector op_dec_to_dec(const std::vector& other); + static std::vector op_dec_to_dec(const std::vector& other, + const std::vector>& centers); /// turn pure functions with operator into pure functions without operators static std::vector op_pure_to_pure(const std::vector& other); @@ -426,11 +428,13 @@ using pureT=Function; /// @param[in] other: a vector of CCPairFunctions /// @param[in] options: a vector of strings which can be "one_term", "op_pure_to_pure", "svd" + /// @param[in] centers: a vector of 3D-vectors which are the centers of the grid for low-rank functions /// TODO: implement a function for removing linearly dependent terms without orthonormalization friend std::vector consolidate(const std::vector& other, - std::vector options={}) { + const std::vector options, + const std::vector> centers=std::vector>()) { - if (other.size()>0) return other.front().consolidate(other,options); // workaround + if (other.size()>0) return other.front().consolidate(other,options,centers); // workaround return other; }; diff --git a/src/madness/chem/lowrankfunction.h b/src/madness/chem/lowrankfunction.h index a26cb770c2d..a175277c30c 100644 --- a/src/madness/chem/lowrankfunction.h +++ b/src/madness/chem/lowrankfunction.h @@ -23,13 +23,12 @@ namespace madness { initialize("radius",2.0,"the radius"); initialize("gamma",1.0,"the exponent of the correlation factor"); initialize("volume_element",0.1,"volume covered by each grid point"); - initialize("hard_shell",true,"radius is hard"); initialize("tol",1.e-8,"rank-reduced cholesky tolerance"); initialize("f12type","Slater","correlation factor",{"Slater","SlaterF12"}); initialize("orthomethod","cholesky","orthonormalization",{"cholesky","canonical","symmetric"}); initialize("transpose","slater2","transpose of the matrix",{"slater1","slater2"}); initialize("gridtype","random","the grid type",{"random","cartesian","spherical"}); - initialize("rhsfunctiontype","exponential","the type of function",{"delta","exponential"}); + initialize("rhsfunctiontype","exponential","the type of function",{"exponential"}); initialize("optimize",1,"number of optimization iterations"); } @@ -41,7 +40,6 @@ namespace madness { double gamma() const {return get("gamma");} double volume_element() const {return get("volume_element");} double tol() const {return get("tol");} - bool hard_shell() const {return get("hard_shell");} int optimize() const {return get("optimize");} std::string gridtype() const {return get("gridtype");} std::string orthomethod() const {return get("orthomethod");} @@ -51,16 +49,37 @@ namespace madness { class gridbase { + public: + double get_volume_element() const {return volume_element;} + double get_radius() const {return radius;} + + // visualize the grid in xyz format + template + void visualize(const std::string filename, const std::vector>& grid) const { + print("visualizing grid to file",filename); + print("a total of",grid.size(),"grid points"); + std::ofstream file(filename); + for (const auto& r : grid) { + // formatted output + file << std::fixed << std::setprecision(6); + for (int i=0; i class randomgrid : public gridbase { public: - randomgrid(const double volume_element, const double radius) : gridbase() { + randomgrid(const double volume_element, const double radius, const Vector origin=Vector(0.0)) + : gridbase(), origin(origin) { this->volume_element=volume_element; this->radius=radius; } @@ -76,8 +95,9 @@ namespace madness { return true; }; double rad=radius; - auto is_in_sphere = [&rad](const Vector& r) { - return (r.normf()& r) { + return ((r-o).normf() get_origin() const { + return origin; + } + private: double volume() const { @@ -111,15 +137,20 @@ namespace madness { if (NDIM==3) return 4.0 / 3.0 * constants::pi * std::pow(radius, 3.0); } - static Vector gaussian_random_distribution(double mean, double variance) { + static Vector gaussian_random_distribution(const Vector origin, double variance) { std::random_device rd{}; std::mt19937 gen{rd()}; - std::normal_distribution<> d{mean, variance}; Vector result; - for (int i = 0; i < NDIM; ++i) result[i]=d(gen); + for (int i = 0; i < NDIM; ++i) { + std::normal_distribution<> d{origin[i], variance}; + result[i]=d(gen); + } + return result; } + Vector origin; + }; template @@ -191,6 +222,35 @@ namespace madness { }; + /// given a molecule, return a suitable grid + template + class molecular_grid : public gridbase { + + public: + /// ctor takes molecule and grid + molecular_grid(const std::vector> origins, randomgrid grid) { + for (const auto& coords : origins) { + atomicgrid.push_back(randomgrid(grid.get_volume_element(),grid.get_radius(),coords)); + } + } + + molecular_grid(const Molecule& molecule, randomgrid grid) : molecular_grid(molecule.get_all_coords_vec(),grid) {} + + std::vector> get_grid() const { + std::vector> grid; + for (const auto& atomic : atomicgrid) { + print("atom sites",atomic.get_origin()); + auto atomgrid=atomic.get_grid(); + grid.insert(grid.end(),atomgrid.begin(),atomgrid.end()); + } + return grid; + } + + private: + std::vector> atomicgrid; + + }; + template struct particle { std::array dims; @@ -902,9 +962,17 @@ struct LRFunctorPure : public LRFunctorBase { const particle p1=particle::particle1(); const particle p2=particle::particle2(); + LowRankFunctionParameters parameters; + std::vector> origins; ///< origins of the molecular grid + LowRankFunctionFactory() = default; - LowRankFunctionFactory(const LowRankFunctionParameters param) : parameters(param) {} + LowRankFunctionFactory(const LowRankFunctionParameters param, const std::vector> origins={}) + : parameters(param), origins(origins) {} + + LowRankFunctionFactory(const LowRankFunctionParameters param, const Molecule& molecule) + : LowRankFunctionFactory(param,molecule.get_all_coords_vec()){} + LowRankFunctionFactory(const LowRankFunctionFactory& other) = default; LowRankFunctionFactory& set_radius(const double radius) { @@ -933,8 +1001,15 @@ struct LRFunctorPure : public LRFunctorBase { auto rank_revealing_tol=parameters.tol(); // get sampling grid + std::vector> grid; randomgrid rgrid(parameters.volume_element(),parameters.radius()); - std::vector> grid=rgrid.get_grid(); + if (origins.size()>0) { + molecular_grid mgrid(origins,rgrid); + grid=mgrid.get_grid(); + } else { + grid=rgrid.get_grid(); + } + auto Y=Yformer(lrfunctor,grid,parameters.rhsfunctiontype()); t1.tag("Yforming"); diff --git a/src/madness/chem/mp3.cc b/src/madness/chem/mp3.cc index 22d5a4e3d83..931cf68ba46 100644 --- a/src/madness/chem/mp3.cc +++ b/src/madness/chem/mp3.cc @@ -420,6 +420,7 @@ double MP3::compute_mp3_ghij_fast(const Pairs& mp2pairs, const Pairs::Parameters cparam; auto g12=CCConvolutionOperatorPtr(world,OpType::OT_G12,cparam); + const Molecule molecule=nemo_->molecule(); timer t2(world); // compute intermediates for terms G, I, H, and J @@ -439,13 +440,13 @@ double MP3::compute_mp3_ghij_fast(const Pairs& mp2pairs, const Pairs consolidation={"op_pure_to_pure","remove_lindep","op_dec_to_pure"}; + std::vector consolidation={"op_pure_to_pure","remove_lindep","op_dec_to_dec"}; print("consolidating with ",consolidation); std::vector intermediate(nocc); for (int i = parameters.freeze(); i < nocc; ++i) { intermediate[i]=2.0*tau_kk_i[i]; intermediate[i]-=tau_ij_j[i]; - intermediate[i]=consolidate(intermediate[i],consolidation); + intermediate[i]=consolidate(intermediate[i],consolidation,molecule.get_all_coords_vec()); } t2.tag("GHIJ term prep"); @@ -683,10 +684,10 @@ double MP3::mp3_energy_contribution(const Pairs& mp2pairs) const { t2.tag("make cluster functions"); mp3_test(mp2pairs,clusterfunctions); double term_CD=0.0, term_EF=0.0, term_GHIJ=0.0, term_KLMN=0.0; - term_KLMN=compute_mp3_klmn_fast(mp2pairs); - t2.tag("KLMN term fast"); term_GHIJ=compute_mp3_ghij_fast(mp2pairs,clusterfunctions); t2.tag("GHIJ term"); + term_KLMN=compute_mp3_klmn_fast(mp2pairs); + t2.tag("KLMN term fast"); term_EF=compute_mp3_ef_with_permutational_symmetry(mp2pairs); t2.tag("EF term, permutational symmetry"); term_CD=compute_mp3_cd(mp2pairs); diff --git a/src/madness/chem/test_low_rank_function.cc b/src/madness/chem/test_low_rank_function.cc index 22045f27a2f..a0130dc4330 100644 --- a/src/madness/chem/test_low_rank_function.cc +++ b/src/madness/chem/test_low_rank_function.cc @@ -38,7 +38,6 @@ int test_lowrank_function(World& world, LowRankFunctionParameters parameters) { j["gamma"]=parameters.gamma(); j["volume_element"]=parameters.volume_element(); j["tol"]=parameters.tol(); - j["hard_shell"]=parameters.hard_shell(); j["transpose"]=transpose; j["orthomethod"]=parameters.orthomethod(); j["gridtype"]=parameters.gridtype(); @@ -203,7 +202,6 @@ int test_Kcommutator(World& world, LowRankFunctionParameters& parameters) { j["thresh"]=FunctionDefaults<3>::get_thresh(); j["volume_element"]=parameters.volume_element(); j["tol"]=parameters.tol(); - j["hard_shell"]=parameters.hard_shell(); j["orthomethod"]=parameters.orthomethod(); j["gridtype"]=parameters.gridtype(); j["rhsfunctiontype"]=parameters.rhsfunctiontype(); @@ -703,6 +701,92 @@ int test_construction_optimization(World& world, LowRankFunctionParameters param return t1.end(); } +template +int test_molecular_grid(World& world, LowRankFunctionParameters parameters) { + constexpr std::size_t NDIM=2*LDIM; + test_output t1("LowRankFunction::molecular_grid in dimension "+std::to_string(NDIM)); + t1.set_cout_to_terminal(); + OperatorInfo info(1.0,1.e-6,FunctionDefaults::get_thresh(),OT_SLATER); + auto slater=std::shared_ptr >(new SeparatedConvolution(world,info)); + + /* + * we test the accuracy of the matrix element _12 + */ + + // a molecule of hydrogen atoms in the xy plane + std::vector> atomic_sites; + atomic_sites.push_back(Vector( 0.0)); + atomic_sites.push_back(Vector( 2.0)); + atomic_sites.push_back(Vector(-4.0)); + if (LDIM>1) { + atomic_sites.back()[0]=0.0; + atomic_sites.back()[1]=-4.0; + } + + randomgrid rgrid(parameters.volume_element(), parameters.radius()); +// randomgrid rgrid(parameters.volume_element(), 1.0); + molecular_grid mgrid(atomic_sites,rgrid); + auto grid=mgrid.get_grid(); + mgrid.visualize("grid",grid); + + // something like a density + auto dens=[&atomic_sites](const Vector& r) { + double result=0.0; + for (auto& c : atomic_sites) result+=exp(-0.4*inner(r-c,r-c)); + return result; + }; + + Function density=FunctionFactory(world).functor(dens); + Function one=FunctionFactory(world).functor([](const Vector& r){return exp(-0.4*inner(r,r));}); + Function half=FunctionFactory(world).functor([](const Vector& r){return sqrt(0.5)*exp(-0.4*inner(r,r));}); + + LRFunctorF12 lrfunctor(slater,density,density); + { + +// atomic_sites.erase(atomic_sites.begin()+1, atomic_sites.end()); + LowRankFunctionFactory builder(parameters, atomic_sites); + auto lrf = builder.project(lrfunctor); + t1.checkpoint(lrf.rank() > 0, "construction"); + + // with Slater tol must be relaxed + double tol = 1.e-2; + + double error = lrf.l2error(lrfunctor); + double norm = lrf.norm2(); + print("lrf.norm", norm); + print("l2 error project ", error); + t1.checkpoint(error, tol, "l2 error in projection"); + + auto lrf2(lrf); + error = lrf2.l2error(lrfunctor); + print("l2 error copy ctor ", error); + MADNESS_CHECK(lrf.rank() == lrf2.rank()); + MADNESS_CHECK(&(lrf.g[0]) != &(lrf2.g[0])); // deep copy + t1.checkpoint(error, tol, "l2 error in copy ctor"); + + lrf.optimize(lrfunctor); + error = lrf.l2error(lrfunctor); + print("l2 error optimize", error); + t1.checkpoint(error, tol, "l2 error in optimization"); + + lrf.reorthonormalize(); + error = lrf.l2error(lrfunctor); + print("l2 error reorthonormalize", error); + t1.checkpoint(error, tol, "l2 error in reorthonormalization"); + + lrf+=lrf; + lrf*=0.5; + lrf.reorthonormalize(); + error = lrf.l2error(lrfunctor); + print("l2 error reorthonormalize with lindep", error); + t1.checkpoint(error, tol, "l2 error in reorthonormalization with lindep"); + + } + return t1.end(); +} + + + int main(int argc, char **argv) { madness::World& world = madness::initialize(argc, argv); @@ -765,6 +849,7 @@ int main(int argc, char **argv) { isuccess+=test_construction_optimization<2>(world,parameters); isuccess+=test_arithmetic<2>(world,parameters); isuccess+=test_inner<2>(world,parameters); + isuccess+=test_molecular_grid<2>(world,parameters); } // parameters.set_user_defined_value("volume_element",1.e-1); From bec75ace2d2a3201e22e23cf62f685b666384b73 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Thu, 21 Mar 2024 12:24:16 +0100 Subject: [PATCH 101/109] implementing a scalar return type for macrotask --- src/madness/mra/macrotaskq.h | 187 ++++++++++++++++++++++-- src/madness/mra/test_cloud.cc | 101 ++++++++++++- src/madness/mra/test_vectormacrotask.cc | 89 ++++++++++- src/madness/world/cloud.h | 63 ++++++-- src/madness/world/test_utilities.h | 1 + 5 files changed, 419 insertions(+), 22 deletions(-) diff --git a/src/madness/mra/macrotaskq.h b/src/madness/mra/macrotaskq.h index ea523b6febd..668149b1df3 100644 --- a/src/madness/mra/macrotaskq.h +++ b/src/madness/mra/macrotaskq.h @@ -35,6 +35,145 @@ namespace madness { +/// helper class for returning the result of a task, which is not a madness Function, but a simple scalar + +/// the result value is accumulated via gaxpy in universe rank=0, after completion of the taskq the final +/// value can be obtained via get(), which includes a broadcast of the final value to all processes +template +class ScalarResult : public WorldObject> { +public: + typedef T value_type; + ScalarResult(World &world) : WorldObject>(world) { + this->process_pending(); + } + + /// Disable the default copy constructor + ScalarResult(const ScalarResult& other) = delete; + ScalarResult(ScalarResult&& ) = default; + ScalarResult& operator=(ScalarResult&& ) = default; + + /// disable assignment operator + ScalarResult& operator=(const ScalarResult& other) = delete; + + ~ScalarResult() { +// print("calling destructor of ScalarResult",this->id()); +// std::cout << std::flush; + } + + /// simple assignment of the scalar value + ScalarResult& operator=(const T& x) { + value = x; + return *this; + } + + ScalarResult& operator+= (const T& x) { + gaxpy(1.0, x, 1.0,true); + return *this; + } + + /// accumulate, optional fence + void gaxpy(const double a, const T& right, double b, const bool fence=true) { + if (this->get_world().rank()==0) { + value =a*value + b * right; + } + else this->send(0, &ScalarResult::gaxpy, a, right, b, fence); + } + + template + void serialize(Archive &ar) { + ar & value; + } + + /// after completion of the taskq get the final value + T get() { + this->get_world().gop.broadcast_serializable(*this, 0); + return value; + } + + /// get the local value of this rank, which might differ for different ranks + /// for the final value use get() + T get_local() const { + return value; + } + +private: + /// the scalar value + T value=T(); +}; + +/// helper function to create a vector of ScalarResult, circumventing problems with the constructors +template +std::vector>> scalar_result_shared_ptr_vector(World& world, std::size_t n) { + auto v=std::vector>>(); + for (std::size_t i=0; i>(world)); +// for (int i=0; iid()); + std::cout << std::flush; + auto ptr_opt = world.ptr_from_id< WorldObject< ScalarResult > >(v[0]->id()); + if (!ptr_opt) + MADNESS_EXCEPTION("ScalarResult: remote operation attempting to use a locally uninitialized object",0); + auto ptr = static_cast< ScalarResult*>(*ptr_opt); + if (!ptr) + MADNESS_EXCEPTION("ScalarResult operation attempting to use an unregistered object",0); + return v; +} + + +// type traits to check if a template parameter is a WorldContainer +template +struct is_scalar_result_ptr : std::false_type {}; + +template +struct is_scalar_result_ptr>> : std::true_type {}; + +template +struct is_scalar_result_ptr_vector : std::false_type { +}; + +template +struct is_scalar_result_ptr_vector>>> : std::true_type { +}; + + + +/// the result type of a macrotask must implement gaxpy +template +void gaxpy(const double a, ScalarResult& left, const double b, const T& right, const bool fence=true) { + left.gaxpy(a, right, b, fence); +} + +template +struct madness::archive::ArchiveStoreImpl>> { + static void store(const Archive& ar, const std::shared_ptr>& ptr) { + bool exists=(ptr) ? true : false; + ar & exists; + if (exists) ar & ptr->id(); + } +}; + + +template +struct madness::archive::ArchiveLoadImpl>> { + static void load(const Archive& ar, std::shared_ptr>& ptr) { + bool exists=false; + ar & exists; + if (exists) { + uniqueidT id; + ar & id; + World* world = World::world_from_id(id.get_world_id()); + MADNESS_ASSERT(world); + auto ptr_opt = (world->ptr_from_id< ScalarResult >(id)); + if (!ptr_opt) + MADNESS_EXCEPTION("ScalarResult: remote operation attempting to use a locally uninitialized object",0); + ptr.reset(ptr_opt.value(), [] (ScalarResult *p_) -> void {}); // disable destruction + if (!ptr) + MADNESS_EXCEPTION("ScalarResult operation attempting to use an unregistered object",0); + } else { + ptr=nullptr; + } + } +}; + + /// base class class MacroTaskBase { public: @@ -349,7 +488,8 @@ class MacroTask { // store input and output: output being a pointer to a universe function (vector) recordlistT inputrecords = taskq_ptr->cloud.store(world, argtuple); - auto[outputrecords, result] =prepare_output(taskq_ptr->cloud, argtuple); + resultT result = task.allocator(world, argtuple); + auto outputrecords =prepare_output_records(taskq_ptr->cloud, result); // create tasks and add them to the taskq MacroTaskBase::taskqT vtask; @@ -361,7 +501,7 @@ class MacroTask { if (immediate_execution) taskq_ptr->run_all(vtask); - return result; + return std::move(result); } private: @@ -369,21 +509,29 @@ class MacroTask { World &world; std::shared_ptr taskq_ptr; - /// prepare the output of the macrotask: Function must be created in the universe - std::pair prepare_output(Cloud &cloud, const argtupleT &argtuple) { - static_assert(is_madness_function::value || is_madness_function_vector::value); - resultT result = task.allocator(world, argtuple); + /// store the result WorldObject in the cloud and return the recordlist + recordlistT prepare_output_records(Cloud &cloud, resultT& result) { + static_assert(is_madness_function::value + || is_madness_function_vector::value + || is_scalar_result_ptr::value + || is_scalar_result_ptr_vector::value, + "unknown result type in prepare_output_records"); recordlistT outputrecords; if constexpr (is_madness_function::value) { outputrecords += cloud.store(world, result.get_impl().get()); // store pointer to FunctionImpl - } else if constexpr (is_vector::value) { + } else if constexpr (is_madness_function_vector::value) { outputrecords += cloud.store(world, get_impl(result)); + } else if constexpr (is_scalar_result_ptr::value) { + outputrecords += cloud.store(world, result); // store pointer to ScalarResult + } else if constexpr (is_vector::value && is_scalar_result_ptr::value) { + outputrecords+=cloud.store(world,result); } else { MADNESS_EXCEPTION("\n\n unknown result type in prepare_input ", 1); } - return std::make_pair(outputrecords, result); + return outputrecords; } + class MacroTaskInternal : public MacroTaskIntermediate { typedef decay_tuple argtupleT; // removes const, &, etc @@ -396,7 +544,11 @@ class MacroTask { MacroTaskInternal(const taskT &task, const std::pair &batch_prio, const recordlistT &inputrecords, const recordlistT &outputrecords) : inputrecords(inputrecords), outputrecords(outputrecords), task(task) { - static_assert(is_madness_function::value || is_madness_function_vector::value); + static_assert(is_madness_function::value + || is_madness_function_vector::value + || is_scalar_result_ptr::value + || is_scalar_result_ptr_vector::value, + "unknown result type in MacroTaskInternal constructor"); this->task.batch=batch_prio.first; this->priority=batch_prio.second; } @@ -443,6 +595,16 @@ class MacroTask { gaxpy(1.0,result,1.0,tmp1,false); // was using operator+=, but this requires a fence, which is not allowed here.. // result += tmp1; + } else if constexpr (is_scalar_result_ptr::value) { + gaxpy(1.0, *result, 1.0, result_tmp->get_local(), false); + } else if constexpr (is_scalar_result_ptr_vector::value) { + resultT tmp1=task.allocator(subworld,argtuple); + tmp1=task.batch.template insert_result_batch(tmp1,result_tmp); + + std::size_t sz=result.size(); + for (int i=0; iget_local(), false); + } } else { MADNESS_EXCEPTION("failing result",1); } @@ -463,6 +625,13 @@ class MacroTask { std::vector rimpl = cloud.load>(subworld, outputrecords); result.resize(rimpl.size()); set_impl(result, rimpl); + } else if constexpr (is_scalar_result_ptr::value) { + result = cloud.load(subworld, outputrecords); + } else if constexpr (is_scalar_result_ptr_vector::value) { + typedef typename resultT::value_type::element_type::value_type T; + typedef typename resultT::value_type::element_type ScalarResultT; + result=cloud.load>>(subworld, outputrecords); + } else { MADNESS_EXCEPTION("unknown result type in get_output", 1); } diff --git a/src/madness/mra/test_cloud.cc b/src/madness/mra/test_cloud.cc index 12a33416a84..06aa7ac2ece 100644 --- a/src/madness/mra/test_cloud.cc +++ b/src/madness/mra/test_cloud.cc @@ -126,6 +126,40 @@ int chunk_example(World &universe) { } } + +template using is_world_constructible = std::is_constructible; + + +/// test storing and loading a custom WorldObject, used e.g. for the scalar output of a macrotask +int test_custom_worldobject(World& universe, World& subworld, Cloud& cloud) { + test_output t1("testing custom worldobject"); + t1.set_cout_to_terminal(); + cloud.set_debug(false); + auto o1 =std::shared_ptr>(new ScalarResult(universe)); + auto o5 =std::shared_ptr>(new ScalarResult(universe)); + *o1=1.2; + if (universe.rank() == 0) gaxpy(1.0,*o1,2.0,2.8); + + auto adrecords = cloud.store(universe, o1); + MacroTaskQ::set_pmap(subworld); + print("world constructible",is_world_constructible>::value); + + cloud.set_force_load_from_cache(false); + auto o2 = cloud.load>>(subworld, adrecords); + cloud.set_force_load_from_cache(true); + auto o3 = cloud.load>>(subworld, adrecords); + double d1=o1->get_local(); + double d2=o2->get_local(); + double d3=o3->get_local(); + std::cout << "pointer " << o1->id() << " " << o2->id() << " " << o3->id() << " other: " << o5->id() << std::endl; + std::cout << "numerics (plain)" << d1 << " " << d2 << " " << d3 << std::endl; + std::cout << "numerics (get) " << o1->get() << " " << o2->get() << " " << o3->get() << std::endl; + double error=d1-d2; + cloud.set_force_load_from_cache(false); + return t1.end(error < 1.e-10 ); + +} + int main(int argc, char **argv) { madness::World &universe = madness::initialize(argc, argv); @@ -139,7 +173,10 @@ int main(int argc, char **argv) { // cloud.set_debug(true); auto subworld_ptr = MacroTaskQ::create_worlds(universe, universe.size()); - World &subworld = *subworld_ptr; + World& subworld = *subworld_ptr; + + // test storing custom WorldObject + success += test_custom_worldobject(universe, subworld, cloud); if (universe.rank() == 0) print("entering test_cloud"); print("my world: universe_rank, subworld_id", universe.rank(), subworld.id()); @@ -262,6 +299,68 @@ int main(int argc, char **argv) { cloud.set_force_load_from_cache(false); } + + // test storing WorldContainer + test_output test_worldcontainer("testing worldcontainer"); + test_worldcontainer.set_cout_to_terminal(); + cloud.set_debug(false); + typedef WorldContainer result_container; + result_container ad(universe); + ad.replace(0,1.0); + auto adrecords = cloud.store(universe, ad); + { + MacroTaskQ::set_pmap(subworld); + + cloud.set_force_load_from_cache(false); + auto t2 = cloud.load(subworld, adrecords); + cloud.set_force_load_from_cache(true); + auto t3 = cloud.load(subworld, adrecords); + double d1=ad.find(0).get()->second; + double d2=t2.find(0).get()->second; + double d3=t3.find(0).get()->second; + std::cout << "array_double " << d1 << " " << d2 << " " << d3 << std::endl; + double error=d1-d2; + success += test_worldcontainer.end(error < 1.e-10 ); + cloud.set_force_load_from_cache(false); + } + + // test pointer to WorldContainer + if constexpr (0) { + typedef std::shared_ptr::implT> impl_ptrT; + auto p1 = std::shared_ptr>(new WorldContainer(universe)); + p1->replace(0,1.5); + auto precords = cloud.store(universe, p1); + + { + test_output test_dc_ptr("testing cloud/shared_ptr in world " + std::to_string(subworld.id())); + test_dc_ptr.set_cout_to_terminal(); + MacroTaskQ::set_pmap(subworld); + + auto p3 = cloud.load>>(subworld, precords); + auto p4 = cloud.load>>(subworld, precords); + auto p5 = cloud.load>>(subworld, precords); + std::cout << "p1/p2/p3/p4" << " " << p1.get() << " " << p3.get() << " " << p4.get() << " " + << p5.get() << std::endl; + test_dc_ptr.end(p1 == p3 && p1 == p4 && p1 == p5 + && p1->get_world().id() == p3->get_world().id() + && p1->get_world().id() == p4->get_world().id() + && p1->get_world().id() == p5->get_world().id()); + double d3=p3->find(0).get()->second; + double d4=p4->find(0).get()->second; + double d5=p5->find(0).get()->second; + + MacroTaskQ::set_pmap(universe); + cloud.clear_cache(subworld); + } + subworld.gop.fence(); + universe.gop.fence(); + test_output test_dc_ptr("testing cloud/shared_ptr numerics in universe"); + double ffnorm = ff.norm2(); + test_dc_ptr.end((ffnorm < 1.e-10)); + universe.gop.fence(); + } + + // test storing twice (using cache) { cloud.clear_timings(); diff --git a/src/madness/mra/test_vectormacrotask.cc b/src/madness/mra/test_vectormacrotask.cc index 19a055e52bc..ec339806a80 100644 --- a/src/madness/mra/test_vectormacrotask.cc +++ b/src/madness/mra/test_vectormacrotask.cc @@ -138,6 +138,55 @@ class MicroTask2 : public MacroTaskOperationBase{ } }; +class VectorOfScalarTask : public MacroTaskOperationBase{ +public: + // you need to define the result type + // resultT must implement gaxpy(alpha, result, beta, contribution) + // with resultT result, contribution; + typedef std::vector>> resultT; + + // you need to define the exact argument(s) of operator() as tuple + typedef std::tuple &, const double &, + const std::vector &> argtupleT; + + resultT allocator(World &world, const argtupleT &argtuple) const { + std::size_t n = std::get<0>(argtuple).size(); + return scalar_result_shared_ptr_vector(world,n); + } + + resultT operator()(const std::vector& f1, const double &arg2, + const std::vector& f2) const { + World &world = f1[0].world(); + auto result=scalar_result_shared_ptr_vector(world,f1.size()); + for (int i=0; i> resultT; + + // you need to define the exact argument(s) of operator() as tuple + typedef std::tuple &> argtupleT; + + resultT allocator(World &world, const argtupleT &argtuple) const { + return resultT(new ScalarResult(world)); + } + + resultT operator()(const std::vector& f1) const { + World &world = f1[0].world(); + resultT result(new ScalarResult(world)); + *result=double(f1.size()); + return result; + } +}; + + + int check_vector(World& universe, const std::vector &ref, const std::vector &test, const std::string msg) { double norm_ref = norm2(universe, ref); @@ -218,6 +267,38 @@ int test_task1(World& universe, const std::vector& v3) { return success; } +/// each task accumulates into the same result +int test_scalar_task(World& universe, const std::vector& v3) { + if (universe.rank()==0) print("\nstarting ScalarTask\n"); + ScalarTask t1; + std::shared_ptr> result = t1(v3); + print("result",result->get()); + + + MacroTask task1(universe, t1); + auto result2= task1(v3); + print("result",result2->get()); + +// int success = check(universe,ref_t1, ref_t2, "task1 immediate"); + int success=0; + return success; +} +int test_vector_of_scalar_task(World& universe, const std::vector& v3) { + if (universe.rank()==0) print("\nstarting VectorOfScalarTask\n"); + VectorOfScalarTask t1; + std::vector>> result = t1(v3, 2.0, v3); + for (auto& r : result) print("result",r->get()); + + + MacroTask task1(universe, t1); + auto result2= task1(v3, 2.0, v3); + for (auto& r : result2) print("result",r->get()); + +// int success = check(universe,ref_t1, ref_t2, "task1 immediate"); + int success=0; + return success; +} + int test_2d_partitioning(World& universe, const std::vector& v3) { if (universe.rank() == 0) print("\nstarting 2d partitioning"); auto taskq = std::shared_ptr(new MacroTaskQ(universe, universe.size())); @@ -265,6 +346,12 @@ int main(int argc, char **argv) { success+=test_immediate(universe,v3,ref); timer1.tag("immediate taskq execution"); + success+=test_vector_of_scalar_task(universe,v3); + timer1.tag("vector of scalar task execution"); + + success+=test_scalar_task(universe,v3); + timer1.tag("scalar task execution"); + success+=test_deferred(universe,v3,ref); timer1.tag("deferred taskq execution"); @@ -284,7 +371,7 @@ int main(int argc, char **argv) { } madness::finalize(); - return 0; + return success; } template<> volatile std::list WorldObject::pending = std::list(); diff --git a/src/madness/world/cloud.h b/src/madness/world/cloud.h index 2e0d87af5ba..6c08d6e69d3 100644 --- a/src/madness/world/cloud.h +++ b/src/madness/world/cloud.h @@ -60,12 +60,26 @@ struct Recordlist { return list.size(); } + // if type provides id() member function (i.e. WorldObject) use that for hashing, otherwise use hash_value() for + // fundamental types (see worldhash.h) + template + using member_id_t = decltype(std::declval().id()); + + template + using has_member_id = madness::meta::is_detected; + template static keyT compute_record(const Function& arg) {return hash_value(arg.get_impl()->id());} template static keyT compute_record(const FunctionImpl* arg) {return hash_value(arg->id());} + template + static keyT compute_record(const WorldContainer& arg) {return hash_value(arg.id());} + + template + static keyT compute_record(const std::shared_ptr>& arg) {return hash_value(arg->id());} + template static keyT compute_record(const std::shared_ptr>& arg) {return hash_value(arg->id());} @@ -76,7 +90,18 @@ struct Recordlist { static keyT compute_record(const Tensor& arg) {return hash_value(arg.normf());} template - static keyT compute_record(const T& arg) {return hash_value(arg);} + static keyT compute_record(const std::shared_ptr& arg) {return compute_record(*arg);} + + template + static keyT compute_record(const T& arg) { + if constexpr (has_member_id::value) { + return hash_value(arg.id()); + } else if constexpr (std::is_pointer_v && has_member_id>::value) { + return hash_value(arg->id()); + } else { + return hash_value(arg); + } + } friend std::ostream &operator<<(std::ostream &os, const Recordlist &arg) { @@ -349,22 +374,25 @@ class Cloud { // if (auto obj = std::get_if(&cached_objects.find(record)->second)) return *obj; if (auto obj = std::any_cast(&cached_objects.find(record)->second)) return *obj; MADNESS_EXCEPTION("failed to load from cloud-cache", 1); - return T(); + T target = allocator(world); + return target; } template T load_internal(madness::World &world, recordlistT &recordlist) const { - T result; +// T result; if constexpr (is_vector::value) { if constexpr( is_parallel_serializable_object::value) { - result = load_vector_of_parallel_serializable_objects(world, recordlist); +// result = load_vector_of_parallel_serializable_objects(world, recordlist); + return load_vector_of_parallel_serializable_objects(world, recordlist); } else { - result = load_other(world, recordlist); +// result = load_other(world, recordlist); + return load_vector_other(world, recordlist); } } else { - result = load_other(world, recordlist); +// result = load_other(world, recordlist); + return load_other(world, recordlist); } - return result; } bool is_cached(const keyT &key) const { @@ -383,8 +411,11 @@ class Cloud { template T allocator(World &world) const { - if constexpr (is_world_constructible::value) return T(world); - return T(); + if constexpr (is_world_constructible::value) { + return T(world); + } else { + return T(); + } } template @@ -409,6 +440,16 @@ class Cloud { return recordlistT{record}; } + template + T load_vector_other(World &world, recordlistT &recordlist) const { + std::size_t sz = load_other(world, recordlist); + T target(sz); + for (std::size_t i = 0; i < sz; ++i) { + target[i] = load_other(world, recordlist); + } + return target; + } + template T load_other(World &world, recordlistT &recordlist) const { keyT record = recordlist.pop_front_and_return(); @@ -426,8 +467,8 @@ class Cloud { // overloaded template - std::enable_if_t::value, recordlistT> - store_other(madness::World& world, const std::vector& source) { +// std::enable_if_t::value, recordlistT> + recordlistT store_other(madness::World& world, const std::vector& source) { if (debug) std::cout << "storing " << typeid(source).name() << " of size " << source.size() << std::endl; recordlistT l = store_other(world, source.size()); diff --git a/src/madness/world/test_utilities.h b/src/madness/world/test_utilities.h index c2359f4188d..a1aad7c7976 100644 --- a/src/madness/world/test_utilities.h +++ b/src/madness/world/test_utilities.h @@ -127,6 +127,7 @@ struct test_output { std::cout.rdbuf(stream_buffer_cout); } cout_set_to_logger=false; + std::cout << std::endl; } std::stringstream logger; From f6b63bb1641596bb425366a8e3a128d8659b2341 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Thu, 21 Mar 2024 12:51:01 +0100 Subject: [PATCH 102/109] fixed failing test in test_vectormacrotask.cc --- src/madness/mra/macrotaskq.h | 10 ++++++++-- src/madness/mra/test_vectormacrotask.cc | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/madness/mra/macrotaskq.h b/src/madness/mra/macrotaskq.h index 668149b1df3..751c7cfe6e3 100644 --- a/src/madness/mra/macrotaskq.h +++ b/src/madness/mra/macrotaskq.h @@ -455,9 +455,11 @@ class MacroTask { typedef typename taskT::argtupleT argtupleT; typedef Cloud::recordlistT recordlistT; taskT task; + bool debug=false; public: + /// constructor takes the actual task MacroTask(World &world, taskT &task, std::shared_ptr taskq_ptr = 0) : task(task), world(world), taskq_ptr(taskq_ptr) { if (taskq_ptr) { @@ -467,6 +469,10 @@ class MacroTask { } } + void set_debug(const bool value) { + debug=value; + } + /// this mimicks the original call to the task functor, called from the universe /// store all input to the cloud, create output Function in the universe, @@ -476,6 +482,7 @@ class MacroTask { const bool immediate_execution = (not taskq_ptr); if (not taskq_ptr) taskq_ptr.reset(new MacroTaskQ(world, world.size())); + if (debug) taskq_ptr->set_printlevel(20); auto argtuple = std::tie(args...); static_assert(std::is_same::value, "type or number of arguments incorrect"); @@ -499,7 +506,7 @@ class MacroTask { } taskq_ptr->add_tasks(vtask); - if (immediate_execution) taskq_ptr->run_all(vtask); + if (immediate_execution) taskq_ptr->run_all(); return std::move(result); } @@ -587,7 +594,6 @@ class MacroTask { if constexpr (is_madness_function::value) { result_tmp.compress(); gaxpy(1.0,result,1.0, result_tmp); - result += result_tmp; } else if constexpr(is_madness_function_vector::value) { compress(subworld, result_tmp); resultT tmp1=task.allocator(subworld,argtuple); diff --git a/src/madness/mra/test_vectormacrotask.cc b/src/madness/mra/test_vectormacrotask.cc index ec339806a80..4ce5b87f2bf 100644 --- a/src/madness/mra/test_vectormacrotask.cc +++ b/src/madness/mra/test_vectormacrotask.cc @@ -262,6 +262,7 @@ int test_task1(World& universe, const std::vector& v3) { MicroTask1 t1; real_function_3d ref_t1 = t1(v3[0], 2.0, v3); MacroTask task1(universe, t1); + task1.set_debug(true); real_function_3d ref_t2 = task1(v3[0], 2.0, v3); int success = check(universe,ref_t1, ref_t2, "task1 immediate"); return success; From 336e6d3031e13d7946d619c2ba965e9ccbf966b9 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Fri, 22 Mar 2024 12:33:05 +0100 Subject: [PATCH 103/109] serializing CCPairFunction to file --- src/madness/chem/CCStructures.h | 5 + src/madness/chem/ccpairfunction.h | 71 ++++++++++++- src/madness/chem/molecule.h | 17 +++ src/madness/chem/mp3.cc | 107 ++++++++++++++++--- src/madness/chem/mp3.h | 135 +++++++++++++++++++++++- src/madness/chem/test_ccpairfunction.cc | 56 +++++++++- src/madness/world/test_utilities.h | 15 +-- 7 files changed, 382 insertions(+), 24 deletions(-) diff --git a/src/madness/chem/CCStructures.h b/src/madness/chem/CCStructures.h index 28440a80dad..a491a105962 100644 --- a/src/madness/chem/CCStructures.h +++ b/src/madness/chem/CCStructures.h @@ -727,6 +727,11 @@ struct CCConvolutionOperator { double lo = 1.e-6; int freeze = 0; double gamma = 1.0; /// f12 exponent + + template + void serialize(archiveT& ar) { + ar & thresh_op & lo & freeze & gamma; + } }; diff --git a/src/madness/chem/ccpairfunction.h b/src/madness/chem/ccpairfunction.h index 6c957ab7851..6154d334cb5 100644 --- a/src/madness/chem/ccpairfunction.h +++ b/src/madness/chem/ccpairfunction.h @@ -153,8 +153,6 @@ class TwoBodyFunctionPureComponent : public TwoBodyFunctionComponentBase { World& world() const override {return u.world();}; - void serialize() {} - void print_size() const override { u.print_size(name(false)); } @@ -328,7 +326,7 @@ class TwoBodyFunctionSeparatedComponent : public TwoBodyFunctionComponentBase { * **/ template -struct CCPairFunction { +struct CCPairFunction : public archive::ParallelSerializableObject { static constexpr std::size_t LDIM=NDIM/2; static_assert(NDIM%2==0,"NDIM must be even"); @@ -399,6 +397,15 @@ using pureT=Function; return result; } + bool is_assigned() const { + return component.get(); + } + + hashT hash() const { + MADNESS_EXCEPTION("no hash in CCPairFunction",1); + return hashT(); + } + private: std::vector consolidate(const std::vector& other, const std::vector& options, @@ -756,6 +763,64 @@ using pureT=Function; }; +namespace archive { +template +struct ArchiveLoadImpl< ParallelInputArchive, CCPairFunction > { + static inline void load(const ParallelInputArchive& ar, CCPairFunction& p) { + constexpr std::size_t LDIM=CCPairFunction::LDIM; + bool exists, is_pure, has_operator; + ar & exists; + if (exists) { + ar & is_pure & has_operator; + if (is_pure) { + Function f; + ar & f; + p=CCPairFunction(f); + } else { + std::size_t sz; + ar & sz; + std::vector> a(sz),b(sz); + for (auto& aa : a) ar & aa; + for (auto& bb : b) ar & bb; + p=CCPairFunction(a,b); + } + + // store construction parameters of the operator, not the operator itself + if (has_operator) { + auto param=typename CCConvolutionOperator::Parameters(); + OpType type; + ar & param & type; + auto op=std::make_shared>(*ar.get_world(),type,param); + p.reset_operator(op); + } + } + } +}; + +template +struct ArchiveStoreImpl< ParallelOutputArchive, CCPairFunction > { + static inline void store(const ParallelOutputArchive& ar, const CCPairFunction& f) { + bool exists=f.is_assigned(); + ar & exists; + if (exists) { + ar & f.is_pure() & f.has_operator(); + if (f.is_pure()) ar & f.get_function(); + if (f.is_decomposed()) { + auto avec=f.get_a(); + auto bvec=f.get_b(); + ar & avec.size(); + for (const auto& a : avec) ar & a; + for (const auto& b : bvec) ar & b; + } + // store construction parameters of the operator, not the operator itself + if (f.has_operator()) { + ar & f.get_operator().parameters & f.get_operator().type(); + } + } + } +}; +} + /// apply the operator to the argument /// the operator is applied to one particle only, the other one is left untouched diff --git a/src/madness/chem/molecule.h b/src/madness/chem/molecule.h index 4a575273bb4..341401c86f4 100644 --- a/src/madness/chem/molecule.h +++ b/src/madness/chem/molecule.h @@ -107,6 +107,16 @@ class Atom { void serialize(Archive& ar) { ar & x & y & z & q & atomic_number & mass & pseudo_atom; } + hashT hash() const { + hashT h=hash_value(x); + hash_combine(h,y); + hash_combine(h,z); + hash_combine(h,q); + hash_combine(h,atomic_number); + hash_combine(h,mass); + hash_combine(h,pseudo_atom); + return h; + } }; std::ostream& operator<<(std::ostream& s, const Atom& atom); @@ -521,6 +531,13 @@ class Molecule { void serialize(Archive& ar) { ar & atoms & rcut & core_pot & parameters & pointgroup_ & field; } + + hashT hash() const { + hashT h= hash_range(atoms.begin(),atoms.end()); + hash_combine(h,hash_range(rcut.begin(),rcut.end())); + hash_combine(h,pointgroup_); + return h; + } [[nodiscard]] json to_json() const; }; diff --git a/src/madness/chem/mp3.cc b/src/madness/chem/mp3.cc index 931cf68ba46..8172dc38123 100644 --- a/src/madness/chem/mp3.cc +++ b/src/madness/chem/mp3.cc @@ -652,19 +652,40 @@ double MP3::mp3_test(const Pairs& mp2pairs, const Pairs>>& pair_square, + const std::vector>& mo_ket, + const std::vector>& mo_bra, + const CCParameters& parameters, + const Molecule& molecule, + const Function& Rsquare, + const std::vector& argument) { + print_header2("entering compute_mp3_cd"); + + CCConvolutionOperator::Parameters cparam(parameters); + auto g12=CCConvolutionOperatorPtr(world,OpType::OT_G12,cparam); + + double result = 0.0; +// for (int i = parameters.freeze(); i < nocc; ++i) { +// for (int j = i; j < nocc; ++j) { + auto bra = pair_square(i, j); + double tmp1 = inner(bra, g12 * pair_square(i, j), Rsquare); + double tmp2 = inner(bra, g12 * pair_square(j, i), Rsquare); + double fac = (i == j) ? 0.5 : 1.0; + double tmp = fac * (4.0 * tmp1 - 2.0 * tmp2); + printf("mp3 energy: term_CD %2ld %2ld: %12.8f\n", i, j, tmp); + result+= tmp; +// } +// } + printf("MP3 energy: term_CD %12.8f\n", result); + return result; +} + double MP3::mp3_energy_contribution(const Pairs& mp2pairs) const { print_header2("computing the MP3 correlation energy"); print("mp2pairs.size()",mp2pairs.allpairs.size()); - // print_header3("prepare the cluster function"); - // typedef std::vector> ClusterFunction; - // Pairs clusterfunctions; - // - // auto R2 = nemo->ncf->square(); - // auto R = nemo->ncf->function(); - // std::vector nemo_orbital=mo_ket().get_vecfunction(); - // std::vector R2_orbital=mo_bra().get_vecfunction(); - // const int nocc=mo_ket().size(); timer t2(world); std::size_t nocc=mo_ket().size(); @@ -682,16 +703,17 @@ double MP3::mp3_energy_contribution(const Pairs& mp2pairs) const { } t2.tag("make cluster functions"); - mp3_test(mp2pairs,clusterfunctions); +// mp3_test(mp2pairs,clusterfunctions); double term_CD=0.0, term_EF=0.0, term_GHIJ=0.0, term_KLMN=0.0; + term_CD=compute_mp3_cd(mp2pairs); + t2.tag("CD term"); + term_GHIJ=compute_mp3_ghij_fast(mp2pairs,clusterfunctions); t2.tag("GHIJ term"); term_KLMN=compute_mp3_klmn_fast(mp2pairs); t2.tag("KLMN term fast"); term_EF=compute_mp3_ef_with_permutational_symmetry(mp2pairs); t2.tag("EF term, permutational symmetry"); - term_CD=compute_mp3_cd(mp2pairs); - t2.tag("CD term"); printf("term_CD %12.8f\n",term_CD); printf("term_GHIJ %12.8f\n",term_GHIJ); @@ -701,4 +723,65 @@ double MP3::mp3_energy_contribution(const Pairs& mp2pairs) const { printf("MP3 energy contribution %12.8f\n",mp3_energy); return mp3_energy; } + +double MP3::mp3_energy_contribution_macrotask_driver(const Pairs& mp2pairs) const { + + print_header2("computing the MP3 correlation energy, macrotask version"); + print("mp2pairs.size()",mp2pairs.allpairs.size()); + + // compute all ij pairs + timer t2(world); + std::size_t nocc=mo_ket().size(); + typedef std::vector> ClusterFunction; + Pairs clusterfunctions; + for (int i = parameters.freeze(); i < nocc; ++i) { + for (int j = i; j < nocc; ++j) { + clusterfunctions(i,j)=mp2pairs(i,j).functions; + if (i!=j) { + for (const auto& t : clusterfunctions(i,j)) { + clusterfunctions(j, i).push_back(t.swap_particles()); + } + } + } + } + // turn Pair into vector for cloud and stuff -- will be reversed later on + PairVectorMap square_map=PairVectorMap::quadratic_map(parameters.freeze(),mo_ket().size()); + auto clusterfunc_vec=Pairs>>::pairs2vector(clusterfunctions,square_map); + + t2.tag("make cluster functions"); + + // create dummy scheduling vector of length npair=nocc*(nocc+1)/2, for the macrotask scheduler + std::vector ij_vec(mp2pairs.allpairs.size()); + + // get mos + const std::vector& ket=mo_ket().get_vecfunction(); + const std::vector& bra=mo_bra().get_vecfunction(); + + + + auto taskq=std::shared_ptr(new MacroTaskQ(world,world.size(),3)); + MacroTaskMP3 task; + MacroTask macrotask(world,task,taskq); + taskq->print_taskq(); +// auto cd_future=macrotask(std::string("cd"), ij_vec, clusterfunc_vec, ket, bra, parameters, nemo_->molecule(), nemo_->R_square, std::vector()); +// auto ef_future=macrotask("ef", mp2pairs, clusterfunctions, mo_ket(), mo_bra(), parameters, nemo_->molecule(), nemo_->R_square, std::vector()); +// auto ghij_future=macrotask("ghij", mp2pairs, clusterfunctions, mo_ket(), mo_bra(), parameters, nemo_->molecule(), nemo_->R_square, std::vector()); +// auto klmn_future=macrotask("klmn", mp2pairs, clusterfunctions, mo_ket(), mo_bra(), parameters, nemo_->molecule(), nemo_->R_square, std::vector()); + taskq->run_all(); + +// double term_CD=cd_future->get(); +// double term_EF=ef_future->get(); +// double term_GHIJ=ghij_future->get(); +// double term_KLMN=klmn_future->get(); + +// printf("term_CD %12.8f\n",term_CD); +// printf("term_GHIJ %12.8f\n",term_GHIJ); +// printf("term_KLMN %12.8f\n",term_KLMN); +// printf("term_EF %12.8f\n",term_EF); +// double mp3_energy=term_CD+term_GHIJ+term_KLMN+term_EF; +// double mp3_energy=term_CD; + double mp3_energy=-1.0; + printf("MP3 energy contribution %12.8f\n",mp3_energy); + return mp3_energy; +} } diff --git a/src/madness/chem/mp3.h b/src/madness/chem/mp3.h index 5e7974c294f..d68c9dea7b8 100644 --- a/src/madness/chem/mp3.h +++ b/src/madness/chem/mp3.h @@ -25,6 +25,103 @@ class MP3 : public CCPotentials { : CCPotentials(world,nemo,param) {} MP3(const CCPotentials& ops) : CCPotentials(ops) {} + double mp3_energy_contribution(const Pairs& mp2pairs) const; + + /// compute the MP3 energy contribution, macrotask version + double mp3_energy_contribution_macrotask_driver(const Pairs& mp2pairs) const; + +private: + /// helper class for calculating the MP3 energy contributions + class MacroTaskMP3 : public MacroTaskOperationBase { + + class ConstantPartPartitioner : public MacroTaskPartitioner { + public: + ConstantPartPartitioner() {}; + + partitionT do_partitioning(const std::size_t& vsize1, const std::size_t& vsize2, + const std::string policy) const override { + partitionT p; + for (size_t i = 0; i < vsize1; i++) { + Batch batch(Batch_1D(i,i+1), Batch_1D(i,i+1)); + p.push_back(std::make_pair(batch,1.0)); + } + return p; + } + }; + + public: + MacroTaskMP3(){partitioner.reset(new ConstantPartPartitioner());} + + typedef std::tuple< + const std::string&, + const std::vector&, + const std::vector>>& , // all pairs ij + const std::vector>&, + const std::vector>&, + const CCParameters&, + const Molecule&, + const Function&, + const std::vector& > argtupleT; + + using resultT =std::shared_ptr>; + + resultT allocator(World& world, const argtupleT& argtuple) const { + return std::shared_ptr>(new ScalarResult(world)); + } + + resultT operator() (const std::string& diagram, // which diagram to calculate + const std::vector& ij_vec, // dummy vector of size npair + const std::vector>>& pair_square, // all pairs ij + const std::vector>& mo_ket, // the orbitals + const std::vector>& mo_bra, // the orbitals*R2 + const CCParameters& parameters, + const Molecule& molecule, + const Function& Rsquare, + const std::vector& argument) const { + + // the partitioner will break the input vector of pairs into single pairs + MADNESS_CHECK(ij_vec.size()==1); + + // determine the orbital indices i and j for the pair + // active occupied orbitals, the total length of pair_triangular is nact*(nact+1) + const long nact=mo_ket.size()-parameters.freeze(); + MADNESS_CHECK(pair_square.size()==nact*nact); + + // the batch index is the ij composite index [0,nact*(nact+1)-1] + const long ij=batch.result.begin; + MADNESS_CHECK(batch.result.size()==1); + + // turn composite index ij into i and j, taking care of frozen orbitals + PairVectorMap tri_map=PairVectorMap::triangular_map(parameters.freeze(),mo_ket.size()); + auto ij_to_i_and_j = [&tri_map](const int ij) { return tri_map.map[ij]; }; + auto [i,j]=ij_to_i_and_j(ij); + + PairVectorMap square_map=PairVectorMap::quadratic_map(parameters.freeze(),mo_ket.size()); + auto clusterfunctions=Pairs>>::vector2pairs(pair_square,square_map); + + double result=0.0; + World& world=Rsquare.world(); + if (diagram=="cd") + result= MP3::compute_mp3_cd(world,i,j,clusterfunctions,mo_ket,mo_bra,parameters,molecule,Rsquare,argument); +// else if (diagram=="ef") +// result= MP3::compute_mp3_ef(pair_triangular,pair_square,mo_ket,mo_bra,parameters,molecule,Rsquare,argument); +// else if (diagram=="ghij") +// result= MP3::compute_mp3_ghij(pair_triangular,pair_square,mo_ket,mo_bra,parameters,molecule,Rsquare,argument); +// else if (diagram=="klmn") +// result= MP3::compute_mp3_klmn(pair_triangular,pair_square,mo_ket,mo_bra,parameters,molecule,Rsquare,argument); + else { + std::string msg = "Unknown MP3 diagram: " + diagram; + MADNESS_EXCEPTION(msg.c_str(), 1); + } + auto result1=std::shared_ptr>(new ScalarResult(world)); + *result1=result; + return result1; + + }; + + + }; + double compute_mp3_cd(const Pairs& mp2pairs) const; double compute_mp3_ef(const Pairs& mp2pairs) const; @@ -35,9 +132,45 @@ class MP3 : public CCPotentials { double compute_mp3_ghij_fast(const Pairs& mp2pairs, const Pairs>> clusterfunctions) const; double compute_mp3_klmn(const Pairs& mp2pairs) const; double compute_mp3_klmn_fast(const Pairs& mp2pairs) const; - double mp3_energy_contribution(const Pairs& mp2pairs) const; double mp3_test(const Pairs& mp2pairs, const Pairs>> clusterfunctions) const; + static double compute_mp3_cd(World& world, + const long i, const long j, + const Pairs>>& pair_square, + const std::vector>& mo_ket, + const std::vector>& mo_bra, + const CCParameters& parameters, + const Molecule& molecule, + const Function& Rsquare, + const std::vector& argument); + static double compute_mp3_ef(World& world, + const std::vector& pair_triangular, + const std::vector& pair_square, + const std::vector>& mo_ket, + const std::vector>& mo_bra, + const CCParameters& parameters, + const Molecule& molecule, + const Function& Rsquare, + const std::vector& argument); + static double compute_mp3_ghij(World& world, + const std::vector& pair_triangular, + const std::vector& pair_square, + const std::vector>& mo_ket, + const std::vector>& mo_bra, + const CCParameters& parameters, + const Molecule& molecule, + const Function& Rsquare, + const std::vector& argument); + static double compute_mp3_klmn(World& world, + const std::vector& pair_triangular, + const std::vector& pair_square, + const std::vector>& mo_ket, + const std::vector>& mo_bra, + const CCParameters& parameters, + const Molecule& molecule, + const Function& Rsquare, + const std::vector& argument); + }; } diff --git a/src/madness/chem/test_ccpairfunction.cc b/src/madness/chem/test_ccpairfunction.cc index 8cb1c209b78..e2c7b925074 100644 --- a/src/madness/chem/test_ccpairfunction.cc +++ b/src/madness/chem/test_ccpairfunction.cc @@ -155,7 +155,7 @@ int test_constructor(World& world, std::shared_ptr ncf MADNESS_CHECK(!p2.is_op_decomposed()); auto p = p2.pure(); auto ff = p2.pure().get_function(); - MADNESS_CHECK(!(ff.get_impl()==f.get_impl())); // deep copy of f + MADNESS_CHECK((ff.get_impl()==f.get_impl())); // shallow copy of f } t1.checkpoint(true,"checks on pure"); @@ -194,6 +194,59 @@ int test_constructor(World& world, std::shared_ptr ncf return t1.end(); } +template +int test_load_store(World& world, std::shared_ptr ncf, data& data, + const CCParameters& parameter) { + test_output t1("load/store of "); + + t1.set_cout_to_terminal(); + static_assert(NDIM%2==0, "NDIM must be even"); + constexpr std::size_t LDIM=NDIM/2; + + auto [p1,p2,p3,p4,p5]=data.get_ccpairfunctions(); // p2-p5 correspond to f23 + auto [f1,f2,f3,f4,f5,ff]=data.get_functions(); + + auto compute_diff_norm = [](const CCPairFunction& f1, const CCPairFunction f2) { + std::vector> diff; + diff+={f1}; + diff-={f2}; + double in = inner(diff,diff); + if (in<0) return -sqrt(-in); + return sqrt(in); + }; + + std::string fname="ccpairfunction_test"; + { + archive::ParallelOutputArchive ar(world, fname, 1); + ar & f1; + ar & p2; + ar & p3; + ar & p4; + ar & p5; + } + { + archive::ParallelInputArchive ar(world, fname, 1); + CCPairFunction g2, g3, g4, g5; + ar & f1; + ar & g2; + ar & g3; + ar & g4; + ar & g5; + + double n2=compute_diff_norm(g2,p2); + double n3=compute_diff_norm(g3,p3); + double n4=compute_diff_norm(g4,p4); + double n5=compute_diff_norm(g5,p5); + t1.checkpoint(n2,FunctionDefaults::get_thresh(),"store/load "+p2.name()); + t1.checkpoint(n3,FunctionDefaults::get_thresh(),"store/load "+p3.name()); + t1.checkpoint(n4,FunctionDefaults::get_thresh(),"store/load "+p4.name()); + t1.checkpoint(n5,FunctionDefaults::get_thresh(),"store/load "+p5.name()); + } + t1.checkpoint(true,"checks on load/store"); + return t1.end(); +} + + template int test_operator_apply(World& world, std::shared_ptr ncf, data& data, const CCParameters& parameter) { @@ -1267,6 +1320,7 @@ int main(int argc, char **argv) { auto data6=data(world,ccparam); isuccess+=test_constructor(world, ncf, data2, ccparam); + isuccess+=test_load_store(world,ncf,data2,ccparam); isuccess+=test_operator_apply(world, ncf, data2, ccparam); isuccess+=test_transformations(world, ncf, data2, ccparam); isuccess+=test_multiply_with_f12(world, ncf, data2, ccparam); diff --git a/src/madness/world/test_utilities.h b/src/madness/world/test_utilities.h index a1aad7c7976..f98db1eaea5 100644 --- a/src/madness/world/test_utilities.h +++ b/src/madness/world/test_utilities.h @@ -28,7 +28,7 @@ struct test_output { } ~test_output() { - set_cout_to_terminal(); + set_cout_to_terminal(false); } void print_and_clear_log() { @@ -40,7 +40,7 @@ struct test_output { void checkpoint(double error, double tol, std::string message, double time=-1.0) { bool use_logger=cout_set_to_logger; - set_cout_to_terminal(); + set_cout_to_terminal(false); bool success=error final result -->",70); success = success and final_success; double time_end=cpu_time(); @@ -121,13 +121,14 @@ struct test_output { std::cout.rdbuf(stream_buffer_file); } - void set_cout_to_terminal() { + /// newline for use by user, not for internal use (e.g. checkpoint()) + void set_cout_to_terminal(bool newline=true) { if (not cout_set_to_logger) return; if (cout_set_to_logger) { std::cout.rdbuf(stream_buffer_cout); } cout_set_to_logger=false; - std::cout << std::endl; + if (newline) std::cout << std::endl; } std::stringstream logger; From be64d32644a09c041a0b95abdd4743cebb9ffb4e Mon Sep 17 00:00:00 2001 From: fbischoff Date: Fri, 22 Mar 2024 18:22:53 +0100 Subject: [PATCH 104/109] fixing CCPairFunctions tests, failures due to the change from deep to shallow constructor from a Function --- src/madness/chem/ccpairfunction.h | 16 +++++++++++ src/madness/chem/test_ccpairfunction.cc | 38 +++++++++++++------------ src/madness/mra/mraimpl.h | 6 +++- 3 files changed, 41 insertions(+), 19 deletions(-) diff --git a/src/madness/chem/ccpairfunction.h b/src/madness/chem/ccpairfunction.h index 6154d334cb5..b9a7d671a0f 100644 --- a/src/madness/chem/ccpairfunction.h +++ b/src/madness/chem/ccpairfunction.h @@ -606,6 +606,22 @@ using pureT=Function; return component->name(transpose); } + typename Tensor::scalar_type norm2() const { + if (component->is_pure()) return pure().get_function().norm2(); + if (component->is_decomposed()) { + Function R2; + auto tmp= inner_internal(*this,R2); + typename Tensor::scalar_type result=std::real(tmp); + typename Tensor::scalar_type imag=std::imag(tmp); + if ((imag>1.e-14) or (result<-1.e-14)) { + MADNESS_EXCEPTION("bad norm in TwoBodyFunction",1); + } + return sqrt(std::abs(result)); + } + MADNESS_EXCEPTION("bad cast in TwoBodyFunction",1); + return 0.0; + } + /// multiply CCPairFunction with a 3D function of one of the two particles friend CCPairFunction multiply(const CCPairFunction& other, const Function& f, const std::array& v1) { diff --git a/src/madness/chem/test_ccpairfunction.cc b/src/madness/chem/test_ccpairfunction.cc index e2c7b925074..d1dbad93ab2 100644 --- a/src/madness/chem/test_ccpairfunction.cc +++ b/src/madness/chem/test_ccpairfunction.cc @@ -117,10 +117,10 @@ struct data { /// p5: op_pure, corresponds to f23 auto get_ccpairfunctions() { if (not is_initialized()) initialize(); - CCPairFunction p1(f12); + CCPairFunction p1(copy(f12)); CCPairFunction p2({f1,f2},{f2,f3}); CCPairFunction p3(f12_op,{f1,f2},{f2,f3}); - CCPairFunction p4(f23); // two-term, corresponds to p2 + CCPairFunction p4(copy(f23)); // two-term, corresponds to p2 CCPairFunction p5(f12_op,copy(f23)); // two-term, corresponds to p2 return std::make_tuple(p1,p2,p3,p4,p5); } @@ -143,8 +143,9 @@ int test_constructor(World& world, std::shared_ptr ncf auto f12=CCConvolutionOperatorPtr(world, OT_F12, parameter); t1.checkpoint(true,"preparation"); + auto f_copy=copy(f); CCPairFunction p1; - CCPairFunction p2(f); + CCPairFunction p2(f_copy); CCPairFunction p3({f1,f2},{f1,f3}); CCPairFunction p4(f12,{f1,f2},{f2,f3}); t1.checkpoint(true,"construction"); @@ -155,7 +156,7 @@ int test_constructor(World& world, std::shared_ptr ncf MADNESS_CHECK(!p2.is_op_decomposed()); auto p = p2.pure(); auto ff = p2.pure().get_function(); - MADNESS_CHECK((ff.get_impl()==f.get_impl())); // shallow copy of f + MADNESS_CHECK((ff.get_impl()==f_copy.get_impl())); // shallow copy of f } t1.checkpoint(true,"checks on pure"); @@ -199,7 +200,7 @@ int test_load_store(World& world, std::shared_ptr ncf, const CCParameters& parameter) { test_output t1("load/store of "); - t1.set_cout_to_terminal(); +// t1.set_cout_to_terminal(); static_assert(NDIM%2==0, "NDIM must be even"); constexpr std::size_t LDIM=NDIM/2; @@ -251,7 +252,7 @@ template int test_operator_apply(World& world, std::shared_ptr ncf, data& data, const CCParameters& parameter) { test_output t1("test_operator_apply"); - t1.set_cout_to_terminal(); +// t1.set_cout_to_terminal(); static_assert(NDIM%2==0, "NDIM must be even"); constexpr std::size_t LDIM=NDIM/2; @@ -366,7 +367,7 @@ int test_transformations(World& world, std::shared_ptr return sqrt(inner(diff,diff)); }; - CCPairFunction p1(ff); + CCPairFunction p1(copy(ff)); t1.checkpoint(p1.is_pure(),"is_pure"); t1.checkpoint(p1.is_pure_no_op(),"is_pure_no_op"); @@ -379,7 +380,7 @@ int test_transformations(World& world, std::shared_ptr t1.checkpoint(p2.is_op_pure(),"is_op_pure"); t1.checkpoint(p3.is_pure_no_op(),"is_pure_no_op"); - CCPairFunction p4(g12,ff); + CCPairFunction p4(g12,copy(ff)); t1.checkpoint(p4.is_pure(),"is_pure"); t1.checkpoint(p4.is_op_pure(),"is_op_pure"); t1.checkpoint(not p4.is_convertible_to_pure_no_op(),"not is_convertible_to_pure_no_op"); @@ -507,7 +508,7 @@ int test_inner(World& world, std::shared_ptr ncf, data test_output t1("test_inner<"+std::to_string(NDIM)+">"); static_assert(NDIM%2==0, "NDIM must be even"); constexpr std::size_t LDIM=NDIM/2; - t1.set_cout_to_terminal(); +// t1.set_cout_to_terminal(); /// f1: exp(-1.0 r^2) /// f2: exp(-2.0 r^2) @@ -590,7 +591,7 @@ int test_partial_inner_6d(World& world, std::shared_ptr"); static_assert(NDIM%2==0, "NDIM must be even"); constexpr std::size_t LDIM=NDIM/2; - t1.set_cout_to_terminal(); +// t1.set_cout_to_terminal(); // auto data=get_data<6>(world,parameter); auto [f1,f2,f3,f4,f5,f] = data.get_functions(); @@ -718,7 +719,7 @@ int test_partial_inner_3d(World& world, std::shared_ptr"); - t1.set_cout_to_terminal(); +// t1.set_cout_to_terminal(); static_assert(NDIM%2==0, "NDIM must be even"); constexpr std::size_t LDIM=NDIM/2; auto [f1,f2,f3,f4,f5,f] = data.get_functions(); @@ -735,7 +736,7 @@ int test_partial_inner_3d(World& world, std::shared_ptr(world, OT_F12, parameter); - CCPairFunction p1(f); // e(-r1 - 2r2) + CCPairFunction p1(copy(f)); // e(-r1 - 2r2) CCPairFunction p2(a,b); CCPairFunction p3(f12,a,b); CCPairFunction p11({f1},{f1}); @@ -870,7 +871,7 @@ int test_consolidate(World& world, std::shared_ptr ncf for (const auto& p : {p3}) { auto tmp=std::vector>({p}); tmp+=tmp; - t1.checkpoint(tmp.size()==1,"correct number of terms"); + t1.checkpoint(tmp.size()==2,"correct number of terms"); t1.checkpoint(tmp.front().get_a().size()==2,"correct number of vectors in a"); t1.checkpoint(tmp.front().is_op_decomposed(),"correct initial type: op_decomposed"); auto tmp1=consolidate(tmp,{"remove_lindep"}); @@ -938,7 +939,7 @@ int test_apply(World& world, std::shared_ptr ncf, data test_output t1("CCPairFunction::test_apply"); static_assert(NDIM%2==0, "NDIM must be even"); constexpr std::size_t LDIM=NDIM/2; - t1.set_cout_to_terminal(); +// t1.set_cout_to_terminal(); /// f12: exp(-r_1^2 - 2 r_2^2) /// f23: exp(-r_1^2 - 2 r_2^2) + exp(-2 r_1^2 - 3 r_2^2) @@ -994,7 +995,7 @@ int test_scalar_multiplication(World& world, std::shared_ptr p(f); + CCPairFunction p(copy(f)); CCPairFunction p1(a,b); double norm1=inner(p,p1); double pnorm=inner(p,p); @@ -1054,7 +1055,7 @@ int test_swap_particles(World& world, std::shared_ptr // test pure { - CCPairFunction p(f); + CCPairFunction p(copy(f)); CCPairFunction p_swapped=p.swap_particles(); double pnorm=p.get_function().norm2(); double psnorm=p_swapped.get_function().norm2(); @@ -1106,7 +1107,7 @@ int test_projector(World& world, std::shared_ptr ncf, constexpr std::size_t LDIM=NDIM/2; // t1.set_cout_to_logger(); - t1.set_cout_to_terminal(); +// t1.set_cout_to_terminal(); const auto [f11,f22,f3,f4,f5,f] = data.get_functions(); auto f1=copy(f11); // keep f1, f2 constant for use in other tests! auto f2=copy(f22); @@ -1129,7 +1130,7 @@ int test_projector(World& world, std::shared_ptr ncf, CCPairFunction p1(a,b); CCPairFunction p2(f12,a,b); - CCPairFunction p3(f); // outer (f1,f2) + CCPairFunction p3(copy(f)); // outer (f1,f2) std::vector> vp1({p1}); std::vector> vp2({p2}); @@ -1336,6 +1337,7 @@ int main(int argc, char **argv) { // isuccess+=test_constructor(world, ncf, data4, ccparam); +// isuccess+=test_load_store(world,ncf,data2,ccparam); // isuccess+=test_operator_apply(world, ncf, data4, ccparam); // isuccess+=test_transformations(world, ncf, data4, ccparam); // isuccess+=test_multiply_with_f12(world, ncf, data4, ccparam); diff --git a/src/madness/mra/mraimpl.h b/src/madness/mra/mraimpl.h index eff868d9b97..3e3c4e0ce69 100644 --- a/src/madness/mra/mraimpl.h +++ b/src/madness/mra/mraimpl.h @@ -2106,8 +2106,12 @@ namespace madness { } if (this->world.rank()==0) { - printf("%40s at time %.1fs: norm/tree/#coeff/size: %7.5f %zu, %6.3f m, %6.3f GByte\n", + + std::size_t bufsize=128; + char buf[bufsize]; + snprintf(buf, bufsize, "%40s at time %.1fs: norm/tree/#coeff/size: %7.5f %zu, %6.3f m, %6.3f GByte", (name.c_str()), wall, norm, tsize,double(ncoeff)*1.e-6,double(ncoeff)/fac*d); + print(std::string(buf)); } } From b4607354fcf019980341b5a0c70a2f25376e9d4f Mon Sep 17 00:00:00 2001 From: fbischoff Date: Mon, 25 Mar 2024 19:12:26 +0100 Subject: [PATCH 105/109] towards MP3 using macrotasks --- src/madness/chem/CC2.h | 2 +- src/madness/chem/CCStructures.h | 10 +++++ src/madness/chem/ccpairfunction.h | 26 +++++++++++-- src/madness/chem/mp3.cc | 18 +++++---- src/madness/mra/test_cloud.cc | 62 ------------------------------- src/madness/world/cloud.h | 56 ++++++---------------------- 6 files changed, 54 insertions(+), 120 deletions(-) diff --git a/src/madness/chem/CC2.h b/src/madness/chem/CC2.h index 9f2d23cc709..c5d13aba5c0 100644 --- a/src/madness/chem/CC2.h +++ b/src/madness/chem/CC2.h @@ -138,7 +138,7 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { double compute_mp3(const Pairs& mp2pairs) const { MP3 mp3(CCOPS); - double mp3_contribution=mp3.mp3_energy_contribution(mp2pairs); + double mp3_contribution=mp3.mp3_energy_contribution_macrotask_driver(mp2pairs); return mp3_contribution; } diff --git a/src/madness/chem/CCStructures.h b/src/madness/chem/CCStructures.h index a491a105962..e64fb0cd47a 100644 --- a/src/madness/chem/CCStructures.h +++ b/src/madness/chem/CCStructures.h @@ -840,6 +840,16 @@ struct CCConvolutionOperator { /// prints out information (operatorname, number of stored intermediates ...) size_t info() const; + friend hashT hash_value(CCConvolutionOperator& op) { + hashT h; + hash_combine(h, op.parameters.thresh_op); + hash_combine(h, op.parameters.lo); + hash_combine(h, op.parameters.freeze); + hash_combine(h, op.parameters.gamma); + hash_combine(h, int(op.type())); + return h; + } + /// sanity check .. doens not do so much void sanity() const { print_intermediate(HOLE); } diff --git a/src/madness/chem/ccpairfunction.h b/src/madness/chem/ccpairfunction.h index b9a7d671a0f..b50893abb3e 100644 --- a/src/madness/chem/ccpairfunction.h +++ b/src/madness/chem/ccpairfunction.h @@ -120,6 +120,7 @@ class TwoBodyFunctionComponentBase { virtual World& world() const =0; virtual std::shared_ptr clone() = 0; virtual ~TwoBodyFunctionComponentBase() {} + virtual hashT hash() const = 0; }; /// a two-body, explicitly 6-dimensional function @@ -186,6 +187,12 @@ class TwoBodyFunctionPureComponent : public TwoBodyFunctionComponentBase { return u; } + hashT hash() const override { + hashT h1=hash_value(u.get_impl()); + if (op) hash_combine(h1,hash_value(*op)); + return h1; + } + private: /// pure 6D function Function u; @@ -251,7 +258,18 @@ class TwoBodyFunctionSeparatedComponent : public TwoBodyFunctionComponentBase { void serialize() {} - template + hashT hash() const override { + hashT h1=0; + for (const auto& aa : a) hash_combine(h1,hash_value(aa.get_impl())); + for (const auto& bb : b) hash_combine(h1,hash_value(bb.get_impl())); + // print("hashvalue of TwoBodyFunctionSeparatedComponent: ",h1); + + if (op) hash_combine(h1,hash_value(*op)); + return h1; + } + + + template TwoBodyFunctionPureComponent apply(const SeparatedConvolution* op, const int particle=0) { MADNESS_EXCEPTION("TwoBodyFunctionPureComponent apply not yet implemented",1); } @@ -401,9 +419,9 @@ using pureT=Function; return component.get(); } - hashT hash() const { - MADNESS_EXCEPTION("no hash in CCPairFunction",1); - return hashT(); + friend hashT hash_value(const CCPairFunction& f) { + if (not f.is_assigned()) { return hashT(); } + return f.component->hash(); } private: diff --git a/src/madness/chem/mp3.cc b/src/madness/chem/mp3.cc index 8172dc38123..5acf2e258f0 100644 --- a/src/madness/chem/mp3.cc +++ b/src/madness/chem/mp3.cc @@ -726,8 +726,10 @@ double MP3::mp3_energy_contribution(const Pairs& mp2pairs) const { double MP3::mp3_energy_contribution_macrotask_driver(const Pairs& mp2pairs) const { - print_header2("computing the MP3 correlation energy, macrotask version"); - print("mp2pairs.size()",mp2pairs.allpairs.size()); + if (world.rank()==0) { + print_header2("computing the MP3 correlation energy, macrotask version"); + print("mp2pairs.size()",mp2pairs.allpairs.size()); + } // compute all ij pairs timer t2(world); @@ -757,24 +759,24 @@ double MP3::mp3_energy_contribution_macrotask_driver(const Pairs& mp2pai const std::vector& ket=mo_ket().get_vecfunction(); const std::vector& bra=mo_bra().get_vecfunction(); - - auto taskq=std::shared_ptr(new MacroTaskQ(world,world.size(),3)); + // taskq->set_printlevel(20); + // taskq->cloud.set_debug(true); MacroTaskMP3 task; MacroTask macrotask(world,task,taskq); - taskq->print_taskq(); -// auto cd_future=macrotask(std::string("cd"), ij_vec, clusterfunc_vec, ket, bra, parameters, nemo_->molecule(), nemo_->R_square, std::vector()); + auto cd_future=macrotask(std::string("cd"), ij_vec, clusterfunc_vec, ket, bra, parameters, nemo_->molecule(), nemo_->R_square, std::vector()); // auto ef_future=macrotask("ef", mp2pairs, clusterfunctions, mo_ket(), mo_bra(), parameters, nemo_->molecule(), nemo_->R_square, std::vector()); // auto ghij_future=macrotask("ghij", mp2pairs, clusterfunctions, mo_ket(), mo_bra(), parameters, nemo_->molecule(), nemo_->R_square, std::vector()); // auto klmn_future=macrotask("klmn", mp2pairs, clusterfunctions, mo_ket(), mo_bra(), parameters, nemo_->molecule(), nemo_->R_square, std::vector()); + taskq->print_taskq(); taskq->run_all(); -// double term_CD=cd_future->get(); + double term_CD=cd_future->get(); // double term_EF=ef_future->get(); // double term_GHIJ=ghij_future->get(); // double term_KLMN=klmn_future->get(); -// printf("term_CD %12.8f\n",term_CD); + printf("term_CD %12.8f\n",term_CD); // printf("term_GHIJ %12.8f\n",term_GHIJ); // printf("term_KLMN %12.8f\n",term_KLMN); // printf("term_EF %12.8f\n",term_EF); diff --git a/src/madness/mra/test_cloud.cc b/src/madness/mra/test_cloud.cc index 06aa7ac2ece..b421e8b1efa 100644 --- a/src/madness/mra/test_cloud.cc +++ b/src/madness/mra/test_cloud.cc @@ -299,68 +299,6 @@ int main(int argc, char **argv) { cloud.set_force_load_from_cache(false); } - - // test storing WorldContainer - test_output test_worldcontainer("testing worldcontainer"); - test_worldcontainer.set_cout_to_terminal(); - cloud.set_debug(false); - typedef WorldContainer result_container; - result_container ad(universe); - ad.replace(0,1.0); - auto adrecords = cloud.store(universe, ad); - { - MacroTaskQ::set_pmap(subworld); - - cloud.set_force_load_from_cache(false); - auto t2 = cloud.load(subworld, adrecords); - cloud.set_force_load_from_cache(true); - auto t3 = cloud.load(subworld, adrecords); - double d1=ad.find(0).get()->second; - double d2=t2.find(0).get()->second; - double d3=t3.find(0).get()->second; - std::cout << "array_double " << d1 << " " << d2 << " " << d3 << std::endl; - double error=d1-d2; - success += test_worldcontainer.end(error < 1.e-10 ); - cloud.set_force_load_from_cache(false); - } - - // test pointer to WorldContainer - if constexpr (0) { - typedef std::shared_ptr::implT> impl_ptrT; - auto p1 = std::shared_ptr>(new WorldContainer(universe)); - p1->replace(0,1.5); - auto precords = cloud.store(universe, p1); - - { - test_output test_dc_ptr("testing cloud/shared_ptr in world " + std::to_string(subworld.id())); - test_dc_ptr.set_cout_to_terminal(); - MacroTaskQ::set_pmap(subworld); - - auto p3 = cloud.load>>(subworld, precords); - auto p4 = cloud.load>>(subworld, precords); - auto p5 = cloud.load>>(subworld, precords); - std::cout << "p1/p2/p3/p4" << " " << p1.get() << " " << p3.get() << " " << p4.get() << " " - << p5.get() << std::endl; - test_dc_ptr.end(p1 == p3 && p1 == p4 && p1 == p5 - && p1->get_world().id() == p3->get_world().id() - && p1->get_world().id() == p4->get_world().id() - && p1->get_world().id() == p5->get_world().id()); - double d3=p3->find(0).get()->second; - double d4=p4->find(0).get()->second; - double d5=p5->find(0).get()->second; - - MacroTaskQ::set_pmap(universe); - cloud.clear_cache(subworld); - } - subworld.gop.fence(); - universe.gop.fence(); - test_output test_dc_ptr("testing cloud/shared_ptr numerics in universe"); - double ffnorm = ff.norm2(); - test_dc_ptr.end((ffnorm < 1.e-10)); - universe.gop.fence(); - } - - // test storing twice (using cache) { cloud.clear_timings(); diff --git a/src/madness/world/cloud.h b/src/madness/world/cloud.h index 6c08d6e69d3..aba5f36ad38 100644 --- a/src/madness/world/cloud.h +++ b/src/madness/world/cloud.h @@ -246,7 +246,7 @@ class Cloud { if constexpr (is_tuple::value) { return load_tuple(world, rlist); } else { - return load_internal(world, rlist); + return load_other(world, rlist); } } @@ -378,23 +378,6 @@ class Cloud { return target; } - template - T load_internal(madness::World &world, recordlistT &recordlist) const { -// T result; - if constexpr (is_vector::value) { - if constexpr( is_parallel_serializable_object::value) { -// result = load_vector_of_parallel_serializable_objects(world, recordlist); - return load_vector_of_parallel_serializable_objects(world, recordlist); - } else { -// result = load_other(world, recordlist); - return load_vector_other(world, recordlist); - } - } else { -// result = load_other(world, recordlist); - return load_other(world, recordlist); - } - } - bool is_cached(const keyT &key) const { return (cached_objects.count(key) == 1); } @@ -424,6 +407,10 @@ class Cloud { bool is_already_present= is_in_container(record); if (debug) { if (is_already_present) std::cout << "skipping "; + std::string msg; + if constexpr (Recordlist::has_member_id::value) { + std::cout << "storing world object of " << typeid(T).name() << "id " << source.id() << " to record " << record << std::endl; + } std::cout << "storing object of " << typeid(T).name() << " to record " << record << std::endl; } @@ -441,7 +428,8 @@ class Cloud { } template - T load_vector_other(World &world, recordlistT &recordlist) const { + typename std::enable_if::value, T>::type + load_other(World &world, recordlistT &recordlist) const { std::size_t sz = load_other(world, recordlist); T target(sz); for (std::size_t i = 0; i < sz; ++i) { @@ -451,7 +439,8 @@ class Cloud { } template - T load_other(World &world, recordlistT &recordlist) const { + typename std::enable_if::value, T>::type + load_other(World &world, recordlistT &recordlist) const { keyT record = recordlist.pop_front_and_return(); if (force_load_from_cache) MADNESS_CHECK(is_cached(record)); @@ -467,39 +456,16 @@ class Cloud { // overloaded template -// std::enable_if_t::value, recordlistT> recordlistT store_other(madness::World& world, const std::vector& source) { if (debug) std::cout << "storing " << typeid(source).name() << " of size " << source.size() << std::endl; recordlistT l = store_other(world, source.size()); - for (auto s : source) l += store_other(world, s); + for (const auto& s : source) l += store_other(world, s); if (dofence) world.gop.fence(); if (debug) std::cout << "done with vector storing; container size " << container.size() << std::endl; return l; } -// // overloaded -// template -// recordlistT store_other(madness::World &world, const std::vector> &source) { -// if (debug) -// std::cout << "storing " << typeid(source).name() << " of size " << source.size() << std::endl; -// recordlistT l = store_other(world, source.size()); -// for (auto s : source) l += store_other(world, s); -// if (dofence) world.gop.fence(); -// if (debug) std::cout << "done with vector storing; container size " << container.size() << std::endl; -// return l; -// } - - template - T load_vector_of_parallel_serializable_objects(World &world, recordlistT &recordlist) const { - std::size_t sz = load_other(world, recordlist); - T target(sz); - for (std::size_t i = 0; i < sz; ++i) { - target[i] = load_other(world, recordlist); - } - return target; - } - /// store a tuple in multiple records template recordlistT store_tuple(World &world, const std::tuple &input) { @@ -519,7 +485,7 @@ class Cloud { if (debug) std::cout << "loading tuple of type " << typeid(T).name() << " to world " << world.id() << std::endl; T target; std::apply([&](auto &&... args) { - ((args = load_internal::type>(world, recordlist)), ...); + ((args = load_other::type>(world, recordlist)), ...); }, target); return target; } From 762eb6c9f97fef58c446e999f96f08ad4b34c0fc Mon Sep 17 00:00:00 2001 From: fbischoff Date: Sat, 30 Mar 2024 16:52:32 +0100 Subject: [PATCH 106/109] only rank==0 writes to json --- src/madness/chem/CC2.cc | 14 ++++++----- src/madness/chem/SCF.cc | 52 +++++++++++++++++++++-------------------- 2 files changed, 35 insertions(+), 31 deletions(-) diff --git a/src/madness/chem/CC2.cc b/src/madness/chem/CC2.cc index c8d24835f9c..d54f9b73708 100644 --- a/src/madness/chem/CC2.cc +++ b/src/madness/chem/CC2.cc @@ -303,12 +303,14 @@ CC2::solve() { } void CC2::output_calc_info_schema(const std::string model, const double& energy) const { - nlohmann::json j; - j["model"]=model; - j["driver"]="energy"; - j["return_energy"]=energy; - j["mp2_correlation_energy"]=energy; - update_schema(nemo->get_param().prefix()+".calc_info", j); + if (world.rank()==0) { + nlohmann::json j; + j["model"]=model; + j["driver"]="energy"; + j["return_energy"]=energy; + j["mp2_correlation_energy"]=energy; + update_schema(nemo->get_param().prefix()+".calc_info", j); + } } diff --git a/src/madness/chem/SCF.cc b/src/madness/chem/SCF.cc index 4c2ed155da2..dbd3c68e0db 100644 --- a/src/madness/chem/SCF.cc +++ b/src/madness/chem/SCF.cc @@ -157,33 +157,35 @@ tensorT Q2(const tensorT& s) { void SCF::output_calc_info_schema() const { nlohmann::json j = {}; - vec_pair_ints int_vals; - vec_pair_T double_vals; - vec_pair_tensor_T double_tensor_vals; - - - int_vals.emplace_back("calcinfo_nmo", param.nmo_alpha() + param.nmo_beta()); - int_vals.emplace_back("calcinfo_nalpha", param.nalpha()); - int_vals.emplace_back("calcinfo_nbeta", param.nbeta()); - int_vals.emplace_back("calcinfo_natom", molecule.natom()); - int_vals.emplace_back("k", FunctionDefaults<3>::get_k()); - - to_json(j, int_vals); -// double_vals.push_back({"return_energy", value(molecule.get_all_coords().flat())}); - double_vals.emplace_back("return_energy", current_energy); - to_json(j, double_vals); - double_tensor_vals.emplace_back("scf_eigenvalues_a", aeps); - if (param.nbeta() != 0 && !param.spin_restricted()) { - double_tensor_vals.emplace_back("scf_eigenvalues_b", beps); - } + World& world=amo.front().world(); + if (world.rank()==0) { + vec_pair_ints int_vals; + vec_pair_T double_vals; + vec_pair_tensor_T double_tensor_vals; + + + int_vals.emplace_back("calcinfo_nmo", param.nmo_alpha() + param.nmo_beta()); + int_vals.emplace_back("calcinfo_nalpha", param.nalpha()); + int_vals.emplace_back("calcinfo_nbeta", param.nbeta()); + int_vals.emplace_back("calcinfo_natom", molecule.natom()); + int_vals.emplace_back("k", FunctionDefaults<3>::get_k()); + + to_json(j, int_vals); + // double_vals.push_back({"return_energy", value(molecule.get_all_coords().flat())}); + double_vals.emplace_back("return_energy", current_energy); + to_json(j, double_vals); + double_tensor_vals.emplace_back("scf_eigenvalues_a", aeps); + if (param.nbeta() != 0 && !param.spin_restricted()) { + double_tensor_vals.emplace_back("scf_eigenvalues_b", beps); + } - to_json(j, double_tensor_vals); - param.to_json(j); - e_data.to_json(j); + to_json(j, double_tensor_vals); + param.to_json(j); + e_data.to_json(j); -// output_schema(param.prefix()+".calc_info", j); - World& world=amo.front().world(); - if (world.rank()==0) update_schema(param.prefix()+".calc_info", j); + // output_schema(param.prefix()+".calc_info", j); + update_schema(param.prefix()+".calc_info", j); + } } void scf_data::add_data(std::map values) { From 6ed896fdf4fea927626c377598b1b11a13037913 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Sat, 30 Mar 2024 16:57:47 +0100 Subject: [PATCH 107/109] nearly done with mp3 macrotasks, ghij term still wrong --- src/madness/chem/ccpairfunction.cc | 6 +- src/madness/chem/lowrankfunction.h | 1 + src/madness/chem/mp3.cc | 253 +++++++++++++++++++++++++---- src/madness/chem/mp3.h | 96 +++++++---- 4 files changed, 289 insertions(+), 67 deletions(-) diff --git a/src/madness/chem/ccpairfunction.cc b/src/madness/chem/ccpairfunction.cc index 2bda14f8558..91f186e4ad2 100644 --- a/src/madness/chem/ccpairfunction.cc +++ b/src/madness/chem/ccpairfunction.cc @@ -77,9 +77,13 @@ template std::vector> CCPairFunction::op_dec_to_dec(const std::vector>& other, const std::vector::LDIM>>& centers) { LowRankFunctionParameters lrparameters; + lrparameters.set_derived_value("tol",1.e-10); auto builder = LowRankFunctionFactory(lrparameters,centers); // builder.set_volume_element(3.e-2); -// builder.parameters.print("lrparameters"); + if (other.front().world().rank()==0) { + builder.parameters.print("lrparameters"); + print("centers",centers); + } std::vector> result; for (const auto& c : other) { if (c.is_op_decomposed()) { diff --git a/src/madness/chem/lowrankfunction.h b/src/madness/chem/lowrankfunction.h index a175277c30c..10b2aeff235 100644 --- a/src/madness/chem/lowrankfunction.h +++ b/src/madness/chem/lowrankfunction.h @@ -1009,6 +1009,7 @@ struct LRFunctorPure : public LRFunctorBase { } else { grid=rgrid.get_grid(); } + if (world.rank()==0) print("grid size",grid.size()); auto Y=Yformer(lrfunctor,grid,parameters.rhsfunctiontype()); t1.tag("Yforming"); diff --git a/src/madness/chem/mp3.cc b/src/madness/chem/mp3.cc index 5acf2e258f0..f1702067328 100644 --- a/src/madness/chem/mp3.cc +++ b/src/madness/chem/mp3.cc @@ -661,24 +661,210 @@ double MP3::compute_mp3_cd(World& world, const Molecule& molecule, const Function& Rsquare, const std::vector& argument) { - print_header2("entering compute_mp3_cd"); CCConvolutionOperator::Parameters cparam(parameters); auto g12=CCConvolutionOperatorPtr(world,OpType::OT_G12,cparam); - double result = 0.0; -// for (int i = parameters.freeze(); i < nocc; ++i) { -// for (int j = i; j < nocc; ++j) { - auto bra = pair_square(i, j); - double tmp1 = inner(bra, g12 * pair_square(i, j), Rsquare); - double tmp2 = inner(bra, g12 * pair_square(j, i), Rsquare); - double fac = (i == j) ? 0.5 : 1.0; - double tmp = fac * (4.0 * tmp1 - 2.0 * tmp2); - printf("mp3 energy: term_CD %2ld %2ld: %12.8f\n", i, j, tmp); - result+= tmp; -// } -// } - printf("MP3 energy: term_CD %12.8f\n", result); + auto bra = pair_square(i, j); + double tmp1 = inner(bra, g12 * pair_square(i, j), Rsquare); + double tmp2 = inner(bra, g12 * pair_square(j, i), Rsquare); + double fac = (i == j) ? 0.5 : 1.0; + double result = fac * (4.0 * tmp1 - 2.0 * tmp2); + printf("mp3 energy: term_CD %2ld %2ld: %12.8f\n", i, j, result); + return result; +} + +double MP3::compute_mp3_ef(World& world, + const long i, const long j, + const Pairs>>& pair_square, + const std::vector>& mo_ket, + const std::vector>& mo_bra, + const CCParameters& parameters, + const Molecule& molecule, + const Function& Rsquare, + const std::vector& argument) { + + CCConvolutionOperator::Parameters cparam; + auto g12=CCConvolutionOperatorPtr(world,OpType::OT_G12,cparam); + + int nfrozen=parameters.freeze(); + int nocc=mo_ket.size(); + + /// = (ik | jl) + std::vector all_tau_permutations; + std::vector> tmp_tau; + + // loop over all k and l + for (int k=nfrozen; k (2* - ) + // = (2*(ik|jl) - (jk|il)) + const auto& ket_i=mo_ket[i]; + const auto& ket_k=mo_ket[k]; + const auto& ket_l=mo_ket[l]; + const auto& bra_i=mo_bra[i]; + const auto& bra_j=mo_bra[j]; + const auto& bra_l=mo_bra[l]; + double g_ikjl=inner(bra_i*ket_k, (*g12)(bra_j*ket_l)); + double g_jkil=inner(bra_j*ket_k, (*g12)(bra_l*ket_i)); + tmp_tau+=weight*(2.0* g_ikjl - g_jkil)*pair_square(k,l); + } + } + tmp_tau=consolidate(tmp_tau,{"remove_lindep"}); + double result=inner(pair_square(i,j),tmp_tau,Rsquare); + printf("mp3 energy: term_EF %2ld %2ld %12.8f\n",i,j,result); + + // can't do sanity check, because we are working on a single pair +// int npermutations=all_tau_permutations.size(); +// all_tau_permutations=permutation::remove_duplicates(all_tau_permutations); +// int nuniquepermutations=all_tau_permutations.size(); +// int ntotalpermutations=std::pow(nocc-nfrozen,4); +// MADNESS_CHECK_THROW(npermutations==nuniquepermutations,"incorrect number of unique permutations"); +// MADNESS_CHECK_THROW(npermutations==ntotalpermutations,"incorrect number of unique permutations"); + + return result; +} + +double MP3::compute_mp3_ghij(World& world, + const long i, const long jj, + const Pairs>>& pair_square, + const std::vector>& mo_ket, + const std::vector>& mo_bra, + const CCParameters& parameters, + const Molecule& molecule, + const Function& Rsquare, + const std::vector& argument) { + + // this scales linearly, use only the diagaonal contributions + if (i!=jj) return 0.0; + + print_header3("entering compute_mp3_ghij_fast"); + + // prepare cluster functions + std::size_t nocc=mo_ket.size(); + typedef std::vector> ClusterFunction; + double result=0.0; + + CCConvolutionOperator::Parameters cparam; + auto g12=CCConvolutionOperatorPtr(world,OpType::OT_G12,cparam); + + timer t2(world); + + // compute intermediates for terms G, I, H, and J + + // \sum_j tau_ij(1,2) * phi_j(2) + ClusterFunction tau_kk_i; + // \sum_j tau_ij(1,2) * phi_j(1) + ClusterFunction tau_ij_j; + + for (int j = parameters.freeze(); j < nocc; ++j) { + // auto tmp2 = multiply(pair_square(i, j), mo_bra[i], {0, 1, 2}); + // for (auto& t: tmp2) tau_kk_i[j].push_back(t); + auto tmp2 = multiply(pair_square(i, j), mo_bra[j], {3, 4, 5}); + for (auto& t: tmp2) tau_kk_i.push_back(t); + + auto tmp3 = multiply(pair_square(i, j), mo_bra[j], {0, 1, 2}); + for (auto& t: tmp3) tau_ij_j.push_back(t); + } + + // std::vector consolidation={"op_pure_to_pure","remove_lindep","op_dec_to_dec"}; + std::vector consolidation={"op_pure_to_pure","remove_lindep","op_dec_to_pure"}; + print("consolidating with ",consolidation); + ClusterFunction intermediate; + // for (int i = parameters.freeze(); i < nocc; ++i) { + intermediate=2.0*tau_kk_i; + intermediate-=tau_ij_j; + intermediate=consolidate(intermediate,consolidation,molecule.get_all_coords_vec()); + // } + + t2.tag("GHIJ term prep"); + + // terms G, I, H, J of Bartlett/Silver 1975 + real_convolution_3d& g = *(g12->get_op()); + g.set_particle(1); + // for (int i = parameters.freeze(); i < nocc; ++i) { + // tmp(1,2) = g(1,1') | tau_ij(1',2) j(2) > + timer t4(world, "gtau"); + auto gintermediate = g(intermediate); + t4.tag("compute gintermediate"); + auto bra_intermediate = multiply(intermediate, Rsquare, {3, 4, 5}); + t4.tag("multiply"); + double tmp = 2.0*inner(bra_intermediate, gintermediate); + printf("mp3 energy: term_GHIJ %2ld %12.8f\n", i, tmp); + t4.tag("inner"); + result += tmp; + // } + t2.tag("GHIJ term"); + return result; +} + + +double MP3::compute_mp3_klmn(World& world, + const long i, const long j, + const Pairs>>& pair_square, + const std::vector>& mo_ket, + const std::vector>& mo_bra, + const CCParameters& parameters, + const Molecule& molecule, + const Function& Rsquare, + const std::vector& argument) { + + // prepare cluster functions + std::size_t nocc=mo_ket.size(); + typedef std::vector> ClusterFunction; + double result=0.0; + + CCConvolutionOperator::Parameters cparam; + auto g12=CCConvolutionOperatorPtr(world,OpType::OT_G12,cparam); + + // compute the term (2) + madness::Pairs gij; + + for (int k = parameters.freeze(); k < nocc; ++k) { + for (int l = parameters.freeze(); l < nocc; ++l) { + gij.insert(k,l,(*g12)(mo_ket[k]*mo_bra[l])); + } + } + + + timer multiply_KLMN(world, "multiplication in KLMN term"); + multiply_KLMN.interrupt(); + timer inner_KLMN(world, "inner in KLMN term"); + inner_KLMN.interrupt(); + + // for (int i = parameters.freeze(); i < nocc; ++i) { + // for (int j = parameters.freeze(); j < nocc; ++j) { + multiply_KLMN.resume(); + std::vector> rhs; + for (int k = parameters.freeze(); k < nocc; ++k) { + rhs += +2.0 * multiply(pair_square(j, k), gij(k, i), {0, 1, 2}); // M + rhs += +2.0 * multiply(pair_square(k, i), gij(k, j), {0, 1, 2}); // N + rhs += -4.0 * multiply(pair_square(i, k), gij(k, j), {3, 4, 5}); // K + rhs += -4.0 * multiply(pair_square(k, j), gij(k, i), {3, 4, 5}); // L + } + rhs = consolidate(rhs, {}); + multiply_KLMN.interrupt(); + + inner_KLMN.resume(); + double tmp = inner(pair_square(i, j), rhs, Rsquare); + inner_KLMN.interrupt(); + + printf("mp3 energy: term_KLMN with particle=1 %2ld %2ld %12.8f\n", i, j, tmp); + result += tmp; + // } + // } + multiply_KLMN.print("multiplication in KLMN term"); + inner_KLMN.print("inner in KLMN term"); + return result; } @@ -752,8 +938,12 @@ double MP3::mp3_energy_contribution_macrotask_driver(const Pairs& mp2pai t2.tag("make cluster functions"); - // create dummy scheduling vector of length npair=nocc*(nocc+1)/2, for the macrotask scheduler - std::vector ij_vec(mp2pairs.allpairs.size()); + // create dummy scheduling vector of length npair=nocc*(nocc+1)/2, for the macrotask scheduler, triangular form + std::vector ij_triangular(mp2pairs.allpairs.size()); + // create dummy scheduling vector of length nact for the macrotask scheduler, square form + std::vector nact(nocc-parameters.freeze()); + std::vector dummy; + // get mos const std::vector& ket=mo_ket().get_vecfunction(); @@ -762,28 +952,29 @@ double MP3::mp3_energy_contribution_macrotask_driver(const Pairs& mp2pai auto taskq=std::shared_ptr(new MacroTaskQ(world,world.size(),3)); // taskq->set_printlevel(20); // taskq->cloud.set_debug(true); - MacroTaskMP3 task; - MacroTask macrotask(world,task,taskq); - auto cd_future=macrotask(std::string("cd"), ij_vec, clusterfunc_vec, ket, bra, parameters, nemo_->molecule(), nemo_->R_square, std::vector()); -// auto ef_future=macrotask("ef", mp2pairs, clusterfunctions, mo_ket(), mo_bra(), parameters, nemo_->molecule(), nemo_->R_square, std::vector()); -// auto ghij_future=macrotask("ghij", mp2pairs, clusterfunctions, mo_ket(), mo_bra(), parameters, nemo_->molecule(), nemo_->R_square, std::vector()); -// auto klmn_future=macrotask("klmn", mp2pairs, clusterfunctions, mo_ket(), mo_bra(), parameters, nemo_->molecule(), nemo_->R_square, std::vector()); + MacroTaskMP3 task_triangular("triangular"); + MacroTaskMP3 task_square("square"); + MacroTask macrotask_triangular(world,task_triangular,taskq); + MacroTask macrotask_square(world,task_square,taskq); + auto ghij_future=macrotask_triangular(std::string("ghij"), ij_triangular, dummy, clusterfunc_vec, ket, bra, parameters, nemo_->molecule(), nemo_->R_square, std::vector()); + auto klmn_future=macrotask_square(std::string("klmn"), nact, nact, clusterfunc_vec, ket, bra, parameters, nemo_->molecule(), nemo_->R_square, std::vector()); + auto cd_future=macrotask_triangular(std::string("cd"), ij_triangular, dummy, clusterfunc_vec, ket, bra, parameters, nemo_->molecule(), nemo_->R_square, std::vector()); + auto ef_future=macrotask_triangular(std::string("ef"), ij_triangular, dummy, clusterfunc_vec, ket, bra, parameters, nemo_->molecule(), nemo_->R_square, std::vector()); taskq->print_taskq(); taskq->run_all(); double term_CD=cd_future->get(); -// double term_EF=ef_future->get(); -// double term_GHIJ=ghij_future->get(); -// double term_KLMN=klmn_future->get(); + double term_EF=ef_future->get(); + double term_GHIJ=ghij_future->get(); + double term_KLMN=klmn_future->get(); printf("term_CD %12.8f\n",term_CD); -// printf("term_GHIJ %12.8f\n",term_GHIJ); -// printf("term_KLMN %12.8f\n",term_KLMN); -// printf("term_EF %12.8f\n",term_EF); -// double mp3_energy=term_CD+term_GHIJ+term_KLMN+term_EF; -// double mp3_energy=term_CD; - double mp3_energy=-1.0; + printf("term_GHIJ %12.8f\n",term_GHIJ); + printf("term_KLMN %12.8f\n",term_KLMN); + printf("term_EF %12.8f\n",term_EF); + double mp3_energy=term_CD+term_GHIJ+term_KLMN+term_EF; printf("MP3 energy contribution %12.8f\n",mp3_energy); return mp3_energy; + // return 0.0; } } diff --git a/src/madness/chem/mp3.h b/src/madness/chem/mp3.h index d68c9dea7b8..3c0a7328c15 100644 --- a/src/madness/chem/mp3.h +++ b/src/madness/chem/mp3.h @@ -34,27 +34,29 @@ class MP3 : public CCPotentials { /// helper class for calculating the MP3 energy contributions class MacroTaskMP3 : public MacroTaskOperationBase { - class ConstantPartPartitioner : public MacroTaskPartitioner { + class Partitioner : public MacroTaskPartitioner { public: - ConstantPartPartitioner() {}; - - partitionT do_partitioning(const std::size_t& vsize1, const std::size_t& vsize2, - const std::string policy) const override { - partitionT p; - for (size_t i = 0; i < vsize1; i++) { - Batch batch(Batch_1D(i,i+1), Batch_1D(i,i+1)); - p.push_back(std::make_pair(batch,1.0)); + Partitioner(const std::string shape) { + min_batch_size=1; + max_batch_size=1; + if (shape=="triangular") dimension=1; + else if (shape=="square") dimension=2; + else { + std::string msg = "Unknown partitioning shape: " + shape; + MADNESS_EXCEPTION(msg.c_str(), 1); } - return p; - } + }; }; public: - MacroTaskMP3(){partitioner.reset(new ConstantPartPartitioner());} + MacroTaskMP3(const std::string shape) { + partitioner.reset(new Partitioner(shape)); + } typedef std::tuple< const std::string&, - const std::vector&, + const std::vector&, // dummy vector of size npair or nocc for scheduling + const std::vector&, // dummy vector of size npair or nocc for scheduling const std::vector>>& , // all pairs ij const std::vector>&, const std::vector>&, @@ -70,7 +72,8 @@ class MP3 : public CCPotentials { } resultT operator() (const std::string& diagram, // which diagram to calculate - const std::vector& ij_vec, // dummy vector of size npair + const std::vector& ij_vec, // dummy vector of size npair or nocc + const std::vector& j_vec, // dummy vector of size 0 or nocc const std::vector>>& pair_square, // all pairs ij const std::vector>& mo_ket, // the orbitals const std::vector>& mo_bra, // the orbitals*R2 @@ -81,21 +84,35 @@ class MP3 : public CCPotentials { // the partitioner will break the input vector of pairs into single pairs MADNESS_CHECK(ij_vec.size()==1); + MADNESS_CHECK(batch.result.size()==1); - // determine the orbital indices i and j for the pair - // active occupied orbitals, the total length of pair_triangular is nact*(nact+1) + // nact=active occupied orbitals const long nact=mo_ket.size()-parameters.freeze(); MADNESS_CHECK(pair_square.size()==nact*nact); - // the batch index is the ij composite index [0,nact*(nact+1)-1] - const long ij=batch.result.begin; - MADNESS_CHECK(batch.result.size()==1); + // loop over pairs idimension==1); - // turn composite index ij into i and j, taking care of frozen orbitals - PairVectorMap tri_map=PairVectorMap::triangular_map(parameters.freeze(),mo_ket.size()); - auto ij_to_i_and_j = [&tri_map](const int ij) { return tri_map.map[ij]; }; - auto [i,j]=ij_to_i_and_j(ij); + // determine the orbital indices i and j for the pair + int i=0, j=0; + if (is_triangular) { + // the batch index is the ij composite index [0,nact*(nact+1)-1] + const long ij=batch.result.begin; + // turn composite index ij into i and j, taking care of frozen orbitals + PairVectorMap tri_map=PairVectorMap::triangular_map(parameters.freeze(),mo_ket.size()); + auto ij_to_i_and_j = [&tri_map](const int ij) { return tri_map.map[ij]; }; + auto [ii,jj]=ij_to_i_and_j(ij); + i=ii; + j=jj; + } else { + MADNESS_CHECK(partitioner->dimension==2); + MADNESS_CHECK(j_vec.size()==ij_vec.size()); + i=batch.input[0].begin; + j=batch.input[1].begin; + } + // convert vector of vectors back to Pairs PairVectorMap square_map=PairVectorMap::quadratic_map(parameters.freeze(),mo_ket.size()); auto clusterfunctions=Pairs>>::vector2pairs(pair_square,square_map); @@ -103,12 +120,12 @@ class MP3 : public CCPotentials { World& world=Rsquare.world(); if (diagram=="cd") result= MP3::compute_mp3_cd(world,i,j,clusterfunctions,mo_ket,mo_bra,parameters,molecule,Rsquare,argument); -// else if (diagram=="ef") -// result= MP3::compute_mp3_ef(pair_triangular,pair_square,mo_ket,mo_bra,parameters,molecule,Rsquare,argument); -// else if (diagram=="ghij") -// result= MP3::compute_mp3_ghij(pair_triangular,pair_square,mo_ket,mo_bra,parameters,molecule,Rsquare,argument); -// else if (diagram=="klmn") -// result= MP3::compute_mp3_klmn(pair_triangular,pair_square,mo_ket,mo_bra,parameters,molecule,Rsquare,argument); + else if (diagram=="ef") + result= MP3::compute_mp3_ef(world,i,j,clusterfunctions,mo_ket,mo_bra,parameters,molecule,Rsquare,argument); + else if (diagram=="ghij") + result= MP3::compute_mp3_ghij(world,i,j,clusterfunctions,mo_ket,mo_bra,parameters,molecule,Rsquare,argument); + else if (diagram=="klmn") + result= MP3::compute_mp3_klmn(world,i,j,clusterfunctions,mo_ket,mo_bra,parameters,molecule,Rsquare,argument); else { std::string msg = "Unknown MP3 diagram: " + diagram; MADNESS_EXCEPTION(msg.c_str(), 1); @@ -134,6 +151,7 @@ class MP3 : public CCPotentials { double compute_mp3_klmn_fast(const Pairs& mp2pairs) const; double mp3_test(const Pairs& mp2pairs, const Pairs>> clusterfunctions) const; + /// compute the cd term for single pair ij static double compute_mp3_cd(World& world, const long i, const long j, const Pairs>>& pair_square, @@ -143,27 +161,35 @@ class MP3 : public CCPotentials { const Molecule& molecule, const Function& Rsquare, const std::vector& argument); + + /// compute the ef term for single pair ij static double compute_mp3_ef(World& world, - const std::vector& pair_triangular, - const std::vector& pair_square, + const long i, const long j, + const Pairs>>& pair_square, const std::vector>& mo_ket, const std::vector>& mo_bra, const CCParameters& parameters, const Molecule& molecule, const Function& Rsquare, const std::vector& argument); + + /// compute the ghij term for single pair ij + /// + /// the term actually scales linearly with the number of occupied orbitals i, so for all i!=j return zero static double compute_mp3_ghij(World& world, - const std::vector& pair_triangular, - const std::vector& pair_square, + const long i, const long j, + const Pairs>>& pair_square, const std::vector>& mo_ket, const std::vector>& mo_bra, const CCParameters& parameters, const Molecule& molecule, const Function& Rsquare, const std::vector& argument); + + /// compute the klmn term for single pair ij static double compute_mp3_klmn(World& world, - const std::vector& pair_triangular, - const std::vector& pair_square, + const long i, const long j, + const Pairs>>& pair_square, const std::vector>& mo_ket, const std::vector>& mo_bra, const CCParameters& parameters, From e33c946d863cd5f05c61d06d2ff5dcc1a2818289 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Sat, 30 Mar 2024 23:07:28 +0100 Subject: [PATCH 108/109] ghij presumably working, frozen orbitals still incorrect --- src/madness/chem/mp3.cc | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/madness/chem/mp3.cc b/src/madness/chem/mp3.cc index f1702067328..76c0e7d3e51 100644 --- a/src/madness/chem/mp3.cc +++ b/src/madness/chem/mp3.cc @@ -766,18 +766,22 @@ double MP3::compute_mp3_ghij(World& world, // \sum_j tau_ij(1,2) * phi_j(1) ClusterFunction tau_ij_j; - for (int j = parameters.freeze(); j < nocc; ++j) { - // auto tmp2 = multiply(pair_square(i, j), mo_bra[i], {0, 1, 2}); - // for (auto& t: tmp2) tau_kk_i[j].push_back(t); - auto tmp2 = multiply(pair_square(i, j), mo_bra[j], {3, 4, 5}); - for (auto& t: tmp2) tau_kk_i.push_back(t); - - auto tmp3 = multiply(pair_square(i, j), mo_bra[j], {0, 1, 2}); - for (auto& t: tmp3) tau_ij_j.push_back(t); + for (int ii = parameters.freeze(); ii < nocc; ++ii) { + // for (int j = parameters.freeze(); j < nocc; ++j) { + auto tmp2 = multiply(pair_square(ii, i), mo_bra[ii], {0, 1, 2}); + for (auto& t: tmp2) tau_kk_i.push_back(t); + // } } - // std::vector consolidation={"op_pure_to_pure","remove_lindep","op_dec_to_dec"}; - std::vector consolidation={"op_pure_to_pure","remove_lindep","op_dec_to_pure"}; + // for (int i = parameters.freeze(); i < nocc; ++i) { + for (int j = parameters.freeze(); j < nocc; ++j) { + auto tmp3 = multiply(pair_square(i, j), mo_bra[j], {0, 1, 2}); + for (auto& t: tmp3) tau_ij_j.push_back(t); + } + // } + + std::vector consolidation={"op_pure_to_pure","remove_lindep","op_dec_to_dec"}; + // std::vector consolidation={"op_pure_to_pure","remove_lindep","op_dec_to_pure"}; print("consolidating with ",consolidation); ClusterFunction intermediate; // for (int i = parameters.freeze(); i < nocc; ++i) { From b7a0824bc86af2beed31e3217d550540e00ce972 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Tue, 2 Apr 2024 09:38:59 +0200 Subject: [PATCH 109/109] mp3 working with macrotasks and frozen core --- src/madness/chem/mp3.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/madness/chem/mp3.h b/src/madness/chem/mp3.h index 3c0a7328c15..b31c4eb27e2 100644 --- a/src/madness/chem/mp3.h +++ b/src/madness/chem/mp3.h @@ -108,9 +108,10 @@ class MP3 : public CCPotentials { } else { MADNESS_CHECK(partitioner->dimension==2); MADNESS_CHECK(j_vec.size()==ij_vec.size()); - i=batch.input[0].begin; - j=batch.input[1].begin; + i=batch.input[0].begin+parameters.freeze(); + j=batch.input[1].begin+parameters.freeze(); } + print("i,j,parameters.freeze()=",i,j,parameters.freeze()); // convert vector of vectors back to Pairs PairVectorMap square_map=PairVectorMap::quadratic_map(parameters.freeze(),mo_ket.size());