From 8b4f0a1265f65d6d1663d423c7cda5abb2c39154 Mon Sep 17 00:00:00 2001 From: Aodong Liu Date: Mon, 30 Oct 2023 19:01:37 -0700 Subject: [PATCH 01/49] Add swap files to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index d92d4623..f1d1a073 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ src/xc_integrator/local_work_driver/host/obara_saika/test/*.x src/xc_integrator/local_work_driver/host/obara_saika/generator/integral* src/xc_integrator/local_work_driver/host/obara_saika/generator/obara* src/xc_integrator/local_work_driver/host/obara_saika/generator/*.x +.*.swp From 403882b2ddffac55b46afc0bac178a6fad3acba5 Mon Sep 17 00:00:00 2001 From: Aodong Liu Date: Mon, 30 Oct 2023 22:25:17 -0700 Subject: [PATCH 02/49] change H slater radius and fix C++ syntax in trim_left --- src/atomic_radii.cxx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/atomic_radii.cxx b/src/atomic_radii.cxx index 6e3a829f..e71bb4c2 100644 --- a/src/atomic_radii.cxx +++ b/src/atomic_radii.cxx @@ -35,7 +35,9 @@ double slater_radius_64(AtomicNumber _Z) { auto Z = _Z.get(); switch(Z) { - case 1: /* H */ return pm_to_bohr(25. ); + //Change H radius to match Chronus + //case 1: /* H */ return pm_to_bohr(25. ); + case 1: /* H */ return pm_to_bohr(52.9); //case 2: /* He */ return pm_to_bohr(120.); case 3: /* Li */ return pm_to_bohr(145.); case 4: /* Be */ return pm_to_bohr(105.); From 23fafd267663dea98413eec45500753ff7a7dd30 Mon Sep 17 00:00:00 2001 From: Aodong Liu Date: Mon, 30 Oct 2023 22:46:05 -0700 Subject: [PATCH 03/49] add neo rks/uks skeleton --- include/gauxc/xc_integrator.hpp | 8 ++- include/gauxc/xc_integrator/impl.hpp | 15 ++++++ .../gauxc/xc_integrator/replicated/impl.hpp | 51 +++++++++++++++++++ .../replicated_xc_integrator_impl.hpp | 40 ++++++++++++++- .../replicated_xc_integrator.hpp | 4 ++ .../xc_integrator/xc_integrator_impl.hpp | 16 ++++++ ...incore_replicated_xc_device_integrator.hpp | 20 ++++++++ ...eplicated_xc_device_integrator_exc_vxc.hpp | 30 +++++++++++ ...eplicated_xc_device_integrator_exc_vxc.hpp | 32 ++++++++++++ ...eference_replicated_xc_host_integrator.hpp | 20 ++++++++ .../replicated_xc_integrator_impl.cxx | 48 +++++++++++++++++ 11 files changed, 282 insertions(+), 2 deletions(-) diff --git a/include/gauxc/xc_integrator.hpp b/include/gauxc/xc_integrator.hpp index 43c27551..8bf1ea66 100644 --- a/include/gauxc/xc_integrator.hpp +++ b/include/gauxc/xc_integrator.hpp @@ -34,6 +34,8 @@ class XCIntegrator { using exc_vxc_type_rks = std::tuple< value_type, matrix_type >; using exc_vxc_type_uks = std::tuple< value_type, matrix_type, matrix_type >; using exc_vxc_type_gks = std::tuple< value_type, matrix_type, matrix_type, matrix_type, matrix_type >; + using exc_vxc_type_neo_rks = std::tuple< value_type, matrix_type, matrix_type, matrix_type >; + using exc_vxc_type_neo_uks = std::tuple< value_type, matrix_type, matrix_type, matrix_type, matrix_type >; using exc_grad_type = std::vector< value_type >; using exx_type = matrix_type; @@ -59,7 +61,11 @@ class XCIntegrator { exc_vxc_type_uks eval_exc_vxc ( const MatrixType&, const MatrixType&, const IntegratorSettingsXC& = IntegratorSettingsXC{} ); exc_vxc_type_gks eval_exc_vxc ( const MatrixType&, const MatrixType&, const MatrixType&, const MatrixType&, - const IntegratorSettingsXC& = IntegratorSettingsXC{}); + const IntegratorSettingsXC& = IntegratorSettingsXC{}) ; + exc_vxc_type_neo_rks neo_eval_exc_vxc ( const MatrixType&, const MatrixType&, const MatrixType& + const IntegratorSettingsXC& = IntegratorSettingsXC{} ); + exc_vxc_type_neo_uks neo_eval_exc_vxc ( const MatrixType&, const MatrixType&, const MatrixType&, const MatrixType&, + const IntegratorSettingsXC& = IntegratorSettingsXC{} ); exc_grad_type eval_exc_grad( const MatrixType& ); exx_type eval_exx ( const MatrixType&, const IntegratorSettingsEXX& = IntegratorSettingsEXX{} ); diff --git a/include/gauxc/xc_integrator/impl.hpp b/include/gauxc/xc_integrator/impl.hpp index c7db4a93..7ebc5f66 100644 --- a/include/gauxc/xc_integrator/impl.hpp +++ b/include/gauxc/xc_integrator/impl.hpp @@ -52,6 +52,21 @@ typename XCIntegrator::exc_vxc_type_gks if( not pimpl_ ) GAUXC_PIMPL_NOT_INITIALIZED(); return pimpl_->eval_exc_vxc(Ps, Pz, Py, Px, ks_settings); }; +typename XCIntegrator::exc_vxc_type_neo_rks + XCIntegrator::neo_eval_exc_vxc( const MatrixType& elec_Ps, const MatrixType& prot_Ps, const MatrixType& prot_Pz, + const IntegratorSettingsXC& ks_settings ){ + if( not pimpl_ ) GAUXC_PIMPL_NOT_INITIALIZED(); + return pimpl_->neo_eval_exc_vxc(elec_Ps, prot_Ps, prot_Pz); +}; + +template +typename XCIntegrator::exc_vxc_type_neo_uks + XCIntegrator::neo_eval_exc_vxc( const MatrixType& elec_Ps, const MatrixType& elec_Pz, const MatrixType& prot_Ps, const MatrixType& prot_Pz, + const IntegratorSettingsXC& ks_settings ){ + if( not pimpl_ ) GAUXC_PIMPL_NOT_INITIALIZED(); + return pimpl_->neo_eval_exc_vxc(elec_Ps, elec_Pz, prot_Ps, prot_Pz); +}; + template typename XCIntegrator::exc_grad_type diff --git a/include/gauxc/xc_integrator/replicated/impl.hpp b/include/gauxc/xc_integrator/replicated/impl.hpp index 1b395d34..5498595a 100644 --- a/include/gauxc/xc_integrator/replicated/impl.hpp +++ b/include/gauxc/xc_integrator/replicated/impl.hpp @@ -119,6 +119,57 @@ typename ReplicatedXCIntegrator::exc_vxc_type_gks } +template +typename ReplicatedXCIntegrator::exc_vxc_type_neo_rks + ReplicatedXCIntegrator::neo_eval_exc_vxc_( const MatrixType& elec_Ps, const MatrixType& prot_Ps, const MatrixType& prot_Pz, + const IntegratorSettingsXC& ks_settings ) { + + if( not pimpl_ ) GAUXC_PIMPL_NOT_INITIALIZED(); + matrix_type elec_VXCs( elec_Ps.rows(), elec_Ps.cols() ); + matrix_type prot_VXCs( prot_Ps.rows(), prot_Ps.cols() ); + matrix_type prot_VXCz( prot_Pz.rows(), prot_Pz.cols() ); + value_type EXC; + + pimpl_->neo_eval_exc_vxc( elec_Ps.rows(), elec_Ps.cols(), prot_Ps.rows(), prot_Ps.cols(), + elec_Ps.data(), elec_Ps.rows(), + prot_Ps.data(), prot_Ps.rows(), + prot_Pz.data(), prot_Pz.rows(), + elec_VXCs.data(), elec_VXCs.rows(), + prot_VXCs.data(), prot_VXCs.rows(), + prot_VXCz.data(), prot_VXCz.rows(), + &EXC); + + return std::make_tuple( EXC, elec_VXCs, prot_VXCs, prot_VXCz ); + +} + +template +typename ReplicatedXCIntegrator::exc_vxc_type_neo_uks + ReplicatedXCIntegrator::neo_eval_exc_vxc_( const MatrixType& elec_Ps, const MatrixType& elec_Pz, const MatrixType& prot_Ps, const MatrixType& prot_Pz, + const IntegratorSettingsXC& ks_settings ) { + + if( not pimpl_ ) GAUXC_PIMPL_NOT_INITIALIZED(); + matrix_type elec_VXCs( elec_Ps.rows(), elec_Ps.cols() ); + matrix_type elec_VXCz( elec_Pz.rows(), elec_Pz.cols() ); + matrix_type prot_VXCs( prot_Ps.rows(), prot_Ps.cols() ); + matrix_type prot_VXCz( prot_Pz.rows(), prot_Pz.cols() ); + value_type EXC; + + pimpl_->neo_eval_exc_vxc( elec_Ps.rows(), elec_Ps.cols(), prot_Ps.rows(), prot_Ps.cols(), + elec_Ps.data(), elec_Ps.rows(), + elec_Pz.data(), elec_Pz.rows(), + prot_Ps.data(), prot_Ps.rows(), + prot_Pz.data(), prot_Pz.rows(), + elec_VXCs.data(), elec_VXCs.rows(), + elec_VXCz.data(), elec_VXCz.rows(), + prot_VXCs.data(), prot_VXCs.rows(), + prot_VXCz.data(), prot_VXCz.rows(), + &EXC); + + return std::make_tuple( EXC, elec_VXCs, elec_VXCz, prot_VXCs, prot_VXCz ); + +} + template typename ReplicatedXCIntegrator::exc_grad_type ReplicatedXCIntegrator::eval_exc_grad_( const MatrixType& P ) { diff --git a/include/gauxc/xc_integrator/replicated/replicated_xc_integrator_impl.hpp b/include/gauxc/xc_integrator/replicated/replicated_xc_integrator_impl.hpp index dea0fdcb..c12f0753 100644 --- a/include/gauxc/xc_integrator/replicated/replicated_xc_integrator_impl.hpp +++ b/include/gauxc/xc_integrator/replicated/replicated_xc_integrator_impl.hpp @@ -61,7 +61,24 @@ class ReplicatedXCIntegratorImpl { value_type* VXCy, int64_t ldvxcy, value_type* VXCx, int64_t ldvxcx, value_type* EXC, const IntegratorSettingsXC& ks_settings ) = 0; - + virtual void neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + const value_type* P1s, int64_t ldp1s, + const value_type* P2s, int64_t ldp2s, + const value_type* P2z, int64_t ldp2z, + value_type* VXC1s, int64_t ldvxc1s, + value_type* VXC2s, int64_t ldvxc2s, + value_type* VXC2z, int64_t ldvxc2z, + value_type* EXC, const IntegratorSettingsXC& ks_settings ) = 0; + virtual void neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + const value_type* P1s, int64_t ldp1s, + const value_type* P1z, int64_t ldp1z, + const value_type* P2s, int64_t ldp2s, + const value_type* P2z, int64_t ldp2z, + value_type* VXC1s, int64_t ldvxc1s, + value_type* VXC1z, int64_t ldvxc1z, + value_type* VXC2s, int64_t ldvxc2s, + value_type* VXC2z, int64_t ldvxc2z, + value_type* EXC, const IntegratorSettingsXC& ks_settings ) = 0; virtual void eval_exc_grad_( int64_t m, int64_t n, const value_type* P, int64_t ldp, value_type* EXC_GRAD ) = 0; virtual void eval_exx_( int64_t m, int64_t n, const value_type* P, @@ -92,6 +109,7 @@ class ReplicatedXCIntegratorImpl { value_type* VXCs, int64_t ldvxcs, value_type* VXCz, int64_t ldvxcz, value_type* EXC, const IntegratorSettingsXC& ks_settings ); + void eval_exc_vxc( int64_t m, int64_t n, const value_type* Ps, int64_t ldps, const value_type* Pz, @@ -106,6 +124,26 @@ class ReplicatedXCIntegratorImpl { value_type* VXCx, int64_t ldvxcx, value_type* EXC, const IntegratorSettingsXC& ks_settings ); + + void neo_eval_exc_vxc( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + const value_type* P1s, int64_t ldp1s, + const value_type* P2s, int64_t ldp2s, + const value_type* P2z, int64_t ldp2z, + value_type* VXC1s, int64_t ldvxc1s, + value_type* VXC2s, int64_t ldvxc2s, + value_type* VXC2z, int64_t ldvxc2z, + value_type* EXC, const IntegratorSettingsXC& ks_settings); + + void neo_eval_exc_vxc( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + const value_type* P1s, int64_t ldp1s, + const value_type* P1z, int64_t ldp1z, + const value_type* P2s, int64_t ldp2s, + const value_type* P2z, int64_t ldp2z, + value_type* VXC1s, int64_t ldvxc1s, + value_type* VXC1z, int64_t ldvxc1z, + value_type* VXC2s, int64_t ldvxc2s, + value_type* VXC2z, int64_t ldvxc2z, + value_type* EXC, const IntegratorSettingsXC& ks_settings); void eval_exc_grad( int64_t m, int64_t n, const value_type* P, int64_t ldp, value_type* EXC_GRAD ); diff --git a/include/gauxc/xc_integrator/replicated_xc_integrator.hpp b/include/gauxc/xc_integrator/replicated_xc_integrator.hpp index 921161e1..25617405 100644 --- a/include/gauxc/xc_integrator/replicated_xc_integrator.hpp +++ b/include/gauxc/xc_integrator/replicated_xc_integrator.hpp @@ -31,6 +31,8 @@ class ReplicatedXCIntegrator : public XCIntegratorImpl { using exc_vxc_type_rks = typename XCIntegratorImpl::exc_vxc_type_rks; using exc_vxc_type_uks = typename XCIntegratorImpl::exc_vxc_type_uks; using exc_vxc_type_gks = typename XCIntegratorImpl::exc_vxc_type_gks; + using exc_vxc_type_neo_rks = typename XCIntegratorImpl::exc_vxc_type_neo_rks; + using exc_vxc_type_neo_uks = typename XCIntegratorImpl::exc_vxc_type_neo_uks; using exc_grad_type = typename XCIntegratorImpl::exc_grad_type; using exx_type = typename XCIntegratorImpl::exx_type; @@ -43,6 +45,8 @@ class ReplicatedXCIntegrator : public XCIntegratorImpl { exc_vxc_type_rks eval_exc_vxc_ ( const MatrixType&, const IntegratorSettingsXC& ) override; exc_vxc_type_uks eval_exc_vxc_ ( const MatrixType&, const MatrixType&, const IntegratorSettingsXC&) override; exc_vxc_type_gks eval_exc_vxc_ ( const MatrixType&, const MatrixType&, const MatrixType&, const MatrixType&, const IntegratorSettingsXC& ) override; + exc_vxc_type_neo_rks neo_eval_exc_vxc_ ( const MatrixType&, const MatrixType&, const MatrixType&, const IntegratorSettingsXC& ) override; + exc_vxc_type_neo_uks neo_eval_exc_vxc_ ( const MatrixType&, const MatrixType&, const MatrixType&, const MatrixType&, const IntegratorSettingsXC& ) override; exc_grad_type eval_exc_grad_( const MatrixType& ) override; exx_type eval_exx_ ( const MatrixType&, const IntegratorSettingsEXX& ) override; const util::Timer& get_timings_() const override; diff --git a/include/gauxc/xc_integrator/xc_integrator_impl.hpp b/include/gauxc/xc_integrator/xc_integrator_impl.hpp index b7a19b71..a2d8f517 100644 --- a/include/gauxc/xc_integrator/xc_integrator_impl.hpp +++ b/include/gauxc/xc_integrator/xc_integrator_impl.hpp @@ -23,6 +23,8 @@ class XCIntegratorImpl { using exc_vxc_type_rks = typename XCIntegrator::exc_vxc_type_rks; using exc_vxc_type_uks = typename XCIntegrator::exc_vxc_type_uks; using exc_vxc_type_gks = typename XCIntegrator::exc_vxc_type_gks; + using exc_vxc_type_neo_rks = typename XCIntegrator::exc_vxc_type_neo_rks; + using exc_vxc_type_neo_uks = typename XCIntegrator::exc_vxc_type_neo_uks; using exc_grad_type = typename XCIntegrator::exc_grad_type; using exx_type = typename XCIntegrator::exx_type; @@ -33,6 +35,10 @@ class XCIntegratorImpl { virtual exc_vxc_type_uks eval_exc_vxc_ ( const MatrixType& Ps, const MatrixType& Pz, const IntegratorSettingsXC& ks_settings ) = 0; virtual exc_vxc_type_gks eval_exc_vxc_ ( const MatrixType& Ps, const MatrixType& Pz, const MatrixType& Py, const MatrixType& Px, const IntegratorSettingsXC& ks_settings ) = 0; + virtual exc_vxc_type_neo_rks neo_eval_exc_vxc_ ( const MatrixType& elec_Ps, const MatrixType& prot_Ps, const MatrixType& prot_Pz, + const IntegratorSettingsXC& ks_settings ) = 0; + virtual exc_vxc_type_neo_uks neo_eval_exc_vxc_ ( const MatrixType& elec_Ps, const MatrixType& elec_Pz, const MatrixType& prot_Ps, const MatrixType& prot_Pz, + const IntegratorSettingsXC& ks_settings ) = 0; virtual exc_grad_type eval_exc_grad_( const MatrixType& P ) = 0; virtual exx_type eval_exx_ ( const MatrixType& P, const IntegratorSettingsEXX& settings ) = 0; @@ -76,6 +82,16 @@ class XCIntegratorImpl { exc_vxc_type_gks eval_exc_vxc( const MatrixType& Ps, const MatrixType& Pz, const MatrixType& Py, const MatrixType& Px, const IntegratorSettingsXC& ks_settings ) { return eval_exc_vxc_(Ps, Pz, Py, Px, ks_settings); } + + exc_vxc_type_neo_rks neo_eval_exc_vxc( const MatrixType& elec_Ps, const MatrixType& prot_Ps, const MatrixType& prot_Pz, + const IntegratorSettingsXC& ks_settings){ + return neo_eval_exc_vxc_(elec_Ps, prot_Ps, prot_Pz); + } + + exc_vxc_type_neo_uks neo_eval_exc_vxc( const MatrixType& elec_Ps, const MatrixType& elec_Pz, const MatrixType& prot_Ps, const MatrixType& prot_Pz, + const IntegratorSettingsXC& ks_settings){ + return neo_eval_exc_vxc_(elec_Ps, elec_Pz, prot_Ps, prot_Pz); + } /** Integrate EXC gradient for RKS * diff --git a/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator.hpp b/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator.hpp index 6d169c03..c46b75a3 100644 --- a/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator.hpp +++ b/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator.hpp @@ -56,6 +56,26 @@ class IncoreReplicatedXCDeviceIntegrator : value_type* VXCy, int64_t ldvxcy, value_type* VXCx, int64_t ldvxcx, value_type* EXC, const IntegratorSettingsXC& settings ) override; + + void neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + const value_type* P1s, int64_t ldp1s, + const value_type* P2s, int64_t ldp2s, + const value_type* P2z, int64_t ldp2z, + value_type* VXC1s, int64_t ldvxc1s, + value_type* VXC2s, int64_t ldvxc2s, + value_type* VXC2z, int64_t ldvxc2z, + value_type* EXC, const IntegratorSettingsXC& settings) override; + + void neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + const value_type* P1s, int64_t ldp1s, + const value_type* P1z, int64_t ldp1z, + const value_type* P2s, int64_t ldp2s, + const value_type* P2z, int64_t ldp2z, + value_type* VXC1s, int64_t ldvxc1s, + value_type* VXC1z, int64_t ldvxc1z, + value_type* VXC2s, int64_t ldvxc2s, + value_type* VXC2z, int64_t ldvxc2z, + value_type* EXC, const IntegratorSettingsXC& settings) override; void eval_exc_grad_( int64_t m, int64_t n, const value_type* P, diff --git a/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator_exc_vxc.hpp b/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator_exc_vxc.hpp index d0e44894..570ec9cf 100644 --- a/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator_exc_vxc.hpp +++ b/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator_exc_vxc.hpp @@ -139,6 +139,36 @@ void IncoreReplicatedXCDeviceIntegrator:: GAUXC_GENERIC_EXCEPTION("GKS NOT YET IMPLEMENTED FOR DEVICE"); } +template +void IncoreReplicatedXCDeviceIntegrator:: + neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + const value_type* P1s, int64_t ldp1s, + const value_type* P2s, int64_t ldp2s, + const value_type* P2z, int64_t ldp2z, + value_type* VXC1s, int64_t ldvxc1s, + value_type* VXC2s, int64_t ldvxc2s, + value_type* VXC2z, int64_t ldvxc2z, + value_type* EXC, const IntegratorSettingsXC& settings ) { + GauXC::util::unused(m1,n1,m2,n2,P1s,ldp1s,P2s,ldp2s,P2z,ldp2z,VXC1s,ldvxc1s,VXC2s,ldvxc2s,VXC2z,ldvxc2z,EXC,settings); + GAUXC_GENERIC_EXCEPTION("NEO-RKS NOT YET IMPLEMENTED FOR DEVICE"); +} + +template +void IncoreReplicatedXCDeviceIntegrator:: + neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + const value_type* P1s, int64_t ldp1s, + const value_type* P1z, int64_t ldp1z, + const value_type* P2s, int64_t ldp2s, + const value_type* P2z, int64_t ldp2z, + value_type* VXC1s, int64_t ldvxc1s, + value_type* VXC1z, int64_t ldvxc1z, + value_type* VXC2s, int64_t ldvxc2s, + value_type* VXC2z, int64_t ldvxc2z, + value_type* EXC, const IntegratorSettingsXC& settings ) { + + GauXC::util::unused(m1,n1,m2,n2,P1s,ldp1s,P1z,ldp1z,P2s,ldp2s,P2z,ldp2z,VXC1s,ldvxc1s,VXC1z,ldvxc1z,VXC2s,ldvxc2s,VXC2z,ldvxc2z,EXC,settings); + GAUXC_GENERIC_EXCEPTION("NEO-UKS NOT YET IMPLEMENTED FOR DEVICE"); +} template void IncoreReplicatedXCDeviceIntegrator:: diff --git a/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator_exc_vxc.hpp b/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator_exc_vxc.hpp index df2d6f57..aa141b80 100644 --- a/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator_exc_vxc.hpp +++ b/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator_exc_vxc.hpp @@ -120,6 +120,38 @@ void ShellBatchedReplicatedXCDeviceIntegrator:: } +template +void ShellBatchedReplicatedXCDeviceIntegrator:: + neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + const value_type* P1s, int64_t ldp1s, + const value_type* P2s, int64_t ldp2s, + const value_type* P2z, int64_t ldp2z, + value_type* VXC1s, int64_t ldvxc1s, + value_type* VXC2s, int64_t ldvxc2s, + value_type* VXC2z, int64_t ldvxc2z, + value_type* EXC ) { + + GauXC::util::unused(m1,n1,m2,n2,P1s,ldp1s,P2s,ldp2s,P2z,ldp2z,VXC1s,ldvxc1s,VXC2s,ldvxc2s,VXC2z,ldvxc2z,EXC); + GAUXC_GENERIC_EXCEPTION("NOT YET IMPLEMENTED"); +} + +template +void ShellBatchedReplicatedXCDeviceIntegrator:: + neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + const value_type* P1s, int64_t ldp1s, + const value_type* P1z, int64_t ldp1z, + const value_type* P2s, int64_t ldp2s, + const value_type* P2z, int64_t ldp2z, + value_type* VXC1s, int64_t ldvxc1s, + value_type* VXC1z, int64_t ldvxc1z, + value_type* VXC2s, int64_t ldvxc2s, + value_type* VXC2z, int64_t ldvxc2z, + value_type* EXC ) { + + GauXC::util::unused(m1,n1,m2,n2,P1s,ldp1s,P1z,ldp1z,P2s,ldp2s,P2z,ldp2z,VXC1s,ldvxc1s,VXC1z,ldvxc1z,VXC2s,ldvxc2s,VXC2z,ldvxc2z,EXC); + GAUXC_GENERIC_EXCEPTION("NOT YET IMPLEMENTED"); +} + template void ShellBatchedReplicatedXCDeviceIntegrator:: exc_vxc_local_work_( const basis_type& basis, const value_type* P, int64_t ldp, diff --git a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator.hpp b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator.hpp index d1567572..b3f16be0 100644 --- a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator.hpp +++ b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator.hpp @@ -55,6 +55,26 @@ class ReferenceReplicatedXCHostIntegrator : value_type* EXC, const IntegratorSettingsXC& ks_settings ) override; + void neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + const value_type* P1s, int64_t ldp1s, + const value_type* P2s, int64_t ldp2s, + const value_type* P2z, int64_t ldp2z, + value_type* VXC1s, int64_t ldvxc1s, + value_type* VXC2s, int64_t ldvxc2s, + value_type* VXC2z, int64_t ldvxc2z, + value_type* EXC ) override; + + void neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + const value_type* P1s, int64_t ldp1s, + const value_type* P1z, int64_t ldp1z, + const value_type* P2s, int64_t ldp2s, + const value_type* P2z, int64_t ldp2z, + value_type* VXC1s, int64_t ldvxc1s, + value_type* VXC1z, int64_t ldvxc1z, + value_type* VXC2s, int64_t ldvxc2s, + value_type* VXC2z, int64_t ldvxc2z, + value_type* EXC ) override; + void eval_exc_grad_( int64_t m, int64_t n, const value_type* P, int64_t ldp, value_type* EXC_GRAD ) override; diff --git a/src/xc_integrator/replicated/replicated_xc_integrator_impl.cxx b/src/xc_integrator/replicated/replicated_xc_integrator_impl.cxx index fc55835b..5bc2aeca 100644 --- a/src/xc_integrator/replicated/replicated_xc_integrator_impl.cxx +++ b/src/xc_integrator/replicated/replicated_xc_integrator_impl.cxx @@ -86,6 +86,54 @@ void ReplicatedXCIntegratorImpl:: } +template +void ReplicatedXCIntegratorImpl:: + neo_eval_exc_vxc( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + const value_type* P1s, int64_t ldp1s, + const value_type* P2s, int64_t ldp2s, + const value_type* P2z, int64_t ldp2z, + value_type* VXC1s, int64_t ldvxc1s, + value_type* VXC2s, int64_t ldvxc2s, + value_type* VXC2z, int64_t ldvxc2z, + value_type* EXC ){ + + neo_eval_exc_vxc_(m1,n1,m2,n2, + P1s,ldp1s, + P2s,ldp2s, + P2z,ldp2z, + VXC1s,ldvxc1s, + VXC2s,ldvxc2s, + VXC2z,ldvxc2z, + EXC); + +} + +template +void ReplicatedXCIntegratorImpl:: + neo_eval_exc_vxc( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + const value_type* P1s, int64_t ldp1s, + const value_type* P1z, int64_t ldp1z, + const value_type* P2s, int64_t ldp2s, + const value_type* P2z, int64_t ldp2z, + value_type* VXC1s, int64_t ldvxc1s, + value_type* VXC1z, int64_t ldvxc1z, + value_type* VXC2s, int64_t ldvxc2s, + value_type* VXC2z, int64_t ldvxc2z, + value_type* EXC ){ + + neo_eval_exc_vxc_(m1,n1,m2,n2, + P1s,ldp1s, + P1z,ldp1z, + P2s,ldp2s, + P2z,ldp2z, + VXC1s,ldvxc1s, + VXC1z,ldvxc1z, + VXC2s,ldvxc2s, + VXC2z,ldvxc2z, + EXC); + +} + template void ReplicatedXCIntegratorImpl:: eval_exc_grad( int64_t m, int64_t n, const value_type* P, From 180955139bdab2a822f5667cffda9b1888835b4a Mon Sep 17 00:00:00 2001 From: Aodong Liu Date: Mon, 30 Oct 2023 22:48:43 -0700 Subject: [PATCH 04/49] pass another basis to the load balancer --- include/gauxc/load_balancer.hpp | 9 +++++ .../replicated_xc_integrator_impl.hpp | 1 - make_command.sh | 4 +++ .../host/load_balancer_host_factory.cxx | 30 ++++++++++++++++ .../host/load_balancer_host_factory.hpp | 6 ++++ src/load_balancer/load_balancer_factory.cxx | 35 +++++++++++++++++++ src/load_balancer/load_balancer_impl.cxx | 35 +++++++++++++++++++ src/load_balancer/load_balancer_impl.hpp | 11 ++++++ ...atched_replicated_xc_device_integrator.hpp | 20 +++++++++++ 9 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 make_command.sh diff --git a/include/gauxc/load_balancer.hpp b/include/gauxc/load_balancer.hpp index ea67f9c4..c897e4d5 100644 --- a/include/gauxc/load_balancer.hpp +++ b/include/gauxc/load_balancer.hpp @@ -163,6 +163,10 @@ class LoadBalancerFactory { LoadBalancer get_instance( const RuntimeEnvironment& rt, const Molecule& mol, const MolGrid& mg, const BasisSet& bs); + LoadBalancer get_instance( const RuntimeEnvironment& rt, + const Molecule& mol, const MolGrid& mg, const BasisSet& bs, + const BasisSet& bs2, size_t pad_val = 1 ); + /** * @brief Generate a shared pointer to a LoadBalancer instance per kernel and * execution space specfication @@ -180,6 +184,11 @@ class LoadBalancerFactory { const RuntimeEnvironment& rt, const Molecule& mol, const MolGrid& mg, const BasisSet&); + std::shared_ptr get_shared_instance( + const RuntimeEnvironment& rt, + const Molecule& mol, const MolGrid& mg, const BasisSet&, + const BasisSet&, size_t pad_val = 1 ); + private: ExecutionSpace ex_; ///< Execution space for the generated LoadBalancer instances diff --git a/include/gauxc/xc_integrator/replicated/replicated_xc_integrator_impl.hpp b/include/gauxc/xc_integrator/replicated/replicated_xc_integrator_impl.hpp index c12f0753..e69d6263 100644 --- a/include/gauxc/xc_integrator/replicated/replicated_xc_integrator_impl.hpp +++ b/include/gauxc/xc_integrator/replicated/replicated_xc_integrator_impl.hpp @@ -123,7 +123,6 @@ class ReplicatedXCIntegratorImpl { value_type* VXCy, int64_t ldvxcy, value_type* VXCx, int64_t ldvxcx, value_type* EXC, const IntegratorSettingsXC& ks_settings ); - void neo_eval_exc_vxc( int64_t m1, int64_t n1, int64_t m2, int64_t n2, const value_type* P1s, int64_t ldp1s, diff --git a/make_command.sh b/make_command.sh new file mode 100644 index 00000000..932f5e8d --- /dev/null +++ b/make_command.sh @@ -0,0 +1,4 @@ +cmake -DCMAKE_BUILD_TYPE=Debug -DGAUXC_ENABLE_OPENMP=off -DGAUXC_ENABLE_MPI=off .. +make -j 4 +make DESTDIR=../install2 install +touch /Users/aodongliu/Softwares/chronusq_dev_dft/cmake/HandleGauXC.cmake diff --git a/src/load_balancer/host/load_balancer_host_factory.cxx b/src/load_balancer/host/load_balancer_host_factory.cxx index 94db35de..c33c2945 100644 --- a/src/load_balancer/host/load_balancer_host_factory.cxx +++ b/src/load_balancer/host/load_balancer_host_factory.cxx @@ -41,5 +41,35 @@ std::shared_ptr LoadBalancerHostFactory::get_shared_instance( } +std::shared_ptr LoadBalancerHostFactory::get_shared_instance( + std::string kernel_name, const RuntimeEnvironment& rt, + const Molecule& mol, const MolGrid& mg, const BasisSet& basis, + const BasisSet& basis2, size_t pv +) { + + std::transform(kernel_name.begin(), kernel_name.end(), + kernel_name.begin(), ::toupper ); + + + if( kernel_name == "DEFAULT" or kernel_name == "REPLICATED" ) + kernel_name = "REPLICATED-PETITE"; + + std::unique_ptr ptr = nullptr; + if( kernel_name == "REPLICATED-PETITE" ) + ptr = std::make_unique( + rt, mol, mg, basis, basis2, pv + ); + + if( kernel_name == "REPLICATED-FILLIN" ) + ptr = std::make_unique( + rt, mol, mg, basis, basis2, pv + ); + + if( ! ptr ) GAUXC_GENERIC_EXCEPTION("Load Balancer Kernel Not Recognized: " + kernel_name); + + return std::make_shared(std::move(ptr)); + +} + } diff --git a/src/load_balancer/host/load_balancer_host_factory.hpp b/src/load_balancer/host/load_balancer_host_factory.hpp index d02e5c03..bd6a51b2 100644 --- a/src/load_balancer/host/load_balancer_host_factory.hpp +++ b/src/load_balancer/host/load_balancer_host_factory.hpp @@ -17,6 +17,12 @@ struct LoadBalancerHostFactory { const Molecule& mol, const MolGrid& mg, const BasisSet& basis ); + static std::shared_ptr get_shared_instance( + std::string kernel_name, const RuntimeEnvironment& rt, + const Molecule& mol, const MolGrid& mg, const BasisSet& basis, + const BasisSet& basis2, size_t pv + ); + }; diff --git a/src/load_balancer/load_balancer_factory.cxx b/src/load_balancer/load_balancer_factory.cxx index b14ddbee..bc3b687a 100644 --- a/src/load_balancer/load_balancer_factory.cxx +++ b/src/load_balancer/load_balancer_factory.cxx @@ -50,6 +50,41 @@ LoadBalancer LoadBalancerFactory::get_instance( } +std::shared_ptr LoadBalancerFactory::get_shared_instance( + const RuntimeEnvironment& rt, + const Molecule& mol, const MolGrid& mg, const BasisSet& basis, + const BasisSet& basis2, size_t pad_value +) { + + switch(ex_) { + case ExecutionSpace::Host: + using host_factory = LoadBalancerHostFactory; + return host_factory::get_shared_instance(kernel_name_, + rt, mol, mg, basis, basis2, pad_value ); + #ifdef GAUXC_ENABLE_DEVICE + case ExecutionSpace::Device: + GAUXC_GENERIC_EXCEPTION("2 basis with GPU NYI"); + //using device_factory = LoadBalancerDeviceFactory; + //return device_factory::get_shared_instance(kernel_name_, + // rt, mol, mg, basis, pad_value ); + #endif + default: + GAUXC_GENERIC_EXCEPTION("Unrecognized Execution Space"); + } + + +} + +LoadBalancer LoadBalancerFactory::get_instance( + const RuntimeEnvironment& rt, + const Molecule& mol, const MolGrid& mg, const BasisSet& basis, + const BasisSet& basis2, size_t pad_value +) { + + auto ptr = get_shared_instance(rt, mol, mg, basis, basis2, pad_value); + return LoadBalancer(std::move(*ptr)); + +} } diff --git a/src/load_balancer/load_balancer_impl.cxx b/src/load_balancer/load_balancer_impl.cxx index 06dbbd19..c1e81039 100644 --- a/src/load_balancer/load_balancer_impl.cxx +++ b/src/load_balancer/load_balancer_impl.cxx @@ -21,6 +21,34 @@ LoadBalancerImpl::LoadBalancerImpl( const RuntimeEnvironment& rt, const Molecule } +LoadBalancerImpl::LoadBalancerImpl( const RuntimeEnvironment& rt, const Molecule& mol, + const MolGrid& mg, const basis_type& basis, const basis_type& basis2, std::shared_ptr molmeta ) : + runtime_(rt), + mol_( std::make_shared(mol) ), + mg_( std::make_shared(mg) ), + basis_( std::make_shared(basis) ), + basis2_( std::make_shared(basis2) ), + molmeta_( molmeta ) { + + basis_map_ = std::make_shared(*basis_, mol); + basis_map2_ = std::make_shared(*basis2_, mol); + +} + +LoadBalancerImpl::LoadBalancerImpl( const RuntimeEnvironment& rt, const Molecule& mol, + const MolGrid& mg, const basis_type& basis, const basis_type& basis2, std::shared_ptr molmeta ) : + runtime_(rt), + mol_( std::make_shared(mol) ), + mg_( std::make_shared(mg) ), + basis_( std::make_shared(basis) ), + basis2_( std::make_shared(basis2) ), + molmeta_( molmeta ) { + + basis_map_ = std::make_shared(*basis_, mol); + basis_map2_ = std::make_shared(*basis2_, mol); + +} + LoadBalancerImpl::LoadBalancerImpl( const RuntimeEnvironment& rt, const Molecule& mol, const MolGrid& mg, const basis_type& basis, const MolMeta& molmeta ) : LoadBalancerImpl( rt, mol, mg, basis, std::make_shared(molmeta) ) { } @@ -29,6 +57,13 @@ LoadBalancerImpl::LoadBalancerImpl( const RuntimeEnvironment& rt, const Molecule const MolGrid& mg, const basis_type& basis ) : LoadBalancerImpl( rt, mol, mg, basis, std::make_shared(mol) ) { } +LoadBalancerImpl::LoadBalancerImpl( const RuntimeEnvironment& rt, const Molecule& mol, + const MolGrid& mg, const basis_type& basis, const basis_type& basis2 ) : + LoadBalancerImpl( rt, mol, mg, basis, basis2, std::make_shared(mol) ) { } + +LoadBalancerImpl::LoadBalancerImpl( const RuntimeEnvironment& rt, const Molecule& mol, + const MolGrid& mg, const basis_type& basis, const basis_type& basis2, const MolMeta& molmeta ) : + LoadBalancerImpl( rt, mol, mg, basis, basis2, std::make_shared(molmeta) ) { } LoadBalancerImpl::LoadBalancerImpl( const LoadBalancerImpl& ) = default; LoadBalancerImpl::LoadBalancerImpl( LoadBalancerImpl&& ) noexcept = default; diff --git a/src/load_balancer/load_balancer_impl.hpp b/src/load_balancer/load_balancer_impl.hpp index 566279a1..ae777abd 100644 --- a/src/load_balancer/load_balancer_impl.hpp +++ b/src/load_balancer/load_balancer_impl.hpp @@ -30,6 +30,10 @@ class LoadBalancerImpl { std::shared_ptr basis_map_; std::shared_ptr shell_pairs_; + std::shared_ptr basis2_; + std::shared_ptr basis_map2_; + std::shared_ptr shell_pairs2_; + std::vector< XCTask > local_tasks_; LoadBalancerState state_; @@ -48,6 +52,13 @@ class LoadBalancerImpl { const basis_type&, const MolMeta& ); LoadBalancerImpl( const RuntimeEnvironment&, const Molecule&, const MolGrid& mg, const basis_type&, std::shared_ptr ); + + LoadBalancerImpl( const RuntimeEnvironment&, const Molecule&, const MolGrid& mg, + const basis_type&, const basis_type& ); + LoadBalancerImpl( const RuntimeEnvironment&, const Molecule&, const MolGrid& mg, + const basis_type&, const basis_type&, const MolMeta& ); + LoadBalancerImpl( const RuntimeEnvironment&, const Molecule&, const MolGrid& mg, + const basis_type&, const basis_type&, std::shared_ptr ); LoadBalancerImpl( const LoadBalancerImpl& ); LoadBalancerImpl( LoadBalancerImpl&& ) noexcept; diff --git a/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator.hpp b/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator.hpp index 01210e0c..dc55785f 100644 --- a/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator.hpp +++ b/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator.hpp @@ -68,6 +68,26 @@ class ShellBatchedReplicatedXCDeviceIntegrator : value_type* VXCx, int64_t ldvxcx, value_type* EXC, const IntegratorSettingsXC& settings ) override; + void neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + const value_type* P1s, int64_t ldp1s, + const value_type* P2s, int64_t ldp2s, + const value_type* P2z, int64_t ldp2z, + value_type* VXC1s, int64_t ldvxc1s, + value_type* VXC2s, int64_t ldvxc2s, + value_type* VXC2z, int64_t ldvxc2z, + value_type* EXC ) override; + + void neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + const value_type* P1s, int64_t ldp1s, + const value_type* P1z, int64_t ldp1z, + const value_type* P2s, int64_t ldp2s, + const value_type* P2z, int64_t ldp2z, + value_type* VXC1s, int64_t ldvxc1s, + value_type* VXC1z, int64_t ldvxc1z, + value_type* VXC2s, int64_t ldvxc2s, + value_type* VXC2z, int64_t ldvxc2z, + value_type* EXC ) override; + void eval_exc_grad_( int64_t m, int64_t n, const value_type* P, int64_t ldp, value_type* EXC_GRAD ) override; From f47b51f73e8d50a398342a5447f15ccc11678364 Mon Sep 17 00:00:00 2001 From: Aodong Liu Date: Mon, 30 Oct 2023 22:50:31 -0700 Subject: [PATCH 05/49] set up gauxc to call neo_exc_vxc_local_work --- include/gauxc/load_balancer.hpp | 9 + src/load_balancer/load_balancer.cxx | 17 + src/load_balancer/load_balancer_impl.cxx | 10 + src/load_balancer/load_balancer_impl.hpp | 4 + ...eference_replicated_xc_host_integrator.hpp | 25 +- ..._replicated_xc_host_integrator_exc_vxc.hpp | 298 +++++++++++++++++- 6 files changed, 359 insertions(+), 4 deletions(-) diff --git a/include/gauxc/load_balancer.hpp b/include/gauxc/load_balancer.hpp index c897e4d5..a8fb5832 100644 --- a/include/gauxc/load_balancer.hpp +++ b/include/gauxc/load_balancer.hpp @@ -102,6 +102,15 @@ class LoadBalancer { const shell_pair_type& shell_pairs() const; const shell_pair_type& shell_pairs(); + /// Return the underlying 2nd BasisSet instance used to generate this LoadBalancer + const basis_type& basis2() const; + + /// Return BasisSetMap instance corresponding to 2nd basis/molecule + const basis_map_type& basis_map2() const; + + /// Return the number of non-negligible local shell pairs for 2nd basis for this LoadBalancer + const shell_pair_type& shell_pairs2() const; + /// Return the runtime handle used to construct this LoadBalancer const RuntimeEnvironment& runtime() const; diff --git a/src/load_balancer/load_balancer.cxx b/src/load_balancer/load_balancer.cxx index 9329fef8..df49202f 100644 --- a/src/load_balancer/load_balancer.cxx +++ b/src/load_balancer/load_balancer.cxx @@ -93,6 +93,23 @@ const LoadBalancer::shell_pair_type& LoadBalancer::shell_pairs() { return pimpl_->shell_pairs(); } +const LoadBalancer::basis_type& LoadBalancer::basis2() const { + if( not pimpl_ ) GAUXC_PIMPL_NOT_INITIALIZED(); + return pimpl_->basis2(); +} +const LoadBalancer::basis_map_type& LoadBalancer::basis_map2() const { + if( not pimpl_ ) GAUXC_PIMPL_NOT_INITIALIZED(); + return pimpl_->basis_map2(); +} +const LoadBalancer::shell_pair_type& LoadBalancer::shell_pairs2() const { + if( not pimpl_ ) GAUXC_PIMPL_NOT_INITIALIZED(); + return pimpl_->shell_pairs2(); +} +const LoadBalancer::shell_pair_type& LoadBalancer::shell_pairs2() { + if( not pimpl_ ) GAUXC_PIMPL_NOT_INITIALIZED(); + return pimpl_->shell_pairs2(); +} + LoadBalancerState& LoadBalancer::state() { if( not pimpl_ ) GAUXC_PIMPL_NOT_INITIALIZED(); return pimpl_->state(); diff --git a/src/load_balancer/load_balancer_impl.cxx b/src/load_balancer/load_balancer_impl.cxx index c1e81039..917626e1 100644 --- a/src/load_balancer/load_balancer_impl.cxx +++ b/src/load_balancer/load_balancer_impl.cxx @@ -155,6 +155,16 @@ const LoadBalancerImpl::shell_pair_type& LoadBalancerImpl::shell_pairs() { return *shell_pairs_; } +const LoadBalancerImpl::basis_type& LoadBalancerImpl::basis2() const { + return *basis2_; +} +const LoadBalancerImpl::basis_map_type& LoadBalancerImpl::basis_map2() const { + return *basis_map2_; +} +const LoadBalancerImpl::shell_pair_type& LoadBalancerImpl::shell_pairs2() const { + return *shell_pairs2_; +} + const RuntimeEnvironment& LoadBalancerImpl::runtime() const { return runtime_; } diff --git a/src/load_balancer/load_balancer_impl.hpp b/src/load_balancer/load_balancer_impl.hpp index ae777abd..e2a0285c 100644 --- a/src/load_balancer/load_balancer_impl.hpp +++ b/src/load_balancer/load_balancer_impl.hpp @@ -85,6 +85,10 @@ class LoadBalancerImpl { const basis_map_type& basis_map() const; const shell_pair_type& shell_pairs() const; const shell_pair_type& shell_pairs(); + const basis_type& basis2() const; + const basis_map_type& basis_map2() const; + const shell_pair_type& shell_pairs2() const; + const shell_pair_type& shell_pairs2(); LoadBalancerState& state(); diff --git a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator.hpp b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator.hpp index b3f16be0..9dc16b71 100644 --- a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator.hpp +++ b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator.hpp @@ -62,7 +62,7 @@ class ReferenceReplicatedXCHostIntegrator : value_type* VXC1s, int64_t ldvxc1s, value_type* VXC2s, int64_t ldvxc2s, value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC ) override; + value_type* EXC, const IntegratorSettingsXC& ks_settings) override; void neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, const value_type* P1s, int64_t ldp1s, @@ -73,7 +73,7 @@ class ReferenceReplicatedXCHostIntegrator : value_type* VXC1z, int64_t ldvxc1z, value_type* VXC2s, int64_t ldvxc2s, value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC ) override; + value_type* EXC, const IntegratorSettingsXC& ks_settings ) override; void eval_exc_grad_( int64_t m, int64_t n, const value_type* P, int64_t ldp, value_type* EXC_GRAD ) override; @@ -100,7 +100,26 @@ class ReferenceReplicatedXCHostIntegrator : value_type* VXCz, int64_t ldvxcz, value_type* VXCy, int64_t ldvxcy, value_type* VXCx, int64_t ldvxcx, - value_type* EXC, value_type *N_EL, const IntegratorSettingsXC& ks_settings ); + value_type* EXC, value_type *N_EL, + const IntegratorSettingsXC& ks_settings ); + + void neo_exc_vxc_local_work_( const value_type* P1s, int64_t ldp1s, + const value_type* P2s, int64_t ldp2s, + const value_type* P2z, int64_t ldp2z, + value_type* VXC1s, int64_t ldvxc1s, + value_type* VXC2s, int64_t ldvxc2s, + value_type* VXC2z, int64_t ldvxc2z, + value_type* EXC, value_type *N_EL ); + + void neo_exc_vxc_local_work_( const value_type* P1s, int64_t ldp1s, + const value_type* P1z, int64_t ldp1z, + const value_type* P2s, int64_t ldp2s, + const value_type* P2z, int64_t ldp2z, + value_type* VXC1s, int64_t ldvxc1s, + value_type* VXC1z, int64_t ldvxc1z, + value_type* VXC2s, int64_t ldvxc2s, + value_type* VXC2z, int64_t ldvxc2z, + value_type* EXC, value_type *N_EL ); void exc_grad_local_work_( const value_type* P, int64_t ldp, value_type* EXC_GRAD ); void exx_local_work_( const value_type* P, int64_t ldp, value_type* K, int64_t ldk, diff --git a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp index d891b543..c075193c 100644 --- a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp +++ b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp @@ -191,9 +191,68 @@ void ReferenceReplicatedXCHostIntegrator:: }); -} +} + +template +void ReferenceReplicatedXCHostIntegrator:: + neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + const value_type* P1s, int64_t ldp1s, + const value_type* P2s, int64_t ldp2s, + const value_type* P2z, int64_t ldp2z, + value_type* VXC1s, int64_t ldvxc1s, + value_type* VXC2s, int64_t ldvxc2s, + value_type* VXC2z, int64_t ldvxc2z, + value_type* EXC, const IntegratorSettingsXC& ks_settings){ + + const auto& basis = this->load_balancer_->basis(); + const auto& basis2 = this->load_balancer_->basis2(); + + // Check that P / VXC are sane + const int64_t nbf1 = basis.nbf(); + const int64_t nbf2 = basis2.nbf(); + + if( m1 != n1 | m2 != n2) + GAUXC_GENERIC_EXCEPTION("P/VXC Must Be Square"); + if( m1 != nbf1 | m2 != nbf2) + GAUXC_GENERIC_EXCEPTION("P/VXC Must Have Same Dimension as Basis"); + if( ldp1s < nbf1 | ldp2s < nbf2 | ldp2z < nbf2 ) + GAUXC_GENERIC_EXCEPTION("Invalid LDP"); + if( ldvxc1s < nbf1 | ldvxc2s < nbf2 | ldvxc2z < nbf2 ) + GAUXC_GENERIC_EXCEPTION("Invalid LDVXC"); + + // Get Tasks + this->load_balancer_->get_tasks(); + + // Temporary electron count to judge integrator accuracy + value_type N_EL; + + // Compute Local contributions to EXC / VXC + this->timer_.time_op("XCIntegrator.LocalWork", [&](){ + neo_exc_vxc_local_work_( P1s, ldp1s, + P2s, ldp2s, + P2z, ldp2z, + VXC1s, ldvxc1s, + VXC2s, ldvxc2s, + VXC2z, ldvxc2z, + EXC, &N_EL, ks_settings ); + }); + + + // Reduce Results + this->timer_.time_op("XCIntegrator.Allreduce", [&](){ + if( not this->reduction_driver_->takes_host_memory() ) + GAUXC_GENERIC_EXCEPTION("This Module Only Works With Host Reductions"); + this->reduction_driver_->allreduce_inplace( VXC1s, nbf1*nbf1, ReductionOp::Sum ); + this->reduction_driver_->allreduce_inplace( VXC2s, nbf2*nbf1, ReductionOp::Sum ); + this->reduction_driver_->allreduce_inplace( VXC2z, nbf2*nbf2, ReductionOp::Sum ); + this->reduction_driver_->allreduce_inplace( EXC, 1 , ReductionOp::Sum ); + this->reduction_driver_->allreduce_inplace( &N_EL, 1 , ReductionOp::Sum ); + + }); + +} template void ReferenceReplicatedXCHostIntegrator:: @@ -681,7 +740,244 @@ void ReferenceReplicatedXCHostIntegrator:: } } +} + + +template +void ReferenceReplicatedXCHostIntegrator:: + neo_exc_vxc_local_work_( const value_type* P1s, int64_t ldp1s, + const value_type* P2s, int64_t ldp2s, + const value_type* P2z, int64_t ldp2z, + value_type* VXC1s, int64_t ldvxc1s, + value_type* VXC2s, int64_t ldvxc2s, + value_type* VXC2z, int64_t ldvxc2z, + value_type* EXC, value_type *N_EL ) { + + GAUXC_GENERIC_EXCEPTION("neo_exc_vxc_local_work_ RKS NYI"); + /* + // Cast LWD to LocalHostWorkDriver + auto* lwd = dynamic_cast(this->local_work_driver_.get()); + + // Setup Aliases + const auto& func = *this->func_; + const auto& basis = this->load_balancer_->basis(); + const auto& mol = this->load_balancer_->molecule(); + + // Get basis map + BasisSetMap basis_map(basis,mol); + + const int32_t nbf = basis.nbf(); + + // Sort tasks on size (XXX: maybe doesnt matter?) + auto task_comparator = []( const XCTask& a, const XCTask& b ) { + return (a.points.size() * a.bfn_screening.nbe) > (b.points.size() * b.bfn_screening.nbe); + }; + + auto& tasks = this->load_balancer_->get_tasks(); + std::sort( tasks.begin(), tasks.end(), task_comparator ); + + + // Check that Partition Weights have been calculated + auto& lb_state = this->load_balancer_->state(); + if( not lb_state.modified_weights_are_stored ) { + GAUXC_GENERIC_EXCEPTION("Weights Have Not Beed Modified"); + } + + // Zero out integrands + + for( auto j = 0; j < nbf; ++j ) { + for( auto i = 0; i < nbf; ++i ) { + VXC[i + j*ldvxc] = 0.; + VXCz[i + j*ldvxc] = 0.; + } + } + *EXC = 0.; + + + // Loop over tasks + const size_t ntasks = tasks.size(); + + #pragma omp parallel + { + + XCHostData host_data; // Thread local host data + + #pragma omp for schedule(dynamic) + for( size_t iT = 0; iT < ntasks; ++iT ) { + + //std::cout << iT << "/" << ntasks << std::endl; + // Alias current task + const auto& task = tasks[iT]; + + // Get tasks constants + const int32_t npts = task.points.size(); + const int32_t nbe = task.bfn_screening.nbe; + const int32_t nshells = task.bfn_screening.shell_list.size(); + + const auto* points = task.points.data()->data(); + const auto* weights = task.weights.data(); + const int32_t* shell_list = task.bfn_screening.shell_list.data(); + + // Allocate enough memory for batch + + // Things that every calc needs + host_data.nbe_scr .resize( nbe * nbe * 2 ); + host_data.zmat .resize( npts * nbe * 2); + host_data.eps .resize( npts ); + host_data.vrho .resize( npts * 2); + + // LDA data requirements + if( func.is_lda() ){ + host_data.basis_eval .resize( npts * nbe ); + host_data.den_scr .resize( npts * 2); + } + + // GGA data requirements + if( func.is_gga() ){ + host_data.basis_eval .resize( 4 * npts * nbe ); + host_data.den_scr .resize( 2 * 4 * npts ); + host_data.gamma .resize( 3 * npts ); + host_data.vgamma .resize( 3 * npts ); + } + + // Alias/Partition out scratch memory + auto* basis_eval = host_data.basis_eval.data(); + auto* den_eval = host_data.den_scr.data(); + auto* nbe_scr = host_data.nbe_scr.data(); + auto* zmat = host_data.zmat.data(); + + auto* eps = host_data.eps.data(); + auto* gamma = host_data.gamma.data(); + auto* vrho = host_data.vrho.data(); + auto* vgamma = host_data.vgamma.data(); + + value_type* dbasis_x_eval = nullptr; + value_type* dbasis_y_eval = nullptr; + value_type* dbasis_z_eval = nullptr; + value_type* dden_x_eval = nullptr; + value_type* dden_y_eval = nullptr; + value_type* dden_z_eval = nullptr; + + if( func.is_gga() ) { + dbasis_x_eval = basis_eval + npts * nbe; + dbasis_y_eval = dbasis_x_eval + npts * nbe; + dbasis_z_eval = dbasis_y_eval + npts * nbe; + dden_x_eval = den_eval + 2*npts; + dden_y_eval = dden_x_eval + 2*npts; + dden_z_eval = dden_y_eval + 2*npts; + } + + + // Get the submatrix map for batch + std::vector< std::array > submat_map; + std::tie(submat_map, std::ignore) = + gen_compressed_submat_map(basis_map, task.bfn_screening.shell_list, nbf, nbf); + + // Evaluate Collocation (+ Grad) + if( func.is_gga() ) + lwd->eval_collocation_gradient( npts, nshells, nbe, points, basis, shell_list, + basis_eval, dbasis_x_eval, dbasis_y_eval, dbasis_z_eval ); + else + lwd->eval_collocation( npts, nshells, nbe, points, basis, shell_list, + basis_eval ); + + + // Evaluate X matrix (P * B) -> store in Z + lwd->eval_xmat( npts, nbf, nbe, submat_map, P, ldp, basis_eval, nbe, + zmat, nbe, nbe_scr ); + + lwd->eval_xmat( npts, nbf, nbe, submat_map, Pz, ldpz, basis_eval, nbe, + zmat + npts*nbe, nbe, nbe_scr + nbe * nbe); + + + // Evaluate U and V variables + if( func.is_gga() ) + lwd->eval_uvvar_gga_uks( npts, nbe, basis_eval, dbasis_x_eval, dbasis_y_eval, + dbasis_z_eval, zmat, nbe, den_eval, dden_x_eval, dden_y_eval, dden_z_eval, + gamma ); + else + lwd->eval_uvvar_lda_uks( npts, nbe, basis_eval, zmat, nbe, den_eval ); + + // Evaluate XC functional + if( func.is_gga() ) + func.eval_exc_vxc( npts, den_eval, gamma, eps, vrho, vgamma ); + else + func.eval_exc_vxc( npts, den_eval, eps, vrho ); + + // Factor weights into XC results + for( int32_t i = 0; i < npts; ++i ) { + eps[i] *= weights[i]; + vrho[2*i] *= weights[i]; + vrho[2*i+1] *= weights[i]; + } + + if( func.is_gga() ){ + for( int32_t i = 0; i < npts; ++i ) { + vgamma[3*i] *= weights[i]; + vgamma[3*i+1] *= weights[i]; + vgamma[3*i+2] *= weights[i]; + } + } + + + + // Evaluate Z matrix for VXC + if( func.is_gga() ) + lwd->eval_zmat_gga_vxc_uks( npts, nbe, vrho, vgamma, basis_eval, dbasis_x_eval, + dbasis_y_eval, dbasis_z_eval, dden_x_eval, dden_y_eval, + dden_z_eval, zmat, nbe); + else + lwd->eval_zmat_lda_vxc_uks( npts, nbe, vrho, basis_eval, zmat, nbe ); + + + // Incremeta LT of VXC + #pragma omp critical + { + // Scalar integrations + for( int32_t i = 0; i < npts; ++i ) { + *N_EL += weights[i] * (den_eval[2*i] + den_eval[2*i+1]); + *EXC += eps[i] * (den_eval[2*i] + den_eval[2*i+1]); + } + + // Increment VXC + lwd->inc_vxc( npts, nbf, nbe, basis_eval, submat_map, zmat, nbe, VXC, ldvxc, + nbe_scr ); + lwd->inc_vxc( npts, nbf, nbe, basis_eval, submat_map, zmat+ npts*nbe, nbe, VXCz, ldvxcz, + nbe_scr + nbe * nbe); + + } + + } // Loop over tasks + + } // End OpenMP region + + //std::cout << "N_EL = " << std::setprecision(12) << std::scientific << *N_EL << std::endl; + + // Symmetrize VXC + for( int32_t j = 0; j < nbf; ++j ) { + for( int32_t i = j+1; i < nbf; ++i ) { + VXC[ j + i*nbf ] = VXC[ i + j*nbf ]; + VXCz[ j + i*nbf ] = VXCz[ i + j*nbf ]; + } + } + */ + } +template +void ReferenceReplicatedXCHostIntegrator:: + neo_exc_vxc_local_work_( const value_type* P1s, int64_t ldp1s, + const value_type* P1z, int64_t ldp1z, + const value_type* P2s, int64_t ldp2s, + const value_type* P2z, int64_t ldp2z, + value_type* VXC1s, int64_t ldvxc1s, + value_type* VXC1z, int64_t ldvxc1z, + value_type* VXC2s, int64_t ldvxc2s, + value_type* VXC2z, int64_t ldvxc2z, + value_type* EXC, value_type *N_EL ) { + + GAUXC_GENERIC_EXCEPTION("neo_exc_vxc_local_work_ UKS NYI"); +} + } } From c220f09f911ddfff8d33456f5b15602f19e309b7 Mon Sep 17 00:00:00 2001 From: aodongliu Date: Wed, 18 Oct 2023 17:16:01 -0700 Subject: [PATCH 06/49] attemp to create protonic shell list --- ..._replicated_xc_host_integrator_exc_vxc.hpp | 192 +++--------------- 1 file changed, 30 insertions(+), 162 deletions(-) diff --git a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp index c075193c..797de4cf 100644 --- a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp +++ b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp @@ -753,44 +753,46 @@ void ReferenceReplicatedXCHostIntegrator:: value_type* VXC2z, int64_t ldvxc2z, value_type* EXC, value_type *N_EL ) { - GAUXC_GENERIC_EXCEPTION("neo_exc_vxc_local_work_ RKS NYI"); - /* + //GAUXC_GENERIC_EXCEPTION("neo_exc_vxc_local_work_ RKS NYI"); + // Cast LWD to LocalHostWorkDriver auto* lwd = dynamic_cast(this->local_work_driver_.get()); // Setup Aliases - const auto& func = *this->func_; - const auto& basis = this->load_balancer_->basis(); - const auto& mol = this->load_balancer_->molecule(); + const auto& func = *this->func_; + const auto& basis1 = this->load_balancer_->basis(); + const auto& basis2 = this->load_balancer_->basis2(); + const auto& mol = this->load_balancer_->molecule(); // Get basis map - BasisSetMap basis_map(basis,mol); + BasisSetMap basis_map1(basis1,mol); + BasisSetMap basis_map2(basis2,mol); - const int32_t nbf = basis.nbf(); + + const int32_t nbf1 = basis1.nbf(); + const int32_t nbf2 = basis2.nbf(); // Sort tasks on size (XXX: maybe doesnt matter?) auto task_comparator = []( const XCTask& a, const XCTask& b ) { return (a.points.size() * a.bfn_screening.nbe) > (b.points.size() * b.bfn_screening.nbe); }; + auto& tasks = this->load_balancer_->get_tasks(); std::sort( tasks.begin(), tasks.end(), task_comparator ); // Check that Partition Weights have been calculated auto& lb_state = this->load_balancer_->state(); - if( not lb_state.modified_weights_are_stored ) { - GAUXC_GENERIC_EXCEPTION("Weights Have Not Beed Modified"); - } + if( not lb_state.modified_weights_are_stored ) GAUXC_GENERIC_EXCEPTION("Weights Have Not Beed Modified"); + // Zero out integrands - for( auto j = 0; j < nbf; ++j ) { - for( auto i = 0; i < nbf; ++i ) { - VXC[i + j*ldvxc] = 0.; - VXCz[i + j*ldvxc] = 0.; - } - } + std::fill(VXC1s, VXC1s + nbf1 * ldvxc1s, 0.0); + std::fill(VXC2s, VXC2s + nbf2 * ldvxc2s, 0.0); + std::fill(VXC2z, VXC2z + nbf2 * ldvxc2z, 0.0); + *EXC = 0.; @@ -810,157 +812,23 @@ void ReferenceReplicatedXCHostIntegrator:: const auto& task = tasks[iT]; // Get tasks constants - const int32_t npts = task.points.size(); - const int32_t nbe = task.bfn_screening.nbe; - const int32_t nshells = task.bfn_screening.shell_list.size(); + const int32_t npts = task.points.size(); + const int32_t nbe1 = task.bfn_screening.nbe; + const int32_t nshells1 = task.bfn_screening.shell_list.size(); + + const int32_t nbe2 = nbf2; + const int32_t nshells2 = basis2.nshells(); const auto* points = task.points.data()->data(); const auto* weights = task.weights.data(); - const int32_t* shell_list = task.bfn_screening.shell_list.data(); - - // Allocate enough memory for batch - - // Things that every calc needs - host_data.nbe_scr .resize( nbe * nbe * 2 ); - host_data.zmat .resize( npts * nbe * 2); - host_data.eps .resize( npts ); - host_data.vrho .resize( npts * 2); - - // LDA data requirements - if( func.is_lda() ){ - host_data.basis_eval .resize( npts * nbe ); - host_data.den_scr .resize( npts * 2); - } - - // GGA data requirements - if( func.is_gga() ){ - host_data.basis_eval .resize( 4 * npts * nbe ); - host_data.den_scr .resize( 2 * 4 * npts ); - host_data.gamma .resize( 3 * npts ); - host_data.vgamma .resize( 3 * npts ); - } - - // Alias/Partition out scratch memory - auto* basis_eval = host_data.basis_eval.data(); - auto* den_eval = host_data.den_scr.data(); - auto* nbe_scr = host_data.nbe_scr.data(); - auto* zmat = host_data.zmat.data(); - - auto* eps = host_data.eps.data(); - auto* gamma = host_data.gamma.data(); - auto* vrho = host_data.vrho.data(); - auto* vgamma = host_data.vgamma.data(); - - value_type* dbasis_x_eval = nullptr; - value_type* dbasis_y_eval = nullptr; - value_type* dbasis_z_eval = nullptr; - value_type* dden_x_eval = nullptr; - value_type* dden_y_eval = nullptr; - value_type* dden_z_eval = nullptr; - - if( func.is_gga() ) { - dbasis_x_eval = basis_eval + npts * nbe; - dbasis_y_eval = dbasis_x_eval + npts * nbe; - dbasis_z_eval = dbasis_y_eval + npts * nbe; - dden_x_eval = den_eval + 2*npts; - dden_y_eval = dden_x_eval + 2*npts; - dden_z_eval = dden_y_eval + 2*npts; - } + const int32_t* shell_list1 = task.bfn_screening.shell_list.data(); - - // Get the submatrix map for batch - std::vector< std::array > submat_map; - std::tie(submat_map, std::ignore) = - gen_compressed_submat_map(basis_map, task.bfn_screening.shell_list, nbf, nbf); - - // Evaluate Collocation (+ Grad) - if( func.is_gga() ) - lwd->eval_collocation_gradient( npts, nshells, nbe, points, basis, shell_list, - basis_eval, dbasis_x_eval, dbasis_y_eval, dbasis_z_eval ); - else - lwd->eval_collocation( npts, nshells, nbe, points, basis, shell_list, - basis_eval ); - - - // Evaluate X matrix (P * B) -> store in Z - lwd->eval_xmat( npts, nbf, nbe, submat_map, P, ldp, basis_eval, nbe, - zmat, nbe, nbe_scr ); - - lwd->eval_xmat( npts, nbf, nbe, submat_map, Pz, ldpz, basis_eval, nbe, - zmat + npts*nbe, nbe, nbe_scr + nbe * nbe); - - - // Evaluate U and V variables - if( func.is_gga() ) - lwd->eval_uvvar_gga_uks( npts, nbe, basis_eval, dbasis_x_eval, dbasis_y_eval, - dbasis_z_eval, zmat, nbe, den_eval, dden_x_eval, dden_y_eval, dden_z_eval, - gamma ); - else - lwd->eval_uvvar_lda_uks( npts, nbe, basis_eval, zmat, nbe, den_eval ); - - // Evaluate XC functional - if( func.is_gga() ) - func.eval_exc_vxc( npts, den_eval, gamma, eps, vrho, vgamma ); - else - func.eval_exc_vxc( npts, den_eval, eps, vrho ); - - // Factor weights into XC results - for( int32_t i = 0; i < npts; ++i ) { - eps[i] *= weights[i]; - vrho[2*i] *= weights[i]; - vrho[2*i+1] *= weights[i]; - } - - if( func.is_gga() ){ - for( int32_t i = 0; i < npts; ++i ) { - vgamma[3*i] *= weights[i]; - vgamma[3*i+1] *= weights[i]; - vgamma[3*i+2] *= weights[i]; - } - } - - - - // Evaluate Z matrix for VXC - if( func.is_gga() ) - lwd->eval_zmat_gga_vxc_uks( npts, nbe, vrho, vgamma, basis_eval, dbasis_x_eval, - dbasis_y_eval, dbasis_z_eval, dden_x_eval, dden_y_eval, - dden_z_eval, zmat, nbe); - else - lwd->eval_zmat_lda_vxc_uks( npts, nbe, vrho, basis_eval, zmat, nbe ); - - - // Incremeta LT of VXC - #pragma omp critical - { - // Scalar integrations - for( int32_t i = 0; i < npts; ++i ) { - *N_EL += weights[i] * (den_eval[2*i] + den_eval[2*i+1]); - *EXC += eps[i] * (den_eval[2*i] + den_eval[2*i+1]); - } - - // Increment VXC - lwd->inc_vxc( npts, nbf, nbe, basis_eval, submat_map, zmat, nbe, VXC, ldvxc, - nbe_scr ); - lwd->inc_vxc( npts, nbf, nbe, basis_eval, submat_map, zmat+ npts*nbe, nbe, VXCz, ldvxcz, - nbe_scr + nbe * nbe); - - } - - } // Loop over tasks - - } // End OpenMP region - - //std::cout << "N_EL = " << std::setprecision(12) << std::scientific << *N_EL << std::endl; - - // Symmetrize VXC - for( int32_t j = 0; j < nbf; ++j ) { - for( int32_t i = j+1; i < nbf; ++i ) { - VXC[ j + i*nbf ] = VXC[ i + j*nbf ]; - VXCz[ j + i*nbf ] = VXCz[ i + j*nbf ]; - } + std::vector bs2(basis2.size()); + std::iota(bs2.begin(), bs2.end(), 0); + const int32_t* shell_list2 = bs2.data(); } - */ + } + } From e39c08ec385b75673a62ad252e2dff57c1e6aa19 Mon Sep 17 00:00:00 2001 From: aodongliu Date: Fri, 20 Oct 2023 17:11:48 -0700 Subject: [PATCH 07/49] try to evaluate protonic density --- .../host/replicated_host_load_balancer.cxx | 1 + ..._replicated_xc_host_integrator_exc_vxc.hpp | 173 ++++++++++++++++-- .../replicated/host/xc_host_data.hpp | 11 ++ 3 files changed, 169 insertions(+), 16 deletions(-) diff --git a/src/load_balancer/host/replicated_host_load_balancer.cxx b/src/load_balancer/host/replicated_host_load_balancer.cxx index 5a3bb9c9..384dcc40 100644 --- a/src/load_balancer/host/replicated_host_load_balancer.cxx +++ b/src/load_balancer/host/replicated_host_load_balancer.cxx @@ -45,6 +45,7 @@ std::vector< XCTask > HostReplicatedLoadBalancer::create_local_tasks_() const { batcher.quadrature().recenter( center ); const size_t nbatches = batcher.nbatches(); + std::cout << "nbatches: " << nbatches << std::endl; #pragma omp parallel for for( size_t ibatch = 0; ibatch < nbatches; ++ibatch ) { diff --git a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp index 797de4cf..4375a2f8 100644 --- a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp +++ b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp @@ -760,23 +760,23 @@ void ReferenceReplicatedXCHostIntegrator:: // Setup Aliases const auto& func = *this->func_; - const auto& basis1 = this->load_balancer_->basis(); - const auto& basis2 = this->load_balancer_->basis2(); + const auto& basis = this->load_balancer_->basis(); const auto& mol = this->load_balancer_->molecule(); // Get basis map - BasisSetMap basis_map1(basis1,mol); - BasisSetMap basis_map2(basis2,mol); - + BasisSetMap basis_map(basis,mol); - const int32_t nbf1 = basis1.nbf(); + const int32_t nbf = basis.nbf(); + + //NEO + const auto& basis2 = this->load_balancer_->basis2(); + BasisSetMap basis_map2(basis2,mol); const int32_t nbf2 = basis2.nbf(); // Sort tasks on size (XXX: maybe doesnt matter?) auto task_comparator = []( const XCTask& a, const XCTask& b ) { return (a.points.size() * a.bfn_screening.nbe) > (b.points.size() * b.bfn_screening.nbe); }; - auto& tasks = this->load_balancer_->get_tasks(); std::sort( tasks.begin(), tasks.end(), task_comparator ); @@ -789,7 +789,7 @@ void ReferenceReplicatedXCHostIntegrator:: // Zero out integrands - std::fill(VXC1s, VXC1s + nbf1 * ldvxc1s, 0.0); + std::fill(VXC1s, VXC1s + nbf * ldvxc1s, 0.0); std::fill(VXC2s, VXC2s + nbf2 * ldvxc2s, 0.0); std::fill(VXC2z, VXC2z + nbf2 * ldvxc2z, 0.0); @@ -813,19 +813,160 @@ void ReferenceReplicatedXCHostIntegrator:: // Get tasks constants const int32_t npts = task.points.size(); - const int32_t nbe1 = task.bfn_screening.nbe; - const int32_t nshells1 = task.bfn_screening.shell_list.size(); + const int32_t nbe = task.bfn_screening.nbe; + const int32_t nshells = task.bfn_screening.shell_list.size(); + + const auto* points = task.points.data()->data(); + const auto* weights = task.weights.data(); + const int32_t* shell_list = task.bfn_screening.shell_list.data(); + + // Allocate enough memory for batch + + // Things that every calc needs + host_data.nbe_scr .resize( nbe * nbe ); + host_data.zmat .resize( npts * nbe ); + host_data.eps .resize( npts ); + host_data.vrho .resize( npts ); + + // LDA data requirements + if( func.is_lda() ){ + host_data.basis_eval .resize( npts * nbe ); + host_data.den_scr .resize( npts ); + } + + // GGA data requirements + if( func.is_gga() ){ + host_data.basis_eval .resize( 4 * npts * nbe ); + host_data.den_scr .resize( 4 * npts ); + host_data.gamma .resize( npts ); + host_data.vgamma .resize( npts ); + } + // Alias/Partition out scratch memory + auto* basis_eval = host_data.basis_eval.data(); + auto* den_eval = host_data.den_scr.data(); + auto* nbe_scr = host_data.nbe_scr.data(); + auto* zmat = host_data.zmat.data(); + + auto* eps = host_data.eps.data(); + auto* gamma = host_data.gamma.data(); + auto* vrho = host_data.vrho.data(); + auto* vgamma = host_data.vgamma.data(); + + value_type* dbasis_x_eval = nullptr; + value_type* dbasis_y_eval = nullptr; + value_type* dbasis_z_eval = nullptr; + value_type* dden_x_eval = nullptr; + value_type* dden_y_eval = nullptr; + value_type* dden_z_eval = nullptr; + + if( func.is_gga() ) { + dbasis_x_eval = basis_eval + npts * nbe; + dbasis_y_eval = dbasis_x_eval + npts * nbe; + dbasis_z_eval = dbasis_y_eval + npts * nbe; + dden_x_eval = den_eval + npts; + dden_y_eval = dden_x_eval + npts; + dden_z_eval = dden_y_eval + npts; + } + + //----------------------Start Protonic System Setup------------------------ + // Get shell info const int32_t nbe2 = nbf2; const int32_t nshells2 = basis2.nshells(); + std::vector shell_list2_vector; + shell_list2_vector.reserve(basis2.nshells()); + for(auto iSh = 0ul; iSh < basis2.size(); ++iSh) shell_list2_vector.emplace_back( iSh ); + const int32_t* shell_list2 = shell_list2_vector.data(); + + // Set Up Memory + host_data.nbe2_scr .resize( nbe2 * nbe2 * 2); + host_data.zmat2 .resize( npts * nbe2 ); + host_data.eps2 .resize( npts ); + host_data.vrho2 .resize( npts * 2); + // LDA + host_data.basis_eval .resize( npts * nbe2 ); + host_data.den_scr .resize( npts * 2); + // No GGA for NEO yet + // Alias/Partition out scratch memory + auto* basis2_eval = host_data.basis_eval.data(); + auto* den2_eval = host_data.den_scr.data(); + auto* nbe2_scr = host_data.nbe_scr.data(); + auto* zmat2 = host_data.zmat.data(); + auto* eps2 = host_data.eps.data(); + auto* vrho2 = host_data.vrho.data(); - const auto* points = task.points.data()->data(); - const auto* weights = task.weights.data(); - const int32_t* shell_list1 = task.bfn_screening.shell_list.data(); + // No GGA for NEO yet + value_type* dbasis2_x_eval = nullptr; + value_type* dbasis2_y_eval = nullptr; + value_type* dbasis2_z_eval = nullptr; + value_type* dden2_x_eval = nullptr; + value_type* dden2_y_eval = nullptr; + value_type* dden2_z_eval = nullptr; + //----------------------End Protonic System Setup------------------------ + + + + + //----------------------Start Electronic Density Eval------------------------ + // Get the submatrix map for batch + std::vector< std::array > submat_map; + std::tie(submat_map, std::ignore) = + gen_compressed_submat_map(basis_map, task.bfn_screening.shell_list, nbf, nbf); + + // Evaluate Collocation (+ Grad) + if( func.is_gga() ) + lwd->eval_collocation_gradient( npts, nshells, nbe, points, basis, shell_list, + basis_eval, dbasis_x_eval, dbasis_y_eval, dbasis_z_eval ); + else + lwd->eval_collocation( npts, nshells, nbe, points, basis, shell_list, + basis_eval ); + + // Evaluate X matrix (P * B) -> store in Z + lwd->eval_xmat( npts, nbf, nbe, submat_map, P1s, ldp1s, basis_eval, nbe, + zmat, nbe, nbe_scr ); + + // Evaluate U and V variables + if( func.is_gga() ) + lwd->eval_uvvar_gga( npts, nbe, basis_eval, dbasis_x_eval, dbasis_y_eval, + dbasis_z_eval, zmat, nbe, den_eval, dden_x_eval, dden_y_eval, dden_z_eval, + gamma ); + else + lwd->eval_uvvar_lda( npts, nbe, basis_eval, zmat, nbe, den_eval ); + + // Evaluate XC functional + if( func.is_gga() ) + func.eval_exc_vxc( npts, den_eval, gamma, eps, vrho, vgamma ); + else + func.eval_exc_vxc( npts, den_eval, eps, vrho ); + //----------------------End Electronic Density Eval------------------------ + + + + + //----------------------Start Protonic Density Eval------------------------ + // Get the submatrix map for batch + std::vector< std::array > submat_map2; + std::tie(submat_map2, std::ignore) = + gen_compressed_submat_map(basis_map2, shell_list2_vector, nbf2, nbf2); + + // Evaluate Collocation + lwd->eval_collocation( npts, nshells2, nbe2, points, basis2, shell_list2, + basis2_eval ); + + // Evaluate X matrix (P * B) -> store in Z + lwd->eval_xmat( npts, nbf2, nbe2, submat_map2, P2s, ldp2s, basis2_eval, nbe2, + zmat2, nbe2, nbe2_scr ); + lwd->eval_xmat( npts, nbf2, nbe2, submat_map2, P2z, ldp2z, basis2_eval, nbe2, + zmat2 + npts*nbe2, nbe2, nbe2_scr + nbe2 * nbe2); + + lwd->eval_uvvar_lda_uks( npts, nbe2, basis2_eval, zmat2, nbe2, den2_eval ); + //----------------------End Protonic Density Eval------------------------ + + + + + GAUXC_GENERIC_EXCEPTION("AODONG WIP"); - std::vector bs2(basis2.size()); - std::iota(bs2.begin(), bs2.end(), 0); - const int32_t* shell_list2 = bs2.data(); } } diff --git a/src/xc_integrator/replicated/host/xc_host_data.hpp b/src/xc_integrator/replicated/host/xc_host_data.hpp index 5649d523..3d7b0c22 100644 --- a/src/xc_integrator/replicated/host/xc_host_data.hpp +++ b/src/xc_integrator/replicated/host/xc_host_data.hpp @@ -30,6 +30,17 @@ struct XCHostData { std::vector nbe_scr; std::vector den_scr; std::vector basis_eval; + + std::vector eps2; + std::vector gamma2; + std::vector vrho2; + std::vector vgamma2; + + std::vector zmat2; + std::vector gmat2; + std::vector nbe2_scr; + std::vector den2_scr; + std::vector basis2_eval; inline XCHostData() {} From 7fbb65733c743faa2691db68671aa1c07c8e633d Mon Sep 17 00:00:00 2001 From: aodongliu Date: Mon, 23 Oct 2023 19:06:26 -0700 Subject: [PATCH 08/49] first attempt. Begin to debug --- ..._replicated_xc_host_integrator_exc_vxc.hpp | 122 +++++++++++++++++- 1 file changed, 116 insertions(+), 6 deletions(-) diff --git a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp index 4375a2f8..052f080b 100644 --- a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp +++ b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp @@ -907,7 +907,7 @@ void ReferenceReplicatedXCHostIntegrator:: - //----------------------Start Electronic Density Eval------------------------ + //----------------------Start Calculating Electronic Density & UV Variable------------------------ // Get the submatrix map for batch std::vector< std::array > submat_map; std::tie(submat_map, std::ignore) = @@ -938,12 +938,12 @@ void ReferenceReplicatedXCHostIntegrator:: func.eval_exc_vxc( npts, den_eval, gamma, eps, vrho, vgamma ); else func.eval_exc_vxc( npts, den_eval, eps, vrho ); - //----------------------End Electronic Density Eval------------------------ + //----------------------End Calculating Electronic Density & UV Variable------------------------ - //----------------------Start Protonic Density Eval------------------------ + //----------------------Start Calculating Protonic Density & UV Variable------------------------ // Get the submatrix map for batch std::vector< std::array > submat_map2; std::tie(submat_map2, std::ignore) = @@ -959,16 +959,126 @@ void ReferenceReplicatedXCHostIntegrator:: lwd->eval_xmat( npts, nbf2, nbe2, submat_map2, P2z, ldp2z, basis2_eval, nbe2, zmat2 + npts*nbe2, nbe2, nbe2_scr + nbe2 * nbe2); + // Evaluate U and V variables lwd->eval_uvvar_lda_uks( npts, nbe2, basis2_eval, zmat2, nbe2, den2_eval ); - //----------------------End Protonic Density Eval------------------------ + + // No protonic XC functional. Fill with eps and vrho to be 0.0 + std::fill_n(eps2, npts, 0.); + std::fill_n(vrho2, npts*2, 0.); + //----------------------End Calculating Protonic Density & UV Variable------------------------ + + + + + //----------------------Start epc-17-2 functional Evaluation------------------------ + for (int32_t iPt = 0; iPt < npts; iPt++ ){ + // Get Electronic density scalar (RKS) + value_type total_erho = std::abs(den_eval[iPt] > 1e-15) ? den_eval[iPt] : 0.0; + // Get Protonic density scalar (UKS) + value_type total_prho = std::abs(den2_eval[2*iPt] + den2_eval[2*iPt+1]) > 1e-15? + den2_eval[2*iPt]+den2_eval[2*iPt+1] : 0.0; + + // Skip this point if the density is too small + if(total_erho < 1e-15 | total_prho < 1e-15){ + eps2[iPt] = 0.0; + vrho2[2*iPt] = 0.0; + vrho2[2*iPt+1] = 0.0; + continue; + } + + // epc-17-2 denominator + value_type dn = 2.35 - 2.4 * std::sqrt(total_erho*total_prho) + 6.6 * total_erho*total_prho; + + // Update electronic eps and vxc + eps[iPt] += -1.0 * total_prho/dn; + vrho[iPt] += 2 * ( -1.0 * total_prho / dn + (-1.2 * std::sqrt(total_erho) * std::sqrt(total_prho) * total_prho + + 6.6 * total_erho * total_prho * total_prho ) / (dn * dn) ); + + // Assign protonic eps and vxc + eps[iPt] = -1.0 * total_prho/dn; + vrho2[2*iPt] = ( -1.0 * total_erho / dn + (-1.2 * std::sqrt(total_prho) * std::sqrt(total_erho) * total_erho + + 6.6 * total_erho * total_erho * total_prho ) / (dn * dn) ); + vrho2[2*iPt+1] = 0.0; + } + //----------------------End epc-17-2 functional Evaluation------------------------ - GAUXC_GENERIC_EXCEPTION("AODONG WIP"); + + // Factor weights into XC results + for( int32_t i = 0; i < npts; ++i ) { + // Electronic + eps[i] *= weights[i]; + vrho[i] *= weights[i]; + // Protonic + eps2[i] *= weights[i]; + vrho2[2*i] *= weights[i]; + vrho2[2*i+1] *= weights[i]; + } + + if( func.is_gga() ) + for( int32_t i = 0; i < npts; ++i ) vgamma[i] *= weights[i]; + + + + + + // Evaluate Z matrix for VXC + // Electronic + if( func.is_gga() ) + lwd->eval_zmat_gga_vxc( npts, nbe, vrho, vgamma, basis_eval, dbasis_x_eval, + dbasis_y_eval, dbasis_z_eval, dden_x_eval, dden_y_eval, + dden_z_eval, zmat, nbe); + else + lwd->eval_zmat_lda_vxc( npts, nbe, vrho, basis_eval, zmat, nbe ); + // Protonic + lwd->eval_zmat_lda_vxc_uks( npts, nbe2, vrho2, basis2_eval, zmat2, nbe2 ); + + + // Incremeta LT of VXC + #pragma omp critical + { + // Scalar integrations + for( int32_t i = 0; i < npts; ++i ) { + *N_EL += weights[i] * den_eval[i]; + // Electronic XC (VXC+EPC) + *EXC += eps[i] * den_eval[i]; + // Protonic (EPC) + *EXC += eps2[i] * (den2_eval[2*i] + den2_eval[2*i+1]); + } + + // Increment VXC + // Electronic + lwd->inc_vxc( npts, nbf, nbe, basis_eval, submat_map, zmat, nbe, VXC1s, ldvxc1s, + nbe_scr ); + // Protonic + lwd->inc_vxc( npts, nbf2, nbe2, basis2_eval, submat_map2, zmat2, nbe2, VXC2s, ldvxc2s, + nbe2_scr ); + lwd->inc_vxc( npts, nbf2, nbe2, basis2_eval, submat_map2, zmat2+ npts*nbe2, nbe2, VXC2z, ldvxc2z, + nbe2_scr + nbe2 * nbe2); + + } + + } // Loop over tasks + + } // End OpenMP region + + //std::cout << "N_EL = " << std::setprecision(12) << std::scientific << *N_EL << std::endl; + + // Symmetrize Electronic VXC + for( int32_t j = 0; j < nbf; ++j ) + for( int32_t i = j+1; i < nbf; ++i ) + VXC1s[ j + i*nbf ] = VXC1s[ i + j*nbf ]; + + // Symmetrize Protonic VXC + for( int32_t j = 0; j < nbf2; ++j ){ + for( int32_t i = j+1; i < nbf2; ++i ){ + VXC2s[ j + i*nbf2 ] = VXC2s[ i + j*nbf2 ]; + VXC2z[ j + i*nbf2 ] = VXC2z[ i + j*nbf2 ]; + } } - } } From fed1b3e05c08cfe2642ebac24e2ee1fc8511e59c Mon Sep 17 00:00:00 2001 From: Aodong Liu Date: Mon, 30 Oct 2023 22:54:36 -0700 Subject: [PATCH 09/49] allow neo_eval_exc_exc to return 2 energies --- .../gauxc/xc_integrator/replicated/impl.hpp | 14 +++++++------ .../replicated_xc_integrator_impl.hpp | 8 ++++---- ...incore_replicated_xc_device_integrator.hpp | 5 ++--- ...eplicated_xc_device_integrator_exc_vxc.hpp | 8 ++++---- ...atched_replicated_xc_device_integrator.hpp | 4 ++-- ...eplicated_xc_device_integrator_exc_vxc.hpp | 4 ++-- ...eference_replicated_xc_host_integrator.hpp | 8 ++++---- ..._replicated_xc_host_integrator_exc_vxc.hpp | 20 ++++++++++--------- .../replicated_xc_integrator_impl.cxx | 8 ++++---- 9 files changed, 41 insertions(+), 38 deletions(-) diff --git a/include/gauxc/xc_integrator/replicated/impl.hpp b/include/gauxc/xc_integrator/replicated/impl.hpp index 5498595a..80889aab 100644 --- a/include/gauxc/xc_integrator/replicated/impl.hpp +++ b/include/gauxc/xc_integrator/replicated/impl.hpp @@ -128,7 +128,8 @@ typename ReplicatedXCIntegrator::exc_vxc_type_neo_rks matrix_type elec_VXCs( elec_Ps.rows(), elec_Ps.cols() ); matrix_type prot_VXCs( prot_Ps.rows(), prot_Ps.cols() ); matrix_type prot_VXCz( prot_Pz.rows(), prot_Pz.cols() ); - value_type EXC; + value_type elec_EXC; + value_type prot_EXC; pimpl_->neo_eval_exc_vxc( elec_Ps.rows(), elec_Ps.cols(), prot_Ps.rows(), prot_Ps.cols(), elec_Ps.data(), elec_Ps.rows(), @@ -137,9 +138,9 @@ typename ReplicatedXCIntegrator::exc_vxc_type_neo_rks elec_VXCs.data(), elec_VXCs.rows(), prot_VXCs.data(), prot_VXCs.rows(), prot_VXCz.data(), prot_VXCz.rows(), - &EXC); + &elec_EXC, &prot_EXC); - return std::make_tuple( EXC, elec_VXCs, prot_VXCs, prot_VXCz ); + return std::make_tuple( elec_EXC, prot_EXC, elec_VXCs, prot_VXCs, prot_VXCz ); } @@ -153,7 +154,8 @@ typename ReplicatedXCIntegrator::exc_vxc_type_neo_uks matrix_type elec_VXCz( elec_Pz.rows(), elec_Pz.cols() ); matrix_type prot_VXCs( prot_Ps.rows(), prot_Ps.cols() ); matrix_type prot_VXCz( prot_Pz.rows(), prot_Pz.cols() ); - value_type EXC; + value_type elec_EXC; + value_type prot_EXC; pimpl_->neo_eval_exc_vxc( elec_Ps.rows(), elec_Ps.cols(), prot_Ps.rows(), prot_Ps.cols(), elec_Ps.data(), elec_Ps.rows(), @@ -164,9 +166,9 @@ typename ReplicatedXCIntegrator::exc_vxc_type_neo_uks elec_VXCz.data(), elec_VXCz.rows(), prot_VXCs.data(), prot_VXCs.rows(), prot_VXCz.data(), prot_VXCz.rows(), - &EXC); + &elec_EXC, &prot_EXC); - return std::make_tuple( EXC, elec_VXCs, elec_VXCz, prot_VXCs, prot_VXCz ); + return std::make_tuple( elec_EXC, prot_EXC, elec_VXCs, elec_VXCz, prot_VXCs, prot_VXCz ); } diff --git a/include/gauxc/xc_integrator/replicated/replicated_xc_integrator_impl.hpp b/include/gauxc/xc_integrator/replicated/replicated_xc_integrator_impl.hpp index e69d6263..66095645 100644 --- a/include/gauxc/xc_integrator/replicated/replicated_xc_integrator_impl.hpp +++ b/include/gauxc/xc_integrator/replicated/replicated_xc_integrator_impl.hpp @@ -68,7 +68,7 @@ class ReplicatedXCIntegratorImpl { value_type* VXC1s, int64_t ldvxc1s, value_type* VXC2s, int64_t ldvxc2s, value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC, const IntegratorSettingsXC& ks_settings ) = 0; + value_type* EXC1, value_type* EXC2, const IntegratorSettingsXC& ks_settings) = 0; virtual void neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, const value_type* P1s, int64_t ldp1s, const value_type* P1z, int64_t ldp1z, @@ -78,7 +78,7 @@ class ReplicatedXCIntegratorImpl { value_type* VXC1z, int64_t ldvxc1z, value_type* VXC2s, int64_t ldvxc2s, value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC, const IntegratorSettingsXC& ks_settings ) = 0; + value_type* EXC1, value_type* EXC2, const IntegratorSettingsXC& ks_settings) = 0; virtual void eval_exc_grad_( int64_t m, int64_t n, const value_type* P, int64_t ldp, value_type* EXC_GRAD ) = 0; virtual void eval_exx_( int64_t m, int64_t n, const value_type* P, @@ -131,7 +131,7 @@ class ReplicatedXCIntegratorImpl { value_type* VXC1s, int64_t ldvxc1s, value_type* VXC2s, int64_t ldvxc2s, value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC, const IntegratorSettingsXC& ks_settings); + value_type* EXC1, value_type* EXC2, const IntegratorSettingsXC& ks_settings ); void neo_eval_exc_vxc( int64_t m1, int64_t n1, int64_t m2, int64_t n2, const value_type* P1s, int64_t ldp1s, @@ -142,7 +142,7 @@ class ReplicatedXCIntegratorImpl { value_type* VXC1z, int64_t ldvxc1z, value_type* VXC2s, int64_t ldvxc2s, value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC, const IntegratorSettingsXC& ks_settings); + value_type* EXC1, value_type* EXC2, const IntegratorSettingsXC& ks_settings ); void eval_exc_grad( int64_t m, int64_t n, const value_type* P, int64_t ldp, value_type* EXC_GRAD ); diff --git a/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator.hpp b/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator.hpp index c46b75a3..e95621a9 100644 --- a/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator.hpp +++ b/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator.hpp @@ -64,7 +64,7 @@ class IncoreReplicatedXCDeviceIntegrator : value_type* VXC1s, int64_t ldvxc1s, value_type* VXC2s, int64_t ldvxc2s, value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC, const IntegratorSettingsXC& settings) override; + value_type* EXC1, value_type* EXC2, const IntegratorSettingsXC& settings ) override; void neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, const value_type* P1s, int64_t ldp1s, @@ -75,8 +75,7 @@ class IncoreReplicatedXCDeviceIntegrator : value_type* VXC1z, int64_t ldvxc1z, value_type* VXC2s, int64_t ldvxc2s, value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC, const IntegratorSettingsXC& settings) override; - + value_type* EXC1, value_type* EXC2, const IntegratorSettingsXC& settings ) override; void eval_exc_grad_( int64_t m, int64_t n, const value_type* P, int64_t ldp, value_type* EXC_GRAD ) override; diff --git a/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator_exc_vxc.hpp b/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator_exc_vxc.hpp index 570ec9cf..c1e34f2b 100644 --- a/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator_exc_vxc.hpp +++ b/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator_exc_vxc.hpp @@ -148,8 +148,8 @@ void IncoreReplicatedXCDeviceIntegrator:: value_type* VXC1s, int64_t ldvxc1s, value_type* VXC2s, int64_t ldvxc2s, value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC, const IntegratorSettingsXC& settings ) { - GauXC::util::unused(m1,n1,m2,n2,P1s,ldp1s,P2s,ldp2s,P2z,ldp2z,VXC1s,ldvxc1s,VXC2s,ldvxc2s,VXC2z,ldvxc2z,EXC,settings); + value_type* EXC1, value_type* EXC2, const IntegratorSettingsXC& settings ) { + GauXC::util::unused(m1,n1,m2,n2,P1s,ldp1s,P2s,ldp2s,P2z,ldp2z,VXC1s,ldvxc1s,VXC2s,ldvxc2s,VXC2z,ldvxc2z,EXC1,EXC2,settings); GAUXC_GENERIC_EXCEPTION("NEO-RKS NOT YET IMPLEMENTED FOR DEVICE"); } @@ -164,9 +164,9 @@ void IncoreReplicatedXCDeviceIntegrator:: value_type* VXC1z, int64_t ldvxc1z, value_type* VXC2s, int64_t ldvxc2s, value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC, const IntegratorSettingsXC& settings ) { + value_type* EXC1, value_type* EXC2, const IntegratorSettingsXC& settings ) { - GauXC::util::unused(m1,n1,m2,n2,P1s,ldp1s,P1z,ldp1z,P2s,ldp2s,P2z,ldp2z,VXC1s,ldvxc1s,VXC1z,ldvxc1z,VXC2s,ldvxc2s,VXC2z,ldvxc2z,EXC,settings); + GauXC::util::unused(m1,n1,m2,n2,P1s,ldp1s,P1z,ldp1z,P2s,ldp2s,P2z,ldp2z,VXC1s,ldvxc1s,VXC1z,ldvxc1z,VXC2s,ldvxc2s,VXC2z,ldvxc2z,EXC1,EXC2,settings); GAUXC_GENERIC_EXCEPTION("NEO-UKS NOT YET IMPLEMENTED FOR DEVICE"); } diff --git a/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator.hpp b/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator.hpp index dc55785f..430e084d 100644 --- a/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator.hpp +++ b/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator.hpp @@ -75,7 +75,7 @@ class ShellBatchedReplicatedXCDeviceIntegrator : value_type* VXC1s, int64_t ldvxc1s, value_type* VXC2s, int64_t ldvxc2s, value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC ) override; + value_type* EXC1, value_type* EXC2 ) override; void neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, const value_type* P1s, int64_t ldp1s, @@ -86,7 +86,7 @@ class ShellBatchedReplicatedXCDeviceIntegrator : value_type* VXC1z, int64_t ldvxc1z, value_type* VXC2s, int64_t ldvxc2s, value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC ) override; + value_type* EXC1, value_type* EXC2 ) override; void eval_exc_grad_( int64_t m, int64_t n, const value_type* P, int64_t ldp, value_type* EXC_GRAD ) override; diff --git a/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator_exc_vxc.hpp b/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator_exc_vxc.hpp index aa141b80..0f2c6715 100644 --- a/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator_exc_vxc.hpp +++ b/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator_exc_vxc.hpp @@ -129,7 +129,7 @@ void ShellBatchedReplicatedXCDeviceIntegrator:: value_type* VXC1s, int64_t ldvxc1s, value_type* VXC2s, int64_t ldvxc2s, value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC ) { + value_type* EXC1, value_type* EXC2 ) { GauXC::util::unused(m1,n1,m2,n2,P1s,ldp1s,P2s,ldp2s,P2z,ldp2z,VXC1s,ldvxc1s,VXC2s,ldvxc2s,VXC2z,ldvxc2z,EXC); GAUXC_GENERIC_EXCEPTION("NOT YET IMPLEMENTED"); @@ -146,7 +146,7 @@ void ShellBatchedReplicatedXCDeviceIntegrator:: value_type* VXC1z, int64_t ldvxc1z, value_type* VXC2s, int64_t ldvxc2s, value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC ) { + value_type* EXC1, value_type* EXC2 ) { GauXC::util::unused(m1,n1,m2,n2,P1s,ldp1s,P1z,ldp1z,P2s,ldp2s,P2z,ldp2z,VXC1s,ldvxc1s,VXC1z,ldvxc1z,VXC2s,ldvxc2s,VXC2z,ldvxc2z,EXC); GAUXC_GENERIC_EXCEPTION("NOT YET IMPLEMENTED"); diff --git a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator.hpp b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator.hpp index 9dc16b71..53272c2d 100644 --- a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator.hpp +++ b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator.hpp @@ -62,7 +62,7 @@ class ReferenceReplicatedXCHostIntegrator : value_type* VXC1s, int64_t ldvxc1s, value_type* VXC2s, int64_t ldvxc2s, value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC, const IntegratorSettingsXC& ks_settings) override; + value_type* EXC1, value_type* EXC2, const IntegratorSettingsXC& ks_settings ) override; void neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, const value_type* P1s, int64_t ldp1s, @@ -73,7 +73,7 @@ class ReferenceReplicatedXCHostIntegrator : value_type* VXC1z, int64_t ldvxc1z, value_type* VXC2s, int64_t ldvxc2s, value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC, const IntegratorSettingsXC& ks_settings ) override; + value_type* EXC1, value_type* EXC2, const IntegratorSettingsXC& ks_settings ) override; void eval_exc_grad_( int64_t m, int64_t n, const value_type* P, int64_t ldp, value_type* EXC_GRAD ) override; @@ -109,7 +109,7 @@ class ReferenceReplicatedXCHostIntegrator : value_type* VXC1s, int64_t ldvxc1s, value_type* VXC2s, int64_t ldvxc2s, value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC, value_type *N_EL ); + value_type* EXC1, value_type* EXC2, value_type *N_EL ); void neo_exc_vxc_local_work_( const value_type* P1s, int64_t ldp1s, const value_type* P1z, int64_t ldp1z, @@ -119,7 +119,7 @@ class ReferenceReplicatedXCHostIntegrator : value_type* VXC1z, int64_t ldvxc1z, value_type* VXC2s, int64_t ldvxc2s, value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC, value_type *N_EL ); + value_type* EXC1, value_type* EXC2, value_type *N_EL ); void exc_grad_local_work_( const value_type* P, int64_t ldp, value_type* EXC_GRAD ); void exx_local_work_( const value_type* P, int64_t ldp, value_type* K, int64_t ldk, diff --git a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp index 052f080b..e6cdd672 100644 --- a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp +++ b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp @@ -202,8 +202,8 @@ void ReferenceReplicatedXCHostIntegrator:: value_type* VXC1s, int64_t ldvxc1s, value_type* VXC2s, int64_t ldvxc2s, value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC, const IntegratorSettingsXC& ks_settings){ - + value_type* EXC1, value_type* EXC2, const IntegratorSettingsXC& ks_settings ){ + const auto& basis = this->load_balancer_->basis(); const auto& basis2 = this->load_balancer_->basis2(); @@ -234,7 +234,7 @@ void ReferenceReplicatedXCHostIntegrator:: VXC1s, ldvxc1s, VXC2s, ldvxc2s, VXC2z, ldvxc2z, - EXC, &N_EL, ks_settings ); + EXC1, EXC2, &N_EL, ks_settings ); }); @@ -247,7 +247,8 @@ void ReferenceReplicatedXCHostIntegrator:: this->reduction_driver_->allreduce_inplace( VXC1s, nbf1*nbf1, ReductionOp::Sum ); this->reduction_driver_->allreduce_inplace( VXC2s, nbf2*nbf1, ReductionOp::Sum ); this->reduction_driver_->allreduce_inplace( VXC2z, nbf2*nbf2, ReductionOp::Sum ); - this->reduction_driver_->allreduce_inplace( EXC, 1 , ReductionOp::Sum ); + this->reduction_driver_->allreduce_inplace( EXC1, 1 , ReductionOp::Sum ); + this->reduction_driver_->allreduce_inplace( EXC2, 1 , ReductionOp::Sum ); this->reduction_driver_->allreduce_inplace( &N_EL, 1 , ReductionOp::Sum ); }); @@ -751,7 +752,7 @@ void ReferenceReplicatedXCHostIntegrator:: value_type* VXC1s, int64_t ldvxc1s, value_type* VXC2s, int64_t ldvxc2s, value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC, value_type *N_EL ) { + value_type* EXC1, value_type* EXC2, value_type *N_EL ) { //GAUXC_GENERIC_EXCEPTION("neo_exc_vxc_local_work_ RKS NYI"); @@ -793,7 +794,8 @@ void ReferenceReplicatedXCHostIntegrator:: std::fill(VXC2s, VXC2s + nbf2 * ldvxc2s, 0.0); std::fill(VXC2z, VXC2z + nbf2 * ldvxc2z, 0.0); - *EXC = 0.; + *EXC1 = 0.; + *EXC2 = 0.; // Loop over tasks @@ -1044,9 +1046,9 @@ void ReferenceReplicatedXCHostIntegrator:: for( int32_t i = 0; i < npts; ++i ) { *N_EL += weights[i] * den_eval[i]; // Electronic XC (VXC+EPC) - *EXC += eps[i] * den_eval[i]; + *EXC1 += eps[i] * den_eval[i]; // Protonic (EPC) - *EXC += eps2[i] * (den2_eval[2*i] + den2_eval[2*i+1]); + *EXC2 += eps2[i] * (den2_eval[2*i] + den2_eval[2*i+1]); } // Increment VXC @@ -1093,7 +1095,7 @@ void ReferenceReplicatedXCHostIntegrator:: value_type* VXC1z, int64_t ldvxc1z, value_type* VXC2s, int64_t ldvxc2s, value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC, value_type *N_EL ) { + value_type* EXC1, value_type* EXC2, value_type *N_EL ) { GAUXC_GENERIC_EXCEPTION("neo_exc_vxc_local_work_ UKS NYI"); } diff --git a/src/xc_integrator/replicated/replicated_xc_integrator_impl.cxx b/src/xc_integrator/replicated/replicated_xc_integrator_impl.cxx index 5bc2aeca..15af5533 100644 --- a/src/xc_integrator/replicated/replicated_xc_integrator_impl.cxx +++ b/src/xc_integrator/replicated/replicated_xc_integrator_impl.cxx @@ -95,7 +95,7 @@ void ReplicatedXCIntegratorImpl:: value_type* VXC1s, int64_t ldvxc1s, value_type* VXC2s, int64_t ldvxc2s, value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC ){ + value_type* EXC1, value_type* EXC2){ neo_eval_exc_vxc_(m1,n1,m2,n2, P1s,ldp1s, @@ -104,7 +104,7 @@ void ReplicatedXCIntegratorImpl:: VXC1s,ldvxc1s, VXC2s,ldvxc2s, VXC2z,ldvxc2z, - EXC); + EXC1, EXC2); } @@ -119,7 +119,7 @@ void ReplicatedXCIntegratorImpl:: value_type* VXC1z, int64_t ldvxc1z, value_type* VXC2s, int64_t ldvxc2s, value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC ){ + value_type* EXC1, value_type* EXC2 ){ neo_eval_exc_vxc_(m1,n1,m2,n2, P1s,ldp1s, @@ -130,7 +130,7 @@ void ReplicatedXCIntegratorImpl:: VXC1z,ldvxc1z, VXC2s,ldvxc2s, VXC2z,ldvxc2z, - EXC); + EXC1, EXC2); } From 53f255127769d664c4f8965a7a92865c791413e8 Mon Sep 17 00:00:00 2001 From: aodongliu Date: Tue, 24 Oct 2023 11:18:55 -0700 Subject: [PATCH 10/49] correct some errors --- ..._replicated_xc_host_integrator_exc_vxc.hpp | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp index e6cdd672..8de7aa27 100644 --- a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp +++ b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp @@ -754,8 +754,6 @@ void ReferenceReplicatedXCHostIntegrator:: value_type* VXC2z, int64_t ldvxc2z, value_type* EXC1, value_type* EXC2, value_type *N_EL ) { - //GAUXC_GENERIC_EXCEPTION("neo_exc_vxc_local_work_ RKS NYI"); - // Cast LWD to LocalHostWorkDriver auto* lwd = dynamic_cast(this->local_work_driver_.get()); @@ -769,7 +767,7 @@ void ReferenceReplicatedXCHostIntegrator:: const int32_t nbf = basis.nbf(); - //NEO + //NEO basis const auto& basis2 = this->load_balancer_->basis2(); BasisSetMap basis_map2(basis2,mol); const int32_t nbf2 = basis2.nbf(); @@ -882,28 +880,28 @@ void ReferenceReplicatedXCHostIntegrator:: // Set Up Memory host_data.nbe2_scr .resize( nbe2 * nbe2 * 2); - host_data.zmat2 .resize( npts * nbe2 ); + host_data.zmat2 .resize( npts * nbe2 * 2); host_data.eps2 .resize( npts ); host_data.vrho2 .resize( npts * 2); // LDA - host_data.basis_eval .resize( npts * nbe2 ); - host_data.den_scr .resize( npts * 2); + host_data.basis2_eval .resize( npts * nbe2 ); + host_data.den2_scr .resize( npts * 2); // No GGA for NEO yet // Alias/Partition out scratch memory - auto* basis2_eval = host_data.basis_eval.data(); - auto* den2_eval = host_data.den_scr.data(); - auto* nbe2_scr = host_data.nbe_scr.data(); - auto* zmat2 = host_data.zmat.data(); - auto* eps2 = host_data.eps.data(); - auto* vrho2 = host_data.vrho.data(); + auto* basis2_eval = host_data.basis2_eval.data(); + auto* den2_eval = host_data.den2_scr.data(); + auto* nbe2_scr = host_data.nbe2_scr.data(); + auto* zmat2 = host_data.zmat2.data(); + auto* eps2 = host_data.eps2.data(); + auto* vrho2 = host_data.vrho2.data(); // No GGA for NEO yet value_type* dbasis2_x_eval = nullptr; value_type* dbasis2_y_eval = nullptr; value_type* dbasis2_z_eval = nullptr; - value_type* dden2_x_eval = nullptr; - value_type* dden2_y_eval = nullptr; - value_type* dden2_z_eval = nullptr; + value_type* dden2_x_eval = nullptr; + value_type* dden2_y_eval = nullptr; + value_type* dden2_z_eval = nullptr; //----------------------End Protonic System Setup------------------------ @@ -982,25 +980,25 @@ void ReferenceReplicatedXCHostIntegrator:: // Skip this point if the density is too small if(total_erho < 1e-15 | total_prho < 1e-15){ - eps2[iPt] = 0.0; + eps2[iPt] = 0.0; vrho2[2*iPt] = 0.0; vrho2[2*iPt+1] = 0.0; continue; } // epc-17-2 denominator - value_type dn = 2.35 - 2.4 * std::sqrt(total_erho*total_prho) + 6.6 * total_erho*total_prho; + value_type dn = 2.35 - 2.4 * std::sqrt(total_erho*total_prho) + 6.6 * (total_erho*total_prho); // Update electronic eps and vxc - eps[iPt] += -1.0 * total_prho/dn; - vrho[iPt] += 2 * ( -1.0 * total_prho / dn + (-1.2 * std::sqrt(total_erho) * std::sqrt(total_prho) * total_prho - + 6.6 * total_erho * total_prho * total_prho ) / (dn * dn) ); + eps[iPt] += -1.0 * total_prho/dn; + vrho[iPt] += 2 * ( -1.0 * total_prho / dn + (-1.2 * std::sqrt(total_erho) * std::sqrt(total_prho) * total_prho + + 6.6 * total_erho * total_prho * total_prho ) / (dn * dn) ); // Assign protonic eps and vxc - eps[iPt] = -1.0 * total_prho/dn; - vrho2[2*iPt] = ( -1.0 * total_erho / dn + (-1.2 * std::sqrt(total_prho) * std::sqrt(total_erho) * total_erho - + 6.6 * total_erho * total_erho * total_prho ) / (dn * dn) ); - vrho2[2*iPt+1] = 0.0; + eps2[iPt] = -1.0 * total_erho/dn; + vrho2[2*iPt] = ( -1.0 * total_erho / dn + (-1.2 * std::sqrt(total_prho) * std::sqrt(total_erho) * total_erho + + 6.6 * total_erho * total_erho * total_prho ) / (dn * dn) ); + vrho2[2*iPt+1] = 0.0; } //----------------------End epc-17-2 functional Evaluation------------------------ @@ -1012,11 +1010,11 @@ void ReferenceReplicatedXCHostIntegrator:: // Factor weights into XC results for( int32_t i = 0; i < npts; ++i ) { // Electronic - eps[i] *= weights[i]; - vrho[i] *= weights[i]; + eps[i] *= weights[i]; + vrho[i] *= weights[i]; // Protonic - eps2[i] *= weights[i]; - vrho2[2*i] *= weights[i]; + eps2[i] *= weights[i]; + vrho2[2*i] *= weights[i]; vrho2[2*i+1] *= weights[i]; } @@ -1044,7 +1042,7 @@ void ReferenceReplicatedXCHostIntegrator:: { // Scalar integrations for( int32_t i = 0; i < npts; ++i ) { - *N_EL += weights[i] * den_eval[i]; + *N_EL += weights[i] * den_eval[i]; // Electronic XC (VXC+EPC) *EXC1 += eps[i] * den_eval[i]; // Protonic (EPC) @@ -1067,7 +1065,9 @@ void ReferenceReplicatedXCHostIntegrator:: } // End OpenMP region - //std::cout << "N_EL = " << std::setprecision(12) << std::scientific << *N_EL << std::endl; + std::cout << "N_EL = " << std::setprecision(12) << std::scientific << *N_EL << std::endl; + //std::cout << "EXC1 = " << std::setprecision(12) << std::scientific << *EXC1 << std::endl + //std::cout << "EXC2 = " << std::setprecision(12) << std::scientific << *EXC2 << std::endl; // Symmetrize Electronic VXC for( int32_t j = 0; j < nbf; ++j ) From a2fc43ca6f2543e7b59ba35a3c0ec6d829322828 Mon Sep 17 00:00:00 2001 From: aodongliu Date: Tue, 24 Oct 2023 12:45:18 -0700 Subject: [PATCH 11/49] fix factor of 2 in electronic EPC --- .../host/reference_replicated_xc_host_integrator_exc_vxc.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp index 8de7aa27..d70a8409 100644 --- a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp +++ b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp @@ -991,7 +991,7 @@ void ReferenceReplicatedXCHostIntegrator:: // Update electronic eps and vxc eps[iPt] += -1.0 * total_prho/dn; - vrho[iPt] += 2 * ( -1.0 * total_prho / dn + (-1.2 * std::sqrt(total_erho) * std::sqrt(total_prho) * total_prho + vrho[iPt] += ( -1.0 * total_prho / dn + (-1.2 * std::sqrt(total_erho) * std::sqrt(total_prho) * total_prho + 6.6 * total_erho * total_prho * total_prho ) / (dn * dn) ); // Assign protonic eps and vxc @@ -1065,7 +1065,7 @@ void ReferenceReplicatedXCHostIntegrator:: } // End OpenMP region - std::cout << "N_EL = " << std::setprecision(12) << std::scientific << *N_EL << std::endl; + //std::cout << "N_EL = " << std::setprecision(12) << std::scientific << *N_EL << std::endl; //std::cout << "EXC1 = " << std::setprecision(12) << std::scientific << *EXC1 << std::endl //std::cout << "EXC2 = " << std::setprecision(12) << std::scientific << *EXC2 << std::endl; From ad2cd1f4a14ebe4fe43240d7bc3df7448d5ed68d Mon Sep 17 00:00:00 2001 From: aodongliu Date: Fri, 27 Oct 2023 13:31:46 -0700 Subject: [PATCH 12/49] refactor epc functional to be a enum class in GauXC. This is for prepare for later implementation of EPC19 --- include/gauxc/enums.hpp | 8 +++ include/gauxc/load_balancer.hpp | 7 ++- .../host/load_balancer_host_factory.cxx | 6 +- .../host/load_balancer_host_factory.hpp | 2 +- src/load_balancer/load_balancer.cxx | 5 ++ src/load_balancer/load_balancer_factory.cxx | 8 +-- src/load_balancer/load_balancer_impl.cxx | 15 +++-- src/load_balancer/load_balancer_impl.hpp | 8 ++- ..._replicated_xc_host_integrator_exc_vxc.hpp | 61 ++++++++++--------- 9 files changed, 74 insertions(+), 46 deletions(-) diff --git a/include/gauxc/enums.hpp b/include/gauxc/enums.hpp index ce7c19e1..d5182419 100644 --- a/include/gauxc/enums.hpp +++ b/include/gauxc/enums.hpp @@ -58,4 +58,12 @@ enum class SupportedAlg { SNLINK }; +/** + * @brief Specification of NEO Electronc Proton Correlation Functional + */ +enum class EPCFunctional { + EPC17, ///< EPC-17-2 functional, LDA + EPC19 ///< EPC-19 functional, GGA +}; } // namespace GauXC + diff --git a/include/gauxc/load_balancer.hpp b/include/gauxc/load_balancer.hpp index a8fb5832..dc5cbc54 100644 --- a/include/gauxc/load_balancer.hpp +++ b/include/gauxc/load_balancer.hpp @@ -110,6 +110,9 @@ class LoadBalancer { /// Return the number of non-negligible local shell pairs for 2nd basis for this LoadBalancer const shell_pair_type& shell_pairs2() const; + + /// Return the EPC functional for NEO electron-protonic correlation evaluation + const EPCFunctional& epc_functional() const; /// Return the runtime handle used to construct this LoadBalancer const RuntimeEnvironment& runtime() const; @@ -174,7 +177,7 @@ class LoadBalancerFactory { LoadBalancer get_instance( const RuntimeEnvironment& rt, const Molecule& mol, const MolGrid& mg, const BasisSet& bs, - const BasisSet& bs2, size_t pad_val = 1 ); + const BasisSet& bs2, EPCFunctional, size_t pad_val = 1 ); /** * @brief Generate a shared pointer to a LoadBalancer instance per kernel and @@ -196,7 +199,7 @@ class LoadBalancerFactory { std::shared_ptr get_shared_instance( const RuntimeEnvironment& rt, const Molecule& mol, const MolGrid& mg, const BasisSet&, - const BasisSet&, size_t pad_val = 1 ); + const BasisSet&, EPCFunctional, size_t pad_val = 1 ); private: diff --git a/src/load_balancer/host/load_balancer_host_factory.cxx b/src/load_balancer/host/load_balancer_host_factory.cxx index c33c2945..fa062fc5 100644 --- a/src/load_balancer/host/load_balancer_host_factory.cxx +++ b/src/load_balancer/host/load_balancer_host_factory.cxx @@ -44,7 +44,7 @@ std::shared_ptr LoadBalancerHostFactory::get_shared_instance( std::shared_ptr LoadBalancerHostFactory::get_shared_instance( std::string kernel_name, const RuntimeEnvironment& rt, const Molecule& mol, const MolGrid& mg, const BasisSet& basis, - const BasisSet& basis2, size_t pv + const BasisSet& basis2, EPCFunctional epcfunc, size_t pv ) { std::transform(kernel_name.begin(), kernel_name.end(), @@ -57,12 +57,12 @@ std::shared_ptr LoadBalancerHostFactory::get_shared_instance( std::unique_ptr ptr = nullptr; if( kernel_name == "REPLICATED-PETITE" ) ptr = std::make_unique( - rt, mol, mg, basis, basis2, pv + rt, mol, mg, basis, basis2, epcfunc, pv ); if( kernel_name == "REPLICATED-FILLIN" ) ptr = std::make_unique( - rt, mol, mg, basis, basis2, pv + rt, mol, mg, basis, basis2, epcfunc, pv ); if( ! ptr ) GAUXC_GENERIC_EXCEPTION("Load Balancer Kernel Not Recognized: " + kernel_name); diff --git a/src/load_balancer/host/load_balancer_host_factory.hpp b/src/load_balancer/host/load_balancer_host_factory.hpp index bd6a51b2..6926e8c9 100644 --- a/src/load_balancer/host/load_balancer_host_factory.hpp +++ b/src/load_balancer/host/load_balancer_host_factory.hpp @@ -20,7 +20,7 @@ struct LoadBalancerHostFactory { static std::shared_ptr get_shared_instance( std::string kernel_name, const RuntimeEnvironment& rt, const Molecule& mol, const MolGrid& mg, const BasisSet& basis, - const BasisSet& basis2, size_t pv + const BasisSet& basis2, EPCFunctional epcfunc, size_t pv ); }; diff --git a/src/load_balancer/load_balancer.cxx b/src/load_balancer/load_balancer.cxx index df49202f..4cd21c48 100644 --- a/src/load_balancer/load_balancer.cxx +++ b/src/load_balancer/load_balancer.cxx @@ -109,6 +109,11 @@ const LoadBalancer::shell_pair_type& LoadBalancer::shell_pairs2() { if( not pimpl_ ) GAUXC_PIMPL_NOT_INITIALIZED(); return pimpl_->shell_pairs2(); } +const EPCFunctional& LoadBalancer::epc_functional() const{ + if( not pimpl_ ) GAUXC_PIMPL_NOT_INITIALIZED(); + return pimpl_->epc_functional(); + +} LoadBalancerState& LoadBalancer::state() { if( not pimpl_ ) GAUXC_PIMPL_NOT_INITIALIZED(); diff --git a/src/load_balancer/load_balancer_factory.cxx b/src/load_balancer/load_balancer_factory.cxx index bc3b687a..0f898744 100644 --- a/src/load_balancer/load_balancer_factory.cxx +++ b/src/load_balancer/load_balancer_factory.cxx @@ -53,14 +53,14 @@ LoadBalancer LoadBalancerFactory::get_instance( std::shared_ptr LoadBalancerFactory::get_shared_instance( const RuntimeEnvironment& rt, const Molecule& mol, const MolGrid& mg, const BasisSet& basis, - const BasisSet& basis2, size_t pad_value + const BasisSet& basis2, EPCFunctional epcfunc, size_t pad_value ) { switch(ex_) { case ExecutionSpace::Host: using host_factory = LoadBalancerHostFactory; return host_factory::get_shared_instance(kernel_name_, - rt, mol, mg, basis, basis2, pad_value ); + rt, mol, mg, basis, basis2, epcfunc, pad_value ); #ifdef GAUXC_ENABLE_DEVICE case ExecutionSpace::Device: GAUXC_GENERIC_EXCEPTION("2 basis with GPU NYI"); @@ -78,10 +78,10 @@ std::shared_ptr LoadBalancerFactory::get_shared_instance( LoadBalancer LoadBalancerFactory::get_instance( const RuntimeEnvironment& rt, const Molecule& mol, const MolGrid& mg, const BasisSet& basis, - const BasisSet& basis2, size_t pad_value + const BasisSet& basis2, EPCFunctional epcfunc, size_t pad_value ) { - auto ptr = get_shared_instance(rt, mol, mg, basis, basis2, pad_value); + auto ptr = get_shared_instance(rt, mol, mg, basis, basis2, epcfunc, pad_value); return LoadBalancer(std::move(*ptr)); } diff --git a/src/load_balancer/load_balancer_impl.cxx b/src/load_balancer/load_balancer_impl.cxx index 917626e1..adc7c2fa 100644 --- a/src/load_balancer/load_balancer_impl.cxx +++ b/src/load_balancer/load_balancer_impl.cxx @@ -28,7 +28,7 @@ LoadBalancerImpl::LoadBalancerImpl( const RuntimeEnvironment& rt, const Molecule mg_( std::make_shared(mg) ), basis_( std::make_shared(basis) ), basis2_( std::make_shared(basis2) ), - molmeta_( molmeta ) { + molmeta_( molmeta ) { basis_map_ = std::make_shared(*basis_, mol); basis_map2_ = std::make_shared(*basis2_, mol); @@ -58,12 +58,13 @@ LoadBalancerImpl::LoadBalancerImpl( const RuntimeEnvironment& rt, const Molecule LoadBalancerImpl( rt, mol, mg, basis, std::make_shared(mol) ) { } LoadBalancerImpl::LoadBalancerImpl( const RuntimeEnvironment& rt, const Molecule& mol, - const MolGrid& mg, const basis_type& basis, const basis_type& basis2 ) : - LoadBalancerImpl( rt, mol, mg, basis, basis2, std::make_shared(mol) ) { } +LoadBalancerImpl::LoadBalancerImpl( const RuntimeEnvironment& rt, const Molecule& mol, + const MolGrid& mg, const basis_type& basis, const basis_type& basis2, EPCFunctional epcfunc ) : + LoadBalancerImpl( rt, mol, mg, basis, basis2, epcfunc, std::make_shared(mol) ) { } LoadBalancerImpl::LoadBalancerImpl( const RuntimeEnvironment& rt, const Molecule& mol, - const MolGrid& mg, const basis_type& basis, const basis_type& basis2, const MolMeta& molmeta ) : - LoadBalancerImpl( rt, mol, mg, basis, basis2, std::make_shared(molmeta) ) { } + const MolGrid& mg, const basis_type& basis, const basis_type& basis2, EPCFunctional epcfunc, const MolMeta& molmeta ) : + LoadBalancerImpl( rt, mol, mg, basis, basis2, epcfunc, std::make_shared(molmeta) ) { } LoadBalancerImpl::LoadBalancerImpl( const LoadBalancerImpl& ) = default; LoadBalancerImpl::LoadBalancerImpl( LoadBalancerImpl&& ) noexcept = default; @@ -165,6 +166,10 @@ const LoadBalancerImpl::shell_pair_type& LoadBalancerImpl::shell_pairs2() const return *shell_pairs2_; } +const EPCFunctional& LoadBalancerImpl::epc_functional() const{ + return epc_functional_; +} + const RuntimeEnvironment& LoadBalancerImpl::runtime() const { return runtime_; } diff --git a/src/load_balancer/load_balancer_impl.hpp b/src/load_balancer/load_balancer_impl.hpp index e2a0285c..c4e2a4c3 100644 --- a/src/load_balancer/load_balancer_impl.hpp +++ b/src/load_balancer/load_balancer_impl.hpp @@ -33,6 +33,7 @@ class LoadBalancerImpl { std::shared_ptr basis2_; std::shared_ptr basis_map2_; std::shared_ptr shell_pairs2_; + EPCFunctional epc_functional_; std::vector< XCTask > local_tasks_; @@ -54,11 +55,11 @@ class LoadBalancerImpl { const basis_type&, std::shared_ptr ); LoadBalancerImpl( const RuntimeEnvironment&, const Molecule&, const MolGrid& mg, - const basis_type&, const basis_type& ); + const basis_type&, const basis_type&, EPCFunctional ); LoadBalancerImpl( const RuntimeEnvironment&, const Molecule&, const MolGrid& mg, - const basis_type&, const basis_type&, const MolMeta& ); + const basis_type&, const basis_type&, EPCFunctional, const MolMeta& ); LoadBalancerImpl( const RuntimeEnvironment&, const Molecule&, const MolGrid& mg, - const basis_type&, const basis_type&, std::shared_ptr ); + const basis_type&, const basis_type&, EPCFunctional, std::shared_ptr ); LoadBalancerImpl( const LoadBalancerImpl& ); LoadBalancerImpl( LoadBalancerImpl&& ) noexcept; @@ -89,6 +90,7 @@ class LoadBalancerImpl { const basis_map_type& basis_map2() const; const shell_pair_type& shell_pairs2() const; const shell_pair_type& shell_pairs2(); + const EPCFunctional& epc_functional() const; LoadBalancerState& state(); diff --git a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp index d70a8409..b6593e69 100644 --- a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp +++ b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp @@ -759,7 +759,7 @@ void ReferenceReplicatedXCHostIntegrator:: // Setup Aliases const auto& func = *this->func_; - const auto& basis = this->load_balancer_->basis(); + const auto& basis = this->load_balancer_->basis(); const auto& mol = this->load_balancer_->molecule(); // Get basis map @@ -970,37 +970,42 @@ void ReferenceReplicatedXCHostIntegrator:: - //----------------------Start epc-17-2 functional Evaluation------------------------ - for (int32_t iPt = 0; iPt < npts; iPt++ ){ - // Get Electronic density scalar (RKS) - value_type total_erho = std::abs(den_eval[iPt] > 1e-15) ? den_eval[iPt] : 0.0; - // Get Protonic density scalar (UKS) - value_type total_prho = std::abs(den2_eval[2*iPt] + den2_eval[2*iPt+1]) > 1e-15? - den2_eval[2*iPt]+den2_eval[2*iPt+1] : 0.0; - - // Skip this point if the density is too small - if(total_erho < 1e-15 | total_prho < 1e-15){ - eps2[iPt] = 0.0; - vrho2[2*iPt] = 0.0; - vrho2[2*iPt+1] = 0.0; - continue; - } + if(this->load_balancer_->epc_functional() == EPCFunctional::EPC17){ + //----------------------Start epc-17-2 functional Evaluation------------------------ + for (int32_t iPt = 0; iPt < npts; iPt++ ){ + // Get Electronic density scalar (RKS) + value_type total_erho = std::abs(den_eval[iPt] > 1e-15) ? den_eval[iPt] : 0.0; + // Get Protonic density scalar (UKS) + value_type total_prho = std::abs(den2_eval[2*iPt] + den2_eval[2*iPt+1]) > 1e-15? + den2_eval[2*iPt]+den2_eval[2*iPt+1] : 0.0; + + // Skip this point if the density is too small + if(total_erho < 1e-15 | total_prho < 1e-15){ + eps2[iPt] = 0.0; + vrho2[2*iPt] = 0.0; + vrho2[2*iPt+1] = 0.0; + continue; + } - // epc-17-2 denominator - value_type dn = 2.35 - 2.4 * std::sqrt(total_erho*total_prho) + 6.6 * (total_erho*total_prho); + // epc-17-2 denominator + value_type dn = 2.35 - 2.4 * std::sqrt(total_erho*total_prho) + 6.6 * (total_erho*total_prho); - // Update electronic eps and vxc - eps[iPt] += -1.0 * total_prho/dn; - vrho[iPt] += ( -1.0 * total_prho / dn + (-1.2 * std::sqrt(total_erho) * std::sqrt(total_prho) * total_prho - + 6.6 * total_erho * total_prho * total_prho ) / (dn * dn) ); + // Update electronic eps and vxc + eps[iPt] += -1.0 * total_prho/dn; + vrho[iPt] += ( -1.0 * total_prho / dn + (-1.2 * std::sqrt(total_erho) * std::sqrt(total_prho) * total_prho + + 6.6 * total_erho * total_prho * total_prho ) / (dn * dn) ); - // Assign protonic eps and vxc - eps2[iPt] = -1.0 * total_erho/dn; - vrho2[2*iPt] = ( -1.0 * total_erho / dn + (-1.2 * std::sqrt(total_prho) * std::sqrt(total_erho) * total_erho - + 6.6 * total_erho * total_erho * total_prho ) / (dn * dn) ); - vrho2[2*iPt+1] = 0.0; + // Assign protonic eps and vxc + eps2[iPt] = -1.0 * total_erho/dn; + vrho2[2*iPt] = ( -1.0 * total_erho / dn + (-1.2 * std::sqrt(total_prho) * std::sqrt(total_erho) * total_erho + + 6.6 * total_erho * total_erho * total_prho ) / (dn * dn) ); + vrho2[2*iPt+1] = 0.0; + } + //----------------------End epc-17-2 functional Evaluation------------------------ + } else{ + GAUXC_GENERIC_EXCEPTION("Only EPC17 is supported in GauXC"); } - //----------------------End epc-17-2 functional Evaluation------------------------ + From d1a7cecce413c32aacb4d74cba7f75e903b31b3d Mon Sep 17 00:00:00 2001 From: Aodong Liu Date: Mon, 30 Oct 2023 23:12:43 -0700 Subject: [PATCH 13/49] finished rebasing. Need to change function calls in neo. Non-working atm --- include/gauxc/xc_integrator/impl.hpp | 11 ++++++----- include/gauxc/xc_integrator/xc_integrator_impl.hpp | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/include/gauxc/xc_integrator/impl.hpp b/include/gauxc/xc_integrator/impl.hpp index 7ebc5f66..4511c651 100644 --- a/include/gauxc/xc_integrator/impl.hpp +++ b/include/gauxc/xc_integrator/impl.hpp @@ -49,14 +49,15 @@ template typename XCIntegrator::exc_vxc_type_gks XCIntegrator::eval_exc_vxc( const MatrixType& Ps, const MatrixType& Pz, const MatrixType& Py, const MatrixType& Px, const IntegratorSettingsXC& ks_settings ) { - if( not pimpl_ ) GAUXC_PIMPL_NOT_INITIALIZED(); - return pimpl_->eval_exc_vxc(Ps, Pz, Py, Px, ks_settings); - }; + if( not pimpl_ ) GAUXC_PIMPL_NOT_INITIALIZED(); + return pimpl_->eval_exc_vxc(Ps, Pz, Py, Px, ks_settings); +}; + typename XCIntegrator::exc_vxc_type_neo_rks XCIntegrator::neo_eval_exc_vxc( const MatrixType& elec_Ps, const MatrixType& prot_Ps, const MatrixType& prot_Pz, const IntegratorSettingsXC& ks_settings ){ if( not pimpl_ ) GAUXC_PIMPL_NOT_INITIALIZED(); - return pimpl_->neo_eval_exc_vxc(elec_Ps, prot_Ps, prot_Pz); + return pimpl_->neo_eval_exc_vxc(elec_Ps, prot_Ps, prot_Pz, ks_settings); }; template @@ -64,7 +65,7 @@ typename XCIntegrator::exc_vxc_type_neo_uks XCIntegrator::neo_eval_exc_vxc( const MatrixType& elec_Ps, const MatrixType& elec_Pz, const MatrixType& prot_Ps, const MatrixType& prot_Pz, const IntegratorSettingsXC& ks_settings ){ if( not pimpl_ ) GAUXC_PIMPL_NOT_INITIALIZED(); - return pimpl_->neo_eval_exc_vxc(elec_Ps, elec_Pz, prot_Ps, prot_Pz); + return pimpl_->neo_eval_exc_vxc(elec_Ps, elec_Pz, prot_Ps, prot_Pz, ks_settings); }; diff --git a/include/gauxc/xc_integrator/xc_integrator_impl.hpp b/include/gauxc/xc_integrator/xc_integrator_impl.hpp index a2d8f517..7f339fc2 100644 --- a/include/gauxc/xc_integrator/xc_integrator_impl.hpp +++ b/include/gauxc/xc_integrator/xc_integrator_impl.hpp @@ -85,12 +85,12 @@ class XCIntegratorImpl { exc_vxc_type_neo_rks neo_eval_exc_vxc( const MatrixType& elec_Ps, const MatrixType& prot_Ps, const MatrixType& prot_Pz, const IntegratorSettingsXC& ks_settings){ - return neo_eval_exc_vxc_(elec_Ps, prot_Ps, prot_Pz); + return neo_eval_exc_vxc_(elec_Ps, prot_Ps, prot_Pz, ks_settings); } exc_vxc_type_neo_uks neo_eval_exc_vxc( const MatrixType& elec_Ps, const MatrixType& elec_Pz, const MatrixType& prot_Ps, const MatrixType& prot_Pz, const IntegratorSettingsXC& ks_settings){ - return neo_eval_exc_vxc_(elec_Ps, elec_Pz, prot_Ps, prot_Pz); + return neo_eval_exc_vxc_(elec_Ps, elec_Pz, prot_Ps, prot_Pz, ks_settings); } /** Integrate EXC gradient for RKS From 8de578e789076139929bbe38e4184156c54f5cdf Mon Sep 17 00:00:00 2001 From: Aodong Liu Date: Tue, 31 Oct 2023 15:00:14 -0700 Subject: [PATCH 14/49] fix issues to allow energy to match after rebase --- include/gauxc/xc_integrator.hpp | 4 +- .../gauxc/xc_integrator/replicated/impl.hpp | 4 +- .../replicated_xc_integrator_impl.hpp | 4 +- ...incore_replicated_xc_device_integrator.hpp | 4 +- ...eplicated_xc_device_integrator_exc_vxc.hpp | 2 +- ...atched_replicated_xc_device_integrator.hpp | 4 +- ...eplicated_xc_device_integrator_exc_vxc.hpp | 8 +- ...eference_replicated_xc_host_integrator.hpp | 28 +- ..._replicated_xc_host_integrator_exc_vxc.hpp | 283 +++++++++++++----- .../replicated_xc_integrator_impl.cxx | 8 +- 10 files changed, 235 insertions(+), 114 deletions(-) diff --git a/include/gauxc/xc_integrator.hpp b/include/gauxc/xc_integrator.hpp index 8bf1ea66..74b1a381 100644 --- a/include/gauxc/xc_integrator.hpp +++ b/include/gauxc/xc_integrator.hpp @@ -34,8 +34,8 @@ class XCIntegrator { using exc_vxc_type_rks = std::tuple< value_type, matrix_type >; using exc_vxc_type_uks = std::tuple< value_type, matrix_type, matrix_type >; using exc_vxc_type_gks = std::tuple< value_type, matrix_type, matrix_type, matrix_type, matrix_type >; - using exc_vxc_type_neo_rks = std::tuple< value_type, matrix_type, matrix_type, matrix_type >; - using exc_vxc_type_neo_uks = std::tuple< value_type, matrix_type, matrix_type, matrix_type, matrix_type >; + using exc_vxc_type_neo_rks = std::tuple< value_type, value_type, matrix_type, matrix_type, matrix_type >; + using exc_vxc_type_neo_uks = std::tuple< value_type, value_type, matrix_type, matrix_type, matrix_type, matrix_type >; using exc_grad_type = std::vector< value_type >; using exx_type = matrix_type; diff --git a/include/gauxc/xc_integrator/replicated/impl.hpp b/include/gauxc/xc_integrator/replicated/impl.hpp index 80889aab..ad72b273 100644 --- a/include/gauxc/xc_integrator/replicated/impl.hpp +++ b/include/gauxc/xc_integrator/replicated/impl.hpp @@ -131,7 +131,7 @@ typename ReplicatedXCIntegrator::exc_vxc_type_neo_rks value_type elec_EXC; value_type prot_EXC; - pimpl_->neo_eval_exc_vxc( elec_Ps.rows(), elec_Ps.cols(), prot_Ps.rows(), prot_Ps.cols(), + pimpl_->eval_neo_exc_vxc( elec_Ps.rows(), elec_Ps.cols(), prot_Ps.rows(), prot_Ps.cols(), elec_Ps.data(), elec_Ps.rows(), prot_Ps.data(), prot_Ps.rows(), prot_Pz.data(), prot_Pz.rows(), @@ -157,7 +157,7 @@ typename ReplicatedXCIntegrator::exc_vxc_type_neo_uks value_type elec_EXC; value_type prot_EXC; - pimpl_->neo_eval_exc_vxc( elec_Ps.rows(), elec_Ps.cols(), prot_Ps.rows(), prot_Ps.cols(), + pimpl_->eval_neo_exc_vxc( elec_Ps.rows(), elec_Ps.cols(), prot_Ps.rows(), prot_Ps.cols(), elec_Ps.data(), elec_Ps.rows(), elec_Pz.data(), elec_Pz.rows(), prot_Ps.data(), prot_Ps.rows(), diff --git a/include/gauxc/xc_integrator/replicated/replicated_xc_integrator_impl.hpp b/include/gauxc/xc_integrator/replicated/replicated_xc_integrator_impl.hpp index 66095645..fb6eb9d0 100644 --- a/include/gauxc/xc_integrator/replicated/replicated_xc_integrator_impl.hpp +++ b/include/gauxc/xc_integrator/replicated/replicated_xc_integrator_impl.hpp @@ -124,7 +124,7 @@ class ReplicatedXCIntegratorImpl { value_type* VXCx, int64_t ldvxcx, value_type* EXC, const IntegratorSettingsXC& ks_settings ); - void neo_eval_exc_vxc( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + void eval_neo_exc_vxc( int64_t m1, int64_t n1, int64_t m2, int64_t n2, const value_type* P1s, int64_t ldp1s, const value_type* P2s, int64_t ldp2s, const value_type* P2z, int64_t ldp2z, @@ -133,7 +133,7 @@ class ReplicatedXCIntegratorImpl { value_type* VXC2z, int64_t ldvxc2z, value_type* EXC1, value_type* EXC2, const IntegratorSettingsXC& ks_settings ); - void neo_eval_exc_vxc( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + void eval_neo_exc_vxc( int64_t m1, int64_t n1, int64_t m2, int64_t n2, const value_type* P1s, int64_t ldp1s, const value_type* P1z, int64_t ldp1z, const value_type* P2s, int64_t ldp2s, diff --git a/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator.hpp b/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator.hpp index e95621a9..cd2b1cc9 100644 --- a/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator.hpp +++ b/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator.hpp @@ -57,7 +57,7 @@ class IncoreReplicatedXCDeviceIntegrator : value_type* VXCx, int64_t ldvxcx, value_type* EXC, const IntegratorSettingsXC& settings ) override; - void neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + void eval_neo_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, const value_type* P1s, int64_t ldp1s, const value_type* P2s, int64_t ldp2s, const value_type* P2z, int64_t ldp2z, @@ -66,7 +66,7 @@ class IncoreReplicatedXCDeviceIntegrator : value_type* VXC2z, int64_t ldvxc2z, value_type* EXC1, value_type* EXC2, const IntegratorSettingsXC& settings ) override; - void neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + void eval_neo_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, const value_type* P1s, int64_t ldp1s, const value_type* P1z, int64_t ldp1z, const value_type* P2s, int64_t ldp2s, diff --git a/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator_exc_vxc.hpp b/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator_exc_vxc.hpp index c1e34f2b..35a2e44a 100644 --- a/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator_exc_vxc.hpp +++ b/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator_exc_vxc.hpp @@ -155,7 +155,7 @@ void IncoreReplicatedXCDeviceIntegrator:: template void IncoreReplicatedXCDeviceIntegrator:: - neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + eval_neo_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, const value_type* P1s, int64_t ldp1s, const value_type* P1z, int64_t ldp1z, const value_type* P2s, int64_t ldp2s, diff --git a/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator.hpp b/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator.hpp index 430e084d..a6883164 100644 --- a/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator.hpp +++ b/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator.hpp @@ -68,7 +68,7 @@ class ShellBatchedReplicatedXCDeviceIntegrator : value_type* VXCx, int64_t ldvxcx, value_type* EXC, const IntegratorSettingsXC& settings ) override; - void neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + void eval_neo_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, const value_type* P1s, int64_t ldp1s, const value_type* P2s, int64_t ldp2s, const value_type* P2z, int64_t ldp2z, @@ -77,7 +77,7 @@ class ShellBatchedReplicatedXCDeviceIntegrator : value_type* VXC2z, int64_t ldvxc2z, value_type* EXC1, value_type* EXC2 ) override; - void neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + void eval_neo_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, const value_type* P1s, int64_t ldp1s, const value_type* P1z, int64_t ldp1z, const value_type* P2s, int64_t ldp2s, diff --git a/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator_exc_vxc.hpp b/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator_exc_vxc.hpp index 0f2c6715..6b3053c5 100644 --- a/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator_exc_vxc.hpp +++ b/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator_exc_vxc.hpp @@ -122,7 +122,7 @@ void ShellBatchedReplicatedXCDeviceIntegrator:: template void ShellBatchedReplicatedXCDeviceIntegrator:: - neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + eval_neo_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, const value_type* P1s, int64_t ldp1s, const value_type* P2s, int64_t ldp2s, const value_type* P2z, int64_t ldp2z, @@ -132,12 +132,12 @@ void ShellBatchedReplicatedXCDeviceIntegrator:: value_type* EXC1, value_type* EXC2 ) { GauXC::util::unused(m1,n1,m2,n2,P1s,ldp1s,P2s,ldp2s,P2z,ldp2z,VXC1s,ldvxc1s,VXC2s,ldvxc2s,VXC2z,ldvxc2z,EXC); - GAUXC_GENERIC_EXCEPTION("NOT YET IMPLEMENTED"); + GAUXC_GENERIC_EXCEPTION("NEO RKS NOT YET IMPLEMENTED FOR DEVICE"); } template void ShellBatchedReplicatedXCDeviceIntegrator:: - neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + eval_neo_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, const value_type* P1s, int64_t ldp1s, const value_type* P1z, int64_t ldp1z, const value_type* P2s, int64_t ldp2s, @@ -149,7 +149,7 @@ void ShellBatchedReplicatedXCDeviceIntegrator:: value_type* EXC1, value_type* EXC2 ) { GauXC::util::unused(m1,n1,m2,n2,P1s,ldp1s,P1z,ldp1z,P2s,ldp2s,P2z,ldp2z,VXC1s,ldvxc1s,VXC1z,ldvxc1z,VXC2s,ldvxc2s,VXC2z,ldvxc2z,EXC); - GAUXC_GENERIC_EXCEPTION("NOT YET IMPLEMENTED"); + GAUXC_GENERIC_EXCEPTION("NEO UKS NOT YET IMPLEMENTED FOR DEVICE"); } template diff --git a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator.hpp b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator.hpp index 53272c2d..9ebc9af6 100644 --- a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator.hpp +++ b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator.hpp @@ -55,7 +55,7 @@ class ReferenceReplicatedXCHostIntegrator : value_type* EXC, const IntegratorSettingsXC& ks_settings ) override; - void neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + void eval_neo_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, const value_type* P1s, int64_t ldp1s, const value_type* P2s, int64_t ldp2s, const value_type* P2z, int64_t ldp2z, @@ -64,7 +64,7 @@ class ReferenceReplicatedXCHostIntegrator : value_type* VXC2z, int64_t ldvxc2z, value_type* EXC1, value_type* EXC2, const IntegratorSettingsXC& ks_settings ) override; - void neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + void eval_neo_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, const value_type* P1s, int64_t ldp1s, const value_type* P1z, int64_t ldp1z, const value_type* P2s, int64_t ldp2s, @@ -104,22 +104,14 @@ class ReferenceReplicatedXCHostIntegrator : const IntegratorSettingsXC& ks_settings ); void neo_exc_vxc_local_work_( const value_type* P1s, int64_t ldp1s, - const value_type* P2s, int64_t ldp2s, - const value_type* P2z, int64_t ldp2z, - value_type* VXC1s, int64_t ldvxc1s, - value_type* VXC2s, int64_t ldvxc2s, - value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC1, value_type* EXC2, value_type *N_EL ); - - void neo_exc_vxc_local_work_( const value_type* P1s, int64_t ldp1s, - const value_type* P1z, int64_t ldp1z, - const value_type* P2s, int64_t ldp2s, - const value_type* P2z, int64_t ldp2z, - value_type* VXC1s, int64_t ldvxc1s, - value_type* VXC1z, int64_t ldvxc1z, - value_type* VXC2s, int64_t ldvxc2s, - value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC1, value_type* EXC2, value_type *N_EL ); + const value_type* P1z, int64_t ldp1z, + const value_type* P2s, int64_t ldp2s, + const value_type* P2z, int64_t ldp2z, + value_type* VXC1s, int64_t ldvxc1s, + value_type* VXC1z, int64_t ldvxc1z, + value_type* VXC2s, int64_t ldvxc2s, + value_type* VXC2z, int64_t ldvxc2z, + value_type* EXC1, value_type* EXC2, value_type *N_EL ); void exc_grad_local_work_( const value_type* P, int64_t ldp, value_type* EXC_GRAD ); void exx_local_work_( const value_type* P, int64_t ldp, value_type* K, int64_t ldk, diff --git a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp index b6593e69..4c709cd4 100644 --- a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp +++ b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp @@ -229,9 +229,11 @@ void ReferenceReplicatedXCHostIntegrator:: // Compute Local contributions to EXC / VXC this->timer_.time_op("XCIntegrator.LocalWork", [&](){ neo_exc_vxc_local_work_( P1s, ldp1s, + nullptr, 0, P2s, ldp2s, P2z, ldp2z, VXC1s, ldvxc1s, + nullptr, 0, VXC2s, ldvxc2s, VXC2z, ldvxc2z, EXC1, EXC2, &N_EL, ks_settings ); @@ -255,6 +257,74 @@ void ReferenceReplicatedXCHostIntegrator:: } +template +void ReferenceReplicatedXCHostIntegrator:: + eval_neo_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + const value_type* P1s, int64_t ldp1s, + const value_type* P1z, int64_t ldp1z, + const value_type* P2s, int64_t ldp2s, + const value_type* P2z, int64_t ldp2z, + value_type* VXC1s, int64_t ldvxc1s, + value_type* VXC1z, int64_t ldvxc1z, + value_type* VXC2s, int64_t ldvxc2s, + value_type* VXC2z, int64_t ldvxc2z, + value_type* EXC1, value_type* EXC2 ) { + + const auto& basis = this->load_balancer_->basis(); + const auto& basis2 = this->load_balancer_->basis2(); + + // Check that P / VXC are sane + const int64_t nbf1 = basis.nbf(); + const int64_t nbf2 = basis2.nbf(); + + if( m1 != n1 | m2 != n2) + GAUXC_GENERIC_EXCEPTION("P/VXC Must Be Square"); + if( m1 != nbf1 | m2 != nbf2) + GAUXC_GENERIC_EXCEPTION("P/VXC Must Have Same Dimension as Basis"); + if( ldp1s < nbf1 | ldp2s < nbf2 | ldp2z < nbf2 ) + GAUXC_GENERIC_EXCEPTION("Invalid LDP"); + if( ldvxc1s < nbf1 | ldvxc2s < nbf2 | ldvxc2z < nbf2 ) + GAUXC_GENERIC_EXCEPTION("Invalid LDVXC"); + + // Get Tasks + this->load_balancer_->get_tasks(); + + // Temporary electron count to judge integrator accuracy + value_type N_EL; + + // Compute Local contributions to EXC / VXC + this->timer_.time_op("XCIntegrator.LocalWork", [&](){ + neo_exc_vxc_local_work_( P1s, ldp1s, + P1z, ldp1z, + P2s, ldp2s, + P2z, ldp2z, + VXC1s, ldvxc1s, + VXC1z, ldvxc1z, + VXC2s, ldvxc2s, + VXC2z, ldvxc2z, + EXC1, EXC2, &N_EL ); + }); + + + // Reduce Results + this->timer_.time_op("XCIntegrator.Allreduce", [&](){ + + if( not this->reduction_driver_->takes_host_memory() ) + GAUXC_GENERIC_EXCEPTION("This Module Only Works With Host Reductions"); + + this->reduction_driver_->allreduce_inplace( VXC1s, nbf1*nbf1, ReductionOp::Sum ); + this->reduction_driver_->allreduce_inplace( VXC1z, nbf1*nbf1, ReductionOp::Sum ); + this->reduction_driver_->allreduce_inplace( VXC2s, nbf2*nbf1, ReductionOp::Sum ); + this->reduction_driver_->allreduce_inplace( VXC2z, nbf2*nbf2, ReductionOp::Sum ); + this->reduction_driver_->allreduce_inplace( EXC1, 1 , ReductionOp::Sum ); + this->reduction_driver_->allreduce_inplace( EXC2, 1 , ReductionOp::Sum ); + this->reduction_driver_->allreduce_inplace( &N_EL, 1 , ReductionOp::Sum ); + + }); + +} + + template void ReferenceReplicatedXCHostIntegrator:: exc_vxc_local_work_( const value_type* Ps, int64_t ldps, @@ -747,13 +817,20 @@ void ReferenceReplicatedXCHostIntegrator:: template void ReferenceReplicatedXCHostIntegrator:: neo_exc_vxc_local_work_( const value_type* P1s, int64_t ldp1s, - const value_type* P2s, int64_t ldp2s, - const value_type* P2z, int64_t ldp2z, - value_type* VXC1s, int64_t ldvxc1s, - value_type* VXC2s, int64_t ldvxc2s, - value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC1, value_type* EXC2, value_type *N_EL ) { + const value_type* P1z, int64_t ldp1z, + const value_type* P2s, int64_t ldp2s, + const value_type* P2z, int64_t ldp2z, + value_type* VXC1s, int64_t ldvxc1s, + value_type* VXC1z, int64_t ldvxc1z, + value_type* VXC2s, int64_t ldvxc2s, + value_type* VXC2z, int64_t ldvxc2z, + value_type* EXC1, value_type* EXC2, value_type *N_EL ) { + + // Determine is electronic subsystem is RKS or UKS + const bool is_uks = (P1z != nullptr) and (VXC1z != nullptr); + const bool is_rks = not is_uks; // TODO: GKS + // Cast LWD to LocalHostWorkDriver auto* lwd = dynamic_cast(this->local_work_driver_.get()); @@ -767,7 +844,7 @@ void ReferenceReplicatedXCHostIntegrator:: const int32_t nbf = basis.nbf(); - //NEO basis + // Get Protonic basis information const auto& basis2 = this->load_balancer_->basis2(); BasisSetMap basis_map2(basis2,mol); const int32_t nbf2 = basis2.nbf(); @@ -789,6 +866,8 @@ void ReferenceReplicatedXCHostIntegrator:: // Zero out integrands std::fill(VXC1s, VXC1s + nbf * ldvxc1s, 0.0); + if(is_uks) std::fill(VXC1z, VXC1z + nbf * ldvxc1z, 0.0); + std::fill(VXC2s, VXC2s + nbf2 * ldvxc2s, 0.0); std::fill(VXC2z, VXC2z + nbf2 * ldvxc2z, 0.0); @@ -822,24 +901,26 @@ void ReferenceReplicatedXCHostIntegrator:: // Allocate enough memory for batch + const size_t spin_dim_scal = is_rks ? 1 : 2; // Things that every calc needs - host_data.nbe_scr .resize( nbe * nbe ); - host_data.zmat .resize( npts * nbe ); - host_data.eps .resize( npts ); - host_data.vrho .resize( npts ); + host_data.nbe_scr .resize(nbe * nbe); + host_data.zmat .resize(npts * nbe * spin_dim_scal); + host_data.eps .resize(npts); + host_data.vrho .resize(npts * spin_dim_scal); // LDA data requirements if( func.is_lda() ){ host_data.basis_eval .resize( npts * nbe ); - host_data.den_scr .resize( npts ); + host_data.den_scr .resize( npts * spin_dim_scal); } // GGA data requirements + const size_t gga_dim_scal = is_rks ? 1 : 3; if( func.is_gga() ){ host_data.basis_eval .resize( 4 * npts * nbe ); - host_data.den_scr .resize( 4 * npts ); - host_data.gamma .resize( npts ); - host_data.vgamma .resize( npts ); + host_data.den_scr .resize( spin_dim_scal * 4 * npts ); + host_data.gamma .resize( gga_dim_scal * npts ); + host_data.vgamma .resize( gga_dim_scal * npts ); } // Alias/Partition out scratch memory @@ -848,6 +929,11 @@ void ReferenceReplicatedXCHostIntegrator:: auto* nbe_scr = host_data.nbe_scr.data(); auto* zmat = host_data.zmat.data(); + decltype(zmat) zmat_z = nullptr; + if(!is_rks) { + zmat_z = zmat + nbe * npts; + } + auto* eps = host_data.eps.data(); auto* gamma = host_data.gamma.data(); auto* vrho = host_data.vrho.data(); @@ -864,9 +950,9 @@ void ReferenceReplicatedXCHostIntegrator:: dbasis_x_eval = basis_eval + npts * nbe; dbasis_y_eval = dbasis_x_eval + npts * nbe; dbasis_z_eval = dbasis_y_eval + npts * nbe; - dden_x_eval = den_eval + npts; - dden_y_eval = dden_x_eval + npts; - dden_z_eval = dden_y_eval + npts; + dden_x_eval = den_eval + spin_dim_scal * npts; + dden_y_eval = dden_x_eval + spin_dim_scal * npts; + dden_z_eval = dden_y_eval + spin_dim_scal * npts; } //----------------------Start Protonic System Setup------------------------ @@ -878,11 +964,11 @@ void ReferenceReplicatedXCHostIntegrator:: for(auto iSh = 0ul; iSh < basis2.size(); ++iSh) shell_list2_vector.emplace_back( iSh ); const int32_t* shell_list2 = shell_list2_vector.data(); - // Set Up Memory - host_data.nbe2_scr .resize( nbe2 * nbe2 * 2); - host_data.zmat2 .resize( npts * nbe2 * 2); + // Set Up Memory (assuming UKS) + host_data.nbe2_scr .resize( nbe2 * nbe2 ); + host_data.zmat2 .resize( npts * nbe2 * 2 ); host_data.eps2 .resize( npts ); - host_data.vrho2 .resize( npts * 2); + host_data.vrho2 .resize( npts * 2 ); // LDA host_data.basis2_eval .resize( npts * nbe2 ); host_data.den2_scr .resize( npts * 2); @@ -892,6 +978,8 @@ void ReferenceReplicatedXCHostIntegrator:: auto* den2_eval = host_data.den2_scr.data(); auto* nbe2_scr = host_data.nbe2_scr.data(); auto* zmat2 = host_data.zmat2.data(); + decltype(zmat2) zmat2_z = zmat2 + nbe2 * npts; + auto* eps2 = host_data.eps2.data(); auto* vrho2 = host_data.vrho2.data(); @@ -921,17 +1009,36 @@ void ReferenceReplicatedXCHostIntegrator:: lwd->eval_collocation( npts, nshells, nbe, points, basis, shell_list, basis_eval ); - // Evaluate X matrix (P * B) -> store in Z - lwd->eval_xmat( npts, nbf, nbe, submat_map, P1s, ldp1s, basis_eval, nbe, + // Evaluate X matrix (fac * P * B) -> store in Z + const auto xmat_fac = is_rks ? 2.0 : 1.0; // TODO Fix for spinor RKS input + lwd->eval_xmat( npts, nbf, nbe, submat_map, xmat_fac, P1s, ldp1s, basis_eval, nbe, zmat, nbe, nbe_scr ); + // X matrix for Pz + if(not is_rks) { + lwd->eval_xmat( npts, nbf, nbe, submat_map, 1.0, P1z, ldp1z, basis_eval, nbe, + zmat_z, nbe, nbe_scr ); + } + // Evaluate U and V variables - if( func.is_gga() ) - lwd->eval_uvvar_gga( npts, nbe, basis_eval, dbasis_x_eval, dbasis_y_eval, - dbasis_z_eval, zmat, nbe, den_eval, dden_x_eval, dden_y_eval, dden_z_eval, - gamma ); - else - lwd->eval_uvvar_lda( npts, nbe, basis_eval, zmat, nbe, den_eval ); + if( func.is_gga() ) { + if(is_rks) { + lwd->eval_uvvar_gga_rks( npts, nbe, basis_eval, dbasis_x_eval, dbasis_y_eval, + dbasis_z_eval, zmat, nbe, den_eval, dden_x_eval, dden_y_eval, dden_z_eval, + gamma ); + } else if(is_uks) { + lwd->eval_uvvar_gga_uks( npts, nbe, basis_eval, dbasis_x_eval, dbasis_y_eval, + dbasis_z_eval, zmat, nbe, zmat_z, nbe, den_eval, dden_x_eval, + dden_y_eval, dden_z_eval, gamma ); + } + } else { + if(is_rks) { + lwd->eval_uvvar_lda_rks( npts, nbe, basis_eval, zmat, nbe, den_eval ); + } else if(is_uks) { + lwd->eval_uvvar_lda_uks( npts, nbe, basis_eval, zmat, nbe, zmat_z, nbe, + den_eval ); + } + } // Evaluate XC functional if( func.is_gga() ) @@ -954,13 +1061,15 @@ void ReferenceReplicatedXCHostIntegrator:: basis2_eval ); // Evaluate X matrix (P * B) -> store in Z - lwd->eval_xmat( npts, nbf2, nbe2, submat_map2, P2s, ldp2s, basis2_eval, nbe2, + // NEED THE FACTOR OF 2 HERE! + lwd->eval_xmat( npts, nbf2, nbe2, submat_map2, 2.0, P2s, ldp2s, basis2_eval, nbe2, zmat2, nbe2, nbe2_scr ); - lwd->eval_xmat( npts, nbf2, nbe2, submat_map2, P2z, ldp2z, basis2_eval, nbe2, - zmat2 + npts*nbe2, nbe2, nbe2_scr + nbe2 * nbe2); + lwd->eval_xmat( npts, nbf2, nbe2, submat_map2, 2.0, P2z, ldp2z, basis2_eval, nbe2, + zmat2_z, nbe2, nbe2_scr ); // Evaluate U and V variables - lwd->eval_uvvar_lda_uks( npts, nbe2, basis2_eval, zmat2, nbe2, den2_eval ); + lwd->eval_uvvar_lda_uks( npts, nbe2, basis2_eval, zmat2, nbe2, zmat2_z, nbe2, + den2_eval ); // No protonic XC functional. Fill with eps and vrho to be 0.0 std::fill_n(eps2, npts, 0.); @@ -974,10 +1083,11 @@ void ReferenceReplicatedXCHostIntegrator:: //----------------------Start epc-17-2 functional Evaluation------------------------ for (int32_t iPt = 0; iPt < npts; iPt++ ){ // Get Electronic density scalar (RKS) - value_type total_erho = std::abs(den_eval[iPt] > 1e-15) ? den_eval[iPt] : 0.0; + const auto den = is_rks ? den_eval[iPt] : (den_eval[2*iPt] + den_eval[2*iPt+1]); + value_type total_erho = std::abs(den) > 1e-15? den : 0; // Get Protonic density scalar (UKS) - value_type total_prho = std::abs(den2_eval[2*iPt] + den2_eval[2*iPt+1]) > 1e-15? - den2_eval[2*iPt]+den2_eval[2*iPt+1] : 0.0; + const auto den2 = den2_eval[2*iPt] + den2_eval[2*iPt+1]; + value_type total_prho = std::abs(den2) > 1e-15? den2 : 0; // Skip this point if the density is too small if(total_erho < 1e-15 | total_prho < 1e-15){ @@ -991,9 +1101,12 @@ void ReferenceReplicatedXCHostIntegrator:: value_type dn = 2.35 - 2.4 * std::sqrt(total_erho*total_prho) + 6.6 * (total_erho*total_prho); // Update electronic eps and vxc - eps[iPt] += -1.0 * total_prho/dn; - vrho[iPt] += ( -1.0 * total_prho / dn + (-1.2 * std::sqrt(total_erho) * std::sqrt(total_prho) * total_prho - + 6.6 * total_erho * total_prho * total_prho ) / (dn * dn) ); + eps[iPt] += -1.0 * total_prho/dn; + vrho[spin_dim_scal*iPt] += ( -1.0 * total_prho / dn + (-1.2 * std::sqrt(total_erho) * std::sqrt(total_prho) * total_prho + + 6.6 * total_erho * total_prho * total_prho ) / (dn * dn) ); + if(not is_rks) + vrho[spin_dim_scal*iPt+1] += ( -1.0 * total_prho / dn + (-1.2 * std::sqrt(total_erho) * std::sqrt(total_prho) * total_prho + + 6.6 * total_erho * total_prho * total_prho ) / (dn * dn) ); // Assign protonic eps and vxc eps2[iPt] = -1.0 * total_erho/dn; @@ -1015,31 +1128,48 @@ void ReferenceReplicatedXCHostIntegrator:: // Factor weights into XC results for( int32_t i = 0; i < npts; ++i ) { // Electronic - eps[i] *= weights[i]; - vrho[i] *= weights[i]; + eps[i] *= weights[i]; + vrho[spin_dim_scal*i] *= weights[i]; + if(not is_rks) vrho[spin_dim_scal*i+1] *= weights[i]; // Protonic eps2[i] *= weights[i]; vrho2[2*i] *= weights[i]; vrho2[2*i+1] *= weights[i]; } - if( func.is_gga() ) - for( int32_t i = 0; i < npts; ++i ) vgamma[i] *= weights[i]; - - + if( func.is_gga() ){ + for( int32_t i = 0; i < npts; ++i ) { + vgamma[gga_dim_scal*i] *= weights[i]; + if(not is_rks) { + vgamma[gga_dim_scal*i+1] *= weights[i]; + vgamma[gga_dim_scal*i+2] *= weights[i]; + } + } + } // Evaluate Z matrix for VXC // Electronic - if( func.is_gga() ) - lwd->eval_zmat_gga_vxc( npts, nbe, vrho, vgamma, basis_eval, dbasis_x_eval, - dbasis_y_eval, dbasis_z_eval, dden_x_eval, dden_y_eval, - dden_z_eval, zmat, nbe); - else - lwd->eval_zmat_lda_vxc( npts, nbe, vrho, basis_eval, zmat, nbe ); + if( func.is_gga() ) { + if(is_rks) { + lwd->eval_zmat_gga_vxc_rks( npts, nbe, vrho, vgamma, basis_eval, dbasis_x_eval, + dbasis_y_eval, dbasis_z_eval, dden_x_eval, dden_y_eval, + dden_z_eval, zmat, nbe); + } else if(is_uks) { + lwd->eval_zmat_gga_vxc_uks( npts, nbe, vrho, vgamma, basis_eval, dbasis_x_eval, + dbasis_y_eval, dbasis_z_eval, dden_x_eval, dden_y_eval, + dden_z_eval, zmat, nbe, zmat_z, nbe); + } + } else { + if(is_rks) { + lwd->eval_zmat_lda_vxc_rks( npts, nbe, vrho, basis_eval, zmat, nbe ); + } else if(is_uks) { + lwd->eval_zmat_lda_vxc_uks( npts, nbe, vrho, basis_eval, zmat, nbe, zmat_z, nbe ); + } + } // Protonic - lwd->eval_zmat_lda_vxc_uks( npts, nbe2, vrho2, basis2_eval, zmat2, nbe2 ); + lwd->eval_zmat_lda_vxc_uks( npts, nbe2, vrho2, basis2_eval, zmat2, nbe2, zmat2_z, nbe2 ); // Incremeta LT of VXC @@ -1047,63 +1177,62 @@ void ReferenceReplicatedXCHostIntegrator:: { // Scalar integrations for( int32_t i = 0; i < npts; ++i ) { - *N_EL += weights[i] * den_eval[i]; // Electronic XC (VXC+EPC) - *EXC1 += eps[i] * den_eval[i]; + const auto den = is_rks ? den_eval[i] : (den_eval[2*i] + den_eval[2*i+1]); + *N_EL += weights[i] * den; + *EXC1 += eps[i] * den; // Protonic (EPC) - *EXC2 += eps2[i] * (den2_eval[2*i] + den2_eval[2*i+1]); + const auto den2 = den2_eval[2*i] + den2_eval[2*i+1]; + *EXC2 += eps2[i] * den2; } // Increment VXC // Electronic lwd->inc_vxc( npts, nbf, nbe, basis_eval, submat_map, zmat, nbe, VXC1s, ldvxc1s, nbe_scr ); + if(not is_rks) + lwd->inc_vxc( npts, nbf, nbe, basis_eval, submat_map, zmat_z, nbe, VXC1z, ldvxc1z, + nbe_scr ); // Protonic lwd->inc_vxc( npts, nbf2, nbe2, basis2_eval, submat_map2, zmat2, nbe2, VXC2s, ldvxc2s, nbe2_scr ); - lwd->inc_vxc( npts, nbf2, nbe2, basis2_eval, submat_map2, zmat2+ npts*nbe2, nbe2, VXC2z, ldvxc2z, - nbe2_scr + nbe2 * nbe2); + lwd->inc_vxc( npts, nbf2, nbe2, basis2_eval, submat_map2, zmat2_z, nbe2, VXC2z, ldvxc2z, + nbe2_scr ); - } + } // End #pragma omp critical } // Loop over tasks } // End OpenMP region - //std::cout << "N_EL = " << std::setprecision(12) << std::scientific << *N_EL << std::endl; + std::cout << "N_EL = " << std::setprecision(12) << std::scientific << *N_EL << std::endl; //std::cout << "EXC1 = " << std::setprecision(12) << std::scientific << *EXC1 << std::endl //std::cout << "EXC2 = " << std::setprecision(12) << std::scientific << *EXC2 << std::endl; // Symmetrize Electronic VXC for( int32_t j = 0; j < nbf; ++j ) for( int32_t i = j+1; i < nbf; ++i ) - VXC1s[ j + i*nbf ] = VXC1s[ i + j*nbf ]; + VXC1s[ j + i*ldvxc1s ] = VXC1s[ i + j*ldvxc1s ]; + if(not is_rks) { + for( int32_t j = 0; j < nbf; ++j ) { + for( int32_t i = j+1; i < nbf; ++i ) { + VXC1z[ j + i*ldvxc1z ] = VXC1z[ i + j*ldvxc1z ]; + } + } + } // Symmetrize Protonic VXC for( int32_t j = 0; j < nbf2; ++j ){ for( int32_t i = j+1; i < nbf2; ++i ){ - VXC2s[ j + i*nbf2 ] = VXC2s[ i + j*nbf2 ]; - VXC2z[ j + i*nbf2 ] = VXC2z[ i + j*nbf2 ]; + VXC2s[ j + i*ldvxc2s ] = VXC2s[ i + j*ldvxc2s ]; + VXC2z[ j + i*ldvxc2z ] = VXC2z[ i + j*ldvxc2z ]; } } } -template -void ReferenceReplicatedXCHostIntegrator:: - neo_exc_vxc_local_work_( const value_type* P1s, int64_t ldp1s, - const value_type* P1z, int64_t ldp1z, - const value_type* P2s, int64_t ldp2s, - const value_type* P2z, int64_t ldp2z, - value_type* VXC1s, int64_t ldvxc1s, - value_type* VXC1z, int64_t ldvxc1z, - value_type* VXC2s, int64_t ldvxc2s, - value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC1, value_type* EXC2, value_type *N_EL ) { - - GAUXC_GENERIC_EXCEPTION("neo_exc_vxc_local_work_ UKS NYI"); -} + } } diff --git a/src/xc_integrator/replicated/replicated_xc_integrator_impl.cxx b/src/xc_integrator/replicated/replicated_xc_integrator_impl.cxx index 15af5533..a5961753 100644 --- a/src/xc_integrator/replicated/replicated_xc_integrator_impl.cxx +++ b/src/xc_integrator/replicated/replicated_xc_integrator_impl.cxx @@ -88,7 +88,7 @@ void ReplicatedXCIntegratorImpl:: template void ReplicatedXCIntegratorImpl:: - neo_eval_exc_vxc( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + eval_neo_exc_vxc( int64_t m1, int64_t n1, int64_t m2, int64_t n2, const value_type* P1s, int64_t ldp1s, const value_type* P2s, int64_t ldp2s, const value_type* P2z, int64_t ldp2z, @@ -97,7 +97,7 @@ void ReplicatedXCIntegratorImpl:: value_type* VXC2z, int64_t ldvxc2z, value_type* EXC1, value_type* EXC2){ - neo_eval_exc_vxc_(m1,n1,m2,n2, + eval_neo_exc_vxc_(m1,n1,m2,n2, P1s,ldp1s, P2s,ldp2s, P2z,ldp2z, @@ -110,7 +110,7 @@ void ReplicatedXCIntegratorImpl:: template void ReplicatedXCIntegratorImpl:: - neo_eval_exc_vxc( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + eval_neo_exc_vxc( int64_t m1, int64_t n1, int64_t m2, int64_t n2, const value_type* P1s, int64_t ldp1s, const value_type* P1z, int64_t ldp1z, const value_type* P2s, int64_t ldp2s, @@ -121,7 +121,7 @@ void ReplicatedXCIntegratorImpl:: value_type* VXC2z, int64_t ldvxc2z, value_type* EXC1, value_type* EXC2 ){ - neo_eval_exc_vxc_(m1,n1,m2,n2, + eval_neo_exc_vxc_(m1,n1,m2,n2, P1s,ldp1s, P1z,ldp1z, P2s,ldp2s, From 585710f03ebdf9a7ba8bac7a1267e62a1e1649df Mon Sep 17 00:00:00 2001 From: aodongliu Date: Tue, 7 Nov 2023 10:54:12 -0800 Subject: [PATCH 15/49] add micro batch screening for protons --- include/gauxc/xc_task.hpp | 1 + .../host/replicated_host_load_balancer.cxx | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/include/gauxc/xc_task.hpp b/include/gauxc/xc_task.hpp index 1f70418f..22bb2bad 100644 --- a/include/gauxc/xc_task.hpp +++ b/include/gauxc/xc_task.hpp @@ -55,6 +55,7 @@ struct XCTask { } screening_data bfn_screening; + screening_data bfn2_screening; screening_data cou_screening; void merge_with( const XCTask& other ) { diff --git a/src/load_balancer/host/replicated_host_load_balancer.cxx b/src/load_balancer/host/replicated_host_load_balancer.cxx index 384dcc40..06a7c65e 100644 --- a/src/load_balancer/host/replicated_host_load_balancer.cxx +++ b/src/load_balancer/host/replicated_host_load_balancer.cxx @@ -59,8 +59,16 @@ std::vector< XCTask > HostReplicatedLoadBalancer::create_local_tasks_() const { // Microbatch Screening auto [shell_list, nbe] = micro_batch_screen( (*this->basis_), lo, up ); + // If there's a NEO protonic basis, then do microbatch screening on it + std::vector shell_list2; + size_t nbe2 = 0; + if (this->basis2_) + std::tie(shell_list2, nbe2) = micro_batch_screen((*this->basis2_), lo, up); + // Course grain screening + // For NEO, skip task when electronic shell list is empty if( not shell_list.size() ) continue; + // if (shell_list.empty() && (!this->basis2_ || shell_list2.empty())) continue; // Copy task data XCTask task; @@ -72,6 +80,11 @@ std::vector< XCTask > HostReplicatedLoadBalancer::create_local_tasks_() const { task.bfn_screening.shell_list = std::move(shell_list); task.bfn_screening.nbe = nbe; task.dist_nearest = molmeta_->dist_nearest()[iCurrent]; + if(this->basis2_){ + task.bfn2_screening.shell_list = std::move(shell_list2); + task.bfn2_screening.nbe = nbe2; + } + #pragma omp critical temp_tasks.push_back( From 574ac7ed1e9e82a9b12f936251f40158c9ac99d0 Mon Sep 17 00:00:00 2001 From: aodongliu Date: Tue, 7 Nov 2023 11:30:01 -0800 Subject: [PATCH 16/49] refactor the code after EPC to be electronic & protonic sequentially --- ..._replicated_xc_host_integrator_exc_vxc.hpp | 53 +++++++++++-------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp index 4c709cd4..346a30ed 100644 --- a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp +++ b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp @@ -1121,20 +1121,12 @@ void ReferenceReplicatedXCHostIntegrator:: - - - - + //----------------------Begin Evaluating Electronic ZMat---------------------------- // Factor weights into XC results for( int32_t i = 0; i < npts; ++i ) { - // Electronic eps[i] *= weights[i]; vrho[spin_dim_scal*i] *= weights[i]; if(not is_rks) vrho[spin_dim_scal*i+1] *= weights[i]; - // Protonic - eps2[i] *= weights[i]; - vrho2[2*i] *= weights[i]; - vrho2[2*i+1] *= weights[i]; } if( func.is_gga() ){ @@ -1147,10 +1139,7 @@ void ReferenceReplicatedXCHostIntegrator:: } } - - - // Evaluate Z matrix for VXC - // Electronic + // Evaluate Z matrix for VXC if( func.is_gga() ) { if(is_rks) { lwd->eval_zmat_gga_vxc_rks( npts, nbe, vrho, vgamma, basis_eval, dbasis_x_eval, @@ -1168,32 +1157,52 @@ void ReferenceReplicatedXCHostIntegrator:: lwd->eval_zmat_lda_vxc_uks( npts, nbe, vrho, basis_eval, zmat, nbe, zmat_z, nbe ); } } - // Protonic + //----------------------End Evaluating Electronic ZMat---------------------------- + + + + + //----------------------Begin Evaluating Protonic ZMat---------------------------- + // Factor weights into XC results + for( int32_t i = 0; i < npts; ++i ) { + eps2[i] *= weights[i]; + vrho2[2*i] *= weights[i]; + vrho2[2*i+1] *= weights[i]; + } + + // Evaluate Z matrix for VXC lwd->eval_zmat_lda_vxc_uks( npts, nbe2, vrho2, basis2_eval, zmat2, nbe2, zmat2_z, nbe2 ); + //----------------------End Evaluating Protonic ZMat---------------------------- - // Incremeta LT of VXC + + + // Integrate to obtain Final EXC/VXC: #pragma omp critical { + + // Electronic XC (VXC+EPC) // Scalar integrations for( int32_t i = 0; i < npts; ++i ) { - // Electronic XC (VXC+EPC) const auto den = is_rks ? den_eval[i] : (den_eval[2*i] + den_eval[2*i+1]); *N_EL += weights[i] * den; *EXC1 += eps[i] * den; - // Protonic (EPC) - const auto den2 = den2_eval[2*i] + den2_eval[2*i+1]; - *EXC2 += eps2[i] * den2; } - // Increment VXC - // Electronic lwd->inc_vxc( npts, nbf, nbe, basis_eval, submat_map, zmat, nbe, VXC1s, ldvxc1s, nbe_scr ); if(not is_rks) lwd->inc_vxc( npts, nbf, nbe, basis_eval, submat_map, zmat_z, nbe, VXC1z, ldvxc1z, nbe_scr ); - // Protonic + + + // Protonic XC (EPC) + // Scalar integrations + for( int32_t i = 0; i < npts; ++i ) { + const auto den2 = den2_eval[2*i] + den2_eval[2*i+1]; + *EXC2 += eps2[i] * den2; + } + // Increment VXC lwd->inc_vxc( npts, nbf2, nbe2, basis2_eval, submat_map2, zmat2, nbe2, VXC2s, ldvxc2s, nbe2_scr ); lwd->inc_vxc( npts, nbf2, nbe2, basis2_eval, submat_map2, zmat2_z, nbe2, VXC2z, ldvxc2z, From d2cb40eb61484e7e870e9bbb9400b2c9a888de69 Mon Sep 17 00:00:00 2001 From: aodongliu Date: Tue, 7 Nov 2023 15:48:32 -0800 Subject: [PATCH 17/49] add naive implementation of proton screening --- .../host/replicated_host_load_balancer.cxx | 1 - ..._replicated_xc_host_integrator_exc_vxc.hpp | 192 +++++++++--------- 2 files changed, 101 insertions(+), 92 deletions(-) diff --git a/src/load_balancer/host/replicated_host_load_balancer.cxx b/src/load_balancer/host/replicated_host_load_balancer.cxx index 06a7c65e..496764a9 100644 --- a/src/load_balancer/host/replicated_host_load_balancer.cxx +++ b/src/load_balancer/host/replicated_host_load_balancer.cxx @@ -45,7 +45,6 @@ std::vector< XCTask > HostReplicatedLoadBalancer::create_local_tasks_() const { batcher.quadrature().recenter( center ); const size_t nbatches = batcher.nbatches(); - std::cout << "nbatches: " << nbatches << std::endl; #pragma omp parallel for for( size_t ibatch = 0; ibatch < nbatches; ++ibatch ) { diff --git a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp index 346a30ed..1309fc4f 100644 --- a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp +++ b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp @@ -956,13 +956,18 @@ void ReferenceReplicatedXCHostIntegrator:: } //----------------------Start Protonic System Setup------------------------ + //const int32_t nbe2 = nbf2; + //const int32_t nshells2 = basis2.nshells(); + //std::vector shell_list2_vector; + //shell_list2_vector.reserve(basis2.nshells()); + //for(auto iSh = 0ul; iSh < basis2.size(); ++iSh) shell_list2_vector.emplace_back( iSh ); + //const int32_t* shell_list2 = shell_list2_vector.data(); // Get shell info - const int32_t nbe2 = nbf2; - const int32_t nshells2 = basis2.nshells(); - std::vector shell_list2_vector; - shell_list2_vector.reserve(basis2.nshells()); - for(auto iSh = 0ul; iSh < basis2.size(); ++iSh) shell_list2_vector.emplace_back( iSh ); - const int32_t* shell_list2 = shell_list2_vector.data(); + const int32_t nbe2 = task.bfn2_screening.nbe; + const int32_t nshells2 = task.bfn2_screening.shell_list.size(); + const int32_t* shell_list2 = task.bfn2_screening.shell_list.data(); + + bool evalProtonic = (nshells2 != 0); // Set Up Memory (assuming UKS) host_data.nbe2_scr .resize( nbe2 * nbe2 ); @@ -972,7 +977,6 @@ void ReferenceReplicatedXCHostIntegrator:: // LDA host_data.basis2_eval .resize( npts * nbe2 ); host_data.den2_scr .resize( npts * 2); - // No GGA for NEO yet // Alias/Partition out scratch memory auto* basis2_eval = host_data.basis2_eval.data(); auto* den2_eval = host_data.den2_scr.data(); @@ -982,18 +986,13 @@ void ReferenceReplicatedXCHostIntegrator:: auto* eps2 = host_data.eps2.data(); auto* vrho2 = host_data.vrho2.data(); - // No GGA for NEO yet - value_type* dbasis2_x_eval = nullptr; - value_type* dbasis2_y_eval = nullptr; - value_type* dbasis2_z_eval = nullptr; - value_type* dden2_x_eval = nullptr; - value_type* dden2_y_eval = nullptr; - value_type* dden2_z_eval = nullptr; //----------------------End Protonic System Setup------------------------ - + std::cout << "Task: " << iT << "/" << ntasks << std::endl; + std::cout << "Electronic nbe: " << nbe << std::endl; + std::cout << "Protonic nbe: " << nbe2 << std::endl; //----------------------Start Calculating Electronic Density & UV Variable------------------------ // Get the submatrix map for batch @@ -1051,73 +1050,78 @@ void ReferenceReplicatedXCHostIntegrator:: //----------------------Start Calculating Protonic Density & UV Variable------------------------ - // Get the submatrix map for batch std::vector< std::array > submat_map2; - std::tie(submat_map2, std::ignore) = - gen_compressed_submat_map(basis_map2, shell_list2_vector, nbf2, nbf2); - - // Evaluate Collocation - lwd->eval_collocation( npts, nshells2, nbe2, points, basis2, shell_list2, - basis2_eval ); - - // Evaluate X matrix (P * B) -> store in Z - // NEED THE FACTOR OF 2 HERE! - lwd->eval_xmat( npts, nbf2, nbe2, submat_map2, 2.0, P2s, ldp2s, basis2_eval, nbe2, - zmat2, nbe2, nbe2_scr ); - lwd->eval_xmat( npts, nbf2, nbe2, submat_map2, 2.0, P2z, ldp2z, basis2_eval, nbe2, - zmat2_z, nbe2, nbe2_scr ); - - // Evaluate U and V variables - lwd->eval_uvvar_lda_uks( npts, nbe2, basis2_eval, zmat2, nbe2, zmat2_z, nbe2, - den2_eval ); - - // No protonic XC functional. Fill with eps and vrho to be 0.0 - std::fill_n(eps2, npts, 0.); - std::fill_n(vrho2, npts*2, 0.); + if(evalProtonic){ + //std::tie(submat_map2, std::ignore) = + // gen_compressed_submat_map(basis_map2, shell_list2_vector, nbf2, nbf2); + std::tie(submat_map2, std::ignore) = + gen_compressed_submat_map(basis_map2, task.bfn2_screening.shell_list, nbf2, nbf2); + + // Evaluate Collocation + lwd->eval_collocation( npts, nshells2, nbe2, points, basis2, shell_list2, + basis2_eval ); + + // Evaluate X matrix (P * B) -> store in Z + // NEED THE FACTOR OF 2 HERE! + lwd->eval_xmat( npts, nbf2, nbe2, submat_map2, 2.0, P2s, ldp2s, basis2_eval, nbe2, + zmat2, nbe2, nbe2_scr ); + lwd->eval_xmat( npts, nbf2, nbe2, submat_map2, 2.0, P2z, ldp2z, basis2_eval, nbe2, + zmat2_z, nbe2, nbe2_scr ); + + // Evaluate U and V variables + lwd->eval_uvvar_lda_uks( npts, nbe2, basis2_eval, zmat2, nbe2, zmat2_z, nbe2, + den2_eval ); + + // No protonic XC functional. Fill with eps and vrho to be 0.0 + std::fill_n(eps2, npts, 0.); + std::fill_n(vrho2, npts*2, 0.); + } //----------------------End Calculating Protonic Density & UV Variable------------------------ - if(this->load_balancer_->epc_functional() == EPCFunctional::EPC17){ - //----------------------Start epc-17-2 functional Evaluation------------------------ - for (int32_t iPt = 0; iPt < npts; iPt++ ){ - // Get Electronic density scalar (RKS) - const auto den = is_rks ? den_eval[iPt] : (den_eval[2*iPt] + den_eval[2*iPt+1]); - value_type total_erho = std::abs(den) > 1e-15? den : 0; - // Get Protonic density scalar (UKS) - const auto den2 = den2_eval[2*iPt] + den2_eval[2*iPt+1]; - value_type total_prho = std::abs(den2) > 1e-15? den2 : 0; - - // Skip this point if the density is too small - if(total_erho < 1e-15 | total_prho < 1e-15){ - eps2[iPt] = 0.0; - vrho2[2*iPt] = 0.0; - vrho2[2*iPt+1] = 0.0; - continue; - } + //----------------------Start EPC functional Evaluation--------------------------------------- + if(evalProtonic){ + if(this->load_balancer_->epc_functional() == EPCFunctional::EPC17){ + for (int32_t iPt = 0; iPt < npts; iPt++ ){ + // Get Electronic density scalar (RKS) + const auto den = is_rks ? den_eval[iPt] : (den_eval[2*iPt] + den_eval[2*iPt+1]); + value_type total_erho = std::abs(den) > 1e-15? den : 0; + // Get Protonic density scalar (UKS) + const auto den2 = den2_eval[2*iPt] + den2_eval[2*iPt+1]; + value_type total_prho = std::abs(den2) > 1e-15? den2 : 0; + + // Skip this point if the density is too small + if(total_erho < 1e-15 | total_prho < 1e-15){ + eps2[iPt] = 0.0; + vrho2[2*iPt] = 0.0; + vrho2[2*iPt+1] = 0.0; + continue; + } - // epc-17-2 denominator - value_type dn = 2.35 - 2.4 * std::sqrt(total_erho*total_prho) + 6.6 * (total_erho*total_prho); - - // Update electronic eps and vxc - eps[iPt] += -1.0 * total_prho/dn; - vrho[spin_dim_scal*iPt] += ( -1.0 * total_prho / dn + (-1.2 * std::sqrt(total_erho) * std::sqrt(total_prho) * total_prho - + 6.6 * total_erho * total_prho * total_prho ) / (dn * dn) ); - if(not is_rks) - vrho[spin_dim_scal*iPt+1] += ( -1.0 * total_prho / dn + (-1.2 * std::sqrt(total_erho) * std::sqrt(total_prho) * total_prho - + 6.6 * total_erho * total_prho * total_prho ) / (dn * dn) ); - - // Assign protonic eps and vxc - eps2[iPt] = -1.0 * total_erho/dn; - vrho2[2*iPt] = ( -1.0 * total_erho / dn + (-1.2 * std::sqrt(total_prho) * std::sqrt(total_erho) * total_erho - + 6.6 * total_erho * total_erho * total_prho ) / (dn * dn) ); - vrho2[2*iPt+1] = 0.0; + // epc-17-2 denominator + value_type dn = 2.35 - 2.4 * std::sqrt(total_erho*total_prho) + 6.6 * (total_erho*total_prho); + + // Update electronic eps and vxc + eps[iPt] += -1.0 * total_prho/dn; + vrho[spin_dim_scal*iPt] += ( -1.0 * total_prho / dn + (-1.2 * std::sqrt(total_erho) * std::sqrt(total_prho) * total_prho + + 6.6 * total_erho * total_prho * total_prho ) / (dn * dn) ); + if(not is_rks) + vrho[spin_dim_scal*iPt+1] += ( -1.0 * total_prho / dn + (-1.2 * std::sqrt(total_erho) * std::sqrt(total_prho) * total_prho + + 6.6 * total_erho * total_prho * total_prho ) / (dn * dn) ); + + // Assign protonic eps and vxc + eps2[iPt] = -1.0 * total_erho/dn; + vrho2[2*iPt] = ( -1.0 * total_erho / dn + (-1.2 * std::sqrt(total_prho) * std::sqrt(total_erho) * total_erho + + 6.6 * total_erho * total_erho * total_prho ) / (dn * dn) ); + vrho2[2*iPt+1] = 0.0; + } + } else{ + GAUXC_GENERIC_EXCEPTION("Only EPC17 is supported in GauXC"); } - //----------------------End epc-17-2 functional Evaluation------------------------ - } else{ - GAUXC_GENERIC_EXCEPTION("Only EPC17 is supported in GauXC"); - } + } // End if(evalProtonic) + //----------------------End EPC functional Evaluation--------------------------------------- @@ -1163,15 +1167,17 @@ void ReferenceReplicatedXCHostIntegrator:: //----------------------Begin Evaluating Protonic ZMat---------------------------- - // Factor weights into XC results - for( int32_t i = 0; i < npts; ++i ) { - eps2[i] *= weights[i]; - vrho2[2*i] *= weights[i]; - vrho2[2*i+1] *= weights[i]; - } + if(evalProtonic){ + // Factor weights into XC results + for( int32_t i = 0; i < npts; ++i ) { + eps2[i] *= weights[i]; + vrho2[2*i] *= weights[i]; + vrho2[2*i+1] *= weights[i]; + } - // Evaluate Z matrix for VXC - lwd->eval_zmat_lda_vxc_uks( npts, nbe2, vrho2, basis2_eval, zmat2, nbe2, zmat2_z, nbe2 ); + // Evaluate Z matrix for VXC + lwd->eval_zmat_lda_vxc_uks( npts, nbe2, vrho2, basis2_eval, zmat2, nbe2, zmat2_z, nbe2 ); + } //----------------------End Evaluating Protonic ZMat---------------------------- @@ -1186,7 +1192,7 @@ void ReferenceReplicatedXCHostIntegrator:: for( int32_t i = 0; i < npts; ++i ) { const auto den = is_rks ? den_eval[i] : (den_eval[2*i] + den_eval[2*i+1]); *N_EL += weights[i] * den; - *EXC1 += eps[i] * den; + *EXC1 += eps[i] * den; } // Increment VXC lwd->inc_vxc( npts, nbf, nbe, basis_eval, submat_map, zmat, nbe, VXC1s, ldvxc1s, @@ -1198,15 +1204,19 @@ void ReferenceReplicatedXCHostIntegrator:: // Protonic XC (EPC) // Scalar integrations - for( int32_t i = 0; i < npts; ++i ) { - const auto den2 = den2_eval[2*i] + den2_eval[2*i+1]; - *EXC2 += eps2[i] * den2; + if(evalProtonic){ + for( int32_t i = 0; i < npts; ++i ) { + const auto den2 = den2_eval[2*i] + den2_eval[2*i+1]; + *EXC2 += eps2[i] * den2; + } + // Increment VXC + lwd->inc_vxc( npts, nbf2, nbe2, basis2_eval, submat_map2, zmat2, nbe2, VXC2s, ldvxc2s, + nbe2_scr ); + lwd->inc_vxc( npts, nbf2, nbe2, basis2_eval, submat_map2, zmat2_z, nbe2, VXC2z, ldvxc2z, + nbe2_scr ); } - // Increment VXC - lwd->inc_vxc( npts, nbf2, nbe2, basis2_eval, submat_map2, zmat2, nbe2, VXC2s, ldvxc2s, - nbe2_scr ); - lwd->inc_vxc( npts, nbf2, nbe2, basis2_eval, submat_map2, zmat2_z, nbe2, VXC2z, ldvxc2z, - nbe2_scr ); + std::cout << "Electronic EXC: " << *EXC1 << std::endl; + std::cout << "Protonic EXC: " << *EXC2 << std::endl; } // End #pragma omp critical From 0958be130be85ba40a401b27e8c250fd374feecd Mon Sep 17 00:00:00 2001 From: aodongliu Date: Tue, 7 Nov 2023 16:38:28 -0800 Subject: [PATCH 18/49] allow electronic and protonic to use the same scratch space --- ..._replicated_xc_host_integrator_exc_vxc.hpp | 39 +++++++++---------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp index 1309fc4f..435d120f 100644 --- a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp +++ b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp @@ -899,11 +899,23 @@ void ReferenceReplicatedXCHostIntegrator:: const auto* weights = task.weights.data(); const int32_t* shell_list = task.bfn_screening.shell_list.data(); + const int32_t nbe2 = task.bfn2_screening.nbe; + const int32_t nshells2 = task.bfn2_screening.shell_list.size(); + const int32_t* shell_list2 = task.bfn2_screening.shell_list.data(); + bool evalProtonic = (nshells2 != 0); + // Allocate enough memory for batch const size_t spin_dim_scal = is_rks ? 1 : 2; + // Things that every calc needs - host_data.nbe_scr .resize(nbe * nbe); + + + // Use same scratch for both electronic and protonic + const int32_t scr_dim = std::max(nbe, nbe2); + host_data.nbe_scr .resize(scr_dim * scr_dim); + + //----------------------Start Electronic System Setup------------------------ host_data.zmat .resize(npts * nbe * spin_dim_scal); host_data.eps .resize(npts); host_data.vrho .resize(npts * spin_dim_scal); @@ -954,23 +966,11 @@ void ReferenceReplicatedXCHostIntegrator:: dden_y_eval = dden_x_eval + spin_dim_scal * npts; dden_z_eval = dden_y_eval + spin_dim_scal * npts; } + //----------------------End Electronic System Setup------------------------ - //----------------------Start Protonic System Setup------------------------ - //const int32_t nbe2 = nbf2; - //const int32_t nshells2 = basis2.nshells(); - //std::vector shell_list2_vector; - //shell_list2_vector.reserve(basis2.nshells()); - //for(auto iSh = 0ul; iSh < basis2.size(); ++iSh) shell_list2_vector.emplace_back( iSh ); - //const int32_t* shell_list2 = shell_list2_vector.data(); - // Get shell info - const int32_t nbe2 = task.bfn2_screening.nbe; - const int32_t nshells2 = task.bfn2_screening.shell_list.size(); - const int32_t* shell_list2 = task.bfn2_screening.shell_list.data(); - - bool evalProtonic = (nshells2 != 0); + //----------------------Start Protonic System Setup------------------------ // Set Up Memory (assuming UKS) - host_data.nbe2_scr .resize( nbe2 * nbe2 ); host_data.zmat2 .resize( npts * nbe2 * 2 ); host_data.eps2 .resize( npts ); host_data.vrho2 .resize( npts * 2 ); @@ -980,7 +980,6 @@ void ReferenceReplicatedXCHostIntegrator:: // Alias/Partition out scratch memory auto* basis2_eval = host_data.basis2_eval.data(); auto* den2_eval = host_data.den2_scr.data(); - auto* nbe2_scr = host_data.nbe2_scr.data(); auto* zmat2 = host_data.zmat2.data(); decltype(zmat2) zmat2_z = zmat2 + nbe2 * npts; @@ -1064,9 +1063,9 @@ void ReferenceReplicatedXCHostIntegrator:: // Evaluate X matrix (P * B) -> store in Z // NEED THE FACTOR OF 2 HERE! lwd->eval_xmat( npts, nbf2, nbe2, submat_map2, 2.0, P2s, ldp2s, basis2_eval, nbe2, - zmat2, nbe2, nbe2_scr ); + zmat2, nbe2, nbe_scr ); lwd->eval_xmat( npts, nbf2, nbe2, submat_map2, 2.0, P2z, ldp2z, basis2_eval, nbe2, - zmat2_z, nbe2, nbe2_scr ); + zmat2_z, nbe2, nbe_scr ); // Evaluate U and V variables lwd->eval_uvvar_lda_uks( npts, nbe2, basis2_eval, zmat2, nbe2, zmat2_z, nbe2, @@ -1211,9 +1210,9 @@ void ReferenceReplicatedXCHostIntegrator:: } // Increment VXC lwd->inc_vxc( npts, nbf2, nbe2, basis2_eval, submat_map2, zmat2, nbe2, VXC2s, ldvxc2s, - nbe2_scr ); + nbe_scr ); lwd->inc_vxc( npts, nbf2, nbe2, basis2_eval, submat_map2, zmat2_z, nbe2, VXC2z, ldvxc2z, - nbe2_scr ); + nbe_scr ); } std::cout << "Electronic EXC: " << *EXC1 << std::endl; std::cout << "Protonic EXC: " << *EXC2 << std::endl; From 625bd1cd9d32ce826946fc9a983847ac32f45e19 Mon Sep 17 00:00:00 2001 From: aodongliu Date: Tue, 7 Nov 2023 17:13:18 -0800 Subject: [PATCH 19/49] clean up debug printing --- ...reference_replicated_xc_host_integrator_exc_vxc.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp index 435d120f..84368af4 100644 --- a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp +++ b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp @@ -989,9 +989,9 @@ void ReferenceReplicatedXCHostIntegrator:: //----------------------End Protonic System Setup------------------------ - std::cout << "Task: " << iT << "/" << ntasks << std::endl; - std::cout << "Electronic nbe: " << nbe << std::endl; - std::cout << "Protonic nbe: " << nbe2 << std::endl; + //std::cout << "Task: " << iT << "/" << ntasks << std::endl; + //std::cout << "Electronic nbe: " << nbe << std::endl; + //std::cout << "Protonic nbe: " << nbe2 << std::endl; //----------------------Start Calculating Electronic Density & UV Variable------------------------ // Get the submatrix map for batch @@ -1214,8 +1214,8 @@ void ReferenceReplicatedXCHostIntegrator:: lwd->inc_vxc( npts, nbf2, nbe2, basis2_eval, submat_map2, zmat2_z, nbe2, VXC2z, ldvxc2z, nbe_scr ); } - std::cout << "Electronic EXC: " << *EXC1 << std::endl; - std::cout << "Protonic EXC: " << *EXC2 << std::endl; + //std::cout << "Electronic EXC: " << *EXC1 << std::endl; + //std::cout << "Protonic EXC: " << *EXC2 << std::endl; } // End #pragma omp critical From 51a07fcc3c361d7e66be90c6b471597c94daefed Mon Sep 17 00:00:00 2001 From: aodongliu Date: Wed, 29 Nov 2023 18:38:02 -0800 Subject: [PATCH 20/49] fix issues after rebasing to newest master branch --- include/gauxc/xc_integrator.hpp | 4 ++-- include/gauxc/xc_integrator/impl.hpp | 1 + .../gauxc/xc_integrator/replicated/impl.hpp | 8 ++++---- .../replicated_xc_integrator_impl.hpp | 4 ++-- .../incore_replicated_xc_device_integrator.hpp | 4 ++-- ...replicated_xc_device_integrator_exc_vxc.hpp | 2 +- ...batched_replicated_xc_device_integrator.hpp | 4 ++-- ...replicated_xc_device_integrator_exc_vxc.hpp | 4 ++-- ...reference_replicated_xc_host_integrator.hpp | 7 ++++--- ...e_replicated_xc_host_integrator_exc_vxc.hpp | 12 +++++++----- .../replicated_xc_integrator_impl.cxx | 18 ++++++++++-------- 11 files changed, 37 insertions(+), 31 deletions(-) diff --git a/include/gauxc/xc_integrator.hpp b/include/gauxc/xc_integrator.hpp index 74b1a381..669275e4 100644 --- a/include/gauxc/xc_integrator.hpp +++ b/include/gauxc/xc_integrator.hpp @@ -61,8 +61,8 @@ class XCIntegrator { exc_vxc_type_uks eval_exc_vxc ( const MatrixType&, const MatrixType&, const IntegratorSettingsXC& = IntegratorSettingsXC{} ); exc_vxc_type_gks eval_exc_vxc ( const MatrixType&, const MatrixType&, const MatrixType&, const MatrixType&, - const IntegratorSettingsXC& = IntegratorSettingsXC{}) ; - exc_vxc_type_neo_rks neo_eval_exc_vxc ( const MatrixType&, const MatrixType&, const MatrixType& + const IntegratorSettingsXC& = IntegratorSettingsXC{} ); + exc_vxc_type_neo_rks neo_eval_exc_vxc ( const MatrixType&, const MatrixType&, const MatrixType&, const IntegratorSettingsXC& = IntegratorSettingsXC{} ); exc_vxc_type_neo_uks neo_eval_exc_vxc ( const MatrixType&, const MatrixType&, const MatrixType&, const MatrixType&, const IntegratorSettingsXC& = IntegratorSettingsXC{} ); diff --git a/include/gauxc/xc_integrator/impl.hpp b/include/gauxc/xc_integrator/impl.hpp index 4511c651..4888c486 100644 --- a/include/gauxc/xc_integrator/impl.hpp +++ b/include/gauxc/xc_integrator/impl.hpp @@ -53,6 +53,7 @@ typename XCIntegrator::exc_vxc_type_gks return pimpl_->eval_exc_vxc(Ps, Pz, Py, Px, ks_settings); }; +template typename XCIntegrator::exc_vxc_type_neo_rks XCIntegrator::neo_eval_exc_vxc( const MatrixType& elec_Ps, const MatrixType& prot_Ps, const MatrixType& prot_Pz, const IntegratorSettingsXC& ks_settings ){ diff --git a/include/gauxc/xc_integrator/replicated/impl.hpp b/include/gauxc/xc_integrator/replicated/impl.hpp index ad72b273..912e21a5 100644 --- a/include/gauxc/xc_integrator/replicated/impl.hpp +++ b/include/gauxc/xc_integrator/replicated/impl.hpp @@ -131,14 +131,14 @@ typename ReplicatedXCIntegrator::exc_vxc_type_neo_rks value_type elec_EXC; value_type prot_EXC; - pimpl_->eval_neo_exc_vxc( elec_Ps.rows(), elec_Ps.cols(), prot_Ps.rows(), prot_Ps.cols(), + pimpl_->neo_eval_exc_vxc( elec_Ps.rows(), elec_Ps.cols(), prot_Ps.rows(), prot_Ps.cols(), elec_Ps.data(), elec_Ps.rows(), prot_Ps.data(), prot_Ps.rows(), prot_Pz.data(), prot_Pz.rows(), elec_VXCs.data(), elec_VXCs.rows(), prot_VXCs.data(), prot_VXCs.rows(), prot_VXCz.data(), prot_VXCz.rows(), - &elec_EXC, &prot_EXC); + &elec_EXC, &prot_EXC, ks_settings ); return std::make_tuple( elec_EXC, prot_EXC, elec_VXCs, prot_VXCs, prot_VXCz ); @@ -157,7 +157,7 @@ typename ReplicatedXCIntegrator::exc_vxc_type_neo_uks value_type elec_EXC; value_type prot_EXC; - pimpl_->eval_neo_exc_vxc( elec_Ps.rows(), elec_Ps.cols(), prot_Ps.rows(), prot_Ps.cols(), + pimpl_->neo_eval_exc_vxc( elec_Ps.rows(), elec_Ps.cols(), prot_Ps.rows(), prot_Ps.cols(), elec_Ps.data(), elec_Ps.rows(), elec_Pz.data(), elec_Pz.rows(), prot_Ps.data(), prot_Ps.rows(), @@ -166,7 +166,7 @@ typename ReplicatedXCIntegrator::exc_vxc_type_neo_uks elec_VXCz.data(), elec_VXCz.rows(), prot_VXCs.data(), prot_VXCs.rows(), prot_VXCz.data(), prot_VXCz.rows(), - &elec_EXC, &prot_EXC); + &elec_EXC, &prot_EXC, ks_settings ); return std::make_tuple( elec_EXC, prot_EXC, elec_VXCs, elec_VXCz, prot_VXCs, prot_VXCz ); diff --git a/include/gauxc/xc_integrator/replicated/replicated_xc_integrator_impl.hpp b/include/gauxc/xc_integrator/replicated/replicated_xc_integrator_impl.hpp index fb6eb9d0..66095645 100644 --- a/include/gauxc/xc_integrator/replicated/replicated_xc_integrator_impl.hpp +++ b/include/gauxc/xc_integrator/replicated/replicated_xc_integrator_impl.hpp @@ -124,7 +124,7 @@ class ReplicatedXCIntegratorImpl { value_type* VXCx, int64_t ldvxcx, value_type* EXC, const IntegratorSettingsXC& ks_settings ); - void eval_neo_exc_vxc( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + void neo_eval_exc_vxc( int64_t m1, int64_t n1, int64_t m2, int64_t n2, const value_type* P1s, int64_t ldp1s, const value_type* P2s, int64_t ldp2s, const value_type* P2z, int64_t ldp2z, @@ -133,7 +133,7 @@ class ReplicatedXCIntegratorImpl { value_type* VXC2z, int64_t ldvxc2z, value_type* EXC1, value_type* EXC2, const IntegratorSettingsXC& ks_settings ); - void eval_neo_exc_vxc( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + void neo_eval_exc_vxc( int64_t m1, int64_t n1, int64_t m2, int64_t n2, const value_type* P1s, int64_t ldp1s, const value_type* P1z, int64_t ldp1z, const value_type* P2s, int64_t ldp2s, diff --git a/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator.hpp b/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator.hpp index cd2b1cc9..e95621a9 100644 --- a/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator.hpp +++ b/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator.hpp @@ -57,7 +57,7 @@ class IncoreReplicatedXCDeviceIntegrator : value_type* VXCx, int64_t ldvxcx, value_type* EXC, const IntegratorSettingsXC& settings ) override; - void eval_neo_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + void neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, const value_type* P1s, int64_t ldp1s, const value_type* P2s, int64_t ldp2s, const value_type* P2z, int64_t ldp2z, @@ -66,7 +66,7 @@ class IncoreReplicatedXCDeviceIntegrator : value_type* VXC2z, int64_t ldvxc2z, value_type* EXC1, value_type* EXC2, const IntegratorSettingsXC& settings ) override; - void eval_neo_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + void neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, const value_type* P1s, int64_t ldp1s, const value_type* P1z, int64_t ldp1z, const value_type* P2s, int64_t ldp2s, diff --git a/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator_exc_vxc.hpp b/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator_exc_vxc.hpp index 35a2e44a..c1e34f2b 100644 --- a/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator_exc_vxc.hpp +++ b/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator_exc_vxc.hpp @@ -155,7 +155,7 @@ void IncoreReplicatedXCDeviceIntegrator:: template void IncoreReplicatedXCDeviceIntegrator:: - eval_neo_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, const value_type* P1s, int64_t ldp1s, const value_type* P1z, int64_t ldp1z, const value_type* P2s, int64_t ldp2s, diff --git a/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator.hpp b/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator.hpp index a6883164..430e084d 100644 --- a/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator.hpp +++ b/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator.hpp @@ -68,7 +68,7 @@ class ShellBatchedReplicatedXCDeviceIntegrator : value_type* VXCx, int64_t ldvxcx, value_type* EXC, const IntegratorSettingsXC& settings ) override; - void eval_neo_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + void neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, const value_type* P1s, int64_t ldp1s, const value_type* P2s, int64_t ldp2s, const value_type* P2z, int64_t ldp2z, @@ -77,7 +77,7 @@ class ShellBatchedReplicatedXCDeviceIntegrator : value_type* VXC2z, int64_t ldvxc2z, value_type* EXC1, value_type* EXC2 ) override; - void eval_neo_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + void neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, const value_type* P1s, int64_t ldp1s, const value_type* P1z, int64_t ldp1z, const value_type* P2s, int64_t ldp2s, diff --git a/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator_exc_vxc.hpp b/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator_exc_vxc.hpp index 6b3053c5..8814c823 100644 --- a/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator_exc_vxc.hpp +++ b/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator_exc_vxc.hpp @@ -122,7 +122,7 @@ void ShellBatchedReplicatedXCDeviceIntegrator:: template void ShellBatchedReplicatedXCDeviceIntegrator:: - eval_neo_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, const value_type* P1s, int64_t ldp1s, const value_type* P2s, int64_t ldp2s, const value_type* P2z, int64_t ldp2z, @@ -137,7 +137,7 @@ void ShellBatchedReplicatedXCDeviceIntegrator:: template void ShellBatchedReplicatedXCDeviceIntegrator:: - eval_neo_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, const value_type* P1s, int64_t ldp1s, const value_type* P1z, int64_t ldp1z, const value_type* P2s, int64_t ldp2s, diff --git a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator.hpp b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator.hpp index 9ebc9af6..396bb1d7 100644 --- a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator.hpp +++ b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator.hpp @@ -55,7 +55,7 @@ class ReferenceReplicatedXCHostIntegrator : value_type* EXC, const IntegratorSettingsXC& ks_settings ) override; - void eval_neo_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + void neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, const value_type* P1s, int64_t ldp1s, const value_type* P2s, int64_t ldp2s, const value_type* P2z, int64_t ldp2z, @@ -64,7 +64,7 @@ class ReferenceReplicatedXCHostIntegrator : value_type* VXC2z, int64_t ldvxc2z, value_type* EXC1, value_type* EXC2, const IntegratorSettingsXC& ks_settings ) override; - void eval_neo_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + void neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, const value_type* P1s, int64_t ldp1s, const value_type* P1z, int64_t ldp1z, const value_type* P2s, int64_t ldp2s, @@ -111,7 +111,8 @@ class ReferenceReplicatedXCHostIntegrator : value_type* VXC1z, int64_t ldvxc1z, value_type* VXC2s, int64_t ldvxc2s, value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC1, value_type* EXC2, value_type *N_EL ); + value_type* EXC1, value_type* EXC2, value_type *N_EL, + const IntegratorSettingsXC& ks_settings ); void exc_grad_local_work_( const value_type* P, int64_t ldp, value_type* EXC_GRAD ); void exx_local_work_( const value_type* P, int64_t ldp, value_type* K, int64_t ldk, diff --git a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp index 84368af4..c60f323f 100644 --- a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp +++ b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp @@ -259,7 +259,7 @@ void ReferenceReplicatedXCHostIntegrator:: template void ReferenceReplicatedXCHostIntegrator:: - eval_neo_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, const value_type* P1s, int64_t ldp1s, const value_type* P1z, int64_t ldp1z, const value_type* P2s, int64_t ldp2s, @@ -268,7 +268,8 @@ void ReferenceReplicatedXCHostIntegrator:: value_type* VXC1z, int64_t ldvxc1z, value_type* VXC2s, int64_t ldvxc2s, value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC1, value_type* EXC2 ) { + value_type* EXC1, value_type* EXC2, + const IntegratorSettingsXC& ks_settings ) { const auto& basis = this->load_balancer_->basis(); const auto& basis2 = this->load_balancer_->basis2(); @@ -302,7 +303,7 @@ void ReferenceReplicatedXCHostIntegrator:: VXC1z, ldvxc1z, VXC2s, ldvxc2s, VXC2z, ldvxc2z, - EXC1, EXC2, &N_EL ); + EXC1, EXC2, &N_EL, ks_settings); }); @@ -824,7 +825,8 @@ void ReferenceReplicatedXCHostIntegrator:: value_type* VXC1z, int64_t ldvxc1z, value_type* VXC2s, int64_t ldvxc2s, value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC1, value_type* EXC2, value_type *N_EL ) { + value_type* EXC1, value_type* EXC2, value_type *N_EL, + const IntegratorSettingsXC& ks_settings ) { // Determine is electronic subsystem is RKS or UKS @@ -1223,7 +1225,7 @@ void ReferenceReplicatedXCHostIntegrator:: } // End OpenMP region - std::cout << "N_EL = " << std::setprecision(12) << std::scientific << *N_EL << std::endl; + //std::cout << "N_EL = " << std::setprecision(12) << std::scientific << *N_EL << std::endl; //std::cout << "EXC1 = " << std::setprecision(12) << std::scientific << *EXC1 << std::endl //std::cout << "EXC2 = " << std::setprecision(12) << std::scientific << *EXC2 << std::endl; diff --git a/src/xc_integrator/replicated/replicated_xc_integrator_impl.cxx b/src/xc_integrator/replicated/replicated_xc_integrator_impl.cxx index a5961753..b9a3def3 100644 --- a/src/xc_integrator/replicated/replicated_xc_integrator_impl.cxx +++ b/src/xc_integrator/replicated/replicated_xc_integrator_impl.cxx @@ -88,29 +88,30 @@ void ReplicatedXCIntegratorImpl:: template void ReplicatedXCIntegratorImpl:: - eval_neo_exc_vxc( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + neo_eval_exc_vxc( int64_t m1, int64_t n1, int64_t m2, int64_t n2, const value_type* P1s, int64_t ldp1s, const value_type* P2s, int64_t ldp2s, const value_type* P2z, int64_t ldp2z, value_type* VXC1s, int64_t ldvxc1s, value_type* VXC2s, int64_t ldvxc2s, value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC1, value_type* EXC2){ + value_type* EXC1, value_type* EXC2, + const IntegratorSettingsXC& ks_settings){ - eval_neo_exc_vxc_(m1,n1,m2,n2, + neo_eval_exc_vxc_(m1,n1,m2,n2, P1s,ldp1s, P2s,ldp2s, P2z,ldp2z, VXC1s,ldvxc1s, VXC2s,ldvxc2s, VXC2z,ldvxc2z, - EXC1, EXC2); + EXC1, EXC2, ks_settings); } template void ReplicatedXCIntegratorImpl:: - eval_neo_exc_vxc( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + neo_eval_exc_vxc( int64_t m1, int64_t n1, int64_t m2, int64_t n2, const value_type* P1s, int64_t ldp1s, const value_type* P1z, int64_t ldp1z, const value_type* P2s, int64_t ldp2s, @@ -119,9 +120,10 @@ void ReplicatedXCIntegratorImpl:: value_type* VXC1z, int64_t ldvxc1z, value_type* VXC2s, int64_t ldvxc2s, value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC1, value_type* EXC2 ){ + value_type* EXC1, value_type* EXC2, + const IntegratorSettingsXC& ks_settings ){ - eval_neo_exc_vxc_(m1,n1,m2,n2, + neo_eval_exc_vxc_(m1,n1,m2,n2, P1s,ldp1s, P1z,ldp1z, P2s,ldp2s, @@ -130,7 +132,7 @@ void ReplicatedXCIntegratorImpl:: VXC1z,ldvxc1z, VXC2s,ldvxc2s, VXC2z,ldvxc2z, - EXC1, EXC2); + EXC1, EXC2, ks_settings); } From fab91dde95d4cac629b96a31b67198eeedee95dc Mon Sep 17 00:00:00 2001 From: aodongliu Date: Thu, 30 Nov 2023 11:28:58 -0800 Subject: [PATCH 21/49] revert local changes --- .gitignore | 1 - make_command.sh | 4 ---- src/atomic_radii.cxx | 4 +--- 3 files changed, 1 insertion(+), 8 deletions(-) delete mode 100644 make_command.sh diff --git a/.gitignore b/.gitignore index f1d1a073..d92d4623 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,3 @@ src/xc_integrator/local_work_driver/host/obara_saika/test/*.x src/xc_integrator/local_work_driver/host/obara_saika/generator/integral* src/xc_integrator/local_work_driver/host/obara_saika/generator/obara* src/xc_integrator/local_work_driver/host/obara_saika/generator/*.x -.*.swp diff --git a/make_command.sh b/make_command.sh deleted file mode 100644 index 932f5e8d..00000000 --- a/make_command.sh +++ /dev/null @@ -1,4 +0,0 @@ -cmake -DCMAKE_BUILD_TYPE=Debug -DGAUXC_ENABLE_OPENMP=off -DGAUXC_ENABLE_MPI=off .. -make -j 4 -make DESTDIR=../install2 install -touch /Users/aodongliu/Softwares/chronusq_dev_dft/cmake/HandleGauXC.cmake diff --git a/src/atomic_radii.cxx b/src/atomic_radii.cxx index e71bb4c2..6e3a829f 100644 --- a/src/atomic_radii.cxx +++ b/src/atomic_radii.cxx @@ -35,9 +35,7 @@ double slater_radius_64(AtomicNumber _Z) { auto Z = _Z.get(); switch(Z) { - //Change H radius to match Chronus - //case 1: /* H */ return pm_to_bohr(25. ); - case 1: /* H */ return pm_to_bohr(52.9); + case 1: /* H */ return pm_to_bohr(25. ); //case 2: /* He */ return pm_to_bohr(120.); case 3: /* Li */ return pm_to_bohr(145.); case 4: /* Be */ return pm_to_bohr(105.); From 46070d40df1f063724d67b916778cfa2c57c121d Mon Sep 17 00:00:00 2001 From: aodongliu Date: Fri, 1 Dec 2023 16:22:12 -0800 Subject: [PATCH 22/49] remove epcfunctional enum in GauXC. Will add this in exchcxx --- include/gauxc/enums.hpp | 7 -- include/gauxc/load_balancer.hpp | 7 +- src/atomic_radii.cxx | 5 +- .../host/load_balancer_host_factory.cxx | 6 +- .../host/load_balancer_host_factory.hpp | 2 +- src/load_balancer/load_balancer.cxx | 5 -- src/load_balancer/load_balancer_factory.cxx | 8 +-- src/load_balancer/load_balancer_impl.cxx | 13 ++-- src/load_balancer/load_balancer_impl.hpp | 8 +-- ..._replicated_xc_host_integrator_exc_vxc.hpp | 68 +++++++++---------- 10 files changed, 53 insertions(+), 76 deletions(-) diff --git a/include/gauxc/enums.hpp b/include/gauxc/enums.hpp index d5182419..26a5cf23 100644 --- a/include/gauxc/enums.hpp +++ b/include/gauxc/enums.hpp @@ -58,12 +58,5 @@ enum class SupportedAlg { SNLINK }; -/** - * @brief Specification of NEO Electronc Proton Correlation Functional - */ -enum class EPCFunctional { - EPC17, ///< EPC-17-2 functional, LDA - EPC19 ///< EPC-19 functional, GGA -}; } // namespace GauXC diff --git a/include/gauxc/load_balancer.hpp b/include/gauxc/load_balancer.hpp index dc5cbc54..5297340c 100644 --- a/include/gauxc/load_balancer.hpp +++ b/include/gauxc/load_balancer.hpp @@ -111,9 +111,6 @@ class LoadBalancer { /// Return the number of non-negligible local shell pairs for 2nd basis for this LoadBalancer const shell_pair_type& shell_pairs2() const; - /// Return the EPC functional for NEO electron-protonic correlation evaluation - const EPCFunctional& epc_functional() const; - /// Return the runtime handle used to construct this LoadBalancer const RuntimeEnvironment& runtime() const; @@ -177,7 +174,7 @@ class LoadBalancerFactory { LoadBalancer get_instance( const RuntimeEnvironment& rt, const Molecule& mol, const MolGrid& mg, const BasisSet& bs, - const BasisSet& bs2, EPCFunctional, size_t pad_val = 1 ); + const BasisSet& bs2, size_t pad_val = 1 ); /** * @brief Generate a shared pointer to a LoadBalancer instance per kernel and @@ -199,7 +196,7 @@ class LoadBalancerFactory { std::shared_ptr get_shared_instance( const RuntimeEnvironment& rt, const Molecule& mol, const MolGrid& mg, const BasisSet&, - const BasisSet&, EPCFunctional, size_t pad_val = 1 ); + const BasisSet&, size_t pad_val = 1 ); private: diff --git a/src/atomic_radii.cxx b/src/atomic_radii.cxx index 6e3a829f..e22f00ef 100644 --- a/src/atomic_radii.cxx +++ b/src/atomic_radii.cxx @@ -35,7 +35,10 @@ double slater_radius_64(AtomicNumber _Z) { auto Z = _Z.get(); switch(Z) { - case 1: /* H */ return pm_to_bohr(25. ); + //case 1: /* H */ return pm_to_bohr(25. ); + // Temporarily switch to CQ's H-radius for benchmarking purposes (per https://github.com/wavefunction91/GauXC/issues/77) + // TODO: revert to GauXC's value when code is ready to merge + case 1: /* H */ return pm_to_bohr(52.9); //case 2: /* He */ return pm_to_bohr(120.); case 3: /* Li */ return pm_to_bohr(145.); case 4: /* Be */ return pm_to_bohr(105.); diff --git a/src/load_balancer/host/load_balancer_host_factory.cxx b/src/load_balancer/host/load_balancer_host_factory.cxx index fa062fc5..c33c2945 100644 --- a/src/load_balancer/host/load_balancer_host_factory.cxx +++ b/src/load_balancer/host/load_balancer_host_factory.cxx @@ -44,7 +44,7 @@ std::shared_ptr LoadBalancerHostFactory::get_shared_instance( std::shared_ptr LoadBalancerHostFactory::get_shared_instance( std::string kernel_name, const RuntimeEnvironment& rt, const Molecule& mol, const MolGrid& mg, const BasisSet& basis, - const BasisSet& basis2, EPCFunctional epcfunc, size_t pv + const BasisSet& basis2, size_t pv ) { std::transform(kernel_name.begin(), kernel_name.end(), @@ -57,12 +57,12 @@ std::shared_ptr LoadBalancerHostFactory::get_shared_instance( std::unique_ptr ptr = nullptr; if( kernel_name == "REPLICATED-PETITE" ) ptr = std::make_unique( - rt, mol, mg, basis, basis2, epcfunc, pv + rt, mol, mg, basis, basis2, pv ); if( kernel_name == "REPLICATED-FILLIN" ) ptr = std::make_unique( - rt, mol, mg, basis, basis2, epcfunc, pv + rt, mol, mg, basis, basis2, pv ); if( ! ptr ) GAUXC_GENERIC_EXCEPTION("Load Balancer Kernel Not Recognized: " + kernel_name); diff --git a/src/load_balancer/host/load_balancer_host_factory.hpp b/src/load_balancer/host/load_balancer_host_factory.hpp index 6926e8c9..bd6a51b2 100644 --- a/src/load_balancer/host/load_balancer_host_factory.hpp +++ b/src/load_balancer/host/load_balancer_host_factory.hpp @@ -20,7 +20,7 @@ struct LoadBalancerHostFactory { static std::shared_ptr get_shared_instance( std::string kernel_name, const RuntimeEnvironment& rt, const Molecule& mol, const MolGrid& mg, const BasisSet& basis, - const BasisSet& basis2, EPCFunctional epcfunc, size_t pv + const BasisSet& basis2, size_t pv ); }; diff --git a/src/load_balancer/load_balancer.cxx b/src/load_balancer/load_balancer.cxx index 4cd21c48..df49202f 100644 --- a/src/load_balancer/load_balancer.cxx +++ b/src/load_balancer/load_balancer.cxx @@ -109,11 +109,6 @@ const LoadBalancer::shell_pair_type& LoadBalancer::shell_pairs2() { if( not pimpl_ ) GAUXC_PIMPL_NOT_INITIALIZED(); return pimpl_->shell_pairs2(); } -const EPCFunctional& LoadBalancer::epc_functional() const{ - if( not pimpl_ ) GAUXC_PIMPL_NOT_INITIALIZED(); - return pimpl_->epc_functional(); - -} LoadBalancerState& LoadBalancer::state() { if( not pimpl_ ) GAUXC_PIMPL_NOT_INITIALIZED(); diff --git a/src/load_balancer/load_balancer_factory.cxx b/src/load_balancer/load_balancer_factory.cxx index 0f898744..bc3b687a 100644 --- a/src/load_balancer/load_balancer_factory.cxx +++ b/src/load_balancer/load_balancer_factory.cxx @@ -53,14 +53,14 @@ LoadBalancer LoadBalancerFactory::get_instance( std::shared_ptr LoadBalancerFactory::get_shared_instance( const RuntimeEnvironment& rt, const Molecule& mol, const MolGrid& mg, const BasisSet& basis, - const BasisSet& basis2, EPCFunctional epcfunc, size_t pad_value + const BasisSet& basis2, size_t pad_value ) { switch(ex_) { case ExecutionSpace::Host: using host_factory = LoadBalancerHostFactory; return host_factory::get_shared_instance(kernel_name_, - rt, mol, mg, basis, basis2, epcfunc, pad_value ); + rt, mol, mg, basis, basis2, pad_value ); #ifdef GAUXC_ENABLE_DEVICE case ExecutionSpace::Device: GAUXC_GENERIC_EXCEPTION("2 basis with GPU NYI"); @@ -78,10 +78,10 @@ std::shared_ptr LoadBalancerFactory::get_shared_instance( LoadBalancer LoadBalancerFactory::get_instance( const RuntimeEnvironment& rt, const Molecule& mol, const MolGrid& mg, const BasisSet& basis, - const BasisSet& basis2, EPCFunctional epcfunc, size_t pad_value + const BasisSet& basis2, size_t pad_value ) { - auto ptr = get_shared_instance(rt, mol, mg, basis, basis2, epcfunc, pad_value); + auto ptr = get_shared_instance(rt, mol, mg, basis, basis2, pad_value); return LoadBalancer(std::move(*ptr)); } diff --git a/src/load_balancer/load_balancer_impl.cxx b/src/load_balancer/load_balancer_impl.cxx index adc7c2fa..7f2b0e76 100644 --- a/src/load_balancer/load_balancer_impl.cxx +++ b/src/load_balancer/load_balancer_impl.cxx @@ -58,13 +58,12 @@ LoadBalancerImpl::LoadBalancerImpl( const RuntimeEnvironment& rt, const Molecule LoadBalancerImpl( rt, mol, mg, basis, std::make_shared(mol) ) { } LoadBalancerImpl::LoadBalancerImpl( const RuntimeEnvironment& rt, const Molecule& mol, -LoadBalancerImpl::LoadBalancerImpl( const RuntimeEnvironment& rt, const Molecule& mol, - const MolGrid& mg, const basis_type& basis, const basis_type& basis2, EPCFunctional epcfunc ) : - LoadBalancerImpl( rt, mol, mg, basis, basis2, epcfunc, std::make_shared(mol) ) { } + const MolGrid& mg, const basis_type& basis, const basis_type& basis2 ) : + LoadBalancerImpl( rt, mol, mg, basis, basis2, std::make_shared(mol) ) { } LoadBalancerImpl::LoadBalancerImpl( const RuntimeEnvironment& rt, const Molecule& mol, - const MolGrid& mg, const basis_type& basis, const basis_type& basis2, EPCFunctional epcfunc, const MolMeta& molmeta ) : - LoadBalancerImpl( rt, mol, mg, basis, basis2, epcfunc, std::make_shared(molmeta) ) { } + const MolGrid& mg, const basis_type& basis, const basis_type& basis2, const MolMeta& molmeta ) : + LoadBalancerImpl( rt, mol, mg, basis, basis2, std::make_shared(molmeta) ) { } LoadBalancerImpl::LoadBalancerImpl( const LoadBalancerImpl& ) = default; LoadBalancerImpl::LoadBalancerImpl( LoadBalancerImpl&& ) noexcept = default; @@ -166,10 +165,6 @@ const LoadBalancerImpl::shell_pair_type& LoadBalancerImpl::shell_pairs2() const return *shell_pairs2_; } -const EPCFunctional& LoadBalancerImpl::epc_functional() const{ - return epc_functional_; -} - const RuntimeEnvironment& LoadBalancerImpl::runtime() const { return runtime_; } diff --git a/src/load_balancer/load_balancer_impl.hpp b/src/load_balancer/load_balancer_impl.hpp index c4e2a4c3..e2a0285c 100644 --- a/src/load_balancer/load_balancer_impl.hpp +++ b/src/load_balancer/load_balancer_impl.hpp @@ -33,7 +33,6 @@ class LoadBalancerImpl { std::shared_ptr basis2_; std::shared_ptr basis_map2_; std::shared_ptr shell_pairs2_; - EPCFunctional epc_functional_; std::vector< XCTask > local_tasks_; @@ -55,11 +54,11 @@ class LoadBalancerImpl { const basis_type&, std::shared_ptr ); LoadBalancerImpl( const RuntimeEnvironment&, const Molecule&, const MolGrid& mg, - const basis_type&, const basis_type&, EPCFunctional ); + const basis_type&, const basis_type& ); LoadBalancerImpl( const RuntimeEnvironment&, const Molecule&, const MolGrid& mg, - const basis_type&, const basis_type&, EPCFunctional, const MolMeta& ); + const basis_type&, const basis_type&, const MolMeta& ); LoadBalancerImpl( const RuntimeEnvironment&, const Molecule&, const MolGrid& mg, - const basis_type&, const basis_type&, EPCFunctional, std::shared_ptr ); + const basis_type&, const basis_type&, std::shared_ptr ); LoadBalancerImpl( const LoadBalancerImpl& ); LoadBalancerImpl( LoadBalancerImpl&& ) noexcept; @@ -90,7 +89,6 @@ class LoadBalancerImpl { const basis_map_type& basis_map2() const; const shell_pair_type& shell_pairs2() const; const shell_pair_type& shell_pairs2(); - const EPCFunctional& epc_functional() const; LoadBalancerState& state(); diff --git a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp index c60f323f..d05d6882 100644 --- a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp +++ b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp @@ -1084,43 +1084,39 @@ void ReferenceReplicatedXCHostIntegrator:: //----------------------Start EPC functional Evaluation--------------------------------------- if(evalProtonic){ - if(this->load_balancer_->epc_functional() == EPCFunctional::EPC17){ - for (int32_t iPt = 0; iPt < npts; iPt++ ){ - // Get Electronic density scalar (RKS) - const auto den = is_rks ? den_eval[iPt] : (den_eval[2*iPt] + den_eval[2*iPt+1]); - value_type total_erho = std::abs(den) > 1e-15? den : 0; - // Get Protonic density scalar (UKS) - const auto den2 = den2_eval[2*iPt] + den2_eval[2*iPt+1]; - value_type total_prho = std::abs(den2) > 1e-15? den2 : 0; - - // Skip this point if the density is too small - if(total_erho < 1e-15 | total_prho < 1e-15){ - eps2[iPt] = 0.0; - vrho2[2*iPt] = 0.0; - vrho2[2*iPt+1] = 0.0; - continue; - } - - // epc-17-2 denominator - value_type dn = 2.35 - 2.4 * std::sqrt(total_erho*total_prho) + 6.6 * (total_erho*total_prho); - - // Update electronic eps and vxc - eps[iPt] += -1.0 * total_prho/dn; - vrho[spin_dim_scal*iPt] += ( -1.0 * total_prho / dn + (-1.2 * std::sqrt(total_erho) * std::sqrt(total_prho) * total_prho - + 6.6 * total_erho * total_prho * total_prho ) / (dn * dn) ); - if(not is_rks) - vrho[spin_dim_scal*iPt+1] += ( -1.0 * total_prho / dn + (-1.2 * std::sqrt(total_erho) * std::sqrt(total_prho) * total_prho - + 6.6 * total_erho * total_prho * total_prho ) / (dn * dn) ); - - // Assign protonic eps and vxc - eps2[iPt] = -1.0 * total_erho/dn; - vrho2[2*iPt] = ( -1.0 * total_erho / dn + (-1.2 * std::sqrt(total_prho) * std::sqrt(total_erho) * total_erho - + 6.6 * total_erho * total_erho * total_prho ) / (dn * dn) ); - vrho2[2*iPt+1] = 0.0; + for (int32_t iPt = 0; iPt < npts; iPt++ ){ + // Get Electronic density scalar (RKS) + const auto den = is_rks ? den_eval[iPt] : (den_eval[2*iPt] + den_eval[2*iPt+1]); + value_type total_erho = std::abs(den) > 1e-15? den : 0; + // Get Protonic density scalar (UKS) + const auto den2 = den2_eval[2*iPt] + den2_eval[2*iPt+1]; + value_type total_prho = std::abs(den2) > 1e-15? den2 : 0; + + // Skip this point if the density is too small + if(total_erho < 1e-15 | total_prho < 1e-15){ + eps2[iPt] = 0.0; + vrho2[2*iPt] = 0.0; + vrho2[2*iPt+1] = 0.0; + continue; } - } else{ - GAUXC_GENERIC_EXCEPTION("Only EPC17 is supported in GauXC"); - } + + // epc-17-2 denominator + value_type dn = 2.35 - 2.4 * std::sqrt(total_erho*total_prho) + 6.6 * (total_erho*total_prho); + + // Update electronic eps and vxc + eps[iPt] += -1.0 * total_prho/dn; + vrho[spin_dim_scal*iPt] += ( -1.0 * total_prho / dn + (-1.2 * std::sqrt(total_erho) * std::sqrt(total_prho) * total_prho + + 6.6 * total_erho * total_prho * total_prho ) / (dn * dn) ); + if(not is_rks) + vrho[spin_dim_scal*iPt+1] += ( -1.0 * total_prho / dn + (-1.2 * std::sqrt(total_erho) * std::sqrt(total_prho) * total_prho + + 6.6 * total_erho * total_prho * total_prho ) / (dn * dn) ); + + // Assign protonic eps and vxc + eps2[iPt] = -1.0 * total_erho/dn; + vrho2[2*iPt] = ( -1.0 * total_erho / dn + (-1.2 * std::sqrt(total_prho) * std::sqrt(total_erho) * total_erho + + 6.6 * total_erho * total_erho * total_prho ) / (dn * dn) ); + vrho2[2*iPt+1] = 0.0; + } // End looping over pts } // End if(evalProtonic) //----------------------End EPC functional Evaluation--------------------------------------- From 17277971bac38f036984473bdc29d6155335c488 Mon Sep 17 00:00:00 2001 From: aodongliu Date: Mon, 4 Dec 2023 10:56:59 -0800 Subject: [PATCH 23/49] delegate to default LoadBalancerImpl constructor to initialize common variables --- src/load_balancer/load_balancer_impl.cxx | 29 ++++-------------------- 1 file changed, 5 insertions(+), 24 deletions(-) diff --git a/src/load_balancer/load_balancer_impl.cxx b/src/load_balancer/load_balancer_impl.cxx index 7f2b0e76..c3530c97 100644 --- a/src/load_balancer/load_balancer_impl.cxx +++ b/src/load_balancer/load_balancer_impl.cxx @@ -21,30 +21,11 @@ LoadBalancerImpl::LoadBalancerImpl( const RuntimeEnvironment& rt, const Molecule } -LoadBalancerImpl::LoadBalancerImpl( const RuntimeEnvironment& rt, const Molecule& mol, - const MolGrid& mg, const basis_type& basis, const basis_type& basis2, std::shared_ptr molmeta ) : - runtime_(rt), - mol_( std::make_shared(mol) ), - mg_( std::make_shared(mg) ), - basis_( std::make_shared(basis) ), - basis2_( std::make_shared(basis2) ), - molmeta_( molmeta ) { - - basis_map_ = std::make_shared(*basis_, mol); - basis_map2_ = std::make_shared(*basis2_, mol); - -} - -LoadBalancerImpl::LoadBalancerImpl( const RuntimeEnvironment& rt, const Molecule& mol, - const MolGrid& mg, const basis_type& basis, const basis_type& basis2, std::shared_ptr molmeta ) : - runtime_(rt), - mol_( std::make_shared(mol) ), - mg_( std::make_shared(mg) ), - basis_( std::make_shared(basis) ), - basis2_( std::make_shared(basis2) ), - molmeta_( molmeta ) { - - basis_map_ = std::make_shared(*basis_, mol); +LoadBalancerImpl::LoadBalancerImpl(const RuntimeEnvironment& rt, const Molecule& mol, + const MolGrid& mg, const basis_type& basis, const basis_type& basis2, std::shared_ptr molmeta ) : + LoadBalancerImpl(rt, mol, mg, basis, molmeta) { + + // Unique initializations for the second basis basis_map2_ = std::make_shared(*basis2_, mol); } From 754e744d6317eec9014b095df1a10cb86b1ef783 Mon Sep 17 00:00:00 2001 From: aodongliu Date: Mon, 4 Dec 2023 11:11:35 -0800 Subject: [PATCH 24/49] check existance of protonic basis before returning its basis information --- src/load_balancer/load_balancer_impl.cxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/load_balancer/load_balancer_impl.cxx b/src/load_balancer/load_balancer_impl.cxx index c3530c97..d33ef106 100644 --- a/src/load_balancer/load_balancer_impl.cxx +++ b/src/load_balancer/load_balancer_impl.cxx @@ -137,12 +137,16 @@ const LoadBalancerImpl::shell_pair_type& LoadBalancerImpl::shell_pairs() { } const LoadBalancerImpl::basis_type& LoadBalancerImpl::basis2() const { + if( not basis2_ ) GAUXC_GENERIC_EXCEPTION("No Protonic Basis Found in LoadBalancerImpl::basis2()"); return *basis2_; } + const LoadBalancerImpl::basis_map_type& LoadBalancerImpl::basis_map2() const { + if( not basis_map2_ ) GAUXC_GENERIC_EXCEPTION("No Protonic Basis Found in LoadBalancerImpl::basis_map2()"); return *basis_map2_; } const LoadBalancerImpl::shell_pair_type& LoadBalancerImpl::shell_pairs2() const { + if( not shell_pairs2_ ) GAUXC_GENERIC_EXCEPTION("No Protonic Basis Found in LoadBalancerImpl::shell_pairs2()"); return *shell_pairs2_; } From 6f4019ba2a41df49411fe66a32e44b9931683e6f Mon Sep 17 00:00:00 2001 From: aodongliu Date: Mon, 4 Dec 2023 11:22:40 -0800 Subject: [PATCH 25/49] seperate neo_eval_exc_vxc function and the local driver to its seperate file --- ...eference_replicated_xc_host_integrator.cxx | 1 + ..._replicated_xc_host_integrator_exc_vxc.hpp | 569 ----------------- ...licated_xc_host_integrator_exc_vxc_neo.hpp | 587 ++++++++++++++++++ 3 files changed, 588 insertions(+), 569 deletions(-) create mode 100644 src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp diff --git a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator.cxx b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator.cxx index 3b0da926..bd86459a 100644 --- a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator.cxx +++ b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator.cxx @@ -7,6 +7,7 @@ */ #include "reference_replicated_xc_host_integrator_integrate_den.hpp" #include "reference_replicated_xc_host_integrator_exc_vxc.hpp" +#include "reference_replicated_xc_host_integrator_exc_vxc_neo.hpp" #include "reference_replicated_xc_host_integrator_exc_grad.hpp" #include "reference_replicated_xc_host_integrator_exx.hpp" diff --git a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp index d05d6882..86f02e67 100644 --- a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp +++ b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp @@ -193,139 +193,6 @@ void ReferenceReplicatedXCHostIntegrator:: } -template -void ReferenceReplicatedXCHostIntegrator:: - neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, - const value_type* P1s, int64_t ldp1s, - const value_type* P2s, int64_t ldp2s, - const value_type* P2z, int64_t ldp2z, - value_type* VXC1s, int64_t ldvxc1s, - value_type* VXC2s, int64_t ldvxc2s, - value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC1, value_type* EXC2, const IntegratorSettingsXC& ks_settings ){ - - const auto& basis = this->load_balancer_->basis(); - const auto& basis2 = this->load_balancer_->basis2(); - - // Check that P / VXC are sane - const int64_t nbf1 = basis.nbf(); - const int64_t nbf2 = basis2.nbf(); - - if( m1 != n1 | m2 != n2) - GAUXC_GENERIC_EXCEPTION("P/VXC Must Be Square"); - if( m1 != nbf1 | m2 != nbf2) - GAUXC_GENERIC_EXCEPTION("P/VXC Must Have Same Dimension as Basis"); - if( ldp1s < nbf1 | ldp2s < nbf2 | ldp2z < nbf2 ) - GAUXC_GENERIC_EXCEPTION("Invalid LDP"); - if( ldvxc1s < nbf1 | ldvxc2s < nbf2 | ldvxc2z < nbf2 ) - GAUXC_GENERIC_EXCEPTION("Invalid LDVXC"); - - // Get Tasks - this->load_balancer_->get_tasks(); - - // Temporary electron count to judge integrator accuracy - value_type N_EL; - - // Compute Local contributions to EXC / VXC - this->timer_.time_op("XCIntegrator.LocalWork", [&](){ - neo_exc_vxc_local_work_( P1s, ldp1s, - nullptr, 0, - P2s, ldp2s, - P2z, ldp2z, - VXC1s, ldvxc1s, - nullptr, 0, - VXC2s, ldvxc2s, - VXC2z, ldvxc2z, - EXC1, EXC2, &N_EL, ks_settings ); - }); - - - // Reduce Results - this->timer_.time_op("XCIntegrator.Allreduce", [&](){ - - if( not this->reduction_driver_->takes_host_memory() ) - GAUXC_GENERIC_EXCEPTION("This Module Only Works With Host Reductions"); - - this->reduction_driver_->allreduce_inplace( VXC1s, nbf1*nbf1, ReductionOp::Sum ); - this->reduction_driver_->allreduce_inplace( VXC2s, nbf2*nbf1, ReductionOp::Sum ); - this->reduction_driver_->allreduce_inplace( VXC2z, nbf2*nbf2, ReductionOp::Sum ); - this->reduction_driver_->allreduce_inplace( EXC1, 1 , ReductionOp::Sum ); - this->reduction_driver_->allreduce_inplace( EXC2, 1 , ReductionOp::Sum ); - this->reduction_driver_->allreduce_inplace( &N_EL, 1 , ReductionOp::Sum ); - - }); - -} - -template -void ReferenceReplicatedXCHostIntegrator:: - neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, - const value_type* P1s, int64_t ldp1s, - const value_type* P1z, int64_t ldp1z, - const value_type* P2s, int64_t ldp2s, - const value_type* P2z, int64_t ldp2z, - value_type* VXC1s, int64_t ldvxc1s, - value_type* VXC1z, int64_t ldvxc1z, - value_type* VXC2s, int64_t ldvxc2s, - value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC1, value_type* EXC2, - const IntegratorSettingsXC& ks_settings ) { - - const auto& basis = this->load_balancer_->basis(); - const auto& basis2 = this->load_balancer_->basis2(); - - // Check that P / VXC are sane - const int64_t nbf1 = basis.nbf(); - const int64_t nbf2 = basis2.nbf(); - - if( m1 != n1 | m2 != n2) - GAUXC_GENERIC_EXCEPTION("P/VXC Must Be Square"); - if( m1 != nbf1 | m2 != nbf2) - GAUXC_GENERIC_EXCEPTION("P/VXC Must Have Same Dimension as Basis"); - if( ldp1s < nbf1 | ldp2s < nbf2 | ldp2z < nbf2 ) - GAUXC_GENERIC_EXCEPTION("Invalid LDP"); - if( ldvxc1s < nbf1 | ldvxc2s < nbf2 | ldvxc2z < nbf2 ) - GAUXC_GENERIC_EXCEPTION("Invalid LDVXC"); - - // Get Tasks - this->load_balancer_->get_tasks(); - - // Temporary electron count to judge integrator accuracy - value_type N_EL; - - // Compute Local contributions to EXC / VXC - this->timer_.time_op("XCIntegrator.LocalWork", [&](){ - neo_exc_vxc_local_work_( P1s, ldp1s, - P1z, ldp1z, - P2s, ldp2s, - P2z, ldp2z, - VXC1s, ldvxc1s, - VXC1z, ldvxc1z, - VXC2s, ldvxc2s, - VXC2z, ldvxc2z, - EXC1, EXC2, &N_EL, ks_settings); - }); - - - // Reduce Results - this->timer_.time_op("XCIntegrator.Allreduce", [&](){ - - if( not this->reduction_driver_->takes_host_memory() ) - GAUXC_GENERIC_EXCEPTION("This Module Only Works With Host Reductions"); - - this->reduction_driver_->allreduce_inplace( VXC1s, nbf1*nbf1, ReductionOp::Sum ); - this->reduction_driver_->allreduce_inplace( VXC1z, nbf1*nbf1, ReductionOp::Sum ); - this->reduction_driver_->allreduce_inplace( VXC2s, nbf2*nbf1, ReductionOp::Sum ); - this->reduction_driver_->allreduce_inplace( VXC2z, nbf2*nbf2, ReductionOp::Sum ); - this->reduction_driver_->allreduce_inplace( EXC1, 1 , ReductionOp::Sum ); - this->reduction_driver_->allreduce_inplace( EXC2, 1 , ReductionOp::Sum ); - this->reduction_driver_->allreduce_inplace( &N_EL, 1 , ReductionOp::Sum ); - - }); - -} - - template void ReferenceReplicatedXCHostIntegrator:: exc_vxc_local_work_( const value_type* Ps, int64_t ldps, @@ -814,441 +681,5 @@ void ReferenceReplicatedXCHostIntegrator:: } - -template -void ReferenceReplicatedXCHostIntegrator:: - neo_exc_vxc_local_work_( const value_type* P1s, int64_t ldp1s, - const value_type* P1z, int64_t ldp1z, - const value_type* P2s, int64_t ldp2s, - const value_type* P2z, int64_t ldp2z, - value_type* VXC1s, int64_t ldvxc1s, - value_type* VXC1z, int64_t ldvxc1z, - value_type* VXC2s, int64_t ldvxc2s, - value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC1, value_type* EXC2, value_type *N_EL, - const IntegratorSettingsXC& ks_settings ) { - - - // Determine is electronic subsystem is RKS or UKS - const bool is_uks = (P1z != nullptr) and (VXC1z != nullptr); - const bool is_rks = not is_uks; // TODO: GKS - - // Cast LWD to LocalHostWorkDriver - auto* lwd = dynamic_cast(this->local_work_driver_.get()); - - // Setup Aliases - const auto& func = *this->func_; - const auto& basis = this->load_balancer_->basis(); - const auto& mol = this->load_balancer_->molecule(); - - // Get basis map - BasisSetMap basis_map(basis,mol); - - const int32_t nbf = basis.nbf(); - - // Get Protonic basis information - const auto& basis2 = this->load_balancer_->basis2(); - BasisSetMap basis_map2(basis2,mol); - const int32_t nbf2 = basis2.nbf(); - - // Sort tasks on size (XXX: maybe doesnt matter?) - auto task_comparator = []( const XCTask& a, const XCTask& b ) { - return (a.points.size() * a.bfn_screening.nbe) > (b.points.size() * b.bfn_screening.nbe); - }; - - auto& tasks = this->load_balancer_->get_tasks(); - std::sort( tasks.begin(), tasks.end(), task_comparator ); - - - // Check that Partition Weights have been calculated - auto& lb_state = this->load_balancer_->state(); - if( not lb_state.modified_weights_are_stored ) GAUXC_GENERIC_EXCEPTION("Weights Have Not Beed Modified"); - - - // Zero out integrands - - std::fill(VXC1s, VXC1s + nbf * ldvxc1s, 0.0); - if(is_uks) std::fill(VXC1z, VXC1z + nbf * ldvxc1z, 0.0); - - std::fill(VXC2s, VXC2s + nbf2 * ldvxc2s, 0.0); - std::fill(VXC2z, VXC2z + nbf2 * ldvxc2z, 0.0); - - *EXC1 = 0.; - *EXC2 = 0.; - - - // Loop over tasks - const size_t ntasks = tasks.size(); - - #pragma omp parallel - { - - XCHostData host_data; // Thread local host data - - #pragma omp for schedule(dynamic) - for( size_t iT = 0; iT < ntasks; ++iT ) { - - //std::cout << iT << "/" << ntasks << std::endl; - // Alias current task - const auto& task = tasks[iT]; - - // Get tasks constants - const int32_t npts = task.points.size(); - const int32_t nbe = task.bfn_screening.nbe; - const int32_t nshells = task.bfn_screening.shell_list.size(); - - const auto* points = task.points.data()->data(); - const auto* weights = task.weights.data(); - const int32_t* shell_list = task.bfn_screening.shell_list.data(); - - const int32_t nbe2 = task.bfn2_screening.nbe; - const int32_t nshells2 = task.bfn2_screening.shell_list.size(); - const int32_t* shell_list2 = task.bfn2_screening.shell_list.data(); - bool evalProtonic = (nshells2 != 0); - - // Allocate enough memory for batch - - const size_t spin_dim_scal = is_rks ? 1 : 2; - - // Things that every calc needs - - - // Use same scratch for both electronic and protonic - const int32_t scr_dim = std::max(nbe, nbe2); - host_data.nbe_scr .resize(scr_dim * scr_dim); - - //----------------------Start Electronic System Setup------------------------ - host_data.zmat .resize(npts * nbe * spin_dim_scal); - host_data.eps .resize(npts); - host_data.vrho .resize(npts * spin_dim_scal); - - // LDA data requirements - if( func.is_lda() ){ - host_data.basis_eval .resize( npts * nbe ); - host_data.den_scr .resize( npts * spin_dim_scal); - } - - // GGA data requirements - const size_t gga_dim_scal = is_rks ? 1 : 3; - if( func.is_gga() ){ - host_data.basis_eval .resize( 4 * npts * nbe ); - host_data.den_scr .resize( spin_dim_scal * 4 * npts ); - host_data.gamma .resize( gga_dim_scal * npts ); - host_data.vgamma .resize( gga_dim_scal * npts ); - } - - // Alias/Partition out scratch memory - auto* basis_eval = host_data.basis_eval.data(); - auto* den_eval = host_data.den_scr.data(); - auto* nbe_scr = host_data.nbe_scr.data(); - auto* zmat = host_data.zmat.data(); - - decltype(zmat) zmat_z = nullptr; - if(!is_rks) { - zmat_z = zmat + nbe * npts; - } - - auto* eps = host_data.eps.data(); - auto* gamma = host_data.gamma.data(); - auto* vrho = host_data.vrho.data(); - auto* vgamma = host_data.vgamma.data(); - - value_type* dbasis_x_eval = nullptr; - value_type* dbasis_y_eval = nullptr; - value_type* dbasis_z_eval = nullptr; - value_type* dden_x_eval = nullptr; - value_type* dden_y_eval = nullptr; - value_type* dden_z_eval = nullptr; - - if( func.is_gga() ) { - dbasis_x_eval = basis_eval + npts * nbe; - dbasis_y_eval = dbasis_x_eval + npts * nbe; - dbasis_z_eval = dbasis_y_eval + npts * nbe; - dden_x_eval = den_eval + spin_dim_scal * npts; - dden_y_eval = dden_x_eval + spin_dim_scal * npts; - dden_z_eval = dden_y_eval + spin_dim_scal * npts; - } - //----------------------End Electronic System Setup------------------------ - - - //----------------------Start Protonic System Setup------------------------ - // Set Up Memory (assuming UKS) - host_data.zmat2 .resize( npts * nbe2 * 2 ); - host_data.eps2 .resize( npts ); - host_data.vrho2 .resize( npts * 2 ); - // LDA - host_data.basis2_eval .resize( npts * nbe2 ); - host_data.den2_scr .resize( npts * 2); - // Alias/Partition out scratch memory - auto* basis2_eval = host_data.basis2_eval.data(); - auto* den2_eval = host_data.den2_scr.data(); - auto* zmat2 = host_data.zmat2.data(); - decltype(zmat2) zmat2_z = zmat2 + nbe2 * npts; - - auto* eps2 = host_data.eps2.data(); - auto* vrho2 = host_data.vrho2.data(); - // No GGA for NEO yet - //----------------------End Protonic System Setup------------------------ - - - //std::cout << "Task: " << iT << "/" << ntasks << std::endl; - //std::cout << "Electronic nbe: " << nbe << std::endl; - //std::cout << "Protonic nbe: " << nbe2 << std::endl; - - //----------------------Start Calculating Electronic Density & UV Variable------------------------ - // Get the submatrix map for batch - std::vector< std::array > submat_map; - std::tie(submat_map, std::ignore) = - gen_compressed_submat_map(basis_map, task.bfn_screening.shell_list, nbf, nbf); - - // Evaluate Collocation (+ Grad) - if( func.is_gga() ) - lwd->eval_collocation_gradient( npts, nshells, nbe, points, basis, shell_list, - basis_eval, dbasis_x_eval, dbasis_y_eval, dbasis_z_eval ); - else - lwd->eval_collocation( npts, nshells, nbe, points, basis, shell_list, - basis_eval ); - - // Evaluate X matrix (fac * P * B) -> store in Z - const auto xmat_fac = is_rks ? 2.0 : 1.0; // TODO Fix for spinor RKS input - lwd->eval_xmat( npts, nbf, nbe, submat_map, xmat_fac, P1s, ldp1s, basis_eval, nbe, - zmat, nbe, nbe_scr ); - - // X matrix for Pz - if(not is_rks) { - lwd->eval_xmat( npts, nbf, nbe, submat_map, 1.0, P1z, ldp1z, basis_eval, nbe, - zmat_z, nbe, nbe_scr ); - } - - // Evaluate U and V variables - if( func.is_gga() ) { - if(is_rks) { - lwd->eval_uvvar_gga_rks( npts, nbe, basis_eval, dbasis_x_eval, dbasis_y_eval, - dbasis_z_eval, zmat, nbe, den_eval, dden_x_eval, dden_y_eval, dden_z_eval, - gamma ); - } else if(is_uks) { - lwd->eval_uvvar_gga_uks( npts, nbe, basis_eval, dbasis_x_eval, dbasis_y_eval, - dbasis_z_eval, zmat, nbe, zmat_z, nbe, den_eval, dden_x_eval, - dden_y_eval, dden_z_eval, gamma ); - } - } else { - if(is_rks) { - lwd->eval_uvvar_lda_rks( npts, nbe, basis_eval, zmat, nbe, den_eval ); - } else if(is_uks) { - lwd->eval_uvvar_lda_uks( npts, nbe, basis_eval, zmat, nbe, zmat_z, nbe, - den_eval ); - } - } - - // Evaluate XC functional - if( func.is_gga() ) - func.eval_exc_vxc( npts, den_eval, gamma, eps, vrho, vgamma ); - else - func.eval_exc_vxc( npts, den_eval, eps, vrho ); - //----------------------End Calculating Electronic Density & UV Variable------------------------ - - - - - //----------------------Start Calculating Protonic Density & UV Variable------------------------ - std::vector< std::array > submat_map2; - if(evalProtonic){ - //std::tie(submat_map2, std::ignore) = - // gen_compressed_submat_map(basis_map2, shell_list2_vector, nbf2, nbf2); - std::tie(submat_map2, std::ignore) = - gen_compressed_submat_map(basis_map2, task.bfn2_screening.shell_list, nbf2, nbf2); - - // Evaluate Collocation - lwd->eval_collocation( npts, nshells2, nbe2, points, basis2, shell_list2, - basis2_eval ); - - // Evaluate X matrix (P * B) -> store in Z - // NEED THE FACTOR OF 2 HERE! - lwd->eval_xmat( npts, nbf2, nbe2, submat_map2, 2.0, P2s, ldp2s, basis2_eval, nbe2, - zmat2, nbe2, nbe_scr ); - lwd->eval_xmat( npts, nbf2, nbe2, submat_map2, 2.0, P2z, ldp2z, basis2_eval, nbe2, - zmat2_z, nbe2, nbe_scr ); - - // Evaluate U and V variables - lwd->eval_uvvar_lda_uks( npts, nbe2, basis2_eval, zmat2, nbe2, zmat2_z, nbe2, - den2_eval ); - - // No protonic XC functional. Fill with eps and vrho to be 0.0 - std::fill_n(eps2, npts, 0.); - std::fill_n(vrho2, npts*2, 0.); - } - //----------------------End Calculating Protonic Density & UV Variable------------------------ - - - - - //----------------------Start EPC functional Evaluation--------------------------------------- - if(evalProtonic){ - for (int32_t iPt = 0; iPt < npts; iPt++ ){ - // Get Electronic density scalar (RKS) - const auto den = is_rks ? den_eval[iPt] : (den_eval[2*iPt] + den_eval[2*iPt+1]); - value_type total_erho = std::abs(den) > 1e-15? den : 0; - // Get Protonic density scalar (UKS) - const auto den2 = den2_eval[2*iPt] + den2_eval[2*iPt+1]; - value_type total_prho = std::abs(den2) > 1e-15? den2 : 0; - - // Skip this point if the density is too small - if(total_erho < 1e-15 | total_prho < 1e-15){ - eps2[iPt] = 0.0; - vrho2[2*iPt] = 0.0; - vrho2[2*iPt+1] = 0.0; - continue; - } - - // epc-17-2 denominator - value_type dn = 2.35 - 2.4 * std::sqrt(total_erho*total_prho) + 6.6 * (total_erho*total_prho); - - // Update electronic eps and vxc - eps[iPt] += -1.0 * total_prho/dn; - vrho[spin_dim_scal*iPt] += ( -1.0 * total_prho / dn + (-1.2 * std::sqrt(total_erho) * std::sqrt(total_prho) * total_prho - + 6.6 * total_erho * total_prho * total_prho ) / (dn * dn) ); - if(not is_rks) - vrho[spin_dim_scal*iPt+1] += ( -1.0 * total_prho / dn + (-1.2 * std::sqrt(total_erho) * std::sqrt(total_prho) * total_prho - + 6.6 * total_erho * total_prho * total_prho ) / (dn * dn) ); - - // Assign protonic eps and vxc - eps2[iPt] = -1.0 * total_erho/dn; - vrho2[2*iPt] = ( -1.0 * total_erho / dn + (-1.2 * std::sqrt(total_prho) * std::sqrt(total_erho) * total_erho - + 6.6 * total_erho * total_erho * total_prho ) / (dn * dn) ); - vrho2[2*iPt+1] = 0.0; - } // End looping over pts - } // End if(evalProtonic) - //----------------------End EPC functional Evaluation--------------------------------------- - - - - //----------------------Begin Evaluating Electronic ZMat---------------------------- - // Factor weights into XC results - for( int32_t i = 0; i < npts; ++i ) { - eps[i] *= weights[i]; - vrho[spin_dim_scal*i] *= weights[i]; - if(not is_rks) vrho[spin_dim_scal*i+1] *= weights[i]; - } - - if( func.is_gga() ){ - for( int32_t i = 0; i < npts; ++i ) { - vgamma[gga_dim_scal*i] *= weights[i]; - if(not is_rks) { - vgamma[gga_dim_scal*i+1] *= weights[i]; - vgamma[gga_dim_scal*i+2] *= weights[i]; - } - } - } - - // Evaluate Z matrix for VXC - if( func.is_gga() ) { - if(is_rks) { - lwd->eval_zmat_gga_vxc_rks( npts, nbe, vrho, vgamma, basis_eval, dbasis_x_eval, - dbasis_y_eval, dbasis_z_eval, dden_x_eval, dden_y_eval, - dden_z_eval, zmat, nbe); - } else if(is_uks) { - lwd->eval_zmat_gga_vxc_uks( npts, nbe, vrho, vgamma, basis_eval, dbasis_x_eval, - dbasis_y_eval, dbasis_z_eval, dden_x_eval, dden_y_eval, - dden_z_eval, zmat, nbe, zmat_z, nbe); - } - } else { - if(is_rks) { - lwd->eval_zmat_lda_vxc_rks( npts, nbe, vrho, basis_eval, zmat, nbe ); - } else if(is_uks) { - lwd->eval_zmat_lda_vxc_uks( npts, nbe, vrho, basis_eval, zmat, nbe, zmat_z, nbe ); - } - } - //----------------------End Evaluating Electronic ZMat---------------------------- - - - - - //----------------------Begin Evaluating Protonic ZMat---------------------------- - if(evalProtonic){ - // Factor weights into XC results - for( int32_t i = 0; i < npts; ++i ) { - eps2[i] *= weights[i]; - vrho2[2*i] *= weights[i]; - vrho2[2*i+1] *= weights[i]; - } - - // Evaluate Z matrix for VXC - lwd->eval_zmat_lda_vxc_uks( npts, nbe2, vrho2, basis2_eval, zmat2, nbe2, zmat2_z, nbe2 ); - } - //----------------------End Evaluating Protonic ZMat---------------------------- - - - - - // Integrate to obtain Final EXC/VXC: - #pragma omp critical - { - - // Electronic XC (VXC+EPC) - // Scalar integrations - for( int32_t i = 0; i < npts; ++i ) { - const auto den = is_rks ? den_eval[i] : (den_eval[2*i] + den_eval[2*i+1]); - *N_EL += weights[i] * den; - *EXC1 += eps[i] * den; - } - // Increment VXC - lwd->inc_vxc( npts, nbf, nbe, basis_eval, submat_map, zmat, nbe, VXC1s, ldvxc1s, - nbe_scr ); - if(not is_rks) - lwd->inc_vxc( npts, nbf, nbe, basis_eval, submat_map, zmat_z, nbe, VXC1z, ldvxc1z, - nbe_scr ); - - - // Protonic XC (EPC) - // Scalar integrations - if(evalProtonic){ - for( int32_t i = 0; i < npts; ++i ) { - const auto den2 = den2_eval[2*i] + den2_eval[2*i+1]; - *EXC2 += eps2[i] * den2; - } - // Increment VXC - lwd->inc_vxc( npts, nbf2, nbe2, basis2_eval, submat_map2, zmat2, nbe2, VXC2s, ldvxc2s, - nbe_scr ); - lwd->inc_vxc( npts, nbf2, nbe2, basis2_eval, submat_map2, zmat2_z, nbe2, VXC2z, ldvxc2z, - nbe_scr ); - } - //std::cout << "Electronic EXC: " << *EXC1 << std::endl; - //std::cout << "Protonic EXC: " << *EXC2 << std::endl; - - } // End #pragma omp critical - - } // Loop over tasks - - } // End OpenMP region - - //std::cout << "N_EL = " << std::setprecision(12) << std::scientific << *N_EL << std::endl; - //std::cout << "EXC1 = " << std::setprecision(12) << std::scientific << *EXC1 << std::endl - //std::cout << "EXC2 = " << std::setprecision(12) << std::scientific << *EXC2 << std::endl; - - // Symmetrize Electronic VXC - for( int32_t j = 0; j < nbf; ++j ) - for( int32_t i = j+1; i < nbf; ++i ) - VXC1s[ j + i*ldvxc1s ] = VXC1s[ i + j*ldvxc1s ]; - if(not is_rks) { - for( int32_t j = 0; j < nbf; ++j ) { - for( int32_t i = j+1; i < nbf; ++i ) { - VXC1z[ j + i*ldvxc1z ] = VXC1z[ i + j*ldvxc1z ]; - } - } - } - - // Symmetrize Protonic VXC - for( int32_t j = 0; j < nbf2; ++j ){ - for( int32_t i = j+1; i < nbf2; ++i ){ - VXC2s[ j + i*ldvxc2s ] = VXC2s[ i + j*ldvxc2s ]; - VXC2z[ j + i*ldvxc2z ] = VXC2z[ i + j*ldvxc2z ]; - } - } - - -} - - - } } diff --git a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp new file mode 100644 index 00000000..104e8069 --- /dev/null +++ b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp @@ -0,0 +1,587 @@ +/** + * GauXC Copyright (c) 2020-2023, The Regents of the University of California, + * through Lawrence Berkeley National Laboratory (subject to receipt of + * any required approvals from the U.S. Dept. of Energy). All rights reserved. + * + * See LICENSE.txt for details + */ +#pragma once + +#include "reference_replicated_xc_host_integrator.hpp" +#include "integrator_util/integrator_common.hpp" +#include "host/local_host_work_driver.hpp" +#include "host/blas.hpp" +#include + +namespace GauXC { +namespace detail { + +template +void ReferenceReplicatedXCHostIntegrator:: + neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + const value_type* P1s, int64_t ldp1s, + const value_type* P2s, int64_t ldp2s, + const value_type* P2z, int64_t ldp2z, + value_type* VXC1s, int64_t ldvxc1s, + value_type* VXC2s, int64_t ldvxc2s, + value_type* VXC2z, int64_t ldvxc2z, + value_type* EXC1, value_type* EXC2, const IntegratorSettingsXC& ks_settings ){ + + const auto& basis = this->load_balancer_->basis(); + const auto& basis2 = this->load_balancer_->basis2(); + + // Check that P / VXC are sane + const int64_t nbf1 = basis.nbf(); + const int64_t nbf2 = basis2.nbf(); + + if( m1 != n1 | m2 != n2) + GAUXC_GENERIC_EXCEPTION("P/VXC Must Be Square"); + if( m1 != nbf1 | m2 != nbf2) + GAUXC_GENERIC_EXCEPTION("P/VXC Must Have Same Dimension as Basis"); + if( ldp1s < nbf1 | ldp2s < nbf2 | ldp2z < nbf2 ) + GAUXC_GENERIC_EXCEPTION("Invalid LDP"); + if( ldvxc1s < nbf1 | ldvxc2s < nbf2 | ldvxc2z < nbf2 ) + GAUXC_GENERIC_EXCEPTION("Invalid LDVXC"); + + // Get Tasks + this->load_balancer_->get_tasks(); + + // Temporary electron count to judge integrator accuracy + value_type N_EL; + + // Compute Local contributions to EXC / VXC + this->timer_.time_op("XCIntegrator.LocalWork", [&](){ + neo_exc_vxc_local_work_( P1s, ldp1s, + nullptr, 0, + P2s, ldp2s, + P2z, ldp2z, + VXC1s, ldvxc1s, + nullptr, 0, + VXC2s, ldvxc2s, + VXC2z, ldvxc2z, + EXC1, EXC2, &N_EL, ks_settings ); + }); + + + // Reduce Results + this->timer_.time_op("XCIntegrator.Allreduce", [&](){ + + if( not this->reduction_driver_->takes_host_memory() ) + GAUXC_GENERIC_EXCEPTION("This Module Only Works With Host Reductions"); + + this->reduction_driver_->allreduce_inplace( VXC1s, nbf1*nbf1, ReductionOp::Sum ); + this->reduction_driver_->allreduce_inplace( VXC2s, nbf2*nbf1, ReductionOp::Sum ); + this->reduction_driver_->allreduce_inplace( VXC2z, nbf2*nbf2, ReductionOp::Sum ); + this->reduction_driver_->allreduce_inplace( EXC1, 1 , ReductionOp::Sum ); + this->reduction_driver_->allreduce_inplace( EXC2, 1 , ReductionOp::Sum ); + this->reduction_driver_->allreduce_inplace( &N_EL, 1 , ReductionOp::Sum ); + + }); + +} + +template +void ReferenceReplicatedXCHostIntegrator:: + neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, + const value_type* P1s, int64_t ldp1s, + const value_type* P1z, int64_t ldp1z, + const value_type* P2s, int64_t ldp2s, + const value_type* P2z, int64_t ldp2z, + value_type* VXC1s, int64_t ldvxc1s, + value_type* VXC1z, int64_t ldvxc1z, + value_type* VXC2s, int64_t ldvxc2s, + value_type* VXC2z, int64_t ldvxc2z, + value_type* EXC1, value_type* EXC2, + const IntegratorSettingsXC& ks_settings ) { + + const auto& basis = this->load_balancer_->basis(); + const auto& basis2 = this->load_balancer_->basis2(); + + // Check that P / VXC are sane + const int64_t nbf1 = basis.nbf(); + const int64_t nbf2 = basis2.nbf(); + + if( m1 != n1 | m2 != n2) + GAUXC_GENERIC_EXCEPTION("P/VXC Must Be Square"); + if( m1 != nbf1 | m2 != nbf2) + GAUXC_GENERIC_EXCEPTION("P/VXC Must Have Same Dimension as Basis"); + if( ldp1s < nbf1 | ldp2s < nbf2 | ldp2z < nbf2 ) + GAUXC_GENERIC_EXCEPTION("Invalid LDP"); + if( ldvxc1s < nbf1 | ldvxc2s < nbf2 | ldvxc2z < nbf2 ) + GAUXC_GENERIC_EXCEPTION("Invalid LDVXC"); + + // Get Tasks + this->load_balancer_->get_tasks(); + + // Temporary electron count to judge integrator accuracy + value_type N_EL; + + // Compute Local contributions to EXC / VXC + this->timer_.time_op("XCIntegrator.LocalWork", [&](){ + neo_exc_vxc_local_work_( P1s, ldp1s, + P1z, ldp1z, + P2s, ldp2s, + P2z, ldp2z, + VXC1s, ldvxc1s, + VXC1z, ldvxc1z, + VXC2s, ldvxc2s, + VXC2z, ldvxc2z, + EXC1, EXC2, &N_EL, ks_settings); + }); + + + // Reduce Results + this->timer_.time_op("XCIntegrator.Allreduce", [&](){ + + if( not this->reduction_driver_->takes_host_memory() ) + GAUXC_GENERIC_EXCEPTION("This Module Only Works With Host Reductions"); + + this->reduction_driver_->allreduce_inplace( VXC1s, nbf1*nbf1, ReductionOp::Sum ); + this->reduction_driver_->allreduce_inplace( VXC1z, nbf1*nbf1, ReductionOp::Sum ); + this->reduction_driver_->allreduce_inplace( VXC2s, nbf2*nbf1, ReductionOp::Sum ); + this->reduction_driver_->allreduce_inplace( VXC2z, nbf2*nbf2, ReductionOp::Sum ); + this->reduction_driver_->allreduce_inplace( EXC1, 1 , ReductionOp::Sum ); + this->reduction_driver_->allreduce_inplace( EXC2, 1 , ReductionOp::Sum ); + this->reduction_driver_->allreduce_inplace( &N_EL, 1 , ReductionOp::Sum ); + + }); + +} + + +template +void ReferenceReplicatedXCHostIntegrator:: + neo_exc_vxc_local_work_( const value_type* P1s, int64_t ldp1s, + const value_type* P1z, int64_t ldp1z, + const value_type* P2s, int64_t ldp2s, + const value_type* P2z, int64_t ldp2z, + value_type* VXC1s, int64_t ldvxc1s, + value_type* VXC1z, int64_t ldvxc1z, + value_type* VXC2s, int64_t ldvxc2s, + value_type* VXC2z, int64_t ldvxc2z, + value_type* EXC1, value_type* EXC2, value_type *N_EL, + const IntegratorSettingsXC& ks_settings ) { + + + // Determine is electronic subsystem is RKS or UKS + const bool is_uks = (P1z != nullptr) and (VXC1z != nullptr); + const bool is_rks = not is_uks; // TODO: GKS + + // Cast LWD to LocalHostWorkDriver + auto* lwd = dynamic_cast(this->local_work_driver_.get()); + + // Setup Aliases + const auto& func = *this->func_; + const auto& basis = this->load_balancer_->basis(); + const auto& mol = this->load_balancer_->molecule(); + + // Get basis map + BasisSetMap basis_map(basis,mol); + + const int32_t nbf = basis.nbf(); + + // Get Protonic basis information + const auto& basis2 = this->load_balancer_->basis2(); + BasisSetMap basis_map2(basis2,mol); + const int32_t nbf2 = basis2.nbf(); + + // Sort tasks on size (XXX: maybe doesnt matter?) + auto task_comparator = []( const XCTask& a, const XCTask& b ) { + return (a.points.size() * a.bfn_screening.nbe) > (b.points.size() * b.bfn_screening.nbe); + }; + + auto& tasks = this->load_balancer_->get_tasks(); + std::sort( tasks.begin(), tasks.end(), task_comparator ); + + + // Check that Partition Weights have been calculated + auto& lb_state = this->load_balancer_->state(); + if( not lb_state.modified_weights_are_stored ) GAUXC_GENERIC_EXCEPTION("Weights Have Not Beed Modified"); + + + // Zero out integrands + + std::fill(VXC1s, VXC1s + nbf * ldvxc1s, 0.0); + if(is_uks) std::fill(VXC1z, VXC1z + nbf * ldvxc1z, 0.0); + + std::fill(VXC2s, VXC2s + nbf2 * ldvxc2s, 0.0); + std::fill(VXC2z, VXC2z + nbf2 * ldvxc2z, 0.0); + + *EXC1 = 0.; + *EXC2 = 0.; + + + // Loop over tasks + const size_t ntasks = tasks.size(); + + #pragma omp parallel + { + + XCHostData host_data; // Thread local host data + + #pragma omp for schedule(dynamic) + for( size_t iT = 0; iT < ntasks; ++iT ) { + + //std::cout << iT << "/" << ntasks << std::endl; + // Alias current task + const auto& task = tasks[iT]; + + // Get tasks constants + const int32_t npts = task.points.size(); + const int32_t nbe = task.bfn_screening.nbe; + const int32_t nshells = task.bfn_screening.shell_list.size(); + + const auto* points = task.points.data()->data(); + const auto* weights = task.weights.data(); + const int32_t* shell_list = task.bfn_screening.shell_list.data(); + + const int32_t nbe2 = task.bfn2_screening.nbe; + const int32_t nshells2 = task.bfn2_screening.shell_list.size(); + const int32_t* shell_list2 = task.bfn2_screening.shell_list.data(); + bool evalProtonic = (nshells2 != 0); + + // Allocate enough memory for batch + + const size_t spin_dim_scal = is_rks ? 1 : 2; + + // Things that every calc needs + + + // Use same scratch for both electronic and protonic + const int32_t scr_dim = std::max(nbe, nbe2); + host_data.nbe_scr .resize(scr_dim * scr_dim); + + //----------------------Start Electronic System Setup------------------------ + host_data.zmat .resize(npts * nbe * spin_dim_scal); + host_data.eps .resize(npts); + host_data.vrho .resize(npts * spin_dim_scal); + + // LDA data requirements + if( func.is_lda() ){ + host_data.basis_eval .resize( npts * nbe ); + host_data.den_scr .resize( npts * spin_dim_scal); + } + + // GGA data requirements + const size_t gga_dim_scal = is_rks ? 1 : 3; + if( func.is_gga() ){ + host_data.basis_eval .resize( 4 * npts * nbe ); + host_data.den_scr .resize( spin_dim_scal * 4 * npts ); + host_data.gamma .resize( gga_dim_scal * npts ); + host_data.vgamma .resize( gga_dim_scal * npts ); + } + + // Alias/Partition out scratch memory + auto* basis_eval = host_data.basis_eval.data(); + auto* den_eval = host_data.den_scr.data(); + auto* nbe_scr = host_data.nbe_scr.data(); + auto* zmat = host_data.zmat.data(); + + decltype(zmat) zmat_z = nullptr; + if(!is_rks) { + zmat_z = zmat + nbe * npts; + } + + auto* eps = host_data.eps.data(); + auto* gamma = host_data.gamma.data(); + auto* vrho = host_data.vrho.data(); + auto* vgamma = host_data.vgamma.data(); + + value_type* dbasis_x_eval = nullptr; + value_type* dbasis_y_eval = nullptr; + value_type* dbasis_z_eval = nullptr; + value_type* dden_x_eval = nullptr; + value_type* dden_y_eval = nullptr; + value_type* dden_z_eval = nullptr; + + if( func.is_gga() ) { + dbasis_x_eval = basis_eval + npts * nbe; + dbasis_y_eval = dbasis_x_eval + npts * nbe; + dbasis_z_eval = dbasis_y_eval + npts * nbe; + dden_x_eval = den_eval + spin_dim_scal * npts; + dden_y_eval = dden_x_eval + spin_dim_scal * npts; + dden_z_eval = dden_y_eval + spin_dim_scal * npts; + } + //----------------------End Electronic System Setup------------------------ + + + //----------------------Start Protonic System Setup------------------------ + // Set Up Memory (assuming UKS) + host_data.zmat2 .resize( npts * nbe2 * 2 ); + host_data.eps2 .resize( npts ); + host_data.vrho2 .resize( npts * 2 ); + // LDA + host_data.basis2_eval .resize( npts * nbe2 ); + host_data.den2_scr .resize( npts * 2); + // Alias/Partition out scratch memory + auto* basis2_eval = host_data.basis2_eval.data(); + auto* den2_eval = host_data.den2_scr.data(); + auto* zmat2 = host_data.zmat2.data(); + decltype(zmat2) zmat2_z = zmat2 + nbe2 * npts; + + auto* eps2 = host_data.eps2.data(); + auto* vrho2 = host_data.vrho2.data(); + // No GGA for NEO yet + //----------------------End Protonic System Setup------------------------ + + + //std::cout << "Task: " << iT << "/" << ntasks << std::endl; + //std::cout << "Electronic nbe: " << nbe << std::endl; + //std::cout << "Protonic nbe: " << nbe2 << std::endl; + + //----------------------Start Calculating Electronic Density & UV Variable------------------------ + // Get the submatrix map for batch + std::vector< std::array > submat_map; + std::tie(submat_map, std::ignore) = + gen_compressed_submat_map(basis_map, task.bfn_screening.shell_list, nbf, nbf); + + // Evaluate Collocation (+ Grad) + if( func.is_gga() ) + lwd->eval_collocation_gradient( npts, nshells, nbe, points, basis, shell_list, + basis_eval, dbasis_x_eval, dbasis_y_eval, dbasis_z_eval ); + else + lwd->eval_collocation( npts, nshells, nbe, points, basis, shell_list, + basis_eval ); + + // Evaluate X matrix (fac * P * B) -> store in Z + const auto xmat_fac = is_rks ? 2.0 : 1.0; // TODO Fix for spinor RKS input + lwd->eval_xmat( npts, nbf, nbe, submat_map, xmat_fac, P1s, ldp1s, basis_eval, nbe, + zmat, nbe, nbe_scr ); + + // X matrix for Pz + if(not is_rks) { + lwd->eval_xmat( npts, nbf, nbe, submat_map, 1.0, P1z, ldp1z, basis_eval, nbe, + zmat_z, nbe, nbe_scr ); + } + + // Evaluate U and V variables + if( func.is_gga() ) { + if(is_rks) { + lwd->eval_uvvar_gga_rks( npts, nbe, basis_eval, dbasis_x_eval, dbasis_y_eval, + dbasis_z_eval, zmat, nbe, den_eval, dden_x_eval, dden_y_eval, dden_z_eval, + gamma ); + } else if(is_uks) { + lwd->eval_uvvar_gga_uks( npts, nbe, basis_eval, dbasis_x_eval, dbasis_y_eval, + dbasis_z_eval, zmat, nbe, zmat_z, nbe, den_eval, dden_x_eval, + dden_y_eval, dden_z_eval, gamma ); + } + } else { + if(is_rks) { + lwd->eval_uvvar_lda_rks( npts, nbe, basis_eval, zmat, nbe, den_eval ); + } else if(is_uks) { + lwd->eval_uvvar_lda_uks( npts, nbe, basis_eval, zmat, nbe, zmat_z, nbe, + den_eval ); + } + } + + // Evaluate XC functional + if( func.is_gga() ) + func.eval_exc_vxc( npts, den_eval, gamma, eps, vrho, vgamma ); + else + func.eval_exc_vxc( npts, den_eval, eps, vrho ); + //----------------------End Calculating Electronic Density & UV Variable------------------------ + + + + + //----------------------Start Calculating Protonic Density & UV Variable------------------------ + std::vector< std::array > submat_map2; + if(evalProtonic){ + //std::tie(submat_map2, std::ignore) = + // gen_compressed_submat_map(basis_map2, shell_list2_vector, nbf2, nbf2); + std::tie(submat_map2, std::ignore) = + gen_compressed_submat_map(basis_map2, task.bfn2_screening.shell_list, nbf2, nbf2); + + // Evaluate Collocation + lwd->eval_collocation( npts, nshells2, nbe2, points, basis2, shell_list2, + basis2_eval ); + + // Evaluate X matrix (P * B) -> store in Z + // NEED THE FACTOR OF 2 HERE! + lwd->eval_xmat( npts, nbf2, nbe2, submat_map2, 2.0, P2s, ldp2s, basis2_eval, nbe2, + zmat2, nbe2, nbe_scr ); + lwd->eval_xmat( npts, nbf2, nbe2, submat_map2, 2.0, P2z, ldp2z, basis2_eval, nbe2, + zmat2_z, nbe2, nbe_scr ); + + // Evaluate U and V variables + lwd->eval_uvvar_lda_uks( npts, nbe2, basis2_eval, zmat2, nbe2, zmat2_z, nbe2, + den2_eval ); + + // No protonic XC functional. Fill with eps and vrho to be 0.0 + std::fill_n(eps2, npts, 0.); + std::fill_n(vrho2, npts*2, 0.); + } + //----------------------End Calculating Protonic Density & UV Variable------------------------ + + + + + //----------------------Start EPC functional Evaluation--------------------------------------- + if(evalProtonic){ + for (int32_t iPt = 0; iPt < npts; iPt++ ){ + // Get Electronic density scalar (RKS) + const auto den = is_rks ? den_eval[iPt] : (den_eval[2*iPt] + den_eval[2*iPt+1]); + value_type total_erho = std::abs(den) > 1e-15? den : 0; + // Get Protonic density scalar (UKS) + const auto den2 = den2_eval[2*iPt] + den2_eval[2*iPt+1]; + value_type total_prho = std::abs(den2) > 1e-15? den2 : 0; + + // Skip this point if the density is too small + if(total_erho < 1e-15 | total_prho < 1e-15){ + eps2[iPt] = 0.0; + vrho2[2*iPt] = 0.0; + vrho2[2*iPt+1] = 0.0; + continue; + } + + // epc-17-2 denominator + value_type dn = 2.35 - 2.4 * std::sqrt(total_erho*total_prho) + 6.6 * (total_erho*total_prho); + + // Update electronic eps and vxc + eps[iPt] += -1.0 * total_prho/dn; + vrho[spin_dim_scal*iPt] += ( -1.0 * total_prho / dn + (-1.2 * std::sqrt(total_erho) * std::sqrt(total_prho) * total_prho + + 6.6 * total_erho * total_prho * total_prho ) / (dn * dn) ); + if(not is_rks) + vrho[spin_dim_scal*iPt+1] += ( -1.0 * total_prho / dn + (-1.2 * std::sqrt(total_erho) * std::sqrt(total_prho) * total_prho + + 6.6 * total_erho * total_prho * total_prho ) / (dn * dn) ); + + // Assign protonic eps and vxc + eps2[iPt] = -1.0 * total_erho/dn; + vrho2[2*iPt] = ( -1.0 * total_erho / dn + (-1.2 * std::sqrt(total_prho) * std::sqrt(total_erho) * total_erho + + 6.6 * total_erho * total_erho * total_prho ) / (dn * dn) ); + vrho2[2*iPt+1] = 0.0; + } // End looping over pts + } // End if(evalProtonic) + //----------------------End EPC functional Evaluation--------------------------------------- + + + + //----------------------Begin Evaluating Electronic ZMat---------------------------- + // Factor weights into XC results + for( int32_t i = 0; i < npts; ++i ) { + eps[i] *= weights[i]; + vrho[spin_dim_scal*i] *= weights[i]; + if(not is_rks) vrho[spin_dim_scal*i+1] *= weights[i]; + } + + if( func.is_gga() ){ + for( int32_t i = 0; i < npts; ++i ) { + vgamma[gga_dim_scal*i] *= weights[i]; + if(not is_rks) { + vgamma[gga_dim_scal*i+1] *= weights[i]; + vgamma[gga_dim_scal*i+2] *= weights[i]; + } + } + } + + // Evaluate Z matrix for VXC + if( func.is_gga() ) { + if(is_rks) { + lwd->eval_zmat_gga_vxc_rks( npts, nbe, vrho, vgamma, basis_eval, dbasis_x_eval, + dbasis_y_eval, dbasis_z_eval, dden_x_eval, dden_y_eval, + dden_z_eval, zmat, nbe); + } else if(is_uks) { + lwd->eval_zmat_gga_vxc_uks( npts, nbe, vrho, vgamma, basis_eval, dbasis_x_eval, + dbasis_y_eval, dbasis_z_eval, dden_x_eval, dden_y_eval, + dden_z_eval, zmat, nbe, zmat_z, nbe); + } + } else { + if(is_rks) { + lwd->eval_zmat_lda_vxc_rks( npts, nbe, vrho, basis_eval, zmat, nbe ); + } else if(is_uks) { + lwd->eval_zmat_lda_vxc_uks( npts, nbe, vrho, basis_eval, zmat, nbe, zmat_z, nbe ); + } + } + //----------------------End Evaluating Electronic ZMat---------------------------- + + + + + //----------------------Begin Evaluating Protonic ZMat---------------------------- + if(evalProtonic){ + // Factor weights into XC results + for( int32_t i = 0; i < npts; ++i ) { + eps2[i] *= weights[i]; + vrho2[2*i] *= weights[i]; + vrho2[2*i+1] *= weights[i]; + } + + // Evaluate Z matrix for VXC + lwd->eval_zmat_lda_vxc_uks( npts, nbe2, vrho2, basis2_eval, zmat2, nbe2, zmat2_z, nbe2 ); + } + //----------------------End Evaluating Protonic ZMat---------------------------- + + + + + // Integrate to obtain Final EXC/VXC: + #pragma omp critical + { + + // Electronic XC (VXC+EPC) + // Scalar integrations + for( int32_t i = 0; i < npts; ++i ) { + const auto den = is_rks ? den_eval[i] : (den_eval[2*i] + den_eval[2*i+1]); + *N_EL += weights[i] * den; + *EXC1 += eps[i] * den; + } + // Increment VXC + lwd->inc_vxc( npts, nbf, nbe, basis_eval, submat_map, zmat, nbe, VXC1s, ldvxc1s, + nbe_scr ); + if(not is_rks) + lwd->inc_vxc( npts, nbf, nbe, basis_eval, submat_map, zmat_z, nbe, VXC1z, ldvxc1z, + nbe_scr ); + + + // Protonic XC (EPC) + // Scalar integrations + if(evalProtonic){ + for( int32_t i = 0; i < npts; ++i ) { + const auto den2 = den2_eval[2*i] + den2_eval[2*i+1]; + *EXC2 += eps2[i] * den2; + } + // Increment VXC + lwd->inc_vxc( npts, nbf2, nbe2, basis2_eval, submat_map2, zmat2, nbe2, VXC2s, ldvxc2s, + nbe_scr ); + lwd->inc_vxc( npts, nbf2, nbe2, basis2_eval, submat_map2, zmat2_z, nbe2, VXC2z, ldvxc2z, + nbe_scr ); + } + //std::cout << "Electronic EXC: " << *EXC1 << std::endl; + //std::cout << "Protonic EXC: " << *EXC2 << std::endl; + + } // End #pragma omp critical + + } // Loop over tasks + + } // End OpenMP region + + //std::cout << "N_EL = " << std::setprecision(12) << std::scientific << *N_EL << std::endl; + //std::cout << "EXC1 = " << std::setprecision(12) << std::scientific << *EXC1 << std::endl + //std::cout << "EXC2 = " << std::setprecision(12) << std::scientific << *EXC2 << std::endl; + + // Symmetrize Electronic VXC + for( int32_t j = 0; j < nbf; ++j ) + for( int32_t i = j+1; i < nbf; ++i ) + VXC1s[ j + i*ldvxc1s ] = VXC1s[ i + j*ldvxc1s ]; + if(not is_rks) { + for( int32_t j = 0; j < nbf; ++j ) { + for( int32_t i = j+1; i < nbf; ++i ) { + VXC1z[ j + i*ldvxc1z ] = VXC1z[ i + j*ldvxc1z ]; + } + } + } + + // Symmetrize Protonic VXC + for( int32_t j = 0; j < nbf2; ++j ){ + for( int32_t i = j+1; i < nbf2; ++i ){ + VXC2s[ j + i*ldvxc2s ] = VXC2s[ i + j*ldvxc2s ]; + VXC2z[ j + i*ldvxc2z ] = VXC2z[ i + j*ldvxc2z ]; + } + } + + +} + + +} +} From 44706c10db60917206d283a6566dbe6742bdd572 Mon Sep 17 00:00:00 2001 From: aodongliu Date: Mon, 4 Dec 2023 14:02:11 -0800 Subject: [PATCH 26/49] explicitly spell out 'protonic' for class variables and function arguments --- include/gauxc/load_balancer.hpp | 12 +- .../replicated_xc_integrator_impl.hpp | 74 ++--- include/gauxc/xc_task.hpp | 2 +- .../host/load_balancer_host_factory.cxx | 6 +- .../host/load_balancer_host_factory.hpp | 2 +- .../host/replicated_host_load_balancer.cxx | 18 +- src/load_balancer/load_balancer.cxx | 17 +- src/load_balancer/load_balancer_factory.cxx | 8 +- src/load_balancer/load_balancer_impl.cxx | 34 +- src/load_balancer/load_balancer_impl.hpp | 15 +- ...incore_replicated_xc_device_integrator.hpp | 38 +-- ...eplicated_xc_device_integrator_exc_vxc.hpp | 43 +-- ...atched_replicated_xc_device_integrator.hpp | 38 +-- ...eplicated_xc_device_integrator_exc_vxc.hpp | 48 +-- ...eference_replicated_xc_host_integrator.hpp | 50 +-- ...licated_xc_host_integrator_exc_vxc_neo.hpp | 308 +++++++++--------- .../replicated/host/xc_host_data.hpp | 15 +- .../replicated_xc_integrator_impl.cxx | 72 ++-- 18 files changed, 402 insertions(+), 398 deletions(-) diff --git a/include/gauxc/load_balancer.hpp b/include/gauxc/load_balancer.hpp index 5297340c..7d0ae6d3 100644 --- a/include/gauxc/load_balancer.hpp +++ b/include/gauxc/load_balancer.hpp @@ -102,14 +102,14 @@ class LoadBalancer { const shell_pair_type& shell_pairs() const; const shell_pair_type& shell_pairs(); - /// Return the underlying 2nd BasisSet instance used to generate this LoadBalancer - const basis_type& basis2() const; + /// Return the underlying protonic BasisSet instance used to generate this LoadBalancer + const basis_type& protonic_basis() const; - /// Return BasisSetMap instance corresponding to 2nd basis/molecule - const basis_map_type& basis_map2() const; + /// Return the protonic BasisSetMap instance corresponding to protonic basis/molecule + const basis_map_type& protonic_basis_map() const; - /// Return the number of non-negligible local shell pairs for 2nd basis for this LoadBalancer - const shell_pair_type& shell_pairs2() const; + /// Return the number of non-negligible local shell pairs for the protonic basis for this LoadBalancer + const shell_pair_type& protonic_shell_pairs() const; /// Return the runtime handle used to construct this LoadBalancer const RuntimeEnvironment& runtime() const; diff --git a/include/gauxc/xc_integrator/replicated/replicated_xc_integrator_impl.hpp b/include/gauxc/xc_integrator/replicated/replicated_xc_integrator_impl.hpp index 66095645..db4f2381 100644 --- a/include/gauxc/xc_integrator/replicated/replicated_xc_integrator_impl.hpp +++ b/include/gauxc/xc_integrator/replicated/replicated_xc_integrator_impl.hpp @@ -61,24 +61,24 @@ class ReplicatedXCIntegratorImpl { value_type* VXCy, int64_t ldvxcy, value_type* VXCx, int64_t ldvxcx, value_type* EXC, const IntegratorSettingsXC& ks_settings ) = 0; - virtual void neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, - const value_type* P1s, int64_t ldp1s, - const value_type* P2s, int64_t ldp2s, - const value_type* P2z, int64_t ldp2z, - value_type* VXC1s, int64_t ldvxc1s, - value_type* VXC2s, int64_t ldvxc2s, - value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC1, value_type* EXC2, const IntegratorSettingsXC& ks_settings) = 0; - virtual void neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, - const value_type* P1s, int64_t ldp1s, - const value_type* P1z, int64_t ldp1z, - const value_type* P2s, int64_t ldp2s, - const value_type* P2z, int64_t ldp2z, - value_type* VXC1s, int64_t ldvxc1s, - value_type* VXC1z, int64_t ldvxc1z, - value_type* VXC2s, int64_t ldvxc2s, - value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC1, value_type* EXC2, const IntegratorSettingsXC& ks_settings) = 0; + virtual void neo_eval_exc_vxc_( int64_t elec_m, int64_t elec_mn, int64_t prot_m, int64_t prot_n, + const value_type* elec_Ps, int64_t elec_ldps, + const value_type* prot_Ps, int64_t prot_ldps, + const value_type* prot_Pz, int64_t prot_ldpz, + value_type* elec_VXCs, int64_t elec_ldvxcs, + value_type* prot_VXCs, int64_t prot_ldvxcs, + value_type* prot_VXCz, int64_t prot_ldvxcz, + value_type* elec_EXC, value_type* prot_EXC, const IntegratorSettingsXC& ks_settings) = 0; + virtual void neo_eval_exc_vxc_( int64_t elec_m, int64_t elec_n, int64_t prot_m, int64_t prot_n, + const value_type* elec_Ps, int64_t elec_ldps, + const value_type* elec_Pz, int64_t elec_ldpz, + const value_type* prot_Ps, int64_t prot_ldps, + const value_type* prot_Pz, int64_t prot_ldpz, + value_type* elec_VXCs, int64_t elec_ldvxcs, + value_type* elec_VXCz, int64_t elec_ldvxcz, + value_type* prot_VXCs, int64_t prot_ldvxcs, + value_type* prot_VXCz, int64_t prot_ldvxcz, + value_type* elec_EXC, value_type* prot_EXC, const IntegratorSettingsXC& ks_settings) = 0; virtual void eval_exc_grad_( int64_t m, int64_t n, const value_type* P, int64_t ldp, value_type* EXC_GRAD ) = 0; virtual void eval_exx_( int64_t m, int64_t n, const value_type* P, @@ -124,25 +124,25 @@ class ReplicatedXCIntegratorImpl { value_type* VXCx, int64_t ldvxcx, value_type* EXC, const IntegratorSettingsXC& ks_settings ); - void neo_eval_exc_vxc( int64_t m1, int64_t n1, int64_t m2, int64_t n2, - const value_type* P1s, int64_t ldp1s, - const value_type* P2s, int64_t ldp2s, - const value_type* P2z, int64_t ldp2z, - value_type* VXC1s, int64_t ldvxc1s, - value_type* VXC2s, int64_t ldvxc2s, - value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC1, value_type* EXC2, const IntegratorSettingsXC& ks_settings ); - - void neo_eval_exc_vxc( int64_t m1, int64_t n1, int64_t m2, int64_t n2, - const value_type* P1s, int64_t ldp1s, - const value_type* P1z, int64_t ldp1z, - const value_type* P2s, int64_t ldp2s, - const value_type* P2z, int64_t ldp2z, - value_type* VXC1s, int64_t ldvxc1s, - value_type* VXC1z, int64_t ldvxc1z, - value_type* VXC2s, int64_t ldvxc2s, - value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC1, value_type* EXC2, const IntegratorSettingsXC& ks_settings ); + void neo_eval_exc_vxc( int64_t elec_m, int64_t elec_n, int64_t prot_m, int64_t prot_n, + const value_type* elec_Ps, int64_t elec_ldps, + const value_type* prot_Ps, int64_t prot_ldps, + const value_type* prot_Pz, int64_t prot_ldpz, + value_type* elec_VXCs, int64_t elec_ldvxcs, + value_type* prot_VXCs, int64_t prot_ldvxcs, + value_type* prot_VXCz, int64_t prot_ldvxcz, + value_type* elec_EXC, value_type* prot_EXC, const IntegratorSettingsXC& ks_settings ); + + void neo_eval_exc_vxc( int64_t elec_m, int64_t elec_n, int64_t prot_m, int64_t prot_n, + const value_type* elec_Ps, int64_t elec_ldps, + const value_type* elec_Pz, int64_t elec_ldpz, + const value_type* prot_Ps, int64_t prot_ldps, + const value_type* prot_Pz, int64_t prot_ldpz, + value_type* elec_VXCs, int64_t elec_ldvxcs, + value_type* elec_VXCz, int64_t elec_ldvxcz, + value_type* prot_VXCs, int64_t prot_ldvxcs, + value_type* prot_VXCz, int64_t prot_ldvxcz, + value_type* elec_EXC, value_type* prot_EXC, const IntegratorSettingsXC& ks_settings ); void eval_exc_grad( int64_t m, int64_t n, const value_type* P, int64_t ldp, value_type* EXC_GRAD ); diff --git a/include/gauxc/xc_task.hpp b/include/gauxc/xc_task.hpp index 22bb2bad..27cb26c3 100644 --- a/include/gauxc/xc_task.hpp +++ b/include/gauxc/xc_task.hpp @@ -55,7 +55,7 @@ struct XCTask { } screening_data bfn_screening; - screening_data bfn2_screening; + screening_data protonic_bfn_screening; screening_data cou_screening; void merge_with( const XCTask& other ) { diff --git a/src/load_balancer/host/load_balancer_host_factory.cxx b/src/load_balancer/host/load_balancer_host_factory.cxx index c33c2945..d83e8301 100644 --- a/src/load_balancer/host/load_balancer_host_factory.cxx +++ b/src/load_balancer/host/load_balancer_host_factory.cxx @@ -44,7 +44,7 @@ std::shared_ptr LoadBalancerHostFactory::get_shared_instance( std::shared_ptr LoadBalancerHostFactory::get_shared_instance( std::string kernel_name, const RuntimeEnvironment& rt, const Molecule& mol, const MolGrid& mg, const BasisSet& basis, - const BasisSet& basis2, size_t pv + const BasisSet& protonic_basis, size_t pv ) { std::transform(kernel_name.begin(), kernel_name.end(), @@ -57,12 +57,12 @@ std::shared_ptr LoadBalancerHostFactory::get_shared_instance( std::unique_ptr ptr = nullptr; if( kernel_name == "REPLICATED-PETITE" ) ptr = std::make_unique( - rt, mol, mg, basis, basis2, pv + rt, mol, mg, basis, protonic_basis, pv ); if( kernel_name == "REPLICATED-FILLIN" ) ptr = std::make_unique( - rt, mol, mg, basis, basis2, pv + rt, mol, mg, basis, protonic_basis, pv ); if( ! ptr ) GAUXC_GENERIC_EXCEPTION("Load Balancer Kernel Not Recognized: " + kernel_name); diff --git a/src/load_balancer/host/load_balancer_host_factory.hpp b/src/load_balancer/host/load_balancer_host_factory.hpp index bd6a51b2..b8dcf0fb 100644 --- a/src/load_balancer/host/load_balancer_host_factory.hpp +++ b/src/load_balancer/host/load_balancer_host_factory.hpp @@ -20,7 +20,7 @@ struct LoadBalancerHostFactory { static std::shared_ptr get_shared_instance( std::string kernel_name, const RuntimeEnvironment& rt, const Molecule& mol, const MolGrid& mg, const BasisSet& basis, - const BasisSet& basis2, size_t pv + const BasisSet& protonic_basis, size_t pv ); }; diff --git a/src/load_balancer/host/replicated_host_load_balancer.cxx b/src/load_balancer/host/replicated_host_load_balancer.cxx index 496764a9..075e926b 100644 --- a/src/load_balancer/host/replicated_host_load_balancer.cxx +++ b/src/load_balancer/host/replicated_host_load_balancer.cxx @@ -59,15 +59,15 @@ std::vector< XCTask > HostReplicatedLoadBalancer::create_local_tasks_() const { auto [shell_list, nbe] = micro_batch_screen( (*this->basis_), lo, up ); // If there's a NEO protonic basis, then do microbatch screening on it - std::vector shell_list2; - size_t nbe2 = 0; - if (this->basis2_) - std::tie(shell_list2, nbe2) = micro_batch_screen((*this->basis2_), lo, up); + std::vector protonic_shell_list; + size_t protonic_nbe = 0; + if (this->protonic_basis_) + std::tie(protonic_shell_list, protonic_nbe) = micro_batch_screen((*this->protonic_basis_), lo, up); // Course grain screening - // For NEO, skip task when electronic shell list is empty + // For NEO, skip task when electronic shell list is empty + // (Protonic system doesnt have XC. It only has EPC) if( not shell_list.size() ) continue; - // if (shell_list.empty() && (!this->basis2_ || shell_list2.empty())) continue; // Copy task data XCTask task; @@ -79,9 +79,9 @@ std::vector< XCTask > HostReplicatedLoadBalancer::create_local_tasks_() const { task.bfn_screening.shell_list = std::move(shell_list); task.bfn_screening.nbe = nbe; task.dist_nearest = molmeta_->dist_nearest()[iCurrent]; - if(this->basis2_){ - task.bfn2_screening.shell_list = std::move(shell_list2); - task.bfn2_screening.nbe = nbe2; + if(this->protonic_basis_){ + task.protonic_bfn_screening.shell_list = std::move(protonic_shell_list); + task.protonic_bfn_screening.nbe = protonic_nbe; } diff --git a/src/load_balancer/load_balancer.cxx b/src/load_balancer/load_balancer.cxx index df49202f..e9601bfe 100644 --- a/src/load_balancer/load_balancer.cxx +++ b/src/load_balancer/load_balancer.cxx @@ -87,27 +87,26 @@ const LoadBalancer::shell_pair_type& LoadBalancer::shell_pairs() const { if( not pimpl_ ) GAUXC_PIMPL_NOT_INITIALIZED(); return pimpl_->shell_pairs(); } - const LoadBalancer::shell_pair_type& LoadBalancer::shell_pairs() { if( not pimpl_ ) GAUXC_PIMPL_NOT_INITIALIZED(); return pimpl_->shell_pairs(); } -const LoadBalancer::basis_type& LoadBalancer::basis2() const { +const LoadBalancer::basis_type& LoadBalancer::protonic_basis() const { if( not pimpl_ ) GAUXC_PIMPL_NOT_INITIALIZED(); - return pimpl_->basis2(); + return pimpl_->protonic_basis(); } -const LoadBalancer::basis_map_type& LoadBalancer::basis_map2() const { +const LoadBalancer::basis_map_type& LoadBalancer::protonic_basis_map() const { if( not pimpl_ ) GAUXC_PIMPL_NOT_INITIALIZED(); - return pimpl_->basis_map2(); + return pimpl_->protonic_basis_map(); } -const LoadBalancer::shell_pair_type& LoadBalancer::shell_pairs2() const { +const LoadBalancer::shell_pair_type& LoadBalancer::protonic_shell_pairs() const { if( not pimpl_ ) GAUXC_PIMPL_NOT_INITIALIZED(); - return pimpl_->shell_pairs2(); + return pimpl_->protonic_shell_pairs(); } -const LoadBalancer::shell_pair_type& LoadBalancer::shell_pairs2() { +const LoadBalancer::shell_pair_type& LoadBalancer::protonic_shell_pairs() { if( not pimpl_ ) GAUXC_PIMPL_NOT_INITIALIZED(); - return pimpl_->shell_pairs2(); + return pimpl_->protonic_shell_pairs(); } LoadBalancerState& LoadBalancer::state() { diff --git a/src/load_balancer/load_balancer_factory.cxx b/src/load_balancer/load_balancer_factory.cxx index bc3b687a..bf02c7e8 100644 --- a/src/load_balancer/load_balancer_factory.cxx +++ b/src/load_balancer/load_balancer_factory.cxx @@ -53,14 +53,14 @@ LoadBalancer LoadBalancerFactory::get_instance( std::shared_ptr LoadBalancerFactory::get_shared_instance( const RuntimeEnvironment& rt, const Molecule& mol, const MolGrid& mg, const BasisSet& basis, - const BasisSet& basis2, size_t pad_value + const BasisSet& protonic_basis, size_t pad_value ) { switch(ex_) { case ExecutionSpace::Host: using host_factory = LoadBalancerHostFactory; return host_factory::get_shared_instance(kernel_name_, - rt, mol, mg, basis, basis2, pad_value ); + rt, mol, mg, basis, protonic_basis, pad_value ); #ifdef GAUXC_ENABLE_DEVICE case ExecutionSpace::Device: GAUXC_GENERIC_EXCEPTION("2 basis with GPU NYI"); @@ -78,10 +78,10 @@ std::shared_ptr LoadBalancerFactory::get_shared_instance( LoadBalancer LoadBalancerFactory::get_instance( const RuntimeEnvironment& rt, const Molecule& mol, const MolGrid& mg, const BasisSet& basis, - const BasisSet& basis2, size_t pad_value + const BasisSet& protonic_basis, size_t pad_value ) { - auto ptr = get_shared_instance(rt, mol, mg, basis, basis2, pad_value); + auto ptr = get_shared_instance(rt, mol, mg, basis, protonic_basis, pad_value); return LoadBalancer(std::move(*ptr)); } diff --git a/src/load_balancer/load_balancer_impl.cxx b/src/load_balancer/load_balancer_impl.cxx index d33ef106..e190d721 100644 --- a/src/load_balancer/load_balancer_impl.cxx +++ b/src/load_balancer/load_balancer_impl.cxx @@ -22,12 +22,13 @@ LoadBalancerImpl::LoadBalancerImpl( const RuntimeEnvironment& rt, const Molecule } LoadBalancerImpl::LoadBalancerImpl(const RuntimeEnvironment& rt, const Molecule& mol, - const MolGrid& mg, const basis_type& basis, const basis_type& basis2, std::shared_ptr molmeta ) : + const MolGrid& mg, const basis_type& basis, const basis_type& protonic_basis, + std::shared_ptr molmeta ) : LoadBalancerImpl(rt, mol, mg, basis, molmeta) { // Unique initializations for the second basis + shell_pairs2_ = std::make_shared(*basis2_); basis_map2_ = std::make_shared(*basis2_, mol); - } LoadBalancerImpl::LoadBalancerImpl( const RuntimeEnvironment& rt, const Molecule& mol, @@ -39,12 +40,12 @@ LoadBalancerImpl::LoadBalancerImpl( const RuntimeEnvironment& rt, const Molecule LoadBalancerImpl( rt, mol, mg, basis, std::make_shared(mol) ) { } LoadBalancerImpl::LoadBalancerImpl( const RuntimeEnvironment& rt, const Molecule& mol, - const MolGrid& mg, const basis_type& basis, const basis_type& basis2 ) : - LoadBalancerImpl( rt, mol, mg, basis, basis2, std::make_shared(mol) ) { } + const MolGrid& mg, const basis_type& basis, const basis_type& protonic_basis ) : + LoadBalancerImpl( rt, mol, mg, basis, protonic_basis, std::make_shared(mol) ) { } LoadBalancerImpl::LoadBalancerImpl( const RuntimeEnvironment& rt, const Molecule& mol, - const MolGrid& mg, const basis_type& basis, const basis_type& basis2, const MolMeta& molmeta ) : - LoadBalancerImpl( rt, mol, mg, basis, basis2, std::make_shared(molmeta) ) { } + const MolGrid& mg, const basis_type& basis, const basis_type& protonic_basis, const MolMeta& molmeta ) : + LoadBalancerImpl( rt, mol, mg, basis, protonic_basis, std::make_shared(molmeta) ) { } LoadBalancerImpl::LoadBalancerImpl( const LoadBalancerImpl& ) = default; LoadBalancerImpl::LoadBalancerImpl( LoadBalancerImpl&& ) noexcept = default; @@ -136,18 +137,21 @@ const LoadBalancerImpl::shell_pair_type& LoadBalancerImpl::shell_pairs() { return *shell_pairs_; } -const LoadBalancerImpl::basis_type& LoadBalancerImpl::basis2() const { - if( not basis2_ ) GAUXC_GENERIC_EXCEPTION("No Protonic Basis Found in LoadBalancerImpl::basis2()"); - return *basis2_; +const LoadBalancerImpl::basis_type& LoadBalancerImpl::protonic_basis() const { + if( not protonic_basis_ ) + GAUXC_GENERIC_EXCEPTION("No Protonic Basis Found in LoadBalancerImpl::protonic_basis()"); + return *protonic_basis_; } -const LoadBalancerImpl::basis_map_type& LoadBalancerImpl::basis_map2() const { - if( not basis_map2_ ) GAUXC_GENERIC_EXCEPTION("No Protonic Basis Found in LoadBalancerImpl::basis_map2()"); - return *basis_map2_; +const LoadBalancerImpl::basis_map_type& LoadBalancerImpl::protonic_basis_map() const { + if( not protonic_basis_map_ ) + GAUXC_GENERIC_EXCEPTION("No Protonic Basis Found in LoadBalancerImpl::protonic_basis_map()"); + return *protonic_basis_map_; } -const LoadBalancerImpl::shell_pair_type& LoadBalancerImpl::shell_pairs2() const { - if( not shell_pairs2_ ) GAUXC_GENERIC_EXCEPTION("No Protonic Basis Found in LoadBalancerImpl::shell_pairs2()"); - return *shell_pairs2_; +const LoadBalancerImpl::shell_pair_type& LoadBalancerImpl::protonic_shell_pairs() const { + if( not protonic_shell_pairs_ ) + GAUXC_GENERIC_EXCEPTION("No Protonic Basis Found in LoadBalancerImpl::protonic_shell_pairs()"); + return *protonic_shell_pairs_; } const RuntimeEnvironment& LoadBalancerImpl::runtime() const { diff --git a/src/load_balancer/load_balancer_impl.hpp b/src/load_balancer/load_balancer_impl.hpp index e2a0285c..38f183c8 100644 --- a/src/load_balancer/load_balancer_impl.hpp +++ b/src/load_balancer/load_balancer_impl.hpp @@ -30,9 +30,10 @@ class LoadBalancerImpl { std::shared_ptr basis_map_; std::shared_ptr shell_pairs_; - std::shared_ptr basis2_; - std::shared_ptr basis_map2_; - std::shared_ptr shell_pairs2_; + // Protonic basis information if doing Nuclear-Electronic Orbital (NEO) theory + std::shared_ptr protonic_basis_; + std::shared_ptr protonic_basis_map_; + std::shared_ptr protonic_shell_pairs_; std::vector< XCTask > local_tasks_; @@ -85,10 +86,10 @@ class LoadBalancerImpl { const basis_map_type& basis_map() const; const shell_pair_type& shell_pairs() const; const shell_pair_type& shell_pairs(); - const basis_type& basis2() const; - const basis_map_type& basis_map2() const; - const shell_pair_type& shell_pairs2() const; - const shell_pair_type& shell_pairs2(); + const basis_type& protonic_basis() const; + const basis_map_type& protonic_basis_map() const; + const shell_pair_type& protonic_shell_pairs() const; + const shell_pair_type& protonic_shell_pairs(); LoadBalancerState& state(); diff --git a/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator.hpp b/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator.hpp index e95621a9..346c5e66 100644 --- a/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator.hpp +++ b/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator.hpp @@ -57,25 +57,25 @@ class IncoreReplicatedXCDeviceIntegrator : value_type* VXCx, int64_t ldvxcx, value_type* EXC, const IntegratorSettingsXC& settings ) override; - void neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, - const value_type* P1s, int64_t ldp1s, - const value_type* P2s, int64_t ldp2s, - const value_type* P2z, int64_t ldp2z, - value_type* VXC1s, int64_t ldvxc1s, - value_type* VXC2s, int64_t ldvxc2s, - value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC1, value_type* EXC2, const IntegratorSettingsXC& settings ) override; - - void neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, - const value_type* P1s, int64_t ldp1s, - const value_type* P1z, int64_t ldp1z, - const value_type* P2s, int64_t ldp2s, - const value_type* P2z, int64_t ldp2z, - value_type* VXC1s, int64_t ldvxc1s, - value_type* VXC1z, int64_t ldvxc1z, - value_type* VXC2s, int64_t ldvxc2s, - value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC1, value_type* EXC2, const IntegratorSettingsXC& settings ) override; + void neo_eval_exc_vxc_( int64_t elec_m, int64_t elec_n, int64_t prot_m, int64_t prot_n, + const value_type* elec_Ps, int64_t elec_ldps, + const value_type* prot_Ps, int64_t prot_ldps, + const value_type* prot_Pz, int64_t prot_ldpz, + value_type* elec_VXCs, int64_t elec_ldvxcs, + value_type* prot_VXCs, int64_t prot_ldvxcs, + value_type* prot_VXCz, int64_t prot_ldvxcz, + value_type* elec_EXC, value_type* prot_EXC, const IntegratorSettingsXC& settings ) override; + + void neo_eval_exc_vxc_( int64_t elec_m, int64_t elec_n, int64_t prot_m, int64_t prot_n, + const value_type* elec_Ps, int64_t elec_ldps, + const value_type* elec_Pz, int64_t elec_ldpz, + const value_type* prot_Ps, int64_t prot_ldps, + const value_type* prot_Pz, int64_t prot_ldpz, + value_type* elec_VXCs, int64_t elec_ldvxcs, + value_type* elec_VXCz, int64_t elec_ldvxcz, + value_type* prot_VXCs, int64_t prot_ldvxcs, + value_type* prot_VXCz, int64_t prot_ldvxcz, + value_type* elec_EXC, value_type* prot_EXC, const IntegratorSettingsXC& settings ) override; void eval_exc_grad_( int64_t m, int64_t n, const value_type* P, int64_t ldp, value_type* EXC_GRAD ) override; diff --git a/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator_exc_vxc.hpp b/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator_exc_vxc.hpp index c1e34f2b..d5f624c4 100644 --- a/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator_exc_vxc.hpp +++ b/src/xc_integrator/replicated/device/incore_replicated_xc_device_integrator_exc_vxc.hpp @@ -141,32 +141,33 @@ void IncoreReplicatedXCDeviceIntegrator:: template void IncoreReplicatedXCDeviceIntegrator:: - neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, - const value_type* P1s, int64_t ldp1s, - const value_type* P2s, int64_t ldp2s, - const value_type* P2z, int64_t ldp2z, - value_type* VXC1s, int64_t ldvxc1s, - value_type* VXC2s, int64_t ldvxc2s, - value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC1, value_type* EXC2, const IntegratorSettingsXC& settings ) { - GauXC::util::unused(m1,n1,m2,n2,P1s,ldp1s,P2s,ldp2s,P2z,ldp2z,VXC1s,ldvxc1s,VXC2s,ldvxc2s,VXC2z,ldvxc2z,EXC1,EXC2,settings); + neo_eval_exc_vxc_( int64_t elec_m, int64_t elec_n, int64_t prot_m, int64_t prot_n, + const value_type* elec_Ps, int64_t elec_ldps, + const value_type* prot_Ps, int64_t prot_ldps, + const value_type* prot_Pz, int64_t prot_ldpz, + value_type* elec_VXCs, int64_t elec_ldvxcs, + value_type* prot_VXCs, int64_t prot_ldvxcs, + value_type* prot_VXCz, int64_t prot_ldvxcz, + value_type* elec_EXC, value_type* prot_EXC, const IntegratorSettingsXC& settings ) { + GauXC::util::unused(elec_m,elec_n,prot_m,prot_n,elec_Ps,elec_ldps,prot_Ps,prot_ldps,prot_Pz,prot_ldpz, + elec_VXCs,elec_ldvxcs,prot_VXCs,prot_ldvxcs,prot_VXCz,prot_ldvxcz,elec_EXC,prot_EXC,settings); GAUXC_GENERIC_EXCEPTION("NEO-RKS NOT YET IMPLEMENTED FOR DEVICE"); } template void IncoreReplicatedXCDeviceIntegrator:: - neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, - const value_type* P1s, int64_t ldp1s, - const value_type* P1z, int64_t ldp1z, - const value_type* P2s, int64_t ldp2s, - const value_type* P2z, int64_t ldp2z, - value_type* VXC1s, int64_t ldvxc1s, - value_type* VXC1z, int64_t ldvxc1z, - value_type* VXC2s, int64_t ldvxc2s, - value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC1, value_type* EXC2, const IntegratorSettingsXC& settings ) { - - GauXC::util::unused(m1,n1,m2,n2,P1s,ldp1s,P1z,ldp1z,P2s,ldp2s,P2z,ldp2z,VXC1s,ldvxc1s,VXC1z,ldvxc1z,VXC2s,ldvxc2s,VXC2z,ldvxc2z,EXC1,EXC2,settings); + neo_eval_exc_vxc_( int64_t elec_m, int64_t elec_n, int64_t prot_m, int64_t prot_n, + const value_type* elec_Ps, int64_t elec_ldps, + const value_type* elec_Pz, int64_t elec_ldpz, + const value_type* prot_Ps, int64_t prot_ldps, + const value_type* prot_Pz, int64_t prot_ldpz, + value_type* elec_VXCs, int64_t elec_ldvxcs, + value_type* elec_VXCz, int64_t elec_ldvxcz, + value_type* prot_VXCs, int64_t prot_ldvxcs, + value_type* prot_VXCz, int64_t prot_ldvxcz, + value_type* elec_EXC, value_type* prot_EXC, const IntegratorSettingsXC& settings ) { + GauXC::util::unused(elec_m,elec_n,prot_m,prot_n,elec_Ps,elec_ldps,elec_Pz,elec_ldpz,prot_Ps,prot_ldps,prot_Pz,prot_ldpz, + elec_VXCs,elec_ldvxcs,elec_VXCz,elec_ldvxcz,prot_VXCs,prot_ldvxcs,prot_VXCz,prot_ldvxcz,elec_EXC,prot_EXC,settings); GAUXC_GENERIC_EXCEPTION("NEO-UKS NOT YET IMPLEMENTED FOR DEVICE"); } diff --git a/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator.hpp b/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator.hpp index 430e084d..1263f215 100644 --- a/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator.hpp +++ b/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator.hpp @@ -68,25 +68,25 @@ class ShellBatchedReplicatedXCDeviceIntegrator : value_type* VXCx, int64_t ldvxcx, value_type* EXC, const IntegratorSettingsXC& settings ) override; - void neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, - const value_type* P1s, int64_t ldp1s, - const value_type* P2s, int64_t ldp2s, - const value_type* P2z, int64_t ldp2z, - value_type* VXC1s, int64_t ldvxc1s, - value_type* VXC2s, int64_t ldvxc2s, - value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC1, value_type* EXC2 ) override; - - void neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, - const value_type* P1s, int64_t ldp1s, - const value_type* P1z, int64_t ldp1z, - const value_type* P2s, int64_t ldp2s, - const value_type* P2z, int64_t ldp2z, - value_type* VXC1s, int64_t ldvxc1s, - value_type* VXC1z, int64_t ldvxc1z, - value_type* VXC2s, int64_t ldvxc2s, - value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC1, value_type* EXC2 ) override; + void neo_eval_exc_vxc_( int64_t elec_m, int64_t elec_n, int64_t prot_m, int64_t prot_n, + const value_type* elec_Ps, int64_t elec_ldps, + const value_type* prot_Ps, int64_t prot_ldps, + const value_type* prot_Pz, int64_t prot_ldpz, + value_type* elec_VXCs, int64_t elec_ldvxcs, + value_type* prot_VXCs, int64_t prot_ldvxcs, + value_type* prot_VXCz, int64_t prot_ldvxcz, + value_type* elec_EXC, value_type* prot_EXC, const IntegratorSettingsXC& settings ) override; + + void neo_eval_exc_vxc_( int64_t elec_m, int64_t elec_n, int64_t prot_m, int64_t prot_n, + const value_type* elec_Ps, int64_t elec_ldps, + const value_type* elec_Pz, int64_t elec_ldpz, + const value_type* prot_Ps, int64_t prot_ldps, + const value_type* prot_Pz, int64_t prot_ldpz, + value_type* elec_VXCs, int64_t elec_ldvxcs, + value_type* elec_VXCz, int64_t elec_ldvxcz, + value_type* prot_VXCs, int64_t prot_ldvxcs, + value_type* prot_VXCz, int64_t prot_ldvxcz, + value_type* elec_EXC, value_type* prot_EXC, const IntegratorSettingsXC& settings ) override; void eval_exc_grad_( int64_t m, int64_t n, const value_type* P, int64_t ldp, value_type* EXC_GRAD ) override; diff --git a/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator_exc_vxc.hpp b/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator_exc_vxc.hpp index 8814c823..ae01f9c7 100644 --- a/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator_exc_vxc.hpp +++ b/src/xc_integrator/replicated/device/shellbatched_replicated_xc_device_integrator_exc_vxc.hpp @@ -122,34 +122,36 @@ void ShellBatchedReplicatedXCDeviceIntegrator:: template void ShellBatchedReplicatedXCDeviceIntegrator:: - neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, - const value_type* P1s, int64_t ldp1s, - const value_type* P2s, int64_t ldp2s, - const value_type* P2z, int64_t ldp2z, - value_type* VXC1s, int64_t ldvxc1s, - value_type* VXC2s, int64_t ldvxc2s, - value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC1, value_type* EXC2 ) { - - GauXC::util::unused(m1,n1,m2,n2,P1s,ldp1s,P2s,ldp2s,P2z,ldp2z,VXC1s,ldvxc1s,VXC2s,ldvxc2s,VXC2z,ldvxc2z,EXC); + neo_eval_exc_vxc_( int64_t elec_m, int64_t elec_n, int64_t prot_m, int64_t prot_n, + const value_type* elec_Ps, int64_t elec_ldps, + const value_type* prot_Ps, int64_t prot_ldps, + const value_type* prot_Pz, int64_t prot_ldpz, + value_type* elec_VXCs, int64_t elec_ldvxcs, + value_type* prot_VXCs, int64_t prot_ldvxcs, + value_type* prot_VXCz, int64_t prot_ldvxcz, + value_type* elec_EXC, value_type* prot_EXC, const IntegratorSettingsXC& settings ) { + + GauXC::util::unused(elec_m,elec_n,prot_m,prot_n,elec_Ps,elec_ldps,prot_Ps,prot_ldps,prot_Pz,prot_ldpz, + elec_VXCs,elec_ldvxcs,prot_VXCs,prot_ldvxcs,prot_VXCz,prot_ldvxcz,elec_EXC,prot_EXC,settings); GAUXC_GENERIC_EXCEPTION("NEO RKS NOT YET IMPLEMENTED FOR DEVICE"); } template void ShellBatchedReplicatedXCDeviceIntegrator:: - neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, - const value_type* P1s, int64_t ldp1s, - const value_type* P1z, int64_t ldp1z, - const value_type* P2s, int64_t ldp2s, - const value_type* P2z, int64_t ldp2z, - value_type* VXC1s, int64_t ldvxc1s, - value_type* VXC1z, int64_t ldvxc1z, - value_type* VXC2s, int64_t ldvxc2s, - value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC1, value_type* EXC2 ) { - - GauXC::util::unused(m1,n1,m2,n2,P1s,ldp1s,P1z,ldp1z,P2s,ldp2s,P2z,ldp2z,VXC1s,ldvxc1s,VXC1z,ldvxc1z,VXC2s,ldvxc2s,VXC2z,ldvxc2z,EXC); - GAUXC_GENERIC_EXCEPTION("NEO UKS NOT YET IMPLEMENTED FOR DEVICE"); + neo_eval_exc_vxc_( int64_t elec_m, int64_t elec_n, int64_t prot_m, int64_t prot_n, + const value_type* elec_Ps, int64_t elec_ldps, + const value_type* elec_Pz, int64_t elec_ldpz, + const value_type* prot_Ps, int64_t prot_ldps, + const value_type* prot_Pz, int64_t prot_ldpz, + value_type* elec_VXCs, int64_t elec_ldvxcs, + value_type* elec_VXCz, int64_t elec_ldvxcz, + value_type* prot_VXCs, int64_t prot_ldvxcs, + value_type* prot_VXCz, int64_t prot_ldvxcz, + value_type* elec_EXC, value_type* prot_EXC, const IntegratorSettingsXC& settings ) { + + GauXC::util::unused(elec_m,elec_n,prot_m,prot_n,elec_Ps,elec_ldps,elec_Pz,elec_ldpz,prot_Ps,prot_ldps,prot_Pz,prot_ldpz, + elec_VXCs,elec_ldvxcs,elec_VXCz,elec_ldvxcz,prot_VXCs,prot_ldvxcs,prot_VXCz,prot_ldvxcz,elec_EXC,prot_EXC,settings); + GAUXC_GENERIC_EXCEPTION("NEO RKS NOT YET IMPLEMENTED FOR DEVICE"); } template diff --git a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator.hpp b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator.hpp index 396bb1d7..4baedafe 100644 --- a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator.hpp +++ b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator.hpp @@ -56,24 +56,24 @@ class ReferenceReplicatedXCHostIntegrator : void neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, - const value_type* P1s, int64_t ldp1s, - const value_type* P2s, int64_t ldp2s, - const value_type* P2z, int64_t ldp2z, - value_type* VXC1s, int64_t ldvxc1s, - value_type* VXC2s, int64_t ldvxc2s, - value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC1, value_type* EXC2, const IntegratorSettingsXC& ks_settings ) override; + const value_type* Ps, int64_t ldps, + const value_type* prot_Ps, int64_t prot_ldps, + const value_type* prot_Pz, int64_t prot_ldpz, + value_type* VXCs, int64_t ldvxcs, + value_type* prot_VXCs, int64_t prot_ldvxcs, + value_type* prot_VXCz, int64_t prot_ldvxcz, + value_type* EXC1, value_type* prot_EXC, const IntegratorSettingsXC& ks_settings ) override; void neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, - const value_type* P1s, int64_t ldp1s, - const value_type* P1z, int64_t ldp1z, - const value_type* P2s, int64_t ldp2s, - const value_type* P2z, int64_t ldp2z, - value_type* VXC1s, int64_t ldvxc1s, - value_type* VXC1z, int64_t ldvxc1z, - value_type* VXC2s, int64_t ldvxc2s, - value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC1, value_type* EXC2, const IntegratorSettingsXC& ks_settings ) override; + const value_type* Ps, int64_t ldps, + const value_type* Pz, int64_t ldpz, + const value_type* prot_Ps, int64_t prot_ldps, + const value_type* prot_Pz, int64_t prot_ldpz, + value_type* VXCs, int64_t ldvxcs, + value_type* VXCz, int64_t ldvxcz, + value_type* prot_VXCs, int64_t prot_ldvxcs, + value_type* prot_VXCz, int64_t prot_ldvxcz, + value_type* EXC1, value_type* prot_EXC, const IntegratorSettingsXC& ks_settings ) override; void eval_exc_grad_( int64_t m, int64_t n, const value_type* P, int64_t ldp, value_type* EXC_GRAD ) override; @@ -103,15 +103,15 @@ class ReferenceReplicatedXCHostIntegrator : value_type* EXC, value_type *N_EL, const IntegratorSettingsXC& ks_settings ); - void neo_exc_vxc_local_work_( const value_type* P1s, int64_t ldp1s, - const value_type* P1z, int64_t ldp1z, - const value_type* P2s, int64_t ldp2s, - const value_type* P2z, int64_t ldp2z, - value_type* VXC1s, int64_t ldvxc1s, - value_type* VXC1z, int64_t ldvxc1z, - value_type* VXC2s, int64_t ldvxc2s, - value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC1, value_type* EXC2, value_type *N_EL, + void neo_exc_vxc_local_work_( const value_type* Ps, int64_t ldps, + const value_type* Pz, int64_t ldpz, + const value_type* prot_Ps, int64_t prot_ldps, + const value_type* prot_Pz, int64_t prot_ldpz, + value_type* VXCs, int64_t ldvxcs, + value_type* VXCz, int64_t ldvxcz, + value_type* prot_VXCs, int64_t prot_ldvxcs, + value_type* prot_VXCz, int64_t prot_ldvxcz, + value_type* EXC1, value_type* prot_EXC, value_type *N_EL, const IntegratorSettingsXC& ks_settings ); void exc_grad_local_work_( const value_type* P, int64_t ldp, value_type* EXC_GRAD ); diff --git a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp index 104e8069..0509118a 100644 --- a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp +++ b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp @@ -18,29 +18,29 @@ namespace detail { template void ReferenceReplicatedXCHostIntegrator:: - neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, - const value_type* P1s, int64_t ldp1s, - const value_type* P2s, int64_t ldp2s, - const value_type* P2z, int64_t ldp2z, - value_type* VXC1s, int64_t ldvxc1s, - value_type* VXC2s, int64_t ldvxc2s, - value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC1, value_type* EXC2, const IntegratorSettingsXC& ks_settings ){ + neo_eval_exc_vxc_( int64_t elec_m, int64_t elec_n, int64_t prot_m, int64_t prot_n, + const value_type* elec_Ps, int64_t elec_ldps, + const value_type* prot_Ps, int64_t prot_ldps, + const value_type* prot_Pz, int64_t prot_ldpz, + value_type* elec_VXCs, int64_t elec_ldvxcs, + value_type* prot_VXCs, int64_t prot_ldvxcs, + value_type* prot_VXCz, int64_t prot_ldvxcz, + value_type* elec_EXC, value_type* prot_EXC, const IntegratorSettingsXC& settings){ - const auto& basis = this->load_balancer_->basis(); - const auto& basis2 = this->load_balancer_->basis2(); + const auto& elec_basis = this->load_balancer_->basis(); + const auto& prot_basis = this->load_balancer_->protonic_basis(); // Check that P / VXC are sane - const int64_t nbf1 = basis.nbf(); - const int64_t nbf2 = basis2.nbf(); + const int64_t elec_nbf = elec_basis.nbf(); + const int64_t prot_nbf = prot_basis.nbf(); - if( m1 != n1 | m2 != n2) + if( elec_m != elec_n | prot_m != prot_n) GAUXC_GENERIC_EXCEPTION("P/VXC Must Be Square"); - if( m1 != nbf1 | m2 != nbf2) + if( elec_m != elec_nbf | prot_m != prot_nbf) GAUXC_GENERIC_EXCEPTION("P/VXC Must Have Same Dimension as Basis"); - if( ldp1s < nbf1 | ldp2s < nbf2 | ldp2z < nbf2 ) + if( elec_ldps < elec_nbf | prot_ldps < prot_nbf | prot_ldpz < prot_nbf ) GAUXC_GENERIC_EXCEPTION("Invalid LDP"); - if( ldvxc1s < nbf1 | ldvxc2s < nbf2 | ldvxc2z < nbf2 ) + if( elec_ldvxcs < elec_nbf | prot_ldvxcs < prot_nbf | prot_ldvxcz < prot_nbf ) GAUXC_GENERIC_EXCEPTION("Invalid LDVXC"); // Get Tasks @@ -51,15 +51,15 @@ void ReferenceReplicatedXCHostIntegrator:: // Compute Local contributions to EXC / VXC this->timer_.time_op("XCIntegrator.LocalWork", [&](){ - neo_exc_vxc_local_work_( P1s, ldp1s, - nullptr, 0, - P2s, ldp2s, - P2z, ldp2z, - VXC1s, ldvxc1s, + neo_exc_vxc_local_work_( elec_Ps, elec_ldps, nullptr, 0, - VXC2s, ldvxc2s, - VXC2z, ldvxc2z, - EXC1, EXC2, &N_EL, ks_settings ); + prot_Ps, prot_ldps, + prot_Pz, prot_ldpz, + elec_VXCs, elec_ldvxcs, + nullptr, 0, + prot_VXCs, prot_ldvxcs, + prot_VXCz, prot_ldvxcz, + elec_EXC, prot_EXC, &N_EL, settings ); }); @@ -69,12 +69,12 @@ void ReferenceReplicatedXCHostIntegrator:: if( not this->reduction_driver_->takes_host_memory() ) GAUXC_GENERIC_EXCEPTION("This Module Only Works With Host Reductions"); - this->reduction_driver_->allreduce_inplace( VXC1s, nbf1*nbf1, ReductionOp::Sum ); - this->reduction_driver_->allreduce_inplace( VXC2s, nbf2*nbf1, ReductionOp::Sum ); - this->reduction_driver_->allreduce_inplace( VXC2z, nbf2*nbf2, ReductionOp::Sum ); - this->reduction_driver_->allreduce_inplace( EXC1, 1 , ReductionOp::Sum ); - this->reduction_driver_->allreduce_inplace( EXC2, 1 , ReductionOp::Sum ); - this->reduction_driver_->allreduce_inplace( &N_EL, 1 , ReductionOp::Sum ); + this->reduction_driver_->allreduce_inplace( elec_VXCs, elec_nbf*elec_nbf, ReductionOp::Sum ); + this->reduction_driver_->allreduce_inplace( prot_VXCs, prot_nbf*prot_nbf, ReductionOp::Sum ); + this->reduction_driver_->allreduce_inplace( prot_VXCz, prot_nbf*prot_nbf, ReductionOp::Sum ); + this->reduction_driver_->allreduce_inplace( elec_EXC, 1, ReductionOp::Sum ); + this->reduction_driver_->allreduce_inplace( prot_EXC, 1, ReductionOp::Sum ); + this->reduction_driver_->allreduce_inplace( &N_EL, 1, ReductionOp::Sum ); }); @@ -82,32 +82,31 @@ void ReferenceReplicatedXCHostIntegrator:: template void ReferenceReplicatedXCHostIntegrator:: - neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, - const value_type* P1s, int64_t ldp1s, - const value_type* P1z, int64_t ldp1z, - const value_type* P2s, int64_t ldp2s, - const value_type* P2z, int64_t ldp2z, - value_type* VXC1s, int64_t ldvxc1s, - value_type* VXC1z, int64_t ldvxc1z, - value_type* VXC2s, int64_t ldvxc2s, - value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC1, value_type* EXC2, - const IntegratorSettingsXC& ks_settings ) { + neo_eval_exc_vxc_( int64_t elec_m, int64_t elec_n, int64_t prot_m, int64_t prot_n, + const value_type* elec_Ps, int64_t elec_ldps, + const value_type* elec_Pz, int64_t elec_ldpz, + const value_type* prot_Ps, int64_t prot_ldps, + const value_type* prot_Pz, int64_t prot_ldpz, + value_type* elec_VXCs, int64_t elec_ldvxcs, + value_type* elec_VXCz, int64_t elec_ldvxcz, + value_type* prot_VXCs, int64_t prot_ldvxcs, + value_type* prot_VXCz, int64_t prot_ldvxcz, + value_type* elec_EXC, value_type* prot_EXC, const IntegratorSettingsXC& settings ){ - const auto& basis = this->load_balancer_->basis(); - const auto& basis2 = this->load_balancer_->basis2(); + const auto& elec_basis = this->load_balancer_->basis(); + const auto& prot_basis = this->load_balancer_->protonic_basis(); // Check that P / VXC are sane - const int64_t nbf1 = basis.nbf(); - const int64_t nbf2 = basis2.nbf(); + const int64_t elec_nbf = elec_basis.nbf(); + const int64_t prot_nbf = prot_basis.nbf(); - if( m1 != n1 | m2 != n2) + if( elec_m != elec_n | prot_m != prot_n) GAUXC_GENERIC_EXCEPTION("P/VXC Must Be Square"); - if( m1 != nbf1 | m2 != nbf2) + if( elec_m != elec_nbf | prot_m != prot_nbf) GAUXC_GENERIC_EXCEPTION("P/VXC Must Have Same Dimension as Basis"); - if( ldp1s < nbf1 | ldp2s < nbf2 | ldp2z < nbf2 ) + if( elec_ldps < elec_nbf | elec_ldpz < elec_nbf | prot_ldps < prot_nbf | prot_ldpz < prot_nbf ) GAUXC_GENERIC_EXCEPTION("Invalid LDP"); - if( ldvxc1s < nbf1 | ldvxc2s < nbf2 | ldvxc2z < nbf2 ) + if( elec_ldvxcs < elec_nbf | elec_ldvxcz < elec_nbf | prot_ldvxcs < prot_nbf | prot_ldvxcz < prot_nbf ) GAUXC_GENERIC_EXCEPTION("Invalid LDVXC"); // Get Tasks @@ -118,15 +117,15 @@ void ReferenceReplicatedXCHostIntegrator:: // Compute Local contributions to EXC / VXC this->timer_.time_op("XCIntegrator.LocalWork", [&](){ - neo_exc_vxc_local_work_( P1s, ldp1s, - P1z, ldp1z, - P2s, ldp2s, - P2z, ldp2z, - VXC1s, ldvxc1s, - VXC1z, ldvxc1z, - VXC2s, ldvxc2s, - VXC2z, ldvxc2z, - EXC1, EXC2, &N_EL, ks_settings); + neo_exc_vxc_local_work_( elec_Ps, elec_ldps, + elec_Pz, elec_ldpz, + prot_Ps, prot_ldps, + prot_Pz, prot_ldpz, + elec_VXCs, elec_ldvxcs, + elec_VXCz, elec_ldvxcz, + prot_VXCs, prot_ldvxcs, + prot_VXCz, prot_ldvxcz, + elec_EXC, prot_EXC, &N_EL, settings ); }); @@ -136,13 +135,13 @@ void ReferenceReplicatedXCHostIntegrator:: if( not this->reduction_driver_->takes_host_memory() ) GAUXC_GENERIC_EXCEPTION("This Module Only Works With Host Reductions"); - this->reduction_driver_->allreduce_inplace( VXC1s, nbf1*nbf1, ReductionOp::Sum ); - this->reduction_driver_->allreduce_inplace( VXC1z, nbf1*nbf1, ReductionOp::Sum ); - this->reduction_driver_->allreduce_inplace( VXC2s, nbf2*nbf1, ReductionOp::Sum ); - this->reduction_driver_->allreduce_inplace( VXC2z, nbf2*nbf2, ReductionOp::Sum ); - this->reduction_driver_->allreduce_inplace( EXC1, 1 , ReductionOp::Sum ); - this->reduction_driver_->allreduce_inplace( EXC2, 1 , ReductionOp::Sum ); - this->reduction_driver_->allreduce_inplace( &N_EL, 1 , ReductionOp::Sum ); + this->reduction_driver_->allreduce_inplace( elec_VXCs, elec_nbf*elec_nbf, ReductionOp::Sum ); + this->reduction_driver_->allreduce_inplace( elec_VXCz, elec_nbf*elec_nbf, ReductionOp::Sum ); + this->reduction_driver_->allreduce_inplace( prot_VXCs, prot_nbf*prot_nbf, ReductionOp::Sum ); + this->reduction_driver_->allreduce_inplace( prot_VXCz, prot_nbf*prot_nbf, ReductionOp::Sum ); + this->reduction_driver_->allreduce_inplace( elec_EXC, 1, ReductionOp::Sum ); + this->reduction_driver_->allreduce_inplace( prot_EXC, 1, ReductionOp::Sum ); + this->reduction_driver_->allreduce_inplace( &N_EL, 1, ReductionOp::Sum ); }); @@ -151,20 +150,20 @@ void ReferenceReplicatedXCHostIntegrator:: template void ReferenceReplicatedXCHostIntegrator:: - neo_exc_vxc_local_work_( const value_type* P1s, int64_t ldp1s, - const value_type* P1z, int64_t ldp1z, - const value_type* P2s, int64_t ldp2s, - const value_type* P2z, int64_t ldp2z, - value_type* VXC1s, int64_t ldvxc1s, - value_type* VXC1z, int64_t ldvxc1z, - value_type* VXC2s, int64_t ldvxc2s, - value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC1, value_type* EXC2, value_type *N_EL, + neo_exc_vxc_local_work_( const value_type* elec_Ps, int64_t elec_ldps, + const value_type* elec_Pz, int64_t elec_ldpz, + const value_type* prot_Ps, int64_t prot_ldps, + const value_type* prot_Pz, int64_t prot_ldpz, + value_type* elec_VXCs, int64_t elec_ldvxcs, + value_type* elec_VXCz, int64_t elec_ldvxcz, + value_type* prot_VXCs, int64_t prot_ldvxcs, + value_type* prot_VXCz, int64_t prot_ldvxcz, + value_type* elec_EXC, value_type* prot_EXC, value_type *N_EL, const IntegratorSettingsXC& ks_settings ) { // Determine is electronic subsystem is RKS or UKS - const bool is_uks = (P1z != nullptr) and (VXC1z != nullptr); + const bool is_uks = (elec_Pz != nullptr) and (elec_VXCz != nullptr); const bool is_rks = not is_uks; // TODO: GKS // Cast LWD to LocalHostWorkDriver @@ -181,9 +180,9 @@ void ReferenceReplicatedXCHostIntegrator:: const int32_t nbf = basis.nbf(); // Get Protonic basis information - const auto& basis2 = this->load_balancer_->basis2(); - BasisSetMap basis_map2(basis2,mol); - const int32_t nbf2 = basis2.nbf(); + const auto& protonic_basis = this->load_balancer_->protonic_basis(); + BasisSetMap protonic_basis_map(protonic_basis,mol); + const int32_t protonic_nbf = protonic_basis.nbf(); // Sort tasks on size (XXX: maybe doesnt matter?) auto task_comparator = []( const XCTask& a, const XCTask& b ) { @@ -201,14 +200,14 @@ void ReferenceReplicatedXCHostIntegrator:: // Zero out integrands - std::fill(VXC1s, VXC1s + nbf * ldvxc1s, 0.0); - if(is_uks) std::fill(VXC1z, VXC1z + nbf * ldvxc1z, 0.0); + std::fill(elec_VXCs, elec_VXCs + nbf * elec_ldvxcs, 0.0); + if(is_uks) std::fill(elec_VXCz, elec_VXCz + nbf * elec_ldvxcz, 0.0); - std::fill(VXC2s, VXC2s + nbf2 * ldvxc2s, 0.0); - std::fill(VXC2z, VXC2z + nbf2 * ldvxc2z, 0.0); + std::fill(prot_VXCs, prot_VXCs + protonic_nbf * prot_ldvxcs, 0.0); + std::fill(prot_VXCz, prot_VXCz + protonic_nbf * prot_ldvxcz, 0.0); - *EXC1 = 0.; - *EXC2 = 0.; + *elec_EXC = 0.; + *prot_EXC = 0.; // Loop over tasks @@ -228,17 +227,19 @@ void ReferenceReplicatedXCHostIntegrator:: // Get tasks constants const int32_t npts = task.points.size(); - const int32_t nbe = task.bfn_screening.nbe; - const int32_t nshells = task.bfn_screening.shell_list.size(); + const int32_t nbe = task.bfn_screening.nbe; + const int32_t nshells = task.bfn_screening.shell_list.size(); - const auto* points = task.points.data()->data(); - const auto* weights = task.weights.data(); + const auto* points = task.points.data()->data(); + const auto* weights = task.weights.data(); const int32_t* shell_list = task.bfn_screening.shell_list.data(); - const int32_t nbe2 = task.bfn2_screening.nbe; - const int32_t nshells2 = task.bfn2_screening.shell_list.size(); - const int32_t* shell_list2 = task.bfn2_screening.shell_list.data(); - bool evalProtonic = (nshells2 != 0); + const int32_t protonic_nbe = task.protonic_bfn_screening.nbe; + const int32_t protonic_nshells = task.protonic_bfn_screening.shell_list.size(); + const int32_t* protonic_shell_list = task.protonic_bfn_screening.shell_list.data(); + + // Check if there's protonic shells to evaluate. If not, only electronic EXC/VXC will be calculated + bool evalProtonic = (protonic_nshells != 0); // Allocate enough memory for batch @@ -248,7 +249,7 @@ void ReferenceReplicatedXCHostIntegrator:: // Use same scratch for both electronic and protonic - const int32_t scr_dim = std::max(nbe, nbe2); + const int32_t scr_dim = std::max(nbe, protonic_nbe); host_data.nbe_scr .resize(scr_dim * scr_dim); //----------------------Start Electronic System Setup------------------------ @@ -307,27 +308,27 @@ void ReferenceReplicatedXCHostIntegrator:: //----------------------Start Protonic System Setup------------------------ // Set Up Memory (assuming UKS) - host_data.zmat2 .resize( npts * nbe2 * 2 ); - host_data.eps2 .resize( npts ); - host_data.vrho2 .resize( npts * 2 ); + host_data.protonic_zmat .resize( npts * protonic_nbe * 2 ); + host_data.protonic_eps .resize( npts ); + host_data.protonic_vrho .resize( npts * 2 ); // LDA - host_data.basis2_eval .resize( npts * nbe2 ); - host_data.den2_scr .resize( npts * 2); + host_data.protonic_basis_eval .resize( npts * protonic_nbe ); + host_data.protonic_den_scr .resize( npts * 2); // Alias/Partition out scratch memory - auto* basis2_eval = host_data.basis2_eval.data(); - auto* den2_eval = host_data.den2_scr.data(); - auto* zmat2 = host_data.zmat2.data(); - decltype(zmat2) zmat2_z = zmat2 + nbe2 * npts; + auto* protonic_basis_eval = host_data.protonic_basis_eval.data(); + auto* protonic_den_eval = host_data.protonic_den_scr.data(); + auto* protonic_zmat = host_data.protonic_zmat.data(); + decltype(protonic_zmat) protonic_zmat_z = protonic_zmat + protonic_nbe * npts; - auto* eps2 = host_data.eps2.data(); - auto* vrho2 = host_data.vrho2.data(); + auto* protonic_eps = host_data.protonic_eps.data(); + auto* protonic_vrho = host_data.protonic_vrho.data(); // No GGA for NEO yet //----------------------End Protonic System Setup------------------------ //std::cout << "Task: " << iT << "/" << ntasks << std::endl; //std::cout << "Electronic nbe: " << nbe << std::endl; - //std::cout << "Protonic nbe: " << nbe2 << std::endl; + //std::cout << "Protonic nbe: " << protonic_nbe << std::endl; //----------------------Start Calculating Electronic Density & UV Variable------------------------ // Get the submatrix map for batch @@ -345,12 +346,12 @@ void ReferenceReplicatedXCHostIntegrator:: // Evaluate X matrix (fac * P * B) -> store in Z const auto xmat_fac = is_rks ? 2.0 : 1.0; // TODO Fix for spinor RKS input - lwd->eval_xmat( npts, nbf, nbe, submat_map, xmat_fac, P1s, ldp1s, basis_eval, nbe, + lwd->eval_xmat( npts, nbf, nbe, submat_map, xmat_fac, elec_Ps, elec_ldps, basis_eval, nbe, zmat, nbe, nbe_scr ); // X matrix for Pz if(not is_rks) { - lwd->eval_xmat( npts, nbf, nbe, submat_map, 1.0, P1z, ldp1z, basis_eval, nbe, + lwd->eval_xmat( npts, nbf, nbe, submat_map, 1.0, elec_Pz, elec_ldpz, basis_eval, nbe, zmat_z, nbe, nbe_scr ); } @@ -385,31 +386,29 @@ void ReferenceReplicatedXCHostIntegrator:: //----------------------Start Calculating Protonic Density & UV Variable------------------------ - std::vector< std::array > submat_map2; + std::vector< std::array > protonic_submat_map; if(evalProtonic){ - //std::tie(submat_map2, std::ignore) = - // gen_compressed_submat_map(basis_map2, shell_list2_vector, nbf2, nbf2); - std::tie(submat_map2, std::ignore) = - gen_compressed_submat_map(basis_map2, task.bfn2_screening.shell_list, nbf2, nbf2); + std::tie(protonic_submat_map, std::ignore) = + gen_compressed_submat_map(protonic_basis_map, task.protonic_bfn_screening.shell_list, protonic_nbf, protonic_nbf); // Evaluate Collocation - lwd->eval_collocation( npts, nshells2, nbe2, points, basis2, shell_list2, - basis2_eval ); + lwd->eval_collocation( npts, protonic_nshells, protonic_nbe, points, protonic_basis, protonic_shell_list, + protonic_basis_eval ); // Evaluate X matrix (P * B) -> store in Z // NEED THE FACTOR OF 2 HERE! - lwd->eval_xmat( npts, nbf2, nbe2, submat_map2, 2.0, P2s, ldp2s, basis2_eval, nbe2, - zmat2, nbe2, nbe_scr ); - lwd->eval_xmat( npts, nbf2, nbe2, submat_map2, 2.0, P2z, ldp2z, basis2_eval, nbe2, - zmat2_z, nbe2, nbe_scr ); + lwd->eval_xmat( npts, protonic_nbf, protonic_nbe, protonic_submat_map, 2.0, prot_Ps, prot_ldps, protonic_basis_eval, protonic_nbe, + protonic_zmat, protonic_nbe, nbe_scr ); + lwd->eval_xmat( npts, protonic_nbf, protonic_nbe, protonic_submat_map, 2.0, prot_Pz, prot_ldpz, protonic_basis_eval, protonic_nbe, + protonic_zmat_z, protonic_nbe, nbe_scr ); // Evaluate U and V variables - lwd->eval_uvvar_lda_uks( npts, nbe2, basis2_eval, zmat2, nbe2, zmat2_z, nbe2, - den2_eval ); + lwd->eval_uvvar_lda_uks( npts, protonic_nbe, protonic_basis_eval, protonic_zmat, protonic_nbe, protonic_zmat_z, + protonic_nbe, protonic_den_eval ); // No protonic XC functional. Fill with eps and vrho to be 0.0 - std::fill_n(eps2, npts, 0.); - std::fill_n(vrho2, npts*2, 0.); + std::fill_n(protonic_eps, npts, 0.); + std::fill_n(protonic_vrho, npts*2, 0.); } //----------------------End Calculating Protonic Density & UV Variable------------------------ @@ -423,14 +422,14 @@ void ReferenceReplicatedXCHostIntegrator:: const auto den = is_rks ? den_eval[iPt] : (den_eval[2*iPt] + den_eval[2*iPt+1]); value_type total_erho = std::abs(den) > 1e-15? den : 0; // Get Protonic density scalar (UKS) - const auto den2 = den2_eval[2*iPt] + den2_eval[2*iPt+1]; - value_type total_prho = std::abs(den2) > 1e-15? den2 : 0; + const auto protonic_den = protonic_den_eval[2*iPt] + protonic_den_eval[2*iPt+1]; + value_type total_prho = std::abs(protonic_den) > 1e-15? protonic_den : 0; // Skip this point if the density is too small if(total_erho < 1e-15 | total_prho < 1e-15){ - eps2[iPt] = 0.0; - vrho2[2*iPt] = 0.0; - vrho2[2*iPt+1] = 0.0; + protonic_eps[iPt] = 0.0; + protonic_vrho[2*iPt] = 0.0; + protonic_vrho[2*iPt+1] = 0.0; continue; } @@ -446,10 +445,10 @@ void ReferenceReplicatedXCHostIntegrator:: + 6.6 * total_erho * total_prho * total_prho ) / (dn * dn) ); // Assign protonic eps and vxc - eps2[iPt] = -1.0 * total_erho/dn; - vrho2[2*iPt] = ( -1.0 * total_erho / dn + (-1.2 * std::sqrt(total_prho) * std::sqrt(total_erho) * total_erho + protonic_eps[iPt] = -1.0 * total_erho/dn; + protonic_vrho[2*iPt] = ( -1.0 * total_erho / dn + (-1.2 * std::sqrt(total_prho) * std::sqrt(total_erho) * total_erho + 6.6 * total_erho * total_erho * total_prho ) / (dn * dn) ); - vrho2[2*iPt+1] = 0.0; + protonic_vrho[2*iPt+1] = 0.0; } // End looping over pts } // End if(evalProtonic) //----------------------End EPC functional Evaluation--------------------------------------- @@ -501,13 +500,14 @@ void ReferenceReplicatedXCHostIntegrator:: if(evalProtonic){ // Factor weights into XC results for( int32_t i = 0; i < npts; ++i ) { - eps2[i] *= weights[i]; - vrho2[2*i] *= weights[i]; - vrho2[2*i+1] *= weights[i]; + protonic_eps[i] *= weights[i]; + protonic_vrho[2*i] *= weights[i]; + protonic_vrho[2*i+1] *= weights[i]; } // Evaluate Z matrix for VXC - lwd->eval_zmat_lda_vxc_uks( npts, nbe2, vrho2, basis2_eval, zmat2, nbe2, zmat2_z, nbe2 ); + lwd->eval_zmat_lda_vxc_uks( npts, protonic_nbe, protonic_vrho, protonic_basis_eval, protonic_zmat, protonic_nbe, + protonic_zmat_z, protonic_nbe ); } //----------------------End Evaluating Protonic ZMat---------------------------- @@ -522,14 +522,14 @@ void ReferenceReplicatedXCHostIntegrator:: // Scalar integrations for( int32_t i = 0; i < npts; ++i ) { const auto den = is_rks ? den_eval[i] : (den_eval[2*i] + den_eval[2*i+1]); - *N_EL += weights[i] * den; - *EXC1 += eps[i] * den; + *N_EL += weights[i] * den; + *elec_EXC += eps[i] * den; } // Increment VXC - lwd->inc_vxc( npts, nbf, nbe, basis_eval, submat_map, zmat, nbe, VXC1s, ldvxc1s, + lwd->inc_vxc( npts, nbf, nbe, basis_eval, submat_map, zmat, nbe, elec_VXCs, elec_ldvxcs, nbe_scr ); if(not is_rks) - lwd->inc_vxc( npts, nbf, nbe, basis_eval, submat_map, zmat_z, nbe, VXC1z, ldvxc1z, + lwd->inc_vxc( npts, nbf, nbe, basis_eval, submat_map, zmat_z, nbe, elec_VXCz, elec_ldvxcz, nbe_scr ); @@ -537,17 +537,17 @@ void ReferenceReplicatedXCHostIntegrator:: // Scalar integrations if(evalProtonic){ for( int32_t i = 0; i < npts; ++i ) { - const auto den2 = den2_eval[2*i] + den2_eval[2*i+1]; - *EXC2 += eps2[i] * den2; + const auto protonic_den = protonic_den_eval[2*i] + protonic_den_eval[2*i+1]; + *prot_EXC += protonic_eps[i] * protonic_den; } // Increment VXC - lwd->inc_vxc( npts, nbf2, nbe2, basis2_eval, submat_map2, zmat2, nbe2, VXC2s, ldvxc2s, - nbe_scr ); - lwd->inc_vxc( npts, nbf2, nbe2, basis2_eval, submat_map2, zmat2_z, nbe2, VXC2z, ldvxc2z, - nbe_scr ); + lwd->inc_vxc( npts, protonic_nbf, protonic_nbe, protonic_basis_eval, protonic_submat_map, + protonic_zmat, protonic_nbe, prot_VXCs, prot_ldvxcs, nbe_scr ); + lwd->inc_vxc( npts, protonic_nbf, protonic_nbe, protonic_basis_eval, protonic_submat_map, + protonic_zmat_z, protonic_nbe, prot_VXCz, prot_ldvxcz, nbe_scr ); } - //std::cout << "Electronic EXC: " << *EXC1 << std::endl; - //std::cout << "Protonic EXC: " << *EXC2 << std::endl; + //std::cout << "Electronic EXC: " << *elec_EXC << std::endl; + //std::cout << "Protonic EXC: " << *prot_EXC << std::endl; } // End #pragma omp critical @@ -556,26 +556,26 @@ void ReferenceReplicatedXCHostIntegrator:: } // End OpenMP region //std::cout << "N_EL = " << std::setprecision(12) << std::scientific << *N_EL << std::endl; - //std::cout << "EXC1 = " << std::setprecision(12) << std::scientific << *EXC1 << std::endl - //std::cout << "EXC2 = " << std::setprecision(12) << std::scientific << *EXC2 << std::endl; + //std::cout << "elec_EXC = " << std::setprecision(12) << std::scientific << *elec_EXC << std::endl + //std::cout << "prot_EXC = " << std::setprecision(12) << std::scientific << *prot_EXC << std::endl; // Symmetrize Electronic VXC for( int32_t j = 0; j < nbf; ++j ) for( int32_t i = j+1; i < nbf; ++i ) - VXC1s[ j + i*ldvxc1s ] = VXC1s[ i + j*ldvxc1s ]; + elec_VXCs[ j + i*elec_ldvxcs ] = elec_VXCs[ i + j*elec_ldvxcs ]; if(not is_rks) { for( int32_t j = 0; j < nbf; ++j ) { for( int32_t i = j+1; i < nbf; ++i ) { - VXC1z[ j + i*ldvxc1z ] = VXC1z[ i + j*ldvxc1z ]; + elec_VXCz[ j + i*elec_ldvxcz ] = elec_VXCz[ i + j*elec_ldvxcz ]; } } } // Symmetrize Protonic VXC - for( int32_t j = 0; j < nbf2; ++j ){ - for( int32_t i = j+1; i < nbf2; ++i ){ - VXC2s[ j + i*ldvxc2s ] = VXC2s[ i + j*ldvxc2s ]; - VXC2z[ j + i*ldvxc2z ] = VXC2z[ i + j*ldvxc2z ]; + for( int32_t j = 0; j < protonic_nbf; ++j ){ + for( int32_t i = j+1; i < protonic_nbf; ++i ){ + prot_VXCs[ j + i*prot_ldvxcs ] = prot_VXCs[ i + j*prot_ldvxcs ]; + prot_VXCz[ j + i*prot_ldvxcz ] = prot_VXCz[ i + j*prot_ldvxcz ]; } } diff --git a/src/xc_integrator/replicated/host/xc_host_data.hpp b/src/xc_integrator/replicated/host/xc_host_data.hpp index 3d7b0c22..44cea1ec 100644 --- a/src/xc_integrator/replicated/host/xc_host_data.hpp +++ b/src/xc_integrator/replicated/host/xc_host_data.hpp @@ -31,16 +31,13 @@ struct XCHostData { std::vector den_scr; std::vector basis_eval; - std::vector eps2; - std::vector gamma2; - std::vector vrho2; - std::vector vgamma2; + std::vector protonic_eps; + std::vector protonic_vrho; - std::vector zmat2; - std::vector gmat2; - std::vector nbe2_scr; - std::vector den2_scr; - std::vector basis2_eval; + std::vector protonic_zmat; + std::vector protonic_gmat; + std::vector protonic_den_scr; + std::vector protonic_basis_eval; inline XCHostData() {} diff --git a/src/xc_integrator/replicated/replicated_xc_integrator_impl.cxx b/src/xc_integrator/replicated/replicated_xc_integrator_impl.cxx index b9a3def3..f5836987 100644 --- a/src/xc_integrator/replicated/replicated_xc_integrator_impl.cxx +++ b/src/xc_integrator/replicated/replicated_xc_integrator_impl.cxx @@ -88,51 +88,51 @@ void ReplicatedXCIntegratorImpl:: template void ReplicatedXCIntegratorImpl:: - neo_eval_exc_vxc( int64_t m1, int64_t n1, int64_t m2, int64_t n2, - const value_type* P1s, int64_t ldp1s, - const value_type* P2s, int64_t ldp2s, - const value_type* P2z, int64_t ldp2z, - value_type* VXC1s, int64_t ldvxc1s, - value_type* VXC2s, int64_t ldvxc2s, - value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC1, value_type* EXC2, + neo_eval_exc_vxc( int64_t elec_m, int64_t elec_n, int64_t prot_m, int64_t prot_n, + const value_type* elec_Ps, int64_t elec_ldps, + const value_type* prot_Ps, int64_t prot_ldps, + const value_type* prot_Pz, int64_t prot_ldpz, + value_type* elec_VXCs, int64_t elec_ldvxcs, + value_type* prot_VXCs, int64_t prot_ldvxcs, + value_type* prot_VXCz, int64_t prot_ldvxcz, + value_type* elec_EXC, value_type* prot_EXC, const IntegratorSettingsXC& ks_settings){ - neo_eval_exc_vxc_(m1,n1,m2,n2, - P1s,ldp1s, - P2s,ldp2s, - P2z,ldp2z, - VXC1s,ldvxc1s, - VXC2s,ldvxc2s, - VXC2z,ldvxc2z, - EXC1, EXC2, ks_settings); + neo_eval_exc_vxc_(elec_m,elec_n,prot_m,prot_n, + elec_Ps, elec_ldps, + prot_Ps, prot_ldps, + prot_Pz, prot_ldpz, + elec_VXCs,elec_ldvxcs, + prot_VXCs,prot_ldvxcs, + prot_VXCz,prot_ldvxcz, + elec_EXC, prot_EXC, ks_settings); } template void ReplicatedXCIntegratorImpl:: - neo_eval_exc_vxc( int64_t m1, int64_t n1, int64_t m2, int64_t n2, - const value_type* P1s, int64_t ldp1s, - const value_type* P1z, int64_t ldp1z, - const value_type* P2s, int64_t ldp2s, - const value_type* P2z, int64_t ldp2z, - value_type* VXC1s, int64_t ldvxc1s, - value_type* VXC1z, int64_t ldvxc1z, - value_type* VXC2s, int64_t ldvxc2s, - value_type* VXC2z, int64_t ldvxc2z, - value_type* EXC1, value_type* EXC2, + neo_eval_exc_vxc( int64_t elec_m, int64_t elec_n, int64_t prot_m, int64_t prot_n, + const value_type* elec_Ps, int64_t elec_ldps, + const value_type* elec_Pz, int64_t elec_ldpz, + const value_type* prot_Ps, int64_t prot_ldps, + const value_type* prot_Pz, int64_t prot_ldpz, + value_type* elec_VXCs, int64_t elec_ldvxcs, + value_type* elec_VXCz, int64_t elec_ldvxcz, + value_type* prot_VXCs, int64_t prot_ldvxcs, + value_type* prot_VXCz, int64_t prot_ldvxcz, + value_type* elec_EXC, value_type* prot_EXC, const IntegratorSettingsXC& ks_settings ){ - neo_eval_exc_vxc_(m1,n1,m2,n2, - P1s,ldp1s, - P1z,ldp1z, - P2s,ldp2s, - P2z,ldp2z, - VXC1s,ldvxc1s, - VXC1z,ldvxc1z, - VXC2s,ldvxc2s, - VXC2z,ldvxc2z, - EXC1, EXC2, ks_settings); + neo_eval_exc_vxc_(elec_m,elec_n,prot_m,prot_n, + elec_Ps, elec_ldps, + elec_Pz, elec_ldpz, + prot_Ps, prot_ldps, + prot_Pz, prot_ldpz, + elec_VXCs,elec_ldvxcs, + elec_VXCz,elec_ldvxcz, + prot_VXCs,prot_ldvxcs, + prot_VXCz,prot_ldvxcz, + elec_EXC, prot_EXC, ks_settings); } From 2550d2fe3f23df2adc899b3cfc4c752c7bd97a6b Mon Sep 17 00:00:00 2001 From: aodongliu Date: Tue, 5 Dec 2023 13:44:10 -0800 Subject: [PATCH 27/49] adding neo functionality to test_xc_integrator --- tests/xc_integrator.cxx | 96 +++++++++++++++++++++++++++++++++-------- 1 file changed, 77 insertions(+), 19 deletions(-) diff --git a/tests/xc_integrator.cxx b/tests/xc_integrator.cxx index c70b9e0a..7780ce23 100644 --- a/tests/xc_integrator.cxx +++ b/tests/xc_integrator.cxx @@ -39,6 +39,11 @@ void test_xc_integrator( ExecutionSpace ex, const RuntimeEnvironment& rt, double EXC_ref; std::vector EXC_GRAD_ref; bool has_k = false, has_exc_grad = false, rks = true, uks = false, gks = false; + // For NEO-DFT Test: + bool neo = false; + BasisSet protonic_basis; + matrix_type protonic_Ps, protonic_Pz, protonic_VXCs_ref, protonic_VXCz_ref; + double protonic_EXC_ref; { read_hdf5_record( mol, reference_file, "/MOLECULE" ); read_hdf5_record( basis, reference_file, "/BASIS" ); @@ -68,9 +73,13 @@ void test_xc_integrator( ExecutionSpace ex, const RuntimeEnvironment& rt, gks=true; } + if (file.exist("/PROTONIC_DENSITY_SCALAR") and file.exist("/PROTONIC_DENSITY_Z")) + neo=true; + auto dset = file.getDataSet(den); auto dims = dset.getDimensions(); + P = matrix_type( dims[0], dims[1] ); VXC_ref = matrix_type( dims[0], dims[1] ); if (not rks) { @@ -123,10 +132,39 @@ void test_xc_integrator( ExecutionSpace ex, const RuntimeEnvironment& rt, dset = file.getDataSet("/K"); dset.read( K_ref.data() ); } + + if (neo) { + + read_hdf5_record( protonic_basis, reference_file, "/PROTONIC_BASIS" ); + + std::string prot_den_s="/PROTONIC_DENSITY_SCALAR"; + std::string prot_den_z="/PROTONIC_DENSITY_Z"; + std::string prot_vxc_s="/PROTONIC_VXC_SCALAR"; + std::string prot_vxc_z="/PROTONIC_VXC_Z"; + + auto protonic_dset = file.getDataSet(prot_den_s); + auto protonic_dims = protonic_dset.getDimensions(); + + protonic_Ps = matrix_type( protonic_dims[0], protonic_dims[1] ); + protonic_Pz = matrix_type( protonic_dims[0], protonic_dims[1] ); + protonic_VXCs_ref = matrix_type( protonic_dims[0], protonic_dims[1] ); + protonic_VXCz_ref = matrix_type( protonic_dims[0], protonic_dims[1] ); + + protonic_dset.read( protonic_Ps.data() ); + protonic_dset = file.getDataSet(prot_vxc_s); + protonic_dset.read( protonic_VXCs_ref.data() ); + + + protonic_dset = file.getDataSet(prot_den_z); + protonic_dset.read( protonic_Pz.data() ); + protonic_dset = file.getDataSet(prot_vxc_z); + protonic_dset.read( protonic_VXCz_ref.data() ); + } } if(uks and ex == ExecutionSpace::Device) return; if(gks and ex == ExecutionSpace::Device) return; + if(neo and ex == ExecutionSpace::Device) return; for( auto& sh : basis ) @@ -137,14 +175,21 @@ void test_xc_integrator( ExecutionSpace ex, const RuntimeEnvironment& rt, // Construct Load Balancer LoadBalancerFactory lb_factory(ExecutionSpace::Host, "Default"); - auto lb = lb_factory.get_instance(rt, mol, mg, basis); + std::unique_ptr lb; + if (neo) { + for( auto& sh : protonic_basis ) + sh.set_shell_tolerance( std::numeric_limits::epsilon() ); + lb = std::make_unique( lb_factory.get_instance(rt, mol, mg, basis, protonic_basis) ); + } else{ + lb = std::make_unique( lb_factory.get_instance(rt, mol, mg, basis) ); + } // Construct Weights Module MolecularWeightsFactory mw_factory( ex, "Default", MolecularWeightsSettings{} ); auto mw = mw_factory.get_instance(); // Apply partition weights - mw.modify_weights(lb); + mw.modify_weights(*lb); // Construct XC Functional //auto Spin = uks ? ExchCXX::Spin::Polarized : ExchCXX::Spin::Unpolarized; @@ -153,7 +198,7 @@ void test_xc_integrator( ExecutionSpace ex, const RuntimeEnvironment& rt, // Construct XCIntegrator XCIntegratorFactory integrator_factory( ex, "Replicated", integrator_kernel, lwd_kernel, reduction_kernel ); - auto integrator = integrator_factory.get_instance( func, lb ); + auto integrator = integrator_factory.get_instance( func, *lb ); // Integrate Density if( check_integrate_den and rks) { @@ -166,21 +211,35 @@ void test_xc_integrator( ExecutionSpace ex, const RuntimeEnvironment& rt, // Integrate EXC/VXC if ( rks ) { - auto [ EXC, VXC ] = integrator.eval_exc_vxc( P ); + double EXC, protonic_EXC; + matrix_type VXC, protonic_VXCs, protonic_VXCz; + if ( neo ){ + std::tie( EXC, protonic_EXC, VXC, protonic_VXCs, protonic_VXCz ) = integrator.neo_eval_exc_vxc( P, protonic_Ps, protonic_Pz ); + } else{ + std::tie( EXC, VXC ) = integrator.eval_exc_vxc( P ); + } // Check EXC/VXC auto VXC_diff_nrm = ( VXC - VXC_ref ).norm(); CHECK( EXC == Approx( EXC_ref ) ); CHECK( VXC_diff_nrm / basis.nbf() < 1e-10 ); - // Check if the integrator propagates state correctly - { - auto [ EXC1, VXC1 ] = integrator.eval_exc_vxc( P ); - CHECK( EXC1 == Approx( EXC_ref ) ); - auto VXC1_diff_nrm = ( VXC1 - VXC_ref ).norm(); - CHECK( VXC1_diff_nrm / basis.nbf() < 1e-10 ); + + if ( neo ) { + auto protonic_VXCs_diff_nrm = ( protonic_VXCs - protonic_VXCs_ref ).norm(); + auto protonic_VXCz_diff_nrm = ( protonic_VXCz - protonic_VXCz_ref ).norm(); + CHECK( protonic_EXC == Approx( protonic_EXC_ref ) ); + CHECK( protonic_VXCs_diff_nrm / basis.nbf() < 1e-10 ); + CHECK( protonic_VXCz_diff_nrm / basis.nbf() < 1e-10 ); } + } else if (uks) { - auto [ EXC, VXC, VXCz ] = integrator.eval_exc_vxc( P, Pz ); + double EXC, protonic_EXC; + matrix_type VXC, VXCz, protonic_VXCs, protonic_VXCz; + if ( neo ){ + std::tie( EXC, protonic_EXC, VXC, VXCz, protonic_VXCs, protonic_VXCz ) = integrator.neo_eval_exc_vxc( P, Pz, protonic_Ps, protonic_Pz ); + } else{ + std::tie( EXC, VXC, VXCz ) = integrator.eval_exc_vxc( P, Pz ); + } // Check EXC/VXC auto VXC_diff_nrm = ( VXC - VXC_ref ).norm(); @@ -188,14 +247,13 @@ void test_xc_integrator( ExecutionSpace ex, const RuntimeEnvironment& rt, CHECK( EXC == Approx( EXC_ref ) ); CHECK( VXC_diff_nrm / basis.nbf() < 1e-10 ); CHECK( VXCz_diff_nrm / basis.nbf() < 1e-10 ); - // Check if the integrator propagates state correctly - { - auto [ EXC1, VXC1, VXCz1 ] = integrator.eval_exc_vxc( P, Pz ); - CHECK( EXC1 == Approx( EXC_ref ) ); - auto VXC1_diff_nrm = ( VXC1 - VXC_ref ).norm(); - auto VXCz1_diff_nrm = ( VXCz1 - VXCz_ref ).norm(); - CHECK( VXC1_diff_nrm / basis.nbf() < 1e-10 ); - CHECK( VXCz1_diff_nrm / basis.nbf() < 1e-10 ); + + if ( neo ) { + auto protonic_VXCs_diff_nrm = ( protonic_VXCs - protonic_VXCs_ref ).norm(); + auto protonic_VXCz_diff_nrm = ( protonic_VXCz - protonic_VXCz_ref ).norm(); + CHECK( protonic_EXC == Approx( protonic_EXC_ref ) ); + CHECK( protonic_VXCs_diff_nrm / basis.nbf() < 1e-10 ); + CHECK( protonic_VXCz_diff_nrm / basis.nbf() < 1e-10 ); } } else if (gks) { From cb65123757a03aa33007e0c2d4920d8db0554442 Mon Sep 17 00:00:00 2001 From: aodongliu Date: Tue, 5 Dec 2023 14:32:31 -0800 Subject: [PATCH 28/49] add second integration in test and revert H radius to GauXC default --- src/atomic_radii.cxx | 5 +--- tests/xc_integrator.cxx | 60 ++++++++++++++++++++++++++++++++++------- 2 files changed, 51 insertions(+), 14 deletions(-) diff --git a/src/atomic_radii.cxx b/src/atomic_radii.cxx index e22f00ef..6e3a829f 100644 --- a/src/atomic_radii.cxx +++ b/src/atomic_radii.cxx @@ -35,10 +35,7 @@ double slater_radius_64(AtomicNumber _Z) { auto Z = _Z.get(); switch(Z) { - //case 1: /* H */ return pm_to_bohr(25. ); - // Temporarily switch to CQ's H-radius for benchmarking purposes (per https://github.com/wavefunction91/GauXC/issues/77) - // TODO: revert to GauXC's value when code is ready to merge - case 1: /* H */ return pm_to_bohr(52.9); + case 1: /* H */ return pm_to_bohr(25. ); //case 2: /* He */ return pm_to_bohr(120.); case 3: /* Li */ return pm_to_bohr(145.); case 4: /* Be */ return pm_to_bohr(105.); diff --git a/tests/xc_integrator.cxx b/tests/xc_integrator.cxx index 7780ce23..7b6f2ab1 100644 --- a/tests/xc_integrator.cxx +++ b/tests/xc_integrator.cxx @@ -213,11 +213,9 @@ void test_xc_integrator( ExecutionSpace ex, const RuntimeEnvironment& rt, if ( rks ) { double EXC, protonic_EXC; matrix_type VXC, protonic_VXCs, protonic_VXCz; - if ( neo ){ - std::tie( EXC, protonic_EXC, VXC, protonic_VXCs, protonic_VXCz ) = integrator.neo_eval_exc_vxc( P, protonic_Ps, protonic_Pz ); - } else{ - std::tie( EXC, VXC ) = integrator.eval_exc_vxc( P ); - } + + if(neo) std::tie( EXC, protonic_EXC, VXC, protonic_VXCs, protonic_VXCz ) = integrator.neo_eval_exc_vxc( P, protonic_Ps, protonic_Pz ); + else std::tie( EXC, VXC ) = integrator.eval_exc_vxc( P ); // Check EXC/VXC auto VXC_diff_nrm = ( VXC - VXC_ref ).norm(); @@ -232,14 +230,33 @@ void test_xc_integrator( ExecutionSpace ex, const RuntimeEnvironment& rt, CHECK( protonic_VXCz_diff_nrm / basis.nbf() < 1e-10 ); } + // Check if the integrator propagates state correctly + { + double EXC1, protonic_EXC1; + matrix_type VXC1, protonic_VXCs1, protonic_VXCz1; + + if(neo) std::tie( EXC1, protonic_EXC1, VXC1, protonic_VXCs1, protonic_VXCz1 ) = integrator.neo_eval_exc_vxc( P, protonic_Ps, protonic_Pz ); + else std::tie( EXC1, VXC1 ) = integrator.eval_exc_vxc( P ); + + CHECK( EXC1 == Approx( EXC_ref ) ); + auto VXC1_diff_nrm = ( VXC1 - VXC_ref ).norm(); + CHECK( VXC1_diff_nrm / basis.nbf() < 1e-10 ); + + if ( neo ) { + auto protonic_VXCs1_diff_nrm = ( protonic_VXCs1 - protonic_VXCs_ref ).norm(); + auto protonic_VXCz1_diff_nrm = ( protonic_VXCz1 - protonic_VXCz_ref ).norm(); + CHECK( protonic_EXC1 == Approx( protonic_EXC_ref ) ); + CHECK( protonic_VXCs1_diff_nrm / basis.nbf() < 1e-10 ); + CHECK( protonic_VXCz1_diff_nrm / basis.nbf() < 1e-10 ); + } + } + } else if (uks) { double EXC, protonic_EXC; matrix_type VXC, VXCz, protonic_VXCs, protonic_VXCz; - if ( neo ){ - std::tie( EXC, protonic_EXC, VXC, VXCz, protonic_VXCs, protonic_VXCz ) = integrator.neo_eval_exc_vxc( P, Pz, protonic_Ps, protonic_Pz ); - } else{ - std::tie( EXC, VXC, VXCz ) = integrator.eval_exc_vxc( P, Pz ); - } + + if(neo) std::tie( EXC, protonic_EXC, VXC, VXCz, protonic_VXCs, protonic_VXCz ) = integrator.neo_eval_exc_vxc( P, Pz, protonic_Ps, protonic_Pz ); + else std::tie( EXC, VXC, VXCz ) = integrator.eval_exc_vxc( P, Pz ); // Check EXC/VXC auto VXC_diff_nrm = ( VXC - VXC_ref ).norm(); @@ -256,6 +273,29 @@ void test_xc_integrator( ExecutionSpace ex, const RuntimeEnvironment& rt, CHECK( protonic_VXCz_diff_nrm / basis.nbf() < 1e-10 ); } + // Check if the integrator propagates state correctly + { + double EXC1, protonic_EXC1; + matrix_type VXC1, VXCz1, protonic_VXCs1, protonic_VXCz1; + + if(neo) std::tie( EXC1, protonic_EXC1, VXC1, VXCz1, protonic_VXCs1, protonic_VXCz1 ) = integrator.neo_eval_exc_vxc( P, Pz, protonic_Ps, protonic_Pz ); + else std::tie( EXC1, VXC1, VXCz1 ) = integrator.eval_exc_vxc( P, Pz ); + + auto VXC1_diff_nrm = ( VXC1 - VXC_ref ).norm(); + auto VXCz1_diff_nrm = ( VXCz1 - VXCz_ref ).norm(); + CHECK( EXC1 == Approx( EXC_ref ) ); + CHECK( VXC1_diff_nrm / basis.nbf() < 1e-10 ); + CHECK( VXCz1_diff_nrm / basis.nbf() < 1e-10 ); + + if ( neo ) { + auto protonic_VXCs1_diff_nrm = ( protonic_VXCs1 - protonic_VXCs_ref ).norm(); + auto protonic_VXCz1_diff_nrm = ( protonic_VXCz1 - protonic_VXCz_ref ).norm(); + CHECK( protonic_EXC1 == Approx( protonic_EXC_ref ) ); + CHECK( protonic_VXCs1_diff_nrm / basis.nbf() < 1e-10 ); + CHECK( protonic_VXCz1_diff_nrm / basis.nbf() < 1e-10 ); + } + } + } else if (gks) { auto [ EXC, VXC, VXCz, VXCy, VXCx ] = integrator.eval_exc_vxc( P, Pz, Py, Px ); From 0397aa11b350c2f9153dc29a308b4a2b4f871053 Mon Sep 17 00:00:00 2001 From: aodongliu Date: Tue, 5 Dec 2023 17:14:23 -0800 Subject: [PATCH 29/49] adding neo unit tests --- .../coh2_blyp_epc17-2_cc-pvdz_pb4d_ssf.hdf5 | Bin 0 -> 119824 bytes .../coh2_blyp_epc17-2_sto-3g_protsp_ssf.hdf5 | Bin 0 -> 20616 bytes tests/xc_integrator.cxx | 34 +++++++++++++----- 3 files changed, 25 insertions(+), 9 deletions(-) create mode 100644 tests/ref_data/coh2_blyp_epc17-2_cc-pvdz_pb4d_ssf.hdf5 create mode 100644 tests/ref_data/coh2_blyp_epc17-2_sto-3g_protsp_ssf.hdf5 diff --git a/tests/ref_data/coh2_blyp_epc17-2_cc-pvdz_pb4d_ssf.hdf5 b/tests/ref_data/coh2_blyp_epc17-2_cc-pvdz_pb4d_ssf.hdf5 new file mode 100644 index 0000000000000000000000000000000000000000..102db3f68b1259d55a468cfa0d1b60618ddda084 GIT binary patch literal 119824 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�N= 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 V$6{Ra^N?d<>n literal 0 HcmV?d00001 diff --git a/tests/ref_data/coh2_blyp_epc17-2_sto-3g_protsp_ssf.hdf5 b/tests/ref_data/coh2_blyp_epc17-2_sto-3g_protsp_ssf.hdf5 new file mode 100644 index 0000000000000000000000000000000000000000..c2c413769b1b04e365003554ea9d70f64cb98788 GIT binary patch literal 20616 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 Date: Wed, 6 Dec 2023 15:39:35 -0800 Subject: [PATCH 30/49] modify NEO UT ref data --- .../coh2_blyp_epc17-2_cc-pvdz_pb4d_ssf.hdf5 | Bin 119824 -> 119824 bytes .../coh2_blyp_epc17-2_sto-3g_protsp_ssf.hdf5 | Bin 20616 -> 20616 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/tests/ref_data/coh2_blyp_epc17-2_cc-pvdz_pb4d_ssf.hdf5 b/tests/ref_data/coh2_blyp_epc17-2_cc-pvdz_pb4d_ssf.hdf5 index 102db3f68b1259d55a468cfa0d1b60618ddda084..486c538e27c273031f2d70a8cea5642fdb03ca68 100644 GIT binary patch literal 119824 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 WpqigW-rznH=d{wrk==S^D*p%k;YNZ0 literal 119824 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�N= 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 V$6{Ra^N?d<>n diff --git a/tests/ref_data/coh2_blyp_epc17-2_sto-3g_protsp_ssf.hdf5 b/tests/ref_data/coh2_blyp_epc17-2_sto-3g_protsp_ssf.hdf5 index c2c413769b1b04e365003554ea9d70f64cb98788..b15044092c79be1df9933f039ac7388220321347 100644 GIT binary patch literal 20616 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 literal 20616 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 Date: Wed, 6 Dec 2023 15:54:05 -0800 Subject: [PATCH 31/49] remote protonic_shell_pairs() as it's not needed atm --- include/gauxc/load_balancer.hpp | 3 --- src/load_balancer/load_balancer_impl.cxx | 9 ++------- src/load_balancer/load_balancer_impl.hpp | 1 - 3 files changed, 2 insertions(+), 11 deletions(-) diff --git a/include/gauxc/load_balancer.hpp b/include/gauxc/load_balancer.hpp index 7d0ae6d3..434c8480 100644 --- a/include/gauxc/load_balancer.hpp +++ b/include/gauxc/load_balancer.hpp @@ -108,9 +108,6 @@ class LoadBalancer { /// Return the protonic BasisSetMap instance corresponding to protonic basis/molecule const basis_map_type& protonic_basis_map() const; - /// Return the number of non-negligible local shell pairs for the protonic basis for this LoadBalancer - const shell_pair_type& protonic_shell_pairs() const; - /// Return the runtime handle used to construct this LoadBalancer const RuntimeEnvironment& runtime() const; diff --git a/src/load_balancer/load_balancer_impl.cxx b/src/load_balancer/load_balancer_impl.cxx index e190d721..af14f012 100644 --- a/src/load_balancer/load_balancer_impl.cxx +++ b/src/load_balancer/load_balancer_impl.cxx @@ -27,8 +27,8 @@ LoadBalancerImpl::LoadBalancerImpl(const RuntimeEnvironment& rt, const Molecule& LoadBalancerImpl(rt, mol, mg, basis, molmeta) { // Unique initializations for the second basis - shell_pairs2_ = std::make_shared(*basis2_); - basis_map2_ = std::make_shared(*basis2_, mol); + protonic_basis_ = std::make_shared(protonic_basis); + protonic_basis_map_ = std::make_shared(*protonic_basis_, mol); } LoadBalancerImpl::LoadBalancerImpl( const RuntimeEnvironment& rt, const Molecule& mol, @@ -148,11 +148,6 @@ const LoadBalancerImpl::basis_map_type& LoadBalancerImpl::protonic_basis_map() c GAUXC_GENERIC_EXCEPTION("No Protonic Basis Found in LoadBalancerImpl::protonic_basis_map()"); return *protonic_basis_map_; } -const LoadBalancerImpl::shell_pair_type& LoadBalancerImpl::protonic_shell_pairs() const { - if( not protonic_shell_pairs_ ) - GAUXC_GENERIC_EXCEPTION("No Protonic Basis Found in LoadBalancerImpl::protonic_shell_pairs()"); - return *protonic_shell_pairs_; -} const RuntimeEnvironment& LoadBalancerImpl::runtime() const { return runtime_; diff --git a/src/load_balancer/load_balancer_impl.hpp b/src/load_balancer/load_balancer_impl.hpp index 38f183c8..9e84e203 100644 --- a/src/load_balancer/load_balancer_impl.hpp +++ b/src/load_balancer/load_balancer_impl.hpp @@ -33,7 +33,6 @@ class LoadBalancerImpl { // Protonic basis information if doing Nuclear-Electronic Orbital (NEO) theory std::shared_ptr protonic_basis_; std::shared_ptr protonic_basis_map_; - std::shared_ptr protonic_shell_pairs_; std::vector< XCTask > local_tasks_; From d8578f2c9aad12bd66cc3313f508ece944acb4cb Mon Sep 17 00:00:00 2001 From: aodongliu Date: Sat, 6 Jan 2024 13:34:12 -0800 Subject: [PATCH 32/49] remove unwanted changes --- include/gauxc/enums.hpp | 1 - src/load_balancer/host/replicated_host_load_balancer.cxx | 1 - src/load_balancer/load_balancer_impl.cxx | 2 +- src/load_balancer/load_balancer_impl.hpp | 1 - src/load_balancer/rebalance.cxx | 4 ++++ .../host/reference_replicated_xc_host_integrator.hpp | 1 - .../reference_replicated_xc_host_integrator_exc_vxc.hpp | 8 +++++--- .../replicated/replicated_xc_integrator_impl.cxx | 4 ++-- 8 files changed, 12 insertions(+), 10 deletions(-) diff --git a/include/gauxc/enums.hpp b/include/gauxc/enums.hpp index 26a5cf23..ce7c19e1 100644 --- a/include/gauxc/enums.hpp +++ b/include/gauxc/enums.hpp @@ -59,4 +59,3 @@ enum class SupportedAlg { }; } // namespace GauXC - diff --git a/src/load_balancer/host/replicated_host_load_balancer.cxx b/src/load_balancer/host/replicated_host_load_balancer.cxx index 075e926b..ddf7e24c 100644 --- a/src/load_balancer/host/replicated_host_load_balancer.cxx +++ b/src/load_balancer/host/replicated_host_load_balancer.cxx @@ -84,7 +84,6 @@ std::vector< XCTask > HostReplicatedLoadBalancer::create_local_tasks_() const { task.protonic_bfn_screening.nbe = protonic_nbe; } - #pragma omp critical temp_tasks.push_back( std::pair(batch_idx,std::move( task )) diff --git a/src/load_balancer/load_balancer_impl.cxx b/src/load_balancer/load_balancer_impl.cxx index af14f012..3c6b2338 100644 --- a/src/load_balancer/load_balancer_impl.cxx +++ b/src/load_balancer/load_balancer_impl.cxx @@ -26,7 +26,7 @@ LoadBalancerImpl::LoadBalancerImpl(const RuntimeEnvironment& rt, const Molecule& std::shared_ptr molmeta ) : LoadBalancerImpl(rt, mol, mg, basis, molmeta) { - // Unique initializations for the second basis + // Unique initializations for the protonic basis protonic_basis_ = std::make_shared(protonic_basis); protonic_basis_map_ = std::make_shared(*protonic_basis_, mol); } diff --git a/src/load_balancer/load_balancer_impl.hpp b/src/load_balancer/load_balancer_impl.hpp index 9e84e203..9d673907 100644 --- a/src/load_balancer/load_balancer_impl.hpp +++ b/src/load_balancer/load_balancer_impl.hpp @@ -29,7 +29,6 @@ class LoadBalancerImpl { std::shared_ptr molmeta_; std::shared_ptr basis_map_; std::shared_ptr shell_pairs_; - // Protonic basis information if doing Nuclear-Electronic Orbital (NEO) theory std::shared_ptr protonic_basis_; std::shared_ptr protonic_basis_map_; diff --git a/src/load_balancer/rebalance.cxx b/src/load_balancer/rebalance.cxx index c66086dd..fe885d97 100644 --- a/src/load_balancer/rebalance.cxx +++ b/src/load_balancer/rebalance.cxx @@ -177,6 +177,8 @@ auto rebalance(TaskIterator begin, TaskIterator end, const CostFunctor& cost, MP mpi_buffer.pack(task.weights); mpi_buffer.pack(task.bfn_screening.shell_list); mpi_buffer.pack(task.bfn_screening.nbe); + mpi_buffer.pack(task.protonic_bfn_screening.shell_list); + mpi_buffer.pack(task.protonic_bfn_screening.nbe); mpi_buffer.pack(task.cou_screening.shell_list); mpi_buffer.pack(task.cou_screening.shell_pair_list); mpi_buffer.pack(task.cou_screening.shell_pair_idx_list); @@ -296,6 +298,8 @@ auto rebalance(TaskIterator begin, TaskIterator end, const CostFunctor& cost, MP mpi_buffer.unpack(task.weights); mpi_buffer.unpack(task.bfn_screening.shell_list); mpi_buffer.unpack(task.bfn_screening.nbe); + mpi_buffer.unpack(task.protonic_bfn_screening.shell_list); + mpi_buffer.unpack(task.protonic_bfn_screening.nbe); mpi_buffer.unpack(task.cou_screening.shell_list); mpi_buffer.unpack(task.cou_screening.shell_pair_list); mpi_buffer.unpack(task.cou_screening.shell_pair_idx_list); diff --git a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator.hpp b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator.hpp index 4baedafe..95cd9585 100644 --- a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator.hpp +++ b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator.hpp @@ -54,7 +54,6 @@ class ReferenceReplicatedXCHostIntegrator : value_type* VXCx, int64_t ldvxcx, value_type* EXC, const IntegratorSettingsXC& ks_settings ) override; - void neo_eval_exc_vxc_( int64_t m1, int64_t n1, int64_t m2, int64_t n2, const value_type* Ps, int64_t ldps, const value_type* prot_Ps, int64_t prot_ldps, diff --git a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp index 86f02e67..d891b543 100644 --- a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp +++ b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc.hpp @@ -191,8 +191,10 @@ void ReferenceReplicatedXCHostIntegrator:: }); -} - +} + + + template void ReferenceReplicatedXCHostIntegrator:: exc_vxc_local_work_( const value_type* Ps, int64_t ldps, @@ -679,7 +681,7 @@ void ReferenceReplicatedXCHostIntegrator:: } } -} +} } } diff --git a/src/xc_integrator/replicated/replicated_xc_integrator_impl.cxx b/src/xc_integrator/replicated/replicated_xc_integrator_impl.cxx index f5836987..c0127406 100644 --- a/src/xc_integrator/replicated/replicated_xc_integrator_impl.cxx +++ b/src/xc_integrator/replicated/replicated_xc_integrator_impl.cxx @@ -50,7 +50,7 @@ void ReplicatedXCIntegratorImpl:: int64_t ldpz, value_type* VXCs, int64_t ldvxcs, value_type* VXCz, int64_t ldvxcz, - value_type* EXC, const IntegratorSettingsXC& ks_settings) { + value_type* EXC, const IntegratorSettingsXC& ks_settings ) { eval_exc_vxc_(m,n,Ps,ldps, Pz,ldpz, @@ -96,7 +96,7 @@ void ReplicatedXCIntegratorImpl:: value_type* prot_VXCs, int64_t prot_ldvxcs, value_type* prot_VXCz, int64_t prot_ldvxcz, value_type* elec_EXC, value_type* prot_EXC, - const IntegratorSettingsXC& ks_settings){ + const IntegratorSettingsXC& ks_settings ){ neo_eval_exc_vxc_(elec_m,elec_n,prot_m,prot_n, elec_Ps, elec_ldps, From 55eb9fad1c0c9244a79730b19951f14d40d0d13a Mon Sep 17 00:00:00 2001 From: aodongliu Date: Fri, 5 Apr 2024 15:36:44 -0700 Subject: [PATCH 33/49] fix code after rebase --- include/gauxc/load_balancer.hpp | 8 ++++++-- src/load_balancer/host/load_balancer_host_factory.cxx | 6 +++--- src/load_balancer/host/load_balancer_host_factory.hpp | 2 +- src/load_balancer/load_balancer.cxx | 1 + src/load_balancer/load_balancer_factory.cxx | 10 +++++----- src/load_balancer/load_balancer_impl.cxx | 10 ++++++++++ src/load_balancer/load_balancer_impl.hpp | 1 + 7 files changed, 27 insertions(+), 11 deletions(-) diff --git a/include/gauxc/load_balancer.hpp b/include/gauxc/load_balancer.hpp index 434c8480..25aa0072 100644 --- a/include/gauxc/load_balancer.hpp +++ b/include/gauxc/load_balancer.hpp @@ -108,6 +108,10 @@ class LoadBalancer { /// Return the protonic BasisSetMap instance corresponding to protonic basis/molecule const basis_map_type& protonic_basis_map() const; + /// Return the number of protonic non-negligible local shell pairs for this LoadBalancer + const shell_pair_type& protonic_shell_pairs() const; + const shell_pair_type& protonic_shell_pairs(); + /// Return the runtime handle used to construct this LoadBalancer const RuntimeEnvironment& runtime() const; @@ -171,7 +175,7 @@ class LoadBalancerFactory { LoadBalancer get_instance( const RuntimeEnvironment& rt, const Molecule& mol, const MolGrid& mg, const BasisSet& bs, - const BasisSet& bs2, size_t pad_val = 1 ); + const BasisSet& bs2 ); /** * @brief Generate a shared pointer to a LoadBalancer instance per kernel and @@ -193,7 +197,7 @@ class LoadBalancerFactory { std::shared_ptr get_shared_instance( const RuntimeEnvironment& rt, const Molecule& mol, const MolGrid& mg, const BasisSet&, - const BasisSet&, size_t pad_val = 1 ); + const BasisSet& ); private: diff --git a/src/load_balancer/host/load_balancer_host_factory.cxx b/src/load_balancer/host/load_balancer_host_factory.cxx index d83e8301..ada7d93f 100644 --- a/src/load_balancer/host/load_balancer_host_factory.cxx +++ b/src/load_balancer/host/load_balancer_host_factory.cxx @@ -44,7 +44,7 @@ std::shared_ptr LoadBalancerHostFactory::get_shared_instance( std::shared_ptr LoadBalancerHostFactory::get_shared_instance( std::string kernel_name, const RuntimeEnvironment& rt, const Molecule& mol, const MolGrid& mg, const BasisSet& basis, - const BasisSet& protonic_basis, size_t pv + const BasisSet& protonic_basis ) { std::transform(kernel_name.begin(), kernel_name.end(), @@ -57,12 +57,12 @@ std::shared_ptr LoadBalancerHostFactory::get_shared_instance( std::unique_ptr ptr = nullptr; if( kernel_name == "REPLICATED-PETITE" ) ptr = std::make_unique( - rt, mol, mg, basis, protonic_basis, pv + rt, mol, mg, basis, protonic_basis ); if( kernel_name == "REPLICATED-FILLIN" ) ptr = std::make_unique( - rt, mol, mg, basis, protonic_basis, pv + rt, mol, mg, basis, protonic_basis ); if( ! ptr ) GAUXC_GENERIC_EXCEPTION("Load Balancer Kernel Not Recognized: " + kernel_name); diff --git a/src/load_balancer/host/load_balancer_host_factory.hpp b/src/load_balancer/host/load_balancer_host_factory.hpp index b8dcf0fb..0af2e919 100644 --- a/src/load_balancer/host/load_balancer_host_factory.hpp +++ b/src/load_balancer/host/load_balancer_host_factory.hpp @@ -20,7 +20,7 @@ struct LoadBalancerHostFactory { static std::shared_ptr get_shared_instance( std::string kernel_name, const RuntimeEnvironment& rt, const Molecule& mol, const MolGrid& mg, const BasisSet& basis, - const BasisSet& protonic_basis, size_t pv + const BasisSet& protonic_basis ); }; diff --git a/src/load_balancer/load_balancer.cxx b/src/load_balancer/load_balancer.cxx index e9601bfe..313303ea 100644 --- a/src/load_balancer/load_balancer.cxx +++ b/src/load_balancer/load_balancer.cxx @@ -87,6 +87,7 @@ const LoadBalancer::shell_pair_type& LoadBalancer::shell_pairs() const { if( not pimpl_ ) GAUXC_PIMPL_NOT_INITIALIZED(); return pimpl_->shell_pairs(); } + const LoadBalancer::shell_pair_type& LoadBalancer::shell_pairs() { if( not pimpl_ ) GAUXC_PIMPL_NOT_INITIALIZED(); return pimpl_->shell_pairs(); diff --git a/src/load_balancer/load_balancer_factory.cxx b/src/load_balancer/load_balancer_factory.cxx index bf02c7e8..cd5c19aa 100644 --- a/src/load_balancer/load_balancer_factory.cxx +++ b/src/load_balancer/load_balancer_factory.cxx @@ -53,20 +53,20 @@ LoadBalancer LoadBalancerFactory::get_instance( std::shared_ptr LoadBalancerFactory::get_shared_instance( const RuntimeEnvironment& rt, const Molecule& mol, const MolGrid& mg, const BasisSet& basis, - const BasisSet& protonic_basis, size_t pad_value + const BasisSet& protonic_basis ) { switch(ex_) { case ExecutionSpace::Host: using host_factory = LoadBalancerHostFactory; return host_factory::get_shared_instance(kernel_name_, - rt, mol, mg, basis, protonic_basis, pad_value ); + rt, mol, mg, basis, protonic_basis ); #ifdef GAUXC_ENABLE_DEVICE case ExecutionSpace::Device: GAUXC_GENERIC_EXCEPTION("2 basis with GPU NYI"); //using device_factory = LoadBalancerDeviceFactory; //return device_factory::get_shared_instance(kernel_name_, - // rt, mol, mg, basis, pad_value ); + // rt, mol, mg, basis ); #endif default: GAUXC_GENERIC_EXCEPTION("Unrecognized Execution Space"); @@ -78,10 +78,10 @@ std::shared_ptr LoadBalancerFactory::get_shared_instance( LoadBalancer LoadBalancerFactory::get_instance( const RuntimeEnvironment& rt, const Molecule& mol, const MolGrid& mg, const BasisSet& basis, - const BasisSet& protonic_basis, size_t pad_value + const BasisSet& protonic_basis ) { - auto ptr = get_shared_instance(rt, mol, mg, basis, protonic_basis, pad_value); + auto ptr = get_shared_instance(rt, mol, mg, basis, protonic_basis); return LoadBalancer(std::move(*ptr)); } diff --git a/src/load_balancer/load_balancer_impl.cxx b/src/load_balancer/load_balancer_impl.cxx index 3c6b2338..4859bfc3 100644 --- a/src/load_balancer/load_balancer_impl.cxx +++ b/src/load_balancer/load_balancer_impl.cxx @@ -148,6 +148,16 @@ const LoadBalancerImpl::basis_map_type& LoadBalancerImpl::protonic_basis_map() c GAUXC_GENERIC_EXCEPTION("No Protonic Basis Found in LoadBalancerImpl::protonic_basis_map()"); return *protonic_basis_map_; } +const LoadBalancerImpl::shell_pair_type& LoadBalancerImpl::protonic_shell_pairs() const { + if(!protonic_shell_pairs_) GAUXC_GENERIC_EXCEPTION("No Protonic Basis Found in LoadBalancerImpl::protonic_shell_pairs()"); + return *shell_pairs_; +} +const LoadBalancerImpl::shell_pair_type& LoadBalancerImpl::protonic_shell_pairs() { + if(!protonic_shell_pairs_) { + protonic_shell_pairs_ = std::make_shared(*protonic_basis_); + } + return *protonic_shell_pairs_; +} const RuntimeEnvironment& LoadBalancerImpl::runtime() const { return runtime_; diff --git a/src/load_balancer/load_balancer_impl.hpp b/src/load_balancer/load_balancer_impl.hpp index 9d673907..467e3524 100644 --- a/src/load_balancer/load_balancer_impl.hpp +++ b/src/load_balancer/load_balancer_impl.hpp @@ -31,6 +31,7 @@ class LoadBalancerImpl { std::shared_ptr shell_pairs_; // Protonic basis information if doing Nuclear-Electronic Orbital (NEO) theory std::shared_ptr protonic_basis_; + std::shared_ptr protonic_shell_pairs_; std::shared_ptr protonic_basis_map_; std::vector< XCTask > local_tasks_; From 850a89554c493d0cca966073702e68bc2075fab0 Mon Sep 17 00:00:00 2001 From: aodongliu Date: Fri, 5 Apr 2024 15:49:47 -0700 Subject: [PATCH 34/49] remove unwanted changes --- .../replicated/replicated_xc_integrator_impl.hpp | 1 - src/load_balancer/load_balancer_impl.cxx | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/include/gauxc/xc_integrator/replicated/replicated_xc_integrator_impl.hpp b/include/gauxc/xc_integrator/replicated/replicated_xc_integrator_impl.hpp index db4f2381..d954ab1c 100644 --- a/include/gauxc/xc_integrator/replicated/replicated_xc_integrator_impl.hpp +++ b/include/gauxc/xc_integrator/replicated/replicated_xc_integrator_impl.hpp @@ -109,7 +109,6 @@ class ReplicatedXCIntegratorImpl { value_type* VXCs, int64_t ldvxcs, value_type* VXCz, int64_t ldvxcz, value_type* EXC, const IntegratorSettingsXC& ks_settings ); - void eval_exc_vxc( int64_t m, int64_t n, const value_type* Ps, int64_t ldps, const value_type* Pz, diff --git a/src/load_balancer/load_balancer_impl.cxx b/src/load_balancer/load_balancer_impl.cxx index 4859bfc3..d5ad020d 100644 --- a/src/load_balancer/load_balancer_impl.cxx +++ b/src/load_balancer/load_balancer_impl.cxx @@ -138,13 +138,13 @@ const LoadBalancerImpl::shell_pair_type& LoadBalancerImpl::shell_pairs() { } const LoadBalancerImpl::basis_type& LoadBalancerImpl::protonic_basis() const { - if( not protonic_basis_ ) + if(!protonic_basis_) GAUXC_GENERIC_EXCEPTION("No Protonic Basis Found in LoadBalancerImpl::protonic_basis()"); return *protonic_basis_; } const LoadBalancerImpl::basis_map_type& LoadBalancerImpl::protonic_basis_map() const { - if( not protonic_basis_map_ ) + if(!protonic_basis_map_) GAUXC_GENERIC_EXCEPTION("No Protonic Basis Found in LoadBalancerImpl::protonic_basis_map()"); return *protonic_basis_map_; } From c0639ad75438fa6b06c59d6a0a326454d4687938 Mon Sep 17 00:00:00 2001 From: aodongliu Date: Fri, 5 Apr 2024 17:07:40 -0700 Subject: [PATCH 35/49] update integration to be consistent with regular local work driver --- ...licated_xc_host_integrator_exc_vxc_neo.hpp | 70 ++++++++++++------- 1 file changed, 43 insertions(+), 27 deletions(-) diff --git a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp index 0509118a..9a2c65a2 100644 --- a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp +++ b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp @@ -208,6 +208,10 @@ void ReferenceReplicatedXCHostIntegrator:: *elec_EXC = 0.; *prot_EXC = 0.; + + double NEL_WORK = 0.0; + double ELEC_EXC_WORK = 0.0; + double PROT_EXC_WORK = 0.0; // Loop over tasks @@ -437,18 +441,18 @@ void ReferenceReplicatedXCHostIntegrator:: value_type dn = 2.35 - 2.4 * std::sqrt(total_erho*total_prho) + 6.6 * (total_erho*total_prho); // Update electronic eps and vxc - eps[iPt] += -1.0 * total_prho/dn; - vrho[spin_dim_scal*iPt] += ( -1.0 * total_prho / dn + (-1.2 * std::sqrt(total_erho) * std::sqrt(total_prho) * total_prho + eps[iPt] += -1.0 * total_prho/dn; + vrho[spin_dim_scal*iPt] += ( -1.0 * total_prho / dn + (-1.2 * std::sqrt(total_erho) * std::sqrt(total_prho) * total_prho + 6.6 * total_erho * total_prho * total_prho ) / (dn * dn) ); if(not is_rks) - vrho[spin_dim_scal*iPt+1] += ( -1.0 * total_prho / dn + (-1.2 * std::sqrt(total_erho) * std::sqrt(total_prho) * total_prho + vrho[spin_dim_scal*iPt+1] += ( -1.0 * total_prho / dn + (-1.2 * std::sqrt(total_erho) * std::sqrt(total_prho) * total_prho + 6.6 * total_erho * total_prho * total_prho ) / (dn * dn) ); // Assign protonic eps and vxc - protonic_eps[iPt] = -1.0 * total_erho/dn; - protonic_vrho[2*iPt] = ( -1.0 * total_erho / dn + (-1.2 * std::sqrt(total_prho) * std::sqrt(total_erho) * total_erho - + 6.6 * total_erho * total_erho * total_prho ) / (dn * dn) ); - protonic_vrho[2*iPt+1] = 0.0; + protonic_eps[iPt] = -1.0 * total_erho/dn; + protonic_vrho[2*iPt] = ( -1.0 * total_erho / dn + (-1.2 * std::sqrt(total_prho) * std::sqrt(total_erho) * total_erho + + 6.6 * total_erho * total_erho * total_prho ) / (dn * dn) ); + protonic_vrho[2*iPt+1] = 0.0; } // End looping over pts } // End if(evalProtonic) //----------------------End EPC functional Evaluation--------------------------------------- @@ -511,21 +515,36 @@ void ReferenceReplicatedXCHostIntegrator:: } //----------------------End Evaluating Protonic ZMat---------------------------- + // Scalar integrations + double NEL_local = 0.0; + double ELEC_EXC_local = 0.0; + double PROT_EXC_local = 0.0; + for( int32_t i = 0; i < npts; ++i ) { + const auto den = is_rks ? den_eval[i] : (den_eval[2*i] + den_eval[2*i+1]); + NEL_local += weights[i] * den; + ELEC_EXC_local += eps[i] * den; + } + // Protonic XC (EPC) + if(evalProtonic){ + for( int32_t i = 0; i < npts; ++i ) { + const auto protonic_den = protonic_den_eval[2*i] + protonic_den_eval[2*i+1]; + PROT_EXC_local += protonic_eps[i] * protonic_den; + } + } + // Atomic updates + #pragma omp atomic + NEL_WORK += NEL_local; + #pragma omp atomic + ELEC_EXC_WORK += ELEC_EXC_local; + #pragma omp atomic + PROT_EXC_WORK += PROT_EXC_local; - // Integrate to obtain Final EXC/VXC: - #pragma omp critical + // Incremeta LT of VXC { - // Electronic XC (VXC+EPC) - // Scalar integrations - for( int32_t i = 0; i < npts; ++i ) { - const auto den = is_rks ? den_eval[i] : (den_eval[2*i] + den_eval[2*i+1]); - *N_EL += weights[i] * den; - *elec_EXC += eps[i] * den; - } - // Increment VXC + // Increment Electronic XC (VXC+EPC) lwd->inc_vxc( npts, nbf, nbe, basis_eval, submat_map, zmat, nbe, elec_VXCs, elec_ldvxcs, nbe_scr ); if(not is_rks) @@ -533,28 +552,26 @@ void ReferenceReplicatedXCHostIntegrator:: nbe_scr ); - // Protonic XC (EPC) + // Increment Protonic XC (EPC) // Scalar integrations if(evalProtonic){ - for( int32_t i = 0; i < npts; ++i ) { - const auto protonic_den = protonic_den_eval[2*i] + protonic_den_eval[2*i+1]; - *prot_EXC += protonic_eps[i] * protonic_den; - } - // Increment VXC lwd->inc_vxc( npts, protonic_nbf, protonic_nbe, protonic_basis_eval, protonic_submat_map, protonic_zmat, protonic_nbe, prot_VXCs, prot_ldvxcs, nbe_scr ); lwd->inc_vxc( npts, protonic_nbf, protonic_nbe, protonic_basis_eval, protonic_submat_map, protonic_zmat_z, protonic_nbe, prot_VXCz, prot_ldvxcz, nbe_scr ); } - //std::cout << "Electronic EXC: " << *elec_EXC << std::endl; - //std::cout << "Protonic EXC: " << *prot_EXC << std::endl; - } // End #pragma omp critical + } } // Loop over tasks } // End OpenMP region + // Set scalar return values + *N_EL = NEL_WORK; + *elec_EXC = ELEC_EXC_WORK; + *prot_EXC = PROT_EXC_WORK; + //std::cout << "N_EL = " << std::setprecision(12) << std::scientific << *N_EL << std::endl; //std::cout << "elec_EXC = " << std::setprecision(12) << std::scientific << *elec_EXC << std::endl //std::cout << "prot_EXC = " << std::setprecision(12) << std::scientific << *prot_EXC << std::endl; @@ -578,7 +595,6 @@ void ReferenceReplicatedXCHostIntegrator:: prot_VXCz[ j + i*prot_ldvxcz ] = prot_VXCz[ i + j*prot_ldvxcz ]; } } - } From 1c65a4d02f278addc7b0f5175f4b0ebde71040e0 Mon Sep 17 00:00:00 2001 From: aodongliu Date: Fri, 26 Apr 2024 09:51:29 -0700 Subject: [PATCH 36/49] edit code for benchmarking vs CQ --- src/atomic_radii.cxx | 3 +- ...licated_xc_host_integrator_exc_vxc_neo.hpp | 50 +++++++++---------- tests/ini_input.hpp | 10 ++-- 3 files changed, 31 insertions(+), 32 deletions(-) diff --git a/src/atomic_radii.cxx b/src/atomic_radii.cxx index 6e3a829f..4944a091 100644 --- a/src/atomic_radii.cxx +++ b/src/atomic_radii.cxx @@ -35,7 +35,8 @@ double slater_radius_64(AtomicNumber _Z) { auto Z = _Z.get(); switch(Z) { - case 1: /* H */ return pm_to_bohr(25. ); + //case 1: /* H */ return pm_to_bohr(25. ); + case 1: /* H */ return pm_to_bohr(52.9 ); //case 2: /* He */ return pm_to_bohr(120.); case 3: /* Li */ return pm_to_bohr(145.); case 4: /* Be */ return pm_to_bohr(105.); diff --git a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp index 9a2c65a2..ac9d9c86 100644 --- a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp +++ b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp @@ -51,15 +51,15 @@ void ReferenceReplicatedXCHostIntegrator:: // Compute Local contributions to EXC / VXC this->timer_.time_op("XCIntegrator.LocalWork", [&](){ - neo_exc_vxc_local_work_( elec_Ps, elec_ldps, - nullptr, 0, - prot_Ps, prot_ldps, - prot_Pz, prot_ldpz, + neo_exc_vxc_local_work_( elec_Ps, elec_ldps, + nullptr, 0, + prot_Ps, prot_ldps, + prot_Pz, prot_ldpz, elec_VXCs, elec_ldvxcs, nullptr, 0, prot_VXCs, prot_ldvxcs, prot_VXCz, prot_ldvxcz, - elec_EXC, prot_EXC, &N_EL, settings ); + elec_EXC, prot_EXC, &N_EL, settings ); }); @@ -117,15 +117,15 @@ void ReferenceReplicatedXCHostIntegrator:: // Compute Local contributions to EXC / VXC this->timer_.time_op("XCIntegrator.LocalWork", [&](){ - neo_exc_vxc_local_work_( elec_Ps, elec_ldps, - elec_Pz, elec_ldpz, - prot_Ps, prot_ldps, - prot_Pz, prot_ldpz, + neo_exc_vxc_local_work_( elec_Ps, elec_ldps, + elec_Pz, elec_ldpz, + prot_Ps, prot_ldps, + prot_Pz, prot_ldpz, elec_VXCs, elec_ldvxcs, elec_VXCz, elec_ldvxcz, prot_VXCs, prot_ldvxcs, prot_VXCz, prot_ldvxcz, - elec_EXC, prot_EXC, &N_EL, settings ); + elec_EXC, prot_EXC, &N_EL, settings ); }); @@ -159,12 +159,13 @@ void ReferenceReplicatedXCHostIntegrator:: value_type* prot_VXCs, int64_t prot_ldvxcs, value_type* prot_VXCz, int64_t prot_ldvxcz, value_type* elec_EXC, value_type* prot_EXC, value_type *N_EL, - const IntegratorSettingsXC& ks_settings ) { - + const IntegratorSettingsXC& settings ) { // Determine is electronic subsystem is RKS or UKS const bool is_uks = (elec_Pz != nullptr) and (elec_VXCz != nullptr); - const bool is_rks = not is_uks; // TODO: GKS + const bool is_rks = not is_uks; + // TODO: Integrate with GKS + // TODO: Integrate with mGGA // Cast LWD to LocalHostWorkDriver auto* lwd = dynamic_cast(this->local_work_driver_.get()); @@ -195,7 +196,9 @@ void ReferenceReplicatedXCHostIntegrator:: // Check that Partition Weights have been calculated auto& lb_state = this->load_balancer_->state(); - if( not lb_state.modified_weights_are_stored ) GAUXC_GENERIC_EXCEPTION("Weights Have Not Beed Modified"); + if( not lb_state.modified_weights_are_stored ) { + GAUXC_GENERIC_EXCEPTION("Weights Have Not Beed Modified"); + } // Zero out integrands @@ -212,7 +215,6 @@ void ReferenceReplicatedXCHostIntegrator:: double NEL_WORK = 0.0; double ELEC_EXC_WORK = 0.0; double PROT_EXC_WORK = 0.0; - // Loop over tasks const size_t ntasks = tasks.size(); @@ -226,6 +228,7 @@ void ReferenceReplicatedXCHostIntegrator:: for( size_t iT = 0; iT < ntasks; ++iT ) { //std::cout << iT << "/" << ntasks << std::endl; + //printf("%lu / %lu\n", iT, ntasks); // Alias current task const auto& task = tasks[iT]; @@ -401,9 +404,9 @@ void ReferenceReplicatedXCHostIntegrator:: // Evaluate X matrix (P * B) -> store in Z // NEED THE FACTOR OF 2 HERE! - lwd->eval_xmat( npts, protonic_nbf, protonic_nbe, protonic_submat_map, 2.0, prot_Ps, prot_ldps, protonic_basis_eval, protonic_nbe, + lwd->eval_xmat( npts, protonic_nbf, protonic_nbe, protonic_submat_map, 1.0, prot_Ps, prot_ldps, protonic_basis_eval, protonic_nbe, protonic_zmat, protonic_nbe, nbe_scr ); - lwd->eval_xmat( npts, protonic_nbf, protonic_nbe, protonic_submat_map, 2.0, prot_Pz, prot_ldpz, protonic_basis_eval, protonic_nbe, + lwd->eval_xmat( npts, protonic_nbf, protonic_nbe, protonic_submat_map, 1.0, prot_Pz, prot_ldpz, protonic_basis_eval, protonic_nbe, protonic_zmat_z, protonic_nbe, nbe_scr ); // Evaluate U and V variables @@ -422,12 +425,12 @@ void ReferenceReplicatedXCHostIntegrator:: //----------------------Start EPC functional Evaluation--------------------------------------- if(evalProtonic){ for (int32_t iPt = 0; iPt < npts; iPt++ ){ - // Get Electronic density scalar (RKS) + // Get Electronic density scalar const auto den = is_rks ? den_eval[iPt] : (den_eval[2*iPt] + den_eval[2*iPt+1]); - value_type total_erho = std::abs(den) > 1e-15? den : 0; + value_type total_erho = std::abs(den) > 1e-15? den : 0.0; // Get Protonic density scalar (UKS) const auto protonic_den = protonic_den_eval[2*iPt] + protonic_den_eval[2*iPt+1]; - value_type total_prho = std::abs(protonic_den) > 1e-15? protonic_den : 0; + value_type total_prho = std::abs(protonic_den) > 1e-15? protonic_den : 0.0; // Skip this point if the density is too small if(total_erho < 1e-15 | total_prho < 1e-15){ @@ -545,12 +548,9 @@ void ReferenceReplicatedXCHostIntegrator:: { // Increment Electronic XC (VXC+EPC) - lwd->inc_vxc( npts, nbf, nbe, basis_eval, submat_map, zmat, nbe, elec_VXCs, elec_ldvxcs, - nbe_scr ); + lwd->inc_vxc( npts, nbf, nbe, basis_eval, submat_map, zmat, nbe, elec_VXCs, elec_ldvxcs, nbe_scr ); if(not is_rks) - lwd->inc_vxc( npts, nbf, nbe, basis_eval, submat_map, zmat_z, nbe, elec_VXCz, elec_ldvxcz, - nbe_scr ); - + lwd->inc_vxc( npts, nbf, nbe, basis_eval, submat_map, zmat_z, nbe, elec_VXCz, elec_ldvxcz, nbe_scr ); // Increment Protonic XC (EPC) // Scalar integrations diff --git a/tests/ini_input.hpp b/tests/ini_input.hpp index 00071a92..541b4991 100644 --- a/tests/ini_input.hpp +++ b/tests/ini_input.hpp @@ -23,9 +23,8 @@ * \param [in/out] s std::string to be trimmed */ static inline std::string& trim_left(std::string &s) { - s.erase(s.begin(), std::find_if(s.begin(), s.end(), - std::not1(std::ptr_fun(std::isspace)))); - return s; + s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int c) {return !std::isspace(c);})); + return s; }; // trim_left @@ -35,9 +34,8 @@ static inline std::string& trim_left(std::string &s) { * \param [in/out] s std::string to be trimmed */ static inline std::string& trim_right(std::string &s) { - s.erase(std::find_if(s.rbegin(), s.rend(), - std::not1(std::ptr_fun(std::isspace))).base(), s.end()); - return s; + s.erase(std::find_if(s.rbegin(), s.rend(), [](int c) {return !std::isspace(c);}).base(), s.end()); + return s; }; // trim_right From aac79240c85cfa1ab77f2c918a9368dd5e45ea42 Mon Sep 17 00:00:00 2001 From: aodongliu Date: Fri, 26 Apr 2024 10:57:11 -0700 Subject: [PATCH 37/49] disable mpi to match cq default --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a4419bc..2de9f4de 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,7 +30,7 @@ endif() option( GAUXC_ENABLE_HOST "Enable Host Integrator" ON ) option( GAUXC_ENABLE_CUDA "Enable CUDA Bindings" OFF ) option( GAUXC_ENABLE_HIP "Enable HIP Bindings" OFF ) -option( GAUXC_ENABLE_MPI "Enable MPI Bindings" ON ) +option( GAUXC_ENABLE_MPI "Enable MPI Bindings" OFF ) option( GAUXC_ENABLE_OPENMP "Enable OpenMP Compilation" ON ) option( GAUXC_ENABLE_TESTS "Enable Unit Tests" ON ) option( GAUXC_ENABLE_GAU2GRID "Enable Gau2Grid Collocation" ON ) From 07d6e52f34b3d65247bdabe4ee4b8e55ed4d0167 Mon Sep 17 00:00:00 2001 From: aodongliu Date: Fri, 26 Apr 2024 18:32:15 -0700 Subject: [PATCH 38/49] attemp to add epcfunc pointer --- cmake/gauxc-dep-versions.cmake | 6 ++- .../replicated_xc_device_integrator.hpp | 9 ++++ .../replicated_xc_host_integrator.hpp | 9 ++++ .../replicated_xc_integrator_factory.hpp | 53 +++++++++++++++++++ .../replicated_xc_integrator_impl.hpp | 8 +++ src/load_balancer/load_balancer_impl.cxx | 1 + .../replicated_xc_device_integrator.cxx | 37 +++++++++++++ .../host/replicated_xc_host_integrator.cxx | 35 ++++++++++++ .../replicated_xc_integrator_impl.cxx | 11 ++++ 9 files changed, 167 insertions(+), 2 deletions(-) diff --git a/cmake/gauxc-dep-versions.cmake b/cmake/gauxc-dep-versions.cmake index cd3969d8..23ce98fd 100644 --- a/cmake/gauxc-dep-versions.cmake +++ b/cmake/gauxc-dep-versions.cmake @@ -10,8 +10,10 @@ set( GAUXC_CUB_REVISION 1.10.0 ) set( GAUXC_CUTLASS_REPOSITORY https://github.com/NVIDIA/cutlass.git ) set( GAUXC_CUTLASS_REVISION v2.10.0 ) -set( GAUXC_EXCHCXX_REPOSITORY https://github.com/wavefunction91/ExchCXX.git ) -set( GAUXC_EXCHCXX_REVISION 21a4700a826ec0beae1311a1d59677393bcb168f ) +#set( GAUXC_EXCHCXX_REPOSITORY https://github.com/wavefunction91/ExchCXX.git ) +#set( GAUXC_EXCHCXX_REVISION 21a4700a826ec0beae1311a1d59677393bcb168f ) +set( GAUXC_EXCHCXX_REPOSITORY https://github.com/aodongliu/ExchCXX.git ) +set( GAUXC_EXCHCXX_REVISION 63aab83d92c90c4d130f2806ad008b749539d8b2 ) set( GAUXC_GAU2GRID_REPOSITORY https://github.com/dgasmith/gau2grid.git ) set( GAUXC_GAU2GRID_REVISION v2.0.6 ) diff --git a/include/gauxc/xc_integrator/replicated/replicated_xc_device_integrator.hpp b/include/gauxc/xc_integrator/replicated/replicated_xc_device_integrator.hpp index 4721243c..e8f82aff 100644 --- a/include/gauxc/xc_integrator/replicated/replicated_xc_device_integrator.hpp +++ b/include/gauxc/xc_integrator/replicated/replicated_xc_device_integrator.hpp @@ -57,6 +57,15 @@ struct ReplicatedXCDeviceIntegratorFactory { std::shared_ptr rd ); + static ptr_return_t make_integrator_impl( + std::string integrator_kernel, + std::shared_ptr func, + std::shared_ptr epcfunc, + std::shared_ptr lb, + std::unique_ptr&& lwd, + std::shared_ptr rd + ); + }; diff --git a/include/gauxc/xc_integrator/replicated/replicated_xc_host_integrator.hpp b/include/gauxc/xc_integrator/replicated/replicated_xc_host_integrator.hpp index 57685599..d1fd41d1 100644 --- a/include/gauxc/xc_integrator/replicated/replicated_xc_host_integrator.hpp +++ b/include/gauxc/xc_integrator/replicated/replicated_xc_host_integrator.hpp @@ -56,6 +56,15 @@ struct ReplicatedXCHostIntegratorFactory { std::unique_ptr&& lwd, std::shared_ptr rd ); + + static ptr_return_t make_integrator_impl( + std::string integrator_kernel, + std::shared_ptr func, + std::shared_ptr epcfunc, + std::shared_ptr lb, + std::unique_ptr&& lwd, + std::shared_ptr rd + ); }; diff --git a/include/gauxc/xc_integrator/replicated/replicated_xc_integrator_factory.hpp b/include/gauxc/xc_integrator/replicated/replicated_xc_integrator_factory.hpp index d75a92d8..0eecb4bd 100644 --- a/include/gauxc/xc_integrator/replicated/replicated_xc_integrator_factory.hpp +++ b/include/gauxc/xc_integrator/replicated/replicated_xc_integrator_factory.hpp @@ -73,6 +73,59 @@ struct ReplicatedXCIntegratorFactory { } + + + /** Generate a ReplicatedXCIntegrator instance + * + * @param[in] ex Execution space for integrator instance + * @param[in] integration_kernel Name of integration scaffold to load ("Default", "Reference", etc) + * @param[in] func XC functional to integrate + * @param[in] epcfunc EPC functional to integrate + * @param[in] lb Pregenerated LoadBalancer instance + * @param[in] lwd Local Work Driver + */ + static ptr_return_t make_integrator_impl( + ExecutionSpace ex, + std::string integrator_kernel, + std::shared_ptr func, + std::shared_ptr epcfunc, + std::shared_ptr lb, + std::unique_ptr&& lwd, + std::shared_ptr rd + ) { + + + + switch(ex) { + + using host_factory = + detail::ReplicatedXCHostIntegratorFactory; + case ExecutionSpace::Host: + return std::make_unique( + host_factory::make_integrator_impl( + integrator_kernel, func, epcfunc, lb, std::move(lwd), rd + ) + ); + + #ifdef GAUXC_HAS_DEVICE + using device_factory = + detail::ReplicatedXCDeviceIntegratorFactory; + case ExecutionSpace::Device: + return std::make_unique( + device_factory::make_integrator_impl( + integrator_kernel, func, epcfunc, lb, std::move(lwd), rd + ) + ); + #endif + + default: + GAUXC_GENERIC_EXCEPTION("ReplicatedXCIntegrator ExecutionSpace Not Supported"); + } + + return nullptr; + + } + }; diff --git a/include/gauxc/xc_integrator/replicated/replicated_xc_integrator_impl.hpp b/include/gauxc/xc_integrator/replicated/replicated_xc_integrator_impl.hpp index d954ab1c..f6abecb4 100644 --- a/include/gauxc/xc_integrator/replicated/replicated_xc_integrator_impl.hpp +++ b/include/gauxc/xc_integrator/replicated/replicated_xc_integrator_impl.hpp @@ -29,6 +29,7 @@ class ReplicatedXCIntegratorImpl { protected: std::shared_ptr< functional_type > func_; ///< XC functional + std::shared_ptr< functional_type > epcfunc_; ///< EPC functional for NEO std::shared_ptr< LoadBalancer > load_balancer_; ///< Load Balancer std::unique_ptr< LocalWorkDriver > local_work_driver_; ///< Local Work Driver std::shared_ptr< ReductionDriver > reduction_driver_; ///< Reduction Driver @@ -93,6 +94,13 @@ class ReplicatedXCIntegratorImpl { std::shared_ptr< ReductionDriver> rd ); + ReplicatedXCIntegratorImpl( std::shared_ptr< functional_type > func, + std::shared_ptr< functional_type > epcfunc, + std::shared_ptr< LoadBalancer > lb, + std::unique_ptr< LocalWorkDriver >&& lwd, + std::shared_ptr< ReductionDriver> rd + ); + virtual ~ReplicatedXCIntegratorImpl() noexcept; void integrate_den( int64_t m, int64_t n, const value_type* P, diff --git a/src/load_balancer/load_balancer_impl.cxx b/src/load_balancer/load_balancer_impl.cxx index d5ad020d..742ab06f 100644 --- a/src/load_balancer/load_balancer_impl.cxx +++ b/src/load_balancer/load_balancer_impl.cxx @@ -29,6 +29,7 @@ LoadBalancerImpl::LoadBalancerImpl(const RuntimeEnvironment& rt, const Molecule& // Unique initializations for the protonic basis protonic_basis_ = std::make_shared(protonic_basis); protonic_basis_map_ = std::make_shared(*protonic_basis_, mol); + } LoadBalancerImpl::LoadBalancerImpl( const RuntimeEnvironment& rt, const Molecule& mol, diff --git a/src/xc_integrator/replicated/device/replicated_xc_device_integrator.cxx b/src/xc_integrator/replicated/device/replicated_xc_device_integrator.cxx index 534d5333..19f4596c 100644 --- a/src/xc_integrator/replicated/device/replicated_xc_device_integrator.cxx +++ b/src/xc_integrator/replicated/device/replicated_xc_device_integrator.cxx @@ -52,6 +52,43 @@ typename ReplicatedXCDeviceIntegratorFactory::ptr_return_t GAUXC_GENERIC_EXCEPTION("INTEGRATOR KERNEL " + integrator_kernel + " NOT RECOGNIZED"); +} + + +template +typename ReplicatedXCDeviceIntegratorFactory::ptr_return_t + ReplicatedXCDeviceIntegratorFactory::make_integrator_impl( + std::string integrator_kernel, + std::shared_ptr func, + std::shared_ptr epcfunc, + std::shared_ptr lb, + std::unique_ptr&& lwd, + std::shared_ptr rd + ) { + + // Make sure that the LWD is a valid LocalDeviceWorkDriver + if(not dynamic_cast(lwd.get())) { + GAUXC_GENERIC_EXCEPTION("Passed LWD Not valid for Device ExSpace"); + } + + std::transform(integrator_kernel.begin(), integrator_kernel.end(), + integrator_kernel.begin(), ::toupper ); + + if( integrator_kernel == "DEFAULT" ) integrator_kernel = "INCORE"; + + if( integrator_kernel == "INCORE" ) + return std::make_unique>( + func, epcfunc, lb, std::move(lwd), rd + ); + else if( integrator_kernel == "SHELLBATCHED" ) + return std::make_unique>( + func, epcfunc, lb, std::move(lwd), rd + ); + + else + GAUXC_GENERIC_EXCEPTION("INTEGRATOR KERNEL " + integrator_kernel + " NOT RECOGNIZED"); + + } template struct ReplicatedXCDeviceIntegratorFactory; diff --git a/src/xc_integrator/replicated/host/replicated_xc_host_integrator.cxx b/src/xc_integrator/replicated/host/replicated_xc_host_integrator.cxx index b8a4e06f..efb51374 100644 --- a/src/xc_integrator/replicated/host/replicated_xc_host_integrator.cxx +++ b/src/xc_integrator/replicated/host/replicated_xc_host_integrator.cxx @@ -49,6 +49,41 @@ typename ReplicatedXCHostIntegratorFactory::ptr_return_t return nullptr; +} + + +template +typename ReplicatedXCHostIntegratorFactory::ptr_return_t + ReplicatedXCHostIntegratorFactory::make_integrator_impl( + std::string integrator_kernel, + std::shared_ptr func, + std::shared_ptr epcfunc, + std::shared_ptr lb, + std::unique_ptr&& lwd, + std::shared_ptr rd + ) { + + // Make sure that the LWD is a valid LocalHostWorkDriver + if(not dynamic_cast(lwd.get())) { + GAUXC_GENERIC_EXCEPTION("Passed LWD Not valid for Host ExSpace"); + } + + std::transform(integrator_kernel.begin(), integrator_kernel.end(), + integrator_kernel.begin(), ::toupper ); + + if( integrator_kernel == "DEFAULT" ) integrator_kernel = "REFERENCE"; + + if( integrator_kernel == "REFERENCE" ) + return std::make_unique>( + func, epcfunc, lb, std::move(lwd), rd + ); + + else + GAUXC_GENERIC_EXCEPTION("INTEGRATOR KERNEL: " + integrator_kernel + " NOT RECOGNIZED"); + + return nullptr; + + } template class ReplicatedXCHostIntegratorFactory; diff --git a/src/xc_integrator/replicated/replicated_xc_integrator_impl.cxx b/src/xc_integrator/replicated/replicated_xc_integrator_impl.cxx index c0127406..7b75e940 100644 --- a/src/xc_integrator/replicated/replicated_xc_integrator_impl.cxx +++ b/src/xc_integrator/replicated/replicated_xc_integrator_impl.cxx @@ -19,6 +19,17 @@ ReplicatedXCIntegratorImpl:: func_(func), load_balancer_(lb), local_work_driver_(std::move(lwd)), reduction_driver_(rd){ } +template +ReplicatedXCIntegratorImpl:: + ReplicatedXCIntegratorImpl( std::shared_ptr< functional_type > func, + std::shared_ptr< functional_type > epcfunc, + std::shared_ptr< LoadBalancer > lb, + std::unique_ptr< LocalWorkDriver >&& lwd, + std::shared_ptr< ReductionDriver > rd) : + ReplicatedXCIntegratorImpl(func, lb, std::move(lwd), rd) { + epcfunc_ = epcfunc; + } + template ReplicatedXCIntegratorImpl:: ~ReplicatedXCIntegratorImpl() noexcept = default; From f6040f859e7e05f357c90b21b3e162502064cb87 Mon Sep 17 00:00:00 2001 From: Aodong Liu Date: Sat, 27 Apr 2024 01:55:07 -0700 Subject: [PATCH 39/49] epc is now done via exchcxx builtin --- cmake/gauxc-dep-versions.cmake | 2 +- .../xc_integrator/integrator_factory.hpp | 52 +++++++ ...eference_replicated_xc_host_integrator.hpp | 3 +- ...licated_xc_host_integrator_exc_vxc_neo.hpp | 132 ++++++++++-------- .../replicated/host/xc_host_data.hpp | 2 +- 5 files changed, 128 insertions(+), 63 deletions(-) diff --git a/cmake/gauxc-dep-versions.cmake b/cmake/gauxc-dep-versions.cmake index 23ce98fd..2ca8beb2 100644 --- a/cmake/gauxc-dep-versions.cmake +++ b/cmake/gauxc-dep-versions.cmake @@ -13,7 +13,7 @@ set( GAUXC_CUTLASS_REVISION v2.10.0 ) #set( GAUXC_EXCHCXX_REPOSITORY https://github.com/wavefunction91/ExchCXX.git ) #set( GAUXC_EXCHCXX_REVISION 21a4700a826ec0beae1311a1d59677393bcb168f ) set( GAUXC_EXCHCXX_REPOSITORY https://github.com/aodongliu/ExchCXX.git ) -set( GAUXC_EXCHCXX_REVISION 63aab83d92c90c4d130f2806ad008b749539d8b2 ) +set( GAUXC_EXCHCXX_REVISION 840403f14c7e5abd6b6a3f2126c3ce38d3fe8cf9 ) set( GAUXC_GAU2GRID_REPOSITORY https://github.com/dgasmith/gau2grid.git ) set( GAUXC_GAU2GRID_REVISION v2.0.6 ) diff --git a/include/gauxc/xc_integrator/integrator_factory.hpp b/include/gauxc/xc_integrator/integrator_factory.hpp index d63d23be..2790d3a9 100644 --- a/include/gauxc/xc_integrator/integrator_factory.hpp +++ b/include/gauxc/xc_integrator/integrator_factory.hpp @@ -89,6 +89,58 @@ class XCIntegratorFactory { return get_shared_instance( std::make_shared(func), lb ); } + /** Generate XCIntegrator instance + * + * @param[in] func XC functional + * @param[in] epcfunc EPC functional + * @param[in] lb Preconstructed Load Balancer instance + */ + std::shared_ptr get_shared_instance( + std::shared_ptr func, + std::shared_ptr epcfunc, + std::shared_ptr lb ) { + + // Create Local Work Driver + auto lwd = LocalWorkDriverFactory::make_local_work_driver( ex_, + lwd_kernel_, local_work_settings_ ); + + // Create Reduction Driver + auto rd = ReductionDriverFactory::get_shared_instance( + lb->runtime(), rd_kernel_ ); + + // Create Integrator instance + std::transform( input_type_.begin(), input_type_.end(), input_type_.begin(), + ::toupper ); + + if(!epcfunc->is_polarized()) + GAUXC_GENERIC_EXCEPTION("EPC FUNCTIONAL NOT POLARIZED"); + + if( input_type_ == "REPLICATED" ) + return std::make_shared( + ReplicatedXCIntegratorFactory::make_integrator_impl( + ex_, integrator_kernel_, func, epcfunc, lb, std::move(lwd), rd + ) + ); + else GAUXC_GENERIC_EXCEPTION("INTEGRATOR TYPE NOT RECOGNIZED"); + + return nullptr; + + } + + auto get_shared_instance( const functional_type& func, const functional_type& epcfunc, + const LoadBalancer& lb ) { + return get_shared_instance( std::make_shared(func), + std::make_shared(epcfunc), + std::make_shared(lb) ); + } + + auto get_shared_instance( const functional_type& func, const functional_type& epcfunc, + std::shared_ptr lb ) { + return get_shared_instance( std::make_shared(func), + std::make_shared(epcfunc), + lb ); + } + template integrator_type get_instance( Args&&... args ) { diff --git a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator.hpp b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator.hpp index 95cd9585..eb9bc2c7 100644 --- a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator.hpp +++ b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator.hpp @@ -110,7 +110,8 @@ class ReferenceReplicatedXCHostIntegrator : value_type* VXCz, int64_t ldvxcz, value_type* prot_VXCs, int64_t prot_ldvxcs, value_type* prot_VXCz, int64_t prot_ldvxcz, - value_type* EXC1, value_type* prot_EXC, value_type *N_EL, + value_type* EXC1, value_type* prot_EXC, + value_type *N_EL, value_type *N_PROT, const IntegratorSettingsXC& ks_settings ); void exc_grad_local_work_( const value_type* P, int64_t ldp, value_type* EXC_GRAD ); diff --git a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp index ac9d9c86..f657e280 100644 --- a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp +++ b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp @@ -48,6 +48,8 @@ void ReferenceReplicatedXCHostIntegrator:: // Temporary electron count to judge integrator accuracy value_type N_EL; + // Temporary proton count to judge integrator accuracy + value_type N_PROT; // Compute Local contributions to EXC / VXC this->timer_.time_op("XCIntegrator.LocalWork", [&](){ @@ -59,7 +61,8 @@ void ReferenceReplicatedXCHostIntegrator:: nullptr, 0, prot_VXCs, prot_ldvxcs, prot_VXCz, prot_ldvxcz, - elec_EXC, prot_EXC, &N_EL, settings ); + elec_EXC, prot_EXC, + &N_EL, &N_PROT, settings ); }); @@ -75,6 +78,7 @@ void ReferenceReplicatedXCHostIntegrator:: this->reduction_driver_->allreduce_inplace( elec_EXC, 1, ReductionOp::Sum ); this->reduction_driver_->allreduce_inplace( prot_EXC, 1, ReductionOp::Sum ); this->reduction_driver_->allreduce_inplace( &N_EL, 1, ReductionOp::Sum ); + this->reduction_driver_->allreduce_inplace( &N_PROT, 1, ReductionOp::Sum ); }); @@ -114,6 +118,8 @@ void ReferenceReplicatedXCHostIntegrator:: // Temporary electron count to judge integrator accuracy value_type N_EL; + // Temporary proton count to judge integrator accuracy + value_type N_PROT; // Compute Local contributions to EXC / VXC this->timer_.time_op("XCIntegrator.LocalWork", [&](){ @@ -125,7 +131,8 @@ void ReferenceReplicatedXCHostIntegrator:: elec_VXCz, elec_ldvxcz, prot_VXCs, prot_ldvxcs, prot_VXCz, prot_ldvxcz, - elec_EXC, prot_EXC, &N_EL, settings ); + elec_EXC, prot_EXC, + &N_EL, &N_PROT, settings ); }); @@ -142,6 +149,7 @@ void ReferenceReplicatedXCHostIntegrator:: this->reduction_driver_->allreduce_inplace( elec_EXC, 1, ReductionOp::Sum ); this->reduction_driver_->allreduce_inplace( prot_EXC, 1, ReductionOp::Sum ); this->reduction_driver_->allreduce_inplace( &N_EL, 1, ReductionOp::Sum ); + this->reduction_driver_->allreduce_inplace( &N_PROT, 1, ReductionOp::Sum ); }); @@ -158,7 +166,8 @@ void ReferenceReplicatedXCHostIntegrator:: value_type* elec_VXCz, int64_t elec_ldvxcz, value_type* prot_VXCs, int64_t prot_ldvxcs, value_type* prot_VXCz, int64_t prot_ldvxcz, - value_type* elec_EXC, value_type* prot_EXC, value_type *N_EL, + value_type* elec_EXC, value_type* prot_EXC, + value_type *N_EL, value_type *N_PROT, const IntegratorSettingsXC& settings ) { // Determine is electronic subsystem is RKS or UKS @@ -172,6 +181,7 @@ void ReferenceReplicatedXCHostIntegrator:: // Setup Aliases const auto& func = *this->func_; + const auto& epcfunc = *this->epcfunc_; const auto& basis = this->load_balancer_->basis(); const auto& mol = this->load_balancer_->molecule(); @@ -213,8 +223,9 @@ void ReferenceReplicatedXCHostIntegrator:: *prot_EXC = 0.; double NEL_WORK = 0.0; - double ELEC_EXC_WORK = 0.0; - double PROT_EXC_WORK = 0.0; + double NPROT_WORK = 0.0; + double EXC_WORK = 0.0; + double EPC_WORK = 0.0; // Loop over tasks const size_t ntasks = tasks.size(); @@ -310,14 +321,15 @@ void ReferenceReplicatedXCHostIntegrator:: dden_y_eval = dden_x_eval + spin_dim_scal * npts; dden_z_eval = dden_y_eval + spin_dim_scal * npts; } + //----------------------End Electronic System Setup------------------------ //----------------------Start Protonic System Setup------------------------ // Set Up Memory (assuming UKS) - host_data.protonic_zmat .resize( npts * protonic_nbe * 2 ); - host_data.protonic_eps .resize( npts ); + host_data.epc .resize( npts ); host_data.protonic_vrho .resize( npts * 2 ); + host_data.protonic_zmat .resize( npts * protonic_nbe * 2 ); // LDA host_data.protonic_basis_eval .resize( npts * protonic_nbe ); host_data.protonic_den_scr .resize( npts * 2); @@ -327,8 +339,8 @@ void ReferenceReplicatedXCHostIntegrator:: auto* protonic_zmat = host_data.protonic_zmat.data(); decltype(protonic_zmat) protonic_zmat_z = protonic_zmat + protonic_nbe * npts; - auto* protonic_eps = host_data.protonic_eps.data(); - auto* protonic_vrho = host_data.protonic_vrho.data(); + auto* epc = host_data.epc.data(); + auto* protonic_vrho = host_data.protonic_vrho.data(); // No GGA for NEO yet //----------------------End Protonic System Setup------------------------ @@ -403,7 +415,6 @@ void ReferenceReplicatedXCHostIntegrator:: protonic_basis_eval ); // Evaluate X matrix (P * B) -> store in Z - // NEED THE FACTOR OF 2 HERE! lwd->eval_xmat( npts, protonic_nbf, protonic_nbe, protonic_submat_map, 1.0, prot_Ps, prot_ldps, protonic_basis_eval, protonic_nbe, protonic_zmat, protonic_nbe, nbe_scr ); lwd->eval_xmat( npts, protonic_nbf, protonic_nbe, protonic_submat_map, 1.0, prot_Pz, prot_ldpz, protonic_basis_eval, protonic_nbe, @@ -414,7 +425,7 @@ void ReferenceReplicatedXCHostIntegrator:: protonic_nbe, protonic_den_eval ); // No protonic XC functional. Fill with eps and vrho to be 0.0 - std::fill_n(protonic_eps, npts, 0.); + std::fill_n(epc, npts, 0.); std::fill_n(protonic_vrho, npts*2, 0.); } //----------------------End Calculating Protonic Density & UV Variable------------------------ @@ -424,39 +435,33 @@ void ReferenceReplicatedXCHostIntegrator:: //----------------------Start EPC functional Evaluation--------------------------------------- if(evalProtonic){ + // Prepare for kernal input for (int32_t iPt = 0; iPt < npts; iPt++ ){ - // Get Electronic density scalar - const auto den = is_rks ? den_eval[iPt] : (den_eval[2*iPt] + den_eval[2*iPt+1]); - value_type total_erho = std::abs(den) > 1e-15? den : 0.0; - // Get Protonic density scalar (UKS) + // Sum up electronic density + const auto electonic_den = is_rks ? den_eval[iPt] : (den_eval[2*iPt] + den_eval[2*iPt+1]); + // Sum up protonic density const auto protonic_den = protonic_den_eval[2*iPt] + protonic_den_eval[2*iPt+1]; - value_type total_prho = std::abs(protonic_den) > 1e-15? protonic_den : 0.0; - - // Skip this point if the density is too small - if(total_erho < 1e-15 | total_prho < 1e-15){ - protonic_eps[iPt] = 0.0; - protonic_vrho[2*iPt] = 0.0; - protonic_vrho[2*iPt+1] = 0.0; - continue; - } - - // epc-17-2 denominator - value_type dn = 2.35 - 2.4 * std::sqrt(total_erho*total_prho) + 6.6 * (total_erho*total_prho); - - // Update electronic eps and vxc - eps[iPt] += -1.0 * total_prho/dn; - vrho[spin_dim_scal*iPt] += ( -1.0 * total_prho / dn + (-1.2 * std::sqrt(total_erho) * std::sqrt(total_prho) * total_prho - + 6.6 * total_erho * total_prho * total_prho ) / (dn * dn) ); - if(not is_rks) - vrho[spin_dim_scal*iPt+1] += ( -1.0 * total_prho / dn + (-1.2 * std::sqrt(total_erho) * std::sqrt(total_prho) * total_prho - + 6.6 * total_erho * total_prho * total_prho ) / (dn * dn) ); - - // Assign protonic eps and vxc - protonic_eps[iPt] = -1.0 * total_erho/dn; - protonic_vrho[2*iPt] = ( -1.0 * total_erho / dn + (-1.2 * std::sqrt(total_prho) * std::sqrt(total_erho) * total_erho - + 6.6 * total_erho * total_erho * total_prho ) / (dn * dn) ); - protonic_vrho[2*iPt+1] = 0.0; - } // End looping over pts + // Treat total erho as spin-up, treat total prho as spin down + protonic_den_eval[2*iPt] = electonic_den; + protonic_den_eval[2*iPt+1] = protonic_den; + } + + // EPC Functional Evaluation (Calling ExchCXX Builtin Function) + epcfunc.eval_exc_vxc( npts, protonic_den_eval, epc, protonic_vrho ); + + // Digest kernal output + for (int32_t iPt = 0; iPt < npts; iPt++ ){ + // assign df/derho + vrho[2*iPt] += protonic_vrho[2*iPt]; + vrho[2*iPt+1] += protonic_vrho[2*iPt]; + // assign df/dprho + protonic_vrho[2*iPt] = protonic_vrho[2*iPt+1]; + protonic_vrho[2*iPt+1] = 0.0; + // change back protonic density to original state + protonic_den_eval[2*iPt] = protonic_den_eval[2*iPt+1]; + protonic_den_eval[2*iPt] = 0.0; + } + } // End if(evalProtonic) //----------------------End EPC functional Evaluation--------------------------------------- @@ -466,6 +471,7 @@ void ReferenceReplicatedXCHostIntegrator:: // Factor weights into XC results for( int32_t i = 0; i < npts; ++i ) { eps[i] *= weights[i]; + epc[i] *= weights[i]; vrho[spin_dim_scal*i] *= weights[i]; if(not is_rks) vrho[spin_dim_scal*i+1] *= weights[i]; } @@ -507,7 +513,6 @@ void ReferenceReplicatedXCHostIntegrator:: if(evalProtonic){ // Factor weights into XC results for( int32_t i = 0; i < npts; ++i ) { - protonic_eps[i] *= weights[i]; protonic_vrho[2*i] *= weights[i]; protonic_vrho[2*i+1] *= weights[i]; } @@ -519,29 +524,34 @@ void ReferenceReplicatedXCHostIntegrator:: //----------------------End Evaluating Protonic ZMat---------------------------- // Scalar integrations - double NEL_local = 0.0; - double ELEC_EXC_local = 0.0; - double PROT_EXC_local = 0.0; + double NEL_local = 0.0; + double NPROT_local = 0.0; + double EXC_local = 0.0; + double EPC_local = 0.0; for( int32_t i = 0; i < npts; ++i ) { - const auto den = is_rks ? den_eval[i] : (den_eval[2*i] + den_eval[2*i+1]); - NEL_local += weights[i] * den; - ELEC_EXC_local += eps[i] * den; + const auto den = is_rks ? den_eval[i] : (den_eval[2*i] + den_eval[2*i+1]); + NEL_local += weights[i] * den; + EXC_local += eps[i] * den; + EPC_local += epc[i] * den;; } // Protonic XC (EPC) if(evalProtonic){ for( int32_t i = 0; i < npts; ++i ) { const auto protonic_den = protonic_den_eval[2*i] + protonic_den_eval[2*i+1]; - PROT_EXC_local += protonic_eps[i] * protonic_den; + NPROT_local += weights[i] * protonic_den; + EPC_local += epc[i] * protonic_den; } } // Atomic updates #pragma omp atomic - NEL_WORK += NEL_local; + NEL_WORK += NEL_local; #pragma omp atomic - ELEC_EXC_WORK += ELEC_EXC_local; + NPROT_WORK += NPROT_local; #pragma omp atomic - PROT_EXC_WORK += PROT_EXC_local; + EXC_WORK += EXC_local; + #pragma omp atomic + EPC_WORK += EPC_local; // Incremeta LT of VXC @@ -568,13 +578,15 @@ void ReferenceReplicatedXCHostIntegrator:: } // End OpenMP region // Set scalar return values - *N_EL = NEL_WORK; - *elec_EXC = ELEC_EXC_WORK; - *prot_EXC = PROT_EXC_WORK; - - //std::cout << "N_EL = " << std::setprecision(12) << std::scientific << *N_EL << std::endl; - //std::cout << "elec_EXC = " << std::setprecision(12) << std::scientific << *elec_EXC << std::endl - //std::cout << "prot_EXC = " << std::setprecision(12) << std::scientific << *prot_EXC << std::endl; + *N_EL = NEL_WORK; + *N_PROT = NPROT_WORK; + *elec_EXC = EXC_WORK + EPC_WORK; + *prot_EXC = EPC_WORK; + + std::cout << "N_EL = " << std::setprecision(12) << std::scientific << *N_EL << std::endl; + std::cout << "N_PROT = " << std::setprecision(12) << std::scientific << *N_PROT << std::endl; + std::cout << "elec_EXC = " << std::setprecision(12) << std::scientific << *elec_EXC << std::endl; + std::cout << "prot_EXC = " << std::setprecision(12) << std::scientific << *prot_EXC << std::endl; // Symmetrize Electronic VXC for( int32_t j = 0; j < nbf; ++j ) diff --git a/src/xc_integrator/replicated/host/xc_host_data.hpp b/src/xc_integrator/replicated/host/xc_host_data.hpp index 44cea1ec..decebb43 100644 --- a/src/xc_integrator/replicated/host/xc_host_data.hpp +++ b/src/xc_integrator/replicated/host/xc_host_data.hpp @@ -31,7 +31,7 @@ struct XCHostData { std::vector den_scr; std::vector basis_eval; - std::vector protonic_eps; + std::vector epc; std::vector protonic_vrho; std::vector protonic_zmat; From b955f1733ca1672ebb8065ddcb81f88560e5da12 Mon Sep 17 00:00:00 2001 From: Aodong Liu Date: Sat, 27 Apr 2024 22:30:46 -0700 Subject: [PATCH 40/49] remove debug statements --- ...licated_xc_host_integrator_exc_vxc_neo.hpp | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp index f657e280..3737153a 100644 --- a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp +++ b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp @@ -437,13 +437,9 @@ void ReferenceReplicatedXCHostIntegrator:: if(evalProtonic){ // Prepare for kernal input for (int32_t iPt = 0; iPt < npts; iPt++ ){ - // Sum up electronic density - const auto electonic_den = is_rks ? den_eval[iPt] : (den_eval[2*iPt] + den_eval[2*iPt+1]); - // Sum up protonic density - const auto protonic_den = protonic_den_eval[2*iPt] + protonic_den_eval[2*iPt+1]; // Treat total erho as spin-up, treat total prho as spin down - protonic_den_eval[2*iPt] = electonic_den; - protonic_den_eval[2*iPt+1] = protonic_den; + protonic_den_eval[2*iPt] = is_rks ? den_eval[iPt] : (den_eval[2*iPt] + den_eval[2*iPt+1]); + protonic_den_eval[2*iPt+1] = protonic_den_eval[2*iPt] + protonic_den_eval[2*iPt+1]; } // EPC Functional Evaluation (Calling ExchCXX Builtin Function) @@ -452,8 +448,8 @@ void ReferenceReplicatedXCHostIntegrator:: // Digest kernal output for (int32_t iPt = 0; iPt < npts; iPt++ ){ // assign df/derho - vrho[2*iPt] += protonic_vrho[2*iPt]; - vrho[2*iPt+1] += protonic_vrho[2*iPt]; + vrho[spin_dim_scal*iPt] += protonic_vrho[2*iPt]; + if(not is_rks) vrho[spin_dim_scal*iPt+1] += protonic_vrho[2*iPt]; // assign df/dprho protonic_vrho[2*iPt] = protonic_vrho[2*iPt+1]; protonic_vrho[2*iPt+1] = 0.0; @@ -583,10 +579,10 @@ void ReferenceReplicatedXCHostIntegrator:: *elec_EXC = EXC_WORK + EPC_WORK; *prot_EXC = EPC_WORK; - std::cout << "N_EL = " << std::setprecision(12) << std::scientific << *N_EL << std::endl; - std::cout << "N_PROT = " << std::setprecision(12) << std::scientific << *N_PROT << std::endl; - std::cout << "elec_EXC = " << std::setprecision(12) << std::scientific << *elec_EXC << std::endl; - std::cout << "prot_EXC = " << std::setprecision(12) << std::scientific << *prot_EXC << std::endl; + //std::cout << "N_EL = " << std::setprecision(12) << std::scientific << *N_EL << std::endl; + //std::cout << "N_PROT = " << std::setprecision(12) << std::scientific << *N_PROT << std::endl; + //std::cout << "elec_EXC = " << std::setprecision(12) << std::scientific << *elec_EXC << std::endl; + //std::cout << "prot_EXC = " << std::setprecision(12) << std::scientific << *prot_EXC << std::endl; // Symmetrize Electronic VXC for( int32_t j = 0; j < nbf; ++j ) From 236370d844f03c22f64dde6972e8c5d5deb6670f Mon Sep 17 00:00:00 2001 From: Aodong Liu Date: Mon, 29 Apr 2024 13:57:32 -0700 Subject: [PATCH 41/49] fix logic bug where elec den overwrites prot den in epc --- .../reference_replicated_xc_host_integrator_exc_vxc_neo.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp index 3737153a..96133251 100644 --- a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp +++ b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp @@ -438,8 +438,8 @@ void ReferenceReplicatedXCHostIntegrator:: // Prepare for kernal input for (int32_t iPt = 0; iPt < npts; iPt++ ){ // Treat total erho as spin-up, treat total prho as spin down - protonic_den_eval[2*iPt] = is_rks ? den_eval[iPt] : (den_eval[2*iPt] + den_eval[2*iPt+1]); protonic_den_eval[2*iPt+1] = protonic_den_eval[2*iPt] + protonic_den_eval[2*iPt+1]; + protonic_den_eval[2*iPt] = is_rks ? den_eval[iPt] : (den_eval[2*iPt] + den_eval[2*iPt+1]); } // EPC Functional Evaluation (Calling ExchCXX Builtin Function) @@ -457,7 +457,6 @@ void ReferenceReplicatedXCHostIntegrator:: protonic_den_eval[2*iPt] = protonic_den_eval[2*iPt+1]; protonic_den_eval[2*iPt] = 0.0; } - } // End if(evalProtonic) //----------------------End EPC functional Evaluation--------------------------------------- From 15a44930868bccde2e551a4312549678248b2ba4 Mon Sep 17 00:00:00 2001 From: aodongliu Date: Thu, 2 May 2024 17:14:02 -0700 Subject: [PATCH 42/49] remove unwanted changes --- CMakeLists.txt | 2 +- include/gauxc/load_balancer.hpp | 4 ---- src/atomic_radii.cxx | 3 +-- src/load_balancer/load_balancer.cxx | 8 -------- src/load_balancer/load_balancer_impl.cxx | 10 ---------- src/load_balancer/load_balancer_impl.hpp | 3 --- .../replicated/replicated_xc_integrator_impl.cxx | 2 +- 7 files changed, 3 insertions(+), 29 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2de9f4de..0a4419bc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,7 +30,7 @@ endif() option( GAUXC_ENABLE_HOST "Enable Host Integrator" ON ) option( GAUXC_ENABLE_CUDA "Enable CUDA Bindings" OFF ) option( GAUXC_ENABLE_HIP "Enable HIP Bindings" OFF ) -option( GAUXC_ENABLE_MPI "Enable MPI Bindings" OFF ) +option( GAUXC_ENABLE_MPI "Enable MPI Bindings" ON ) option( GAUXC_ENABLE_OPENMP "Enable OpenMP Compilation" ON ) option( GAUXC_ENABLE_TESTS "Enable Unit Tests" ON ) option( GAUXC_ENABLE_GAU2GRID "Enable Gau2Grid Collocation" ON ) diff --git a/include/gauxc/load_balancer.hpp b/include/gauxc/load_balancer.hpp index 25aa0072..c6ee62e7 100644 --- a/include/gauxc/load_balancer.hpp +++ b/include/gauxc/load_balancer.hpp @@ -108,10 +108,6 @@ class LoadBalancer { /// Return the protonic BasisSetMap instance corresponding to protonic basis/molecule const basis_map_type& protonic_basis_map() const; - /// Return the number of protonic non-negligible local shell pairs for this LoadBalancer - const shell_pair_type& protonic_shell_pairs() const; - const shell_pair_type& protonic_shell_pairs(); - /// Return the runtime handle used to construct this LoadBalancer const RuntimeEnvironment& runtime() const; diff --git a/src/atomic_radii.cxx b/src/atomic_radii.cxx index 4944a091..6e3a829f 100644 --- a/src/atomic_radii.cxx +++ b/src/atomic_radii.cxx @@ -35,8 +35,7 @@ double slater_radius_64(AtomicNumber _Z) { auto Z = _Z.get(); switch(Z) { - //case 1: /* H */ return pm_to_bohr(25. ); - case 1: /* H */ return pm_to_bohr(52.9 ); + case 1: /* H */ return pm_to_bohr(25. ); //case 2: /* He */ return pm_to_bohr(120.); case 3: /* Li */ return pm_to_bohr(145.); case 4: /* Be */ return pm_to_bohr(105.); diff --git a/src/load_balancer/load_balancer.cxx b/src/load_balancer/load_balancer.cxx index 313303ea..aad80ddd 100644 --- a/src/load_balancer/load_balancer.cxx +++ b/src/load_balancer/load_balancer.cxx @@ -101,14 +101,6 @@ const LoadBalancer::basis_map_type& LoadBalancer::protonic_basis_map() const { if( not pimpl_ ) GAUXC_PIMPL_NOT_INITIALIZED(); return pimpl_->protonic_basis_map(); } -const LoadBalancer::shell_pair_type& LoadBalancer::protonic_shell_pairs() const { - if( not pimpl_ ) GAUXC_PIMPL_NOT_INITIALIZED(); - return pimpl_->protonic_shell_pairs(); -} -const LoadBalancer::shell_pair_type& LoadBalancer::protonic_shell_pairs() { - if( not pimpl_ ) GAUXC_PIMPL_NOT_INITIALIZED(); - return pimpl_->protonic_shell_pairs(); -} LoadBalancerState& LoadBalancer::state() { if( not pimpl_ ) GAUXC_PIMPL_NOT_INITIALIZED(); diff --git a/src/load_balancer/load_balancer_impl.cxx b/src/load_balancer/load_balancer_impl.cxx index 742ab06f..ce1722e0 100644 --- a/src/load_balancer/load_balancer_impl.cxx +++ b/src/load_balancer/load_balancer_impl.cxx @@ -149,16 +149,6 @@ const LoadBalancerImpl::basis_map_type& LoadBalancerImpl::protonic_basis_map() c GAUXC_GENERIC_EXCEPTION("No Protonic Basis Found in LoadBalancerImpl::protonic_basis_map()"); return *protonic_basis_map_; } -const LoadBalancerImpl::shell_pair_type& LoadBalancerImpl::protonic_shell_pairs() const { - if(!protonic_shell_pairs_) GAUXC_GENERIC_EXCEPTION("No Protonic Basis Found in LoadBalancerImpl::protonic_shell_pairs()"); - return *shell_pairs_; -} -const LoadBalancerImpl::shell_pair_type& LoadBalancerImpl::protonic_shell_pairs() { - if(!protonic_shell_pairs_) { - protonic_shell_pairs_ = std::make_shared(*protonic_basis_); - } - return *protonic_shell_pairs_; -} const RuntimeEnvironment& LoadBalancerImpl::runtime() const { return runtime_; diff --git a/src/load_balancer/load_balancer_impl.hpp b/src/load_balancer/load_balancer_impl.hpp index 467e3524..d2c68086 100644 --- a/src/load_balancer/load_balancer_impl.hpp +++ b/src/load_balancer/load_balancer_impl.hpp @@ -31,7 +31,6 @@ class LoadBalancerImpl { std::shared_ptr shell_pairs_; // Protonic basis information if doing Nuclear-Electronic Orbital (NEO) theory std::shared_ptr protonic_basis_; - std::shared_ptr protonic_shell_pairs_; std::shared_ptr protonic_basis_map_; std::vector< XCTask > local_tasks_; @@ -87,8 +86,6 @@ class LoadBalancerImpl { const shell_pair_type& shell_pairs(); const basis_type& protonic_basis() const; const basis_map_type& protonic_basis_map() const; - const shell_pair_type& protonic_shell_pairs() const; - const shell_pair_type& protonic_shell_pairs(); LoadBalancerState& state(); diff --git a/src/xc_integrator/replicated/replicated_xc_integrator_impl.cxx b/src/xc_integrator/replicated/replicated_xc_integrator_impl.cxx index 7b75e940..5f42908a 100644 --- a/src/xc_integrator/replicated/replicated_xc_integrator_impl.cxx +++ b/src/xc_integrator/replicated/replicated_xc_integrator_impl.cxx @@ -28,7 +28,7 @@ ReplicatedXCIntegratorImpl:: std::shared_ptr< ReductionDriver > rd) : ReplicatedXCIntegratorImpl(func, lb, std::move(lwd), rd) { epcfunc_ = epcfunc; - } +} template ReplicatedXCIntegratorImpl:: From a9d49fe2575ad80c106fad62d9e4d6c221299d94 Mon Sep 17 00:00:00 2001 From: aodongliu Date: Fri, 3 May 2024 16:00:23 -0700 Subject: [PATCH 43/49] update exchcxx version in cmake --- cmake/gauxc-dep-versions.cmake | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cmake/gauxc-dep-versions.cmake b/cmake/gauxc-dep-versions.cmake index 2ca8beb2..265b92c1 100644 --- a/cmake/gauxc-dep-versions.cmake +++ b/cmake/gauxc-dep-versions.cmake @@ -10,10 +10,8 @@ set( GAUXC_CUB_REVISION 1.10.0 ) set( GAUXC_CUTLASS_REPOSITORY https://github.com/NVIDIA/cutlass.git ) set( GAUXC_CUTLASS_REVISION v2.10.0 ) -#set( GAUXC_EXCHCXX_REPOSITORY https://github.com/wavefunction91/ExchCXX.git ) -#set( GAUXC_EXCHCXX_REVISION 21a4700a826ec0beae1311a1d59677393bcb168f ) -set( GAUXC_EXCHCXX_REPOSITORY https://github.com/aodongliu/ExchCXX.git ) -set( GAUXC_EXCHCXX_REVISION 840403f14c7e5abd6b6a3f2126c3ce38d3fe8cf9 ) +set( GAUXC_EXCHCXX_REPOSITORY https://github.com/wavefunction91/ExchCXX.git ) +set( GAUXC_EXCHCXX_REVISION ef88e168249e38c526353fe7c48aab4bc697c99d ) set( GAUXC_GAU2GRID_REPOSITORY https://github.com/dgasmith/gau2grid.git ) set( GAUXC_GAU2GRID_REVISION v2.0.6 ) From e0bb9e7206eca77c5336c309c5795d5fd10d8f8d Mon Sep 17 00:00:00 2001 From: aodongliu Date: Tue, 7 May 2024 16:54:53 -0700 Subject: [PATCH 44/49] modifying NEO tests --- ...licated_xc_host_integrator_exc_vxc_neo.hpp | 60 +++++++++++++++++++ tests/xc_integrator.cxx | 17 +++--- 2 files changed, 70 insertions(+), 7 deletions(-) diff --git a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp index 96133251..2fe0d2dc 100644 --- a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp +++ b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp @@ -11,6 +11,8 @@ #include "integrator_util/integrator_common.hpp" #include "host/local_host_work_driver.hpp" #include "host/blas.hpp" +#include +#include #include namespace GauXC { @@ -603,6 +605,64 @@ void ReferenceReplicatedXCHostIntegrator:: } } + // Create File + //std::remove("GAUXC.BIN"); + auto outfname = "NEOGAUXC.BIN"; + { HighFive::File( outfname, HighFive::File::Truncate ); } + // Write molecule + write_hdf5_record( mol, outfname, "/MOLECULE" ); + + // Electronic Part + write_hdf5_record( basis, outfname, "/BASIS" ); + + HighFive::File file( outfname, HighFive::File::ReadWrite ); + HighFive::DataSpace mat_space( basis.nbf(), basis.nbf() ); + HighFive::DataSpace sca_space( 1 ); + + std::string den = is_rks ? "/DENSITY" : "/DENSITY_SCALAR"; + std::string den2 = "/DENSITY_Z"; + std::string vxc = is_rks ? "/VXC" : "/VXC_SCALAR"; + std::string vxc2 = "VXC_Z"; + + auto dset = file.createDataSet( den, mat_space ); + dset.write_raw( elec_Ps ); + dset = file.createDataSet( vxc, mat_space ); + dset.write_raw( elec_VXCs ); + if(not is_rks) { + dset = file.createDataSet( den2, mat_space ); + dset.write_raw( elec_Pz ); + dset = file.createDataSet( vxc2, mat_space ); + dset.write_raw( elec_VXCz ); + } + + dset = file.createDataSet( "/EXC", sca_space ); + dset.write_raw( elec_EXC ); + + + + // Protonic Part + write_hdf5_record( protonic_basis, outfname, "/PROTONIC_BASIS" ); + + den = "/PROTONIC_DENSITY_SCALAR"; + den2 = "/PROTONIC_DENSITY_Z"; + vxc = "/PROTONIC_VXC_SCALAR"; + vxc2 = "/PROTONIC_VXC_Z"; + dset = file.createDataSet( den, mat_space ); + dset.write_raw( prot_Ps ); + dset = file.createDataSet( vxc, mat_space ); + dset.write_raw( prot_VXCs ); + + dset = file.createDataSet( den2, mat_space ); + dset.write_raw( prot_Pz ); + dset = file.createDataSet( vxc2, mat_space ); + dset.write_raw( prot_VXCz ); + + dset = file.createDataSet( "/PROTONIC_EXC", sca_space ); + dset.write_raw( prot_EXC ); + + + + } diff --git a/tests/xc_integrator.cxx b/tests/xc_integrator.cxx index d5635e8f..095a6ba7 100644 --- a/tests/xc_integrator.cxx +++ b/tests/xc_integrator.cxx @@ -22,7 +22,7 @@ using namespace GauXC; void test_xc_integrator( ExecutionSpace ex, const RuntimeEnvironment& rt, std::string reference_file, - functional_type& func, + std::shared_ptr func, PruningScheme pruning_scheme, bool check_grad, bool check_integrate_den, @@ -200,7 +200,7 @@ void test_xc_integrator( ExecutionSpace ex, const RuntimeEnvironment& rt, // Construct XCIntegrator XCIntegratorFactory integrator_factory( ex, "Replicated", integrator_kernel, lwd_kernel, reduction_kernel ); - auto integrator = integrator_factory.get_instance( func, *lb ); + auto integrator = integrator_factory.get_instance( *func, *lb ); // Integrate Density if( check_integrate_den and rks) { @@ -354,7 +354,7 @@ void test_xc_integrator( ExecutionSpace ex, const RuntimeEnvironment& rt, } -void test_integrator(std::string reference_file, functional_type& func, PruningScheme pruning_scheme) { +void test_integrator(std::string reference_file, std::shared_ptr func, PruningScheme pruning_scheme) { #ifdef GAUXC_HAS_DEVICE auto rt = DeviceRuntimeEnvironment(GAUXC_MPI_CODE(MPI_COMM_WORLD,) 0.9); @@ -420,8 +420,8 @@ void test_integrator(std::string reference_file, functional_type& func, PruningS } -functional_type make_functional(ExchCXX::Functional func_key, ExchCXX::Spin spin) { - return functional_type(ExchCXX::Backend::builtin, func_key, spin); +std::shared_ptr make_functional(ExchCXX::Functional func_key, ExchCXX::Spin spin) { + return std::make_shared(ExchCXX::Backend::builtin, func_key, spin); } @@ -434,6 +434,8 @@ TEST_CASE( "XC Integrator", "[xc-integrator]" ) { auto blyp = ExchCXX::Functional::BLYP; auto scan = ExchCXX::Functional::SCAN; auto r2scanl = ExchCXX::Functional::R2SCANL; + auto epc17_2 = ExchCXX::Functional::EPC17_2; + auto epc18_2 = ExchCXX::Functional::EPC18_2; // LDA Test SECTION( "Benzene / SVWN5 / cc-pVDZ" ) { @@ -532,14 +534,15 @@ TEST_CASE( "XC Integrator", "[xc-integrator]" ) { // NEO epc-17-2 Test (small basis) SECTION( "COH2 / BLYP,EPC-17-2 / sto-3g, prot-sp" ) { auto func = make_functional(blyp, unpol); + auto epcfunc = make_functional(epc17_2); test_integrator(GAUXC_REF_DATA_PATH "/coh2_blyp_epc17-2_sto-3g_protsp_ssf.hdf5", - func, PruningScheme::Unpruned ); + func, PruningScheme::Unpruned, epcfunc); } // NEO epc-17-2 Test (larger basis) SECTION( "COH2 / BLYP,EPC-17-2 / cc-pVDZ, prot-PB4-D" ) { auto func = make_functional(blyp, unpol); test_integrator(GAUXC_REF_DATA_PATH "/coh2_blyp_epc17-2_cc-pvdz_pb4d_ssf.hdf5", - func, PruningScheme::Unpruned ); + func, PruningScheme::Unpruned, epcfunc); } } From d95f1c902d39329de06bcea7e90b9f0937106824 Mon Sep 17 00:00:00 2001 From: Aodong Liu Date: Tue, 7 May 2024 18:20:25 -0700 Subject: [PATCH 45/49] modified tests to also be able to use epcfunctional --- tests/xc_integrator.cxx | 42 ++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/tests/xc_integrator.cxx b/tests/xc_integrator.cxx index 095a6ba7..60444537 100644 --- a/tests/xc_integrator.cxx +++ b/tests/xc_integrator.cxx @@ -29,7 +29,8 @@ void test_xc_integrator( ExecutionSpace ex, const RuntimeEnvironment& rt, bool check_k, std::string integrator_kernel = "Default", std::string reduction_kernel = "Default", - std::string lwd_kernel = "Default") { + std::string lwd_kernel = "Default", + std::shared_ptr epcfunc = nullptr) { // Read the reference file using matrix_type = Eigen::MatrixXd; @@ -200,13 +201,18 @@ void test_xc_integrator( ExecutionSpace ex, const RuntimeEnvironment& rt, // Construct XCIntegrator XCIntegratorFactory integrator_factory( ex, "Replicated", integrator_kernel, lwd_kernel, reduction_kernel ); - auto integrator = integrator_factory.get_instance( *func, *lb ); + std::unique_ptr> integrator; + if(neo){ + integrator = std::make_unique>( integrator_factory.get_instance(*func, *epcfunc, *lb) ); + }else{ + integrator = std::make_unique>( integrator_factory.get_instance(*func, *lb) ); + } // Integrate Density if( check_integrate_den and rks) { auto N_EL_ref = std::accumulate( mol.begin(), mol.end(), 0ul, [](const auto& a, const auto &b) { return a + b.Z.get(); }); - auto N_EL = integrator.integrate_den( P ); + auto N_EL = integrator->integrate_den( P ); // Factor of 2 b/c P is the alpha density for RKS CHECK( N_EL == Approx(N_EL_ref/2.0).epsilon(1e-6) ); } @@ -216,8 +222,8 @@ void test_xc_integrator( ExecutionSpace ex, const RuntimeEnvironment& rt, double EXC, protonic_EXC; matrix_type VXC, protonic_VXCs, protonic_VXCz; - if(neo) std::tie( EXC, protonic_EXC, VXC, protonic_VXCs, protonic_VXCz ) = integrator.neo_eval_exc_vxc( P, protonic_Ps, protonic_Pz ); - else std::tie( EXC, VXC ) = integrator.eval_exc_vxc( P ); + if(neo) std::tie( EXC, protonic_EXC, VXC, protonic_VXCs, protonic_VXCz ) = integrator->neo_eval_exc_vxc( P, protonic_Ps, protonic_Pz ); + else std::tie( EXC, VXC ) = integrator->eval_exc_vxc( P ); // Check EXC/VXC auto VXC_diff_nrm = ( VXC - VXC_ref ).norm(); @@ -237,8 +243,8 @@ void test_xc_integrator( ExecutionSpace ex, const RuntimeEnvironment& rt, double EXC1, protonic_EXC1; matrix_type VXC1, protonic_VXCs1, protonic_VXCz1; - if(neo) std::tie( EXC1, protonic_EXC1, VXC1, protonic_VXCs1, protonic_VXCz1 ) = integrator.neo_eval_exc_vxc( P, protonic_Ps, protonic_Pz ); - else std::tie( EXC1, VXC1 ) = integrator.eval_exc_vxc( P ); + if(neo) std::tie( EXC1, protonic_EXC1, VXC1, protonic_VXCs1, protonic_VXCz1 ) = integrator->neo_eval_exc_vxc( P, protonic_Ps, protonic_Pz ); + else std::tie( EXC1, VXC1 ) = integrator->eval_exc_vxc( P ); CHECK( EXC1 == Approx( EXC_ref ) ); auto VXC1_diff_nrm = ( VXC1 - VXC_ref ).norm(); @@ -257,8 +263,8 @@ void test_xc_integrator( ExecutionSpace ex, const RuntimeEnvironment& rt, double EXC, protonic_EXC; matrix_type VXC, VXCz, protonic_VXCs, protonic_VXCz; - if(neo) std::tie( EXC, protonic_EXC, VXC, VXCz, protonic_VXCs, protonic_VXCz ) = integrator.neo_eval_exc_vxc( P, Pz, protonic_Ps, protonic_Pz ); - else std::tie( EXC, VXC, VXCz ) = integrator.eval_exc_vxc( P, Pz ); + if(neo) std::tie( EXC, protonic_EXC, VXC, VXCz, protonic_VXCs, protonic_VXCz ) = integrator->neo_eval_exc_vxc( P, Pz, protonic_Ps, protonic_Pz ); + else std::tie( EXC, VXC, VXCz ) = integrator->eval_exc_vxc( P, Pz ); // Check EXC/VXC auto VXC_diff_nrm = ( VXC - VXC_ref ).norm(); @@ -280,8 +286,8 @@ void test_xc_integrator( ExecutionSpace ex, const RuntimeEnvironment& rt, double EXC1, protonic_EXC1; matrix_type VXC1, VXCz1, protonic_VXCs1, protonic_VXCz1; - if(neo) std::tie( EXC1, protonic_EXC1, VXC1, VXCz1, protonic_VXCs1, protonic_VXCz1 ) = integrator.neo_eval_exc_vxc( P, Pz, protonic_Ps, protonic_Pz ); - else std::tie( EXC1, VXC1, VXCz1 ) = integrator.eval_exc_vxc( P, Pz ); + if(neo) std::tie( EXC1, protonic_EXC1, VXC1, VXCz1, protonic_VXCs1, protonic_VXCz1 ) = integrator->neo_eval_exc_vxc( P, Pz, protonic_Ps, protonic_Pz ); + else std::tie( EXC1, VXC1, VXCz1 ) = integrator->eval_exc_vxc( P, Pz ); auto VXC1_diff_nrm = ( VXC1 - VXC_ref ).norm(); auto VXCz1_diff_nrm = ( VXCz1 - VXCz_ref ).norm(); @@ -299,7 +305,7 @@ void test_xc_integrator( ExecutionSpace ex, const RuntimeEnvironment& rt, } } else if (gks) { - auto [ EXC, VXC, VXCz, VXCy, VXCx ] = integrator.eval_exc_vxc( P, Pz, Py, Px ); + auto [ EXC, VXC, VXCz, VXCy, VXCx ] = integrator->eval_exc_vxc( P, Pz, Py, Px ); // Check EXC/VXC auto VXC_diff_nrm = ( VXC - VXC_ref ).norm(); @@ -314,7 +320,7 @@ void test_xc_integrator( ExecutionSpace ex, const RuntimeEnvironment& rt, CHECK( VXCx_diff_nrm / basis.nbf() < 1e-10 ); // Check if the integrator propagates state correctly { - auto [ EXC1, VXC1, VXCz1, VXCy1, VXCx1] = integrator.eval_exc_vxc( P, Pz, Py, Px ); + auto [ EXC1, VXC1, VXCz1, VXCy1, VXCx1] = integrator->eval_exc_vxc( P, Pz, Py, Px ); CHECK( EXC1 == Approx( EXC_ref ) ); auto VXC1_diff_nrm = ( VXC1 - VXC_ref ).norm(); auto VXCz1_diff_nrm = ( VXCz1 - VXCz_ref ).norm(); @@ -332,7 +338,7 @@ void test_xc_integrator( ExecutionSpace ex, const RuntimeEnvironment& rt, // Check EXC Grad if( check_grad and has_exc_grad and rks) { - auto EXC_GRAD = integrator.eval_exc_grad( P ); + auto EXC_GRAD = integrator->eval_exc_grad( P ); using map_type = Eigen::Map; map_type EXC_GRAD_ref_map( EXC_GRAD_ref.data(), mol.size(), 3 ); map_type EXC_GRAD_map( EXC_GRAD.data(), mol.size(), 3 ); @@ -347,14 +353,15 @@ void test_xc_integrator( ExecutionSpace ex, const RuntimeEnvironment& rt, std::cout << "Skiping device sn-K + L > 2" << std::endl; return; } - auto K = integrator.eval_exx( P ); + auto K = integrator->eval_exx( P ); CHECK((K - K.transpose()).norm() < std::numeric_limits::epsilon()); // Symmetric CHECK( (K - K_ref).norm() / basis.nbf() < 1e-7 ); } } -void test_integrator(std::string reference_file, std::shared_ptr func, PruningScheme pruning_scheme) { +void test_integrator(std::string reference_file, std::shared_ptr func, PruningScheme pruning_scheme, + std::shared_ptr epcfunc = nullptr) { #ifdef GAUXC_HAS_DEVICE auto rt = DeviceRuntimeEnvironment(GAUXC_MPI_CODE(MPI_COMM_WORLD,) 0.9); @@ -534,7 +541,7 @@ TEST_CASE( "XC Integrator", "[xc-integrator]" ) { // NEO epc-17-2 Test (small basis) SECTION( "COH2 / BLYP,EPC-17-2 / sto-3g, prot-sp" ) { auto func = make_functional(blyp, unpol); - auto epcfunc = make_functional(epc17_2); + auto epcfunc = make_functional(epc17_2, pol); test_integrator(GAUXC_REF_DATA_PATH "/coh2_blyp_epc17-2_sto-3g_protsp_ssf.hdf5", func, PruningScheme::Unpruned, epcfunc); } @@ -542,6 +549,7 @@ TEST_CASE( "XC Integrator", "[xc-integrator]" ) { // NEO epc-17-2 Test (larger basis) SECTION( "COH2 / BLYP,EPC-17-2 / cc-pVDZ, prot-PB4-D" ) { auto func = make_functional(blyp, unpol); + auto epcfunc = make_functional(epc17_2, pol); test_integrator(GAUXC_REF_DATA_PATH "/coh2_blyp_epc17-2_cc-pvdz_pb4d_ssf.hdf5", func, PruningScheme::Unpruned, epcfunc); } From 1e46e2b26a0c9de0055139bb99d0356196677ad8 Mon Sep 17 00:00:00 2001 From: Aodong Liu Date: Wed, 8 May 2024 09:59:59 -0700 Subject: [PATCH 46/49] fix problems --- ...licated_xc_host_integrator_exc_vxc_neo.hpp | 9 +- tests/xc_integrator.cxx | 200 +++++++++--------- 2 files changed, 106 insertions(+), 103 deletions(-) diff --git a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp index 2fe0d2dc..a8ee2b9f 100644 --- a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp +++ b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp @@ -641,20 +641,21 @@ void ReferenceReplicatedXCHostIntegrator:: // Protonic Part + HighFive::DataSpace protonic_mat_space( protonic_basis.nbf(), protonic_basis.nbf() ); write_hdf5_record( protonic_basis, outfname, "/PROTONIC_BASIS" ); den = "/PROTONIC_DENSITY_SCALAR"; den2 = "/PROTONIC_DENSITY_Z"; vxc = "/PROTONIC_VXC_SCALAR"; vxc2 = "/PROTONIC_VXC_Z"; - dset = file.createDataSet( den, mat_space ); + dset = file.createDataSet( den, protonic_mat_space ); dset.write_raw( prot_Ps ); - dset = file.createDataSet( vxc, mat_space ); + dset = file.createDataSet( vxc, protonic_mat_space ); dset.write_raw( prot_VXCs ); - dset = file.createDataSet( den2, mat_space ); + dset = file.createDataSet( den2, protonic_mat_space ); dset.write_raw( prot_Pz ); - dset = file.createDataSet( vxc2, mat_space ); + dset = file.createDataSet( vxc2, protonic_mat_space ); dset.write_raw( prot_VXCz ); dset = file.createDataSet( "/PROTONIC_EXC", sca_space ); diff --git a/tests/xc_integrator.cxx b/tests/xc_integrator.cxx index 60444537..76a7364f 100644 --- a/tests/xc_integrator.cxx +++ b/tests/xc_integrator.cxx @@ -172,6 +172,8 @@ void test_xc_integrator( ExecutionSpace ex, const RuntimeEnvironment& rt, for( auto& sh : basis ) sh.set_shell_tolerance( std::numeric_limits::epsilon() ); + + std::cout << "std::numeric_limits::epsilon(): " << std::numeric_limits::epsilon() << std::endl; auto mg = MolGridFactory::create_default_molgrid(mol, pruning_scheme, BatchSize(512), RadialQuad::MuraKnowles, AtomicGridSizeDefault::UltraFineGrid); @@ -372,7 +374,7 @@ void test_integrator(std::string reference_file, std::shared_ptr Date: Wed, 8 May 2024 14:09:00 -0700 Subject: [PATCH 47/49] added epc tests --- .../coh2_blyp_epc17-2_cc-pvdz_pb4d_ssf.hdf5 | Bin 119824 -> 119824 bytes ...oh2_blyp_epc17-2_cc-pvdz_pb4d_ssf_uks.hdf5 | Bin 0 -> 113856 bytes .../coh2_blyp_epc17-2_sto-3g_protsp_ssf.hdf5 | Bin 20616 -> 20112 bytes .../coh2_blyp_epc18-2_cc-pvdz_pb4d_ssf.hdf5 | Bin 0 -> 119824 bytes tests/xc_integrator.cxx | 221 ++++++++++-------- 5 files changed, 118 insertions(+), 103 deletions(-) create mode 100644 tests/ref_data/coh2_blyp_epc17-2_cc-pvdz_pb4d_ssf_uks.hdf5 create mode 100644 tests/ref_data/coh2_blyp_epc18-2_cc-pvdz_pb4d_ssf.hdf5 diff --git a/tests/ref_data/coh2_blyp_epc17-2_cc-pvdz_pb4d_ssf.hdf5 b/tests/ref_data/coh2_blyp_epc17-2_cc-pvdz_pb4d_ssf.hdf5 index 486c538e27c273031f2d70a8cea5642fdb03ca68..dfa796583042809e8df2c9c6e4f340803872c153 100644 GIT binary patch literal 119824 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 WpqigW-rznH=d{wrk==S^D*p%k;YNZ0 diff --git a/tests/ref_data/coh2_blyp_epc17-2_cc-pvdz_pb4d_ssf_uks.hdf5 b/tests/ref_data/coh2_blyp_epc17-2_cc-pvdz_pb4d_ssf_uks.hdf5 new file mode 100644 index 0000000000000000000000000000000000000000..08d65f7e912f9b1606108de7edc1f027cec403b1 GIT binary patch literal 113856 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%0AB}w19TAh8F&Nm40V3m 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ð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 literal 0 HcmV?d00001 diff --git a/tests/ref_data/coh2_blyp_epc17-2_sto-3g_protsp_ssf.hdf5 b/tests/ref_data/coh2_blyp_epc17-2_sto-3g_protsp_ssf.hdf5 index b15044092c79be1df9933f039ac7388220321347..52c934fc4eafb27d6f88a6e70e324f85fdcc371c 100644 GIT binary patch literal 20112 zcmeHP3p`cX{@=%A5+zC_G-c9AHN6m_Z5>36HxIfHm+ak8%)>vqd<-$aK0~9!dca1!-ilV z{{XL0U#<;kUzokTDx&K!32hlddr+JpmJ9fRe*GCAE&@JaF8>)Hk{o1Q#>B+Lc*IH3 zJc=_^W%zz}eBf>@-4kx*gGB~@jyAT77#wDxZ8mN7fzf*jRXW}_^}WpBiOz+*X%PAS z5V%+6a4Nb)42T#IF(6{#zn_6m=q|pl-t~=tVKyGO{meYAN4F64ocA!}Bz&T!_1Wbw zkiqD#)n^)BW5Mz%Jr?I$WyQ(_?cup1oAJxlKHWaVo|Z?-C5titY0qDOIMWRYu0OyY zLUE#(_ncMd0N3EG!ENjuEUal~@2@Sa=sfOPt;9V`}GaNafKIM}&1+~+;F9eC{iUOSv(&MHmV z`hq=nI5huzyDNm z22)pR`s@h9QOtsZO5U~sci-&Ic7lkb(`@AdWo~*0vsL12P6(HC_dQ-(p`e}nc;)Q8 z@voSP{Q7ZpNM{pA1=5f|i;fKK*9q8bu&?oOO}H{blG{F;E?4E)ao@ee-v0O>!=Wjv+H}^|0lWpYB8cceMR2B7k{=rVrFW`WF znZ@(*fE`#-LyEVHX;a;MVjmqy`Nao$UPfQFzdn ztN8RBS^sF?8z{?1_k~X0Rgq3O6NES6>4`Gjb#m@+lS3}}JVTcC#SPc>+L8Dkqsmi_ z=S4b!8z~(ga~bG+;wQtD7hm{X>2)V!uJkM)oqBE9+)qmOw03<}Qjc0B79292T92e( zDpW zoVE5XL!LRKscrJxU^(Ui*;nk{J6{c(=Z>)bPC=c-Egrw7?{fvF*XBUKlSO?fAgVyw z(z$uqJa?8RjcOX7c@rC`Tb;kKtq~nus~)+(=cY&}0_)h}u9Kv3o33Zv`~^+W%vN2~ z+KaRwuYEJt?b@){34{2A|Gq=N^e_kw-insNKZZbzqSv>=LUGO)2(Ia$|L)NCCExW9 z-u?&O4Ds9V4y&Q)KN5aCK0N3B|KNjv!UWFuz`HVp|AHRo^ZO59>iDVO>LKhuq61-# zz95Q@Gx3Z7@`rpKB6!9WX+^Zzst!B|-Mf7fA*AwBl6<;zP7;vu=fl0orC;r3LiuG}F!{;IIdUvCz#MEp$%saYV?WWe4|1Z$ z@0NUA(2^or>c_m=&iYqyjnnIADCB;j#+Ab`EzSI zS`e~E`V_GV*+**5)3m1W+?uKmyNnXto+(>o>{o%8r6np2n!A&L7yNFY%FqkjbQ=Xm z&GijRK922Dr>7}CP9n>7`;PA(z$kZGzMcEMI_%v2+*#5t5}$f^B;v=+uW`AzOG=fO z8MYe{{RLW6fuqe@Op=Zu5G>3S8OJTDN>#H9n-~?E0%o0tx&A4}cf^%57}0 z+#}nJqWsh|%bjva*IQz~-j&%@{-iPA7>T)1cCI^s-I30(<1Pf5FNn z$0%ZEgl@+qZ!`-j-1KscX;v7lvz4K!Z;GS5+H=5{aIbJ$V# z@v<^h+NHBv(xnFd6yw+7p~#|OUVwf(%%)5FyCNafPO(|pa&Q?;1_rRyx=#xvdw8@LMQURry`>jnnl4phWQ5b0`v*&tSydb(ypY;7YZ)6_m=J=Q_jnfmif4Huz_ z$9h(59-~Zk?yWi!Zdrtt!oRxuFtHH->hX3(n{)EzXiJy6wB`)#a3s(txbkmk>8g$D z#yw|HPOy#pn2ht6z;9h=Zl7Xa2Y$EJ#v$lQG%lJqG2@xuA#7lfqi?y(hWfk3(X+2- z*5fn#3p)miYjL0U_lo(Sz>Bc3yvD9?$l#OmdRLVjh`4y|mu(!@QpYZw`^r?ZdlXXWfR&%-F z;Pj{*@0%GI_UvFXc2QTDDDmnFDm@)$f;<;ezysg~zml)F2EN$PiCw)F5mU%cX^`|-=Witxah$v5T%+``wMnv{Rvdj;j18c!+?y@IAo`Ma6z zWs<-z@Bnzh@1FF|gUv?m7~ihVt3SSqYN#G19`>^vSuJs5!l9;`g}2J{8{|IAzOUg z?7Jxq(ubemHG8XC>eM!%BMS=;+d6HbV7|e;0R4i_Ko2l(z%TFsc)@RKLFSz1;3wGP z#c|7xcY;Wm$1vYuUVwf1=#CD{{Sbn2X+_Dew3{Fr3bawMyOwiNk9vX`v&K( ziAC<8f8~6z>){YD&_BQl?SWlwV~?T+L85tTNl}_pv`}L7L(?_kQ55hw#0%X&zzOYv zooDk|8GAGx-A&MUZk$ly}I z3GIR1r1c}c#doG+&V5kjCM&a4jMx$OifSq4{Dsr3$yycqRf`_2b-$`bLH__JvcKR%fF z&M->*(V6Ae_CtIEFVH{03GIPh-V4i#gUQEmM0(J()LqS&U>tx?;05{zIH5hTTQa-aIU}9_fY=-cQJxkz{f_&Y0wcNfjONY zHeE;sD5t|1?jPp%2=0{Xa%YeK2Cb{Z9RH&%1m8PLvQaAY$O7Fd*eM{+d#A8U6=?qH{0+ literal 20616 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 diff --git a/tests/ref_data/coh2_blyp_epc18-2_cc-pvdz_pb4d_ssf.hdf5 b/tests/ref_data/coh2_blyp_epc18-2_cc-pvdz_pb4d_ssf.hdf5 new file mode 100644 index 0000000000000000000000000000000000000000..f1dfb03c0b9063f0f9620836e59d50b791168cea GIT binary patch literal 119824 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 z Date: Wed, 8 May 2024 13:51:25 -0700 Subject: [PATCH 48/49] remove unwanted changes --- ...licated_xc_host_integrator_exc_vxc_neo.hpp | 54 ------------------- tests/xc_integrator.cxx | 2 - 2 files changed, 56 deletions(-) diff --git a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp index a8ee2b9f..04a0928e 100644 --- a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp +++ b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp @@ -605,61 +605,7 @@ void ReferenceReplicatedXCHostIntegrator:: } } - // Create File - //std::remove("GAUXC.BIN"); - auto outfname = "NEOGAUXC.BIN"; - { HighFive::File( outfname, HighFive::File::Truncate ); } - // Write molecule - write_hdf5_record( mol, outfname, "/MOLECULE" ); - - // Electronic Part - write_hdf5_record( basis, outfname, "/BASIS" ); - - HighFive::File file( outfname, HighFive::File::ReadWrite ); - HighFive::DataSpace mat_space( basis.nbf(), basis.nbf() ); - HighFive::DataSpace sca_space( 1 ); - - std::string den = is_rks ? "/DENSITY" : "/DENSITY_SCALAR"; - std::string den2 = "/DENSITY_Z"; - std::string vxc = is_rks ? "/VXC" : "/VXC_SCALAR"; - std::string vxc2 = "VXC_Z"; - - auto dset = file.createDataSet( den, mat_space ); - dset.write_raw( elec_Ps ); - dset = file.createDataSet( vxc, mat_space ); - dset.write_raw( elec_VXCs ); - if(not is_rks) { - dset = file.createDataSet( den2, mat_space ); - dset.write_raw( elec_Pz ); - dset = file.createDataSet( vxc2, mat_space ); - dset.write_raw( elec_VXCz ); - } - - dset = file.createDataSet( "/EXC", sca_space ); - dset.write_raw( elec_EXC ); - - - - // Protonic Part - HighFive::DataSpace protonic_mat_space( protonic_basis.nbf(), protonic_basis.nbf() ); - write_hdf5_record( protonic_basis, outfname, "/PROTONIC_BASIS" ); - - den = "/PROTONIC_DENSITY_SCALAR"; - den2 = "/PROTONIC_DENSITY_Z"; - vxc = "/PROTONIC_VXC_SCALAR"; - vxc2 = "/PROTONIC_VXC_Z"; - dset = file.createDataSet( den, protonic_mat_space ); - dset.write_raw( prot_Ps ); - dset = file.createDataSet( vxc, protonic_mat_space ); - dset.write_raw( prot_VXCs ); - - dset = file.createDataSet( den2, protonic_mat_space ); - dset.write_raw( prot_Pz ); - dset = file.createDataSet( vxc2, protonic_mat_space ); - dset.write_raw( prot_VXCz ); - dset = file.createDataSet( "/PROTONIC_EXC", sca_space ); - dset.write_raw( prot_EXC ); diff --git a/tests/xc_integrator.cxx b/tests/xc_integrator.cxx index 0abf0176..b20c692e 100644 --- a/tests/xc_integrator.cxx +++ b/tests/xc_integrator.cxx @@ -172,8 +172,6 @@ void test_xc_integrator( ExecutionSpace ex, const RuntimeEnvironment& rt, for( auto& sh : basis ) sh.set_shell_tolerance( std::numeric_limits::epsilon() ); - - std::cout << "std::numeric_limits::epsilon(): " << std::numeric_limits::epsilon() << std::endl; auto mg = MolGridFactory::create_default_molgrid(mol, pruning_scheme, BatchSize(512), RadialQuad::MuraKnowles, AtomicGridSizeDefault::UltraFineGrid); From ee0033821d06ecb625bb30d81073eab2e2f702ce Mon Sep 17 00:00:00 2001 From: aodongliu Date: Tue, 4 Jun 2024 09:59:40 -0700 Subject: [PATCH 49/49] swap alpha/beta prot den after epc --- .../reference_replicated_xc_host_integrator_exc_vxc_neo.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp index 4427b88a..6aa67471 100644 --- a/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp +++ b/src/xc_integrator/replicated/host/reference_replicated_xc_host_integrator_exc_vxc_neo.hpp @@ -460,7 +460,7 @@ void ReferenceReplicatedXCHostIntegrator:: protonic_vrho[2*iPt+1] = 0.0; // change back protonic density to original state protonic_den_eval[2*iPt] = protonic_den_eval[2*iPt+1]; - protonic_den_eval[2*iPt] = 0.0; + protonic_den_eval[2*iPt+1] = 0.0; } } // End if(evalProtonic) //----------------------End EPC functional Evaluation---------------------------------------