From 0683c11fd4f5f3aba5ec6a85afb3d338b3eec9d1 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Sun, 21 Apr 2024 17:03:27 +0200 Subject: [PATCH 01/54] update in mp3 --- src/madness/chem/CC2.cc | 12 +++++++++--- src/madness/chem/mp3.cc | 34 +++++++++++++++++----------------- src/madness/mra/macrotaskq.h | 12 +++++++++++- src/madness/world/cloud.h | 4 ++++ 4 files changed, 41 insertions(+), 21 deletions(-) diff --git a/src/madness/chem/CC2.cc b/src/madness/chem/CC2.cc index fd129ba6fbc..9221dc98063 100644 --- a/src/madness/chem/CC2.cc +++ b/src/madness/chem/CC2.cc @@ -479,10 +479,16 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { // calc update for pairs via macrotask auto taskq = std::shared_ptr(new MacroTaskQ(world, world.size())); - taskq->set_printlevel(3); - //taskq->cloud.set_debug(true); + taskq->set_printlevel(10); + taskq->cloud.set_debug(true); MacroTaskMp2UpdatePair t; MacroTask task1(world, t, taskq); + task1.set_debug(true); + for (const auto& p :pair_vec) { + print("pair",p.i,p.j); + p.function().print_size("pair_vec function before update macrotask is called"); + p.constant_part.print_size("pair_vec constant part before update macrotask is called"); + } std::vector u_update = task1(pair_vec, coupling_vec, parameters, nemo->get_calc()->molecule.get_all_coords_vec(), CCOPS.mo_ket().get_vecfunction(), CCOPS.mo_bra().get_vecfunction(), nemo->ncf->U1vec(), nemo->ncf->U2()); @@ -620,7 +626,7 @@ Pairs CC2::compute_local_coupling(const Pairs::get_thresh(); - coupling(i, j).truncate(thresh * 0.1).reduce_rank(); + coupling(i, j).truncate(thresh * 0.3).reduce_rank(); } } world.gop.fence(); diff --git a/src/madness/chem/mp3.cc b/src/madness/chem/mp3.cc index 6b781ee4abe..22398737121 100644 --- a/src/madness/chem/mp3.cc +++ b/src/madness/chem/mp3.cc @@ -971,26 +971,26 @@ double MP3::mp3_energy_contribution_macrotask_driver(const Pairs& mp2pai MacroTaskMP3 task_square("square"); MacroTask macrotask_triangular(world,task_triangular,taskq); MacroTask macrotask_square(world,task_square,taskq); - // auto ghij_future=macrotask_triangular(std::string("ghij"), ij_triangular, dummy, clusterfunc_vec, ket, bra, parameters, nemo_->molecule(), nemo_->R_square, std::vector()); + auto ghij_future=macrotask_triangular(std::string("ghij"), ij_triangular, dummy, clusterfunc_vec, ket, bra, parameters, nemo_->molecule(), nemo_->R_square, std::vector()); auto klmn_future=macrotask_square(std::string("klmn"), nact, nact, clusterfunc_vec, ket, bra, parameters, nemo_->molecule(), nemo_->R_square, std::vector()); - // auto cd_future=macrotask_triangular(std::string("cd"), ij_triangular, dummy, clusterfunc_vec, ket, bra, parameters, nemo_->molecule(), nemo_->R_square, std::vector()); - // auto ef_future=macrotask_triangular(std::string("ef"), ij_triangular, dummy, clusterfunc_vec, ket, bra, parameters, nemo_->molecule(), nemo_->R_square, std::vector()); - // taskq->print_taskq(); + auto cd_future=macrotask_triangular(std::string("cd"), ij_triangular, dummy, clusterfunc_vec, ket, bra, parameters, nemo_->molecule(), nemo_->R_square, std::vector()); + auto ef_future=macrotask_triangular(std::string("ef"), ij_triangular, dummy, clusterfunc_vec, ket, bra, parameters, nemo_->molecule(), nemo_->R_square, std::vector()); + taskq->print_taskq(); taskq->run_all(); - // double term_CD=cd_future->get(); - // double term_EF=ef_future->get(); - // double term_GHIJ=ghij_future->get(); - // double term_KLMN=klmn_future->get(); - // double mp3_energy=term_CD+term_GHIJ+term_KLMN+term_EF; - // if (world.rank()==0) { - // printf("term_CD %12.8f\n",term_CD); - // printf("term_GHIJ %12.8f\n",term_GHIJ); - // printf("term_KLMN %12.8f\n",term_KLMN); - // printf("term_EF %12.8f\n",term_EF); - // printf("MP3 energy contribution %12.8f\n",mp3_energy); - // } - // return mp3_energy; + double term_CD=cd_future->get(); + double term_EF=ef_future->get(); + double term_GHIJ=ghij_future->get(); + double term_KLMN=klmn_future->get(); + double mp3_energy=term_CD+term_GHIJ+term_KLMN+term_EF; + if (world.rank()==0) { + printf("term_CD %12.8f\n",term_CD); + printf("term_GHIJ %12.8f\n",term_GHIJ); + printf("term_KLMN %12.8f\n",term_KLMN); + printf("term_EF %12.8f\n",term_EF); + printf("MP3 energy contribution %12.8f\n",mp3_energy); + } + return mp3_energy; return 0.0; } } diff --git a/src/madness/mra/macrotaskq.h b/src/madness/mra/macrotaskq.h index f37b81d8846..0a1ae1de6ab 100644 --- a/src/madness/mra/macrotaskq.h +++ b/src/madness/mra/macrotaskq.h @@ -303,9 +303,11 @@ class MacroTaskQ : public WorldObject< MacroTaskQ> { print("redirecting output to files task.#####"); } - + double cpu0=cpu_time(); cloud.replicate(); universe.gop.fence(); + double cpu1=cpu_time(); + if (printtimings()) print("cloud replication wall time",cpu1-cpu0); if (printdebug()) cloud.print_size(universe); universe.gop.set_forbid_fence(true); // make sure there are no hidden universe fences pmap1=FunctionDefaults<1>::get_pmap(); @@ -363,6 +365,7 @@ class MacroTaskQ : public WorldObject< MacroTaskQ> { // cleanup task-persistent input data for (auto& task : taskq) task->cleanup(); cloud.clear_cache(subworld); + cloud.clear(); subworld.gop.fence(); subworld.gop.fence(); universe.gop.fence(); @@ -638,7 +641,14 @@ class MacroTask { const argtupleT argtuple = cloud.load(subworld, inputrecords); const argtupleT batched_argtuple = task.batch.template copy_input_batch(argtuple); try { + print("starting task no",element, "in subworld",subworld.id(),"at time",wall_time()); + double cpu0=cpu_time(); resultT result_tmp = std::apply(task, batched_argtuple); + double cpu1=cpu_time(); + std::size_t bufsize=256; + char buffer[bufsize]; + std::snprintf(buffer,bufsize,"completed task %3ld after %6.1fs at time %6.1fs\n",element,cpu1-cpu0,wall_time()); + print(std::string(buffer)); resultT result = get_output(subworld, cloud, argtuple); // lives in the universe if constexpr (is_madness_function::value) { diff --git a/src/madness/world/cloud.h b/src/madness/world/cloud.h index aba5f36ad38..73ac5d7e148 100644 --- a/src/madness/world/cloud.h +++ b/src/madness/world/cloud.h @@ -231,6 +231,10 @@ class Cloud { subworld.gop.fence(); } + void clear() { + container.clear(); + } + void clear_timings() { reading_time=0l; writing_time=0l; From 600c8b4f1532ad5555d53b8adcba7b0a83cca887 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Fri, 26 Apr 2024 14:05:15 +0200 Subject: [PATCH 02/54] customized cloud store/load for CCPair to avoid storing several large functions in the same cloud record (MPI count integer overflow) --- src/apps/cc2/cc2.cc | 4 +- src/madness/chem/CC2.cc | 40 ++++++++++++------ src/madness/chem/CC2.h | 5 ++- src/madness/chem/CCStructures.h | 34 +++++++++++++++ src/madness/mra/test_cloud.cc | 67 +++++++++++++++++++++++++++++ src/madness/world/cloud.h | 75 ++++++++++++++++++++++++++++----- 6 files changed, 199 insertions(+), 26 deletions(-) diff --git a/src/apps/cc2/cc2.cc b/src/apps/cc2/cc2.cc index 79f7d3864b7..8fe169735ae 100644 --- a/src/apps/cc2/cc2.cc +++ b/src/apps/cc2/cc2.cc @@ -79,8 +79,8 @@ int main(int argc, char **argv) { nemo->get_calc()->param.set_derived_value("print_level", 2); nemo->param.set_derived_value("k", 5); nemo->get_calc()->param.set_derived_value("k", 5); - nemo->param.set_derived_value("localize", "canon"); - nemo->get_calc()->param.set_derived_value("localize", "canon"); + // nemo->param.set_derived_value("localize", "canon"); + // nemo->get_calc()->param.set_derived_value("localize", "canon"); nemo->param.set_derived_values(nemo->molecule(),nemo->get_calc()->aobasis,parser); nemo->get_calc()->param.set_derived_values(nemo->molecule(),nemo->get_calc()->aobasis,parser); CC2 cc2(world, parser, nemo); diff --git a/src/madness/chem/CC2.cc b/src/madness/chem/CC2.cc index 9221dc98063..50099125606 100644 --- a/src/madness/chem/CC2.cc +++ b/src/madness/chem/CC2.cc @@ -458,9 +458,6 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { if (world.rank()==0) print_header3("Starting updating MP2 pairs"); - // create new pairs structure - Pairs updated_pairs; - for (auto& tmp_pair : pair_vec) updated_pairs.insert(tmp_pair.i, tmp_pair.j, tmp_pair); auto solver= nonlinear_vector_solver(world,pair_vec.size()); solver.set_maxsub(parameters.kain_subspace()); @@ -469,8 +466,14 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { for (size_t iter = 0; iter < parameters.iter_max_6D(); iter++) { + if (world.rank()==0) print("pair_vec before coupling"); + for (const auto& p :pair_vec) { + if (world.rank()==0) print("pair",p.i,p.j, p.function().get_impl()->get_tree_state()); + p.function().print_size("pair_vec function before coupling"); + p.constant_part.print_size("pair_vec constant part before coupling"); + } // compute the coupling between the pair functions - Pairs coupling=compute_local_coupling(updated_pairs); + Pairs coupling=compute_local_coupling(pair_vec); auto coupling_vec=Pairs::pairs2vector(coupling,triangular_map); if (parameters.debug()) print_size(world, coupling_vec, "couplingvector"); @@ -484,9 +487,12 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { MacroTaskMp2UpdatePair t; MacroTask task1(world, t, taskq); task1.set_debug(true); - for (const auto& p :pair_vec) { - print("pair",p.i,p.j); - p.function().print_size("pair_vec function before update macrotask is called"); + if (world.rank()==0) print("pair_vec before update"); + for (auto& p :pair_vec) { + if (world.rank()==0) print("pair",p.i,p.j, p.function().get_impl()->get_tree_state()); + p.function().print_size("pair_vec function before update"); // flodbg 2.0 GByte + p.function().change_tree_state(reconstructed); + p.function().print_size("pair_vec function before update after reconstruction"); // flodbg 2.0 GByte p.constant_part.print_size("pair_vec constant part before update macrotask is called"); } std::vector u_update = task1(pair_vec, coupling_vec, parameters, nemo->get_calc()->molecule.get_all_coords_vec(), @@ -513,6 +519,12 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { pair_vec[i].update_u(pair_vec[i].function() - u_update[i]); } } + if (world.rank()==0) print("pair_vec after update"); // flodbg 0.9 GByte + for (const auto& p :pair_vec) { + if (world.rank()==0) print("pair",p.i,p.j, p.function().get_impl()->get_tree_state()); + p.function().print_size("pair_vec function after KAIN update "); + p.constant_part.print_size("pair_vec constant part after KAIN update "); + } // calculate energy and error and update pairs double total_rnorm = 0.0, maxrnorm=0.0; @@ -532,8 +544,12 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { total_energy += energy; } - for (auto& tmp_pair : pair_vec) { - updated_pairs(tmp_pair.i, tmp_pair.j).update_u(tmp_pair.function()); + + if (world.rank()==0) print("pair_vec after energy computation"); // flodbg 0.3 GByte + for (const auto& p :pair_vec) { + if (world.rank()==0) print("pair",p.i,p.j, p.function().get_impl()->get_tree_state()); + p.function().print_size("pair_vec function after energy computation"); + p.constant_part.print_size("pair_vec constant part after energy computation"); } if (world.rank()==0) { @@ -553,11 +569,11 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { if (converged) { if (world.rank() == 0) std::cout << "\nPairs converged!\n"; if (world.rank() == 0) std::cout << "\nMP2 Pair Correlation Energies:\n"; - for (auto& pair : updated_pairs.allpairs) { - const double pair_energy = CCOPS.compute_pair_correlation_energy(pair.second); + for (auto& pair : pair_vec) { + const double pair_energy = CCOPS.compute_pair_correlation_energy(pair); if (world.rank() == 0) { std::cout << std::fixed << std::setprecision(10) << "omega_" - << pair.second.i << pair.second.j << "=" << pair_energy << "\n"; + << pair.i << pair.j << "=" << pair_energy << "\n"; } } if (world.rank() == 0) std::cout << "sum =" << total_energy << "\n"; diff --git a/src/madness/chem/CC2.h b/src/madness/chem/CC2.h index c5d13aba5c0..66781f7ef7b 100644 --- a/src/madness/chem/CC2.h +++ b/src/madness/chem/CC2.h @@ -473,7 +473,10 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { } /// forward to the other function (converting CCPair to real_function) - Pairs compute_local_coupling(const Pairs &pairs) const { + Pairs compute_local_coupling(const std::vector &vpairs) const { + // create new pairs structure + Pairs pairs; + for (auto& tmp_pair : vpairs) pairs.insert(tmp_pair.i, tmp_pair.j, tmp_pair); auto ccpair2function = [](const CCPair& a) {return a.function();}; return compute_local_coupling(pairs.convert(pairs,ccpair2function)); diff --git a/src/madness/chem/CCStructures.h b/src/madness/chem/CCStructures.h index bdf9847f4e1..6d9efd68a0b 100644 --- a/src/madness/chem/CCStructures.h +++ b/src/madness/chem/CCStructures.h @@ -934,6 +934,40 @@ class CCPair : public archive::ParallelSerializableObject { size_t i; size_t j; + /// customized function to store this to the cloud + + /// functions and constant_part can be very large and we want to split them and store them in different records + Recordlist cloud_store(World& world, Cloud& cloud) const { + // save bookkeeping stuff in a vector + std::vector v; + archive::VectorOutputArchive arout(v); + bool function_is_assigned=(functions.size()>0 && functions[0].is_assigned()); + arout & type & ctype & i & j & bsh_eps & function_is_assigned & constant_part.is_initialized(); + + Recordlist records; + records+=cloud.store(world,v); + if (function_is_assigned) records+=cloud.store(world,functions[0]); + if (constant_part.is_initialized()) records+=cloud.store(world,constant_part); + return records; + } + + /// customized function to load this from the cloud + + /// functions and constant_part can be very large and we want to split them and store them in different records + /// @param[inout] recordlist: containing the keys of the member variables -> will be reduced by the keys which are used + void cloud_load(World& world, const Cloud& cloud, Recordlist& recordlist) { + // load bookkeeping stuff in a vector + std::vector v=cloud.forward_load>(world,recordlist); + archive::VectorInputArchive arin(v); + bool function_is_assigned = false, constant_part_is_initialized=false; + arin & type & ctype & i & j & bsh_eps & function_is_assigned & constant_part_is_initialized; + functions.clear(); + constant_part.clear(); + + if (function_is_assigned) functions.emplace_back(cloud.forward_load>(world,recordlist)); + if (constant_part_is_initialized) constant_part=cloud.forward_load(world,recordlist); + } + /// gives back the pure 6D part of the pair function real_function_6d function() const { MADNESS_ASSERT(not functions.empty()); diff --git a/src/madness/mra/test_cloud.cc b/src/madness/mra/test_cloud.cc index b421e8b1efa..3b2027559ec 100644 --- a/src/madness/mra/test_cloud.cc +++ b/src/madness/mra/test_cloud.cc @@ -31,6 +31,43 @@ struct gaussian { } }; + +/// this class stores different member variables in different records of the cloud +class custom_serialize_tester { +public: + int i; + double d; + + custom_serialize_tester() : i(0), d(0.0) {} + bool operator==(const custom_serialize_tester& other) const { + return i == other.i && d == other.d; + } + + /// customized function to store this to the cloud + + /// functions and constant_part can be very large and we want to split them and store them in differenc records + Recordlist cloud_store(World& world, Cloud& cloud) const { + // save bookkeeping stuff in a vector + std::vector v; + archive::VectorOutputArchive arout(v); + arout & i; + + Recordlist records; + records+=cloud.store(world,v); + records+=cloud.store(world,d); + return records; + } + + void cloud_load(World& world, const Cloud& cloud, Recordlist& recordlist) { + std::vector v=cloud.forward_load>(world,recordlist); + archive::VectorInputArchive arin(v); + arin & i; + d=cloud.forward_load(world,recordlist); + } + + +}; + template double norm(const T i1) { return fabs(i1); } @@ -157,6 +194,35 @@ int test_custom_worldobject(World& universe, World& subworld, Cloud& cloud) { double error=d1-d2; cloud.set_force_load_from_cache(false); return t1.end(error < 1.e-10 ); +} + +int test_custom_serialization(World& universe, Cloud& cloud) { + test_output t1("testing custom serialization"); + t1.set_cout_to_terminal(); + cloud.set_debug(true); + custom_serialize_tester cst; + cst.i=1; + cst.d=2.0; + static_assert(Cloud::has_cloud_serialize::value,"custom_serialize_tester must have a cloud_serialize method"); + { + auto records = cloud.store(universe, cst); + auto cst2=cloud.load(universe, records); + t1.checkpoint(cst==cst2,"custom serialization"); + } + + // test being part of a tuple + typedef std::tuple tupleT; + tupleT tuple1=std::make_tuple(1,2.0,cst); + cloud.clear(); + { + auto records = cloud.store(universe, tuple1); + auto tuple2=cloud.load(universe, records); + + t1.checkpoint(tuple1==tuple2,"custom serialization with tuple"); + } + + return t1.end(); + } @@ -177,6 +243,7 @@ int main(int argc, char **argv) { // test storing custom WorldObject success += test_custom_worldobject(universe, subworld, cloud); + success += test_custom_serialization(universe, cloud); if (universe.rank() == 0) print("entering test_cloud"); print("my world: universe_rank, subworld_id", universe.rank(), subworld.id()); diff --git a/src/madness/world/cloud.h b/src/madness/world/cloud.h index 73ac5d7e148..29ad7189eb0 100644 --- a/src/madness/world/cloud.h +++ b/src/madness/world/cloud.h @@ -68,6 +68,13 @@ struct Recordlist { template using has_member_id = madness::meta::is_detected; + // if type provides a hashing function use that, intrusive hashing, see worldhash.h + template + using member_hash_t = decltype(std::declval().hash()); + + template + using has_member_hash = madness::meta::is_detected; + template static keyT compute_record(const Function& arg) {return hash_value(arg.get_impl()->id());} @@ -154,6 +161,13 @@ class Cloud { cacheT cached_objects; recordlistT local_list_of_container_keys; // a world-local list of keys occupied in container +public: + template + using member_cloud_serialize_t = decltype(std::declval().cloud_store(std::declval(), std::declval())); + + template + using has_cloud_serialize = madness::meta::is_detected; + public: /// @param[in] universe the universe world @@ -243,14 +257,32 @@ class Cloud { cache_reads=0l; } + + /// load a single object from the cloud, recordlist is kept unchanged template T load(madness::World &world, const recordlistT recordlist) const { recordlistT rlist = recordlist; cloudtimer t(world, reading_time); + + // forward_load will consume the recordlist while loading elements + return forward_load(world, rlist); + } + + /// load a single object from the cloud, recordlist is consumed while loading elements + template + T forward_load(madness::World &world, recordlistT& recordlist) const { + // different objects are stored in different ways + // - tuples are split up into their components + // - classes with their own cloud serialization are stored using that + // - everything else is stored using their usual serialization if constexpr (is_tuple::value) { - return load_tuple(world, rlist); + return load_tuple(world, recordlist); + } else if constexpr (has_cloud_serialize::value) { + T target = allocator(world); + target.cloud_load(world, *this, recordlist); + return target; } else { - return load_other(world, rlist); + return do_load(world, recordlist); } } @@ -261,9 +293,16 @@ class Cloud { MADNESS_EXCEPTION("cloud error",1); } cloudtimer t(world,writing_time); + + // different objects are stored in different ways + // - tuples are split up into their components + // - classes with their own cloud serialization are stored using that + // - everything else is stored using their usual serialization recordlistT recordlist; if constexpr (is_tuple::value) { recordlist+=store_tuple(world,source); + } else if constexpr (has_cloud_serialize::value) { + recordlist+=source.cloud_store(world,*this); } else { recordlist+=store_other(world,source); } @@ -365,17 +404,16 @@ class Cloud { } }; - template void cache(madness::World &world, const T &obj, const keyT &record) const { const_cast(cached_objects).insert({record,std::make_any(obj)}); } + /// load an object from the cache, record is unchanged template T load_from_cache(madness::World &world, const keyT &record) const { if (world.rank()==0) cache_reads++; if (debug) print("loading", typeid(T).name(), "from cache record", record, "to world", world.id()); -// if (auto obj = std::get_if(&cached_objects.find(record)->second)) return *obj; if (auto obj = std::any_cast(&cached_objects.find(record)->second)) return *obj; MADNESS_EXCEPTION("failed to load from cloud-cache", 1); T target = allocator(world); @@ -411,7 +449,6 @@ class Cloud { bool is_already_present= is_in_container(record); if (debug) { if (is_already_present) std::cout << "skipping "; - std::string msg; if constexpr (Recordlist::has_member_id::value) { std::cout << "storing world object of " << typeid(T).name() << "id " << source.id() << " to record " << record << std::endl; } @@ -431,20 +468,29 @@ class Cloud { return recordlistT{record}; } +public: + /// load a vector from the cloud, pop records from recordlist + /// + /// @param[inout] world destination world + /// @param[inout] recordlist list of records to load from (reduced by the first few elements) template typename std::enable_if::value, T>::type - load_other(World &world, recordlistT &recordlist) const { - std::size_t sz = load_other(world, recordlist); + do_load(World &world, recordlistT &recordlist) const { + std::size_t sz = do_load(world, recordlist); T target(sz); for (std::size_t i = 0; i < sz; ++i) { - target[i] = load_other(world, recordlist); + target[i] = do_load(world, recordlist); } return target; } + /// load a single object from the cloud, pop record from recordlist + /// + /// @param[inout] world destination world + /// @param[inout] recordlist list of records to load from (reduced by the first element) template typename std::enable_if::value, T>::type - load_other(World &world, recordlistT &recordlist) const { + do_load(World &world, recordlistT &recordlist) const { keyT record = recordlist.pop_front_and_return(); if (force_load_from_cache) MADNESS_CHECK(is_cached(record)); @@ -454,10 +500,13 @@ class Cloud { madness::archive::ContainerRecordInputArchive ar(world, container, record); madness::archive::ParallelInputArchive par(world, ar); par & target; + cache(world, target, record); return target; } +public: + // overloaded template recordlistT store_other(madness::World& world, const std::vector& source) { @@ -484,12 +533,16 @@ class Cloud { return v; } + /// load a tuple from the cloud, pop records from recordlist + /// + /// @param[inout] world destination world + /// @param[inout] recordlist list of records to load from (reduced by the first few elements) template - T load_tuple(madness::World &world, recordlistT &recordlist) const { + T load_tuple(madness::World &world, recordlistT &recordlist) const { if (debug) std::cout << "loading tuple of type " << typeid(T).name() << " to world " << world.id() << std::endl; T target; std::apply([&](auto &&... args) { - ((args = load_other::type>(world, recordlist)), ...); + ((args = forward_load::type>(world, recordlist)), ...); }, target); return target; } From c4c607d0bb50137447a63c9595b46bc5dcfc4647 Mon Sep 17 00:00:00 2001 From: Florian Bischoff Date: Fri, 26 Apr 2024 14:47:48 +0200 Subject: [PATCH 03/54] Update cmake.yml, use gcc11 instead of gcc10 original error message: gcc@10: The x86_64 architecture is required for this software. ==> Downloading https://ghcr.io/v2/homebrew/core/boost/manifests/1.84.0_1 Error: gcc@10: An unsatisfied requirement failed this build. --- .github/workflows/cmake.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index e2122f7343d..664d1e1951e 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -69,7 +69,7 @@ jobs: - name: Install prerequisite MacOS packages if: ${{ matrix.os == 'macos-latest' }} run: | - brew install ninja gcc@10 boost eigen open-mpi bison ccache + brew install ninja gcc@11 boost eigen open-mpi bison ccache if [ "X${{ matrix.task_backend }}" = "XLegacyTBB" ]; then brew install tbb@2020 echo "TBBROOT=/usr/local/opt/tbb@2020" >> $GITHUB_ENV From 278be911c3e2d17110bba4140ea443248b38e0a4 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Fri, 26 Apr 2024 15:45:41 +0200 Subject: [PATCH 04/54] less debug output --- src/madness/chem/CC2.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/madness/chem/CC2.cc b/src/madness/chem/CC2.cc index 50099125606..9a51d578ded 100644 --- a/src/madness/chem/CC2.cc +++ b/src/madness/chem/CC2.cc @@ -482,11 +482,10 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { // calc update for pairs via macrotask auto taskq = std::shared_ptr(new MacroTaskQ(world, world.size())); - taskq->set_printlevel(10); - taskq->cloud.set_debug(true); + taskq->set_printlevel(3); + //taskq->cloud.set_debug(true); MacroTaskMp2UpdatePair t; MacroTask task1(world, t, taskq); - task1.set_debug(true); if (world.rank()==0) print("pair_vec before update"); for (auto& p :pair_vec) { if (world.rank()==0) print("pair",p.i,p.j, p.function().get_impl()->get_tree_state()); From f64cf316305eb330dfda367dbdcb3c220bc9ffec Mon Sep 17 00:00:00 2001 From: fbischoff Date: Fri, 31 May 2024 12:14:40 +0200 Subject: [PATCH 05/54] checkpoint macrotasks for MP2, CC2 and LRCC2 --- src/madness/chem/CC2.cc | 60 +++- src/madness/chem/CC2.h | 2 +- src/madness/chem/CCPotentials.cc | 499 +++++++++++++++++++++++++++-- src/madness/chem/CCPotentials.h | 69 +++- src/madness/chem/CCStructures.cc | 59 ++-- src/madness/chem/CCStructures.h | 183 +++++++++-- src/madness/chem/ccpairfunction.cc | 4 +- src/madness/chem/ccpairfunction.h | 91 ++++-- src/madness/chem/projector.h | 62 +++- src/madness/chem/test_projector.cc | 36 ++- 10 files changed, 940 insertions(+), 125 deletions(-) diff --git a/src/madness/chem/CC2.cc b/src/madness/chem/CC2.cc index 9a51d578ded..ebf6c7fea79 100644 --- a/src/madness/chem/CC2.cc +++ b/src/madness/chem/CC2.cc @@ -30,6 +30,7 @@ CC2::solve() { dummy_mo.print_frozen_orbitals(parameters.freeze()); CCOPS.reset_nemo(nemo); + CCOPS.get_potentials.parameters=parameters; CCOPS.update_intermediates(CCOPS.mo_ket()); // doubles for ground state @@ -248,6 +249,15 @@ CC2::solve() { std::vector > > timings; auto vccs=solve_ccs(); + Info info; + info.mo_bra=CCOPS.mo_bra().get_vecfunction(); + info.mo_ket=CCOPS.mo_ket().get_vecfunction(); + info.parameters=parameters; + info.R_square=nemo->R_square; + info.U1=nemo->ncf->U1vec(); + info.U2=nemo->ncf->U2(); + info.intermediate_potentials=CCOPS.get_potentials; + std::vector > > results_ex; for (size_t xxx = 0; xxx < vccs.size(); xxx++) { @@ -268,10 +278,11 @@ CC2::solve() { if (found_lrcc2d) iterate_lrcc2_singles(cc2singles, cc2pairs, lrcc2_s, lrcc2_d); else iterate_ccs_singles(lrcc2_s); const double omega_cis = lrcc2_s.omega; + info.intermediate_potentials=CCOPS.get_potentials; // update applied singles potentials for (size_t iter = 0; iter < parameters.iter_max(); iter++) { output.section("Macroiteration " + std::to_string(int(iter)) + " of LRCC2"); - bool dconv = iterate_lrcc2_pairs(cc2singles, cc2pairs, lrcc2_s, lrcc2_d); + bool dconv = iterate_lrcc2_pairs(cc2singles, cc2pairs, lrcc2_s, lrcc2_d, info); bool sconv = iterate_lrcc2_singles(cc2singles, cc2pairs, lrcc2_s, lrcc2_d); if (dconv and sconv) break; } @@ -408,6 +419,14 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { // make vector holding CCPairs for partitioner of MacroTask std::vector pair_vec=Pairs::pairs2vector(doubles,triangular_map); + Info info; + info.mo_bra=CCOPS.mo_bra().get_vecfunction(); + info.mo_ket=CCOPS.mo_ket().get_vecfunction(); + info.parameters=parameters; + info.R_square=nemo->R_square; + info.U1=nemo->ncf->U1vec(); + info.U2=nemo->ncf->U2(); + // read constant part from file if (parameters.no_compute_mp2_constantpart()) { if (world.rank()==0) print("Skipping MP2 constant part calculation"); @@ -422,12 +441,11 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { // calc constant part via taskq auto taskq = std::shared_ptr(new MacroTaskQ(world, world.size())); taskq->set_printlevel(3); - MacroTaskMp2ConstantPart t; + MacroTaskConstantPart t; MacroTask task(world, t, taskq); task.set_name("MP2_Constant_Part"); - std::vector result_vec = task(pair_vec, CCOPS.mo_ket().get_vecfunction(), - CCOPS.mo_bra().get_vecfunction(), parameters, - nemo->R_square, nemo->ncf->U1vec(),std::vector({"Ue","KffK"})); + std::vector> gs_singles, ex_singles; // dummy vectors + std::vector result_vec = task(pair_vec, gs_singles, ex_singles, info) ; taskq->print_taskq(); taskq->run_all(); @@ -494,9 +512,11 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { p.function().print_size("pair_vec function before update after reconstruction"); // flodbg 2.0 GByte p.constant_part.print_size("pair_vec constant part before update macrotask is called"); } - std::vector u_update = task1(pair_vec, coupling_vec, parameters, nemo->get_calc()->molecule.get_all_coords_vec(), - CCOPS.mo_ket().get_vecfunction(), CCOPS.mo_bra().get_vecfunction(), - nemo->ncf->U1vec(), nemo->ncf->U2()); +// std::vector u_update = task1(pair_vec, coupling_vec, parameters, nemo->get_calc()->molecule.get_all_coords_vec(), +// CCOPS.mo_ket().get_vecfunction(), CCOPS.mo_bra().get_vecfunction(), +// nemo->ncf->U1vec(), nemo->ncf->U2()); + auto all_coords=nemo->get_calc()->molecule.get_all_coords_vec(); + std::vector u_update = task1(pair_vec, coupling_vec, all_coords , info); taskq->print_taskq(); taskq->run_all(); @@ -705,7 +725,7 @@ CC2::iterate_adc2_pairs(Pairs& cispd, const CC_vecfunction& ccs) { bool CC2::iterate_lrcc2_pairs(const CC_vecfunction& cc2_s, const Pairs& cc2_d, const CC_vecfunction lrcc2_s, - Pairs& lrcc2_d) { + Pairs& lrcc2_d, const Info& info) { output.section("Solve LRCC2 for Excitation energy " + std::to_string(double(lrcc2_s.omega))); MADNESS_ASSERT(lrcc2_s.type == RESPONSE); CCOPS.update_intermediates(lrcc2_s); @@ -721,7 +741,9 @@ CC2::iterate_lrcc2_pairs(const CC_vecfunction& cc2_s, const Pairs& cc2_d output("Skipping Pair Iteration, No significant Change in Singles"); else { pair.bsh_eps = CCOPS.get_epsilon(pair.i, pair.j) + lrcc2_s.omega; - update_constant_part_lrcc2(pair, cc2_s, lrcc2_s); + // update_constant_part_lrcc2(pair, cc2_s, lrcc2_s); + pair.constant_part=CCPotentials::make_constant_part_macrotask(world, pair, + cc2_s, lrcc2_s, info); conv = iterate_pair(pair, lrcc2_s); } } @@ -743,11 +765,25 @@ CC2::solve_cc2(CC_vecfunction& singles, Pairs& doubles) { double omega = CCOPS.compute_cc2_correlation_energy(singles, doubles); if (world.rank() == 0) std::cout << std::fixed << std::setprecision(10) << "Current Correlation Energy = " << omega << "\n"; + CC_vecfunction ex_singles_dummy; + vector_real_function_3d empty(CCOPS.mo_ket().size()-parameters.freeze()); + Info info; + info.intermediate_potentials=CCIntermediatePotentials(parameters); + info.mo_bra=CCOPS.mo_bra().get_vecfunction(); + info.mo_ket=CCOPS.mo_ket().get_vecfunction(); + info.parameters=parameters; + info.R_square=nemo->R_square; + info.U1=nemo->ncf->U1vec(); + info.U2=nemo->ncf->U2(); + info.intermediate_potentials.insert(empty,singles,POT_singles_); // initialize with empty vector if (not parameters.no_compute_cc2()) { // first singles iteration output.section("Initialize Singles to the Doubles"); iterate_cc2_singles(singles, doubles); + // nasty hack + info.intermediate_potentials=CCOPS.get_potentials; + info.intermediate_potentials.parameters=parameters; // update correlation energy omega = CCOPS.compute_cc2_correlation_energy(singles, doubles); @@ -759,7 +795,9 @@ CC2::solve_cc2(CC_vecfunction& singles, Pairs& doubles) { bool doubles_converged = true; for (auto& pairs: doubles.allpairs) { CCPair& pair = pairs.second; - update_constant_part_cc2_gs(singles, pair); + // update_constant_part_cc2_gs(singles, pair); + pair.constant_part=CCPotentials::make_constant_part_macrotask(world, pair, + singles, ex_singles_dummy, info); bool pair_converged = iterate_pair(pair, singles); save(pair.function(), pair.name()); if (not pair_converged) doubles_converged = false; diff --git a/src/madness/chem/CC2.h b/src/madness/chem/CC2.h index 66781f7ef7b..6fc41019a14 100644 --- a/src/madness/chem/CC2.h +++ b/src/madness/chem/CC2.h @@ -406,7 +406,7 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { bool iterate_lrcc2_pairs(const CC_vecfunction& cc2_s, const Pairs& cc2_d, const CC_vecfunction lrcc2_s, - Pairs& lrcc2_d); + Pairs& lrcc2_d, const Info& info); bool update_constant_part_cc2_gs(const CC_vecfunction& tau, CCPair& pair) { MADNESS_ASSERT(pair.ctype == CT_CC2); diff --git a/src/madness/chem/CCPotentials.cc b/src/madness/chem/CCPotentials.cc index a658f532c30..881fdcf1fd8 100644 --- a/src/madness/chem/CCPotentials.cc +++ b/src/madness/chem/CCPotentials.cc @@ -26,16 +26,16 @@ CCPotentials::CCPotentials(World& world_, std::shared_ptr nemo, const CCP //orbital_energies_(init_orbital_energies(nemo)) // g12(std::shared_ptrget_calc()->molecule), - get_potentials(world, param), + get_potentials(param), output(world) { g12=std::shared_ptr>(new CCConvolutionOperator(world,OpType::OT_G12,param)); f12=std::shared_ptr>(new CCConvolutionOperator(world,OpType::OT_F12,param)); output.debug = parameters.debug(); -// reset_nemo(nemo); -// g12.update_elements(mo_bra_, mo_ket_); -// g12.sanity(); -// f12.update_elements(mo_bra_, mo_ket_); -// f12.sanity(); + // reset_nemo(nemo); + // g12.update_elements(mo_bra_, mo_ket_); + // g12.sanity(); + // f12.update_elements(mo_bra_, mo_ket_); + // f12.sanity(); } madness::CC_vecfunction @@ -78,7 +78,7 @@ CCPotentials::make_pair_gs(const real_function_6d& u, const CC_vecfunction& tau, MADNESS_ASSERT(tau.type == PARTICLE || tau.type == HOLE); // for MP2: tau is empty or Hole states, the function will give back mo_ket_ // for freeze!=0 the function will give back (mo0,mo1,...,t_freeze,t_freeze+1,...) - const CC_vecfunction t = make_t_intermediate(tau); + const CC_vecfunction t = make_t_intermediate(tau,parameters); // functions for the projector CC_vecfunction pt; if (!parameters.QtAnsatz()) pt = mo_ket_; @@ -222,7 +222,7 @@ CCPotentials::make_pair_ex(const real_function_6d& u, const CC_vecfunction& tau, MADNESS_ASSERT(!(j < parameters.freeze())); // for CIS(D): tau is empty or Hole states, the function will give back mo_ket_ // for freeze!=0 the function will give back (mo0,mo1,...,t_freeze,t_freeze+1,...) - const CC_vecfunction t = make_t_intermediate(tau).copy(); + const CC_vecfunction t = make_t_intermediate(tau,parameters).copy(); // functions for the projector CC_vecfunction pt; if (!parameters.QtAnsatz()) pt = mo_ket_.copy(); @@ -661,7 +661,7 @@ CCPotentials::fock_residue_6d_macrotask(World& world, const CCPair& u, const CCP double tight_thresh = parameters.thresh_6D(); real_function_6d x = CompositeFactory(world).ket(copy(Du)).V_for_particle2( copy(U1_axis)).thresh(tight_thresh).special_points(sp6d); - x.fill_nuclear_cuspy_tree(op_mod, 2); + x.fill_nuclear_cuspy_tree(op_mod, 2); if (parameters.debug()) x.print_size("Un_axis_" + stringify(axis)); Un2 += x; } @@ -679,6 +679,120 @@ CCPotentials::fock_residue_6d_macrotask(World& world, const CCPair& u, const CCP return vphi; } +/// the constant part is the contribution to the doubles that are independent of the doubles + +/// CC-equations from Kottmann et al., JCTC 13, 5956 (2017) +/// MP2: +/// cp = G Q g~ |ij> +/// g~ = Ue - KffK +/// GS-CC2: eqs. (6,7) +/// cp = G Qt g~ |t_i t_j> +/// g~ = Ue - KffK - Fock_commutator - reduced_Fock +/// LRCC2: eqs. (24-29) +/// cp = G d(Qt g~ d|t_i t_j>) +/// = G (Qt g~ d|t_i t_j> + Qt dg~ |t_i t_j> + dQt g~ |t_i t_j>) +madness::real_function_6d +CCPotentials::make_constant_part_macrotask(World& world, const CCPair& pair, + const CC_vecfunction& gs_singles, const CC_vecfunction& ex_singles, + const Info& info) { + const CalcType targetstate=pair.ctype; + const auto& parameters=info.parameters; + + // t1-transformed orbitals + CC_vecfunction t(MIXED); + if (targetstate==CT_CC2 or targetstate==CT_LRCC2) + { + for (int i=0; i t1(info.mo_ket[i] + gs_singles(i).function, i, MIXED); + t.insert(i, t1); + } + } + + // construct the projectors + // Q12 = (1-|i> Q12(world); + Q12.set_spaces(info.mo_bra,info.mo_ket,info.mo_bra,info.mo_ket); + + // Q12t = (1-|t_i> Q12t(world); + Q12t.set_spaces(info.mo_bra,t.get_vecfunction(),info.mo_bra,t.get_vecfunction()); + + // dQ12t = -(Qt(1) Ox(2) + Ox(1) Qt(2)) eq. (22) + QProjector Qt(world,info.mo_bra,t.get_vecfunction()); + Projector Ox(info.mo_bra,ex_singles.get_vecfunction()); + auto dQt_1 = outer(Qt,Ox); + auto dQt_2 = outer(Ox,Qt); + + std::size_t i=pair.i; + std::size_t j=pair.j; + auto phi = [&](size_t i) { return CCFunction(info.mo_ket[i],i,HOLE); }; + // auto t = [&](size_t i) { return CCFunction(info.mo_ket[i]+gs_singles(i).function); }; + auto x = [&](size_t i) { return ex_singles(i); }; + + // save memory: + // split application of the BSH operator into high-rank, local part U|ij>, and + // low-rank, delocalized part (-O1 -O2 +O1O2) U|ij> by splitting the SO operator + auto apply_in_separated_form = [](const StrongOrthogonalityProjector& Q, + const std::vector>& ccp) { + + std::vector> result; + for (const auto& cc : ccp) { + if (cc.is_pure()) { + auto [left,right]=Q.get_vectors_for_outer_product(cc.get_function()); + result.push_back(cc); + result.push_back(CCPairFunction(left,right)); + } else if (cc.is_decomposed()) { + result.push_back(Q(cc)); + } + } + return result; + }; + + // compute all 6d potentials without applying the SO projector + std::vector> V; + if (targetstate==CT_MP2) { + std::vector argument={"Ue","KffK"}; + auto Vreg=apply_Vreg(world,phi(i),phi(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); + V=consolidate(apply_in_separated_form(Q12,Vreg)); + } else if (targetstate==CT_CC2) { // Eq. (42) of Kottmann, JCTC 13, 5945 (2017) + std::vector argument={"Ue","KffK","comm_F_Qt_f12","reduced_Fock"}; + auto Vreg=apply_Vreg(world,t(i),t(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); + V=consolidate(Q12t(Vreg)); + } else if (targetstate==CT_LRCC2) { // Eq. (25) of Kottmann, JCTC 13, 5956 (2017) + // eq. (25) Q12t (g~ - omega f12) (|x_i t_j> + |t_i x_j> ) + // note the term omega f12 is included in the reduced_Fock term, see eq. (34) + std::vector argument={"Ue","KffK","comm_F_Qt_f12","reduced_Fock"}; + auto Vreg=apply_Vreg(world,t(i),x(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); + Vreg+=apply_Vreg(world,x(i),t(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); + V=consolidate(apply_in_separated_form(Q12t,Vreg)); + + // eq. (29) first term: dQt g~ |t_i t_j> + argument={"Ue","KffK","comm_F_Qt_f12","reduced_Fock"}; + auto Vreg1=apply_Vreg(world,t(i),t(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); + V-=consolidate(dQt_1(Vreg1) + dQt_2(Vreg1)); + + // eq. (29) second term = eq. (31): [F12, dQt] f12 |t_i t_j> + omega dQ12t f12 |t_i t_j> + argument={"comm_F_dQt_f12"}; + V+=apply_Vreg(world,t(i),t(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); + } + V=consolidate(V); + MADNESS_CHECK(V.size()==2); // term 1: 6d, hi-rank, local; term 2: 3d, low-rank, delocalized + + // the Green's function + auto G = BSHOperator<6>(world, sqrt(-2.0 * pair.bsh_eps), parameters.lo(), parameters.thresh_bsh_6D()); + G.destructive() = true; + + real_function_6d GV=real_factory_6d(world).empty(); + for (const auto& vv : V) GV+= (-2.0 * G(vv)).get_function(); // note V is destroyed here + GV=Q12(GV).truncate().reduce_rank(); + + GV.print_size("GVreg"); + return GV; +} + + + + madness::real_function_6d CCPotentials::make_constant_part_mp2_macrotask(World& world, const CCPair& pair, const std::vector& mo_ket, @@ -719,13 +833,13 @@ CCPotentials::make_constant_part_mp2_macrotask(World& world, const CCPair& pair, StrongOrthogonalityProjector Q(world); Q.set_spaces(mo_bra, mo_ket, mo_bra, mo_ket); -// V = Q(V); -// -// V.print_size("QVreg"); + // V = Q(V); + // + // V.print_size("QVreg"); real_convolution_6d G = BSHOperator<6>(world, sqrt(-2.0 * epsilon), parameters.lo(), parameters.thresh_bsh_6D()); G.destructive() = true; -// real_function_6d GV = -2.0 * G(V); + // real_function_6d GV = -2.0 * G(V); // save memory: // split application of the BSH operator into high-rank, local part U|ij>, and @@ -904,6 +1018,7 @@ CCPotentials::make_constant_part_cc2_Qt_gs(const CCPair& u, const CC_vecfunction real_convolution_6d G = BSHOperator<6>(world, sqrt(-2.0 * get_epsilon(ti.i, tj.i)), parameters.lo(), parameters.thresh_bsh_6D()); G.destructive() = true; + G.particle_=-1; // calculate [F,Qt] commutator which is [F1,Q1t]Q2t + Q1t [F2,Q2t] // and [F1,Q1t] = - [F1,O1t] = - (F-e_k) |tk> @@ -1425,7 +1540,7 @@ CCPotentials::apply_Vreg(const CCFunction& ti, const CCFunction"); CCTimer timer(world, "Vreg|" + ti.name() + tj.name() + ">"); CCTimer time_f(world, "F-Part"); - const real_function_6d F_part = apply_reduced_F(ti, tj, Gscreen); + const real_function_6d F_part = apply_reduced_F1(ti, tj, Gscreen); time_f.stop(); CCTimer time_u(world, "U-Part"); const real_function_6d U_part = apply_transformed_Ue(ti, tj, Gscreen); @@ -1449,6 +1564,66 @@ CCPotentials::apply_Vreg(const CCFunction& ti, const CCFunction \f$ +/// - Ue = [T,f12] +/// - [K,f12] +/// - [F12,Q12t] f12 or [F12,dQ12t] f12 +/// - f12 (F - e_ij - omega) or f12 (F - e_ij) +/// the last terms are computed using the converged singles potential, i.e. we assume that the following equation holds +/// (see Kottmann et al., JCTC 13, 5945 (2017) eqs (30), (31), (44) +/// (see Kottmann et al., JCTC 13, 5956 (2017) eqs (17), (19), (32) +/// CC2: (F - e_i ) |t_i t_j> = | Vtau > +/// LRCC2: (F - e_i - omega) |x_i> = | Vx > +/// @param[in] ti, first function in the ket, for MP2 it is the Orbital, for CC2 the relaxed Orbital t_i=\phi_i + \tau_i +/// @param[in] tj, second function in the ket ... +/// @param[in] gs_singles, the converged ground state singles: with (F - e_i ) |t_i t_j> = | Vtau > +/// @param[in] ex_singles, the converged excited state singles: with (F - e_i - omega) |x_i> = | Vx > +/// @param[in] info Info structure holding the applied singles potentials Vtau and Vx and reference orbitals +/// @param[out] the regularization potential (unprojected), see equation above +std::vector> + CCPotentials::apply_Vreg(World& world, const CCFunction& ti, const CCFunction& tj, + const CC_vecfunction& gs_singles, const CC_vecfunction& ex_singles, + const Info& info, const std::vector& argument, const double bsh_eps) { + + const auto parameters=info.parameters; + if (parameters.debug() and (world.rank()==0)) { + print("computing the following terms in constant_part for pair: (",ti.name(),",", tj.name(),"):" , argument); + } + + real_convolution_6d Gscreen = BSHOperator<6>(world, sqrt(-2.0 * bsh_eps), + parameters.lo(), parameters.thresh_bsh_6D()); + Gscreen.modified() = true; + + auto exists=[&](const std::string term) { + return std::find(argument.begin(), argument.end(), term) != argument.end(); + }; + + // calculate the regularized potential + real_function_6d V=real_factory_6d(world); + std::vector> V_lowrank; + if (exists("Ue")) V += apply_Ue(world,ti,tj,info,&Gscreen); + if (exists("KffK")) V -= apply_KffK(world,ti,tj,info,&Gscreen); + if (exists("reduced_Fock")) V += apply_reduced_F(world,ti,tj,info,&Gscreen); + if (exists("comm_F_Qt_f12")) { + V_lowrank += apply_commutator_F_Qt_f12(world,ti,tj,gs_singles,ex_singles,info,&Gscreen); + } + if (exists("comm_F_dQt_f12")) { + V_lowrank += apply_commutator_F_dQt_f12(world,ti,tj,gs_singles,ex_singles,info,&Gscreen); + } + V.truncate().reduce_rank(); + if (parameters.debug()) V.print_size("Vreg"); + + std::vector> result; + result+=CCPairFunction(V); + result+=V_lowrank; + return result; + +} + madness::real_function_6d CCPotentials::apply_Vreg_macrotask(World& world, const std::vector& mo_ket, const std::vector& mo_bra, @@ -1509,7 +1684,7 @@ CCPotentials::apply_Vreg_macrotask(World& world, const std::vector& ti, const CCFunction& tj, const real_convolution_6d *Gscreen) const { +CCPotentials::apply_reduced_F1(const CCFunction& ti, const CCFunction& tj, const real_convolution_6d *Gscreen) const { //CC_Timer time(world,"(F-eij)|"+ti.name()+tj.name()+">"); // get singles potential const bool symmetric = (ti.type == tj.type && ti.i == tj.i); @@ -1526,6 +1701,26 @@ CCPotentials::apply_reduced_F(const CCFunction& ti, const CCFunction +/// f12 (F12 - e_ij - omega) |ti xj> +madness::real_function_6d +CCPotentials::apply_reduced_F(World& world, const CCFunction& ti, const CCFunction& tj, + const Info& info, const real_convolution_6d *Gscreen) { + //CC_Timer time(world,"(F-eij)|"+ti.name()+tj.name()+">"); + // get singles potential + const bool symmetric = (ti == tj); + const real_function_3d Vti = info.intermediate_potentials(ti, POT_singles_); + const real_function_3d Vtj = info.intermediate_potentials(tj, POT_singles_); + const real_function_6d Vt = make_f_xy(world, Vti, tj, info, Gscreen); + real_function_6d tV; + if (symmetric) tV = madness::swap_particles(Vt); + else tV = make_f_xy(world, ti, Vtj, info, Gscreen); + + const real_function_6d result = -1.0 * (Vt + tV); + return result; +} madness::real_function_6d CCPotentials::apply_transformed_Ue(const CCFunction& x, const CCFunction& y, const real_convolution_6d *Gscreen) const { @@ -1610,6 +1805,101 @@ CCPotentials::apply_transformed_Ue(const CCFunction& x, const CCFuncti } +madness::real_function_6d +CCPotentials::apply_Ue(World& world, const CCFunction& phi_i, const CCFunction& phi_j, + const Info& info, const real_convolution_6d *Gscreen) { + + const std::string x_name = phi_i.name(); + const std::string y_name = phi_j.name(); + const auto& parameters=info.parameters; + + if (parameters.debug()) print("Computing Ue|" + x_name + y_name + ">"); + + real_function_3d x_function=phi_i.function; + real_function_3d y_function=phi_j.function; + CorrelationFactor corrfac(world, parameters.gamma(), 1.e-7, parameters.lo()); + + const bool symmetric = (phi_i.type == phi_j.type && phi_i.i == phi_j.i); + CCTimer time_Ue(world, "Ue|" + x_name + y_name + ">"); + double tight_thresh = parameters.thresh_6D(); // right now this is the std. thresh + // check if screening operator is in modified NS Form + if (Gscreen != NULL) { + if (!Gscreen->modified()) error("Demanded Screening for Ue but given BSH Operator is not in modified NS form"); + } + if (parameters.debug()) print("Applying transformed Ue to \n" + x_name + y_name); + + if (parameters.debug() && symmetric) print("Exploiting Pair Symmetry\n"); + + real_function_6d Uxy = real_factory_6d(world); + Uxy.set_thresh(tight_thresh); + // Apply the untransformed U Potential + Uxy = corrfac.apply_U(x_function, y_function, *Gscreen, symmetric); + Uxy.set_thresh(tight_thresh); + // Apply the double commutator R^{-1}[[T,f,R] + for (size_t axis = 0; axis < 3; axis++) { + // Make the local parts of the Nuclear and electronic U potentials + const real_function_3d Un_local = info.U1[axis]; + const real_function_3d Un_local_x = (Un_local * x_function).truncate(); + real_function_3d Un_local_y; + if (symmetric) Un_local_y = copy(Un_local_x); + else Un_local_y = (Un_local * y_function).truncate(); + + const real_function_6d Ue_local = corrfac.U1(axis); + // Now add the Un_local_x part to the first particle of the Ue_local potential + real_function_6d UeUnx = CompositeFactory(world).g12(Ue_local).particle1(Un_local_x).particle2( + copy(y_function)).thresh(tight_thresh); + // Fill the Tree where it will be necessary + UeUnx.fill_cuspy_tree(*Gscreen); + // Set back the thresh + UeUnx.set_thresh(FunctionDefaults<6>::get_thresh()); +// print_size(UeUnx, "UeUnx", parameters.debug()); + // Now add the Un_local_y part to the second particle of the Ue_local potential + real_function_6d UeUny; + if (symmetric) UeUny = -1.0 * madness::swap_particles(UeUnx); // Ue_local is antisymmetric + else { + UeUny = CompositeFactory(world).g12(Ue_local).particle1(copy(x_function)).particle2( + Un_local_y).thresh(tight_thresh); + // Fill the Tree were it will be necessary + UeUny.fill_cuspy_tree(*Gscreen); + // Set back the thresh + UeUny.set_thresh(FunctionDefaults<6>::get_thresh()); + } +// print_size(UeUny, "UeUny", parameters.debug()); + // Construct the double commutator part and add it to the Ue part + real_function_6d diff = (UeUnx - UeUny).scale(-1.0); + diff.truncate(); + Uxy = (Uxy + diff).truncate(); + } + if (parameters.debug()) time_Ue.info(); + + // sanity check: = - = 0 + CCTimer time_sane(world, "Ue-Sanity-Check"); + real_function_6d tmp = CompositeFactory(world).particle1( + copy(x_function * info.R_square)).particle2(copy(y_function * info.R_square)); + const double a = inner(Uxy, tmp); + const real_function_3d xx = (x_function * x_function * info.R_square); + const real_function_3d yy = (y_function * y_function * info.R_square); +// const real_function_3d gxx = g12(xx); + real_convolution_3d poisson= CoulombOperator(world,parameters.lo(),parameters.thresh_3D()); + const real_function_3d gxx= poisson(xx); + + const double aa = inner(yy, gxx); + const double error = std::fabs(a - aa); + const double diff = a - aa; + time_sane.info(parameters.debug(), error); + if (world.rank() == 0) { + std::cout << std::fixed << std::setprecision(10) << "<" << x_name + y_name << "|U_R|" << x_name + y_name + << "> =" << a << ", <" << x_name + y_name << "|g12|" << x_name + y_name + << "> =" << aa << ", diff=" << error << "\n"; + //printf(" %12.8f\n",a); + //printf(" %12.8f\n",aa); + if (error > FunctionDefaults<6>::get_thresh() * 10.0) std::cout << ("Ue Potential plain wrong!\n"); + else if (error > FunctionDefaults<6>::get_thresh()) std::cout << ("Ue Potential wrong!!!!\n"); + else std::cout << ("Ue seems to be sane, diff=" + std::to_string(diff)) << std::endl; + } + return Uxy; +} + madness::real_function_6d CCPotentials::apply_transformed_Ue_macrotask(World& world, const std::vector& mo_ket, const CCParameters& parameters, const real_function_3d& Rsquare, @@ -1705,6 +1995,159 @@ CCPotentials::apply_transformed_Ue_macrotask(World& world, const std::vector + +/// From Eqs. (42) - (44) of Kottmann et al. JCTC 13, 5945 (2017) +/// and eq. (30) of Kottmann et al. JCTC 13, 5956 (2017) +/// [F,Qt] = [F1,Q1t]Q2t + Q1t [F2,Q2t] +/// and [F1,Q1t] = - [F1,O1t] = - (F-e_k) |tk> +/// @return the commutator [F,Qt] f12 |phi_i phi_j> +madness::CCPairFunction +CCPotentials::apply_commutator_F_Qt_f12(World& world, const CCFunction& phi_i, const CCFunction& phi_j, + const CC_vecfunction& gs_singles, const CC_vecfunction& ex_singles, + const Info& info, const real_convolution_6d *Gscreen) { + const auto& parameters=info.parameters; + + // if ground-state use Eqs (43)-(44) of Kottmann et al. JCTC 13, 5945 (2017) + auto f12=CCConvolutionOperatorPtr(world,OT_F12,parameters); + auto ftt=std::vector>({CCPairFunction(f12, phi_i.function, phi_j.function)}); + + const vector_real_function_3d Vtau=info.intermediate_potentials(gs_singles, POT_singles_); + Projector OVtau(info.mo_bra,Vtau); + QProjector Qt(world,info.mo_bra,gs_singles.get_vecfunction()); + + auto p1=outer(OVtau,Qt); + auto p2=outer(Qt,OVtau); + + // result=Qt2(Ov1(ftt)) + Qt1(Ov2(ftt)); + auto result=p1(ftt) + p2(ftt); + + result=consolidate(result,{}); // will collect similar terms only + MADNESS_CHECK_THROW(result.size()==1 and result[0].is_decomposed(),"apply_Fock_commutator should return a single CCPairFunction"); + return result[0]; +} + +/// calculate [F,dQt] f12 |rhs> + +/// Using eq. (31) of Kottmann et al. JCTC 13, 5956 (2017) +/// note that we leave the omega dQ12t term out, as it cancels with eq. (29) +/// @return [F,Qt] f12 |rhs> - omega dQ12 f12 |phi_i phi_j> +madness::CCPairFunction +CCPotentials::apply_commutator_F_dQt_f12(World& world, const CCFunction& phi_i, const CCFunction& phi_j, + const CC_vecfunction& gs_singles, const CC_vecfunction& ex_singles, + const Info& info, const real_convolution_6d *Gscreen) { + const auto& parameters=info.parameters; + + + auto f12=CCConvolutionOperatorPtr(world,OT_F12,parameters); + auto ftt=std::vector>({CCPairFunction(f12, phi_i.function, phi_j.function)}); + + const vector_real_function_3d Vtau=info.intermediate_potentials(gs_singles, POT_singles_); + const vector_real_function_3d Vx=info.intermediate_potentials(ex_singles, POT_singles_); + Projector OVtau(info.mo_bra,Vtau); + Projector Ox(info.mo_bra,ex_singles.get_vecfunction()); + Projector OVx(info.mo_bra,Vx); + QProjector Qt(world,info.mo_bra,gs_singles.get_vecfunction()); + + auto p1_1=outer(OVx,Qt); + auto p1_2=outer(Qt,OVx); + auto p2_1=outer(Ox,OVtau); + auto p2_2=outer(OVtau,Ox); + + auto result=p1_1(ftt) + p1_2(ftt) - p2_1(ftt) - p2_2(ftt); + result=consolidate(result,{""}); // will collect similar terms only + MADNESS_CHECK_THROW(result.size()==1 and result[0].is_decomposed(),"apply_Fock_commutator should return a single CCPairFunction"); + return result[0]; +} + + +madness::real_function_6d +CCPotentials::apply_KffK(World& world, const CCFunction& phi_i, const CCFunction& phi_j, + const Info& info, const real_convolution_6d *Gscreen) { + real_function_3d x_ket = phi_i.function; + real_function_3d y_ket = phi_j.function; + real_function_3d x_bra = (info.R_square*phi_i.function).truncate(); + real_function_3d y_bra = (info.R_square*phi_j.function).truncate(); + const std::string x_name = phi_i.name(); + const std::string y_name = phi_j.name(); + + const auto& parameters=info.parameters; + + //apply Kf + if (parameters.debug()) print("\nComputing [K,f]|" + x_name + y_name + ">\n"); + + CCTimer time(world, "[K,f]|" + x_name + y_name + ">"); + CCTimer part1_time(world, "Kf" + x_name + y_name + ">"); + + bool symmetric_kf = false; + if ((phi_i.type == phi_j.type) && (phi_i.i == phi_j.i)) symmetric_kf = true; + + // First make the 6D function f12|x,y> + real_function_6d f12xy = make_f_xy_macrotask(world, x_ket, y_ket, x_bra, y_bra, phi_i.i, phi_j.i, + parameters, phi_i.type, phi_j.type, Gscreen); + f12xy.truncate().reduce_rank(); + // Apply the Exchange Operator + real_function_6d Kfxy = K_macrotask(world, info.mo_ket, info.mo_bra, f12xy, symmetric_kf, parameters); + + if (parameters.debug()) part1_time.info(); + + //apply fk + CCTimer part2_time(world, "fK" + x_name + y_name + ">"); + + const bool symmetric_fk = (phi_i==phi_j); + const real_function_3d Kx = K_macrotask(world, info.mo_ket, info.mo_bra, x_ket, parameters); + const FuncType Kx_type = UNDEFINED; + const real_function_6d fKphi0b = make_f_xy_macrotask(world, Kx, y_ket, x_bra, y_bra, phi_i.i, phi_j.i, + parameters, Kx_type, phi_j.type, Gscreen); + real_function_6d fKphi0a; + if (symmetric_fk) fKphi0a = madness::swap_particles(fKphi0b); + else { + real_function_3d Ky = K_macrotask(world, info.mo_ket, info.mo_bra, y_ket, parameters); + const FuncType Ky_type = UNDEFINED; + fKphi0a = make_f_xy_macrotask(world, x_ket, Ky, x_bra, y_bra, phi_i.i, phi_j.i, + parameters, phi_i.type, Ky_type, Gscreen); + } + const real_function_6d fKxy = (fKphi0a + fKphi0b); + + if (parameters.debug()) part2_time.info(); + + //final result + Kfxy.print_size("Kf" + x_name + y_name); + Kfxy.set_thresh(parameters.thresh_6D()); + Kfxy.truncate().reduce_rank(); + Kfxy.print_size("Kf after truncation" + x_name + y_name); + fKxy.print_size("fK" + x_name + y_name); + real_function_6d result = (Kfxy - fKxy); + result.set_thresh(parameters.thresh_6D()); + result.print_size("[K,f]" + x_name + y_name); + result.truncate().reduce_rank(); + result.print_size("[K,f]" + x_name + y_name); + + //sanity check + CCTimer sanity(world, "[K,f] sanity check"); + // make the =" << test << "\n"; + } + if (world.rank() == 0 && fabs(diff) > parameters.thresh_6D()) print("Exchange Commutator Plain Wrong"); + else print("Exchange Commutator seems to be sane, diff=" + std::to_string(diff)); + + if (parameters.debug()) sanity.info(diff); + + if (parameters.debug()) print("\n"); + + return result; +} + + madness::real_function_6d CCPotentials::apply_exchange_commutator_macrotask(World& world, const std::vector& mo_ket, const std::vector& mo_bra, const real_function_3d& Rsquare, @@ -2244,7 +2687,7 @@ CCPotentials::potential_singles_gs(const CC_vecfunction& singles, const Pairs& x, const CCFunction& phi_i, const CCFunction& phi_j, + const Info& info, const real_convolution_6d *Gscreen) { + const auto& parameters=info.parameters; + CorrelationFactor corrfac(world, parameters.gamma(), 1.e-7, parameters.lo()); + + real_function_6d fxy = CompositeFactory(world).g12(corrfac.f()). + particle1(copy(phi_i.function)).particle2(copy(phi_j.function)); + if (Gscreen == NULL) fxy.fill_tree().truncate().reduce_rank(); + else fxy.fill_cuspy_tree(*Gscreen).truncate().reduce_rank(); + return fxy; +} + + madness::real_function_6d CCPotentials::make_f_xy_macrotask(World& world, const real_function_3d& x_ket, const real_function_3d& y_ket, const real_function_3d& x_bra, const real_function_3d& y_bra, @@ -3029,12 +3486,12 @@ void CCPotentials::plot(const real_function_3d& f, const std::string& msg, const /// makes the t intermediates /// t_i = mo_ket_(i) + factor*tau(i) /// if factor!=1 then we can not use intermediates and set the type to UNDEFINED -CC_vecfunction CCPotentials::make_t_intermediate(const CC_vecfunction& tau, const double factor) const { +CC_vecfunction CCPotentials::make_t_intermediate(const CC_vecfunction& tau, const CCParameters& parameters) const { + FuncType returntype = MIXED; - if (factor != 1.0) returntype = UNDEFINED; if (tau.type == HOLE) { - output("make_t_intermediate: returning hole states"); + // output("make_t_intermediate: returning hole states"); return CC_vecfunction(get_active_mo_ket(), HOLE, parameters.freeze()); } if (tau.size() == 0) { @@ -3045,7 +3502,7 @@ CC_vecfunction CCPotentials::make_t_intermediate(const CC_vecfunction& tau, cons CC_vecfunction result(returntype); for (const auto& itmp:tau.functions) { const size_t i = itmp.first; - CCFunction t(mo_ket_(i).function + factor * tau(i).function, i, MIXED); + CCFunction t(mo_ket_(i).function + tau(i).function, i, MIXED); result.insert(i, t); } diff --git a/src/madness/chem/CCPotentials.h b/src/madness/chem/CCPotentials.h index 05a1fe202d7..f7249222f41 100644 --- a/src/madness/chem/CCPotentials.h +++ b/src/madness/chem/CCPotentials.h @@ -142,7 +142,7 @@ class CCPotentials { /// makes the t intermediates /// t_i = mo_ket_(i) + factor*tau(i) /// if factor!=1 then we can not use intermediates and set the type to UNDEFINED - CC_vecfunction make_t_intermediate(const CC_vecfunction& tau, const double factor = 1.0) const; + CC_vecfunction make_t_intermediate(const CC_vecfunction& tau, const CCParameters& parameters) const; /// makes the t intermediates /// t_i = mo_ket_(i) + factor*tau(i) @@ -267,6 +267,20 @@ class CCPotentials { const std::vector& U1, const std::vector argument); + /// Compute the constant part of MP2, CC2 or LR-CC2 + /// + /// depending on pair.calc_type different terms are included in the constant part. + /// @param[in] pair the (empty) pair function, determines the terms in the constant part, contains some bookkeeping information (bsh_eps, i, j) + /// @param[in] gs_singles the ground-state singles for CC2 (used for the T1-transformed SO projector), may be left empty for MP2 + /// @param[in] ex_singles the excited-state singles for CC2 (used for the T1-transformed SO projector), may be left empty for MP2 and GS-CC2 + /// @param[in] info the Info object, containing the some basic quantities (MOs, parameters, etc) + /// @return the constant part of the MP2, CC2 or LR-CC2: G(Q12(g~|titj>)) + static madness::real_function_6d + make_constant_part_macrotask(World& world, const CCPair& pair, + const CC_vecfunction& gs_singles, const CC_vecfunction& ex_singles, + const Info& info); + + /// Static function to iterate the mp2 pairs from macrotask static madness::real_function_6d update_pair_mp2_macrotask(World& world, const CCPair& pair, const CCParameters& parameters, @@ -331,6 +345,17 @@ class CCPotentials { real_function_6d apply_Vreg(const CCFunction& ti, const CCFunction& tj, const real_convolution_6d *Gscreen = NULL) const; + /// Apply the Regularization potential + /// \f$ V_{reg} = [ U_e - [K,f12] + f12(F12-eij) + [F,Qt] ]|titj> \f$ + /// @param[in] ti, first function in the ket, for MP2 it is the Orbital, for CC2 the relaxed Orbital t_i=\phi_i + \tau_i + /// @param[in] tj, second function in the ket ... + /// @param[in] pointer to bsh operator (in order to screen) + /// @param[out] the regularization potential (unprojected), see equation above + std::vector> + static apply_Vreg(World& world, const CCFunction& ti, const CCFunction& tj, + const CC_vecfunction& gs_singles, const CC_vecfunction& ex_singles, + const Info& info, const std::vector& argument, const double bsh_eps); + /// Static version of apply_Vreg to be used from a macrotask. Will eventually replace former. madness::real_function_6d static @@ -351,8 +376,19 @@ class CCPotentials { /// @param[in] tj, second function in the ket ... /// @param[in] pointer to bsh operator (in order to screen) real_function_6d - apply_reduced_F(const CCFunction& ti, const CCFunction& tj, const real_convolution_6d *Gscreen = NULL) const; + apply_reduced_F1(const CCFunction& ti, const CCFunction& tj, const real_convolution_6d *Gscreen = NULL) const; + /// evaluates: \f$ (F(1)-ei)|ti> (x) |tj> + |ti> (x) (F(2)-ej)|tj> \f$ with the help of the singles potential + /// singles equation is: (F-ei)|ti> = - V(ti) + /// response singles equation: (F-ei-omega)|xi> = - V(xi) + /// response: \f$ (F12-ei-ej-omega)|xitj> = (F1 - ei - omega)|xi> (x) |tj> + |xi> (x) (F2-ej)|tj> \f$ + /// so in both cases the result will be: |V(ti),tj> + |ti,V(tj)> + /// @param[in] ti, first function in the ket, for MP2 it is the Orbital, for CC2 the relaxed Orbital t_i=\phi_i + \tau_i + /// @param[in] tj, second function in the ket ... + /// @param[in] pointer to bsh operator (in order to screen) + real_function_6d + static apply_reduced_F(World& world, const CCFunction& ti, const CCFunction& tj, + const Info& info, const real_convolution_6d *Gscreen = NULL); /// Apply Ue on a tensor product of two 3d functions: Ue(1,2) |x(1)y(2)> (will be either |ij> or |\tau_i\tau_j> or mixed forms) /// The Transformed electronic regularization potential (Kutzelnigg) is R_{12}^{-1} U_e R_{12} with R_{12} = R_1*R_2 @@ -376,6 +412,24 @@ class CCPotentials { const FuncType& x_type, const FuncType& y_type, const real_convolution_6d *Gscreen = NULL); + real_function_6d + static apply_Ue(World& world, const CCFunction& phi_i, const CCFunction& phi_j, + const Info& info, const real_convolution_6d *Gscreen); + + + static real_function_6d + apply_KffK(World& world, const CCFunction& phi_i, const CCFunction& phi_j, + const Info& info, const real_convolution_6d *Gscreen) ; + static CCPairFunction + apply_commutator_F_Qt_f12(World& world, const CCFunction& phi_i, const CCFunction& phi_j, + const CC_vecfunction& gs_singles, const CC_vecfunction& ex_singles, + const Info& info, const real_convolution_6d *Gscreen) ; + + static CCPairFunction + apply_commutator_F_dQt_f12(World& world, const CCFunction& phi_i, const CCFunction& phi_j, + const CC_vecfunction& gs_singles, const CC_vecfunction& ex_singles, + const Info& info, const real_convolution_6d *Gscreen) ; + /// Apply Ue on a tensor product of two 3d functions: Ue(1,2) |x(1)y(2)> (will be either |ij> or |\tau_i\tau_j> or mixed forms) /// The Transformed electronic regularization potential (Kutzelnigg) is R_{12}^{-1} U_e R_{12} with R_{12} = R_1*R_2 /// It is represented as: R_{12}^{-1} U_e R_{12} = U_e + R^-1[Ue,R] @@ -681,6 +735,11 @@ class CCPotentials { real_function_6d make_f_xy(const CCFunction& x, const CCFunction& y, const real_convolution_6d *Gscreen = NULL) const; + /// Creates a 6D function with the correlation factor and two given CCFunctions + real_function_6d + static make_f_xy(World& world, const CCFunction& x, const CCFunction& y, + const Info& info, const real_convolution_6d *Gscreen = NULL); + real_function_6d static make_f_xy_macrotask( World& world, const real_function_3d& x_ket, const real_function_3d& y_ket, const real_function_3d& x_bra, const real_function_3d& y_bra, @@ -805,7 +864,9 @@ class CCPotentials { } } -protected: +public: + + // member variables /// MPI World World& world; @@ -828,6 +889,8 @@ class CCPotentials { CorrelationFactor corrfac; /// Manager for stored intermediate potentials which are s2c, s2b and the whole singles potentials without fock-residue for GS and EX state mutable CCIntermediatePotentials get_potentials; + /// POD for basis and intermediates + Info info; public: /// Messenger structure for formated output and to store warnings CCMessenger output; diff --git a/src/madness/chem/CCStructures.cc b/src/madness/chem/CCStructures.cc index 218337c7f30..8f4009825fa 100644 --- a/src/madness/chem/CCStructures.cc +++ b/src/madness/chem/CCStructures.cc @@ -125,7 +125,7 @@ CCIntermediatePotentials::operator()(const CC_vecfunction& f, const PotentialTyp else if (type == POT_s2c_ and f.type == RESPONSE) return current_s2c_potential_ex_; else if (f.type == HOLE) { output(assign_name(type) + " is zero for HOLE states"); - result = zero_functions(world, f.size()); + // result = zero_functions(f.size()); } else { output("ERROR: Potential was not supposed to be stored"); MADNESS_EXCEPTION("Potential was not supposed to be stored", 1); @@ -139,22 +139,17 @@ CCIntermediatePotentials::operator()(const CC_vecfunction& f, const PotentialTyp madness::real_function_3d CCIntermediatePotentials::operator()(const CCFunction& f, const PotentialType& type) const { output("Getting " + assign_name(type) + " for " + f.name()); - real_function_3d result = real_factory_3d(world); - if (type == POT_singles_ and (f.type == PARTICLE or f.type == MIXED)) - return current_singles_potential_gs_[f.i - parameters.freeze()]; + if (type == POT_singles_ and (f.type == PARTICLE or f.type == MIXED)) return current_singles_potential_gs_[f.i - parameters.freeze()]; else if (type == POT_singles_ and f.type == RESPONSE) return current_singles_potential_ex_[f.i - parameters.freeze()]; else if (type == POT_s2b_ and f.type == PARTICLE) return current_s2b_potential_gs_[f.i - parameters.freeze()]; else if (type == POT_s2b_ and f.type == RESPONSE) return current_s2b_potential_ex_[f.i - parameters.freeze()]; else if (type == POT_s2c_ and f.type == PARTICLE) return current_s2c_potential_gs_[f.i - parameters.freeze()]; else if (type == POT_s2c_ and f.type == RESPONSE) return current_s2c_potential_ex_[f.i - parameters.freeze()]; else if (f.type == HOLE) output(assign_name(type) + " is zero for HOLE states"); - else MADNESS_EXCEPTION("Potential was not supposed to be stored", 1) + else MADNESS_EXCEPTION("Potential was not supposed to be stored", 1); - ; - if (result.norm2() < FunctionDefaults<3>::get_thresh()) - output("WARNING: Potential seems to be zero ||V||=" + std::to_string(double(result.norm2()))); - return result; + return real_function_3d(); } void @@ -527,34 +522,54 @@ assign_name(const FuncType& inp) { std::vector -MacroTaskMp2ConstantPart::operator() (const std::vector& pair, const std::vector& mo_ket, - const std::vector& mo_bra, const CCParameters& parameters, - const real_function_3d& Rsquare, const std::vector& U1, +//MacroTaskMp2ConstantPart::operator() (const std::vector& pair, const std::vector& mo_ket, +// const std::vector& mo_bra, const CCParameters& parameters, +// const real_function_3d& Rsquare, const std::vector& U1, +// const std::vector& argument) const { +MacroTaskMp2ConstantPart::operator() (const std::vector& pair, const Info& info, const std::vector& argument) const { - World& world = mo_ket[0].world(); + World& world =info.mo_ket[0].world(); resultT result = zero_functions_compressed(world, pair.size()); for (size_t i = 0; i < pair.size(); i++) { - result[i] = CCPotentials::make_constant_part_mp2_macrotask(world, pair[i], mo_ket, mo_bra, parameters, - Rsquare, U1, argument); + result[i] = CCPotentials::make_constant_part_mp2_macrotask(world, pair[i], info.mo_ket, info.mo_bra, + info.parameters, info.R_square, info.U1, argument); } return result; } std::vector +MacroTaskConstantPart::operator() (const std::vector& pair, + const std::vector> & gs_singles, + const std::vector> & ex_singles, + const Info& info) const { + World& world =info.mo_ket[0].world(); + resultT result = zero_functions_compressed(world, pair.size()); + for (size_t i = 0; i < pair.size(); i++) { + result[i] = CCPotentials::make_constant_part_macrotask(world, pair[i], gs_singles, ex_singles, info); + } + return result; +} + + +std::vector +//MacroTaskMp2UpdatePair::operator() (const std::vector &pair, +// const std::vector &mp2_coupling, +// const CCParameters ¶meters, +// const std::vector> &all_coords_vec, +// const std::vector &mo_ket, +// const std::vector &mo_bra, +// const std::vector &U1, const real_function_3d &U2) const { MacroTaskMp2UpdatePair::operator() (const std::vector &pair, const std::vector &mp2_coupling, - const CCParameters ¶meters, const std::vector> &all_coords_vec, - const std::vector &mo_ket, - const std::vector &mo_bra, - const std::vector &U1, const real_function_3d &U2) const { - World& world = mo_ket[0].world(); + const Info& info) const { + World& world = info.mo_ket[0].world(); resultT result = zero_functions_compressed(world, pair.size()); for (size_t i = 0; i < pair.size(); i++) { //(i, j) -> j*(j+1) + i - result[i] = CCPotentials::update_pair_mp2_macrotask(world, pair[i], parameters, all_coords_vec, mo_ket, - mo_bra, U1, U2, mp2_coupling[i]); + result[i] = CCPotentials::update_pair_mp2_macrotask(world, pair[i], info.parameters, all_coords_vec, info.mo_ket, + info.mo_bra, info.U1, info.U2, mp2_coupling[i]); } return result; } diff --git a/src/madness/chem/CCStructures.h b/src/madness/chem/CCStructures.h index 6d9efd68a0b..ba14deec3b4 100644 --- a/src/madness/chem/CCStructures.h +++ b/src/madness/chem/CCStructures.h @@ -1059,7 +1059,11 @@ class CCPair : public archive::ParallelSerializableObject { /// little helper structure which manages the stored singles potentials struct CCIntermediatePotentials { - CCIntermediatePotentials(World& world, const CCParameters& p) : world(world), parameters(p) {}; + CCIntermediatePotentials() = default; + CCIntermediatePotentials(const CCParameters& p) : parameters(p) {}; + + CCIntermediatePotentials(const CCIntermediatePotentials& other) = default; + CCIntermediatePotentials& operator=(const CCIntermediatePotentials& other) = default; /// fetches the correct stored potential or throws an exception vector_real_function_3d @@ -1090,9 +1094,52 @@ struct CCIntermediatePotentials { void insert(const vector_real_function_3d& potential, const CC_vecfunction& f, const PotentialType& type); + Recordlist cloud_store(World& world, Cloud& cloud) const { + Recordlist records; + records+=cloud.store(world,parameters); + records+=cloud.store(world,current_s2b_potential_ex_); + records+=cloud.store(world,current_s2b_potential_gs_); + records+=cloud.store(world,current_s2c_potential_ex_); + records+=cloud.store(world,current_s2c_potential_gs_); + records+=cloud.store(world,current_singles_potential_ex_); + records+=cloud.store(world,current_singles_potential_gs_); + records+=cloud.store(world,unprojected_cc2_projector_response_); + return records; + } + + void cloud_load(World& world, const Cloud& cloud, Recordlist& recordlist) { + parameters=cloud.forward_load(world,recordlist); + current_s2b_potential_ex_=cloud.forward_load(world,recordlist); + current_s2b_potential_gs_=cloud.forward_load(world,recordlist); + current_s2c_potential_ex_=cloud.forward_load(world,recordlist); + current_s2c_potential_gs_=cloud.forward_load(world,recordlist); + current_singles_potential_ex_=cloud.forward_load(world,recordlist); + current_singles_potential_gs_=cloud.forward_load(world,recordlist); + unprojected_cc2_projector_response_=cloud.forward_load(world,recordlist); + } + + friend hashT hash_value(const CCIntermediatePotentials& ip) { + auto hash_vector_of_functions =[](const vector_real_function_3d& v) { + hashT h; + for (const auto& f : v) { + hash_combine(h, hash_value(f.get_impl()->id())); + } + return h; + }; + hashT h; + hash_combine(h, hash_vector_of_functions(ip.current_s2b_potential_ex_)); + hash_combine(h, hash_vector_of_functions(ip.current_s2b_potential_gs_)); + hash_combine(h, hash_vector_of_functions(ip.current_s2c_potential_ex_)); + hash_combine(h, hash_vector_of_functions(ip.current_s2c_potential_gs_)); + hash_combine(h, hash_vector_of_functions(ip.current_singles_potential_ex_)); + hash_combine(h, hash_vector_of_functions(ip.current_singles_potential_gs_)); + hash_combine(h, hash_vector_of_functions(ip.unprojected_cc2_projector_response_)); + return h; + } + + CCParameters parameters; private: - World& world; - const CCParameters& parameters; + // World& world; /// whole ground state singles potential without fock-residue vector_real_function_3d current_singles_potential_gs_; /// whole excited state singles potential without fock-residue @@ -1111,11 +1158,57 @@ struct CCIntermediatePotentials { /// structured output void output(const std::string& msg) const { - if (world.rank() == 0 and parameters.debug()) + if (parameters.debug()) std::cout << "Intermediate Potential Manager: " << msg << "\n"; } }; +/// POD holding some basic functions and some intermediates for the CC2 calculation + +/// the class is cloud-serializable and can be used in MacroTasks +struct Info { + std::vector> mo_ket; + std::vector> mo_bra; + CCParameters parameters; + std::vector orbital_energies; + CCIntermediatePotentials intermediate_potentials; + Function R_square, U2; + std::vector> U1; + + /// customized function to store this to the cloud + + /// functions and constant_part can be very large and we want to split them and store them in different records + Recordlist cloud_store(World& world, Cloud& cloud) const { + Recordlist records; + records+=cloud.store(world,mo_bra); + records+=cloud.store(world,mo_ket); + records+=cloud.store(world,parameters); + records+=cloud.store(world,orbital_energies); + records+=cloud.store(world,intermediate_potentials); + records+=cloud.store(world,R_square); + records+=cloud.store(world,U2); + records+=cloud.store(world,U1); + return records; + } + + /// customized function to load this from the cloud + + /// functions and constant_part can be very large and we want to split them and store them in different records + /// @param[inout] recordlist: containing the keys of the member variables -> will be reduced by the keys which are used + void cloud_load(World& world, const Cloud& cloud, Recordlist& recordlist) { + // load bookkeeping stuff in a vector + mo_bra=cloud.forward_load>>(world,recordlist); + mo_ket=cloud.forward_load>>(world,recordlist); + parameters=cloud.forward_load(world,recordlist); + orbital_energies=cloud.forward_load>(world,recordlist); + intermediate_potentials=cloud.forward_load(world,recordlist); + R_square=cloud.forward_load>(world,recordlist); + U2=cloud.forward_load>(world,recordlist); + U1=cloud.forward_load>>(world,recordlist); + } + +}; + class MacroTaskMp2ConstantPart : public MacroTaskOperationBase { class ConstantPartPartitioner : public MacroTaskPartitioner { @@ -1136,9 +1229,10 @@ class MacroTaskMp2ConstantPart : public MacroTaskOperationBase { public: MacroTaskMp2ConstantPart(){partitioner.reset(new ConstantPartPartitioner());} - typedef std::tuple&, const std::vector>&, - const std::vector>&, const CCParameters&, const Function&, - const std::vector>&, const std::vector& > argtupleT; + // typedef std::tuple&, const std::vector>&, + // const std::vector>&, const CCParameters&, const Function&, + // const std::vector>&, const std::vector& > argtupleT; + typedef std::tuple&, const madness::Info&, const std::vector& > argtupleT; using resultT = std::vector; @@ -1148,10 +1242,57 @@ class MacroTaskMp2ConstantPart : public MacroTaskOperationBase { return result; } - resultT operator() (const std::vector& pair, const std::vector>& mo_ket, - const std::vector>& mo_bra, const CCParameters& parameters, - const Function& Rsquare, const std::vector>& U1, - const std::vector& argument) const; +// resultT operator() (const std::vector& pair, const std::vector>& mo_ket, +// const std::vector>& mo_bra, const CCParameters& parameters, +// const Function& Rsquare, const std::vector>& U1, +// const std::vector& argument) const; + resultT operator() (const std::vector& pair, const Info& info, const std::vector& argument) const; +}; + +/// compute the "constant" part of MP2, CC2, or LR-CC2 +/// +/// the constant part is +/// result = G [F,f] |ij> for MP2 +/// result = G [F,f] |t_i t_j> for CC2 +/// result = G [F,f] |t_i x_j> + |x_i t_j> for LR-CC2 +class MacroTaskConstantPart : public MacroTaskOperationBase { + + class ConstantPartPartitioner : public MacroTaskPartitioner { + public: + ConstantPartPartitioner() {}; + + partitionT do_partitioning(const std::size_t& vsize1, const std::size_t& vsize2, + const std::string policy) const override { + partitionT p; + for (size_t i = 0; i < vsize1; i++) { + Batch batch(Batch_1D(i,i+1), Batch_1D(i,i+1)); + p.push_back(std::make_pair(batch,1.0)); + } + return p; + } + }; + +public: + MacroTaskConstantPart(){partitioner.reset(new ConstantPartPartitioner());} + + // typedef std::tuple&, const std::vector>&, + // const std::vector>&, const CCParameters&, const Function&, + // const std::vector>&, const std::vector& > argtupleT; + typedef std::tuple&, + const std::vector>&, const std::vector>&, + const madness::Info&> argtupleT; + + using resultT = std::vector; + + resultT allocator(World& world, const argtupleT& argtuple) const { + std::size_t n = std::get<0>(argtuple).size(); + resultT result = zero_functions_compressed(world, n); + return result; + } + resultT operator() (const std::vector& pair, + const std::vector>& gs_singles, + const std::vector>& ex_singles, + const Info& info) const; }; class MacroTaskMp2UpdatePair : public MacroTaskOperationBase { @@ -1175,10 +1316,12 @@ class MacroTaskMp2UpdatePair : public MacroTaskOperationBase { public: MacroTaskMp2UpdatePair() {partitioner.reset(new UpdatePairPartitioner());} - typedef std::tuple&, const std::vector&, const CCParameters&, - const std::vector< madness::Vector >&, - const std::vector>&, const std::vector>&, - const std::vector>&, const Function&> argtupleT; + // typedef std::tuple&, const std::vector&, const CCParameters&, + // const std::vector< madness::Vector >&, + // const std::vector>&, const std::vector>&, + // const std::vector>&, const Function&> argtupleT; + typedef std::tuple&, const std::vector&, + const std::vector>&, const Info& > argtupleT; using resultT = std::vector; @@ -1188,10 +1331,12 @@ class MacroTaskMp2UpdatePair : public MacroTaskOperationBase { return result; } - resultT operator() (const std::vector& pair, const std::vector& mp2_coupling, const CCParameters& parameters, - const std::vector< madness::Vector >& all_coords_vec, - const std::vector>& mo_ket, const std::vector>& mo_bra, - const std::vector>& U1, const Function& U2) const; +// resultT operator() (const std::vector& pair, const std::vector& mp2_coupling, const CCParameters& parameters, +// const std::vector< madness::Vector >& all_coords_vec, +// const std::vector>& mo_ket, const std::vector>& mo_bra, +// const std::vector>& U1, const Function& U2) const; + resultT operator() (const std::vector& pair, const std::vector& mp2_coupling, + const std::vector< madness::Vector >& all_coords_vec, const Info& info) const; }; }//namespace madness diff --git a/src/madness/chem/ccpairfunction.cc b/src/madness/chem/ccpairfunction.cc index 8fbfe3010c6..3eef80ff54f 100644 --- a/src/madness/chem/ccpairfunction.cc +++ b/src/madness/chem/ccpairfunction.cc @@ -618,10 +618,10 @@ std::vector> CCPairFunction::apply(const Projecto auto tmp2=CCPairFunction(tmp); result.push_back(tmp2); } else if (auto P=dynamic_cast*>(&projector)) { - result.push_back(CCPairFunction((*P)(pf.get_function(),P->get_particle()+1))); + result.push_back(CCPairFunction((*P)(pf.get_function()))); } else if (auto Q=dynamic_cast*>(&projector)) { - result.push_back(CCPairFunction((*Q)(pf.get_function(),Q->get_particle()+1))); + result.push_back(CCPairFunction((*Q)(pf.get_function()))); } else { MADNESS_EXCEPTION("CCPairFunction: unknown projector type",1); diff --git a/src/madness/chem/ccpairfunction.h b/src/madness/chem/ccpairfunction.h index 309171900ca..6d26a688b23 100644 --- a/src/madness/chem/ccpairfunction.h +++ b/src/madness/chem/ccpairfunction.h @@ -458,7 +458,7 @@ using pureT=Function; /// @param[in] centers: a vector of 3D-vectors which are the centers of the grid for low-rank functions /// TODO: implement a function for removing linearly dependent terms without orthonormalization friend std::vector consolidate(const std::vector& other, - const std::vector options, + const std::vector options=std::vector(), const std::vector> centers=std::vector>()) { if (other.size()>0) return other.front().consolidate(other,options,centers); // workaround @@ -760,33 +760,8 @@ using pureT=Function; const std::pair>, std::vector>> assign_particles(const size_t particle) const; static std::vector> apply(const ProjectorBase& P, const std::vector>& argument); - - /// apply the operator on a CCPairfunction, both with the same dimension - - /// note there is another function, where the operator works only on some dimensions of the CCPairFunction! - /// @return result(x) = \int op(x,x') arg(x') dx': a CCPairfunction with the same dimension as the argument - friend CCPairFunction apply(const SeparatedConvolution& G, const CCPairFunction& argument) { - CCPairFunction result; - timer t1(argument.world()); - if (argument.is_pure()) { - result=CCPairFunction(G(argument.get_function())); - } else if (argument.is_decomposed_no_op()) { - Function result1=real_factory_6d(argument.world()).compressed(); - - MADNESS_ASSERT(argument.get_a().size() == argument.get_b().size()); - MADNESS_CHECK_THROW(G.particle()==-1,"G must be a two-particle operator in apply(CCPairFunction)"); - - for (size_t k = 0; k < argument.get_a().size(); k++) { - const Function tmp = G(argument.get_a()[k], argument.get_b()[k]); - result1 += tmp; - } - result=CCPairFunction(result1); - } else { - MADNESS_EXCEPTION("unknown type in CCPairFunction::apply",1); - } - t1.end("applying G to " + argument.name()); - return result; - }; + static std::vector> apply(const SeparatedConvolution& G, const CCPairFunction& argument); + static std::vector> apply(const SeparatedConvolution& G, const std::vector>& argument); Function partial_inner(const Function& f, @@ -909,12 +884,33 @@ std::vector> apply(const SeparatedConvolution& return result; } +/// apply the operator on a CCPairfunction, both with the same dimension + +/// note there is another function, where the operator works only on some dimensions of the CCPairFunction! +/// @return result(x) = \int op(x,x') arg(x') dx': a CCPairfunction with the same dimension as the argument template -CCPairFunction apply(const ProjectorBase& projector, const CCPairFunction& argument) { - auto result=madness::apply(projector,std::vector> (1,argument)); - MADNESS_CHECK(result.size()==1); - return result[0]; -} +CCPairFunction apply(const SeparatedConvolution& G, const CCPairFunction& argument) { + CCPairFunction result; + timer t1(argument.world()); + if (argument.is_pure()) { + result=CCPairFunction(G(argument.get_function())); + } else if (argument.is_decomposed_no_op()) { + Function result1=real_factory_6d(argument.world()).compressed(); + + MADNESS_ASSERT(argument.get_a().size() == argument.get_b().size()); + + for (size_t k = 0; k < argument.get_a().size(); k++) { + const Function tmp = G(argument.get_a()[k], argument.get_b()[k]); + result1 += tmp; + } + result=CCPairFunction(result1); + } else { + MADNESS_EXCEPTION("unknown type in CCPairFunction::apply",1); + } + t1.end("applying G to " + argument.name()); + return result; +}; + /// apply the projector on the argument function, potentially yielding a vector of CCPairfunctions as result @@ -928,6 +924,13 @@ std::vector> apply(const ProjectorBase& projector, const } +template +CCPairFunction apply(const ProjectorBase& projector, const CCPairFunction& argument) { + auto result=madness::apply(projector,std::vector> (1,argument)); + MADNESS_CHECK(result.size()==1); + return result[0]; +} + template Function::LDIM>inner(const CCPairFunction& c, const Function::LDIM>& f, const std::tuple v1, const std::tuple v2) { @@ -987,6 +990,28 @@ std::vector> inner(const std::vector +std::vector > operator+(const std::vector> c1, const std::vector >& c2) { + std::vector> result; + for (const auto& l : c1) result.push_back(l); + for (const auto& l : c2) result.push_back(l); + return result; +} + +template +std::vector > operator-(const std::vector> c1, const std::vector >& c2) { + std::vector> result; + for (const auto& l : c1) result.push_back(l); + for (const auto& l : c2) result.push_back(-1.0*l); + return result; +} + +template +std::vector >& operator+=(std::vector >& lhs, + const CCPairFunction& rhs) { + lhs.push_back(rhs); + return lhs; +} template std::vector >& operator+=(std::vector >& rhs, diff --git a/src/madness/chem/projector.h b/src/madness/chem/projector.h index f40341a5d50..7f082fc8511 100644 --- a/src/madness/chem/projector.h +++ b/src/madness/chem/projector.h @@ -17,11 +17,15 @@ namespace madness { class ProjectorBase { protected: /// a projector might work only on a subset of dimensions, e.g. P(1) | \psi(1,2) > - int particle=-1; + int particle=-1; // must only be 0 or 1! public: virtual ~ProjectorBase() {} - virtual void set_particle(const int p) {particle=p;} - int get_particle() const {return particle;} + virtual void set_particle(const int p) + { + MADNESS_CHECK_THROW(p==0 or p==1, "particle must be 0 or 1"); + particle=p; + } + virtual int get_particle() const {return particle;} virtual std::string type() const = 0; }; @@ -113,21 +117,24 @@ namespace madness { /// @return the projected function template typename std::enable_if >::type - operator()(const Function& f, size_t particle1=size_t(-1)) const { + operator()(const Function& f, int particle1=-1) const { Function result = FunctionFactory(f.world()); - if (particle1==size_t(-1)) particle1=particle; - MADNESS_CHECK_THROW(particle1 == 1 or particle1 == 2, "particle must be 1 or 2"); + if (particle1==-1) particle1=get_particle(); + MADNESS_CHECK_THROW(particle1 == 0 or particle1 == 1, "particle must be 1 or 2"); for (size_t i = 0; i < mo_ket_.size(); i++) { Function tmp1 = mo_ket_[i]; - Function tmp2 = f.project_out(mo_bra_[i], particle1 - 1); + Function tmp2 = f.project_out(mo_bra_[i], particle1); Function tmp12; - if (particle1 == 1) { + if (particle1 == 0) { tmp12 = CompositeFactory(f.world()).particle1(copy(tmp1)).particle2(copy(tmp2)); tmp12.fill_tree(); - } else { + } else if (particle1==1) { tmp12 = CompositeFactory(f.world()).particle1(copy(tmp2)).particle2(copy(tmp1)); tmp12.fill_tree(); + } else { + MADNESS_EXCEPTION("messed up",1); } + result += tmp12; } return result; @@ -184,7 +191,7 @@ namespace madness { return result; } - Function operator()(const Function& f, const size_t particle) const { + Function operator()(const Function& f, const size_t particle=-1) const { return f-O(f,particle); } @@ -200,8 +207,12 @@ namespace madness { Projector get_P_projector() const {return O;} void set_particle(const int p) override { - particle=p; O.set_particle(p); + particle=p; + } + + int get_particle() const override { + return O.get_particle(); } private: @@ -367,6 +378,35 @@ namespace madness { std::vector > ket1_, bra1_, ket2_, bra2_; }; + + + /// an outer product of two projectors + template + class OuterProjector : public ProjectorBase { + projT projector0; + projQ projector1; + public: + + OuterProjector() = default; + OuterProjector(const projT& p0, const projQ& p1) : projector0(p0), projector1(p1) { + projector0.set_particle(0); + projector1.set_particle(1); + } + + std::string type() const override { + return "OuterProjector"; + } + + template + resultT operator()(const resultT& argument) const { + return projector0(projector1(argument)); + } + }; + + template + OuterProjector outer(const projT& p0 , const projQ& p1) { + return OuterProjector(p0, p1); + } } #endif /* PROJECTOR_H_ */ diff --git a/src/madness/chem/test_projector.cc b/src/madness/chem/test_projector.cc index 1cf44fd8147..e58f435daf4 100644 --- a/src/madness/chem/test_projector.cc +++ b/src/madness/chem/test_projector.cc @@ -70,6 +70,36 @@ int test_projector(World& world) { + return t1.end(); +} + +template +int test_projector_outer(World& world) { + test_output t1("testing projector_outer for dimension " + std::to_string(NDIM)); + constexpr std::size_t LDIM=NDIM/2; + static_assert(2*LDIM==NDIM); + + auto g1=[](const Vector& r){return exp(-inner(r,r));}; + auto g_hidim=[](const Vector& r){return 2.0*exp(-3.0*inner(r,r));}; + Function f1=FunctionFactory(world).f(g1); + Function f_hidim=FunctionFactory(world).f(g_hidim); + + + // compare explicit SO projector Q12 and outer product projector Q1Q2 + StrongOrthogonalityProjector Q1(world); + Q1.set_spaces({f1}); + + QProjector q(world,{f1}); + auto Q2=outer(q,q); + + auto Q1f=Q1(f_hidim); + auto Q2f=Q2(f_hidim); + double err=(Q1f-Q2f).norm2(); + double norm=Q1f.norm2(); + print("norm",norm); + + t1.checkpoint(err/norm,FunctionDefaults::get_thresh(),"Q1 direct and Q2 outer are the same"); + return t1.end(); } @@ -128,8 +158,8 @@ int test_Q12_projector(World& world) { // SO(f) = f - O1(f) - O2(f) + O1O2(f) Projector O1(vphi); Projector O2(vphi); - O1.set_particle(1); - O2.set_particle(2); + O1.set_particle(0); + O2.set_particle(1); Function f3=f-O1(f)-O2(f)+O1(O2(f)); double err1=(f1-f3).norm2()/f.norm2(); print("err1",err1); @@ -191,6 +221,8 @@ int main(int argc, char**argv) { error+=test_projector(world); error+=test_projector(world); + error+=test_projector_outer(world); + if (HAVE_GENTENSOR) { error+=test_Q12_projector(world); error+=test_Q12_projector(world); From 1b32015e254283044a498db8ecd5643090219258 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Tue, 4 Jun 2024 15:50:47 -0400 Subject: [PATCH 06/54] checkpoint macrotasks for MP2, CC2 and LRCC2 --- src/madness/chem/CC2.cc | 16 +-- src/madness/chem/CCPotentials.cc | 192 ++++++++++++++++++++++++----- src/madness/chem/CCPotentials.h | 5 + src/madness/chem/CCStructures.h | 12 ++ src/madness/chem/ccpairfunction.cc | 8 +- src/madness/chem/ccpairfunction.h | 15 +-- src/madness/chem/projector.h | 6 +- src/madness/mra/mra.h | 13 +- 8 files changed, 215 insertions(+), 52 deletions(-) diff --git a/src/madness/chem/CC2.cc b/src/madness/chem/CC2.cc index ebf6c7fea79..e42dabc78f4 100644 --- a/src/madness/chem/CC2.cc +++ b/src/madness/chem/CC2.cc @@ -736,16 +736,16 @@ CC2::iterate_lrcc2_pairs(const CC_vecfunction& cc2_s, const Pairs& cc2_d const size_t i = pair.i; const size_t j = pair.j; // check if singles have significantly changed - if (lrcc2_s(i).current_error < 0.1 * parameters.thresh_6D() and - lrcc2_s(j).current_error < 0.1 * parameters.thresh_6D()) - output("Skipping Pair Iteration, No significant Change in Singles"); - else { + // if (lrcc2_s(i).current_error < 0.1 * parameters.thresh_6D() and + // lrcc2_s(j).current_error < 0.1 * parameters.thresh_6D()) + // output("Skipping Pair Iteration, No significant Change in Singles"); + // else { pair.bsh_eps = CCOPS.get_epsilon(pair.i, pair.j) + lrcc2_s.omega; - // update_constant_part_lrcc2(pair, cc2_s, lrcc2_s); - pair.constant_part=CCPotentials::make_constant_part_macrotask(world, pair, - cc2_s, lrcc2_s, info); + update_constant_part_lrcc2(pair, cc2_s, lrcc2_s); + // pair.constant_part=CCPotentials::make_constant_part_macrotask(world, pair, + // cc2_s, lrcc2_s, info); conv = iterate_pair(pair, lrcc2_s); - } + // } } return conv; diff --git a/src/madness/chem/CCPotentials.cc b/src/madness/chem/CCPotentials.cc index 881fdcf1fd8..cc4da0fbc52 100644 --- a/src/madness/chem/CCPotentials.cc +++ b/src/madness/chem/CCPotentials.cc @@ -700,12 +700,8 @@ CCPotentials::make_constant_part_macrotask(World& world, const CCPair& pair, // t1-transformed orbitals CC_vecfunction t(MIXED); - if (targetstate==CT_CC2 or targetstate==CT_LRCC2) - { - for (int i=0; i t1(info.mo_ket[i] + gs_singles(i).function, i, MIXED); - t.insert(i, t1); - } + if (targetstate==CT_CC2 or targetstate==CT_LRCC2) { + t=CCPotentials::make_full_t_intermediate(gs_singles,info); } // construct the projectors @@ -748,6 +744,24 @@ CCPotentials::make_constant_part_macrotask(World& world, const CCPair& pair, return result; }; + auto GG = BSHOperator<6>(world, sqrt(-2.0 * pair.bsh_eps), parameters.lo(), parameters.thresh_bsh_6D()); + GG.destructive() = true; + GG.print_timings=false; + auto apply_G_and_print = [&](const std::vector>& cc, std::string name) { + std::vector> tmp1; + print("cc in apply_G_and_print:",name,cc.size()); + for (const auto& tt : cc) tmp1 += GG(copy(tt)); + print("tmp1 after apply G"); + for (const auto& tt : tmp1) { + print(tt.name()); + tt.print_size(); + } + tmp1=consolidate(tmp1); + tmp1=-2.0*tmp1; + MADNESS_CHECK(tmp1.size()==1); + tmp1[0].get_function().print_size(name); + }; + // compute all 6d potentials without applying the SO projector std::vector> V; if (targetstate==CT_MP2) { @@ -761,20 +775,85 @@ CCPotentials::make_constant_part_macrotask(World& world, const CCPair& pair, } else if (targetstate==CT_LRCC2) { // Eq. (25) of Kottmann, JCTC 13, 5956 (2017) // eq. (25) Q12t (g~ - omega f12) (|x_i t_j> + |t_i x_j> ) // note the term omega f12 is included in the reduced_Fock term, see eq. (34) - std::vector argument={"Ue","KffK","comm_F_Qt_f12","reduced_Fock"}; - auto Vreg=apply_Vreg(world,t(i),x(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); - Vreg+=apply_Vreg(world,x(i),t(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); - V=consolidate(apply_in_separated_form(Q12t,Vreg)); + if (0) + { + std::vector argument={"Ue","KffK","comm_F_Qt_f12","reduced_Fock"}; + auto Vreg=apply_Vreg(world,x(i),t(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); + //debug Vreg+=apply_Vreg(world,t(i),x(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); + V=consolidate(apply_in_separated_form(Q12t,Vreg)); + apply_G_and_print(V,"functional response"); + } + + if (0) { + std::vector argument={"Ue","KffK","reduced_Fock"}; + auto Vreg=apply_Vreg(world,x(i),t(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); + Vreg+=apply_Vreg(world,t(i),x(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); + + V=consolidate(apply_in_separated_form(Q12t,Vreg)); + apply_G_and_print(V,"functional response in old terminology, V -- separated"); +// print("debug 1", V.size()); +// for (auto& vv : V) { +// print(vv.name()); +// vv.print_size(); +// } +// for (auto& vv : V) vv.convert_to_pure_no_op_inplace(); +// print("debug 2", V.size()); +// for (auto& vv : V) { +// print(vv.name()); +// vv.print_size(); +// } +// V=consolidate(V); +// print("debug 3", V.size()); +// for (auto& vv : V) { +// print(vv.name()); +// vv.print_size(); +// } +// print("V separate-consolidate",V.size()); +// V[0].get_function().print_size("Q12t_FQtQtF_f12.size() separate-consolidate"); +// apply_G_and_print(V,"functional response in old terminology, V -- consolidated"); +// +// auto Q12V=Q12t(Vreg); +// print("Q12t_Ue_KffK_redF.size()",Q12V.size()); +// Q12V[0].get_function().print_size("Q12t_FQtQtF_f12"); +// apply_G_and_print(Q12V,"functional response in old terminology, Q12V- single term"); + } + if (1) { + print_header3("[F12,Qt] f12 |x_i t_j + t_i x_j>"); + std::vector argument={"comm_F_Qt_f12"}; + auto Vreg=apply_Vreg(world,x(i),t(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); + Vreg+=apply_Vreg(world,t(i),x(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); + auto Q12V=Q12t(Vreg); + print("Q12t_FQtQtF_f12.size()",Q12V.size()); + apply_G_and_print(Q12V,"commutator response in old terminology: Q12V direct"); + + V=consolidate(apply_in_separated_form(Q12t,Vreg)); + apply_G_and_print(V,"commutator response in old terminology: Q12V separated"); + + } // eq. (29) first term: dQt g~ |t_i t_j> - argument={"Ue","KffK","comm_F_Qt_f12","reduced_Fock"}; - auto Vreg1=apply_Vreg(world,t(i),t(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); - V-=consolidate(dQt_1(Vreg1) + dQt_2(Vreg1)); + if (1) { + print_header3("dQt g~ |t_i t_j>"); + const std::vector argument={"Ue","KffK","comm_F_Qt_f12","reduced_Fock"}; + auto Vreg1=apply_Vreg(world,t(i),t(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); + V-=consolidate(dQt_1(Vreg1) + dQt_2(Vreg1)); + apply_G_and_print(consolidate(dQt_1(Vreg1) + dQt_2(Vreg1)),"projector response"); + } + + // eq. (29) second term = eq. (31): [F12, dQt] f12 |t_i t_j> + omega dQ12t f12 |t_i t_j> - argument={"comm_F_dQt_f12"}; - V+=apply_Vreg(world,t(i),t(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); + if (1) { + print_header3("[F12, dQt] f12 |t_i t_j>"); + const std::vector argument={"comm_F_dQt_f12"}; + // V+=apply_Vreg(world,t(i),t(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); + auto tmp1=apply_Vreg(world,t(i),t(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); + apply_G_and_print(tmp1,"commutator projector response"); + } + } + throw; + V=consolidate(V); MADNESS_CHECK(V.size()==2); // term 1: 6d, hi-rank, local; term 2: 3d, low-rank, delocalized @@ -1409,12 +1488,14 @@ CCPotentials::make_constant_part_cc2_Qt_ex(const CCPair& u, const CC_vecfunction CCTimer time_cpr(world, "Commutator-Projector Response"); // Make functional response part: G(QtVreg|xitj + tixj>) real_function_6d functional_response; - { + if (0) { time_fr.start(); const real_function_6d Vxt = (apply_Vreg(xi, tj, Gscreen)).truncate().reduce_rank(); if (symmetric) { real_function_6d V = apply_Q12t(Vxt, t); + V.print_size("Q12tVreg"); const real_function_6d tmp = -2.0 * G(V); + tmp.print_size("G(Q12tVreg)"); functional_response = tmp + swap_particles(tmp); } else { const real_function_6d Vtx = apply_Vreg(ti, xj, Gscreen); @@ -1423,22 +1504,28 @@ CCPotentials::make_constant_part_cc2_Qt_ex(const CCPair& u, const CC_vecfunction functional_response = -2.0 * G(V); } time_fr.stop(); - } // make Projector Response: -G(OxQt+QtOx)Vreg|titj> + } + functional_response.print_size("G functional response"); + + // make Projector Response: -G(OxQt+QtOx)Vreg|titj> real_function_6d projector_response; - { + if (0) { time_pr.start(); // here is an inconsistency: The Vreg potential will apply (F12-eij) to the |titj> state but we have here (F12-eij-omega) // in the future this part here is supposed to be entirely 3D and not use the 6D apply_Vreg function, so right now this is a workaround // however, we have to add the missing -omega|titj> real_function_6d Vtt_tmp = apply_Vreg(ti, tj, Gscreen); real_function_6d titj = make_f_xy(ti, tj); - Vtt_tmp = Vtt_tmp - x.omega * titj; + print("skipping omega term 1"); + // Vtt_tmp = Vtt_tmp - x.omega * titj; CCPairFunction Vtt(Vtt_tmp); real_function_6d tmp1; real_function_6d tmp2; { CCPairFunction Ox = apply_Ot(Vtt, x, 1); CCPairFunction OxQt = apply_Qt(Ox, t, 2); + OxQt.convert_to_pure_no_op_inplace(); + OxQt.get_function().print_size("Q12t_FQtQtF_f12"); tmp1 = -2.0 * apply_G(OxQt, G); } if (symmetric) tmp2 = swap_particles(tmp1); @@ -1450,9 +1537,12 @@ CCPotentials::make_constant_part_cc2_Qt_ex(const CCPair& u, const CC_vecfunction projector_response = tmp1 + tmp2; time_pr.stop(); } + projector_response.print_size("G projector response"); + // make commutator response: [F12,Qt12]f12|xitj+tixj> = (O1VQ2t + Q1tO2V)f12|xitj+tixj> real_function_6d commutator_response; { + print_header3("[F12,Qt12]f12|xitj+tixj> = (Ov Qt + Qt Ov) f12 |xitj+tixj>"); time_cr.start(); real_function_6d part1; // the xt parts const vector_real_function_3d Vtmp = get_potentials(tau, POT_singles_); @@ -1482,6 +1572,8 @@ CCPotentials::make_constant_part_cc2_Qt_ex(const CCPair& u, const CC_vecfunction commutator_response = part1 + part2; time_cr.stop(); } + commutator_response.print_size("G commutator response"); + // make Commutator Projector response Response: [F,d/dtau(Qt)] part of d/dtau{([F,Qt])f12|xitj + tixj>} // {-O1x[F,Q2t] - Q1t[F,O2x] - [F,O1x]Q2t - [F,Q1t]O2x , used d/dtau(Qt) = -Ox // O1x[F,O2t] - Q1t[F,O2x] - [F,O1x]Q2t + [F,O1t]O2x , used [F,Qt] = -[F,Ot] @@ -1492,10 +1584,17 @@ CCPotentials::make_constant_part_cc2_Qt_ex(const CCPair& u, const CC_vecfunction // }f12|titj> real_function_6d commutator_projector_response; { + print_header3("[F12,dQt] f12 |t_i t_j> = (Ox OVt + Qt OVx) f12 |t_i t_j>"); time_cpr.start(); - const vector_real_function_3d Vxtmp = sub(world, get_potentials(x, POT_singles_), - x.omega * x.get_vecfunction()); + print("skipping omega term 2"); + // const vector_real_function_3d Vxtmp = sub(world, get_potentials(x, POT_singles_), + // x.omega * x.get_vecfunction()); + const vector_real_function_3d Vxtmp = get_potentials(x, POT_singles_); const vector_real_function_3d Vttmp = get_potentials(tau, POT_singles_); + + madness::print_size(world,Vxtmp,"Vxtmp"); + madness::print_size(world,Vttmp,"Vttmp"); + madness::print_size(world,get_active_mo_bra(),"active bra"); const CC_vecfunction Vx(Vxtmp, UNDEFINED, parameters.freeze()); const CC_vecfunction Vt(Vttmp, UNDEFINED, parameters.freeze()); CCPairFunction ftt(f12, ti, tj); @@ -1523,9 +1622,13 @@ CCPotentials::make_constant_part_cc2_Qt_ex(const CCPair& u, const CC_vecfunction commutator_projector_response = tmp1 + tmp2; time_cpr.stop(); } + commutator_projector_response.print_size("G commutator projector response"); + print_header3("add all up"); real_function_6d result = functional_response - projector_response + commutator_response + commutator_projector_response; + result.print_size("result"); result = apply_Q12t(result, mo_ket_); + result.print_size("Q12t result"); output.section("Constant Term for Pair " + u.name() + " ended"); time_fr.info(true, functional_response.norm2()); time_pr.info(true, projector_response.norm2()); @@ -1615,9 +1718,12 @@ std::vector> V_lowrank += apply_commutator_F_dQt_f12(world,ti,tj,gs_singles,ex_singles,info,&Gscreen); } V.truncate().reduce_rank(); - if (parameters.debug()) V.print_size("Vreg"); + if (parameters.debug()) { + V.print_size("Vreg -- pure component"); + print("V_lowrank.size()",V_lowrank.size()); + } - std::vector> result; + std::vector> result; result+=CCPairFunction(V); result+=V_lowrank; return result; @@ -2015,8 +2121,8 @@ CCPotentials::apply_commutator_F_Qt_f12(World& world, const CCFunction auto ftt=std::vector>({CCPairFunction(f12, phi_i.function, phi_j.function)}); const vector_real_function_3d Vtau=info.intermediate_potentials(gs_singles, POT_singles_); - Projector OVtau(info.mo_bra,Vtau); - QProjector Qt(world,info.mo_bra,gs_singles.get_vecfunction()); + Projector OVtau(info.get_active_mo_bra(),Vtau); + QProjector Qt(world,info.get_active_mo_bra(),gs_singles.get_vecfunction()); auto p1=outer(OVtau,Qt); auto p2=outer(Qt,OVtau); @@ -2040,16 +2146,20 @@ CCPotentials::apply_commutator_F_dQt_f12(World& world, const CCFunction(world,OT_F12,parameters); auto ftt=std::vector>({CCPairFunction(f12, phi_i.function, phi_j.function)}); const vector_real_function_3d Vtau=info.intermediate_potentials(gs_singles, POT_singles_); const vector_real_function_3d Vx=info.intermediate_potentials(ex_singles, POT_singles_); - Projector OVtau(info.mo_bra,Vtau); - Projector Ox(info.mo_bra,ex_singles.get_vecfunction()); - Projector OVx(info.mo_bra,Vx); - QProjector Qt(world,info.mo_bra,gs_singles.get_vecfunction()); + auto bra=info.get_active_mo_bra(); + madness::print_size(world,Vtau,"Vtau"); + madness::print_size(world,Vx,"x"); + madness::print_size(world,bra,"active bra"); + + Projector OVtau(bra,Vtau); + Projector Ox(bra,ex_singles.get_vecfunction()); + Projector OVx(bra,Vx); + QProjector Qt(world,bra,gs_singles.get_vecfunction()); auto p1_1=outer(OVx,Qt); auto p1_2=outer(Qt,OVx); @@ -2057,7 +2167,7 @@ CCPotentials::apply_commutator_F_dQt_f12(World& world, const CCFunction(info.mo_ket[i],i,MIXED)); + } else { + CCFunction t(info.mo_ket[i] + tau(i).function, i, MIXED); + result.insert(i, t); + } + } + return result; +} + + /// makes the t intermediates /// t_i = mo_ket_(i) + tau /// i = tau.i diff --git a/src/madness/chem/CCPotentials.h b/src/madness/chem/CCPotentials.h index f7249222f41..900af5b1086 100644 --- a/src/madness/chem/CCPotentials.h +++ b/src/madness/chem/CCPotentials.h @@ -149,6 +149,11 @@ class CCPotentials { /// if the core is frozen the core ti will just be mo_ket_ CC_vecfunction make_full_t_intermediate(const CC_vecfunction& tau) const; + /// makes the t intermediates + /// t_i = mo_ket_(i) + factor*tau(i) + /// if the core is frozen the core ti will just be mo_ket_ + static CC_vecfunction make_full_t_intermediate(const CC_vecfunction& tau, const Info& info); + /// makes the t intermediates /// t_i = mo_ket_(i) + tau /// i = tau.i diff --git a/src/madness/chem/CCStructures.h b/src/madness/chem/CCStructures.h index ba14deec3b4..db6ace38d64 100644 --- a/src/madness/chem/CCStructures.h +++ b/src/madness/chem/CCStructures.h @@ -1175,6 +1175,18 @@ struct Info { Function R_square, U2; std::vector> U1; + vector_real_function_3d get_active_mo_ket() const { + vector_real_function_3d result; + for (size_t i = parameters.freeze(); i < mo_ket.size(); i++) result.push_back(mo_ket[i]); + return result; + } + + vector_real_function_3d get_active_mo_bra() const { + vector_real_function_3d result; + for (size_t i = parameters.freeze(); i < mo_bra.size(); i++) result.push_back(mo_bra[i]); + return result; + } + /// customized function to store this to the cloud /// functions and constant_part can be very large and we want to split them and store them in different records diff --git a/src/madness/chem/ccpairfunction.cc b/src/madness/chem/ccpairfunction.cc index 3eef80ff54f..c9468f56090 100644 --- a/src/madness/chem/ccpairfunction.cc +++ b/src/madness/chem/ccpairfunction.cc @@ -38,11 +38,17 @@ void CCPairFunction::convert_to_pure_no_op_inplace() { result= CompositeFactory(world()) .g12(get_operator().get_kernel()) .ket(get_function()); - } else if (is_decomposed()) { + } else if (is_decomposed_no_op()) { + result= CompositeFactory(world()) + .particle1(get_a()) + .particle2(get_b()); + } else if (is_op_decomposed()) { result= CompositeFactory(world()) .g12(get_operator().get_kernel()) .particle1(get_a()) .particle2(get_b()); + } else { + MADNESS_EXCEPTION("error in convert_to_pure_no_op_inplace",1); } result.fill_tree(); result.truncate(FunctionDefaults::get_thresh()*0.1); diff --git a/src/madness/chem/ccpairfunction.h b/src/madness/chem/ccpairfunction.h index 6d26a688b23..1146c985503 100644 --- a/src/madness/chem/ccpairfunction.h +++ b/src/madness/chem/ccpairfunction.h @@ -884,6 +884,13 @@ std::vector> apply(const SeparatedConvolution& return result; } +template +CCPairFunction apply(const SeparatedConvolution& G, const std::vector>& argument) { + CCPairFunction result; + for (const auto& a : argument) result+=G(a); + return result; +} + /// apply the operator on a CCPairfunction, both with the same dimension /// note there is another function, where the operator works only on some dimensions of the CCPairFunction! @@ -895,14 +902,8 @@ CCPairFunction apply(const SeparatedConvolution& G, const CCPair if (argument.is_pure()) { result=CCPairFunction(G(argument.get_function())); } else if (argument.is_decomposed_no_op()) { - Function result1=real_factory_6d(argument.world()).compressed(); - MADNESS_ASSERT(argument.get_a().size() == argument.get_b().size()); - - for (size_t k = 0; k < argument.get_a().size(); k++) { - const Function tmp = G(argument.get_a()[k], argument.get_b()[k]); - result1 += tmp; - } + Function result1=G(argument.get_a(), argument.get_b()); result=CCPairFunction(result1); } else { MADNESS_EXCEPTION("unknown type in CCPairFunction::apply",1); diff --git a/src/madness/chem/projector.h b/src/madness/chem/projector.h index 7f082fc8511..4d6e26b34d8 100644 --- a/src/madness/chem/projector.h +++ b/src/madness/chem/projector.h @@ -66,7 +66,9 @@ namespace madness { /// bra and ket spaces are not symmetric (e.g. |ket>^+ = print_size(name); + if (!impl) { + print("function",name,"not assigned yet"); + } else { + impl->print_size(name); + } } /// Returns the maximum depth of the function tree ... collective global sum @@ -2101,8 +2104,10 @@ namespace madness { result.get_impl()->recursive_apply(op, f1[i].get_impl().get(),f2[i].get_impl().get(),false); world.gop.fence(); - result.get_impl()->print_timer(); - op.print_timer(); + if (op.print_timings) { + result.get_impl()->print_timer(); + op.print_timer(); + } result.get_impl()->finalize_apply(); // need fence before reconstruct From 538817a7f99d31b028648b0b5dbc3c0806e2808b Mon Sep 17 00:00:00 2001 From: fbischoff Date: Thu, 6 Jun 2024 10:48:33 -0400 Subject: [PATCH 07/54] update on debugging --- src/madness/chem/CC2.cc | 8 +- src/madness/chem/CCPotentials.cc | 124 +++++++++++------------- src/madness/chem/CCPotentials.h | 8 +- src/madness/chem/ccpairfunction.cc | 32 +++++- src/madness/chem/ccpairfunction.h | 29 ++++-- src/madness/chem/lowrankfunction.h | 5 +- src/madness/chem/projector.h | 42 ++++---- src/madness/chem/test_ccpairfunction.cc | 36 ++++--- src/madness/chem/test_projector.cc | 16 ++- 9 files changed, 177 insertions(+), 123 deletions(-) diff --git a/src/madness/chem/CC2.cc b/src/madness/chem/CC2.cc index e42dabc78f4..c7c3e9ba06c 100644 --- a/src/madness/chem/CC2.cc +++ b/src/madness/chem/CC2.cc @@ -741,14 +741,14 @@ CC2::iterate_lrcc2_pairs(const CC_vecfunction& cc2_s, const Pairs& cc2_d // output("Skipping Pair Iteration, No significant Change in Singles"); // else { pair.bsh_eps = CCOPS.get_epsilon(pair.i, pair.j) + lrcc2_s.omega; - update_constant_part_lrcc2(pair, cc2_s, lrcc2_s); - // pair.constant_part=CCPotentials::make_constant_part_macrotask(world, pair, - // cc2_s, lrcc2_s, info); + // update_constant_part_lrcc2(pair, cc2_s, lrcc2_s); + pair.constant_part=CCPotentials::make_constant_part_macrotask(world, pair, + cc2_s, lrcc2_s, info); conv = iterate_pair(pair, lrcc2_s); // } } - return conv; + } diff --git a/src/madness/chem/CCPotentials.cc b/src/madness/chem/CCPotentials.cc index cc4da0fbc52..ffc4c4d357c 100644 --- a/src/madness/chem/CCPotentials.cc +++ b/src/madness/chem/CCPotentials.cc @@ -719,6 +719,7 @@ CCPotentials::make_constant_part_macrotask(World& world, const CCPair& pair, auto dQt_1 = outer(Qt,Ox); auto dQt_2 = outer(Ox,Qt); + std::size_t i=pair.i; std::size_t j=pair.j; auto phi = [&](size_t i) { return CCFunction(info.mo_ket[i],i,HOLE); }; @@ -750,6 +751,10 @@ CCPotentials::make_constant_part_macrotask(World& world, const CCPair& pair, auto apply_G_and_print = [&](const std::vector>& cc, std::string name) { std::vector> tmp1; print("cc in apply_G_and_print:",name,cc.size()); + for (const auto& tt : cc) { + print(tt.name()); + tt.print_size(); + } for (const auto& tt : cc) tmp1 += GG(copy(tt)); print("tmp1 after apply G"); for (const auto& tt : tmp1) { @@ -772,87 +777,58 @@ CCPotentials::make_constant_part_macrotask(World& world, const CCPair& pair, std::vector argument={"Ue","KffK","comm_F_Qt_f12","reduced_Fock"}; auto Vreg=apply_Vreg(world,t(i),t(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); V=consolidate(Q12t(Vreg)); - } else if (targetstate==CT_LRCC2) { // Eq. (25) of Kottmann, JCTC 13, 5956 (2017) + } else if (targetstate==CT_LRCC2) + { + // Eq. (25) of Kottmann, JCTC 13, 5956 (2017) // eq. (25) Q12t (g~ - omega f12) (|x_i t_j> + |t_i x_j> ) // note the term omega f12 is included in the reduced_Fock term, see eq. (34) if (0) { + print_header3("Q12t g~ |x_i t_j + t_i x_j>"); std::vector argument={"Ue","KffK","comm_F_Qt_f12","reduced_Fock"}; auto Vreg=apply_Vreg(world,x(i),t(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); - //debug Vreg+=apply_Vreg(world,t(i),x(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); + Vreg+=apply_Vreg(world,t(i),x(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); V=consolidate(apply_in_separated_form(Q12t,Vreg)); apply_G_and_print(V,"functional response"); } if (0) { - std::vector argument={"Ue","KffK","reduced_Fock"}; - auto Vreg=apply_Vreg(world,x(i),t(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); - Vreg+=apply_Vreg(world,t(i),x(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); - - V=consolidate(apply_in_separated_form(Q12t,Vreg)); - apply_G_and_print(V,"functional response in old terminology, V -- separated"); -// print("debug 1", V.size()); -// for (auto& vv : V) { -// print(vv.name()); -// vv.print_size(); -// } -// for (auto& vv : V) vv.convert_to_pure_no_op_inplace(); -// print("debug 2", V.size()); -// for (auto& vv : V) { -// print(vv.name()); -// vv.print_size(); -// } -// V=consolidate(V); -// print("debug 3", V.size()); -// for (auto& vv : V) { -// print(vv.name()); -// vv.print_size(); -// } -// print("V separate-consolidate",V.size()); -// V[0].get_function().print_size("Q12t_FQtQtF_f12.size() separate-consolidate"); -// apply_G_and_print(V,"functional response in old terminology, V -- consolidated"); -// -// auto Q12V=Q12t(Vreg); -// print("Q12t_Ue_KffK_redF.size()",Q12V.size()); -// Q12V[0].get_function().print_size("Q12t_FQtQtF_f12"); -// apply_G_and_print(Q12V,"functional response in old terminology, Q12V- single term"); - } - if (1) { print_header3("[F12,Qt] f12 |x_i t_j + t_i x_j>"); std::vector argument={"comm_F_Qt_f12"}; auto Vreg=apply_Vreg(world,x(i),t(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); Vreg+=apply_Vreg(world,t(i),x(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); auto Q12V=Q12t(Vreg); - print("Q12t_FQtQtF_f12.size()",Q12V.size()); - apply_G_and_print(Q12V,"commutator response in old terminology: Q12V direct"); - - V=consolidate(apply_in_separated_form(Q12t,Vreg)); - apply_G_and_print(V,"commutator response in old terminology: Q12V separated"); - + // apply_G_and_print(Q12V,"commutator response in old terminology: Q12V direct"); } // eq. (29) first term: dQt g~ |t_i t_j> if (1) { - print_header3("dQt g~ |t_i t_j>"); - const std::vector argument={"Ue","KffK","comm_F_Qt_f12","reduced_Fock"}; + print_header3("dQt g~ |t_i t_j> -- incomplete !!"); + // const std::vector argument={"Ue","KffK","comm_F_Qt_f12","reduced_Fock"}; + const std::vector argument={"Ue","KffK","reduced_Fock"}; auto Vreg1=apply_Vreg(world,t(i),t(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); - V-=consolidate(dQt_1(Vreg1) + dQt_2(Vreg1)); - apply_G_and_print(consolidate(dQt_1(Vreg1) + dQt_2(Vreg1)),"projector response"); - } + auto tmp=consolidate(dQt_1(Vreg1) + dQt_2(Vreg1)); + V-=tmp; + + MADNESS_CHECK_THROW(tmp.size()==1,"tmp size is incorrect"); + tmp[0].print_size("dQt g~ |t_i t_j>"); + apply_G_and_print(tmp,"projector response"); + } // eq. (29) second term = eq. (31): [F12, dQt] f12 |t_i t_j> + omega dQ12t f12 |t_i t_j> if (1) { print_header3("[F12, dQt] f12 |t_i t_j>"); const std::vector argument={"comm_F_dQt_f12"}; - // V+=apply_Vreg(world,t(i),t(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); - auto tmp1=apply_Vreg(world,t(i),t(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); - apply_G_and_print(tmp1,"commutator projector response"); + auto tmp=apply_Vreg(world,t(i),t(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); + tmp=consolidate(tmp); + MADNESS_CHECK_THROW(tmp.size()==1,"tmp size incorrect"); + tmp[0].print_size(); + V+=tmp; + apply_G_and_print(tmp,"commutator projector response"); } - } - throw; V=consolidate(V); MADNESS_CHECK(V.size()==2); // term 1: 6d, hi-rank, local; term 2: 3d, low-rank, delocalized @@ -862,8 +838,8 @@ CCPotentials::make_constant_part_macrotask(World& world, const CCPair& pair, G.destructive() = true; real_function_6d GV=real_factory_6d(world).empty(); - for (const auto& vv : V) GV+= (-2.0 * G(vv)).get_function(); // note V is destroyed here - GV=Q12(GV).truncate().reduce_rank(); + for (const auto& vv : V) GV+= (G(vv)).get_function(); // note V is destroyed here + GV=-2.0*Q12(GV).truncate().reduce_rank(); GV.print_size("GVreg"); return GV; @@ -1488,7 +1464,7 @@ CCPotentials::make_constant_part_cc2_Qt_ex(const CCPair& u, const CC_vecfunction CCTimer time_cpr(world, "Commutator-Projector Response"); // Make functional response part: G(QtVreg|xitj + tixj>) real_function_6d functional_response; - if (0) { + if (1) { time_fr.start(); const real_function_6d Vxt = (apply_Vreg(xi, tj, Gscreen)).truncate().reduce_rank(); if (symmetric) { @@ -1509,7 +1485,7 @@ CCPotentials::make_constant_part_cc2_Qt_ex(const CCPair& u, const CC_vecfunction // make Projector Response: -G(OxQt+QtOx)Vreg|titj> real_function_6d projector_response; - if (0) { + if (1) { time_pr.start(); // here is an inconsistency: The Vreg potential will apply (F12-eij) to the |titj> state but we have here (F12-eij-omega) // in the future this part here is supposed to be entirely 3D and not use the 6D apply_Vreg function, so right now this is a workaround @@ -1592,9 +1568,6 @@ CCPotentials::make_constant_part_cc2_Qt_ex(const CCPair& u, const CC_vecfunction const vector_real_function_3d Vxtmp = get_potentials(x, POT_singles_); const vector_real_function_3d Vttmp = get_potentials(tau, POT_singles_); - madness::print_size(world,Vxtmp,"Vxtmp"); - madness::print_size(world,Vttmp,"Vttmp"); - madness::print_size(world,get_active_mo_bra(),"active bra"); const CC_vecfunction Vx(Vxtmp, UNDEFINED, parameters.freeze()); const CC_vecfunction Vt(Vttmp, UNDEFINED, parameters.freeze()); CCPairFunction ftt(f12, ti, tj); @@ -2149,24 +2122,22 @@ CCPotentials::apply_commutator_F_dQt_f12(World& world, const CCFunction(world,OT_F12,parameters); auto ftt=std::vector>({CCPairFunction(f12, phi_i.function, phi_j.function)}); + auto t=CCPotentials::make_active_t_intermediate(gs_singles,info); const vector_real_function_3d Vtau=info.intermediate_potentials(gs_singles, POT_singles_); const vector_real_function_3d Vx=info.intermediate_potentials(ex_singles, POT_singles_); auto bra=info.get_active_mo_bra(); - madness::print_size(world,Vtau,"Vtau"); - madness::print_size(world,Vx,"x"); - madness::print_size(world,bra,"active bra"); Projector OVtau(bra,Vtau); Projector Ox(bra,ex_singles.get_vecfunction()); Projector OVx(bra,Vx); - QProjector Qt(world,bra,gs_singles.get_vecfunction()); + QProjector Qt(world,bra,t.get_vecfunction()); - auto p1_1=outer(OVx,Qt); - auto p1_2=outer(Qt,OVx); - auto p2_1=outer(Ox,OVtau); - auto p2_2=outer(OVtau,Ox); + auto OvxQt=outer(OVx,Qt); + auto QtOvx=outer(Qt,OVx); + auto OxOvt=outer(Ox,OVtau); + auto OvtOx=outer(OVtau,Ox); - auto result=p1_1(ftt) + p1_2(ftt) - p2_1(ftt) - p2_2(ftt); + auto result=OvxQt(ftt) + QtOvx(ftt) - OxOvt(ftt) - OvtOx(ftt); result=consolidate(result); // will collect similar terms only MADNESS_CHECK_THROW(result.size()==1 and result[0].is_decomposed(),"apply_Fock_commutator should return a single CCPairFunction"); return result[0]; @@ -3647,7 +3618,8 @@ CC_vecfunction CCPotentials::make_full_t_intermediate(const CC_vecfunction& tau) } /// makes the t intermediates -/// t_i = mo_ket_(i) + factor*tau(i) + +/// t_i = mo_ket_(i) + tau(i) /// if the core is frozen the core ti will just be mo_ket_ CC_vecfunction CCPotentials::make_full_t_intermediate(const CC_vecfunction& tau, const Info& info) { @@ -3665,6 +3637,22 @@ CC_vecfunction CCPotentials::make_full_t_intermediate(const CC_vecfunction& tau, return result; } +/// makes the t intermediates + +/// t_i = mo_ket_(i) + tau(i) +/// skip frozen core orbitals +CC_vecfunction CCPotentials::make_active_t_intermediate(const CC_vecfunction& tau, const Info& info) { + + if (tau.type == HOLE or tau.size()==0) return CC_vecfunction(info.mo_ket,HOLE); + + CC_vecfunction result(MIXED); + for (size_t i = info.parameters.freeze(); i < info.mo_ket.size(); i++) { + CCFunction t(info.mo_ket[i] + tau(i).function, i, MIXED); + result.insert(i, t); + } + return result; +} + /// makes the t intermediates /// t_i = mo_ket_(i) + tau diff --git a/src/madness/chem/CCPotentials.h b/src/madness/chem/CCPotentials.h index 900af5b1086..c847d253811 100644 --- a/src/madness/chem/CCPotentials.h +++ b/src/madness/chem/CCPotentials.h @@ -150,10 +150,16 @@ class CCPotentials { CC_vecfunction make_full_t_intermediate(const CC_vecfunction& tau) const; /// makes the t intermediates - /// t_i = mo_ket_(i) + factor*tau(i) + /// t_i = mo_ket_(i) + tau(i) /// if the core is frozen the core ti will just be mo_ket_ static CC_vecfunction make_full_t_intermediate(const CC_vecfunction& tau, const Info& info); + /// makes the t intermediates + + /// t_i = mo_ket_(i) + tau(i) + /// skip frozen orbitals + static CC_vecfunction make_active_t_intermediate(const CC_vecfunction& tau, const Info& info); + /// makes the t intermediates /// t_i = mo_ket_(i) + tau /// i = tau.i diff --git a/src/madness/chem/ccpairfunction.cc b/src/madness/chem/ccpairfunction.cc index c9468f56090..a8f36b2792a 100644 --- a/src/madness/chem/ccpairfunction.cc +++ b/src/madness/chem/ccpairfunction.cc @@ -105,10 +105,26 @@ std::vector> CCPairFunction::op_dec_to_dec(const return result; } +/// turn decomposed functions with operator into pure functions +template +std::vector> CCPairFunction::dec_to_pure(const std::vector>& other) { + std::vector> result; + for (const auto& c : other) { + if (c.is_decomposed_no_op()) { + CCPairFunction tmp=copy(c); + tmp.convert_to_pure_no_op_inplace(); + result.push_back(tmp); + } else { + result.push_back(c); + } + } + return result; +} + + /// turn decomposed functions with operator into pure functions template std::vector> CCPairFunction::op_dec_to_pure(const std::vector>& other) { - LowRankFunctionParameters lrparameters; std::vector> result; for (const auto& c : other) { if (c.is_op_decomposed()) { @@ -226,6 +242,8 @@ std::vector> CCPairFunction::consolidate(const st bool op_dec_to_dec=find(options.begin(),options.end(),"op_dec_to_dec")!=options.end(); // convert op_dec functions to pure (via fill_tree) bool op_dec_to_pure=find(options.begin(),options.end(),"op_dec_to_pure")!=options.end(); + // convert dec functions to pure (via hartree product) + bool dec_to_pure=find(options.begin(),options.end(),"dec_to_pure")!=options.end(); // reorthogonalize decomposed functions and op_decomposed functions bool lindep=find(options.begin(),options.end(),"remove_lindep")!=options.end(); @@ -235,6 +253,7 @@ std::vector> CCPairFunction::consolidate(const st if (op_dec_to_dec) result=CCPairFunction::op_dec_to_dec(result,centers); if (op_dec_to_pure) result=CCPairFunction::op_dec_to_pure(result); + if (dec_to_pure) result=CCPairFunction::dec_to_pure(result); if (op_pure_to_pure) result=CCPairFunction::op_pure_to_pure(result); if (not is_collected(result)) result=collect_same_types(result); @@ -608,11 +627,9 @@ std::vector> CCPairFunction::apply(const Projecto constexpr std::size_t LDIM=CCPairFunction::LDIM; // print("apply projector on argument with terms",argument.size()); if (auto P=dynamic_cast*>(&projector)) { -// print("P->get_particle()",P->get_particle()); MADNESS_CHECK_THROW(P->get_particle()==0 or P->get_particle()==1,"P Projector particle must be 0 or 1 in CCPairFunction"); } if (auto Q=dynamic_cast*>(&projector)) { -// print("Q->get_particle()",Q->get_particle()); MADNESS_CHECK_THROW(Q->get_particle()==0 or Q->get_particle()==1,"Q Projector particle must be 0 or 1 in CCPairFunction"); } std::vector> result; @@ -624,10 +641,15 @@ std::vector> CCPairFunction::apply(const Projecto auto tmp2=CCPairFunction(tmp); result.push_back(tmp2); } else if (auto P=dynamic_cast*>(&projector)) { - result.push_back(CCPairFunction((*P)(pf.get_function()))); + // result.push_back(CCPairFunction((*P)(pf.get_function()))); + auto [left,right]=P->get_vectors_for_outer_product(pf.get_function()); + result.push_back(CCPairFunction(left,right)); + } else if (auto Q=dynamic_cast*>(&projector)) { - result.push_back(CCPairFunction((*Q)(pf.get_function()))); + // result.push_back(CCPairFunction((*Q)(pf.get_function()))); + result.push_back(pf); + result.push_back(-1.0*Q->get_P_projector()(pf)); } else { MADNESS_EXCEPTION("CCPairFunction: unknown projector type",1); diff --git a/src/madness/chem/ccpairfunction.h b/src/madness/chem/ccpairfunction.h index 1146c985503..43baa9dc241 100644 --- a/src/madness/chem/ccpairfunction.h +++ b/src/madness/chem/ccpairfunction.h @@ -116,7 +116,7 @@ class TwoBodyFunctionComponentBase { virtual bool has_operator() const = 0; // virtual void set_operator(const std::shared_ptr op) = 0; // virtual const std::shared_ptr get_operator_ptr() const = 0; - virtual void print_size() const = 0; + virtual void print_size(const std::string name="") const = 0; virtual std::string name(const bool transpose=false) const = 0; virtual World& world() const =0; virtual std::shared_ptr clone() = 0; @@ -155,8 +155,8 @@ class TwoBodyFunctionPureComponent : public TwoBodyFunctionComponentBase { World& world() const override {return u.world();}; - void print_size() const override { - u.print_size(name(false)); + void print_size(const std::string name1="") const override { + u.print_size(name1+name(false)); } std::string name(const bool transpose) const override { @@ -240,7 +240,7 @@ class TwoBodyFunctionSeparatedComponent : public TwoBodyFunctionComponentBase { return a.front().world(); }; - void print_size() const override { + void print_size(const std::string name1="") const override { if (a.size() > 0) { World& world = a.front().world(); madness::print_size(world, a, "a from " + name(false)); @@ -441,6 +441,9 @@ using pureT=Function; /// turn decomposed functions with operator into pure functions without operators static std::vector op_dec_to_pure(const std::vector& other); + /// turn decomposed functions without operator into pure functions without operators + static std::vector dec_to_pure(const std::vector& other); + /// remove linear dependent terms in the low-rank parts static std::vector remove_linearly_dependent_terms(const std::vector& other, double thresh=-1.0); @@ -617,8 +620,22 @@ using pureT=Function; } /// print the size of the functions - void print_size() const { - if (component) component->print_size(); + void print_size(const std::string name1="") const { + if (not component) { + print("CCPairFunction "+name1+ " not assigned"); + } else if (component->is_pure()) { + component->print_size(name1); + } else { + double wall=wall_time(); + double norm=this->norm2(); + std::size_t fsize=get_a().size(); + std::size_t bufsize=128; + char buf[bufsize]; + snprintf(buf, bufsize, "%40s at time %.1fs: norm/ #functions: %7.5f %zu \n", + ((name1+" "+name()).c_str()), wall, norm, fsize); + if (world().rank()==0) print(std::string(buf)); + } + }; std::string name(const bool transpose=false) const { diff --git a/src/madness/chem/lowrankfunction.h b/src/madness/chem/lowrankfunction.h index 3fbfffe2005..9b8845dda45 100644 --- a/src/madness/chem/lowrankfunction.h +++ b/src/madness/chem/lowrankfunction.h @@ -271,8 +271,9 @@ namespace madness { public: /// ctor takes centers of the grid and the grid parameters molecular_grid(const std::vector> origins, const LowRankFunctionParameters& params) - : centers(origins) { - if (centers.size()==0) centers.push_back({0,0,0}); + : centers(origins) + { + if (centers.size()==0) centers.push_back(Vector(0) ); if (params.gridtype()=="random") grid_builder=std::make_shared>(params.volume_element(),params.radius()); // else if (params.gridtype()=="cartesian") grid_builder=std::make_shared>(params.volume_element(),params.radius()); else if (params.gridtype()=="dftgrid") { diff --git a/src/madness/chem/projector.h b/src/madness/chem/projector.h index 4d6e26b34d8..b9fc655f96d 100644 --- a/src/madness/chem/projector.h +++ b/src/madness/chem/projector.h @@ -115,31 +115,37 @@ namespace madness { /// |result> = \sum_p |p(particle)> _{particle} /// \f] /// @param[in] f the 6D function to be projected - /// @param[in] the particle that is projected (1 or 2) + /// @param[in] the particle that is projected (0 or 1) /// @return the projected function template typename std::enable_if >::type operator()(const Function& f, int particle1=-1) const { - Function result = FunctionFactory(f.world()); if (particle1==-1) particle1=get_particle(); - MADNESS_CHECK_THROW(particle1 == 0 or particle1 == 1, "particle must be 1 or 2"); - for (size_t i = 0; i < mo_ket_.size(); i++) { - Function tmp1 = mo_ket_[i]; - Function tmp2 = f.project_out(mo_bra_[i], particle1); - Function tmp12; - if (particle1 == 0) { - tmp12 = CompositeFactory(f.world()).particle1(copy(tmp1)).particle2(copy(tmp2)); - tmp12.fill_tree(); - } else if (particle1==1) { - tmp12 = CompositeFactory(f.world()).particle1(copy(tmp2)).particle2(copy(tmp1)); - tmp12.fill_tree(); - } else { - MADNESS_EXCEPTION("messed up",1); - } + MADNESS_CHECK_THROW(particle1 == 0 or particle1 == 1, "particle must be 0 or 1"); + auto [left,right]=get_vectors_for_outer_product(f); + return hartree_product(left,right); + } - result += tmp12; + /// apply the projection parts of the operator on a function f + + /// The operator applied on f(1,2) is + /// O(1)f(1,2) = \sum_i |i(1) > _1 = \sum_i |i(1) f_i(2)> + /// return the lo-dim vectors i and f_i only, perform no outer product + std::pair>,std::vector>> + get_vectors_for_outer_product(const Function& f) const { + World& world=f.world(); + reconstruct(world, mo_bra_, false); + f.reconstruct(false); + reconstruct(world, mo_ket_, true); + std::vector> projected; + for (const auto& i : mo_bra_) { + projected.push_back(f.project_out(i,particle)); + } + if (particle==0) return std::make_pair(mo_ket_,projected); + else if (particle==1) return std::make_pair(projected,mo_ket_); + else { + MADNESS_EXCEPTION("confused particles in Projector::get_vector_for_outer_products",1); } - return result; } template diff --git a/src/madness/chem/test_ccpairfunction.cc b/src/madness/chem/test_ccpairfunction.cc index 72536e7eaca..47dc8c26469 100644 --- a/src/madness/chem/test_ccpairfunction.cc +++ b/src/madness/chem/test_ccpairfunction.cc @@ -1151,7 +1151,10 @@ int test_projector(World& world, std::shared_ptr ncf, O.set_particle(0); { double ref=inner({CCPairFunction({of1},{f2})},vp[i]); - double result=inner({CCPairFunction({f1},{f2})},O(vp[i])); + auto tmp=O(vp[i]); + t1.checkpoint(tmp.size()==1,"vector size correct"); + t1.checkpoint(tmp[0].is_decomposed(),"O(argument) is decomposed"); + double result=inner({CCPairFunction({f1},{f2})},tmp); t1.checkpoint(result,ref,thresh,"O1 p"+std::to_string(i)); } @@ -1159,7 +1162,10 @@ int test_projector(World& world, std::shared_ptr ncf, O.set_particle(1); { double ref=inner({CCPairFunction({f1},{of2})},vp[i]); - double result=inner({CCPairFunction({f1},{f2})},O(vp[i])); + auto tmp=O(vp[i]); + t1.checkpoint(tmp.size()==1,"vector size correct"); + t1.checkpoint(tmp[0].is_decomposed(),"O(argument) is decomposed"); + double result=inner({CCPairFunction({f1},{f2})},tmp); t1.checkpoint(result,ref,thresh,"O2 p"+std::to_string(i)); } // Q1 @@ -1315,20 +1321,20 @@ int main(int argc, char **argv) { auto data4=data(world,ccparam); auto data6=data(world,ccparam); -// isuccess+=test_constructor(world, ncf, data2, ccparam); -// isuccess+=test_load_store(world,ncf,data2,ccparam); -// isuccess+=test_operator_apply(world, ncf, data2, ccparam); -// isuccess+=test_transformations(world, ncf, data2, ccparam); -// isuccess+=test_multiply_with_f12(world, ncf, data2, ccparam); -// isuccess+=test_inner(world, ncf, data2, ccparam); -// isuccess+=test_multiply(world, ncf, data2, ccparam); -// isuccess+=test_swap_particles(world, ncf, data2, ccparam); -// isuccess+=test_scalar_multiplication(world, ncf, data2, ccparam); + isuccess+=test_constructor(world, ncf, data2, ccparam); + isuccess+=test_load_store(world,ncf,data2,ccparam); + isuccess+=test_operator_apply(world, ncf, data2, ccparam); + isuccess+=test_transformations(world, ncf, data2, ccparam); + isuccess+=test_multiply_with_f12(world, ncf, data2, ccparam); + isuccess+=test_inner(world, ncf, data2, ccparam); + isuccess+=test_multiply(world, ncf, data2, ccparam); + isuccess+=test_swap_particles(world, ncf, data2, ccparam); + isuccess+=test_scalar_multiplication(world, ncf, data2, ccparam); isuccess+=test_projector(world, ncf, data2, ccparam); - // isuccess+=test_partial_inner_3d(world, ncf, data2, ccparam); - // isuccess+=test_partial_inner_6d(world, ncf, data2, ccparam); - // isuccess+=test_apply(world, ncf, data2, ccparam); - // isuccess+=test_consolidate(world, ncf, data2, ccparam); + isuccess+=test_partial_inner_3d(world, ncf, data2, ccparam); + isuccess+=test_partial_inner_6d(world, ncf, data2, ccparam); + isuccess+=test_apply(world, ncf, data2, ccparam); + isuccess+=test_consolidate(world, ncf, data2, ccparam); // isuccess+=test_constructor(world, ncf, data4, ccparam); diff --git a/src/madness/chem/test_projector.cc b/src/madness/chem/test_projector.cc index e58f435daf4..5aff5b528a4 100644 --- a/src/madness/chem/test_projector.cc +++ b/src/madness/chem/test_projector.cc @@ -95,10 +95,18 @@ int test_projector_outer(World& world) { auto Q1f=Q1(f_hidim); auto Q2f=Q2(f_hidim); double err=(Q1f-Q2f).norm2(); - double norm=Q1f.norm2(); - print("norm",norm); - - t1.checkpoint(err/norm,FunctionDefaults::get_thresh(),"Q1 direct and Q2 outer are the same"); + print("error",err); + double norm1=Q1f.norm2(); + double norm2=Q2f.norm2(); + print("norm1/2",norm1,norm2); + double trace1=Q1f.trace(); + double trace2=Q2f.trace(); + print("trace1/2",trace1,trace2); + + t1.checkpoint(norm1-norm2,FunctionDefaults::get_thresh(),"Q1 direct and Q2 outer are the same"); + t1.checkpoint(trace1-trace2,FunctionDefaults::get_thresh(),"Q1 direct and Q2 outer are the same"); + // loosen threshold due to outer product + t1.checkpoint(err,FunctionDefaults::get_thresh()*3.0,"Q1 direct and Q2 outer are the same"); return t1.end(); } From 83b59ac40e522dfdb6f524839217ffb8aca4e146 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Fri, 7 Jun 2024 16:57:07 -0400 Subject: [PATCH 08/54] constant term for LRCC2 seems correct for Beh2 and frozen core --- src/madness/chem/CCPotentials.cc | 21 ++++++++++---------- src/madness/chem/ccpairfunction.h | 14 +++++++++++-- src/madness/chem/projector.h | 9 ++++++++- src/madness/chem/test_ccpairfunction.cc | 26 +++++++++++++++++++++++++ 4 files changed, 56 insertions(+), 14 deletions(-) diff --git a/src/madness/chem/CCPotentials.cc b/src/madness/chem/CCPotentials.cc index ffc4c4d357c..e8a3a3d8f7b 100644 --- a/src/madness/chem/CCPotentials.cc +++ b/src/madness/chem/CCPotentials.cc @@ -715,11 +715,12 @@ CCPotentials::make_constant_part_macrotask(World& world, const CCPair& pair, // dQ12t = -(Qt(1) Ox(2) + Ox(1) Qt(2)) eq. (22) QProjector Qt(world,info.mo_bra,t.get_vecfunction()); - Projector Ox(info.mo_bra,ex_singles.get_vecfunction()); + Projector Ox(info.get_active_mo_bra(),ex_singles.get_vecfunction()); auto dQt_1 = outer(Qt,Ox); auto dQt_2 = outer(Ox,Qt); + std::size_t i=pair.i; std::size_t j=pair.j; auto phi = [&](size_t i) { return CCFunction(info.mo_ket[i],i,HOLE); }; @@ -782,7 +783,7 @@ CCPotentials::make_constant_part_macrotask(World& world, const CCPair& pair, // Eq. (25) of Kottmann, JCTC 13, 5956 (2017) // eq. (25) Q12t (g~ - omega f12) (|x_i t_j> + |t_i x_j> ) // note the term omega f12 is included in the reduced_Fock term, see eq. (34) - if (0) + if (1) { print_header3("Q12t g~ |x_i t_j + t_i x_j>"); std::vector argument={"Ue","KffK","comm_F_Qt_f12","reduced_Fock"}; @@ -798,21 +799,21 @@ CCPotentials::make_constant_part_macrotask(World& world, const CCPair& pair, auto Vreg=apply_Vreg(world,x(i),t(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); Vreg+=apply_Vreg(world,t(i),x(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); auto Q12V=Q12t(Vreg); - // apply_G_and_print(Q12V,"commutator response in old terminology: Q12V direct"); + apply_G_and_print(Q12V,"commutator response in old terminology: Q12V direct"); } // eq. (29) first term: dQt g~ |t_i t_j> if (1) { - print_header3("dQt g~ |t_i t_j> -- incomplete !!"); - // const std::vector argument={"Ue","KffK","comm_F_Qt_f12","reduced_Fock"}; - const std::vector argument={"Ue","KffK","reduced_Fock"}; + print_header3("dQt g~ |t_i t_j> "); + const std::vector argument={"Ue","KffK","comm_F_Qt_f12","reduced_Fock"}; + // const std::vector argument={"Ue","KffK","reduced_Fock"}; auto Vreg1=apply_Vreg(world,t(i),t(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); auto tmp=consolidate(dQt_1(Vreg1) + dQt_2(Vreg1)); V-=tmp; - MADNESS_CHECK_THROW(tmp.size()==1,"tmp size is incorrect"); - tmp[0].print_size("dQt g~ |t_i t_j>"); + // MADNESS_CHECK_THROW(tmp.size()==1,"tmp size is incorrect"); + // for (auto& t : tmp) t.print_size("dQt g~ |t_i t_j>"); apply_G_and_print(tmp,"projector response"); } @@ -823,8 +824,6 @@ CCPotentials::make_constant_part_macrotask(World& world, const CCPair& pair, const std::vector argument={"comm_F_dQt_f12"}; auto tmp=apply_Vreg(world,t(i),t(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); tmp=consolidate(tmp); - MADNESS_CHECK_THROW(tmp.size()==1,"tmp size incorrect"); - tmp[0].print_size(); V+=tmp; apply_G_and_print(tmp,"commutator projector response"); } @@ -1697,7 +1696,7 @@ std::vector> } std::vector> result; - result+=CCPairFunction(V); + if (V.tree_size()>0) result+=CCPairFunction(V); result+=V_lowrank; return result; diff --git a/src/madness/chem/ccpairfunction.h b/src/madness/chem/ccpairfunction.h index 43baa9dc241..79573623fe5 100644 --- a/src/madness/chem/ccpairfunction.h +++ b/src/madness/chem/ccpairfunction.h @@ -626,7 +626,12 @@ using pureT=Function; } else if (component->is_pure()) { component->print_size(name1); } else { + print("printing",name1,name()); double wall=wall_time(); + component->print_size(); + double anorm=madness::norm2(world(),get_a()); + double bnorm=madness::norm2(world(),get_b()); + print("anorm, bnorm",anorm,bnorm); double norm=this->norm2(); std::size_t fsize=get_a().size(); std::size_t bufsize=128; @@ -644,8 +649,13 @@ using pureT=Function; } typename Tensor::scalar_type norm2() const { - if (component->is_pure()) return pure().get_function().norm2(); - if (component->is_decomposed()) { + if (is_pure_no_op()) { + return pure().get_function().norm2(); + } else if (is_op_pure()) { + double n2=inner(*this,*this); + if (n2<0.0) print("norm of ",name()," is < 0.0"); + return sqrt(std::max(0.0,n2)); + } else if (component->is_decomposed()) { Function R2; auto tmp= inner_internal(*this,R2); typename Tensor::scalar_type result=std::real(tmp); diff --git a/src/madness/chem/projector.h b/src/madness/chem/projector.h index b9fc655f96d..9f298df6188 100644 --- a/src/madness/chem/projector.h +++ b/src/madness/chem/projector.h @@ -73,7 +73,9 @@ namespace madness { /// constructor with a set of orbitals to project out /// bra and ket spaces are symmetric - Projector(const vecfuncT& p) : mo_ket_(p), mo_bra_(p) {} + Projector(const vecfuncT& p) : mo_ket_(p), mo_bra_(p) { + MADNESS_CHECK_THROW(mo_bra_.size()==mo_ket_.size(), "bra and ket spaces must have the same size in projector"); + } /// constructor with a set of orbitals to project out @@ -401,6 +403,11 @@ namespace madness { OuterProjector(const projT& p0, const projQ& p1) : projector0(p0), projector1(p1) { projector0.set_particle(0); projector1.set_particle(1); + print("projector vector sizes", + projector0.get_bra_vector().size(), + projector1.get_bra_vector().size(), + projector0.get_ket_vector().size(), + projector1.get_ket_vector().size()); } std::string type() const override { diff --git a/src/madness/chem/test_ccpairfunction.cc b/src/madness/chem/test_ccpairfunction.cc index 47dc8c26469..d84d9ba5bbf 100644 --- a/src/madness/chem/test_ccpairfunction.cc +++ b/src/madness/chem/test_ccpairfunction.cc @@ -195,6 +195,31 @@ int test_constructor(World& world, std::shared_ptr ncf return t1.end(); } +template +int test_norm(World& world, std::shared_ptr ncf, data& data, + const CCParameters& parameter) { + test_output t1("norm of "); + + auto [p1,p2,p3,p4,p5]=data.get_ccpairfunctions(); // p2-p5 correspond to f230 + for (const CCPairFunction& p : {p2,p3,p4,p5}) { + double n=p.norm2(); + print("norm of ",p.name(),n); + double n1=sqrt(inner(p,p)); + print("inner",n1); + t1.checkpoint(n,n1,FunctionDefaults::get_thresh(),"norm of p"); + } + + double n2=p2.norm2(); + double n3=p3.norm2(); + double n4=p4.norm2(); + double n5=p5.norm2(); + t1.checkpoint(n2,n4,FunctionDefaults::get_thresh(),"norm of p2/4"); + t1.checkpoint(n3,n5,FunctionDefaults::get_thresh(),"norm of p3/5"); + + return t1.end(); + +} + template int test_load_store(World& world, std::shared_ptr ncf, data& data, const CCParameters& parameter) { @@ -1324,6 +1349,7 @@ int main(int argc, char **argv) { isuccess+=test_constructor(world, ncf, data2, ccparam); isuccess+=test_load_store(world,ncf,data2,ccparam); isuccess+=test_operator_apply(world, ncf, data2, ccparam); + isuccess+=test_norm(world,ncf,data2,ccparam); isuccess+=test_transformations(world, ncf, data2, ccparam); isuccess+=test_multiply_with_f12(world, ncf, data2, ccparam); isuccess+=test_inner(world, ncf, data2, ccparam); From 52d21a6fdbc820e63fd5f9607de6b8900e59922d Mon Sep 17 00:00:00 2001 From: fbischoff Date: Mon, 10 Jun 2024 13:45:08 +0200 Subject: [PATCH 09/54] debug update --- src/madness/chem/CC2.cc | 32 ++++++++---- src/madness/chem/CC2.h | 2 + src/madness/chem/CCPotentials.cc | 50 ++++++++++++------- src/madness/chem/CCStructures.cc | 7 ++- src/madness/chem/CCStructures.h | 6 ++- src/madness/chem/PNO.cpp | 6 +-- src/madness/chem/PNO.h | 2 +- src/madness/chem/PNOF12Potentials.cpp | 4 +- src/madness/chem/TDHF.cc | 2 +- src/madness/chem/ccpairfunction.cc | 8 +-- .../chem/electronic_correlation_factor.h | 18 +++---- src/madness/chem/nemo.cc | 4 +- src/madness/chem/projector.h | 39 ++++++++++++--- src/madness/chem/test_ccpairfunction.cc | 2 +- src/madness/chem/zcis.h | 2 +- src/madness/mra/macrotaskq.h | 3 +- 16 files changed, 121 insertions(+), 66 deletions(-) diff --git a/src/madness/chem/CC2.cc b/src/madness/chem/CC2.cc index c7c3e9ba06c..caeaabba72c 100644 --- a/src/madness/chem/CC2.cc +++ b/src/madness/chem/CC2.cc @@ -38,6 +38,11 @@ CC2::solve() { // singles for ground state CC_vecfunction cc2singles(PARTICLE); + // Pairs structure to vector if necessary + const std::size_t nfreeze=parameters.freeze(); + const int nocc=CCOPS.mo_ket().size(); + triangular_map=PairVectorMap::triangular_map(nfreeze,nocc); + double mp2_energy=0.0, cc2_energy=0.0, mp3_energy=0.0; bool need_tdhf=parameters.response(); @@ -412,9 +417,6 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { if (world.rank()==0) print_header2(" computing the MP1 wave function"); double total_energy = 0.0; - const std::size_t nfreeze=parameters.freeze(); - const int nocc=CCOPS.mo_ket().size(); - auto triangular_map=PairVectorMap::triangular_map(nfreeze,nocc); // make vector holding CCPairs for partitioner of MacroTask std::vector pair_vec=Pairs::pairs2vector(doubles,triangular_map); @@ -443,7 +445,6 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { taskq->set_printlevel(3); MacroTaskConstantPart t; MacroTask task(world, t, taskq); - task.set_name("MP2_Constant_Part"); std::vector> gs_singles, ex_singles; // dummy vectors std::vector result_vec = task(pair_vec, gs_singles, ex_singles, info) ; taskq->print_taskq(); @@ -736,16 +737,16 @@ CC2::iterate_lrcc2_pairs(const CC_vecfunction& cc2_s, const Pairs& cc2_d const size_t i = pair.i; const size_t j = pair.j; // check if singles have significantly changed - // if (lrcc2_s(i).current_error < 0.1 * parameters.thresh_6D() and - // lrcc2_s(j).current_error < 0.1 * parameters.thresh_6D()) - // output("Skipping Pair Iteration, No significant Change in Singles"); - // else { + if (lrcc2_s(i).current_error < 0.1 * parameters.thresh_6D() and + lrcc2_s(j).current_error < 0.1 * parameters.thresh_6D()) + output("Skipping Pair Iteration, No significant Change in Singles"); + else { pair.bsh_eps = CCOPS.get_epsilon(pair.i, pair.j) + lrcc2_s.omega; // update_constant_part_lrcc2(pair, cc2_s, lrcc2_s); pair.constant_part=CCPotentials::make_constant_part_macrotask(world, pair, cc2_s, lrcc2_s, info); conv = iterate_pair(pair, lrcc2_s); - // } + } } return conv; @@ -792,12 +793,21 @@ CC2::solve_cc2(CC_vecfunction& singles, Pairs& doubles) { output.section("Macroiteration " + std::to_string(int(iter)) + " of CC2"); // iterate doubles + std::vector pair_vec=Pairs::pairs2vector(doubles,triangular_map); + MacroTaskConstantPart t; + MacroTask task(world, t); + std::vector result_vec = task(pair_vec, singles.get_vecfunction(), + ex_singles_dummy.get_vecfunction(), info) ; + auto constant_part=Pairs::vector2pairs(result_vec,triangular_map); + + bool doubles_converged = true; for (auto& pairs: doubles.allpairs) { CCPair& pair = pairs.second; + pair.constant_part= constant_part(pair.i, pair.j); // update_constant_part_cc2_gs(singles, pair); - pair.constant_part=CCPotentials::make_constant_part_macrotask(world, pair, - singles, ex_singles_dummy, info); + // pair.constant_part=CCPotentials::make_constant_part_macrotask(world, pair, + // singles, ex_singles_dummy, info); bool pair_converged = iterate_pair(pair, singles); save(pair.function(), pair.name()); if (not pair_converged) doubles_converged = false; diff --git a/src/madness/chem/CC2.h b/src/madness/chem/CC2.h index 6fc41019a14..145903406a9 100644 --- a/src/madness/chem/CC2.h +++ b/src/madness/chem/CC2.h @@ -128,6 +128,8 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { CCPotentials CCOPS; /// Formated Output (same as used in CC2Potentials structure) CCMessenger& output; + /// map Pair struct to vector + PairVectorMap triangular_map; /// solve the CC2 ground state equations, returns the correlation energy void solve(); diff --git a/src/madness/chem/CCPotentials.cc b/src/madness/chem/CCPotentials.cc index e8a3a3d8f7b..57fa20b872b 100644 --- a/src/madness/chem/CCPotentials.cc +++ b/src/madness/chem/CCPotentials.cc @@ -697,29 +697,39 @@ CCPotentials::make_constant_part_macrotask(World& world, const CCPair& pair, const Info& info) { const CalcType targetstate=pair.ctype; const auto& parameters=info.parameters; - - // t1-transformed orbitals - CC_vecfunction t(MIXED); - if (targetstate==CT_CC2 or targetstate==CT_LRCC2) { - t=CCPotentials::make_full_t_intermediate(gs_singles,info); - } - + std::string msg="compute constant part of pair "+std::to_string(pair.i) + " " + std::to_string(pair.j); + print_header3(msg); + timer t1(world); +print("debug 1"); // construct the projectors // Q12 = (1-|i> Q12(world); Q12.set_spaces(info.mo_bra,info.mo_ket,info.mo_bra,info.mo_ket); +print("debug 2"); // Q12t = (1-|t_i> Q12t(world); - Q12t.set_spaces(info.mo_bra,t.get_vecfunction(),info.mo_bra,t.get_vecfunction()); + +print("debug 3"); + // t1-transformed orbitals + CC_vecfunction t(MIXED); + if (targetstate==CT_CC2 or targetstate==CT_LRCC2) { + t=CCPotentials::make_full_t_intermediate(gs_singles,info); + Q12t.set_spaces(info.mo_bra,t.get_vecfunction(),info.mo_bra,t.get_vecfunction()); + } + +print("debug 4"); // dQ12t = -(Qt(1) Ox(2) + Ox(1) Qt(2)) eq. (22) - QProjector Qt(world,info.mo_bra,t.get_vecfunction()); - Projector Ox(info.get_active_mo_bra(),ex_singles.get_vecfunction()); + QProjector Qt; + Projector Ox; + if (targetstate==CT_LRCC2) { + Qt.set_spaces(info.mo_bra,t.get_vecfunction()); + Ox.set_spaces(info.get_active_mo_bra(),ex_singles.get_vecfunction()); + } auto dQt_1 = outer(Qt,Ox); auto dQt_2 = outer(Ox,Qt); - - +print("debug 5"); std::size_t i=pair.i; std::size_t j=pair.j; @@ -790,7 +800,7 @@ CCPotentials::make_constant_part_macrotask(World& world, const CCPair& pair, auto Vreg=apply_Vreg(world,x(i),t(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); Vreg+=apply_Vreg(world,t(i),x(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); V=consolidate(apply_in_separated_form(Q12t,Vreg)); - apply_G_and_print(V,"functional response"); + // apply_G_and_print(V,"functional response"); } if (0) { @@ -798,8 +808,8 @@ CCPotentials::make_constant_part_macrotask(World& world, const CCPair& pair, std::vector argument={"comm_F_Qt_f12"}; auto Vreg=apply_Vreg(world,x(i),t(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); Vreg+=apply_Vreg(world,t(i),x(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); - auto Q12V=Q12t(Vreg); - apply_G_and_print(Q12V,"commutator response in old terminology: Q12V direct"); + // auto Q12V=Q12t(Vreg); + // apply_G_and_print(Q12V,"commutator response in old terminology: Q12V direct"); } // eq. (29) first term: dQt g~ |t_i t_j> @@ -814,7 +824,7 @@ CCPotentials::make_constant_part_macrotask(World& world, const CCPair& pair, // MADNESS_CHECK_THROW(tmp.size()==1,"tmp size is incorrect"); // for (auto& t : tmp) t.print_size("dQt g~ |t_i t_j>"); - apply_G_and_print(tmp,"projector response"); + // apply_G_and_print(tmp,"projector response"); } @@ -825,12 +835,13 @@ CCPotentials::make_constant_part_macrotask(World& world, const CCPair& pair, auto tmp=apply_Vreg(world,t(i),t(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); tmp=consolidate(tmp); V+=tmp; - apply_G_and_print(tmp,"commutator projector response"); + // apply_G_and_print(tmp,"commutator projector response"); } } V=consolidate(V); MADNESS_CHECK(V.size()==2); // term 1: 6d, hi-rank, local; term 2: 3d, low-rank, delocalized + t1.end("finished computing potential for constant part"); // the Green's function auto G = BSHOperator<6>(world, sqrt(-2.0 * pair.bsh_eps), parameters.lo(), parameters.thresh_bsh_6D()); @@ -841,6 +852,7 @@ CCPotentials::make_constant_part_macrotask(World& world, const CCPair& pair, GV=-2.0*Q12(GV).truncate().reduce_rank(); GV.print_size("GVreg"); + t1.end("finished applying G on potential for constant part"); return GV; } @@ -2094,7 +2106,7 @@ CCPotentials::apply_commutator_F_Qt_f12(World& world, const CCFunction const vector_real_function_3d Vtau=info.intermediate_potentials(gs_singles, POT_singles_); Projector OVtau(info.get_active_mo_bra(),Vtau); - QProjector Qt(world,info.get_active_mo_bra(),gs_singles.get_vecfunction()); + QProjector Qt(info.get_active_mo_bra(),gs_singles.get_vecfunction()); auto p1=outer(OVtau,Qt); auto p2=outer(Qt,OVtau); @@ -2129,7 +2141,7 @@ CCPotentials::apply_commutator_F_dQt_f12(World& world, const CCFunction OVtau(bra,Vtau); Projector Ox(bra,ex_singles.get_vecfunction()); Projector OVx(bra,Vx); - QProjector Qt(world,bra,t.get_vecfunction()); + QProjector Qt(bra,t.get_vecfunction()); auto OvxQt=outer(OVx,Qt); auto QtOvx=outer(Qt,OVx); diff --git a/src/madness/chem/CCStructures.cc b/src/madness/chem/CCStructures.cc index 8f4009825fa..982976ea5de 100644 --- a/src/madness/chem/CCStructures.cc +++ b/src/madness/chem/CCStructures.cc @@ -542,10 +542,15 @@ MacroTaskConstantPart::operator() (const std::vector& pair, const std::vector> & gs_singles, const std::vector> & ex_singles, const Info& info) const { + World& world =info.mo_ket[0].world(); + CC_vecfunction singles(gs_singles, PARTICLE, info.parameters.freeze()); + CC_vecfunction exsingles(gs_singles, PARTICLE, info.parameters.freeze()); + + resultT result = zero_functions_compressed(world, pair.size()); for (size_t i = 0; i < pair.size(); i++) { - result[i] = CCPotentials::make_constant_part_macrotask(world, pair[i], gs_singles, ex_singles, info); + result[i] = CCPotentials::make_constant_part_macrotask(world, pair[i], singles, exsingles, info); } return result; } diff --git a/src/madness/chem/CCStructures.h b/src/madness/chem/CCStructures.h index db6ace38d64..7bb675adbf7 100644 --- a/src/madness/chem/CCStructures.h +++ b/src/madness/chem/CCStructures.h @@ -379,6 +379,7 @@ struct CCParameters : public QCCalculationParametersBase { struct PairVectorMap { std::vector> map; ///< maps pair index (i,j) to vector index k + PairVectorMap() = default; PairVectorMap(const std::vector> map1) : map(map1) {} static PairVectorMap triangular_map(const int nfreeze, const int nocc) { @@ -1285,7 +1286,10 @@ class MacroTaskConstantPart : public MacroTaskOperationBase { }; public: - MacroTaskConstantPart(){partitioner.reset(new ConstantPartPartitioner());} + MacroTaskConstantPart() { + partitioner.reset(new ConstantPartPartitioner()); + name="ConstantPart"; + } // typedef std::tuple&, const std::vector>&, // const std::vector>&, const CCParameters&, const Function&, diff --git a/src/madness/chem/PNO.cpp b/src/madness/chem/PNO.cpp index 9dd1b0f4111..8984a6e32b3 100644 --- a/src/madness/chem/PNO.cpp +++ b/src/madness/chem/PNO.cpp @@ -781,7 +781,7 @@ PNOPairs PNO::initialize_pairs(PNOPairs& pairs, const GuessType& inpgt) const { vector_real_function_3d& pno = pno_ij[it.ij()]; if (not pno.empty()) { msg << it.name() << ": pnos not empty ... project out and assemble\n"; - QProjector Qpno(world, pno, pno); + QProjector Qpno( pno, pno); pno = append(pno, Qpno(virtuals)); } else pno = append(pno, virtuals); @@ -814,7 +814,7 @@ PNOPairs PNO::initialize_pairs(PNOPairs& pairs, const GuessType& inpgt) const { } vector_real_function_3d virtij = guess_virtuals(pair_mo, guesstype); if (not pno.empty()) { - QProjector Qpno(world, pno, pno); + QProjector Qpno( pno, pno); virtij = Qpno(virtij); } @@ -1574,7 +1574,7 @@ PNOPairs PNO::grow_rank(PNOPairs& pairs, std::string exop)const{ vector_real_function_3d virtij = Q(basis.guess_with_exop(pair_mo, exop,param.exop_trigo()));// guess_virtuals(pair_mo, EXOP_TYPE); // project out already existing pno pairs if (not pairs.pno_ij[it.ij()].empty()) { - QProjector Qpno(world, pairs.pno_ij[it.ij()], pairs.pno_ij[it.ij()]); + QProjector Qpno(pairs.pno_ij[it.ij()], pairs.pno_ij[it.ij()]); virtij = Qpno(virtij); } diff --git a/src/madness/chem/PNO.h b/src/madness/chem/PNO.h index 0d0e77db417..cf0b24ffb91 100644 --- a/src/madness/chem/PNO.h +++ b/src/madness/chem/PNO.h @@ -36,7 +36,7 @@ class PNO : public QCPropertyInterface { T(world), V(world, nemo.ncf), F(world, &nemo), - Q(world, nemo.get_calc()->amo), + Q( nemo.get_calc()->amo), basis(world,nemo.get_calc()->molecule,8), f12(world,nemo,basis,paramf12), msg(world) diff --git a/src/madness/chem/PNOF12Potentials.cpp b/src/madness/chem/PNOF12Potentials.cpp index 99fc2bdcfc5..fa7804fd940 100644 --- a/src/madness/chem/PNOF12Potentials.cpp +++ b/src/madness/chem/PNOF12Potentials.cpp @@ -72,7 +72,7 @@ F12Potentials::F12Potentials(World& world,const Nemo& nemo, const BasisFunctions mos(nemo.get_calc()->amo), acmos(initialize_active_mos(nemo)), K(ParametrizedExchange(world, nemo, pp.exchange())), - Q(world, nemo.get_calc()->amo) { + Q(nemo.get_calc()->amo) { const double lo = 1.e-6; const double eps = param.op_thresh(); coulombop = std::shared_ptr < real_convolution_3d > (CoulombOperatorPtr(world, lo, eps)); @@ -1377,7 +1377,7 @@ PairEnergies F12Potentials::compute_hylleraas_f12_energies( for (ElectronPairIterator it = pit(); it; ++it) { // right now this will make the same guess for all pairs //const vector_real_function_3d tmp=guess_virtuals(param.abs); - QProjector Qpno(world, pnos[it.ij()]); + QProjector Qpno( pnos[it.ij()]); const vector_real_function_3d tmp = Qpno(cabs); abs_ij[it.ij()] = tmp; } diff --git a/src/madness/chem/TDHF.cc b/src/madness/chem/TDHF.cc index 72b89e28f73..e9a876d1360 100644 --- a/src/madness/chem/TDHF.cc +++ b/src/madness/chem/TDHF.cc @@ -154,7 +154,7 @@ void TDHF::prepare_calculation() { mo_ket_ = make_mo_ket(get_calc()->amo); mo_bra_ = make_mo_bra(get_calc()->amo); - Q = QProjector(world, mo_bra_.get_vecfunction(), mo_ket_.get_vecfunction()); + Q = QProjector( mo_bra_.get_vecfunction(), mo_ket_.get_vecfunction()); if (not parameters.no_compute()) { diff --git a/src/madness/chem/ccpairfunction.cc b/src/madness/chem/ccpairfunction.cc index a8f36b2792a..8d2ec9a52a4 100644 --- a/src/madness/chem/ccpairfunction.cc +++ b/src/madness/chem/ccpairfunction.cc @@ -657,8 +657,8 @@ std::vector> CCPairFunction::apply(const Projecto } else if (pf.is_decomposed_no_op()) { // pair function is sum_i | a_i b_i > if (auto SO=dynamic_cast*>(&projector)) { // Q12 | kl > = (1-O1)(1-O2) |kl> = |(1-O1)k (1-O2)l> - QProjector Q1(world,SO->bra1(),SO->ket1()); - QProjector Q2(world,SO->bra2(),SO->ket2()); + QProjector Q1(SO->bra1(),SO->ket1()); + QProjector Q2(SO->bra2(),SO->ket2()); result.push_back(CCPairFunction(Q1(pf.get_a()),Q2(pf.get_b()))); } else if (auto P=dynamic_cast*>(&projector)) { @@ -680,9 +680,9 @@ std::vector> CCPairFunction::apply(const Projecto // CCTimer t(world,"SO block"); // Q12 = 1 - O1 (1 - 1/2 O2) - O2 (1 - 1/2 O1) // print("entering SO block"); - QProjector Q1(world,SO->bra1(),SO->ket1()); + QProjector Q1(SO->bra1(),SO->ket1()); Q1.set_particle(0); - QProjector Q2(world,SO->bra2(),SO->ket2()); + QProjector Q2(SO->bra2(),SO->ket2()); Q2.set_particle(1); Projector O1(SO->bra1(),SO->ket1()); diff --git a/src/madness/chem/electronic_correlation_factor.h b/src/madness/chem/electronic_correlation_factor.h index a1fab4d12c1..c4b3168b513 100644 --- a/src/madness/chem/electronic_correlation_factor.h +++ b/src/madness/chem/electronic_correlation_factor.h @@ -35,20 +35,18 @@ class CorrelationFactor { CorrelationFactor(World& world, const double& gamma, const double dcut, const Molecule& molecule) : world(world), _gamma(gamma), dcut(dcut) { lo=1.e-6;//lo = molecule.smallest_length_scale(); - if (world.rank()==0) { - - if (gamma>0.0) print("constructed correlation factor with gamma=",gamma); - else if (gamma==0.0) print("constructed linear correlation factor"); - } +// if (world.rank()==0) { +// if (gamma>0.0) print("constructed correlation factor with gamma=",gamma); +// else if (gamma==0.0) print("constructed linear correlation factor"); +// } } /// ctor, use negative gamma for linear correlation factor r12 CorrelationFactor(World& world, const double& gamma, const double dcut, const double lo) : world(world), _gamma(gamma), dcut(dcut), lo(lo) { - if (world.rank()==0) { - - if (gamma>0.0) print("constructed correlation factor with gamma=",gamma); - else if (gamma==0.0) print("constructed linear correlation factor"); - } +// if (world.rank()==0) { +// if (gamma>0.0) print("constructed correlation factor with gamma=",gamma); +// else if (gamma==0.0) print("constructed linear correlation factor"); +// } } /// copy ctor diff --git a/src/madness/chem/nemo.cc b/src/madness/chem/nemo.cc index 773345b8b3d..2730c2d99e0 100644 --- a/src/madness/chem/nemo.cc +++ b/src/madness/chem/nemo.cc @@ -1094,7 +1094,7 @@ vecfuncT Nemo::make_cphf_constant_term(const size_t iatom, const int iaxis, const int nmo=nemo.size(); const Tensor occ=get_calc()->get_aocc(); - QProjector Q(world,R2nemo,nemo); + QProjector Q(R2nemo,nemo); DNuclear Dunuc(world,this,iatom,iaxis); vecfuncT Vpsi2b=Dunuc(nemo); @@ -1162,7 +1162,7 @@ vecfuncT Nemo::solve_cphf(const size_t iatom, const int iaxis, const Tensor Q(world,R2nemo,nemo); + QProjector Q(R2nemo,nemo); // construct quantities that are independent of xi diff --git a/src/madness/chem/projector.h b/src/madness/chem/projector.h index 9f298df6188..9c081a54e97 100644 --- a/src/madness/chem/projector.h +++ b/src/madness/chem/projector.h @@ -81,7 +81,20 @@ namespace madness { /// bra and ket spaces are not symmetric (e.g. |ket>^+ = operator()(const Function& rhs) const { return (rhs-O(rhs)).truncate(); } @@ -403,11 +431,6 @@ namespace madness { OuterProjector(const projT& p0, const projQ& p1) : projector0(p0), projector1(p1) { projector0.set_particle(0); projector1.set_particle(1); - print("projector vector sizes", - projector0.get_bra_vector().size(), - projector1.get_bra_vector().size(), - projector0.get_ket_vector().size(), - projector1.get_ket_vector().size()); } std::string type() const override { diff --git a/src/madness/chem/test_ccpairfunction.cc b/src/madness/chem/test_ccpairfunction.cc index d84d9ba5bbf..b399a156c96 100644 --- a/src/madness/chem/test_ccpairfunction.cc +++ b/src/madness/chem/test_ccpairfunction.cc @@ -1158,7 +1158,7 @@ int test_projector(World& world, std::shared_ptr ncf, std::vector> vp3({p3}); Projector O(o,o); - QProjector Q(world,o,o); + QProjector Q(o,o); StrongOrthogonalityProjector Q12(world); Q12.set_spaces(o); diff --git a/src/madness/chem/zcis.h b/src/madness/chem/zcis.h index aee71bfe1ae..6899e937cb2 100644 --- a/src/madness/chem/zcis.h +++ b/src/madness/chem/zcis.h @@ -126,7 +126,7 @@ class Zcis : public QCPropertyInterface { Zcis(World& w, const commandlineparser& parser, std::shared_ptr n) : world(w), cis_param(world, parser), nemo(n), - Qa(world,nemo->amo,nemo->amo), Qb(world,nemo->bmo,nemo->bmo) { + Qa(nemo->amo,nemo->amo), Qb(nemo->bmo,nemo->bmo) { cis_param.print("response","end"); print("Qa projector",Qa.get_ket_vector().size()); print("Qb projector",Qb.get_ket_vector().size()); diff --git a/src/madness/mra/macrotaskq.h b/src/madness/mra/macrotaskq.h index 0a1ae1de6ab..b30ec8d2586 100644 --- a/src/madness/mra/macrotaskq.h +++ b/src/madness/mra/macrotaskq.h @@ -506,7 +506,7 @@ class MacroTask { /// constructor takes the actual task MacroTask(World &world, taskT &task, std::shared_ptr taskq_ptr = 0) - : task(task), world(world), taskq_ptr(taskq_ptr) { + : task(task), name(task.name), world(world), taskq_ptr(taskq_ptr) { if (taskq_ptr) { // for the time being this condition must hold because tasks are // constructed as replicated objects and are not broadcast to other processes @@ -716,6 +716,7 @@ class MacroTask { class MacroTaskOperationBase { public: Batch batch; + std::string name; std::shared_ptr partitioner=0; MacroTaskOperationBase() : batch(Batch(_, _, _)), partitioner(new MacroTaskPartitioner) {} }; From a6c587f972864b64d63da8347dc1ee3d7901736b Mon Sep 17 00:00:00 2001 From: fbischoff Date: Fri, 21 Jun 2024 13:27:03 +0200 Subject: [PATCH 10/54] iterate MP2 pairs using generalized macrotask --- src/madness/chem/CC2.cc | 109 ++++++++++--------------- src/madness/chem/CCPotentials.cc | 133 ++++++++++++++++++++++++++++--- src/madness/chem/CCPotentials.h | 13 ++- src/madness/chem/CCStructures.cc | 22 +++++ src/madness/chem/CCStructures.h | 63 +++++++++++++++ 5 files changed, 257 insertions(+), 83 deletions(-) diff --git a/src/madness/chem/CC2.cc b/src/madness/chem/CC2.cc index caeaabba72c..60ee5137e5a 100644 --- a/src/madness/chem/CC2.cc +++ b/src/madness/chem/CC2.cc @@ -99,7 +99,6 @@ CC2::solve() { output.section(assign_name(CT_CC2) + " Calculation Ended !"); if (world.rank() == 0) { printf_msg_energy_time("CC2 correlation energy",cc2_energy,wall_time()); -// std::cout << std::fixed << std::setprecision(10) << " MP2 Correlation Energy =" << mp2_energy << "\n"; std::cout << std::fixed << std::setprecision(10) << " CC2 Correlation Energy =" << cc2_energy << "\n"; } } @@ -257,6 +256,7 @@ CC2::solve() { Info info; info.mo_bra=CCOPS.mo_bra().get_vecfunction(); info.mo_ket=CCOPS.mo_ket().get_vecfunction(); + info.molecular_coordinates=nemo->get_calc()->molecule.get_all_coords_vec(); info.parameters=parameters; info.R_square=nemo->R_square; info.U1=nemo->ncf->U1vec(); @@ -424,6 +424,7 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { Info info; info.mo_bra=CCOPS.mo_bra().get_vecfunction(); info.mo_ket=CCOPS.mo_ket().get_vecfunction(); + info.molecular_coordinates=nemo->get_calc()->molecule.get_all_coords_vec(); info.parameters=parameters; info.R_square=nemo->R_square; info.U1=nemo->ncf->U1vec(); @@ -435,23 +436,23 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { for (auto& c : pair_vec) { MADNESS_CHECK_THROW(c.constant_part.is_initialized(), "could not find constant part"); // constant part is zero-order guess for pair.function + print_header1("clearing function"); + c.function().clear(); if (not c.function().is_initialized()) c.update_u(c.constant_part); } } else { + if (world.rank()==0) print_header3("Starting MP2 constant part calculation"); - // calc constant part via taskq - auto taskq = std::shared_ptr(new MacroTaskQ(world, world.size())); - taskq->set_printlevel(3); MacroTaskConstantPart t; - MacroTask task(world, t, taskq); + MacroTask task(world, t); std::vector> gs_singles, ex_singles; // dummy vectors std::vector result_vec = task(pair_vec, gs_singles, ex_singles, info) ; - taskq->print_taskq(); - taskq->run_all(); - if (world.rank()==0) std::cout << std::fixed << std::setprecision(1) << "\nFinished constant part at time " << wall_time() << std::endl; - if (world.rank()==0) std::cout << std::fixed << std::setprecision(1) << "\nStarting saving pairs and energy calculation at time " << wall_time() << std::endl; + if (world.rank()==0) { + std::cout << std::fixed << std::setprecision(1) << "\nFinished constant part at time " << wall_time() << std::endl; + std::cout << std::fixed << std::setprecision(1) << "\nStarting saving pairs and energy calculation at time " << wall_time() << std::endl; + } // transform vector back to Pairs structure for (size_t i = 0; i < pair_vec.size(); i++) { @@ -484,50 +485,40 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { for (size_t iter = 0; iter < parameters.iter_max_6D(); iter++) { + if (world.rank()==0) print_header3("Starting iteration " + std::to_string(int(iter)) + " of MP2"); - if (world.rank()==0) print("pair_vec before coupling"); - for (const auto& p :pair_vec) { - if (world.rank()==0) print("pair",p.i,p.j, p.function().get_impl()->get_tree_state()); - p.function().print_size("pair_vec function before coupling"); - p.constant_part.print_size("pair_vec constant part before coupling"); - } // compute the coupling between the pair functions Pairs coupling=compute_local_coupling(pair_vec); auto coupling_vec=Pairs::pairs2vector(coupling,triangular_map); if (parameters.debug()) print_size(world, coupling_vec, "couplingvector"); - double old_energy = total_energy; - total_energy = 0.0; - // calc update for pairs via macrotask - auto taskq = std::shared_ptr(new MacroTaskQ(world, world.size())); - taskq->set_printlevel(3); - //taskq->cloud.set_debug(true); - MacroTaskMp2UpdatePair t; - MacroTask task1(world, t, taskq); - if (world.rank()==0) print("pair_vec before update"); - for (auto& p :pair_vec) { - if (world.rank()==0) print("pair",p.i,p.j, p.function().get_impl()->get_tree_state()); - p.function().print_size("pair_vec function before update"); // flodbg 2.0 GByte - p.function().change_tree_state(reconstructed); - p.function().print_size("pair_vec function before update after reconstruction"); // flodbg 2.0 GByte - p.constant_part.print_size("pair_vec constant part before update macrotask is called"); + if (world.rank()==0) print("Start updating pairs in iteration "); + MacroTaskIteratePair t; + MacroTask task1(world, t); + std::vector dummy_singles; // dummy vectors + const std::size_t maxiter=1; + auto unew = task1(pair_vec, coupling_vec, dummy_singles, dummy_singles, + info.molecular_coordinates, info, maxiter); + + std::vector u; + for (auto p : pair_vec) u.push_back(p.function()); + auto residual=u-unew; + + // some statistics + auto errors=norm2s(world,residual); + double rnorm=0.0, maxrnorm=0.0; + for (double& e : errors) { + maxrnorm=std::max(maxrnorm,e); + rnorm+=e*e; } -// std::vector u_update = task1(pair_vec, coupling_vec, parameters, nemo->get_calc()->molecule.get_all_coords_vec(), -// CCOPS.mo_ket().get_vecfunction(), CCOPS.mo_bra().get_vecfunction(), -// nemo->ncf->U1vec(), nemo->ncf->U2()); - auto all_coords=nemo->get_calc()->molecule.get_all_coords_vec(); - std::vector u_update = task1(pair_vec, coupling_vec, all_coords , info); - taskq->print_taskq(); - taskq->run_all(); - + rnorm=sqrt(rnorm/errors.size()); + // update the pair functions if (parameters.kain()) { if (world.rank()==0) std::cout << "Update with KAIN" << std::endl; - - std::vector u; - for (auto p : pair_vec) u.push_back(p.function()); - std::vector kain_update = copy(world,solver.update(u, u_update)); + // std::vector kain_update = copy(world,solver.update(u, u_update)); + std::vector kain_update = copy(world,solver.update(u, residual)); for (size_t i=0; i& doubles) { } else { if (world.rank()==0) std::cout << "Update without KAIN" << std::endl; for (size_t i=0; iget_tree_state()); - p.function().print_size("pair_vec function after KAIN update "); - p.constant_part.print_size("pair_vec constant part after KAIN update "); - } // calculate energy and error and update pairs - double total_rnorm = 0.0, maxrnorm=0.0; + double old_energy = total_energy; + total_energy = 0.0; for (size_t i = 0; i < pair_vec.size(); i++) { - const double error = u_update[i].norm2(); - if (world.rank()==0) std::cout << "residual " << pair_vec[i].i << " " << pair_vec[i].j << " " << error << std::endl; - maxrnorm = std::max(maxrnorm, error); - total_rnorm+=error; + if (world.rank()==0) std::cout << "residual " << pair_vec[i].i << " " << pair_vec[i].j << " " << errors[i] << std::endl; save(pair_vec[i].function(), pair_vec[i].name()); double energy = 0.0; @@ -564,18 +548,10 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { total_energy += energy; } - - if (world.rank()==0) print("pair_vec after energy computation"); // flodbg 0.3 GByte - for (const auto& p :pair_vec) { - if (world.rank()==0) print("pair",p.i,p.j, p.function().get_impl()->get_tree_state()); - p.function().print_size("pair_vec function after energy computation"); - p.constant_part.print_size("pair_vec constant part after energy computation"); - } - if (world.rank()==0) { - std::cout << "convergence: total/max residual, energy/norm change " + std::cout << "convergence: rms/max residual, energy change " << std::scientific << std::setprecision(1) - << maxrnorm << " " << total_rnorm << " " + << rnorm << " " << maxrnorm << " " << std::abs(old_energy - total_energy) << std::endl; // << std::abs(old_norm - total_norm); printf("finished iteration %2d at time %8.1fs with energy %12.8f\n", @@ -772,6 +748,7 @@ CC2::solve_cc2(CC_vecfunction& singles, Pairs& doubles) { info.intermediate_potentials=CCIntermediatePotentials(parameters); info.mo_bra=CCOPS.mo_bra().get_vecfunction(); info.mo_ket=CCOPS.mo_ket().get_vecfunction(); + info.molecular_coordinates=nemo->get_calc()->molecule.get_all_coords_vec(); info.parameters=parameters; info.R_square=nemo->R_square; info.U1=nemo->ncf->U1vec(); @@ -953,7 +930,6 @@ bool CC2::iterate_pair(CCPair& pair, const CC_vecfunction& singles) const { return converged; } - bool CC2::initialize_singles(CC_vecfunction& singles, const FuncType type, const int ex) const { MADNESS_ASSERT(singles.size() == 0); @@ -1005,9 +981,6 @@ CC2::initialize_pairs(Pairs& pairs, const CCState ftype, const CalcType tmp.constant_part = const_part; pairs.insert(i, j, tmp); - //const double omega = CCOPS.compute_pair_correlation_energy(tmp); - //if(world.rank()==0) std::cout << "initialized pair " << tmp.name() << " with correlation energy=" << std::fixed << std::setprecision(10) << omega << "\n"; - } else if (ftype == EXCITED_STATE) { name = std::to_string(int(excitation)) + "_" + name; real_function_6d utmp = real_factory_6d(world); diff --git a/src/madness/chem/CCPotentials.cc b/src/madness/chem/CCPotentials.cc index 57fa20b872b..95bbe97d64d 100644 --- a/src/madness/chem/CCPotentials.cc +++ b/src/madness/chem/CCPotentials.cc @@ -700,17 +700,14 @@ CCPotentials::make_constant_part_macrotask(World& world, const CCPair& pair, std::string msg="compute constant part of pair "+std::to_string(pair.i) + " " + std::to_string(pair.j); print_header3(msg); timer t1(world); -print("debug 1"); // construct the projectors // Q12 = (1-|i> Q12(world); Q12.set_spaces(info.mo_bra,info.mo_ket,info.mo_bra,info.mo_ket); -print("debug 2"); // Q12t = (1-|t_i> Q12t(world); -print("debug 3"); // t1-transformed orbitals CC_vecfunction t(MIXED); if (targetstate==CT_CC2 or targetstate==CT_LRCC2) { @@ -718,7 +715,6 @@ print("debug 3"); Q12t.set_spaces(info.mo_bra,t.get_vecfunction(),info.mo_bra,t.get_vecfunction()); } -print("debug 4"); // dQ12t = -(Qt(1) Ox(2) + Ox(1) Qt(2)) eq. (22) QProjector Qt; @@ -729,7 +725,6 @@ print("debug 4"); } auto dQt_1 = outer(Qt,Ox); auto dQt_2 = outer(Ox,Qt); -print("debug 5"); std::size_t i=pair.i; std::size_t j=pair.j; @@ -788,8 +783,7 @@ print("debug 5"); std::vector argument={"Ue","KffK","comm_F_Qt_f12","reduced_Fock"}; auto Vreg=apply_Vreg(world,t(i),t(j),gs_singles,ex_singles,info,argument,pair.bsh_eps); V=consolidate(Q12t(Vreg)); - } else if (targetstate==CT_LRCC2) - { + } else if (targetstate==CT_LRCC2) { // Eq. (25) of Kottmann, JCTC 13, 5956 (2017) // eq. (25) Q12t (g~ - omega f12) (|x_i t_j> + |t_i x_j> ) // note the term omega f12 is included in the reduced_Fock term, see eq. (34) @@ -981,9 +975,124 @@ CCPotentials::update_pair_mp2_macrotask(World& world, const CCPair& pair, const residue.truncate(FunctionDefaults<6>::get_thresh()*0.1); if (parameters.debug()) residue.print_size("bsh residual, truncated"); - return residue; + // return residue; + return unew; } + +CCPair CCPotentials::iterate_pair_macrotask(World& world, + const CCPair& pair, const CC_vecfunction& singles, + const real_function_6d& coupling, + const Info& info, const long maxiter) { + if (world.rank()==0) print_header2("Iterate Pair " + pair.name()); + if (pair.ctype == CT_CC2) MADNESS_ASSERT(singles.type == PARTICLE); + if (pair.ctype == CT_CISPD) MADNESS_ASSERT(singles.type == RESPONSE); + if (pair.ctype == CT_MP2) MADNESS_ASSERT(singles.get_vecfunction().empty()); + if (pair.ctype == CT_ADC2)MADNESS_ASSERT(singles.type == RESPONSE); + + real_function_6d constant_part = pair.constant_part; + constant_part.truncate().reduce_rank(); + pair.function().truncate().reduce_rank(); + + StrongOrthogonalityProjector Q12(world); + Q12.set_spaces(info.mo_bra,info.mo_ket,info.mo_bra,info.mo_ket); + + double bsh_eps = pair.bsh_eps; //CCOPS.get_epsilon(pair.i,pair.j)+omega; + real_convolution_6d G = BSHOperator<6>(world, sqrt(-2.0 * bsh_eps), info.parameters.lo(), info.parameters.thresh_bsh_6D()); + G.destructive() = true; + + NonlinearSolverND<6> solver(info.parameters.kain_subspace()); + solver.do_print = (world.rank() == 0); + + double omega = 0.0; + // if (pair.type == GROUND_STATE) omega = CCOPS.compute_pair_correlation_energy(pair, singles); + // if (pair.type == EXCITED_STATE) omega = CCOPS.compute_excited_pair_energy(pair, singles); + + // if (world.rank() == 0) + // std::cout << "Correlation Energy of Pair " << pair.name() << " =" << std::fixed << std::setprecision(10) + // << omega << "\n"; + + CCPair result=pair; + + for (size_t iter = 0; iter < maxiter; iter++) { + if (world.rank()==0) print_header3(assign_name(pair.ctype) + "-Microiteration"); + CCTimer timer_mp2(world, "MP2-Microiteration of pair " + pair.name()); + + + CCTimer timer_mp2_potential(world, "MP2-Potential of pair " + pair.name()); + // real_function_6d mp2_potential = -2.0 * CCOPS.fock_residue_6d(pair); + real_function_6d mp2_potential = -2.0 * fock_residue_6d_macrotask(world,result,info.parameters, + info.molecular_coordinates,info.mo_ket,info.mo_bra, + info.U1,info.U2); + mp2_potential += 2.0 * coupling; + + if (info.parameters.debug()) mp2_potential.print_size(assign_name(pair.ctype) + " Potential"); + mp2_potential.truncate().reduce_rank(); + timer_mp2_potential.info(true, mp2_potential.norm2()); + + CCTimer timer_G(world, "Apply Greens Operator on MP2-Potential of pair " + pair.name()); + const real_function_6d GVmp2 = G(mp2_potential); + timer_G.info(true, GVmp2.norm2()); + + CCTimer timer_addup(world, "Add constant parts and update pair " + pair.name()); + real_function_6d unew = Q12(GVmp2 + constant_part); + // unew.print_size("unew"); + // unew = CCOPS.apply_Q12t(unew, CCOPS.mo_ket()); + // unew.print_size("Q12unew"); + //unew.truncate().reduce_rank(); // already done in Q12 application at the end + if (info.parameters.debug())unew.print_size("truncated-unew"); + const real_function_6d residue = result.function() - unew; + const double error = residue.norm2(); + if (info.parameters.kain()) { + real_function_6d kain_update = copy(solver.update(pair.function(), residue)); + // kain_update = CCOPS.apply_Q12t(kain_update, CCOPS.mo_ket()); + kain_update = Q12(kain_update); + kain_update.truncate().reduce_rank(); + kain_update.print_size("Kain-Update-Function"); + // pair.update_u(copy(kain_update)); + result.update_u(copy(kain_update)); + } else { + // pair.update_u(unew); + result.update_u(unew); + } + + timer_addup.info(true, pair.function().norm2()); + + double omega_new = 0.0; + double delta = 0.0; + // if (pair.type == GROUND_STATE) omega_new = CCOPS.compute_pair_correlation_energy(pair, singles); + // else if (pair.type == EXCITED_STATE) omega_new = CCOPS.compute_excited_pair_energy(pair, singles); + delta = omega - omega_new; + + const double current_norm = pair.function().norm2(); + + omega = omega_new; + if (world.rank() == 0) { + std::cout << std::fixed + << std::setw(50) << std::setfill('#') + << "\n" << "Iteration " << iter << " of pair " << pair.name() + << std::setprecision(4) << "||u|| = " << current_norm + << "\n" << std::setprecision(10) << "error = " << error << "\nomega = " << omega << "\ndelta = " + << delta << "\n" + << std::setw(50) << std::setfill('#') << "\n"; + } + + + // output("\n--Iteration " + stringify(iter) + " ended--"); + // save(pair.function(), pair.name()); + // timer_mp2.info(); + bool converged=(fabs(error) < info.parameters.dconv_6D()) and (fabs(delta) < info.parameters.econv_pairs()); + if (converged) { + if (world.rank()==0) print("Iteration converged after",iter,"iterations"); + break; + } else { + if (world.rank()==0) print("Iteration not converged after",iter,"iterations"); + } + } + return result; +} + + madness::real_function_6d CCPotentials::make_constant_part_cc2_gs(const CCPair& u, const CC_vecfunction& tau, const real_convolution_6d *Gscreen) const { @@ -1665,10 +1774,10 @@ CCPotentials::apply_Vreg(const CCFunction& ti, const CCFunction = | Vtau > /// LRCC2: (F - e_i - omega) |x_i> = | Vx > -/// @param[in] ti, first function in the ket, for MP2 it is the Orbital, for CC2 the relaxed Orbital t_i=\phi_i + \tau_i -/// @param[in] tj, second function in the ket ... -/// @param[in] gs_singles, the converged ground state singles: with (F - e_i ) |t_i t_j> = | Vtau > -/// @param[in] ex_singles, the converged excited state singles: with (F - e_i - omega) |x_i> = | Vx > +/// @param[in] ti first function in the ket, for MP2 it is the Orbital, for CC2 the relaxed Orbital t_i=\phi_i + \tau_i +/// @param[in] tj second function in the ket ... +/// @param[in] gs_singles the converged ground state singles: with (F - e_i ) |t_i t_j> = | Vtau > +/// @param[in] ex_singles the converged excited state singles: with (F - e_i - omega) |x_i> = | Vx > /// @param[in] info Info structure holding the applied singles potentials Vtau and Vx and reference orbitals /// @param[out] the regularization potential (unprojected), see equation above std::vector> diff --git a/src/madness/chem/CCPotentials.h b/src/madness/chem/CCPotentials.h index c847d253811..0f00ceb2a67 100644 --- a/src/madness/chem/CCPotentials.h +++ b/src/madness/chem/CCPotentials.h @@ -47,7 +47,7 @@ class CCPotentials { real_function_6d make_6D_pair(const CCPair& pair) const; /// Function to load a function from disc - /// @param[in] the function which will be loaded + /// @param[in] f the function which will be loaded /// @param[in] name of the file in which the function was stored /// @return true or false depending on if the data was found on disc template @@ -218,8 +218,8 @@ class CCPotentials { /// Compute pair correlation energies of MP2 or CC2 Ground State // Off diagonal pair energies are multiplied with 2.0 to acount for their permuted partners - /// @param[in] The Pair_function - /// @param[in] The Singles (for MP2 give empty function) for the energy contribution over disconnected doubles + /// @param[in] u the Pair_function + /// @param[in] singles the Singles (for MP2 give empty function) for the energy contribution over disconnected doubles /// @param[out] 2* - , where i and j are determined by u (see CC_Pair class) double compute_pair_correlation_energy(const CCPair& u, const CC_vecfunction& singles = CC_vecfunction(PARTICLE)) const; @@ -302,6 +302,13 @@ class CCPotentials { const real_function_3d& U2, const real_function_6d& mp2_coupling); + /// iterate a pair for MP2, CC2, LRCC2 on constant singles + static CCPair iterate_pair_macrotask(World& world, + const CCPair& pair, const CC_vecfunction& singles, + const real_function_6d& coupling, + const Info& info, const long maxiter); + + /// Function evaluates the consant part of the ground state for CC2 /// @param[out]The result is \f$ Q12(G(Q12((Vreg+V_{coupling})|titj>))) \f$ with \f$ |t_k> = |tau_k> + |k> \f$ /// @param[in] u, The Pair function diff --git a/src/madness/chem/CCStructures.cc b/src/madness/chem/CCStructures.cc index 982976ea5de..c24454ee56b 100644 --- a/src/madness/chem/CCStructures.cc +++ b/src/madness/chem/CCStructures.cc @@ -579,6 +579,28 @@ MacroTaskMp2UpdatePair::operator() (const std::vector &pair, return result; } +std::vector +MacroTaskIteratePair::operator()(const std::vector& pair, + const std::vector& local_coupling, + const std::vector>& gs_singles, + const std::vector>& ex_singles, + const std::vector< madness::Vector >& all_coords_vec, + const Info& info, + const std::size_t& maxiter) const { + World& world = info.mo_ket[0].world(); + resultT result = zero_functions_compressed(world, pair.size()); + + for (size_t i = 0; i < pair.size(); i++) { + //(i, j) -> j*(j+1) + i + // result[i] = CCPotentials::update_pair_mp2_macrotask(world, pair[i], info.parameters, all_coords_vec, info.mo_ket, + // info.mo_bra, info.U1, info.U2, local_coupling[i]); + result[i]= CCPotentials::iterate_pair_macrotask(world, pair[i], gs_singles, local_coupling[i], info, maxiter).function(); + + } + return result; + +} + template class CCConvolutionOperator; template class CCConvolutionOperator; template class CCConvolutionOperator; diff --git a/src/madness/chem/CCStructures.h b/src/madness/chem/CCStructures.h index 7bb675adbf7..9b9252f77af 100644 --- a/src/madness/chem/CCStructures.h +++ b/src/madness/chem/CCStructures.h @@ -19,6 +19,8 @@ #include #include +#include "lowrankfunction.h" + namespace madness { /// Calculation Types used by CC2 @@ -1170,6 +1172,7 @@ struct CCIntermediatePotentials { struct Info { std::vector> mo_ket; std::vector> mo_bra; + std::vector> molecular_coordinates; CCParameters parameters; std::vector orbital_energies; CCIntermediatePotentials intermediate_potentials; @@ -1199,6 +1202,7 @@ struct Info { records+=cloud.store(world,orbital_energies); records+=cloud.store(world,intermediate_potentials); records+=cloud.store(world,R_square); + records+=cloud.store(world,molecular_coordinates); records+=cloud.store(world,U2); records+=cloud.store(world,U1); return records; @@ -1216,6 +1220,7 @@ struct Info { orbital_energies=cloud.forward_load>(world,recordlist); intermediate_potentials=cloud.forward_load(world,recordlist); R_square=cloud.forward_load>(world,recordlist); + molecular_coordinates=cloud.forward_load>>(world,recordlist); U2=cloud.forward_load>(world,recordlist); U1=cloud.forward_load>>(world,recordlist); } @@ -1355,6 +1360,64 @@ class MacroTaskMp2UpdatePair : public MacroTaskOperationBase { const std::vector< madness::Vector >& all_coords_vec, const Info& info) const; }; + +class MacroTaskIteratePair : public MacroTaskOperationBase { + + class IteratePairPartitioner : public MacroTaskPartitioner { + public : + IteratePairPartitioner() = default; + + partitionT do_partitioning(const std::size_t& vsize1, const std::size_t& vsize2, + const std::string policy) const override { + partitionT p; + for (size_t i = 0; i < vsize1; i++) { + Batch batch(Batch_1D(i,i+1), Batch_1D(i,i+1)); + p.push_back(std::make_pair(batch,1.0)); + } + return p; + } + }; +public: + MacroTaskIteratePair() {partitioner.reset(new IteratePairPartitioner());} + + typedef std::tuple< + const std::vector&, + const std::vector&, + const std::vector>&, + const std::vector>&, + const std::vector< madness::Vector >&, + const Info&, + const std::size_t& + > argtupleT; + + using resultT = std::vector; + + resultT allocator(World& world, const argtupleT& argtuple) const { + std::size_t n = std::get<0>(argtuple).size(); + resultT result = zero_functions_compressed(world, n); + return result; + } + + /// iterate a given pair of the MP2, CC2 or LRCC2 calculation + + /// will *NOT* compute the local coupling, + /// will apply the Fock operators (J-K+V)|pair> and use + /// the (excited) singles vectors to update the pair + /// @param[in] pair: the pair which will be updated + /// @param[in] gs_singles: the ground state singles, may be dummy for MP2 + /// @param[in] ex_singles: the excited state singles, may be dummy for MP2, CC2 + /// @param[in] all_coords_vec: the coordinates of the atoms + /// @param[in] info: the info structure + /// @param[in] maxiter: the maximal number of iterations + resultT operator() (const std::vector& pair, + const std::vector& local_coupling, + const std::vector>& gs_singles, + const std::vector>& ex_singles, + const std::vector< madness::Vector >& all_coords_vec, + const Info& info, + const std::size_t& maxiter) const; +}; + }//namespace madness #endif /* CCSTRUCTURES_H_ */ From 31d53c93df9143e87abe9e0059526a4b2d58061c Mon Sep 17 00:00:00 2001 From: fbischoff Date: Sun, 23 Jun 2024 18:59:39 +0200 Subject: [PATCH 11/54] iterate CC2 pairs using generalized macrotask --- src/madness/chem/CC2.cc | 50 ++++++++++---------------------- src/madness/chem/CCPotentials.cc | 36 +++++++++++++---------- src/madness/chem/CCPotentials.h | 20 +++++++++++-- src/madness/chem/CCStructures.cc | 1 - src/madness/chem/CCStructures.h | 7 +++-- 5 files changed, 60 insertions(+), 54 deletions(-) diff --git a/src/madness/chem/CC2.cc b/src/madness/chem/CC2.cc index 60ee5137e5a..4365f84d84d 100644 --- a/src/madness/chem/CC2.cc +++ b/src/madness/chem/CC2.cc @@ -32,6 +32,8 @@ CC2::solve() { CCOPS.reset_nemo(nemo); CCOPS.get_potentials.parameters=parameters; CCOPS.update_intermediates(CCOPS.mo_ket()); + // info keep information on the MOs and the molecular coordinates + CCOPS.info=CCOPS.update_info(parameters,nemo); // doubles for ground state Pairs mp2pairs, cc2pairs; @@ -253,16 +255,6 @@ CC2::solve() { std::vector > > timings; auto vccs=solve_ccs(); - Info info; - info.mo_bra=CCOPS.mo_bra().get_vecfunction(); - info.mo_ket=CCOPS.mo_ket().get_vecfunction(); - info.molecular_coordinates=nemo->get_calc()->molecule.get_all_coords_vec(); - info.parameters=parameters; - info.R_square=nemo->R_square; - info.U1=nemo->ncf->U1vec(); - info.U2=nemo->ncf->U2(); - info.intermediate_potentials=CCOPS.get_potentials; - std::vector > > results_ex; for (size_t xxx = 0; xxx < vccs.size(); xxx++) { @@ -283,11 +275,11 @@ CC2::solve() { if (found_lrcc2d) iterate_lrcc2_singles(cc2singles, cc2pairs, lrcc2_s, lrcc2_d); else iterate_ccs_singles(lrcc2_s); const double omega_cis = lrcc2_s.omega; - info.intermediate_potentials=CCOPS.get_potentials; // update applied singles potentials + CCOPS.info.intermediate_potentials=CCOPS.get_potentials; // update applied singles potentials for (size_t iter = 0; iter < parameters.iter_max(); iter++) { output.section("Macroiteration " + std::to_string(int(iter)) + " of LRCC2"); - bool dconv = iterate_lrcc2_pairs(cc2singles, cc2pairs, lrcc2_s, lrcc2_d, info); + bool dconv = iterate_lrcc2_pairs(cc2singles, cc2pairs, lrcc2_s, lrcc2_d, CCOPS.info); bool sconv = iterate_lrcc2_singles(cc2singles, cc2pairs, lrcc2_s, lrcc2_d); if (dconv and sconv) break; } @@ -421,15 +413,6 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { // make vector holding CCPairs for partitioner of MacroTask std::vector pair_vec=Pairs::pairs2vector(doubles,triangular_map); - Info info; - info.mo_bra=CCOPS.mo_bra().get_vecfunction(); - info.mo_ket=CCOPS.mo_ket().get_vecfunction(); - info.molecular_coordinates=nemo->get_calc()->molecule.get_all_coords_vec(); - info.parameters=parameters; - info.R_square=nemo->R_square; - info.U1=nemo->ncf->U1vec(); - info.U2=nemo->ncf->U2(); - // read constant part from file if (parameters.no_compute_mp2_constantpart()) { if (world.rank()==0) print("Skipping MP2 constant part calculation"); @@ -447,7 +430,7 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { MacroTaskConstantPart t; MacroTask task(world, t); std::vector> gs_singles, ex_singles; // dummy vectors - std::vector result_vec = task(pair_vec, gs_singles, ex_singles, info) ; + std::vector result_vec = task(pair_vec, gs_singles, ex_singles, CCOPS.info) ; if (world.rank()==0) { std::cout << std::fixed << std::setprecision(1) << "\nFinished constant part at time " << wall_time() << std::endl; @@ -464,7 +447,7 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { save(pair_vec[i].constant_part, pair_vec[i].name() + "_const"); // save(pair_vec[i].function(), pair_vec[i].name()); if (pair_vec[i].type == GROUND_STATE) { - double energy = CCOPS.compute_pair_correlation_energy(pair_vec[i]); + double energy = CCOPS.compute_pair_correlation_energy(world,CCOPS.info,pair_vec[i]); if (world.rank()==0) printf("pair energy for pair %zu %zu: %12.8f\n", pair_vec[i].i, pair_vec[i].j, energy); total_energy += energy; } @@ -497,9 +480,9 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { MacroTaskIteratePair t; MacroTask task1(world, t); std::vector dummy_singles; // dummy vectors - const std::size_t maxiter=1; + const std::size_t maxiter=3; auto unew = task1(pair_vec, coupling_vec, dummy_singles, dummy_singles, - info.molecular_coordinates, info, maxiter); + CCOPS.info, maxiter); std::vector u; for (auto p : pair_vec) u.push_back(p.function()); @@ -539,13 +522,9 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { if (world.rank()==0) std::cout << "residual " << pair_vec[i].i << " " << pair_vec[i].j << " " << errors[i] << std::endl; save(pair_vec[i].function(), pair_vec[i].name()); - double energy = 0.0; - if (pair_vec[i].type == GROUND_STATE) { - double energy = CCOPS.compute_pair_correlation_energy(pair_vec[i]); - if (world.rank()==0) printf("pair energy for pair %zu %zu: %12.8f\n", pair_vec[i].i, pair_vec[i].j, energy); - total_energy += energy; - } + double energy = CCOPS.compute_pair_correlation_energy(world,CCOPS.info,pair_vec[i]); total_energy += energy; + if (world.rank()==0) printf("pair energy for pair %zu %zu: %12.8f\n", pair_vec[i].i, pair_vec[i].j, energy); } if (world.rank()==0) { @@ -566,7 +545,7 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { if (world.rank() == 0) std::cout << "\nPairs converged!\n"; if (world.rank() == 0) std::cout << "\nMP2 Pair Correlation Energies:\n"; for (auto& pair : pair_vec) { - const double pair_energy = CCOPS.compute_pair_correlation_energy(pair); + const double pair_energy = CCOPS.compute_pair_correlation_energy(world,CCOPS.info,pair); if (world.rank() == 0) { std::cout << std::fixed << std::setprecision(10) << "omega_" << pair.i << pair.j << "=" << pair_energy << "\n"; @@ -850,7 +829,10 @@ bool CC2::iterate_pair(CCPair& pair, const CC_vecfunction& singles) const { bool converged = false; double omega = 0.0; - if (pair.type == GROUND_STATE) omega = CCOPS.compute_pair_correlation_energy(pair, singles); + Info info; + info.mo_bra=CCOPS.mo_bra_.get_vecfunction(); + info.parameters=parameters; + if (pair.type == GROUND_STATE) omega = CCOPS.compute_pair_correlation_energy(world, info,pair, singles); if (pair.type == EXCITED_STATE) omega = CCOPS.compute_excited_pair_energy(pair, singles); if (world.rank() == 0) @@ -897,7 +879,7 @@ bool CC2::iterate_pair(CCPair& pair, const CC_vecfunction& singles) const { double omega_new = 0.0; double delta = 0.0; - if (pair.type == GROUND_STATE) omega_new = CCOPS.compute_pair_correlation_energy(pair, singles); + if (pair.type == GROUND_STATE) omega_new = CCOPS.compute_pair_correlation_energy(world, info, pair, singles); else if (pair.type == EXCITED_STATE) omega_new = CCOPS.compute_excited_pair_energy(pair, singles); delta = omega - omega_new; diff --git a/src/madness/chem/CCPotentials.cc b/src/madness/chem/CCPotentials.cc index 95bbe97d64d..d1c67c1c5f6 100644 --- a/src/madness/chem/CCPotentials.cc +++ b/src/madness/chem/CCPotentials.cc @@ -310,26 +310,31 @@ CCPotentials::make_pair_ex(const real_function_6d& u, const CC_vecfunction& tau, } double -CCPotentials::compute_pair_correlation_energy(const CCPair& u, const CC_vecfunction& singles) const { +CCPotentials::compute_pair_correlation_energy(World& world, const Info& info, + const CCPair& u, const CC_vecfunction& singles) { + CCTimer timer(world, "Compute Correlation Energy"); MADNESS_ASSERT(u.type == GROUND_STATE); if (singles.functions.empty()) MADNESS_ASSERT(u.ctype == CT_MP2); - const bool print_details=(world.rank()==0 and parameters.debug()); - if (parameters.debug()) output("Compute pair-correlation energy of pair " + u.name()); + const bool print_details=(world.rank()==0 and info.parameters.debug()); double result = 0.0; - const CCFunction& mobi = mo_bra_(u.i); - const CCFunction& mobj = mo_bra_(u.j); + const CCFunction& mobi = info.mo_bra[u.i]; + const CCFunction& mobj = info.mo_bra[u.j]; const bool symmetric = (u.i == u.j); + auto g12=CCConvolutionOperatorPtr(world,OpType::OT_G12,info.parameters); + CCPairFunction ij(mobi.f(),mobj.f()); + CCPairFunction ji(mobj.f(),mobi.f()); for (size_t mm = 0; mm < u.functions.size(); mm++) { double tmp = 0.0; - const double part1 = make_xy_op_u(mobi, mobj, *g12, u.functions[mm]); + // const double part1 = make_xy_op_u(mobi, mobj, *g12, u.functions[mm]); + const double part1 = inner(ij,g12*u.functions[mm]); if (symmetric) tmp = part1; - else //if(world.rank()==0) std::cout << std::fixed << std::setprecision(10) << part1 << "\n"; - { - const double part2 = make_xy_op_u(mobj, mobi, *g12, u.functions[mm]); + else { + // const double part2 = make_xy_op_u(mobj, mobi, *g12, u.functions[mm]); + const double part2 = inner(ji,g12*u.functions[mm]); tmp = 2.0 * (2.0 * part1 - part2); // non symmetric pairs -> offdiagonal -> count twice } result += tmp; @@ -349,7 +354,7 @@ CCPotentials::compute_pair_correlation_energy(const CCPair& u, const CC_vecfunct } // if (world.rank() == 0) std::cout << "------------\n" << std::fixed << std::setprecision(10) << result << "\n\n"; - timer.info(parameters.debug()); + timer.info(info.parameters.debug()); return result; } @@ -362,7 +367,7 @@ CCPotentials::compute_cc2_correlation_energy(const CC_vecfunction& singles, cons for (const auto& tmp : doubles.allpairs) { const size_t i = tmp.second.i; const size_t j = tmp.second.j; - const double omega = compute_pair_correlation_energy(tmp.second, singles); + const double omega = compute_pair_correlation_energy(world, info, tmp.second, singles); result += omega; if (world.rank() == 0) std::cout << std::fixed << "omega " << i << j << " =" << std::setprecision(10) << omega << "\n"; @@ -1044,7 +1049,8 @@ CCPair CCPotentials::iterate_pair_macrotask(World& world, const real_function_6d residue = result.function() - unew; const double error = residue.norm2(); if (info.parameters.kain()) { - real_function_6d kain_update = copy(solver.update(pair.function(), residue)); + + real_function_6d kain_update = copy(solver.update(result.function(), residue)); // kain_update = CCOPS.apply_Q12t(kain_update, CCOPS.mo_ket()); kain_update = Q12(kain_update); kain_update.truncate().reduce_rank(); @@ -1056,15 +1062,15 @@ CCPair CCPotentials::iterate_pair_macrotask(World& world, result.update_u(unew); } - timer_addup.info(true, pair.function().norm2()); + timer_addup.info(true, result.function().norm2()); double omega_new = 0.0; double delta = 0.0; - // if (pair.type == GROUND_STATE) omega_new = CCOPS.compute_pair_correlation_energy(pair, singles); + if (pair.ctype == CT_MP2) omega_new = CCPotentials::compute_pair_correlation_energy(world, info, result); // else if (pair.type == EXCITED_STATE) omega_new = CCOPS.compute_excited_pair_energy(pair, singles); delta = omega - omega_new; - const double current_norm = pair.function().norm2(); + const double current_norm = result.function().norm2(); omega = omega_new; if (world.rank() == 0) { diff --git a/src/madness/chem/CCPotentials.h b/src/madness/chem/CCPotentials.h index 0f00ceb2a67..723ece37a05 100644 --- a/src/madness/chem/CCPotentials.h +++ b/src/madness/chem/CCPotentials.h @@ -29,6 +29,19 @@ class CCPotentials { orbital_energies_=init_orbital_energies(*nemo); }; + Info update_info(const CCParameters& parameters, const std::shared_ptr nemo) const { + Info info; + info.mo_bra=mo_bra().get_vecfunction(); + info.mo_ket=mo_ket().get_vecfunction(); + info.molecular_coordinates=nemo->get_calc()->molecule.get_all_coords_vec(); + info.parameters=parameters; + info.R_square=nemo->R_square; + info.U1=nemo->ncf->U1vec(); + info.U2=nemo->ncf->U2(); + info.intermediate_potentials=get_potentials; + return info; + } + virtual ~CCPotentials() {}; @@ -221,8 +234,11 @@ class CCPotentials { /// @param[in] u the Pair_function /// @param[in] singles the Singles (for MP2 give empty function) for the energy contribution over disconnected doubles /// @param[out] 2* - , where i and j are determined by u (see CC_Pair class) - double - compute_pair_correlation_energy(const CCPair& u, const CC_vecfunction& singles = CC_vecfunction(PARTICLE)) const; + static double + compute_pair_correlation_energy(World& world, + const Info& info, + const CCPair& u, + const CC_vecfunction& singles = CC_vecfunction(PARTICLE)); /// Compute CC2 correlation energy /// @param[in] The Pair_function diff --git a/src/madness/chem/CCStructures.cc b/src/madness/chem/CCStructures.cc index c24454ee56b..1203038a449 100644 --- a/src/madness/chem/CCStructures.cc +++ b/src/madness/chem/CCStructures.cc @@ -584,7 +584,6 @@ MacroTaskIteratePair::operator()(const std::vector& pair, const std::vector& local_coupling, const std::vector>& gs_singles, const std::vector>& ex_singles, - const std::vector< madness::Vector >& all_coords_vec, const Info& info, const std::size_t& maxiter) const { World& world = info.mo_ket[0].world(); diff --git a/src/madness/chem/CCStructures.h b/src/madness/chem/CCStructures.h index 9b9252f77af..e3d763a7055 100644 --- a/src/madness/chem/CCStructures.h +++ b/src/madness/chem/CCStructures.h @@ -748,6 +748,11 @@ class CCConvolutionOperator { CCConvolutionOperator(const CCConvolutionOperator& other) = default; + static inline + std::shared_ptr CCConvolutionOperatorPtr(World& world, const OpType type, Parameters param) { + return std::shared_ptr(new CCConvolutionOperator(world, type, param)); + } + protected: friend CCConvolutionOperator combine(const CCConvolutionOperator& a, const CCConvolutionOperator& b) { @@ -1385,7 +1390,6 @@ class MacroTaskIteratePair : public MacroTaskOperationBase { const std::vector&, const std::vector>&, const std::vector>&, - const std::vector< madness::Vector >&, const Info&, const std::size_t& > argtupleT; @@ -1413,7 +1417,6 @@ class MacroTaskIteratePair : public MacroTaskOperationBase { const std::vector& local_coupling, const std::vector>& gs_singles, const std::vector>& ex_singles, - const std::vector< madness::Vector >& all_coords_vec, const Info& info, const std::size_t& maxiter) const; }; From 7335490fbf7263a5b41a6cc1918de2f4f61ca08c Mon Sep 17 00:00:00 2001 From: fbischoff Date: Sun, 7 Jul 2024 11:05:59 +0200 Subject: [PATCH 12/54] iterate CC2 pairs using generalized macrotask --- src/madness/chem/CC2.cc | 106 ++++++++++++++++--------------- src/madness/chem/CC2.h | 14 ++++ src/madness/chem/CCPotentials.cc | 12 ++-- src/madness/chem/CCStructures.cc | 8 +-- src/madness/chem/CCStructures.h | 31 ++++++--- src/madness/mra/macrotaskq.h | 2 +- 6 files changed, 102 insertions(+), 71 deletions(-) diff --git a/src/madness/chem/CC2.cc b/src/madness/chem/CC2.cc index 4365f84d84d..90130f5a455 100644 --- a/src/madness/chem/CC2.cc +++ b/src/madness/chem/CC2.cc @@ -419,8 +419,6 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { for (auto& c : pair_vec) { MADNESS_CHECK_THROW(c.constant_part.is_initialized(), "could not find constant part"); // constant part is zero-order guess for pair.function - print_header1("clearing function"); - c.function().clear(); if (not c.function().is_initialized()) c.update_u(c.constant_part); } @@ -440,7 +438,7 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { // transform vector back to Pairs structure for (size_t i = 0; i < pair_vec.size(); i++) { pair_vec[i].constant_part = result_vec[i]; - pair_vec[i].functions[0] = CCPairFunction(result_vec[i]); + // pair_vec[i].functions[0] = CCPairFunction(result_vec[i]); pair_vec[i].constant_part.truncate().reduce_rank(); pair_vec[i].constant_part.print_size("constant_part"); pair_vec[i].function().truncate().reduce_rank(); @@ -477,25 +475,19 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { if (world.rank()==0) print("Start updating pairs in iteration "); + MacroTaskIteratePair t; MacroTask task1(world, t); - std::vector dummy_singles; // dummy vectors - const std::size_t maxiter=3; - auto unew = task1(pair_vec, coupling_vec, dummy_singles, dummy_singles, - CCOPS.info, maxiter); + CC_vecfunction dummy_singles1(PARTICLE); + const std::size_t maxiter=1; + auto unew = task1(pair_vec, coupling_vec, dummy_singles1, dummy_singles1, CCOPS.info, maxiter); std::vector u; for (auto p : pair_vec) u.push_back(p.function()); auto residual=u-unew; // some statistics - auto errors=norm2s(world,residual); - double rnorm=0.0, maxrnorm=0.0; - for (double& e : errors) { - maxrnorm=std::max(maxrnorm,e); - rnorm+=e*e; - } - rnorm=sqrt(rnorm/errors.size()); + auto [rmsrnorm, maxrnorm]=residual_stats(residual); // update the pair functions if (parameters.kain()) { @@ -519,8 +511,6 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { double old_energy = total_energy; total_energy = 0.0; for (size_t i = 0; i < pair_vec.size(); i++) { - if (world.rank()==0) std::cout << "residual " << pair_vec[i].i << " " << pair_vec[i].j << " " << errors[i] << std::endl; - save(pair_vec[i].function(), pair_vec[i].name()); double energy = CCOPS.compute_pair_correlation_energy(world,CCOPS.info,pair_vec[i]); total_energy += energy; @@ -530,10 +520,10 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { if (world.rank()==0) { std::cout << "convergence: rms/max residual, energy change " << std::scientific << std::setprecision(1) - << rnorm << " " << maxrnorm << " " + << rmsrnorm << " " << maxrnorm << " " << std::abs(old_energy - total_energy) << std::endl; // << std::abs(old_norm - total_norm); - printf("finished iteration %2d at time %8.1fs with energy %12.8f\n", + printf("finished MP2 iteration %2d at time %8.1fs with energy %12.8f\n", int(iter), wall_time(), total_energy); } @@ -543,15 +533,6 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { //print pair energies if converged if (converged) { if (world.rank() == 0) std::cout << "\nPairs converged!\n"; - if (world.rank() == 0) std::cout << "\nMP2 Pair Correlation Energies:\n"; - for (auto& pair : pair_vec) { - const double pair_energy = CCOPS.compute_pair_correlation_energy(world,CCOPS.info,pair); - if (world.rank() == 0) { - std::cout << std::fixed << std::setprecision(10) << "omega_" - << pair.i << pair.j << "=" << pair_energy << "\n"; - } - } - if (world.rank() == 0) std::cout << "sum =" << total_energy << "\n"; break; } } @@ -724,14 +705,8 @@ CC2::solve_cc2(CC_vecfunction& singles, Pairs& doubles) { CC_vecfunction ex_singles_dummy; vector_real_function_3d empty(CCOPS.mo_ket().size()-parameters.freeze()); Info info; + info=CCOPS.update_info(parameters,nemo); info.intermediate_potentials=CCIntermediatePotentials(parameters); - info.mo_bra=CCOPS.mo_bra().get_vecfunction(); - info.mo_ket=CCOPS.mo_ket().get_vecfunction(); - info.molecular_coordinates=nemo->get_calc()->molecule.get_all_coords_vec(); - info.parameters=parameters; - info.R_square=nemo->R_square; - info.U1=nemo->ncf->U1vec(); - info.U2=nemo->ncf->U2(); info.intermediate_potentials.insert(empty,singles,POT_singles_); // initialize with empty vector if (not parameters.no_compute_cc2()) { @@ -748,35 +723,57 @@ CC2::solve_cc2(CC_vecfunction& singles, Pairs& doubles) { CCTimer time_miter(world, "Macroiteration " + std::to_string(int(iter)) + " of CC2"); output.section("Macroiteration " + std::to_string(int(iter)) + " of CC2"); - // iterate doubles + if (world.rank()==0) print("computing the constant part via macrotasks -- output redirected"); + timer timer1(world); + std::vector pair_vec=Pairs::pairs2vector(doubles,triangular_map); MacroTaskConstantPart t; MacroTask task(world, t); - std::vector result_vec = task(pair_vec, singles.get_vecfunction(), + std::vector constant_part_vec = task(pair_vec, singles.get_vecfunction(), ex_singles_dummy.get_vecfunction(), info) ; - auto constant_part=Pairs::vector2pairs(result_vec,triangular_map); - - - bool doubles_converged = true; - for (auto& pairs: doubles.allpairs) { - CCPair& pair = pairs.second; - pair.constant_part= constant_part(pair.i, pair.j); - // update_constant_part_cc2_gs(singles, pair); - // pair.constant_part=CCPotentials::make_constant_part_macrotask(world, pair, - // singles, ex_singles_dummy, info); - bool pair_converged = iterate_pair(pair, singles); - save(pair.function(), pair.name()); - if (not pair_converged) doubles_converged = false; + for (int i=0; i coupling=compute_local_coupling(pair_vec); + auto coupling_vec=Pairs::pairs2vector(coupling,triangular_map); + timer1.tag("computing local coupling"); + + if (world.rank()==0) print("update the pair functions via macrotasks -- output redirected"); + MacroTaskIteratePair t1; + MacroTask task1(world, t1); + CC_vecfunction dummy_ex_singles; + std::vector vdummy_3d; // dummy vectors + const std::size_t maxiter=3; + auto unew = task1(pair_vec, coupling_vec, singles, dummy_ex_singles, + CCOPS.info, maxiter); + + std::vector u_old; + for (auto p : pair_vec) u_old.push_back(p.function()); + auto residual=u_old-unew; + timer1.tag("computing pair function update via macrotasks"); + + for (int i=0; i::vector2pairs(pair_vec,triangular_map); + + auto [rmsrnorm,maxrnorm]=residual_stats(residual); + bool doubles_converged=rmsrnorm& doubles) { if (world.rank() == 0) std::cout << std::fixed << std::setprecision(10) << "Difference = " << delta << "\n"; + std::cout << "convergence: rms/max residual, energy change " + << std::scientific << std::setprecision(1) + << rmsrnorm << " " << maxrnorm << " " + << std::abs(delta) << std::endl; + // << std::abs(old_norm - total_norm); + printf("finished CC2 iteration %2d at time %8.1fs with energy %12.8f\n", + int(iter), wall_time(), omega); if (doubles_converged and singles_converged and omega_converged) break; time_miter.info(); diff --git a/src/madness/chem/CC2.h b/src/madness/chem/CC2.h index 145903406a9..12b8609f822 100644 --- a/src/madness/chem/CC2.h +++ b/src/madness/chem/CC2.h @@ -116,6 +116,20 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { output("Plotted " + msg); } + /// return RMS norm and max norm of residuals + static std::pair residual_stats(const std::vector& residual) { + if (residual.size()==0) return std::make_pair(0.0,0.0); + World& world=residual.front().world(); + auto errors=norm2s(world,residual); + double rnorm=0.0, maxrnorm=0.0; + for (double& e : errors) { + maxrnorm=std::max(maxrnorm,e); + rnorm+=e*e; + } + rnorm=sqrt(rnorm/errors.size()); + return std::make_pair(rnorm,maxrnorm); + } + /// The World World& world; /// Structure holds all the parameters used in the CC2 calculation diff --git a/src/madness/chem/CCPotentials.cc b/src/madness/chem/CCPotentials.cc index d1c67c1c5f6..289f4d22357 100644 --- a/src/madness/chem/CCPotentials.cc +++ b/src/madness/chem/CCPotentials.cc @@ -962,6 +962,7 @@ CCPotentials::update_pair_mp2_macrotask(World& world, const CCPair& pair, const CCTimer timer_G(world, "Apply Greens Operator on MP2-Potential of pair " + pair.name()); const real_function_6d GVmp2 = G(mp2_potential); + if (parameters.debug()) GVmp2.print_size("GVmp2"); timer_G.info(true, GVmp2.norm2()); //CCTimer timer_addup(world, "Add constant parts and update pair " + pair.name()); @@ -972,7 +973,7 @@ CCPotentials::update_pair_mp2_macrotask(World& world, const CCPair& pair, const Q.set_spaces(mo_bra, mo_ket, mo_bra, mo_ket); unew = Q(unew); - if (parameters.debug())unew.print_size("truncated-unew"); + if (parameters.debug())unew.print_size("Q12(unew)"); timer_mp2.info(); real_function_6d residue = (pair.function() - unew); @@ -1037,6 +1038,7 @@ CCPair CCPotentials::iterate_pair_macrotask(World& world, CCTimer timer_G(world, "Apply Greens Operator on MP2-Potential of pair " + pair.name()); const real_function_6d GVmp2 = G(mp2_potential); + if (info.parameters.debug()) GVmp2.print_size("GVmp2"); timer_G.info(true, GVmp2.norm2()); CCTimer timer_addup(world, "Add constant parts and update pair " + pair.name()); @@ -1045,7 +1047,7 @@ CCPair CCPotentials::iterate_pair_macrotask(World& world, // unew = CCOPS.apply_Q12t(unew, CCOPS.mo_ket()); // unew.print_size("Q12unew"); //unew.truncate().reduce_rank(); // already done in Q12 application at the end - if (info.parameters.debug())unew.print_size("truncated-unew"); + if (info.parameters.debug()) unew.print_size("Q12(unew)"); const real_function_6d residue = result.function() - unew; const double error = residue.norm2(); if (info.parameters.kain()) { @@ -1053,8 +1055,9 @@ CCPair CCPotentials::iterate_pair_macrotask(World& world, real_function_6d kain_update = copy(solver.update(result.function(), residue)); // kain_update = CCOPS.apply_Q12t(kain_update, CCOPS.mo_ket()); kain_update = Q12(kain_update); + kain_update.print_size("Kain-Update-Function not truncated"); kain_update.truncate().reduce_rank(); - kain_update.print_size("Kain-Update-Function"); + kain_update.print_size("Kain-Update-Function truncated"); // pair.update_u(copy(kain_update)); result.update_u(copy(kain_update)); } else { @@ -1199,7 +1202,8 @@ CCPotentials::make_constant_part_cc2_Qt_gs(const CCPair& u, const CC_vecfunction real_convolution_6d G = BSHOperator<6>(world, sqrt(-2.0 * get_epsilon(ti.i, tj.i)), parameters.lo(), parameters.thresh_bsh_6D()); G.destructive() = true; - G.particle_=-1; + G.particle_=1; + // G.particle_=-1; // calculate [F,Qt] commutator which is [F1,Q1t]Q2t + Q1t [F2,Q2t] // and [F1,Q1t] = - [F1,O1t] = - (F-e_k) |tk> diff --git a/src/madness/chem/CCStructures.cc b/src/madness/chem/CCStructures.cc index 1203038a449..795921e23fb 100644 --- a/src/madness/chem/CCStructures.cc +++ b/src/madness/chem/CCStructures.cc @@ -582,19 +582,15 @@ MacroTaskMp2UpdatePair::operator() (const std::vector &pair, std::vector MacroTaskIteratePair::operator()(const std::vector& pair, const std::vector& local_coupling, - const std::vector>& gs_singles, - const std::vector>& ex_singles, + const CC_vecfunction& gs_singles, + const CC_vecfunction& ex_singles, const Info& info, const std::size_t& maxiter) const { World& world = info.mo_ket[0].world(); resultT result = zero_functions_compressed(world, pair.size()); for (size_t i = 0; i < pair.size(); i++) { - //(i, j) -> j*(j+1) + i - // result[i] = CCPotentials::update_pair_mp2_macrotask(world, pair[i], info.parameters, all_coords_vec, info.mo_ket, - // info.mo_bra, info.U1, info.U2, local_coupling[i]); result[i]= CCPotentials::iterate_pair_macrotask(world, pair[i], gs_singles, local_coupling[i], info, maxiter).function(); - } return result; diff --git a/src/madness/chem/CCStructures.h b/src/madness/chem/CCStructures.h index e3d763a7055..4f4035b0a15 100644 --- a/src/madness/chem/CCStructures.h +++ b/src/madness/chem/CCStructures.h @@ -611,6 +611,13 @@ struct CC_vecfunction : public archive::ParallelSerializableObject { } } + hashT hash() const { + hashT hashval = std::hash{}(type); + for (const auto& f : functions) hash_combine(hashval, hash_value(f.second.f().get_impl()->id())); + + return hashval; + } + typedef std::map> CC_functionmap; CC_functionmap functions; @@ -1340,7 +1347,10 @@ class MacroTaskMp2UpdatePair : public MacroTaskOperationBase { } }; public: - MacroTaskMp2UpdatePair() {partitioner.reset(new UpdatePairPartitioner());} + MacroTaskMp2UpdatePair() { + partitioner.reset(new UpdatePairPartitioner()); + name="MP2UpdatePair"; + } // typedef std::tuple&, const std::vector&, const CCParameters&, // const std::vector< madness::Vector >&, @@ -1376,20 +1386,23 @@ class MacroTaskIteratePair : public MacroTaskOperationBase { const std::string policy) const override { partitionT p; for (size_t i = 0; i < vsize1; i++) { - Batch batch(Batch_1D(i,i+1), Batch_1D(i,i+1)); + Batch batch(Batch_1D(i, i+1), Batch_1D(i, i+1), Batch_1D(i,i+1)); p.push_back(std::make_pair(batch,1.0)); } return p; } }; public: - MacroTaskIteratePair() {partitioner.reset(new IteratePairPartitioner());} + MacroTaskIteratePair() { + partitioner.reset(new IteratePairPartitioner()); + name="IteratePair"; + } typedef std::tuple< - const std::vector&, - const std::vector&, - const std::vector>&, - const std::vector>&, + const std::vector&, // pair + const std::vector&, // local coupling + const CC_vecfunction&, // gs singles + const CC_vecfunction&, // ex singles const Info&, const std::size_t& > argtupleT; @@ -1415,8 +1428,8 @@ class MacroTaskIteratePair : public MacroTaskOperationBase { /// @param[in] maxiter: the maximal number of iterations resultT operator() (const std::vector& pair, const std::vector& local_coupling, - const std::vector>& gs_singles, - const std::vector>& ex_singles, + const CC_vecfunction& gs_singles, + const CC_vecfunction& ex_singles, const Info& info, const std::size_t& maxiter) const; }; diff --git a/src/madness/mra/macrotaskq.h b/src/madness/mra/macrotaskq.h index b30ec8d2586..6253cb9a653 100644 --- a/src/madness/mra/macrotaskq.h +++ b/src/madness/mra/macrotaskq.h @@ -716,7 +716,7 @@ class MacroTask { class MacroTaskOperationBase { public: Batch batch; - std::string name; + std::string name="unknown_task"; std::shared_ptr partitioner=0; MacroTaskOperationBase() : batch(Batch(_, _, _)), partitioner(new MacroTaskPartitioner) {} }; From d45e4a1d4d1bea9110122c7ef69f362c8ac7fcbc Mon Sep 17 00:00:00 2001 From: fbischoff Date: Mon, 8 Jul 2024 12:08:01 +0200 Subject: [PATCH 13/54] fixed compilation error --- src/madness/chem/projector.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/madness/chem/projector.h b/src/madness/chem/projector.h index 9c081a54e97..00d4ef957c4 100644 --- a/src/madness/chem/projector.h +++ b/src/madness/chem/projector.h @@ -429,6 +429,8 @@ namespace madness { OuterProjector() = default; OuterProjector(const projT& p0, const projQ& p1) : projector0(p0), projector1(p1) { + static_assert(std::is_base_of::value, "projT must be a ProjectorBase"); + static_assert(std::is_base_of::value, "projQ must be a ProjectorBase"); projector0.set_particle(0); projector1.set_particle(1); } @@ -443,8 +445,14 @@ namespace madness { } }; +// template +// OuterProjector outer(const projT& p0 , const projQ& p1) { +// return OuterProjector(p0, p1); +// } + template - OuterProjector outer(const projT& p0 , const projQ& p1) { + typename std::enable_if::value, OuterProjector>::type + outer(const projT& p0 , const projQ& p1) { return OuterProjector(p0, p1); } } From 9bed5ac428facacd36ce607a67ef0ddbb312e687 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Tue, 9 Jul 2024 23:22:27 +0200 Subject: [PATCH 14/54] checkpoint --- src/madness/chem/CC2.cc | 77 +++++-- src/madness/chem/CC2.h | 51 ++-- src/madness/chem/CCPotentials.cc | 320 ++++++++++++++------------ src/madness/chem/CCPotentials.h | 94 ++++---- src/madness/chem/correlationfactor.cc | 1 + src/madness/chem/correlationfactor.h | 63 ++++- 6 files changed, 379 insertions(+), 227 deletions(-) diff --git a/src/madness/chem/CC2.cc b/src/madness/chem/CC2.cc index 90130f5a455..0cf7bb1390a 100644 --- a/src/madness/chem/CC2.cc +++ b/src/madness/chem/CC2.cc @@ -135,7 +135,7 @@ CC2::solve() { CCTimer time_ex(world, "CIS(D) for Excitation " + std::to_string(int(excitation))); // check the convergence of the cis function (also needed to store the ccs potential) and to recalulate the excitation energy - iterate_ccs_singles(ccs); + iterate_ccs_singles(ccs, CCOPS.info); Pairs cispd; initialize_pairs(cispd, EXCITED_STATE, CT_CISPD, CC_vecfunction(PARTICLE), ccs, excitation); @@ -183,7 +183,7 @@ CC2::solve() { // check the convergence of the cis function (also needed to store the ccs potential) and to recalulate the excitation energy CC_vecfunction dummy = ccs.copy(); - iterate_ccs_singles(dummy); + iterate_ccs_singles(dummy, CCOPS.info); ccs.omega = dummy.omega; // will be overwritten soon output("Changes not stored!"); @@ -206,10 +206,10 @@ CC2::solve() { } } - iterate_adc2_singles(mp2pairs, ccs, xpairs); + iterate_adc2_singles(mp2pairs, ccs, xpairs, CCOPS.info); for (size_t iter = 0; iter < 10; iter++) { bool dconv = iterate_adc2_pairs(xpairs, ccs); - bool sconv = iterate_adc2_singles(mp2pairs, ccs, xpairs); + bool sconv = iterate_adc2_singles(mp2pairs, ccs, xpairs, CCOPS.info); if (sconv and dconv) { output("ADC(2) Converged"); break; @@ -264,7 +264,7 @@ CC2::solve() { // needed to assign an omega const vector_real_function_3d backup = copy(world, lrcc2_s.get_vecfunction()); CC_vecfunction test(backup, RESPONSE, parameters.freeze()); - iterate_ccs_singles(test); + iterate_ccs_singles(test, CCOPS.info); lrcc2_s.omega = test.omega; output("CCS Iteration: Changes are not applied (just omega)!"); @@ -272,15 +272,15 @@ CC2::solve() { Pairs lrcc2_d; bool found_lrcc2d = initialize_pairs(lrcc2_d, EXCITED_STATE, CT_LRCC2, cc2singles, lrcc2_s, excitation); - if (found_lrcc2d) iterate_lrcc2_singles(cc2singles, cc2pairs, lrcc2_s, lrcc2_d); - else iterate_ccs_singles(lrcc2_s); + if (found_lrcc2d) iterate_lrcc2_singles(cc2singles, cc2pairs, lrcc2_s, lrcc2_d, CCOPS.info); + else iterate_ccs_singles(lrcc2_s, CCOPS.info); const double omega_cis = lrcc2_s.omega; CCOPS.info.intermediate_potentials=CCOPS.get_potentials; // update applied singles potentials for (size_t iter = 0; iter < parameters.iter_max(); iter++) { output.section("Macroiteration " + std::to_string(int(iter)) + " of LRCC2"); bool dconv = iterate_lrcc2_pairs(cc2singles, cc2pairs, lrcc2_s, lrcc2_d, CCOPS.info); - bool sconv = iterate_lrcc2_singles(cc2singles, cc2pairs, lrcc2_s, lrcc2_d); + bool sconv = iterate_lrcc2_singles(cc2singles, cc2pairs, lrcc2_s, lrcc2_d, CCOPS.info); if (dconv and sconv) break; } const double omega_cc2 = lrcc2_s.omega; @@ -424,7 +424,9 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { } else { - if (world.rank()==0) print_header3("Starting MP2 constant part calculation"); + if (world.rank()==0) { + std::cout << std::fixed << std::setprecision(1) << "\nStarting constant part at time " << wall_time() << std::endl; + } MacroTaskConstantPart t; MacroTask task(world, t); std::vector> gs_singles, ex_singles; // dummy vectors @@ -474,7 +476,9 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { if (parameters.debug()) print_size(world, coupling_vec, "couplingvector"); - if (world.rank()==0) print("Start updating pairs in iteration "); + if (world.rank()==0) { + std::cout << std::fixed << std::setprecision(1) << "\nStart updating pairs part at time " << wall_time() << std::endl; + } MacroTaskIteratePair t; MacroTask task1(world, t); @@ -712,7 +716,7 @@ CC2::solve_cc2(CC_vecfunction& singles, Pairs& doubles) { if (not parameters.no_compute_cc2()) { // first singles iteration output.section("Initialize Singles to the Doubles"); - iterate_cc2_singles(singles, doubles); + iterate_cc2_singles(singles, doubles, info); // nasty hack info.intermediate_potentials=CCOPS.get_potentials; info.intermediate_potentials.parameters=parameters; @@ -767,7 +771,7 @@ CC2::solve_cc2(CC_vecfunction& singles, Pairs& doubles) { bool doubles_converged=rmsrnorm& doubles) { } else { output.section("Found no_compute_cc2 Key: Reiterating Singles to check convergence"); // need the singles potential for the constant part of LRCC2 so we recompute it (also good to check if it is converged) - bool sconv = iterate_cc2_singles(singles, doubles); + bool sconv = iterate_cc2_singles(singles, doubles, CCOPS.info); if (not sconv) output.warning("Singles not Converged"); } @@ -810,6 +814,53 @@ CC2::solve_cc2(CC_vecfunction& singles, Pairs& doubles) { } +/// solve the excited state LR-CC2 equations for a given excitation + +/// @param[in] gs_doubles: the ground state doubles +/// @param[in] gs_singles: the ground state singles +/// @param[in] cis: the CIS singles +/// @param[in] excitation: the excitation number +/// @return a tuple with the excited state doubles, the excited state singles and the excitation energy +std::tuple, CC_vecfunction, double> +CC2::solve_lrcc2(const Pairs& gs_doubles, const CC_vecfunction& gs_singles, const CC_vecfunction& cis, + const std::size_t excitation) const +{ + Pairs ex_doubles; + initialize_pairs(ex_doubles, EXCITED_STATE, CT_LRCC2, gs_singles, cis, excitation); + + auto all_doubles_present =[&]() { + for (const auto& p : ex_doubles.allpairs) { + if (not p.second.function().is_initialized()) return false; + } + return true; + }; + + double omega_cis=cis.omega; + double omega=0.0; + CC_vecfunction ex_singles=cis.copy(); + +// if (all_doubles_present()) { +// iterate_lrcc2_singles(gs_singles, gs_doubles, ex_singles, ex_doubles); +// } else { +// iterate_ccs_singles(ex_singles); +// } +// CCOPS.info.intermediate_potentials=CCOPS.get_potentials; // update applied singles potentials +// +// for (size_t iter = 0; iter < parameters.iter_max(); iter++) { +// output.section("Macroiteration " + std::to_string(int(iter)) + " of LRCC2"); +// bool dconv = iterate_lrcc2_pairs(cc2singles, cc2pairs, lrcc2_s, lrcc2_d, CCOPS.info); +// bool sconv = iterate_lrcc2_singles(cc2singles, cc2pairs, lrcc2_s, lrcc2_d); +// if (dconv and sconv) break; +// } +// const double omega_cc2 = lrcc2_s.omega; +// const std::string msg = "Excitation " + std::to_string(int(excitation)); +// results_ex.push_back(std::make_pair(msg, std::make_pair(omega_cis, omega_cc2))); +// timings.push_back(std::make_pair(msg, time_ex.current_time(true))); + + return std::make_tuple(ex_doubles, ex_singles, omega); + +}; + bool CC2::iterate_pair(CCPair& pair, const CC_vecfunction& singles) const { output.section("Iterate Pair " + pair.name()); if (pair.ctype == CT_CC2) MADNESS_ASSERT(singles.type == PARTICLE); diff --git a/src/madness/chem/CC2.h b/src/madness/chem/CC2.h index 12b8609f822..a3069abe0cd 100644 --- a/src/madness/chem/CC2.h +++ b/src/madness/chem/CC2.h @@ -161,40 +161,55 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { double solve_cc2(CC_vecfunction& tau, Pairs& u); + /// solve the excited state LR-CC2 equations for a given excitation + + /// @param[in] gs_doubles: the ground state doubles + /// @param[in] gs_singles: the ground state singles + /// @param[in] cis: the CIS singles + /// @param[in] excitation: the excitation number + /// @return a tuple with the excited state doubles, the excited state singles and the excitation energy + std::tuple, CC_vecfunction, double> + solve_lrcc2(const Pairs& gs_doubles, const CC_vecfunction& gs_singles, const CC_vecfunction& cis, + const std::size_t excitation) const; + double solve_cispd(Pairs& doubles, const Pairs& mp2_pairs, const CC_vecfunction& cis_singles); /// convencience function to iterate the CC2 ground state singles, /// makes the right call on the iterate_singles functions bool - iterate_cc2_singles(CC_vecfunction& singles, Pairs& doubles) { - CCOPS.clear_potentials(singles); + iterate_cc2_singles(CC_vecfunction& singles, Pairs& doubles, Info& info) { + // CCOPS.clear_potentials(singles); + info.intermediate_potentials.clear_all(); Pairs empty; - return iterate_singles(singles, CC_vecfunction(RESPONSE), doubles, empty, CT_CC2, parameters.iter_max_3D()); + return iterate_singles(world, singles, CC_vecfunction(RESPONSE), doubles, empty, CT_CC2, parameters.iter_max_3D(), info); } bool - iterate_adc2_singles(Pairs& mp2, CC_vecfunction& singles, Pairs& x) { + iterate_adc2_singles(Pairs& mp2, CC_vecfunction& singles, Pairs& x, Info& info) { MADNESS_ASSERT(singles.type == RESPONSE); - CCOPS.clear_potentials(singles); - return iterate_singles(singles, CC_vecfunction(UNDEFINED), mp2, x, CT_ADC2, parameters.iter_max_3D()); + // CCOPS.clear_potentials(singles); + info.intermediate_potentials.clear_response(); + return iterate_singles(world, singles, CC_vecfunction(UNDEFINED), mp2, x, CT_ADC2, parameters.iter_max_3D(), info); } bool - iterate_lrcc2_singles(CC_vecfunction& cc2_s, Pairs& cc2_d, CC_vecfunction& lrcc2_s, Pairs lrcc2_d) { + iterate_lrcc2_singles(CC_vecfunction& cc2_s, Pairs& cc2_d, CC_vecfunction& lrcc2_s, Pairs lrcc2_d, Info& info) { MADNESS_ASSERT(cc2_s.type == PARTICLE); MADNESS_ASSERT(lrcc2_s.type == RESPONSE); - CCOPS.clear_potentials(lrcc2_s); - return iterate_singles(lrcc2_s, cc2_s, cc2_d, lrcc2_d, CT_LRCC2, parameters.iter_max_3D()); + info.intermediate_potentials.clear_response(); + // CCOPS.clear_potentials(lrcc2_s); + return iterate_singles(world, lrcc2_s, cc2_s, cc2_d, lrcc2_d, CT_LRCC2, parameters.iter_max_3D(), info); } /// convencience function to iterate the CCS Response singles, /// makes the right call on the iterate_singles functions bool - iterate_ccs_singles(CC_vecfunction& x) { + iterate_ccs_singles(CC_vecfunction& x, Info& info) { Pairs empty; - CCOPS.clear_potentials(x); - return iterate_singles(x, CC_vecfunction(PARTICLE), empty, empty, CT_LRCCS, 1); + // CCOPS.clear_potentials(x); + info.intermediate_potentials.clear_response(); + return iterate_singles(world, x, CC_vecfunction(PARTICLE), empty, empty, CT_LRCCS, 1, info); } bool @@ -207,8 +222,8 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { /// @param[in] : ctype: the calculation type: CCS, CC2, CC2_response_ /// @param[in] : maxiter: maxmial number of iterations /// @param[out]: true if the overall change of the singles is below 10*donv_6D - iterate_singles(CC_vecfunction& singles, const CC_vecfunction singles2, Pairs& gs_doubles, - Pairs& ex_doubles, const CalcType ctype, const std::size_t maxiter) { + iterate_singles(World& world, CC_vecfunction& singles, const CC_vecfunction singles2, Pairs& gs_doubles, + Pairs& ex_doubles, const CalcType ctype, const std::size_t maxiter, Info& info) { output.subsection("Iterate " + assign_name(ctype) + "-Singles"); CCTimer time_all(world, "Overall Iteration of " + assign_name(ctype) + "-Singles"); bool converged = true; @@ -262,11 +277,11 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { // get potentials CCTimer time_V(world, assign_name(ctype) + "-Singles Potential"); vector_real_function_3d V; - if (ctype == CT_CC2) V = CCOPS.get_CC2_singles_potential_gs(singles, gs_doubles); + if (ctype == CT_CC2) V = CCPotentials::get_CC2_singles_potential_gs(world, singles, gs_doubles, info); else if (ctype == CT_LRCC2) - V = CCOPS.get_CC2_singles_potential_ex(singles2, gs_doubles, singles, ex_doubles); - else if (ctype == CT_LRCCS) V = CCOPS.get_CCS_potential_ex(singles); - else if (ctype == CT_ADC2) V = CCOPS.get_ADC2_singles_potential(gs_doubles, singles, ex_doubles); + V = CCOPS.get_CC2_singles_potential_ex(world, singles2, gs_doubles, singles, ex_doubles, info); + else if (ctype == CT_LRCCS) V = CCOPS.get_CCS_potential_ex(world,singles,false, info); + else if (ctype == CT_ADC2) V = CCOPS.get_ADC2_singles_potential(world, gs_doubles, singles, ex_doubles, info); else MADNESS_EXCEPTION("iterate singles: unknown type", 1); time_V.info(true, norm2(world, V)); diff --git a/src/madness/chem/CCPotentials.cc b/src/madness/chem/CCPotentials.cc index 289f4d22357..87b8e9e5a0c 100644 --- a/src/madness/chem/CCPotentials.cc +++ b/src/madness/chem/CCPotentials.cc @@ -488,17 +488,17 @@ CCPotentials::compute_cc2_excitation_energy(const CC_vecfunction& stau, const CC truncate(world, tmp); CC_vecfunction xbra(tmp, RESPONSE, parameters.freeze()); const double xbrax = inner(world, xbra.get_vecfunction(), sx.get_vecfunction()).sum(); - double result = potential_energy_ex(xbra, stau, dtau, sx, dx, POT_s3a_); - result += potential_energy_ex(xbra, stau, dtau, sx, dx, POT_s3b_); - result += potential_energy_ex(xbra, stau, dtau, sx, dx, POT_s3c_); - result += potential_energy_ex(xbra, stau, dtau, sx, dx, POT_s5b_); - result += potential_energy_ex(xbra, stau, dtau, sx, dx, POT_s5c_); - result += potential_energy_ex(xbra, stau, dtau, sx, dx, POT_s6_); - result += potential_energy_ex(xbra, stau, dtau, sx, dx, POT_s2b_); - result += potential_energy_ex(xbra, stau, dtau, sx, dx, POT_s2c_); - result += potential_energy_ex(xbra, stau, dtau, sx, dx, POT_s4a_); - result += potential_energy_ex(xbra, stau, dtau, sx, dx, POT_s4b_); - result += potential_energy_ex(xbra, stau, dtau, sx, dx, POT_s4c_); + double result = potential_energy_ex(world, xbra, stau, dtau, sx, dx, POT_s3a_); + result += potential_energy_ex(world, xbra, stau, dtau, sx, dx, POT_s3b_); + result += potential_energy_ex(world, xbra, stau, dtau, sx, dx, POT_s3c_); + result += potential_energy_ex(world, xbra, stau, dtau, sx, dx, POT_s5b_); + result += potential_energy_ex(world, xbra, stau, dtau, sx, dx, POT_s5c_); + result += potential_energy_ex(world, xbra, stau, dtau, sx, dx, POT_s6_); + result += potential_energy_ex(world, xbra, stau, dtau, sx, dx, POT_s2b_); + result += potential_energy_ex(world, xbra, stau, dtau, sx, dx, POT_s2c_); + result += potential_energy_ex(world, xbra, stau, dtau, sx, dx, POT_s4a_); + result += potential_energy_ex(world, xbra, stau, dtau, sx, dx, POT_s4b_); + result += potential_energy_ex(world, xbra, stau, dtau, sx, dx, POT_s4c_); return 1.0 / xbrax * result; } @@ -2499,18 +2499,21 @@ CCPotentials::apply_exchange_commutator1(const CCFunction& x, const CC double CCPotentials::make_xy_gf_ab(const CCFunction& x, const CCFunction& y, const CCFunction& a, const CCFunction& b) const { const real_function_3d xa = (x.function * a.function).truncate(); - const real_function_3d x_gf_a = apply_gf(xa); + const real_function_3d x_gf_a = apply_gf(world, xa, info); const double result = y.function.inner(x_gf_a * b.function); return result; } madness::real_function_3d -CCPotentials::apply_gf(const real_function_3d& f) const { - std::shared_ptr fBSH = std::shared_ptr( - BSHOperatorPtr3D(world, parameters.gamma(), parameters.lo(), parameters.thresh_poisson())); - double bsh_prefactor = 4.0 * constants::pi; - double prefactor = 1.0 / (2.0 * parameters.gamma()); - return prefactor * ((*g12)(f) - bsh_prefactor * (*fBSH)(f)).truncate(); +CCPotentials::apply_gf(World& world, const real_function_3d& f, const Info& info) { + // std::shared_ptr fBSH = std::shared_ptr( + // BSHOperatorPtr3D(world, info.parameters.gamma(), info.parameters.lo(), info.parameters.thresh_poisson())); + auto fg=CCConvolutionOperator(world,OpType::OT_FG12,info.parameters); + + // double bsh_prefactor = 4.0 * constants::pi; + // double prefactor = 1.0 / (2.0 * info.parameters.gamma()); + return fg(f).truncate(); + // return prefactor * ((*g12)(f) - bsh_prefactor * (*fBSH)(f)).truncate(); } double @@ -2574,7 +2577,7 @@ CCPotentials::make_xy_op_ab(const CCFunction& x, const CCFunction> -CCPotentials::get_pair_function(const Pairs& pairs, const size_t i, const size_t j) const { +CCPotentials::get_pair_function(const Pairs& pairs, const size_t i, const size_t j) { if (i > j) { return swap_particles(pairs(j, i).functions); } else { @@ -2583,8 +2586,11 @@ CCPotentials::get_pair_function(const Pairs& pairs, const size_t i, cons } madness::real_function_3d -CCPotentials::apply_s2b_operation(const CCFunction& bra, const CCPairFunction& u, const size_t particle) const { +CCPotentials::apply_s2b_operation(World& world, const CCFunction& bra, const CCPairFunction& u, + const size_t particle, const Info& info) { real_function_3d result; + auto g12=std::shared_ptr>(new CCConvolutionOperator(world,OpType::OT_G12,info.parameters)); + MADNESS_ASSERT(particle == 1 || particle == 2); if (u.is_pure()) { result = u.dirac_convolution(bra, *g12, particle); @@ -2602,7 +2608,7 @@ CCPotentials::apply_s2b_operation(const CCFunction& bra, const CCPairF b = u.get_a()[0]; } const real_function_3d tmp = (bra.function * a.function).truncate(); - const real_function_3d tmp2 = apply_gf(tmp); + const real_function_3d tmp2 = apply_gf(world, tmp, info); real_function_3d tmp3 = tmp2 * b.function; tmp3.truncate(); result = tmp3; @@ -2745,36 +2751,42 @@ CCPotentials::apply_G(const CCPairFunction& u, const real_convolution_ } madness::vector_real_function_3d -CCPotentials::get_CC2_singles_potential_gs(const CC_vecfunction& singles, const Pairs& doubles) const { +CCPotentials::get_CC2_singles_potential_gs(World& world, const CC_vecfunction& singles, + const Pairs& doubles, Info& info) +{ CCTimer time(world, "CC2 Singles potential"); - vector_real_function_3d fock_residue = potential_singles_gs(singles, doubles, POT_F3D_); + vector_real_function_3d fock_residue = potential_singles_gs(world, singles, doubles, POT_F3D_, info); + Projector Otau(info.mo_bra, singles.get_vecfunction()); + QProjector Q(info.mo_bra, info.mo_ket); // CC2 Singles potential: Q(S4c) + Qt(ccs+s2b+s2c) - vector_real_function_3d Vccs = potential_singles_gs(singles, doubles, POT_ccs_); - vector_real_function_3d Vs2b = potential_singles_gs(singles, doubles, POT_s2b_); - vector_real_function_3d Vs2c = potential_singles_gs(singles, doubles, POT_s2c_); - vector_real_function_3d Vs4b = potential_singles_gs(singles, doubles, POT_s4b_); - vector_real_function_3d Vs4c = potential_singles_gs(singles, doubles, POT_s4c_); - vector_real_function_3d Vs4a = apply_projector(Vs2b, singles); // need to subtract + vector_real_function_3d Vccs = potential_singles_gs(world, singles, doubles, POT_ccs_, info); + vector_real_function_3d Vs2b = potential_singles_gs(world, singles, doubles, POT_s2b_, info); + vector_real_function_3d Vs2c = potential_singles_gs(world, singles, doubles, POT_s2c_, info); + vector_real_function_3d Vs4b = potential_singles_gs(world, singles, doubles, POT_s4b_, info); + vector_real_function_3d Vs4c = potential_singles_gs(world, singles, doubles, POT_s4c_, info); + // vector_real_function_3d Vs4a = apply_projector(Vs2b, singles); // need to subtract + vector_real_function_3d Vs4a = Otau(Vs2b); // need to subtract vector_real_function_3d unprojected = add(world, Vccs, add(world, Vs2b, add(world, Vs2c, add(world, Vs4b, sub(world, Vs4c, Vs4a))))); - vector_real_function_3d potential = apply_Qt(unprojected, mo_ket_); + // vector_real_function_3d potential = apply_Qt(unprojected, mo_ket_); + vector_real_function_3d potential = Q(unprojected); truncate(world, potential); - get_potentials.insert(copy(world, potential), singles, POT_singles_); + info.intermediate_potentials.insert(copy(world, potential), singles, POT_singles_); time.info(true, norm2(world, potential)); const vector_real_function_3d result = add(world, potential, fock_residue); return result; } madness::vector_real_function_3d -CCPotentials::get_CCS_potential_ex(CC_vecfunction& x, const bool print) const { +CCPotentials::get_CCS_potential_ex(World& world, CC_vecfunction& x, const bool print, Info& info) const { if (x.type != RESPONSE) error("get_CCS_response_potential: Wrong type of input singles"); Pairs empty_doubles; CC_vecfunction empty_singles(PARTICLE); - const vector_real_function_3d fock_residue = potential_singles_ex(empty_singles, empty_doubles, x, empty_doubles, - POT_F3D_); - vector_real_function_3d potential = potential_singles_ex(empty_singles, empty_doubles, x, empty_doubles, POT_cis_); + const vector_real_function_3d fock_residue = potential_singles_ex(world, empty_singles, empty_doubles, x, + empty_doubles, POT_F3D_, info); + vector_real_function_3d potential = potential_singles_ex(world, empty_singles, empty_doubles, x, empty_doubles, POT_cis_, info); // the fock residue does not get projected, but all the rest potential = apply_Qt(potential, mo_ket_); truncate(world, potential); @@ -2787,22 +2799,22 @@ CCPotentials::get_CCS_potential_ex(CC_vecfunction& x, const bool print) const { } madness::vector_real_function_3d -CCPotentials::get_CC2_singles_potential_ex(const CC_vecfunction& gs_singles, const Pairs& gs_doubles, - CC_vecfunction& ex_singles, const Pairs& response_doubles) const { +CCPotentials::get_CC2_singles_potential_ex(World& world, const CC_vecfunction& gs_singles, + const Pairs& gs_doubles, CC_vecfunction& ex_singles, const Pairs& response_doubles, Info& info) const { MADNESS_ASSERT(gs_singles.type == PARTICLE); MADNESS_ASSERT(ex_singles.type == RESPONSE); - const vector_real_function_3d fock_residue = potential_singles_ex(gs_singles, gs_doubles, ex_singles, - response_doubles, POT_F3D_); - vector_real_function_3d Vccs = potential_singles_ex(gs_singles, gs_doubles, ex_singles, response_doubles, POT_ccs_); - vector_real_function_3d Vs2b = potential_singles_ex(gs_singles, gs_doubles, ex_singles, response_doubles, POT_s2b_); - vector_real_function_3d Vs2c = potential_singles_ex(gs_singles, gs_doubles, ex_singles, response_doubles, POT_s2c_); - vector_real_function_3d Vs4b = potential_singles_ex(gs_singles, gs_doubles, ex_singles, response_doubles, POT_s4b_); - vector_real_function_3d Vs4c = potential_singles_ex(gs_singles, gs_doubles, ex_singles, response_doubles, POT_s4c_); + const vector_real_function_3d fock_residue = potential_singles_ex(world, gs_singles, gs_doubles, + ex_singles, response_doubles, POT_F3D_, info); + vector_real_function_3d Vccs = potential_singles_ex(world, gs_singles, gs_doubles, ex_singles, response_doubles,POT_ccs_, info); + vector_real_function_3d Vs2b = potential_singles_ex(world, gs_singles, gs_doubles, ex_singles, response_doubles,POT_s2b_, info); + vector_real_function_3d Vs2c = potential_singles_ex(world, gs_singles, gs_doubles, ex_singles, response_doubles,POT_s2c_, info); + vector_real_function_3d Vs4b = potential_singles_ex(world, gs_singles, gs_doubles, ex_singles, response_doubles,POT_s4b_, info); + vector_real_function_3d Vs4c = potential_singles_ex(world, gs_singles, gs_doubles, ex_singles, response_doubles,POT_s4c_, info); // make low scaling s4a potential // -Otau(s2b_response) + -Ox(s2b_gs) // maybe store full s2b potential of gs // both need to be subtracted - vector_real_function_3d s2b_gs = potential_singles_gs(gs_singles, gs_doubles, POT_s2b_); + vector_real_function_3d s2b_gs = potential_singles_gs(world, gs_singles, gs_doubles, POT_s2b_, info); vector_real_function_3d Vs4a = -1.0 * add(world, apply_projector(s2b_gs, ex_singles), apply_projector(Vs2b, gs_singles)); //add up @@ -2834,18 +2846,18 @@ CCPotentials::get_CC2_singles_potential_ex(const CC_vecfunction& gs_singles, con } madness::vector_real_function_3d -CCPotentials::get_ADC2_singles_potential(const Pairs& gs_doubles, CC_vecfunction& ex_singles, - const Pairs& response_doubles) const { +CCPotentials::get_ADC2_singles_potential(World& world, const Pairs& gs_doubles, + CC_vecfunction& ex_singles, const Pairs& response_doubles, Info& info) const { MADNESS_ASSERT(ex_singles.type == RESPONSE); vector_real_function_3d zero = zero_functions(world, get_active_mo_ket().size()); CC_vecfunction tau(zero, PARTICLE, parameters.freeze()); - const vector_real_function_3d result = get_CC2_singles_potential_ex(tau, gs_doubles, ex_singles, response_doubles); + const vector_real_function_3d result = get_CC2_singles_potential_ex(world, tau, gs_doubles, ex_singles, response_doubles, info); return result; } double -CCPotentials::potential_energy_gs(const CC_vecfunction& bra, const CC_vecfunction& singles, - const Pairs& doubles, const PotentialType& name) const { +CCPotentials::potential_energy_gs(World& world, const CC_vecfunction& bra, + const CC_vecfunction& singles, const Pairs& doubles, const PotentialType& name) const { // sanity check MADNESS_ASSERT(singles.type == PARTICLE); CCTimer timer(world, "potential energy of " + assign_name(name)); @@ -2890,17 +2902,20 @@ CCPotentials::potential_energy_gs(const CC_vecfunction& bra, const CC_vecfunctio } madness::vector_real_function_3d -CCPotentials::potential_singles_gs(const CC_vecfunction& singles, const Pairs& doubles, - const PotentialType& name) const { +CCPotentials::potential_singles_gs(World& world, const CC_vecfunction& singles, + const Pairs& doubles, const PotentialType& name, Info& info) +{ MADNESS_ASSERT(singles.type == PARTICLE); vector_real_function_3d result; CCTimer timer(world, "Singles-Potential:" + assign_name(name)); if (name == POT_F3D_) { - result = fock_residue_closed_shell(singles); + result = fock_residue_closed_shell(world, singles, info); } else if (name == POT_ccs_) { - const CC_vecfunction t = make_t_intermediate(singles,parameters); - result = apply_Qt(ccs_unprojected(t, singles), - t); // this is not the full t projector, but the potential will be projeted afterwards and this will unclude th frozen mos + const CC_vecfunction t = make_active_t_intermediate(singles,info); + QProjector Qt(info.get_active_mo_bra(),t.get_vecfunction()); + result = Qt(ccs_unprojected(world, t, singles, info)); + // result = apply_Qt(ccs_unprojected(world, t, singles, info), t); + // this is not the full t projector, but the potential will be projeted afterwards and this will unclude th frozen mos } else if (name == POT_s2b_) { // // calculate the s2b potential and afterwards the s4a potential from the s2b potential // // because: Qt(S2b) = S2b + S4a @@ -2915,15 +2930,15 @@ CCPotentials::potential_singles_gs(const CC_vecfunction& singles, const Pairs this is calculated along with the s2b potential"); } else if (name == POT_s4b_) { - result = s4b(singles, doubles); + result = s4b(world, singles, doubles, info); } else if (name == POT_s4c_) { - result = s4c(singles, doubles); + result = s4c(world, singles, doubles, info); } else MADNESS_EXCEPTION(("potential_singles: Unknown potential " + assign_name(name)).c_str(), 1) ; @@ -2940,10 +2955,10 @@ CCPotentials::potential_singles_gs(const CC_vecfunction& singles, const Pairs& doubles_gs, const CC_vecfunction& singles_ex, - const Pairs& doubles_ex, - const PotentialType& name) const { +CCPotentials::potential_energy_ex(World& world, const CC_vecfunction& bra, + const CC_vecfunction& singles_gs, const Pairs& doubles_gs, + const CC_vecfunction& singles_ex, + const Pairs& doubles_ex, const PotentialType& name) const { // sanity check MADNESS_ASSERT(singles_gs.type == PARTICLE); MADNESS_ASSERT(singles_ex.type == RESPONSE); @@ -2992,9 +3007,9 @@ CCPotentials::potential_energy_ex(const CC_vecfunction& bra, const CC_vecfunctio } madness::vector_real_function_3d -CCPotentials::potential_singles_ex(const CC_vecfunction& singles_gs, const Pairs& doubles_gs, - const CC_vecfunction& singles_ex, const Pairs& doubles_ex, - const PotentialType& name) const { +CCPotentials::potential_singles_ex(World& world, const CC_vecfunction& singles_gs, + const Pairs& doubles_gs, const CC_vecfunction& singles_ex, + const Pairs& doubles_ex, const PotentialType& name, Info& info) const { //if(mo_ket_.size()>1) output.warning("Potential for ExSingles is not ready for more than one orbital"); // sanity check MADNESS_ASSERT(singles_gs.type == PARTICLE); @@ -3002,30 +3017,30 @@ CCPotentials::potential_singles_ex(const CC_vecfunction& singles_gs, const Pairs vector_real_function_3d result; CCTimer timer(world, "timer-ex-potential"); if (name == POT_F3D_) { - result = fock_residue_closed_shell(singles_ex); + result = fock_residue_closed_shell(world, singles_ex, info); } else if (name == POT_ccs_) { const CC_vecfunction t = make_t_intermediate(singles_gs,parameters); - vector_real_function_3d part1 = apply_Qt(ccs_unprojected(t, singles_ex), t); - vector_real_function_3d part2 = apply_Qt(ccs_unprojected(singles_ex, singles_gs), t); - vector_real_function_3d part3 = apply_projector(ccs_unprojected(t, singles_gs), singles_ex); + vector_real_function_3d part1 = apply_Qt(ccs_unprojected(world, t, singles_ex, info), t); + vector_real_function_3d part2 = apply_Qt(ccs_unprojected(world, singles_ex, singles_gs, info), t); + vector_real_function_3d part3 = apply_projector(ccs_unprojected(world, t, singles_gs, info), singles_ex); vector_real_function_3d tmp = add(world, part1, part2); result = sub(world, tmp, part3); } else if (name == POT_s2b_) { - result = s2b(singles_ex, doubles_ex); + result = s2b(world, singles_ex, doubles_ex, info); } else if (name == POT_s2c_) { - result = s2c(singles_ex, doubles_ex); + result = s2c(world, singles_ex, doubles_ex, info); } else if (name == POT_s4a_) { error("potential_singles: Demanded s4a potential -> this is calculated from the s2b potential"); } else if (name == POT_s4b_) { - vector_real_function_3d s4b_part1 = s4b(singles_gs, doubles_ex); - vector_real_function_3d s4b_part2 = s4b(singles_ex, doubles_gs); + vector_real_function_3d s4b_part1 = s4b(world, singles_gs, doubles_ex, info); + vector_real_function_3d s4b_part2 = s4b(world, singles_ex, doubles_gs, info); result = add(world, s4b_part1, s4b_part2); } else if (name == POT_s4c_) { - vector_real_function_3d s4c_part1 = s4c(singles_gs, doubles_ex); - vector_real_function_3d s4c_part2 = s4c(singles_ex, doubles_gs); + vector_real_function_3d s4c_part1 = s4c(world, singles_gs, doubles_ex, info); + vector_real_function_3d s4c_part2 = s4c(world, singles_ex, doubles_gs, info); result = add(world, s4c_part1, s4c_part2); } else if (name == POT_cis_) { - result = ccs_unprojected(CC_vecfunction(get_active_mo_ket(), HOLE, parameters.freeze()), singles_ex); + result = ccs_unprojected(world, CC_vecfunction(get_active_mo_ket(), HOLE, parameters.freeze()), singles_ex, info); } else MADNESS_EXCEPTION(("potential_singles: Unknown potential " + assign_name(name)).c_str(), 1) ; @@ -3043,19 +3058,24 @@ CCPotentials::potential_singles_ex(const CC_vecfunction& singles_gs, const Pairs } madness::vector_real_function_3d -CCPotentials::fock_residue_closed_shell(const CC_vecfunction& singles) const { +CCPotentials::fock_residue_closed_shell(World& world, const CC_vecfunction& singles, const Info& info) +{ // vecfuncT tau = singles.get_vecfunction(); + auto g12=CCConvolutionOperator(world,OT_G12,info.parameters); CCTimer timer_J(world, "J"); // vecfuncT J = mul(world, intermediates_.get_hartree_potential(), tau); - vector_real_function_3d J; - for (const auto& tmpi : singles.functions) { - const CCFunction& taui = tmpi.second; - real_function_3d hartree_potential = real_function_3d(world); - for (const auto& tmpk : mo_ket_.functions) - hartree_potential += (*g12)(mo_bra_(tmpk.first), tmpk.second); - const real_function_3d Ji = hartree_potential * taui.function; - J.push_back(Ji); - } + // vector_real_function_3d J; + real_function_3d density=dot(world, info.mo_bra,info.mo_ket); + real_function_3d hartree_potential=g12(density); + // for (const auto& tmpi : singles.functions) { + // const CCFunction& taui = tmpi.second; + // real_function_3d hartree_potential = real_function_3d(world); + // for (const auto& tmpk : mo_ket_.functions) + // hartree_potential += (g12)(info.mo_bra[tmpk.first], tmpk.second); + // const real_function_3d Ji = hartree_potential * taui.function; + // J.push_back(Ji); + // } + vector_real_function_3d J = hartree_potential* singles.get_vecfunction(); truncate(world, J); scale(world, J, 2.0); timer_J.info(true, norm2(world, J)); @@ -3063,13 +3083,14 @@ CCPotentials::fock_residue_closed_shell(const CC_vecfunction& singles) const { vector_real_function_3d vK; for (const auto& tmpi : singles.functions) { const CCFunction& taui = tmpi.second; - const real_function_3d Ki = K(taui); + const real_function_3d Ki = K(world, taui, info); vK.push_back(Ki); } scale(world, vK, -1.0); timer_K.info(true, norm2(world, vK)); // apply nuclear potential - Nuclear Uop(world, nemo_.get()); + auto ncf=std::shared_ptr(new AdhocNuclearCorrelationFactor(world, info.U2, info.U1)); + Nuclear Uop(world, ncf); vector_real_function_3d Upot = Uop(singles.get_vecfunction()); vector_real_function_3d KU = add(world, vK, Upot); return add(world, J, KU); @@ -3106,10 +3127,11 @@ CCPotentials::K_macrotask(World& world, const std::vector& mo_ } madness::real_function_3d -CCPotentials::K(const CCFunction& f) const { +CCPotentials::K(World& world, const CCFunction& f, const Info& info) { + auto g12=CCConvolutionOperator(world,OT_G12,info.parameters); real_function_3d result = real_factory_3d(world); - for (const auto& k_iterator : mo_ket_.functions) { - result += (*g12)(mo_bra_(k_iterator.first), f) * mo_ket_(k_iterator.first).function; + for (size_t k = 0; k < info.mo_ket.size(); k++) { + result += ((g12)(info.mo_bra[k] * f.f()).truncate()) *info.mo_ket[k]; } return result; } @@ -3180,12 +3202,12 @@ CCPotentials::apply_Kf(const CCFunction& x, const CCFunction madness::real_function_6d CCPotentials::apply_fK(const CCFunction& x, const CCFunction& y, const real_convolution_6d *Gscreen) const { const bool symmetric = (x.type == y.type && x.i == y.i); - const real_function_3d Kx = K(x); + const real_function_3d Kx = K(world, x, info); const real_function_6d fKphi0b = make_f_xy(CCFunction(Kx, x.i, UNDEFINED), y, Gscreen); real_function_6d fKphi0a; if (symmetric) fKphi0a = swap_particles(fKphi0b); else { - real_function_3d Ky = K(y); + real_function_3d Ky = K(world, y, info); fKphi0a = make_f_xy(x, CCFunction(Ky, y.i, UNDEFINED), Gscreen); } const real_function_6d fKphi0 = (fKphi0a + fKphi0b); @@ -3277,33 +3299,23 @@ CCPotentials::make_f_xy_macrotask(World& world, const real_function_3d& x_ket, c } madness::vector_real_function_3d -CCPotentials::ccs_unprojected(const CC_vecfunction& ti, const CC_vecfunction& tk) const { +CCPotentials::ccs_unprojected(World& world, const CC_vecfunction& ti, const CC_vecfunction& tk, const Info& info) { + auto g12=CCConvolutionOperator(world,OT_G12,info.parameters); vector_real_function_3d result; for (const auto& itmp : ti.functions) { real_function_3d kgtk = real_factory_3d(world); for (const auto& ktmp : tk.functions) - kgtk += (*g12)(mo_bra_(ktmp.first), ktmp.second); + kgtk += (g12)(info.mo_bra[ktmp.first], ktmp.second); const real_function_3d kgtk_ti = kgtk * ti(itmp.first).function; real_function_3d kgti_tk = real_factory_3d(world); for (const auto& ktmp : tk.functions) - kgti_tk += (*g12)(mo_bra_(ktmp.first), ti(itmp.first)) * tk(ktmp.first).function; + kgti_tk += (g12)(info.mo_bra[ktmp.first], ti(itmp.first)) * tk(ktmp.first).function; const real_function_3d resulti = 2.0 * kgtk_ti - kgti_tk; result.push_back(resulti); } return result; } -madness::real_function_3d -CCPotentials::make_density(const CC_vecfunction& x) const { - real_function_3d result = real_factory_3d(world); - for (const auto& ktmp : x.functions) { - const size_t k = ktmp.first; - result += 2.0 * mo_bra_(k).function * (x(k).function); - } - result.truncate(); - return result; -} - double CCPotentials::x_s3a(const CC_vecfunction& x, const CC_vecfunction& t) const { MADNESS_ASSERT(x.size() == t.size()); @@ -3506,10 +3518,11 @@ CCPotentials::x_s4c(const CC_vecfunction& x, const CC_vecfunction& t, const Pair } madness::vector_real_function_3d -CCPotentials::s2b(const CC_vecfunction& singles, const Pairs& doubles) const { +CCPotentials::s2b(World& world, const CC_vecfunction& singles, const Pairs& doubles, Info& info) +{ vector_real_function_3d result; // see if we can skip the recalculation of the pure 6D part since this does not change during the singles iteration - vector_real_function_3d result_u = get_potentials(singles, POT_s2b_); + vector_real_function_3d result_u = info.intermediate_potentials(singles, POT_s2b_); bool recalc_u_part = false; if (result_u.empty()) recalc_u_part = true; @@ -3523,35 +3536,32 @@ CCPotentials::s2b(const CC_vecfunction& singles, const Pairs& doubles) c // check if the first function in the vector is really the pure 6D part MADNESS_ASSERT(uik[0].is_pure()); if (recalc_u_part) { - resulti_u += 2.0 * apply_s2b_operation(mo_bra_(k), uik[0], - 2); //2.0*uik[0].dirac_convolution(mo_bra_(k),g12,2); - resulti_u -= apply_s2b_operation(mo_bra_(k), uik[0], - 1); //uik[0].dirac_convolution(mo_bra_(k),g12,1); + resulti_u += 2.0 * apply_s2b_operation(world, info.mo_bra[k], uik[0], 2, info); //2.0*uik[0].dirac_convolution(mo_bra_(k),g12,2); + resulti_u -= apply_s2b_operation(world, info.mo_bra[k], uik[0], 1, info); //uik[0].dirac_convolution(mo_bra_(k),g12,1); } else { - resulti_u = result_u[i - parameters.freeze()]; + resulti_u = result_u[i - info.parameters.freeze()]; } for (size_t mm = 1; mm < uik.size(); mm++) { - resulti_r += 2.0 * apply_s2b_operation(mo_bra_(k), uik[mm], - 2); //2.0*uik[mm].dirac_convolution(mo_bra_(k),g12,2); - resulti_r -= apply_s2b_operation(mo_bra_(k), uik[mm], - 1); //uik[mm].dirac_convolution(mo_bra_(k),g12,1); + resulti_r += 2.0 * apply_s2b_operation(world, info.mo_bra[k], uik[mm], 2, info); //2.0*uik[mm].dirac_convolution(mo_bra_(k),g12,2); + resulti_r -= apply_s2b_operation(world, info.mo_bra[k], uik[mm], 1, info); //uik[mm].dirac_convolution(mo_bra_(k),g12,1); } } result.push_back(resulti_r + resulti_u); if (recalc_u_part) result_u.push_back(resulti_u); } - if (recalc_u_part) get_potentials.insert(result_u, singles, POT_s2b_); + if (recalc_u_part) info.intermediate_potentials.insert(result_u, singles, POT_s2b_); return result; } madness::vector_real_function_3d -CCPotentials::s2c(const CC_vecfunction& singles, const Pairs& doubles) const { +CCPotentials::s2c(World& world, const CC_vecfunction& singles, const Pairs& doubles, Info& info) { vector_real_function_3d result; // see if we can skip the recalculation of the pure 6D part since this does not change during the singles iteration - vector_real_function_3d result_u = get_potentials(singles, POT_s2c_); + vector_real_function_3d result_u = info.intermediate_potentials(singles, POT_s2c_); bool recalc_u_part = false; if (result_u.empty()) recalc_u_part = true; + auto g12=CCConvolutionOperator(world,OT_G12,info.parameters); for (const auto& itmp : singles.functions) { const size_t i = itmp.first; @@ -3559,10 +3569,10 @@ CCPotentials::s2c(const CC_vecfunction& singles, const Pairs& doubles) c real_function_3d resulti_r = real_factory_3d(world); for (const auto& ktmp : singles.functions) { const size_t k = ktmp.first; - const real_function_3d kgi = (*g12)(mo_bra_(k), mo_ket_(i)); + const real_function_3d kgi = (g12)(info.mo_bra[k], info.mo_ket[i]); for (const auto& ltmp : singles.functions) { const size_t l = ltmp.first; - const real_function_3d l_kgi = mo_bra_(l).function * kgi; + const real_function_3d l_kgi = info.mo_bra[l] * kgi; std::vector> ukl = get_pair_function(doubles, k, l); // check if the first function in the vector is really the pure 6D part MADNESS_ASSERT(ukl[0].is_pure()); @@ -3570,7 +3580,7 @@ CCPotentials::s2c(const CC_vecfunction& singles, const Pairs& doubles) c resulti_u += -2.0 * ukl[0].project_out(l_kgi, 2); resulti_u += ukl[0].project_out(l_kgi, 1); } else { - resulti_u = result_u[i - parameters.freeze()]; + resulti_u = result_u[i - info.parameters.freeze()]; } for (size_t mm = 1; mm < ukl.size(); mm++) { resulti_r += -2.0 * ukl[mm].project_out(l_kgi, 2); @@ -3581,7 +3591,7 @@ CCPotentials::s2c(const CC_vecfunction& singles, const Pairs& doubles) c result.push_back(resulti_r + resulti_u); if (recalc_u_part) result_u.push_back(resulti_u); } - if (recalc_u_part) get_potentials.insert(result_u, singles, POT_s2c_); + if (recalc_u_part) info.intermediate_potentials.insert(result_u, singles, POT_s2c_); return result; } @@ -3615,23 +3625,25 @@ CCPotentials::s4a_from_s2b(const vector_real_function_3d& s2b, const CC_vecfunct } madness::vector_real_function_3d -CCPotentials::s4b(const CC_vecfunction& singles, const Pairs& doubles) const { +CCPotentials::s4b(World& world, const CC_vecfunction& singles, const Pairs& doubles, const Info& info) +{ + auto g12=CCConvolutionOperator(world,OT_G12,info.parameters); vector_real_function_3d result; - const vector_real_function_3d active_mo_bra = get_active_mo_bra(); + const vector_real_function_3d active_mo_bra = info.get_active_mo_bra(); for (const auto& itmp : singles.functions) { const size_t i = itmp.first; real_function_3d resulti = real_factory_3d(world); for (const auto& ktmp : singles.functions) { const size_t k = ktmp.first; - const real_function_3d kgi = (*g12)(mo_bra_(k), singles(i)); - vector_real_function_3d l_kgi = mul_sparse(world, kgi, active_mo_bra, parameters.thresh_3D()); + const real_function_3d kgi = (g12)(info.mo_bra[k], singles(i)); + vector_real_function_3d l_kgi = mul_sparse(world, kgi, active_mo_bra, info.parameters.thresh_3D()); truncate(world, l_kgi); for (const auto& ltmp : singles.functions) { const size_t l = ltmp.first; const std::vector> ukl = get_pair_function(doubles, k, l); for (size_t mm = 0; mm < ukl.size(); mm++) { - resulti += -2.0 * ukl[mm].project_out(l_kgi[l - parameters.freeze()], 2); - resulti += ukl[mm].project_out(l_kgi[l - parameters.freeze()], 1); + resulti += -2.0 * ukl[mm].project_out(l_kgi[l - info.parameters.freeze()], 2); + resulti += ukl[mm].project_out(l_kgi[l - info.parameters.freeze()], 1); } } } @@ -3641,9 +3653,11 @@ CCPotentials::s4b(const CC_vecfunction& singles, const Pairs& doubles) c } madness::vector_real_function_3d -CCPotentials::s4c(const CC_vecfunction& singles, const Pairs& doubles) const { +CCPotentials::s4c(World& world, const CC_vecfunction& singles, const Pairs& doubles, const Info& info) +{ vector_real_function_3d result; - const vector_real_function_3d active_mo_bra = get_active_mo_bra(); + auto g12=CCConvolutionOperator(world,OT_G12,info.parameters); + const vector_real_function_3d active_mo_bra = info.get_active_mo_bra(); for (const auto& itmp : singles.functions) { const size_t i = itmp.first; real_function_3d resulti = real_factory_3d(world); @@ -3654,7 +3668,7 @@ CCPotentials::s4c(const CC_vecfunction& singles, const Pairs& doubles) c real_function_3d kgtauk = real_factory_3d(world); for (const auto& ktmp : singles.functions) { const size_t k = ktmp.first; - kgtauk += (*g12)(mo_bra_(k), singles(k)); + kgtauk += (g12)(info.mo_bra[k], singles(k)); } vector_real_function_3d l_kgtauk = mul(world, kgtauk, active_mo_bra); truncate(world, l_kgtauk); @@ -3662,12 +3676,12 @@ CCPotentials::s4c(const CC_vecfunction& singles, const Pairs& doubles) c const size_t l = ltmp.first; const std::vector> uil = get_pair_function(doubles, i, l); for (size_t mm = 0; mm < uil.size(); mm++) { - part1 += uil[mm].project_out(l_kgtauk[l - parameters.freeze()], 2); - part2 += uil[mm].project_out(l_kgtauk[l - parameters.freeze()], 1); + part1 += uil[mm].project_out(l_kgtauk[l - info.parameters.freeze()], 2); + part2 += uil[mm].project_out(l_kgtauk[l - info.parameters.freeze()], 1); } for (const auto& ktmp : singles.functions) { const size_t k = ktmp.first; - const real_function_3d k_lgtauk = (mo_bra_(k).function * (*g12)(mo_bra_(l), singles(k))).truncate(); + const real_function_3d k_lgtauk = (info.mo_bra[k] * (g12)(info.mo_bra[l], singles(k))).truncate(); for (size_t mm = 0; mm < uil.size(); mm++) { part3 += uil[mm].project_out(k_lgtauk, 2); part4 += uil[mm].project_out(k_lgtauk, 1); @@ -3992,7 +4006,7 @@ void CCPotentials::test_pairs() { } -void CCPotentials::test_singles_potential() const { +void CCPotentials::test_singles_potential(Info& info) const { output("Test LRCC2 Singles Potential with empty doubles and compare to CIS"); { @@ -4003,10 +4017,10 @@ void CCPotentials::test_singles_potential() const { Pairs gs_doubles; Pairs ex_doubles; - vector_real_function_3d cis_potential = potential_singles_ex(gs_singles, gs_doubles, ex_singles, ex_doubles, - POT_cis_); - vector_real_function_3d ccs_potential = potential_singles_ex(gs_singles, gs_doubles, ex_singles, ex_doubles, - POT_ccs_); + vector_real_function_3d cis_potential = potential_singles_ex(world, gs_singles, gs_doubles, ex_singles, + ex_doubles, POT_cis_, info); + vector_real_function_3d ccs_potential = potential_singles_ex(world, gs_singles, gs_doubles, ex_singles, + ex_doubles, POT_ccs_, info); vector_real_function_3d diff = sub(world, cis_potential, ccs_potential); const double d = norm2(world, diff); madness::print_size(world, diff, "difference in potentials"); @@ -4043,9 +4057,9 @@ void CCPotentials::test_singles_potential() const { const CC_vecfunction xbra(tmp, RESPONSE, parameters.freeze()); for (const auto pot:pots) { - const vector_real_function_3d potential = potential_singles_gs(gs_singles, gs_doubles, pot); + const vector_real_function_3d potential = potential_singles_gs(world, gs_singles, gs_doubles, pot, info); const double xpot1 = inner(world, xbra.get_vecfunction(), potential).sum(); - const double xpot2 = potential_energy_gs(xbra, gs_singles, gs_doubles, pot); + const double xpot2 = potential_energy_gs(world, xbra, gs_singles, gs_doubles, pot); const double diff = xpot1 - xpot2; if (world.rank() == 0) std::cout << std::fixed << std::setprecision(10) << @@ -4058,7 +4072,7 @@ void CCPotentials::test_singles_potential() const { if (pot == POT_s2b_) { const vector_real_function_3d pot_s4a = -1.0 * apply_projector(potential, gs_singles); const double xxpot1 = inner(world, xbra.get_vecfunction(), pot_s4a).sum(); - const double xxpot2 = potential_energy_gs(xbra, gs_singles, gs_doubles, POT_s4a_); + const double xxpot2 = potential_energy_gs(world, xbra, gs_singles, gs_doubles, POT_s4a_); const double xdiff = xxpot1 - xxpot2; if (world.rank() == 0) std::cout << @@ -4076,10 +4090,10 @@ void CCPotentials::test_singles_potential() const { CCTimer time_ex(world, "CC2 Singles Response Test"); for (const auto pot:pots) { - const vector_real_function_3d potential = potential_singles_ex(gs_singles, gs_doubles, ex_singles, ex_doubles, - pot); + const vector_real_function_3d potential = potential_singles_ex(world, gs_singles, gs_doubles, ex_singles, + ex_doubles, pot, info); const double xpot1 = inner(world, xbra.get_vecfunction(), potential).sum(); - const double xpot2 = potential_energy_ex(xbra, gs_singles, gs_doubles, ex_singles, ex_doubles, pot); + const double xpot2 = potential_energy_ex(world, xbra, gs_singles, gs_doubles, ex_singles, ex_doubles, pot); const double diff = xpot1 - xpot2; if (world.rank() == 0) std::cout << std::fixed << std::setprecision(10) << @@ -4090,11 +4104,11 @@ void CCPotentials::test_singles_potential() const { if (fabs(diff) > parameters.thresh_6D()) output.warning("Test Failed"); else output("Test Passed"); if (pot == POT_s2b_) { - const vector_real_function_3d potential_gs = potential_singles_gs(gs_singles, gs_doubles, pot); + const vector_real_function_3d potential_gs = potential_singles_gs(world, gs_singles, gs_doubles, pot, info); const vector_real_function_3d pot_s4a = -1.0 * add(world, apply_projector(potential, gs_singles), apply_projector(potential_gs, ex_singles)); const double xxpot1 = inner(world, xbra.get_vecfunction(), pot_s4a).sum(); - const double xxpot2 = potential_energy_ex(xbra, gs_singles, gs_doubles, ex_singles, ex_doubles, POT_s4a_); + const double xxpot2 = potential_energy_ex(world, xbra, gs_singles, gs_doubles, ex_singles, ex_doubles, POT_s4a_); const double xdiff = xxpot1 - xxpot2; if (world.rank() == 0) std::cout << @@ -4120,7 +4134,7 @@ void CCPotentials::test() { assign_name(test5); assign_name(test6); - test_singles_potential(); + test_singles_potential(info); output.section("Testing Scalar Multiplication"); { CC_vecfunction test = mo_ket_ * 2.0; diff --git a/src/madness/chem/CCPotentials.h b/src/madness/chem/CCPotentials.h index 723ece37a05..1df14bafaf5 100644 --- a/src/madness/chem/CCPotentials.h +++ b/src/madness/chem/CCPotentials.h @@ -52,7 +52,7 @@ class CCPotentials { void test_pairs(); - void test_singles_potential() const; + void test_singles_potential(Info& info) const; void test(); @@ -506,8 +506,8 @@ class CCPotentials { /// apply the operator gf = 1/(2\gamma)*(Coulomb - 4\pi*BSH_\gamma) /// works only if f = (1-exp(-\gamma*r12))/(2\gamma) - real_function_3d - apply_gf(const real_function_3d& f) const; + static real_function_3d + apply_gf(World& world, const real_function_3d& f, const Info& info); /// returns /// loops over every entry in the vector and accumulates results @@ -543,13 +543,13 @@ class CCPotentials { /// get the correct pair function as vector of CCPairFunction functions /// @param[in] The pair functions /// @param[out] The demanded pair function as vector of CCPairFunction functions (includes regularization tails) - std::vector> - get_pair_function(const Pairs& pairs, const size_t i, const size_t j) const; + static std::vector> + get_pair_function(const Pairs& pairs, const size_t i, const size_t j) ; /// returns _2 - real_function_3d - apply_s2b_operation(const CCFunction& bra, const CCPairFunction& u, const size_t particle) const; + static real_function_3d + apply_s2b_operation(World& world, const CCFunction& bra, const CCPairFunction& u, const size_t particle, const Info& info); /// dummy to avoid confusion and for convenience real_function_6d swap_particles(const real_function_6d& f) const { @@ -557,7 +557,7 @@ class CCPotentials { } /// swap the particles of the CCPairFunction and return a new vector of swapped functions - std::vector> swap_particles(const std::vector>& f) const { + static std::vector> swap_particles(const std::vector>& f) { std::vector> swapped; for (size_t i = 0; i < f.size(); i++) swapped.push_back(f[i].swap_particles()); return swapped; @@ -636,26 +636,26 @@ class CCPotentials { /// Calculates the CC2 singles potential for the ground state: result = Fock_residue + V /// the V part is stored in the intermediate_potentials structure - vector_real_function_3d - get_CC2_singles_potential_gs(const CC_vecfunction& singles, const Pairs& doubles) const; + static vector_real_function_3d + get_CC2_singles_potential_gs(World& world, const CC_vecfunction& singles, const Pairs& doubles, Info& info); /// Calculates the CCS/CIS singles potential for the excited state: result = Fock_residue + V /// the V part is stored in the intermediate_potentials structure /// the expectation value is calculated and updated vector_real_function_3d - get_CCS_potential_ex(CC_vecfunction& x, const bool print = false) const; + get_CCS_potential_ex(World& world, CC_vecfunction& x, const bool print, Info& info) const; /// Calculates the CC2 singles potential for the Excited state: result = Fock_residue + V /// the V part is stored in the intermediate_potentials structure vector_real_function_3d - get_CC2_singles_potential_ex(const CC_vecfunction& gs_singles, const Pairs& gs_doubles, - CC_vecfunction& ex_singles, const Pairs& response_doubles) const; + get_CC2_singles_potential_ex(World& world, const CC_vecfunction& gs_singles, + const Pairs& gs_doubles, CC_vecfunction& ex_singles, const Pairs& response_doubles, Info& info) const; /// Calculates the CC2 singles potential for the Excited state: result = Fock_residue + V /// the V part is stored in the intermediate_potentials structure vector_real_function_3d - get_ADC2_singles_potential(const Pairs& gs_doubles, CC_vecfunction& ex_singles, - const Pairs& response_doubles) const; + get_ADC2_singles_potential(World& world, const Pairs& gs_doubles, + CC_vecfunction& ex_singles, const Pairs& response_doubles, Info& info) const; /// The potential manager for the ground state potential /// CC2 singles potential parts of the ground state @@ -665,9 +665,10 @@ class CCPotentials { /// @param[in] Doubles of the Ground State /// @param[in] Name of the potential /// @param[out] the potential (without Q application) + /// @param world double - potential_energy_gs(const CC_vecfunction& bra, const CC_vecfunction& singles, const Pairs& doubles, - const PotentialType& name) const; + potential_energy_gs(World& world, const CC_vecfunction& bra, const CC_vecfunction& singles, + const Pairs& doubles, const PotentialType& name) const; /// The potential manager for the ground state potential /// CC2 singles potential parts of the ground state @@ -676,8 +677,10 @@ class CCPotentials { /// @param[in] Doubles of the Ground State /// @param[in] Name of the potential /// @param[out] the potential (without Q application) - vector_real_function_3d - potential_singles_gs(const CC_vecfunction& singles, const Pairs& doubles, const PotentialType& name) const; + /// @param world + static vector_real_function_3d + potential_singles_gs(World& world, const CC_vecfunction& singles, const Pairs& doubles, + const PotentialType& name, Info& info); /// The integra manager for the excited state potential /// CC2 singles potential parts of the ground state @@ -689,10 +692,11 @@ class CCPotentials { /// @param[in] Doubles of the Excited State /// @param[in] Name of the potential /// @param[out] the potential (without Q application) + /// @param world double - potential_energy_ex(const CC_vecfunction& bra, const CC_vecfunction& singles_gs, const Pairs& doubles_gs, - const CC_vecfunction& singles_ex, const Pairs& doubles_ex, - const PotentialType& name) const; + potential_energy_ex(World& world, const CC_vecfunction& bra, const CC_vecfunction& singles_gs, + const Pairs& doubles_gs, const CC_vecfunction& singles_ex, + const Pairs& doubles_ex, const PotentialType& name) const; /// The potential manager for the excited state potential /// CC2 singles potential parts of the ground state @@ -703,21 +707,22 @@ class CCPotentials { /// @param[in] Doubles of the Excited State /// @param[in] Name of the potential /// @param[out] the potential (without Q application) + /// @param world vector_real_function_3d - potential_singles_ex(const CC_vecfunction& singles_gs, const Pairs& doubles_gs, - const CC_vecfunction& singles_ex, const Pairs& doubles_ex, - const PotentialType& name) const; + potential_singles_ex(World& world, const CC_vecfunction& singles_gs, + const Pairs& doubles_gs, const CC_vecfunction& singles_ex, + const Pairs& doubles_ex, const PotentialType& name, Info& info) const; /// The Fock operator is partitioned into F = T + Vn + R /// the fock residue R= 2J-K+Un for closed shell is computed here /// J_i = \sum_k |tau_i> /// K_i = \sum_k |k> - vector_real_function_3d - fock_residue_closed_shell(const CC_vecfunction& singles) const; + static vector_real_function_3d + fock_residue_closed_shell(World& world, const CC_vecfunction& singles, const Info& info); /// the K operator runs over ALL orbitals (also the frozen ones) - real_function_3d - K(const CCFunction& f) const; + static real_function_3d + K(World& world, const CCFunction& f, const Info& info); /// static version of k above for access from macrotask. will eventually replace former. real_function_3d @@ -784,12 +789,9 @@ class CCPotentials { /// unprojected ccs potential /// returns 2kgtk|ti> - kgti|tk> /// the ccs potential: ti = ti and tk = tauk - vector_real_function_3d - ccs_unprojected(const CC_vecfunction& ti, const CC_vecfunction& tk) const; - + static vector_real_function_3d + ccs_unprojected(World& world, const CC_vecfunction& ti, const CC_vecfunction& tk, const Info& info); - real_function_3d - make_density(const CC_vecfunction& x) const; // integrals from singles potentials @@ -839,22 +841,26 @@ class CCPotentials { // result: \sum_k( 2_2 - _1 ) // singles are not needed explicitly but to determine if it is response or ground state + ///@param world ///@param[in] singles:CC_vecfunction fof type response or particle (depending on this the correct intermediates will be used) the functions themselves are not needed ///@param[in] doubles:Pairs of CC_Pairs (GS or Response) + ///@param info ///@param[out] \f$ \sum_k( 2_2 - _1 ) \f$ /// Q-Projector is not applied, sign is correct /// if the s2b potential has already been calculated it will be loaded from the intermediate_potentials structure - vector_real_function_3d - s2b(const CC_vecfunction& singles, const Pairs& doubles) const; + static vector_real_function_3d + s2b(World& world, const CC_vecfunction& singles, const Pairs& doubles, Info& info); // result: -\sum_k( _2 - _1) // singles are not needed explicitly but to determine if it is response or ground state + ///@param world ///@param[in] singles:CC_vecfunction fof type response or particle (depending on this the correct intermediates will be used) the functions themselves are not needed ///@param[in] doubles:Pairs of CC_Pairs (GS or Response) + ///@param info ///@param[out] \f$ -\sum_k( _2 - _1) \f$ /// Q-Projector is not applied, sign is correct - vector_real_function_3d - s2c(const CC_vecfunction& singles, const Pairs& doubles) const; + static vector_real_function_3d + s2c(World& world, const CC_vecfunction& singles, const Pairs& doubles, Info& info); /// the S4a potential can be calcualted from the S2b potential /// result is \f$ s4a_i = - *|tau_l> \f$ @@ -862,20 +868,24 @@ class CCPotentials { s4a_from_s2b(const vector_real_function_3d& s2b, const CC_vecfunction& singles) const; // result: -\sum_k( _2 - _1) | kgtaui = + ///@param world ///@param[in] singles:CC_vecfunction fof type response or particle (depending on this the correct intermediates will be used) the functions themselves are not needed ///@param[in] doubles:Pairs of CC_Pairs (GS or Response) + ///@param info ///@param[out] \f$ -( _2 - _1) | kgtaui = | taui=singles_i \f$ /// Q-Projector is not applied, sign is correct - vector_real_function_3d - s4b(const CC_vecfunction& singles, const Pairs& doubles) const; + static vector_real_function_3d + s4b(World& world, const CC_vecfunction& singles, const Pairs& doubles, const Info& info); + ///@param world ///@param[in] singles:CC_vecfunction fof type response or particle (depending on this the correct intermediates will be used) the functions themselves are not needed ///@param[in] doubles:Pairs of CC_Pairs (GS or Response) + ///@param info ///@param[out] \f$ ( 4_2 - 2_1 - 2_2 + _1 ) \f$ /// Q-Projector is not applied, sign is correct - vector_real_function_3d - s4c(const CC_vecfunction& singles, const Pairs& doubles) const; + static vector_real_function_3d + s4c(World& world, const CC_vecfunction& singles, const Pairs& doubles, const Info& info); // update the intermediates void update_intermediates(const CC_vecfunction& t) { diff --git a/src/madness/chem/correlationfactor.cc b/src/madness/chem/correlationfactor.cc index def3c837957..9f34b498a1e 100644 --- a/src/madness/chem/correlationfactor.cc +++ b/src/madness/chem/correlationfactor.cc @@ -37,6 +37,7 @@ namespace madness{ /// create and return a new nuclear correlation factor + /// note there is also an Ad-hoc nuclear correlation factor, which can only be created directly /// @param[in] world the world /// @param[in] calc the calculation as read from the input file /// @return a nuclear correlation factor diff --git a/src/madness/chem/correlationfactor.h b/src/madness/chem/correlationfactor.h index 65e75178d18..d80ff48586c 100644 --- a/src/madness/chem/correlationfactor.h +++ b/src/madness/chem/correlationfactor.h @@ -83,7 +83,7 @@ namespace madness { class NuclearCorrelationFactor { public: enum corrfactype {None, GradientalGaussSlater, GaussSlater, LinearSlater, - Polynomial, Slater, poly4erfc, Two}; + Polynomial, Slater, poly4erfc, Two, Adhoc}; typedef std::shared_ptr< FunctionFunctorInterface > functorT; /// ctor @@ -213,12 +213,14 @@ class NuclearCorrelationFactor { /// the molecule const Molecule& molecule; +protected: /// the three components of the U1 potential std::vector U1_function; /// the purely local U2 potential, having absorbed the nuclear pot V_nuc real_function_3d U2_function; +private: /// the correlation factor S wrt a given atom /// @param[in] r the distance of the req'd coord to the nucleus @@ -2032,6 +2034,65 @@ class PseudoNuclearCorrelationFactor : public NuclearCorrelationFactor { }; +/// this ncf has no information about itself, only U2 and U1 assigned +class AdhocNuclearCorrelationFactor : public NuclearCorrelationFactor { + +public: + /// ctor + + /// @param[in] world the world + /// @param[in] mol molecule with the sites of the nuclei + AdhocNuclearCorrelationFactor(World& world, const real_function_3d U2, + const std::vector& U1) + : NuclearCorrelationFactor(world,Molecule()) { + + U2_function=U2; + U1_function=U1; + + if (world.rank()==0) { + print("constructed ad hoc nuclear correlation factor"); + } + } + + corrfactype type() const {return Adhoc;} + +private: + + double Sr_div_S(const double& r, const double& Z) const { + MADNESS_EXCEPTION("no Sr_div_S() in AdhocNuclearCorrelationFactor",0); + return 0.0; + } + + double Srr_div_S(const double& r, const double& Z) const { + MADNESS_EXCEPTION("no Srr_div_S() in AdhocNuclearCorrelationFactor",0); + return 0.0; + } + + double Srrr_div_S(const double& r, const double& Z) const { + MADNESS_EXCEPTION("no Srrr_div_S() in AdhocNuclearCorrelationFactor",0); + return 0.0; + } + + /// the nuclear correlation factor + double S(const double& r, const double& Z) const { + MADNESS_EXCEPTION("no S() in AdhocNuclearCorrelationFactor",0); + return 0.0; + } + + /// radial part first derivative of the nuclear correlation factor + coord_3d Sp(const coord_3d& vr1A, const double& Z) const { + MADNESS_EXCEPTION("no Sp() in AdhocNuclearCorrelationFactor",0); + return coord_3d(0.0); + } + + /// second derivative of the nuclear correlation factor + double Spp_div_S(const double& r, const double& Z) const { + MADNESS_EXCEPTION("no Spp_div_S() in AdhocNuclearCorrelationFactor",0); + return 0.0; + } +}; + + std::shared_ptr create_nuclear_correlation_factor(World& world, const Molecule& molecule, From ca2eeb58542bc4a3ac7c21e7e41287773828f816 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Thu, 11 Jul 2024 10:41:55 +0200 Subject: [PATCH 15/54] checkpoint: iterate_cc2_singles is now static --- src/madness/chem/CC2.cc | 90 +++++++++++++++---------------- src/madness/chem/CC2.h | 92 ++++++++++++++++---------------- src/madness/chem/CCPotentials.cc | 61 +++++++++++++++++++-- src/madness/chem/CCPotentials.h | 23 +++++++- 4 files changed, 169 insertions(+), 97 deletions(-) diff --git a/src/madness/chem/CC2.cc b/src/madness/chem/CC2.cc index 0cf7bb1390a..82cff04c1d3 100644 --- a/src/madness/chem/CC2.cc +++ b/src/madness/chem/CC2.cc @@ -54,7 +54,7 @@ CC2::solve() { // check for restart data for CC2, otherwise use MP2 as guess if (need_cc2) { Pairs dummypairs; - bool found_cc2d = initialize_pairs(dummypairs, GROUND_STATE, CT_CC2, cc2singles, CC_vecfunction(RESPONSE)); + bool found_cc2d = initialize_pairs(dummypairs, GROUND_STATE, CT_CC2, cc2singles, CC_vecfunction(RESPONSE), 0, CCOPS.info); if (not found_cc2d) need_mp2=true; } @@ -66,7 +66,7 @@ CC2::solve() { } if (need_mp2) { - bool restarted=initialize_pairs(mp2pairs, GROUND_STATE, CT_MP2, CC_vecfunction(PARTICLE), CC_vecfunction(RESPONSE), 0); + bool restarted=initialize_pairs(mp2pairs, GROUND_STATE, CT_MP2, CC_vecfunction(PARTICLE), CC_vecfunction(RESPONSE), 0, CCOPS.info); if (restarted and parameters.no_compute_mp2()) { // for (auto& pair : mp2pairs.allpairs) mp2_energy+=CCOPS.compute_pair_correlation_energy(pair.second); } else { @@ -83,7 +83,7 @@ CC2::solve() { if (need_cc2) { // check if singles or/and doubles to restart are there initialize_singles(cc2singles, PARTICLE); - const bool load_doubles = initialize_pairs(cc2pairs, GROUND_STATE, CT_CC2, cc2singles, CC_vecfunction(RESPONSE), 0); + const bool load_doubles = initialize_pairs(cc2pairs, GROUND_STATE, CT_CC2, cc2singles, CC_vecfunction(RESPONSE), 0, CCOPS.info); // nothing to restart -> make MP2 if (not load_doubles) { @@ -138,7 +138,7 @@ CC2::solve() { iterate_ccs_singles(ccs, CCOPS.info); Pairs cispd; - initialize_pairs(cispd, EXCITED_STATE, CT_CISPD, CC_vecfunction(PARTICLE), ccs, excitation); + initialize_pairs(cispd, EXCITED_STATE, CT_CISPD, CC_vecfunction(PARTICLE), ccs, excitation, CCOPS.info); const double ccs_omega = ccs.omega; const double cispd_omega = solve_cispd(cispd, mp2pairs, ccs); @@ -188,8 +188,7 @@ CC2::solve() { output("Changes not stored!"); Pairs xpairs; - const bool restart = initialize_pairs(xpairs, EXCITED_STATE, CT_ADC2, CC_vecfunction(PARTICLE), ccs, - excitation); + const bool restart = initialize_pairs(xpairs, EXCITED_STATE, CT_ADC2, CC_vecfunction(PARTICLE), ccs, excitation, CCOPS.info); // if no restart: Calculate CIS(D) as first guess const double ccs_omega = ccs.omega; @@ -197,7 +196,7 @@ CC2::solve() { if (not restart) { output.section("No Restart-Pairs found: Calculating CIS(D) as first Guess"); Pairs cispd; - initialize_pairs(cispd, EXCITED_STATE, CT_CISPD, CC_vecfunction(PARTICLE), ccs, excitation); + initialize_pairs(cispd, EXCITED_STATE, CT_CISPD, CC_vecfunction(PARTICLE), ccs, excitation, CCOPS.info); cispd_omega = solve_cispd(cispd, mp2pairs, ccs); for (auto& tmp:cispd.allpairs) { const size_t i = tmp.first.first; @@ -270,9 +269,9 @@ CC2::solve() { Pairs lrcc2_d; - bool found_lrcc2d = initialize_pairs(lrcc2_d, EXCITED_STATE, CT_LRCC2, cc2singles, lrcc2_s, excitation); + bool found_lrcc2d = initialize_pairs(lrcc2_d, EXCITED_STATE, CT_LRCC2, cc2singles, lrcc2_s, excitation, CCOPS.info); - if (found_lrcc2d) iterate_lrcc2_singles(cc2singles, cc2pairs, lrcc2_s, lrcc2_d, CCOPS.info); + if (found_lrcc2d) iterate_lrcc2_singles(world, cc2singles, cc2pairs, lrcc2_s, lrcc2_d, CCOPS.info); else iterate_ccs_singles(lrcc2_s, CCOPS.info); const double omega_cis = lrcc2_s.omega; CCOPS.info.intermediate_potentials=CCOPS.get_potentials; // update applied singles potentials @@ -280,7 +279,8 @@ CC2::solve() { for (size_t iter = 0; iter < parameters.iter_max(); iter++) { output.section("Macroiteration " + std::to_string(int(iter)) + " of LRCC2"); bool dconv = iterate_lrcc2_pairs(cc2singles, cc2pairs, lrcc2_s, lrcc2_d, CCOPS.info); - bool sconv = iterate_lrcc2_singles(cc2singles, cc2pairs, lrcc2_s, lrcc2_d, CCOPS.info); + bool sconv = iterate_lrcc2_singles(world, cc2singles, cc2pairs, lrcc2_s, lrcc2_d, CCOPS.info); + print_header1("update doubles with the converged singles"); if (dconv and sconv) break; } const double omega_cc2 = lrcc2_s.omega; @@ -700,28 +700,27 @@ CC2::solve_cc2(CC_vecfunction& singles, Pairs& doubles) { MADNESS_ASSERT(singles.type == PARTICLE); CCOPS.update_intermediates(singles); - output.section("Solve CC2 Ground State"); CCTimer time(world, "CC2 Ground State"); - double omega = CCOPS.compute_cc2_correlation_energy(singles, doubles); - if (world.rank() == 0) - std::cout << std::fixed << std::setprecision(10) << "Current Correlation Energy = " << omega << "\n"; - CC_vecfunction ex_singles_dummy; - vector_real_function_3d empty(CCOPS.mo_ket().size()-parameters.freeze()); + // Info keeps important data from the reference: mos, ncf, etc Info info; info=CCOPS.update_info(parameters,nemo); info.intermediate_potentials=CCIntermediatePotentials(parameters); - info.intermediate_potentials.insert(empty,singles,POT_singles_); // initialize with empty vector + + double omega = CCPotentials::compute_cc2_correlation_energy(world, singles, doubles, info); + if (world.rank() == 0) + std::cout << std::fixed << std::setprecision(10) << "Current Correlation Energy = " << omega << "\n"; + CC_vecfunction ex_singles_dummy; if (not parameters.no_compute_cc2()) { // first singles iteration output.section("Initialize Singles to the Doubles"); - iterate_cc2_singles(singles, doubles, info); - // nasty hack - info.intermediate_potentials=CCOPS.get_potentials; - info.intermediate_potentials.parameters=parameters; - // update correlation energy - omega = CCOPS.compute_cc2_correlation_energy(singles, doubles); + + // given the doubles, we can solve the singles equations + iterate_cc2_singles(world, singles, doubles, info); + // the doubles ansatz depends on the singles and must be updated: |\tau_ij> = |u_ij> + Q12 f12 |t_i t_j> + update_reg_residues_gs(world, singles, doubles, info); + omega = CCPotentials::compute_cc2_correlation_energy(world, singles, doubles, info); for (size_t iter = 0; iter < parameters.iter_max(); iter++) { CCTimer time_miter(world, "Macroiteration " + std::to_string(int(iter)) + " of CC2"); @@ -757,7 +756,7 @@ CC2::solve_cc2(CC_vecfunction& singles, Pairs& doubles) { std::vector vdummy_3d; // dummy vectors const std::size_t maxiter=3; auto unew = task1(pair_vec, coupling_vec, singles, dummy_ex_singles, - CCOPS.info, maxiter); + info, maxiter); std::vector u_old; for (auto p : pair_vec) u_old.push_back(p.function()); @@ -771,12 +770,10 @@ CC2::solve_cc2(CC_vecfunction& singles, Pairs& doubles) { bool doubles_converged=rmsrnorm& doubles) { time_miter.info(); } - omega = CCOPS.compute_cc2_correlation_energy(singles, doubles); + omega = CCPotentials::compute_cc2_correlation_energy(world, singles, doubles, info); output.section("CC2 Iterations Eneded"); } else { output.section("Found no_compute_cc2 Key: Reiterating Singles to check convergence"); // need the singles potential for the constant part of LRCC2 so we recompute it (also good to check if it is converged) - bool sconv = iterate_cc2_singles(singles, doubles, CCOPS.info); + bool sconv = iterate_cc2_singles(world, singles, doubles, info); if (not sconv) output.warning("Singles not Converged"); } @@ -826,7 +823,7 @@ CC2::solve_lrcc2(const Pairs& gs_doubles, const CC_vecfunction& gs_singl const std::size_t excitation) const { Pairs ex_doubles; - initialize_pairs(ex_doubles, EXCITED_STATE, CT_LRCC2, gs_singles, cis, excitation); + initialize_pairs(ex_doubles, EXCITED_STATE, CT_LRCC2, gs_singles, cis, excitation, CCOPS.info); auto all_doubles_present =[&]() { for (const auto& p : ex_doubles.allpairs) { @@ -996,7 +993,7 @@ CC2::initialize_singles(CC_vecfunction& singles, const FuncType type, const int bool CC2::initialize_pairs(Pairs& pairs, const CCState ftype, const CalcType ctype, const CC_vecfunction& tau, - const CC_vecfunction& x, const size_t excitation) const { + const CC_vecfunction& x, const size_t excitation, const Info& info) const { MADNESS_ASSERT(tau.type == PARTICLE); MADNESS_ASSERT(x.type == RESPONSE); MADNESS_ASSERT(pairs.empty()); @@ -1014,7 +1011,9 @@ CC2::initialize_pairs(Pairs& pairs, const CCState ftype, const CalcType if (found) restarted = true; // if a single pair was found then the calculation is not from scratch real_function_6d const_part; CCOPS.load_function(const_part, name + "_const"); - CCPair tmp = CCOPS.make_pair_gs(utmp, tau, i, j); + CCPair tmp; + if (ctype==CT_MP2) tmp=CCPotentials::make_pair_mp2(utmp, i, j, info); + if (ctype==CT_CC2) tmp=CCPotentials::make_pair_cc2(utmp, tau, i, j, info); tmp.constant_part = const_part; pairs.insert(i, j, tmp); @@ -1035,30 +1034,27 @@ CC2::initialize_pairs(Pairs& pairs, const CCState ftype, const CalcType return restarted; } -void CC2::update_reg_residues_gs(const CC_vecfunction& singles, Pairs& doubles) const { +void CC2::update_reg_residues_gs(World& world, const CC_vecfunction& singles, Pairs& doubles, const Info& info) +{ CCTimer time(world, "Updated Regularization Residues of the Ground State"); MADNESS_ASSERT(singles.type == PARTICLE); Pairs updated_pairs; - // output("Correlation energy with old pairs"); - // CCOPS.compute_cc2_correlation_energy(singles,doubles); for (auto& tmp:doubles.allpairs) { MADNESS_ASSERT(tmp.second.type == GROUND_STATE); CCPair& pair = tmp.second; const size_t i = pair.i; const size_t j = pair.j; - const CCPair updated_pair = CCOPS.make_pair_gs(pair.function(), singles, i, j); + // const CCPair updated_pair = CCOPS.make_pair_gs(pair.function(), singles, i, j); + const CCPair updated_pair = CCPotentials::make_pair_cc2(pair.function(), singles, i, j, info); updated_pairs.insert(i, j, updated_pair); } - // output("Correlation energy with updated pairs"); - // CCOPS.compute_cc2_correlation_energy(singles,updated_pairs); doubles.swap(updated_pairs); - // output("Correlation energy with swapped pairs"); - // CCOPS.compute_cc2_correlation_energy(singles,updated_pairs); time.info(); } -void CC2::update_reg_residues_ex(const CC_vecfunction& singles, const CC_vecfunction& response, - Pairs& doubles) const { +void CC2::update_reg_residues_ex(World& world, const CC_vecfunction& singles, + const CC_vecfunction& response, Pairs& doubles, const Info& info) +{ CCTimer time(world, "Updated Regularization Residues of the Excited State"); MADNESS_ASSERT(singles.type == PARTICLE); MADNESS_ASSERT(response.type == RESPONSE); @@ -1066,10 +1062,10 @@ void CC2::update_reg_residues_ex(const CC_vecfunction& singles, const CC_vecfunc for (auto& tmp:doubles.allpairs) { MADNESS_ASSERT(tmp.second.type == EXCITED_STATE); CCPair& pair = tmp.second; - const size_t i = pair.i; - const size_t j = pair.j; - CCPair updated_pair = CCOPS.make_pair_ex(pair.function(), singles, response, i, j, pair.ctype); - updated_pairs.insert(i, j, updated_pair); + // CCPair updated_pair = CCPotentials::make_pair_ex(pair.function(), singles, response, i, j, pair.ctype); + CCPair updated_pair = + CCPotentials::make_pair_lrcc2(pair.function(), singles, response, pair.i, pair.j, info); + updated_pairs.insert(pair.i, pair.j, updated_pair); } doubles.swap(updated_pairs); time.info(); diff --git a/src/madness/chem/CC2.h b/src/madness/chem/CC2.h index a3069abe0cd..65945872ba2 100644 --- a/src/madness/chem/CC2.h +++ b/src/madness/chem/CC2.h @@ -177,12 +177,13 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { /// convencience function to iterate the CC2 ground state singles, /// makes the right call on the iterate_singles functions - bool - iterate_cc2_singles(CC_vecfunction& singles, Pairs& doubles, Info& info) { + static bool + iterate_cc2_singles(World& world, CC_vecfunction& singles, Pairs& doubles, Info& info) { // CCOPS.clear_potentials(singles); info.intermediate_potentials.clear_all(); Pairs empty; - return iterate_singles(world, singles, CC_vecfunction(RESPONSE), doubles, empty, CT_CC2, parameters.iter_max_3D(), info); + return iterate_singles(world, singles, CC_vecfunction(RESPONSE), doubles, + empty, CT_CC2, info.parameters.iter_max_3D(), info); } bool @@ -193,13 +194,14 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { return iterate_singles(world, singles, CC_vecfunction(UNDEFINED), mp2, x, CT_ADC2, parameters.iter_max_3D(), info); } - bool - iterate_lrcc2_singles(CC_vecfunction& cc2_s, Pairs& cc2_d, CC_vecfunction& lrcc2_s, Pairs lrcc2_d, Info& info) { + static bool + iterate_lrcc2_singles(World& world, CC_vecfunction& cc2_s, Pairs& cc2_d, CC_vecfunction& lrcc2_s, Pairs lrcc2_d, Info& info) { MADNESS_ASSERT(cc2_s.type == PARTICLE); MADNESS_ASSERT(lrcc2_s.type == RESPONSE); info.intermediate_potentials.clear_response(); // CCOPS.clear_potentials(lrcc2_s); - return iterate_singles(world, lrcc2_s, cc2_s, cc2_d, lrcc2_d, CT_LRCC2, parameters.iter_max_3D(), info); + return iterate_singles(world, lrcc2_s, cc2_s, cc2_d, lrcc2_d, + CT_LRCC2, info.parameters.iter_max_3D(), info); } /// convencience function to iterate the CCS Response singles, @@ -212,7 +214,7 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { return iterate_singles(world, x, CC_vecfunction(PARTICLE), empty, empty, CT_LRCCS, 1, info); } - bool + static bool /// Iterates the singles equations for CCS, CC2, LRCC2 /// The corresponding regulairzation tails of the doubles are updated in every iteration (therefore doubles are not marked as const) /// @param[in] : singles, the singles that are iterated @@ -224,6 +226,7 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { /// @param[out]: true if the overall change of the singles is below 10*donv_6D iterate_singles(World& world, CC_vecfunction& singles, const CC_vecfunction singles2, Pairs& gs_doubles, Pairs& ex_doubles, const CalcType ctype, const std::size_t maxiter, Info& info) { + CCMessenger output(world); output.subsection("Iterate " + assign_name(ctype) + "-Singles"); CCTimer time_all(world, "Overall Iteration of " + assign_name(ctype) + "-Singles"); bool converged = true; @@ -278,10 +281,10 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { CCTimer time_V(world, assign_name(ctype) + "-Singles Potential"); vector_real_function_3d V; if (ctype == CT_CC2) V = CCPotentials::get_CC2_singles_potential_gs(world, singles, gs_doubles, info); - else if (ctype == CT_LRCC2) - V = CCOPS.get_CC2_singles_potential_ex(world, singles2, gs_doubles, singles, ex_doubles, info); - else if (ctype == CT_LRCCS) V = CCOPS.get_CCS_potential_ex(world,singles,false, info); - else if (ctype == CT_ADC2) V = CCOPS.get_ADC2_singles_potential(world, gs_doubles, singles, ex_doubles, info); +// else if (ctype == CT_LRCC2) +// V = CCOPS.get_CC2_singles_potential_ex(world, singles2, gs_doubles, singles, ex_doubles, info); +// else if (ctype == CT_LRCCS) V = CCOPS.get_CCS_potential_ex(world,singles,false, info); +// else if (ctype == CT_ADC2) V = CCOPS.get_ADC2_singles_potential(world, gs_doubles, singles, ex_doubles, info); else MADNESS_EXCEPTION("iterate singles: unknown type", 1); time_V.info(true, norm2(world, V)); @@ -296,9 +299,9 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { CCTimer time_makebsh(world, "Make G-Operators"); std::vector > > G(singles.size()); for (size_t i = 0; i < G.size(); i++) { - const double bsh_eps = CCOPS.get_orbital_energies()[i + parameters.freeze()] + omega; + const double bsh_eps = info.orbital_energies[i + info.parameters.freeze()] + omega; G[i] = std::shared_ptr >( - BSHOperatorPtr3D(world, sqrt(-2.0 * bsh_eps), parameters.lo(), parameters.thresh_bsh_3D())); + BSHOperatorPtr3D(world, sqrt(-2.0 * bsh_eps), info.parameters.lo(), info.parameters.thresh_bsh_3D())); } world.gop.fence(); time_makebsh.info(); @@ -310,17 +313,14 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { time_applyG.info(); // apply Q-Projector to result - GV = CCOPS.apply_Qt(GV, CCOPS.mo_ket()); + QProjector Q(info.mo_bra,info.mo_ket); + // GV = CCOPS.apply_Qt(GV, CCOPS.mo_ket()); + GV = Q(GV); // Normalize Singles if it is excited state if (ctype == CT_LRCCS or ctype == CT_LRCC2 or ctype == CT_ADC2) { output("Normalizing new singles"); - const vector_real_function_3d x = GV; - const vector_real_function_3d xbra = mul(world, nemo->ncf->square(), GV); - const double norm = sqrt(inner(world, xbra, x).sum()); - if (world.rank() == 0) - std::cout << " Norm was " << std::fixed << std::setprecision(parameters.output_prec()) << norm - << "\n"; + const double norm=inner(GV,info.R_square*GV); scale(world, GV, 1.0 / norm); } else output("Singles not normalized"); @@ -328,10 +328,10 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { const vector_real_function_3d residual = sub(world, singles.get_vecfunction(), GV); // information - const Tensor R2xinnerx = inner(world, mul(world, nemo->ncf->square(), singles.get_vecfunction()), + const Tensor R2xinnerx = inner(world, info.R_square*singles.get_vecfunction(), singles.get_vecfunction()); - const Tensor R2GVinnerGV = inner(world, mul(world, nemo->ncf->square(), GV), GV); - const Tensor R2rinnerr = inner(world, mul(world, nemo->ncf->square(), residual), residual); + const Tensor R2GVinnerGV = inner(world, info.R_square*GV, GV); + const Tensor R2rinnerr = inner(world, info.R_square*residual, residual); const double R2vector_error = sqrt(R2rinnerr.sum()); // print information @@ -339,13 +339,13 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { if (world.rank() == 0) std::cout << "\nName: ||" << singles.name(0) << "||, ||GV" << singles.name(0) << ", ||residual||" << "\n"; if (world.rank() == 0) - std::cout << singles.name(0) << ": " << std::scientific << std::setprecision(parameters.output_prec()) + std::cout << singles.name(0) << ": " << std::scientific << std::setprecision(info.parameters.output_prec()) << sqrt(R2xinnerx.sum()) << ", " << sqrt(R2GVinnerGV.sum()) << ", " << sqrt(R2rinnerr.sum()) << "\n----------------------------------------\n"; for (size_t i = 0; i < GV.size(); i++) { if (world.rank() == 0) - std::cout << singles(i + parameters.freeze()).name() << ": " << std::scientific - << std::setprecision(parameters.output_prec()) + std::cout << singles(i + info.parameters.freeze()).name() << ": " << std::scientific + << std::setprecision(info.parameters.output_prec()) << sqrt(R2xinnerx(i)) << ", " << sqrt(R2GVinnerGV(i)) << ", " << sqrt(R2rinnerr(i)) << "\n"; } @@ -356,16 +356,16 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { output("\nMake 2nd order energy update:"); // include nuclear factors { - vector_real_function_3d bra_res = mul(world, nemo->ncf->square(), residual); - vector_real_function_3d bra_GV = mul(world, nemo->ncf->square(), GV); - double Rtmp = inner(world, bra_res, V).sum(); - double Rtmp2 = inner(world, bra_GV, GV).sum(); + // vector_real_function_3d bra_res = mul(world, nemo->ncf->square(), residual); + // vector_real_function_3d bra_GV = mul(world, nemo->ncf->square(), GV); + double Rtmp = inner(world, info.R_square*residual, V).sum(); + double Rtmp2 = inner(world, info.R_square*GV, GV).sum(); const double Rdelta = (0.5 * Rtmp / Rtmp2); double old_omega = omega; output("Delta-Update is not used"); if (world.rank() == 0) std::cout << "omega, old_omega, delta" << std::fixed - << std::setprecision(parameters.output_prec() + 2) << omega << ", " << old_omega << ", " + << std::setprecision(info.parameters.output_prec() + 2) << omega << ", " << old_omega << ", " << Rdelta << "\n\n"; } @@ -374,22 +374,22 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { // update singles singles.omega = omega; vector_real_function_3d new_singles = GV; - if (parameters.kain()) new_singles = solver.update(singles.get_vecfunction(), residual); + if (info.parameters.kain()) new_singles = solver.update(singles.get_vecfunction(), residual); print_size(world, new_singles, "new_singles"); truncate(world, new_singles); print_size(world, new_singles, "new_singles"); for (size_t i = 0; i < GV.size(); i++) { - singles(i + parameters.freeze()).function = copy(new_singles[i]); + singles(i + info.parameters.freeze()).function = copy(new_singles[i]); } // update intermediates - CCOPS.update_intermediates(singles); + // CCOPS.update_intermediates(singles); // update reg_residues of doubles - //if(ctype==CC2_) update_reg_residues_gs(singles,gs_doubles); - //else if(ctype==LRCC2_) update_reg_residues_ex(singles2,singles,ex_doubles); + if (ctype==CT_CC2) update_reg_residues_gs(world, singles,gs_doubles, info); + else if(ctype==CT_LRCC2) update_reg_residues_ex(world, singles2,singles,ex_doubles, info); - converged = (R2vector_error < parameters.dconv_3D()); + converged = (R2vector_error < info.parameters.dconv_3D()); time.info(); if (converged) break; @@ -404,16 +404,16 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { for (auto& tmp : singles.functions) { const double change = (tmp.second.function - old_singles(tmp.first).function).norm2(); tmp.second.current_error = change; - if (change > parameters.dconv_3D()) no_change = false; + if (change > info.parameters.dconv_3D()) no_change = false; if (world.rank() == 0) std::cout << "Change of " << tmp.second.name() << "=" << tmp.second.current_error << std::endl; } // update reg_residues of doubles - if (ctype == CT_CC2) update_reg_residues_gs(singles, gs_doubles); - else if (ctype == CT_LRCC2) update_reg_residues_ex(singles2, singles, ex_doubles); + if (ctype == CT_CC2) update_reg_residues_gs(world, singles, gs_doubles, info); + else if (ctype == CT_LRCC2) update_reg_residues_ex(world, singles2, singles, ex_doubles, info); //CCOPS.plot(singles); - if (no_change) output("Change of Singles was below = " + std::to_string(parameters.dconv_3D()) + "!"); + if (no_change) output("Change of Singles was below = " + std::to_string(info.parameters.dconv_3D()) + "!"); return no_change; } @@ -421,12 +421,14 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { bool initialize_singles(CC_vecfunction& singles, const FuncType type, const int ex = -1) const; bool initialize_pairs(Pairs& pairs, const CCState ftype, const CalcType ctype, const CC_vecfunction& tau, - const CC_vecfunction& x, const size_t extitation = 0) const; + const CC_vecfunction& x, const size_t extitation, const Info& info) const; - void update_reg_residues_gs(const CC_vecfunction& singles, Pairs& doubles) const; + static void + update_reg_residues_gs(World& world, const CC_vecfunction& singles, Pairs& doubles, const Info& info); - void - update_reg_residues_ex(const CC_vecfunction& singles, const CC_vecfunction& response, Pairs& doubles) const; + static void + update_reg_residues_ex(World& world, const CC_vecfunction& singles, const CC_vecfunction& response, Pairs& doubles, + const Info& info); /// Iterates a pair of the CC2 doubles equations bool diff --git a/src/madness/chem/CCPotentials.cc b/src/madness/chem/CCPotentials.cc index 87b8e9e5a0c..adb68396f33 100644 --- a/src/madness/chem/CCPotentials.cc +++ b/src/madness/chem/CCPotentials.cc @@ -72,6 +72,60 @@ CCPotentials::init_orbital_energies(const Nemo& nemo) const { return eps; } +CCPair CCPotentials::make_pair_mp2(const real_function_6d& u, const size_t i, const size_t j, const Info& info) { + World& world=u.world(); + + // construct Q12 f12 |ij> + auto phi=info.mo_ket; + auto phi_bra=info.mo_bra; + StrongOrthogonalityProjector Q12(world); + Q12.set_spaces(phi_bra,phi,phi_bra,phi); + + auto f12=CCConvolutionOperatorPtr(world,OT_F12,info.parameters); + CCPairFunction fij(f12, phi[i], phi[j]); + std::vector> tmp=Q12(std::vector>(1,fij)); + + // first term is the 6d function u, then follows Q12 f12 |ij> + std::vector> functions; + functions+=CCPairFunction(u); + functions+=tmp; + + auto pair=CCPair(i,j,GROUND_STATE,CT_MP2,functions); + pair.bsh_eps=get_epsilon(i,j,info); + return pair; +} + +CCPair CCPotentials::make_pair_cc2(const real_function_6d& u, const CC_vecfunction& gs_singles, const size_t i, const size_t j, + const Info& info) { + World& world=u.world(); + + // construct Q12 f12 |ij> + auto phi=info.mo_ket; + auto phi_bra=info.mo_bra; + auto t=make_full_t_intermediate(gs_singles,info).get_vecfunction(); + StrongOrthogonalityProjector Q12(world); + Q12.set_spaces(phi_bra,t,phi_bra,t); + + auto f12=CCConvolutionOperatorPtr(world,OT_F12,info.parameters); + CCPairFunction fij(f12, t[i], t[j]); + std::vector> tmp=Q12(std::vector>(1,fij)); + + // first term is the 6d function u, then follows Q12 f12 |ij> + std::vector> functions; + functions+=CCPairFunction(u); + functions+=tmp; + + auto pair=CCPair(i,j,GROUND_STATE,CT_CC2,functions); + pair.bsh_eps=get_epsilon(i,j,info); + return pair; +} + +CCPair CCPotentials::make_pair_lrcc2(const real_function_6d& u, const CC_vecfunction& gs_singles, const CC_vecfunction& ex_singles, + const size_t i, const size_t j, const Info& info) { + MADNESS_EXCEPTION("CCPotentials::make_pair_lrcc2 not yet implemented",1); + return CCPair(); +} + madness::CCPair CCPotentials::make_pair_gs(const real_function_6d& u, const CC_vecfunction& tau, const size_t i, const size_t j) const { CCTimer time(world, "make pair u" + std::to_string(int(i)) + std::to_string(int(j))); @@ -359,10 +413,11 @@ CCPotentials::compute_pair_correlation_energy(World& world, const Info& info, } double -CCPotentials::compute_cc2_correlation_energy(const CC_vecfunction& singles, const Pairs& doubles) const { +CCPotentials::compute_cc2_correlation_energy(World& world, const CC_vecfunction& singles, const Pairs& doubles, const Info& info) +{ MADNESS_ASSERT(singles.type == PARTICLE); CCTimer time(world, "Computing CC2 Correlation Energy"); - output.section("Computing CC2 Correlation Energy"); + // output.section("Computing CC2 Correlation Energy"); double result = 0.0; for (const auto& tmp : doubles.allpairs) { const size_t i = tmp.second.i; @@ -2756,7 +2811,7 @@ CCPotentials::get_CC2_singles_potential_gs(World& world, const CC_vecfunction& s { CCTimer time(world, "CC2 Singles potential"); vector_real_function_3d fock_residue = potential_singles_gs(world, singles, doubles, POT_F3D_, info); - Projector Otau(info.mo_bra, singles.get_vecfunction()); + Projector Otau(info.get_active_mo_bra(), singles.get_vecfunction()); QProjector Q(info.mo_bra, info.mo_ket); // CC2 Singles potential: Q(S4c) + Qt(ccs+s2b+s2c) vector_real_function_3d Vccs = potential_singles_gs(world, singles, doubles, POT_ccs_, info); diff --git a/src/madness/chem/CCPotentials.h b/src/madness/chem/CCPotentials.h index 1df14bafaf5..5ec455427c3 100644 --- a/src/madness/chem/CCPotentials.h +++ b/src/madness/chem/CCPotentials.h @@ -39,6 +39,7 @@ class CCPotentials { info.U1=nemo->ncf->U1vec(); info.U2=nemo->ncf->U2(); info.intermediate_potentials=get_potentials; + info.orbital_energies=orbital_energies_; return info; } @@ -98,6 +99,11 @@ class CCPotentials { return orbital_energies_[i] + orbital_energies_[j]; } + /// returns epsilon_i + epsilon_j (needed for bsh operator of pairs) + static double get_epsilon(const size_t i, const size_t j, const Info& info) { + return info.orbital_energies[i] + info.orbital_energies[j]; + } + /// returns a vector of all active mos without nuclear correlation factor (nemos) vector_real_function_3d get_active_mo_ket() const { vector_real_function_3d result; @@ -193,6 +199,17 @@ class CCPotentials { public: + /// return the regularized MP2 ansatz: |\tau_ij> = |u_ij> + Q12 f12 |ij> + static CCPair make_pair_mp2(const real_function_6d& u, const size_t i, const size_t j, const Info& info); + + /// return the regularized CC2 ansatz: |\tau_ij> = |u_ij> + Q12t f12 |t_i t_j> + static CCPair make_pair_cc2(const real_function_6d& u, const CC_vecfunction& gs_singles, + const size_t i, const size_t j, const Info& info); + + /// return the regularized CC2 ansatz: |x_ij> = |u_ij> + Q12t f12 |t_i t_j> + ????? + static CCPair make_pair_lrcc2(const real_function_6d& u, const CC_vecfunction& gs_singles, + const CC_vecfunction& ex_singles, const size_t i, const size_t j, const Info& info); + // Pair functions /// creates pair functions for ground states @@ -245,8 +262,10 @@ class CCPotentials { /// @param[out] \sum_{ij} 2* - + 2* - , where i and j are determined by u (see CC_Pair class) /// since we do not compute all pairs (symmetry reasons) the off diagonal pair energies are conted twice /// the cc2 pair functions are dependent on the doubles (see CC_Pair structure, and make_pair function) so make shure they are updated - double - compute_cc2_correlation_energy(const CC_vecfunction& singles, const Pairs& doubles) const; + /// @param world + /// @param info + static double + compute_cc2_correlation_energy(World& world, const CC_vecfunction& singles, const Pairs& doubles, const Info& info); double From 2cceb8f82fdcd5964d99f8056b45a23809363c5b Mon Sep 17 00:00:00 2001 From: fbischoff Date: Fri, 12 Jul 2024 09:29:44 +0200 Subject: [PATCH 16/54] checkpoint --- src/madness/chem/CC2.cc | 224 +++++++++++++++++++------------ src/madness/chem/CC2.h | 22 +-- src/madness/chem/CCPotentials.cc | 66 +++++---- src/madness/chem/CCPotentials.h | 18 +-- 4 files changed, 198 insertions(+), 132 deletions(-) diff --git a/src/madness/chem/CC2.cc b/src/madness/chem/CC2.cc index 82cff04c1d3..e6d4f70846d 100644 --- a/src/madness/chem/CC2.cc +++ b/src/madness/chem/CC2.cc @@ -32,8 +32,11 @@ CC2::solve() { CCOPS.reset_nemo(nemo); CCOPS.get_potentials.parameters=parameters; CCOPS.update_intermediates(CCOPS.mo_ket()); + // info keep information on the MOs and the molecular coordinates - CCOPS.info=CCOPS.update_info(parameters,nemo); + Info info; + info=CCOPS.update_info(parameters,nemo); + info.intermediate_potentials=CCIntermediatePotentials(parameters); // doubles for ground state Pairs mp2pairs, cc2pairs; @@ -54,7 +57,7 @@ CC2::solve() { // check for restart data for CC2, otherwise use MP2 as guess if (need_cc2) { Pairs dummypairs; - bool found_cc2d = initialize_pairs(dummypairs, GROUND_STATE, CT_CC2, cc2singles, CC_vecfunction(RESPONSE), 0, CCOPS.info); + bool found_cc2d = initialize_pairs(dummypairs, GROUND_STATE, CT_CC2, cc2singles, CC_vecfunction(RESPONSE), 0, info); if (not found_cc2d) need_mp2=true; } @@ -66,11 +69,11 @@ CC2::solve() { } if (need_mp2) { - bool restarted=initialize_pairs(mp2pairs, GROUND_STATE, CT_MP2, CC_vecfunction(PARTICLE), CC_vecfunction(RESPONSE), 0, CCOPS.info); + bool restarted=initialize_pairs(mp2pairs, GROUND_STATE, CT_MP2, CC_vecfunction(PARTICLE), CC_vecfunction(RESPONSE), 0, info); if (restarted and parameters.no_compute_mp2()) { // for (auto& pair : mp2pairs.allpairs) mp2_energy+=CCOPS.compute_pair_correlation_energy(pair.second); } else { - mp2_energy = solve_mp2_coupled(mp2pairs); + mp2_energy = solve_mp2_coupled(mp2pairs, info); output_calc_info_schema("mp2",mp2_energy); } output.section(assign_name(CT_MP2) + " Calculation Ended !"); @@ -83,7 +86,7 @@ CC2::solve() { if (need_cc2) { // check if singles or/and doubles to restart are there initialize_singles(cc2singles, PARTICLE); - const bool load_doubles = initialize_pairs(cc2pairs, GROUND_STATE, CT_CC2, cc2singles, CC_vecfunction(RESPONSE), 0, CCOPS.info); + const bool load_doubles = initialize_pairs(cc2pairs, GROUND_STATE, CT_CC2, cc2singles, CC_vecfunction(RESPONSE), 0, info); // nothing to restart -> make MP2 if (not load_doubles) { @@ -95,7 +98,7 @@ CC2::solve() { } } - cc2_energy = solve_cc2(cc2singles, cc2pairs); + cc2_energy = solve_cc2(cc2singles, cc2pairs, info); output_calc_info_schema("cc2",cc2_energy); output.section(assign_name(CT_CC2) + " Calculation Ended !"); @@ -135,10 +138,10 @@ CC2::solve() { CCTimer time_ex(world, "CIS(D) for Excitation " + std::to_string(int(excitation))); // check the convergence of the cis function (also needed to store the ccs potential) and to recalulate the excitation energy - iterate_ccs_singles(ccs, CCOPS.info); + iterate_ccs_singles(ccs, info); Pairs cispd; - initialize_pairs(cispd, EXCITED_STATE, CT_CISPD, CC_vecfunction(PARTICLE), ccs, excitation, CCOPS.info); + initialize_pairs(cispd, EXCITED_STATE, CT_CISPD, CC_vecfunction(PARTICLE), ccs, excitation, info); const double ccs_omega = ccs.omega; const double cispd_omega = solve_cispd(cispd, mp2pairs, ccs); @@ -250,37 +253,36 @@ CC2::solve() { } else if (ctype == CT_LRCC2) { CCTimer time(world, "Whole LRCC2 Calculation"); - std::vector > results; - std::vector > > timings; + std::vector > results; + std::vector > > timings; - auto vccs=solve_ccs(); + auto vccs=solve_ccs(); - std::vector > > results_ex; - for (size_t xxx = 0; xxx < vccs.size(); xxx++) { - const size_t excitation = parameters.excitations()[xxx]; + std::vector > > results_ex; + for (size_t xxx = 0; xxx < vccs.size(); xxx++) { + const size_t excitation = parameters.excitations()[xxx]; CCTimer time_ex(world, "LRCC2 Calculation for Excitation " + std::to_string(int(excitation))); CC_vecfunction lrcc2_s = vccs[xxx]; // needed to assign an omega const vector_real_function_3d backup = copy(world, lrcc2_s.get_vecfunction()); CC_vecfunction test(backup, RESPONSE, parameters.freeze()); - iterate_ccs_singles(test, CCOPS.info); + iterate_ccs_singles(test, info); lrcc2_s.omega = test.omega; output("CCS Iteration: Changes are not applied (just omega)!"); Pairs lrcc2_d; - bool found_lrcc2d = initialize_pairs(lrcc2_d, EXCITED_STATE, CT_LRCC2, cc2singles, lrcc2_s, excitation, CCOPS.info); + bool found_lrcc2d = initialize_pairs(lrcc2_d, EXCITED_STATE, CT_LRCC2, cc2singles, lrcc2_s, excitation, info); - if (found_lrcc2d) iterate_lrcc2_singles(world, cc2singles, cc2pairs, lrcc2_s, lrcc2_d, CCOPS.info); - else iterate_ccs_singles(lrcc2_s, CCOPS.info); + if (found_lrcc2d) iterate_lrcc2_singles(world, cc2singles, cc2pairs, lrcc2_s, lrcc2_d, info); + else iterate_ccs_singles(lrcc2_s, info); const double omega_cis = lrcc2_s.omega; - CCOPS.info.intermediate_potentials=CCOPS.get_potentials; // update applied singles potentials for (size_t iter = 0; iter < parameters.iter_max(); iter++) { output.section("Macroiteration " + std::to_string(int(iter)) + " of LRCC2"); - bool dconv = iterate_lrcc2_pairs(cc2singles, cc2pairs, lrcc2_s, lrcc2_d, CCOPS.info); - bool sconv = iterate_lrcc2_singles(world, cc2singles, cc2pairs, lrcc2_s, lrcc2_d, CCOPS.info); - print_header1("update doubles with the converged singles"); + bool dconv = iterate_lrcc2_pairs(world, cc2singles, lrcc2_s, lrcc2_d, info); + bool sconv = iterate_lrcc2_singles(world, cc2singles, cc2pairs, lrcc2_s, lrcc2_d, info); + update_reg_residues_ex(world, cc2singles, lrcc2_s, lrcc2_d, info); if (dconv and sconv) break; } const double omega_cc2 = lrcc2_s.omega; @@ -383,7 +385,8 @@ Tensor CC2::enforce_core_valence_separation(const Tensor& fmat) }; // Solve the CCS equations for the ground state (debug potential and check HF convergence) -std::vector CC2::solve_ccs() { +std::vector CC2::solve_ccs() const +{ // output.section("SOLVE CCS"); // std::vector excitations; // for (size_t k = 0; k < parameters.excitations().size(); k++) { @@ -405,7 +408,7 @@ std::vector CC2::solve_ccs() { return result; } -double CC2::solve_mp2_coupled(Pairs& doubles) { +double CC2::solve_mp2_coupled(Pairs& doubles, Info& info) { if (world.rank()==0) print_header2(" computing the MP1 wave function"); double total_energy = 0.0; @@ -430,7 +433,7 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { MacroTaskConstantPart t; MacroTask task(world, t); std::vector> gs_singles, ex_singles; // dummy vectors - std::vector result_vec = task(pair_vec, gs_singles, ex_singles, CCOPS.info) ; + std::vector result_vec = task(pair_vec, gs_singles, ex_singles, info) ; if (world.rank()==0) { std::cout << std::fixed << std::setprecision(1) << "\nFinished constant part at time " << wall_time() << std::endl; @@ -447,7 +450,7 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { save(pair_vec[i].constant_part, pair_vec[i].name() + "_const"); // save(pair_vec[i].function(), pair_vec[i].name()); if (pair_vec[i].type == GROUND_STATE) { - double energy = CCOPS.compute_pair_correlation_energy(world,CCOPS.info,pair_vec[i]); + double energy = CCOPS.compute_pair_correlation_energy(world,info,pair_vec[i]); if (world.rank()==0) printf("pair energy for pair %zu %zu: %12.8f\n", pair_vec[i].i, pair_vec[i].j, energy); total_energy += energy; } @@ -484,7 +487,7 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { MacroTask task1(world, t); CC_vecfunction dummy_singles1(PARTICLE); const std::size_t maxiter=1; - auto unew = task1(pair_vec, coupling_vec, dummy_singles1, dummy_singles1, CCOPS.info, maxiter); + auto unew = task1(pair_vec, coupling_vec, dummy_singles1, dummy_singles1, info, maxiter); std::vector u; for (auto p : pair_vec) u.push_back(p.function()); @@ -516,7 +519,7 @@ double CC2::solve_mp2_coupled(Pairs& doubles) { total_energy = 0.0; for (size_t i = 0; i < pair_vec.size(); i++) { save(pair_vec[i].function(), pair_vec[i].name()); - double energy = CCOPS.compute_pair_correlation_energy(world,CCOPS.info,pair_vec[i]); + double energy = CCOPS.compute_pair_correlation_energy(world,info,pair_vec[i]); total_energy += energy; if (world.rank()==0) printf("pair energy for pair %zu %zu: %12.8f\n", pair_vec[i].i, pair_vec[i].j, energy); } @@ -665,48 +668,66 @@ CC2::iterate_adc2_pairs(Pairs& cispd, const CC_vecfunction& ccs) { } bool -CC2::iterate_lrcc2_pairs(const CC_vecfunction& cc2_s, const Pairs& cc2_d, const CC_vecfunction lrcc2_s, - Pairs& lrcc2_d, const Info& info) { - output.section("Solve LRCC2 for Excitation energy " + std::to_string(double(lrcc2_s.omega))); +CC2::iterate_lrcc2_pairs(World& world, const CC_vecfunction& cc2_s, + const CC_vecfunction lrcc2_s, Pairs& lrcc2_d, const Info& info) { + // output.section("Solve LRCC2 for Excitation energy " + std::to_string(double(lrcc2_s.omega))); + print_header2("Solve LRCC2 for Excitation energy " + std::to_string(double(lrcc2_s.omega))); MADNESS_ASSERT(lrcc2_s.type == RESPONSE); - CCOPS.update_intermediates(lrcc2_s); - bool conv = true; - for (auto& tmp:lrcc2_d.allpairs) { - CCPair& pair = tmp.second; - const size_t i = pair.i; - const size_t j = pair.j; - // check if singles have significantly changed - if (lrcc2_s(i).current_error < 0.1 * parameters.thresh_6D() and - lrcc2_s(j).current_error < 0.1 * parameters.thresh_6D()) - output("Skipping Pair Iteration, No significant Change in Singles"); - else { - pair.bsh_eps = CCOPS.get_epsilon(pair.i, pair.j) + lrcc2_s.omega; - // update_constant_part_lrcc2(pair, cc2_s, lrcc2_s); - pair.constant_part=CCPotentials::make_constant_part_macrotask(world, pair, - cc2_s, lrcc2_s, info); - conv = iterate_pair(pair, lrcc2_s); - } - } - return conv; + auto triangular_map=PairVectorMap::triangular_map(info.parameters.freeze(),info.mo_ket.size()); + auto pair_vec=Pairs::pairs2vector(lrcc2_d,triangular_map); + MacroTaskIteratePair t1; + MacroTask task1(world, t1); + std::vector vdummy_3d; // dummy vectors + std::vector vdummy_6d; // dummy vectors + const std::size_t maxiter=3; + auto unew = task1(pair_vec, vdummy_6d, cc2_s, lrcc2_s, info, maxiter); + + // get some statistics + std::vector> uold; + for (const auto & p : pair_vec) uold.push_back(p.function()); + auto residual=uold-unew; + auto [rmsrnorm, rmsrmax] = residual_stats(residual); + + // update the pair functions + for (int i=0; i::vector2pairs(pair_vec,triangular_map); + + return (rmsrnorm& doubles) { +CC2::solve_cc2(CC_vecfunction& singles, Pairs& doubles, Info& info) const +{ output.section("Solving CC2 Ground State"); MADNESS_ASSERT(singles.type == PARTICLE); - CCOPS.update_intermediates(singles); CCTimer time(world, "CC2 Ground State"); - // Info keeps important data from the reference: mos, ncf, etc - Info info; - info=CCOPS.update_info(parameters,nemo); - info.intermediate_potentials=CCIntermediatePotentials(parameters); - double omega = CCPotentials::compute_cc2_correlation_energy(world, singles, doubles, info); if (world.rank() == 0) std::cout << std::fixed << std::setprecision(10) << "Current Correlation Energy = " << omega << "\n"; @@ -819,42 +840,69 @@ CC2::solve_cc2(CC_vecfunction& singles, Pairs& doubles) { /// @param[in] excitation: the excitation number /// @return a tuple with the excited state doubles, the excited state singles and the excitation energy std::tuple, CC_vecfunction, double> -CC2::solve_lrcc2(const Pairs& gs_doubles, const CC_vecfunction& gs_singles, const CC_vecfunction& cis, - const std::size_t excitation) const -{ - Pairs ex_doubles; - initialize_pairs(ex_doubles, EXCITED_STATE, CT_LRCC2, gs_singles, cis, excitation, CCOPS.info); +CC2::solve_lrcc2(Pairs& gs_doubles, const CC_vecfunction& gs_singles, const CC_vecfunction& cis, + const std::size_t excitation, Info& info) const { + CCTimer time(world, "Whole LRCC2 Calculation"); - auto all_doubles_present =[&]() { - for (const auto& p : ex_doubles.allpairs) { - if (not p.second.function().is_initialized()) return false; + std::vector > results; + std::vector > > timings; + std::vector > > results_ex; + + auto vccs=solve_ccs(); + CCTimer time_ex(world, "LRCC2 Calculation for Excitation " + std::to_string(int(excitation))); + CC_vecfunction ex_singles = vccs[excitation]; + // needed to assign an omega + const vector_real_function_3d backup = copy(world, ex_singles.get_vecfunction()); + CC_vecfunction test(backup, RESPONSE, parameters.freeze()); + iterate_ccs_singles(test, info); + ex_singles.omega = test.omega; + output("CCS Iteration: Changes are not applied (just omega)!"); + + + Pairs ex_doubles; + bool found_lrcc2d = initialize_pairs(ex_doubles, EXCITED_STATE, CT_LRCC2, gs_singles, ex_singles, excitation, info); + + if (found_lrcc2d) iterate_lrcc2_singles(world, gs_singles, gs_doubles, ex_singles, ex_doubles, info); + else iterate_ccs_singles(ex_singles, info); + const double omega_cis = ex_singles.omega; + + for (size_t iter = 0; iter < parameters.iter_max(); iter++) { + output.section("Macroiteration " + std::to_string(int(iter)) + " of LRCC2"); + bool dconv = iterate_lrcc2_pairs(world, gs_singles, ex_singles, ex_doubles, info); + bool sconv = iterate_lrcc2_singles(world, gs_singles, gs_doubles, ex_singles, ex_doubles, info); + update_reg_residues_ex(world, gs_singles, ex_singles, ex_doubles, info); + if (dconv and sconv) break; } - return true; - }; + const double omega_cc2 = ex_singles.omega; + const std::string msg = "Excitation " + std::to_string(int(excitation)); + results_ex.push_back(std::make_pair(msg, std::make_pair(omega_cis, omega_cc2))); + timings.push_back(std::make_pair(msg, time_ex.current_time(true))); - double omega_cis=cis.omega; - double omega=0.0; - CC_vecfunction ex_singles=cis.copy(); -// if (all_doubles_present()) { -// iterate_lrcc2_singles(gs_singles, gs_doubles, ex_singles, ex_doubles); -// } else { -// iterate_ccs_singles(ex_singles); -// } -// CCOPS.info.intermediate_potentials=CCOPS.get_potentials; // update applied singles potentials -// -// for (size_t iter = 0; iter < parameters.iter_max(); iter++) { -// output.section("Macroiteration " + std::to_string(int(iter)) + " of LRCC2"); -// bool dconv = iterate_lrcc2_pairs(cc2singles, cc2pairs, lrcc2_s, lrcc2_d, CCOPS.info); -// bool sconv = iterate_lrcc2_singles(cc2singles, cc2pairs, lrcc2_s, lrcc2_d); -// if (dconv and sconv) break; -// } -// const double omega_cc2 = lrcc2_s.omega; -// const std::string msg = "Excitation " + std::to_string(int(excitation)); -// results_ex.push_back(std::make_pair(msg, std::make_pair(omega_cis, omega_cc2))); -// timings.push_back(std::make_pair(msg, time_ex.current_time(true))); + timings.push_back(std::make_pair("Whole LRCC2", time.current_time(true))); + output.section("LRCC2 Finished"); + output("Ground State Results:"); + for (const auto& res:results) { + if (world.rank() == 0) + std::cout << std::fixed << std::setprecision(10) + << res.first << "=" << res.second << "\n"; + } + output("Response Results:"); + for (const auto& res:results_ex) { + if (world.rank() == 0) + std::cout << std::fixed << std::setprecision(10) + << res.first << ": " << res.second.first << " (CIS)*, " << res.second.second << " (CC2)\n"; + } + if (world.rank() == 0) std::cout << "*only if CIS vectors where given in the beginning (not for CC2 restart)\n"; + output("\nTimings"); + for (const auto& time:timings) { + if (world.rank() == 0) + std::cout << std::scientific << std::setprecision(2) + << std::setfill(' ') << std::setw(15) << time.first + << ": " << time.second.first << " (Wall), " << time.second.second << " (CPU)" << "\n"; + } - return std::make_tuple(ex_doubles, ex_singles, omega); + return std::make_tuple(ex_doubles, ex_singles, omega_cc2); }; diff --git a/src/madness/chem/CC2.h b/src/madness/chem/CC2.h index 65945872ba2..401ce42ddac 100644 --- a/src/madness/chem/CC2.h +++ b/src/madness/chem/CC2.h @@ -150,7 +150,7 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { std::vector - solve_ccs(); + solve_ccs() const; double compute_mp3(const Pairs& mp2pairs) const { MP3 mp3(CCOPS); @@ -159,7 +159,7 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { } double - solve_cc2(CC_vecfunction& tau, Pairs& u); + solve_cc2(CC_vecfunction& tau, Pairs& u, Info& info) const; /// solve the excited state LR-CC2 equations for a given excitation @@ -169,8 +169,8 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { /// @param[in] excitation: the excitation number /// @return a tuple with the excited state doubles, the excited state singles and the excitation energy std::tuple, CC_vecfunction, double> - solve_lrcc2(const Pairs& gs_doubles, const CC_vecfunction& gs_singles, const CC_vecfunction& cis, - const std::size_t excitation) const; + solve_lrcc2(Pairs& gs_doubles, const CC_vecfunction& gs_singles, const CC_vecfunction& cis, + const std::size_t excitation, Info& info) const; double solve_cispd(Pairs& doubles, const Pairs& mp2_pairs, const CC_vecfunction& cis_singles); @@ -195,7 +195,7 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { } static bool - iterate_lrcc2_singles(World& world, CC_vecfunction& cc2_s, Pairs& cc2_d, CC_vecfunction& lrcc2_s, Pairs lrcc2_d, Info& info) { + iterate_lrcc2_singles(World& world, const CC_vecfunction& cc2_s, Pairs& cc2_d, CC_vecfunction& lrcc2_s, Pairs lrcc2_d, Info& info) { MADNESS_ASSERT(cc2_s.type == PARTICLE); MADNESS_ASSERT(lrcc2_s.type == RESPONSE); info.intermediate_potentials.clear_response(); @@ -207,7 +207,7 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { /// convencience function to iterate the CCS Response singles, /// makes the right call on the iterate_singles functions bool - iterate_ccs_singles(CC_vecfunction& x, Info& info) { + iterate_ccs_singles(CC_vecfunction& x, Info& info) const { Pairs empty; // CCOPS.clear_potentials(x); info.intermediate_potentials.clear_response(); @@ -281,8 +281,8 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { CCTimer time_V(world, assign_name(ctype) + "-Singles Potential"); vector_real_function_3d V; if (ctype == CT_CC2) V = CCPotentials::get_CC2_singles_potential_gs(world, singles, gs_doubles, info); -// else if (ctype == CT_LRCC2) -// V = CCOPS.get_CC2_singles_potential_ex(world, singles2, gs_doubles, singles, ex_doubles, info); + else if (ctype == CT_LRCC2) + V = CCPotentials::get_CC2_singles_potential_ex(world, singles2, gs_doubles, singles, ex_doubles, info); // else if (ctype == CT_LRCCS) V = CCOPS.get_CCS_potential_ex(world,singles,false, info); // else if (ctype == CT_ADC2) V = CCOPS.get_ADC2_singles_potential(world, gs_doubles, singles, ex_doubles, info); else MADNESS_EXCEPTION("iterate singles: unknown type", 1); @@ -437,8 +437,8 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { bool iterate_adc2_pairs(Pairs& cispd, const CC_vecfunction& ccs); - bool - iterate_lrcc2_pairs(const CC_vecfunction& cc2_s, const Pairs& cc2_d, const CC_vecfunction lrcc2_s, + static bool + iterate_lrcc2_pairs(World& world, const CC_vecfunction& cc2_s, const CC_vecfunction lrcc2_s, Pairs& lrcc2_d, const Info& info); bool update_constant_part_cc2_gs(const CC_vecfunction& tau, CCPair& pair) { @@ -521,7 +521,7 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { Pairs compute_local_coupling(const Pairs& pairs) const; - double solve_mp2_coupled(Pairs &doubles); + double solve_mp2_coupled(Pairs &doubles, Info& info); bool check_core_valence_separation(const Tensor& fmat) const; diff --git a/src/madness/chem/CCPotentials.cc b/src/madness/chem/CCPotentials.cc index adb68396f33..1bf33b399d0 100644 --- a/src/madness/chem/CCPotentials.cc +++ b/src/madness/chem/CCPotentials.cc @@ -434,7 +434,8 @@ CCPotentials::compute_cc2_correlation_energy(World& world, const CC_vecfunction& } double -CCPotentials::compute_kinetic_energy(const vector_real_function_3d& xbra, const vector_real_function_3d& xket) const { +CCPotentials::compute_kinetic_energy(World& world, const vector_real_function_3d& xbra, const vector_real_function_3d& xket) +{ Kinetic T(world); double kinetic = 0.0; for (size_t k = 0; k < xket.size(); k++) @@ -443,15 +444,16 @@ CCPotentials::compute_kinetic_energy(const vector_real_function_3d& xbra, const } double -CCPotentials::compute_cis_expectation_value(const CC_vecfunction& x, const vector_real_function_3d& V, - const bool print) const { - const vector_real_function_3d xbra = make_bra(x); +CCPotentials::compute_cis_expectation_value(World& world, const CC_vecfunction& x, + const vector_real_function_3d& V, const bool print, const Info& info) +{ + const vector_real_function_3d xbra = info.R_square*(x.get_vecfunction()); const vector_real_function_3d xket = x.get_vecfunction(); - const double kinetic = compute_kinetic_energy(xbra, xket); + const double kinetic = compute_kinetic_energy(world, xbra, xket); const double norm = sqrt(inner(world, xbra, xket).sum()); double eps = 0.0; for (size_t k = 0; k < xket.size(); k++) - eps -= get_orbital_energies()[k + parameters.freeze()] * xbra[k].inner(xket[k]); + eps -= info.orbital_energies[k + info.parameters.freeze()] * xbra[k].inner(xket[k]); double potential = inner(world, xbra, V).sum(); const double result = 1.0 / (norm * norm) * (potential + kinetic + eps); if (world.rank() == 0 && print) { @@ -2848,16 +2850,20 @@ CCPotentials::get_CCS_potential_ex(World& world, CC_vecfunction& x, const bool p get_potentials.insert(copy(world, potential), x, POT_singles_); vector_real_function_3d result = add(world, fock_residue, potential); truncate(world, result); - const double omega = compute_cis_expectation_value(x, result, print); + const double omega = compute_cis_expectation_value(world, x, result, print, info); x.omega = omega; return result; } madness::vector_real_function_3d CCPotentials::get_CC2_singles_potential_ex(World& world, const CC_vecfunction& gs_singles, - const Pairs& gs_doubles, CC_vecfunction& ex_singles, const Pairs& response_doubles, Info& info) const { + const Pairs& gs_doubles, CC_vecfunction& ex_singles, + const Pairs& response_doubles, Info& info) +{ MADNESS_ASSERT(gs_singles.type == PARTICLE); MADNESS_ASSERT(ex_singles.type == RESPONSE); + Projector Ox(info.get_active_mo_bra(),ex_singles.get_vecfunction()); + Projector Ot(info.get_active_mo_bra(),gs_singles.get_vecfunction()); const vector_real_function_3d fock_residue = potential_singles_ex(world, gs_singles, gs_doubles, ex_singles, response_doubles, POT_F3D_, info); vector_real_function_3d Vccs = potential_singles_ex(world, gs_singles, gs_doubles, ex_singles, response_doubles,POT_ccs_, info); @@ -2870,16 +2876,19 @@ CCPotentials::get_CC2_singles_potential_ex(World& world, const CC_vecfunction& g // maybe store full s2b potential of gs // both need to be subtracted vector_real_function_3d s2b_gs = potential_singles_gs(world, gs_singles, gs_doubles, POT_s2b_, info); - vector_real_function_3d Vs4a = - -1.0 * add(world, apply_projector(s2b_gs, ex_singles), apply_projector(Vs2b, gs_singles)); + // vector_real_function_3d Vs4a = + // -1.0 * add(world, apply_projector(s2b_gs, ex_singles), apply_projector(Vs2b, gs_singles)); + vector_real_function_3d Vs4a = -1.0 * (Ox(s2b_gs)+ Ot(Vs2b)); //add up vector_real_function_3d unprojected = add(world, Vccs, add(world, Vs2b, add(world, Vs2c, add(world, Vs4a, add(world, Vs4b, Vs4c))))); - vector_real_function_3d potential = apply_Qt(unprojected, mo_ket_); - if (parameters.debug()) { + QProjector Q(info.mo_bra, info.mo_ket); + // vector_real_function_3d potential = apply_Qt(unprojected, mo_ket_); + vector_real_function_3d potential = Q(unprojected); + if (info.parameters.debug()) { // debug - vector_real_function_3d xbra = mul(world, nemo_->ncf->square(), ex_singles.get_vecfunction()); + vector_real_function_3d xbra = info.R_square* ex_singles.get_vecfunction(); const double ccs = inner(world, xbra, Vccs).sum(); const double s2b = inner(world, xbra, Vs2b).sum(); const double s2c = inner(world, xbra, Vs2c).sum(); @@ -2892,10 +2901,10 @@ CCPotentials::get_CC2_singles_potential_ex(World& world, const CC_vecfunction& g // debug end } // storing potential - get_potentials.insert(copy(world, potential), ex_singles, POT_singles_); + info.intermediate_potentials.insert(copy(world, potential), ex_singles, POT_singles_); vector_real_function_3d result = add(world, fock_residue, potential); truncate(world, result); - const double omega = compute_cis_expectation_value(ex_singles, result); + const double omega = compute_cis_expectation_value(world, ex_singles, result, true, info); ex_singles.omega = omega; return result; } @@ -2930,7 +2939,7 @@ CCPotentials::potential_energy_gs(World& world, const CC_vecfunction& bra, } else if (name == POT_s6_) { result = x_s6(bra, singles, singles, singles); } else if (name == POT_F3D_) { - result = x_s3a(bra, singles) - compute_kinetic_energy(bra.get_vecfunction(), singles.get_vecfunction()); + result = x_s3a(bra, singles) - compute_kinetic_energy(world, bra.get_vecfunction(), singles.get_vecfunction()); } else if (name == POT_ccs_) { result = x_s3c(bra, singles) + x_s5b(bra, singles, singles) + x_s5c(bra, singles, singles) + x_s6(bra, singles, singles, singles); @@ -3033,7 +3042,7 @@ CCPotentials::potential_energy_ex(World& world, const CC_vecfunction& bra, result = x_s6(bra, singles_ex, singles_gs, singles_gs) + x_s6(bra, singles_gs, singles_ex, singles_gs) + x_s6(bra, singles_gs, singles_gs, singles_ex); } else if (name == POT_F3D_) { - result = x_s3a(bra, singles_ex) - compute_kinetic_energy(bra.get_vecfunction(), singles_ex.get_vecfunction()); + result = x_s3a(bra, singles_ex) - compute_kinetic_energy(world, bra.get_vecfunction(), singles_ex.get_vecfunction()); } else if (name == POT_ccs_) { result = x_s3c(bra, singles_ex) + x_s5b(bra, singles_ex, singles_gs) + x_s5c(bra, singles_ex, singles_gs) + x_s6(bra, singles_ex, singles_gs, singles_gs) + x_s5b(bra, singles_gs, singles_ex) @@ -3064,20 +3073,29 @@ CCPotentials::potential_energy_ex(World& world, const CC_vecfunction& bra, madness::vector_real_function_3d CCPotentials::potential_singles_ex(World& world, const CC_vecfunction& singles_gs, const Pairs& doubles_gs, const CC_vecfunction& singles_ex, - const Pairs& doubles_ex, const PotentialType& name, Info& info) const { + const Pairs& doubles_ex, const PotentialType& name, Info& info) +{ //if(mo_ket_.size()>1) output.warning("Potential for ExSingles is not ready for more than one orbital"); // sanity check MADNESS_ASSERT(singles_gs.type == PARTICLE); MADNESS_ASSERT(singles_ex.type == RESPONSE); + + Projector Ox(info.get_active_mo_bra(),singles_ex.get_vecfunction()); + vector_real_function_3d result; CCTimer timer(world, "timer-ex-potential"); if (name == POT_F3D_) { result = fock_residue_closed_shell(world, singles_ex, info); } else if (name == POT_ccs_) { - const CC_vecfunction t = make_t_intermediate(singles_gs,parameters); - vector_real_function_3d part1 = apply_Qt(ccs_unprojected(world, t, singles_ex, info), t); - vector_real_function_3d part2 = apply_Qt(ccs_unprojected(world, singles_ex, singles_gs, info), t); - vector_real_function_3d part3 = apply_projector(ccs_unprojected(world, t, singles_gs, info), singles_ex); + // const CC_vecfunction t = make_t_intermediate(singles_gs,info.parameters); + const CC_vecfunction t = make_active_t_intermediate(singles_gs,info); + QProjector Qt(info.get_active_mo_bra(),t.get_vecfunction()); + // vector_real_function_3d part1 = apply_Qt(ccs_unprojected(world, t, singles_ex, info), t); + // vector_real_function_3d part2 = apply_Qt(ccs_unprojected(world, singles_ex, singles_gs, info), t); + vector_real_function_3d part1 = Qt(ccs_unprojected(world, t, singles_ex, info)); + vector_real_function_3d part2 = Qt(ccs_unprojected(world, singles_ex, singles_gs, info)); + // vector_real_function_3d part3 = apply_projector(ccs_unprojected(world, t, singles_gs, info), singles_ex); + vector_real_function_3d part3 = Ox(ccs_unprojected(world, t, singles_gs, info)); vector_real_function_3d tmp = add(world, part1, part2); result = sub(world, tmp, part3); } else if (name == POT_s2b_) { @@ -3095,7 +3113,7 @@ CCPotentials::potential_singles_ex(World& world, const CC_vecfunction& singles_g vector_real_function_3d s4c_part2 = s4c(world, singles_ex, doubles_gs, info); result = add(world, s4c_part1, s4c_part2); } else if (name == POT_cis_) { - result = ccs_unprojected(world, CC_vecfunction(get_active_mo_ket(), HOLE, parameters.freeze()), singles_ex, info); + result = ccs_unprojected(world, CC_vecfunction(info.get_active_mo_ket(), HOLE, info.parameters.freeze()), singles_ex, info); } else MADNESS_EXCEPTION(("potential_singles: Unknown potential " + assign_name(name)).c_str(), 1) ; @@ -3388,7 +3406,7 @@ CCPotentials::x_s3a(const CC_vecfunction& x, const CC_vecfunction& t) const { pot += (2.0 * gpart - xpart); } } - double kinetic = compute_kinetic_energy(x.get_vecfunction(), t.get_vecfunction()); + double kinetic = compute_kinetic_energy(world, x.get_vecfunction(), t.get_vecfunction()); return kinetic + pot + nuc; } diff --git a/src/madness/chem/CCPotentials.h b/src/madness/chem/CCPotentials.h index 5ec455427c3..88c75eae30c 100644 --- a/src/madness/chem/CCPotentials.h +++ b/src/madness/chem/CCPotentials.h @@ -268,13 +268,13 @@ class CCPotentials { compute_cc2_correlation_energy(World& world, const CC_vecfunction& singles, const Pairs& doubles, const Info& info); - double - compute_kinetic_energy(const vector_real_function_3d& xbra, const vector_real_function_3d& xket) const; + static double + compute_kinetic_energy(World& world, const vector_real_function_3d& xbra, const vector_real_function_3d& xket); /// returns \f$ + \f$ - double - compute_cis_expectation_value(const CC_vecfunction& x, const vector_real_function_3d& V, - const bool print = true) const; + static double + compute_cis_expectation_value(World& world, const CC_vecfunction& x, + const vector_real_function_3d& V, const bool print, const Info& info); /// Something like a pair energy for CIS(D)/LRCC2 to estimate energy convergence /// calculates the response part of s2b and s2c which are independent of the mp2 amplitudes @@ -666,9 +666,9 @@ class CCPotentials { /// Calculates the CC2 singles potential for the Excited state: result = Fock_residue + V /// the V part is stored in the intermediate_potentials structure - vector_real_function_3d + static vector_real_function_3d get_CC2_singles_potential_ex(World& world, const CC_vecfunction& gs_singles, - const Pairs& gs_doubles, CC_vecfunction& ex_singles, const Pairs& response_doubles, Info& info) const; + const Pairs& gs_doubles, CC_vecfunction& ex_singles, const Pairs& response_doubles, Info& info); /// Calculates the CC2 singles potential for the Excited state: result = Fock_residue + V /// the V part is stored in the intermediate_potentials structure @@ -727,10 +727,10 @@ class CCPotentials { /// @param[in] Name of the potential /// @param[out] the potential (without Q application) /// @param world - vector_real_function_3d + static vector_real_function_3d potential_singles_ex(World& world, const CC_vecfunction& singles_gs, const Pairs& doubles_gs, const CC_vecfunction& singles_ex, - const Pairs& doubles_ex, const PotentialType& name, Info& info) const; + const Pairs& doubles_ex, const PotentialType& name, Info& info); /// The Fock operator is partitioned into F = T + Vn + R /// the fock residue R= 2J-K+Un for closed shell is computed here From 502e4f5cb8ffc7baf934d103f6c33130eb7868d0 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Fri, 12 Jul 2024 23:00:33 +0200 Subject: [PATCH 17/54] checkpoint --- src/madness/chem/CC2.cc | 245 ++++++++++++++++-------------- src/madness/chem/CCPotentials.cc | 87 ++++++++++- src/madness/chem/CCPotentials.h | 4 +- src/madness/chem/CCStructures.cc | 11 -- src/madness/chem/CCStructures.h | 27 +++- src/madness/chem/ccpairfunction.h | 11 ++ 6 files changed, 248 insertions(+), 137 deletions(-) diff --git a/src/madness/chem/CC2.cc b/src/madness/chem/CC2.cc index e6d4f70846d..7eeea63a1b0 100644 --- a/src/madness/chem/CC2.cc +++ b/src/madness/chem/CC2.cc @@ -185,7 +185,7 @@ CC2::solve() { CCTimer time_ex(world, "ADC(2) for Excitation " + std::to_string(int(excitation))); // check the convergence of the cis function (also needed to store the ccs potential) and to recalulate the excitation energy - CC_vecfunction dummy = ccs.copy(); + CC_vecfunction dummy = copy(ccs); iterate_ccs_singles(dummy, CCOPS.info); ccs.omega = dummy.omega; // will be overwritten soon output("Changes not stored!"); @@ -253,67 +253,67 @@ CC2::solve() { } else if (ctype == CT_LRCC2) { CCTimer time(world, "Whole LRCC2 Calculation"); - std::vector > results; - std::vector > > timings; - auto vccs=solve_ccs(); - std::vector > > results_ex; - for (size_t xxx = 0; xxx < vccs.size(); xxx++) { - const size_t excitation = parameters.excitations()[xxx]; - CCTimer time_ex(world, "LRCC2 Calculation for Excitation " + std::to_string(int(excitation))); - CC_vecfunction lrcc2_s = vccs[xxx]; - // needed to assign an omega - const vector_real_function_3d backup = copy(world, lrcc2_s.get_vecfunction()); - CC_vecfunction test(backup, RESPONSE, parameters.freeze()); - iterate_ccs_singles(test, info); - lrcc2_s.omega = test.omega; - output("CCS Iteration: Changes are not applied (just omega)!"); - - - Pairs lrcc2_d; - bool found_lrcc2d = initialize_pairs(lrcc2_d, EXCITED_STATE, CT_LRCC2, cc2singles, lrcc2_s, excitation, info); - - if (found_lrcc2d) iterate_lrcc2_singles(world, cc2singles, cc2pairs, lrcc2_s, lrcc2_d, info); - else iterate_ccs_singles(lrcc2_s, info); - const double omega_cis = lrcc2_s.omega; - - for (size_t iter = 0; iter < parameters.iter_max(); iter++) { - output.section("Macroiteration " + std::to_string(int(iter)) + " of LRCC2"); - bool dconv = iterate_lrcc2_pairs(world, cc2singles, lrcc2_s, lrcc2_d, info); - bool sconv = iterate_lrcc2_singles(world, cc2singles, cc2pairs, lrcc2_s, lrcc2_d, info); - update_reg_residues_ex(world, cc2singles, lrcc2_s, lrcc2_d, info); - if (dconv and sconv) break; - } - const double omega_cc2 = lrcc2_s.omega; - const std::string msg = "Excitation " + std::to_string(int(excitation)); - results_ex.push_back(std::make_pair(msg, std::make_pair(omega_cis, omega_cc2))); - timings.push_back(std::make_pair(msg, time_ex.current_time(true))); - - } - - timings.push_back(std::make_pair("Whole LRCC2", time.current_time(true))); - output.section("LRCC2 Finished"); - output("Ground State Results:"); - for (const auto& res:results) { - if (world.rank() == 0) - std::cout << std::fixed << std::setprecision(10) - << res.first << "=" << res.second << "\n"; - } - output("Response Results:"); - for (const auto& res:results_ex) { - if (world.rank() == 0) - std::cout << std::fixed << std::setprecision(10) - << res.first << ": " << res.second.first << " (CIS)*, " << res.second.second << " (CC2)\n"; - } - if (world.rank() == 0) std::cout << "*only if CIS vectors where given in the beginning (not for CC2 restart)\n"; - output("\nTimings"); - for (const auto& time:timings) { - if (world.rank() == 0) - std::cout << std::scientific << std::setprecision(2) - << std::setfill(' ') << std::setw(15) << time.first - << ": " << time.second.first << " (Wall), " << time.second.second << " (CPU)" << "\n"; - } + for (size_t iexcitation = 0; iexcitation < vccs.size(); iexcitation++) { + print_header1("Solving LRCC2 for excitation " + std::to_string(iexcitation) + + " with omega "+std::to_string(vccs[iexcitation].omega)); + solve_lrcc2(cc2pairs,cc2singles,vccs[iexcitation],iexcitation,info); + } + // const size_t excitation = parameters.excitations()[xxx]; + // CCTimer time_ex(world, "LRCC2 Calculation for Excitation " + std::to_string(int(excitation))); + // CC_vecfunction lrcc2_s = vccs[xxx]; + // // needed to assign an omega + // const vector_real_function_3d backup = copy(world, lrcc2_s.get_vecfunction()); + // CC_vecfunction test(backup, RESPONSE, parameters.freeze()); + // iterate_ccs_singles(test, info); + // lrcc2_s.omega = test.omega; + // output("CCS Iteration: Changes are not applied (just omega)!"); + + + // Pairs lrcc2_d; + // bool found_lrcc2d = initialize_pairs(lrcc2_d, EXCITED_STATE, CT_LRCC2, cc2singles, lrcc2_s, excitation, info); + + // if (found_lrcc2d) iterate_lrcc2_singles(world, cc2singles, cc2pairs, lrcc2_s, lrcc2_d, info); + // else iterate_ccs_singles(lrcc2_s, info); + // const double omega_cis = lrcc2_s.omega; + + // for (size_t iter = 0; iter < parameters.iter_max(); iter++) { + // output.section("Macroiteration " + std::to_string(int(iter)) + " of LRCC2"); + // bool dconv = iterate_lrcc2_pairs(world, cc2singles, lrcc2_s, lrcc2_d, info); + // bool sconv = iterate_lrcc2_singles(world, cc2singles, cc2pairs, lrcc2_s, lrcc2_d, info); + // update_reg_residues_ex(world, cc2singles, lrcc2_s, lrcc2_d, info); + // if (dconv and sconv) break; + // } + // const double omega_cc2 = lrcc2_s.omega; + // const std::string msg = "Excitation " + std::to_string(int(excitation)); + // results_ex.push_back(std::make_pair(msg, std::make_pair(omega_cis, omega_cc2))); + // timings.push_back(std::make_pair(msg, time_ex.current_time(true))); + + //} + +// timings.push_back(std::make_pair("Whole LRCC2", time.current_time(true))); +// output.section("LRCC2 Finished"); +// output("Ground State Results:"); +// for (const auto& res:results) { +// if (world.rank() == 0) +// std::cout << std::fixed << std::setprecision(10) +// << res.first << "=" << res.second << "\n"; +// } +// output("Response Results:"); +// for (const auto& res:results_ex) { +// if (world.rank() == 0) +// std::cout << std::fixed << std::setprecision(10) +// << res.first << ": " << res.second.first << " (CIS)*, " << res.second.second << " (CC2)\n"; +// } +// if (world.rank() == 0) std::cout << "*only if CIS vectors where given in the beginning (not for CC2 restart)\n"; +// output("\nTimings"); +// for (const auto& time:timings) { +// if (world.rank() == 0) +// std::cout << std::scientific << std::setprecision(2) +// << std::setfill(' ') << std::setw(15) << time.first +// << ": " << time.second.first << " (Wall), " << time.second.second << " (CPU)" << "\n"; +// } } else MADNESS_EXCEPTION(("Unknown Calculation Type: " + assign_name(ctype)).c_str(), 1); @@ -676,10 +676,32 @@ CC2::iterate_lrcc2_pairs(World& world, const CC_vecfunction& cc2_s, auto triangular_map=PairVectorMap::triangular_map(info.parameters.freeze(),info.mo_ket.size()); auto pair_vec=Pairs::pairs2vector(lrcc2_d,triangular_map); + + + // make new constant part + { + MacroTaskConstantPart tc; + MacroTask task(world, tc); + std::vector constant_part_vec = task(pair_vec, cc2_s.get_vecfunction(), + lrcc2_s.get_vecfunction(), info) ; + + for (int i=0; i vdummy_3d; // dummy vectors - std::vector vdummy_6d; // dummy vectors + // temporary fix: create dummy functions to that the cloud is not confused + real_function_6d tmp=real_factory_6d(world).functor([](const coord_6d& r){return 0.0;}); + std::vector vdummy_6d(pair_vec.size(),tmp); // dummy vectors const std::size_t maxiter=3; auto unew = task1(pair_vec, vdummy_6d, cc2_s, lrcc2_s, info, maxiter); @@ -842,65 +864,59 @@ CC2::solve_cc2(CC_vecfunction& singles, Pairs& doubles, Info& info) cons std::tuple, CC_vecfunction, double> CC2::solve_lrcc2(Pairs& gs_doubles, const CC_vecfunction& gs_singles, const CC_vecfunction& cis, const std::size_t excitation, Info& info) const { - CCTimer time(world, "Whole LRCC2 Calculation"); - - std::vector > results; - std::vector > > timings; - std::vector > > results_ex; + CCTimer time(world, "Whole LRCC2 Calculation"); - auto vccs=solve_ccs(); - CCTimer time_ex(world, "LRCC2 Calculation for Excitation " + std::to_string(int(excitation))); - CC_vecfunction ex_singles = vccs[excitation]; - // needed to assign an omega - const vector_real_function_3d backup = copy(world, ex_singles.get_vecfunction()); - CC_vecfunction test(backup, RESPONSE, parameters.freeze()); - iterate_ccs_singles(test, info); - ex_singles.omega = test.omega; - output("CCS Iteration: Changes are not applied (just omega)!"); + std::vector> results; + std::vector>> timings; + std::vector>> results_ex; + auto ex_singles = copy(cis); - Pairs ex_doubles; - bool found_lrcc2d = initialize_pairs(ex_doubles, EXCITED_STATE, CT_LRCC2, gs_singles, ex_singles, excitation, info); + Pairs ex_doubles; + bool found_lrcc2d = initialize_pairs(ex_doubles, EXCITED_STATE, CT_LRCC2, gs_singles, ex_singles, excitation, info); - if (found_lrcc2d) iterate_lrcc2_singles(world, gs_singles, gs_doubles, ex_singles, ex_doubles, info); - else iterate_ccs_singles(ex_singles, info); - const double omega_cis = ex_singles.omega; + if (found_lrcc2d) iterate_lrcc2_singles(world, gs_singles, gs_doubles, ex_singles, ex_doubles, info); + // else iterate_ccs_singles(ex_singles, info); + const double omega_cis = ex_singles.omega; - for (size_t iter = 0; iter < parameters.iter_max(); iter++) { - output.section("Macroiteration " + std::to_string(int(iter)) + " of LRCC2"); - bool dconv = iterate_lrcc2_pairs(world, gs_singles, ex_singles, ex_doubles, info); - bool sconv = iterate_lrcc2_singles(world, gs_singles, gs_doubles, ex_singles, ex_doubles, info); - update_reg_residues_ex(world, gs_singles, ex_singles, ex_doubles, info); - if (dconv and sconv) break; - } - const double omega_cc2 = ex_singles.omega; - const std::string msg = "Excitation " + std::to_string(int(excitation)); - results_ex.push_back(std::make_pair(msg, std::make_pair(omega_cis, omega_cc2))); - timings.push_back(std::make_pair(msg, time_ex.current_time(true))); + for (size_t iter = 0; iter < parameters.iter_max(); iter++) { + output.section("Macroiteration " + std::to_string(int(iter)) + " of LRCC2"); + bool dconv = iterate_lrcc2_pairs(world, gs_singles, ex_singles, ex_doubles, info); + bool sconv = iterate_lrcc2_singles(world, gs_singles, gs_doubles, ex_singles, ex_doubles, info); + update_reg_residues_ex(world, gs_singles, ex_singles, ex_doubles, info); + if (dconv and sconv) break; + } + const double omega_cc2 = ex_singles.omega; + const std::string msg = "Excitation " + std::to_string(int(excitation)); + results_ex.push_back(std::make_pair(msg, std::make_pair(omega_cis, omega_cc2))); + // timings.push_back(std::make_pair(msg, time_ex.current_time(true))); - timings.push_back(std::make_pair("Whole LRCC2", time.current_time(true))); - output.section("LRCC2 Finished"); - output("Ground State Results:"); - for (const auto& res:results) { - if (world.rank() == 0) - std::cout << std::fixed << std::setprecision(10) - << res.first << "=" << res.second << "\n"; - } - output("Response Results:"); - for (const auto& res:results_ex) { - if (world.rank() == 0) - std::cout << std::fixed << std::setprecision(10) - << res.first << ": " << res.second.first << " (CIS)*, " << res.second.second << " (CC2)\n"; - } - if (world.rank() == 0) std::cout << "*only if CIS vectors where given in the beginning (not for CC2 restart)\n"; - output("\nTimings"); - for (const auto& time:timings) { - if (world.rank() == 0) - std::cout << std::scientific << std::setprecision(2) - << std::setfill(' ') << std::setw(15) << time.first - << ": " << time.second.first << " (Wall), " << time.second.second << " (CPU)" << "\n"; - } + timings.push_back(std::make_pair("Whole LRCC2", time.current_time(true))); + output.section("LRCC2 Finished"); + output("Ground State Results:"); + for (const auto& res : results) + { + if (world.rank() == 0) + std::cout << std::fixed << std::setprecision(10) + << res.first << "=" << res.second << "\n"; + } + output("Response Results:"); + for (const auto& res : results_ex) + { + if (world.rank() == 0) + std::cout << std::fixed << std::setprecision(10) + << res.first << ": " << res.second.first << " (CIS)*, " << res.second.second << " (CC2)\n"; + } + if (world.rank() == 0) std::cout << "*only if CIS vectors where given in the beginning (not for CC2 restart)\n"; + output("\nTimings"); + for (const auto& time : timings) + { + if (world.rank() == 0) + std::cout << std::scientific << std::setprecision(2) + << std::setfill(' ') << std::setw(15) << time.first + << ": " << time.second.first << " (Wall), " << time.second.second << " (CPU)" << "\n"; + } return std::make_tuple(ex_doubles, ex_singles, omega_cc2); @@ -1106,13 +1122,14 @@ void CC2::update_reg_residues_ex(World& world, const CC_vecfunction& singles, CCTimer time(world, "Updated Regularization Residues of the Excited State"); MADNESS_ASSERT(singles.type == PARTICLE); MADNESS_ASSERT(response.type == RESPONSE); + CalcType ctype = doubles.allpairs.begin()->second.ctype; Pairs updated_pairs; for (auto& tmp:doubles.allpairs) { MADNESS_ASSERT(tmp.second.type == EXCITED_STATE); CCPair& pair = tmp.second; // CCPair updated_pair = CCPotentials::make_pair_ex(pair.function(), singles, response, i, j, pair.ctype); CCPair updated_pair = - CCPotentials::make_pair_lrcc2(pair.function(), singles, response, pair.i, pair.j, info); + CCPotentials::make_pair_lrcc2(world, ctype, pair.function(), singles, response, pair.i, pair.j, info); updated_pairs.insert(pair.i, pair.j, updated_pair); } doubles.swap(updated_pairs); diff --git a/src/madness/chem/CCPotentials.cc b/src/madness/chem/CCPotentials.cc index 1bf33b399d0..df0b6b76957 100644 --- a/src/madness/chem/CCPotentials.cc +++ b/src/madness/chem/CCPotentials.cc @@ -120,10 +120,83 @@ CCPair CCPotentials::make_pair_cc2(const real_function_6d& u, const CC_vecfuncti return pair; } -CCPair CCPotentials::make_pair_lrcc2(const real_function_6d& u, const CC_vecfunction& gs_singles, const CC_vecfunction& ex_singles, - const size_t i, const size_t j, const Info& info) { - MADNESS_EXCEPTION("CCPotentials::make_pair_lrcc2 not yet implemented",1); - return CCPair(); +/// follow eq. (23) of Kottmann, JCTC 13, 5956 (2017) +CCPair CCPotentials::make_pair_lrcc2(World& world, const CalcType& ctype, const real_function_6d& u, + const CC_vecfunction& gs_singles, const CC_vecfunction& ex_singles, const size_t i, const size_t j, const Info& info) { + MADNESS_ASSERT(gs_singles.type == PARTICLE || gs_singles.type == HOLE); + MADNESS_ASSERT(ex_singles.type == RESPONSE); + MADNESS_ASSERT(ctype == CT_CISPD || ctype == CT_LRCC2 || ctype == CT_ADC2); + MADNESS_ASSERT(!(i < info.parameters.freeze())); + MADNESS_ASSERT(!(j < info.parameters.freeze())); + + // compute the t intermediates for active orbitals only -- they go into the ansatz + const CC_vecfunction t = info.get_active_mo_ket()+gs_singles.get_vecfunction(); + MADNESS_ASSERT(t.size() == (info.mo_ket.size()-info.parameters.freeze())); + + // compute the t intermediates for all orbitals -- they go into the projector + const CC_vecfunction pt = copy(make_full_t_intermediate(gs_singles,info)); + MADNESS_ASSERT(pt.size() == info.mo_ket.size()); + + auto f12=CCConvolutionOperatorPtr(world,OT_F12,info.parameters); + + // set up projectors -- they project out the occupied space from the response pair function + + // dQ12t = -(Qt(1) Ox(2) + Ox(1) Qt(2)) eq. (22) of the excited state paper + QProjector Qt(info.mo_bra,pt.get_vecfunction()); + Projector Ox(info.get_active_mo_bra(),ex_singles.get_vecfunction()); // this works on active orbitals only + auto dQt_1 = outer(Qt,Ox); + auto dQt_2 = outer(Ox,Qt); + + StrongOrthogonalityProjector Q12t(world); // eq. (21) of the ground state paper + Q12t.set_spaces(info.mo_bra,pt.get_vecfunction(),info.mo_bra,pt.get_vecfunction()); + + typedef CCPairFunction cpT; + auto functions=std::vector(1,cpT(u)); + + auto f_xt=std::vector(1,cpT(f12, ex_singles(i), t(j))); + auto f_tx=std::vector(1,cpT(f12, t(i), ex_singles(j))); + functions+=Q12t(f_xt) + Q12t(f_tx) - dQt_1(f_xt) - dQt_2(f_tx); // note the sign change in the last two terms + + +// CCPairFunction f_xt(f12, ex_singles(i), t(j)); +// functions.push_back(f_xt); +// CCPairFunction f_tx(f12, t(i), ex_singles(j)); +// functions.push_back(f_tx); +// { +// CCPairFunction Ot1_xt = apply_Ot(f_xt, pt, 1); // O1t(f|xt>) +// CCPairFunction OtQt_xt = apply_Qt(Ot1_xt, pt, 2, 0.5); // O1t(1-0.5*O2t)f|xt> +// functions.push_back(OtQt_xt.invert_sign()); // - " +// } +// { +// CCPairFunction Ot2_xt = apply_Ot(f_xt, pt, 2); // O2t(f|xt>) +// CCPairFunction QtOt_xt = apply_Qt(Ot2_xt, pt, 1, 0.5); // (1-0.5*O1t)O2t(f|xt>) +// functions.push_back(QtOt_xt.invert_sign()); // - " +// } +// { +// CCPairFunction Ot1_tx = apply_Ot(f_tx, pt, 1); // O1t(f|tx>) +// CCPairFunction OtQt_tx = apply_Qt(Ot1_tx, pt, 2, 0.5); // O1t(1-0.5*O2t)f|tx> +// functions.push_back(OtQt_tx.invert_sign()); // - " +// } +// { +// CCPairFunction Ot2_tx = apply_Ot(f_tx, pt, 2); // O2t(f|tx>) +// CCPairFunction QtOt_tx = apply_Qt(Ot2_tx, pt, 1, 0.5); // (1-0.5*O1t)O2t(f|tx>) +// functions.push_back(QtOt_tx.invert_sign()); // - " +// } +// +// CCPairFunction ftt(f12, t(i), t(j)); // f|tt> +// CCPairFunction O1x_tt = apply_Ot(ftt, ex_singles, 1); // O1x(f|tt>) +// CCPairFunction OxQt_tt = apply_Qt(O1x_tt, pt, 2); // O1xQt(f|tt>) +// functions.push_back(OxQt_tt.invert_sign()); // - " +// CCPairFunction O2x_tt = apply_Ot(ftt, ex_singles, 2); // O2x(f|tt>) +// CCPairFunction QtOx_tt = apply_Qt(O2x_tt, pt, 1); // Q1tO2x(f|tt>) +// functions.push_back(QtOx_tt.invert_sign()); // - " + + CCPair pair(i, j, EXCITED_STATE, ctype, functions); + MADNESS_ASSERT(functions.size() == 9); + MADNESS_ASSERT(ex_singles.omega != 0.0); + const double bsh_eps = get_epsilon(i, j, info) + ex_singles.omega; + pair.bsh_eps = bsh_eps; + return pair; } madness::CCPair @@ -276,12 +349,12 @@ CCPotentials::make_pair_ex(const real_function_6d& u, const CC_vecfunction& tau, MADNESS_ASSERT(!(j < parameters.freeze())); // for CIS(D): tau is empty or Hole states, the function will give back mo_ket_ // for freeze!=0 the function will give back (mo0,mo1,...,t_freeze,t_freeze+1,...) - const CC_vecfunction t = make_t_intermediate(tau,parameters).copy(); + const CC_vecfunction t = copy(make_t_intermediate(tau,parameters)); // functions for the projector CC_vecfunction pt; - if (!parameters.QtAnsatz()) pt = mo_ket_.copy(); + if (!parameters.QtAnsatz()) pt = copy(mo_ket_); else { - pt = make_full_t_intermediate(tau).copy(); + pt = copy(make_full_t_intermediate(tau)); } MADNESS_ASSERT(pt.size() == mo_ket_.size()); std::vector> functions; diff --git a/src/madness/chem/CCPotentials.h b/src/madness/chem/CCPotentials.h index 88c75eae30c..7014b4dfc02 100644 --- a/src/madness/chem/CCPotentials.h +++ b/src/madness/chem/CCPotentials.h @@ -207,8 +207,8 @@ class CCPotentials { const size_t i, const size_t j, const Info& info); /// return the regularized CC2 ansatz: |x_ij> = |u_ij> + Q12t f12 |t_i t_j> + ????? - static CCPair make_pair_lrcc2(const real_function_6d& u, const CC_vecfunction& gs_singles, - const CC_vecfunction& ex_singles, const size_t i, const size_t j, const Info& info); + static CCPair make_pair_lrcc2(World& world, const CalcType& ctype, const real_function_6d& u, + const CC_vecfunction& gs_singles, const CC_vecfunction& ex_singles, const size_t i, const size_t j, const Info& info); // Pair functions diff --git a/src/madness/chem/CCStructures.cc b/src/madness/chem/CCStructures.cc index 795921e23fb..8d79c6b9e02 100644 --- a/src/madness/chem/CCStructures.cc +++ b/src/madness/chem/CCStructures.cc @@ -64,17 +64,6 @@ CCTimer::info(const bool debug, const double norm) { } -madness::CC_vecfunction -CC_vecfunction::copy() const { - std::vector> vn; - for (auto x : functions) { - const CCFunction fn(madness::copy(x.second.function), x.second.i, x.second.type); - vn.push_back(fn); - } - CC_vecfunction result(vn, type); - result.irrep = irrep; - return result; -} std::string CC_vecfunction::name(const int ex) const { diff --git a/src/madness/chem/CCStructures.h b/src/madness/chem/CCStructures.h index 4f4035b0a15..3cfac06239e 100644 --- a/src/madness/chem/CCStructures.h +++ b/src/madness/chem/CCStructures.h @@ -555,7 +555,7 @@ struct CC_vecfunction : public archive::ParallelSerializableObject { delta(other.delta), irrep(other.irrep) { } - /// assignment operator + /// assignment operator, shallow wrt the functions // CC_vecfunction& operator=(const CC_vecfunction& other) = default; CC_vecfunction& operator=(const CC_vecfunction& other) { if (this == &other) return *this; @@ -570,8 +570,29 @@ struct CC_vecfunction : public archive::ParallelSerializableObject { /// returns a deep copy (void shallow copy errors) - CC_vecfunction - copy() const; + friend CC_vecfunction + copy(const CC_vecfunction& other) { + CC_vecfunction tmp=other; + tmp.functions.clear(); + for (const auto& x : other.functions) { + tmp.functions.insert(std::make_pair(x.first, copy(x.second))); + } + return tmp; + } + + +//madness::CC_vecfunction +//CC_vecfunction::copy() const { +// std::vector> vn; +// for (auto x : functions) { +// const CCFunction fn(madness::copy(x.second.function), x.second.i, x.second.type); +// vn.push_back(fn); +// } +// CC_vecfunction result(vn, type); +// result.irrep = irrep; +// return result; +//} +// static CC_vecfunction load_restartdata(World& world, std::string filename) { archive::ParallelInputArchive ar(world, filename.c_str()); diff --git a/src/madness/chem/ccpairfunction.h b/src/madness/chem/ccpairfunction.h index 59ddab2e2c2..343d6859dd0 100644 --- a/src/madness/chem/ccpairfunction.h +++ b/src/madness/chem/ccpairfunction.h @@ -41,6 +41,17 @@ class CCFunction : public archive::ParallelSerializableObject { CCFunction(const CCFunction& other) : current_error(other.current_error), function(other.function), i(other.i), type(other.type) {}; + + /// deep copy + friend CCFunction copy(const CCFunction& other) { + CCFunction tmp; + tmp.current_error=other.current_error; + tmp.function=madness::copy(other.function); + tmp.i=other.i; + tmp.type=other.type; + return tmp; + } + double current_error; Function function; From d1fa781fc82b8b4de09efd89054812ab1d08fa92 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Wed, 17 Jul 2024 13:25:36 +0200 Subject: [PATCH 18/54] checkpoint: He lrcc2 works --- src/madness/chem/CC2.cc | 69 +++++---- src/madness/chem/CC2.h | 2 +- src/madness/chem/CCPotentials.cc | 218 ++++++++++++++--------------- src/madness/chem/CCPotentials.h | 26 ++-- src/madness/chem/CCStructures.cc | 28 ++-- src/madness/chem/ccpairfunction.cc | 2 + src/madness/chem/projector.h | 2 + 7 files changed, 181 insertions(+), 166 deletions(-) diff --git a/src/madness/chem/CC2.cc b/src/madness/chem/CC2.cc index 7eeea63a1b0..0e4a829e14c 100644 --- a/src/madness/chem/CC2.cc +++ b/src/madness/chem/CC2.cc @@ -680,21 +680,29 @@ CC2::iterate_lrcc2_pairs(World& world, const CC_vecfunction& cc2_s, // make new constant part { - MacroTaskConstantPart tc; - MacroTask task(world, tc); - std::vector constant_part_vec = task(pair_vec, cc2_s.get_vecfunction(), + std::vector cp; + // try { + // load_function(world, cp, "constant_part"); + // } catch (...) { + MacroTaskConstantPart tc; + MacroTask task(world, tc); + // std::vector constant_part_vec = task(pair_vec, cc2_s.get_vecfunction(), + cp = task(pair_vec, cc2_s.get_vecfunction(), lrcc2_s.get_vecfunction(), info) ; + // save_function( cp, "constant_part"); + // } for (int i=0; i::vector2pairs(pair_vec,triangular_map); return (rmsrnorm& gs_doubles, const CC_vecfunction& gs_singles, co bool found_lrcc2d = initialize_pairs(ex_doubles, EXCITED_STATE, CT_LRCC2, gs_singles, ex_singles, excitation, info); if (found_lrcc2d) iterate_lrcc2_singles(world, gs_singles, gs_doubles, ex_singles, ex_doubles, info); - // else iterate_ccs_singles(ex_singles, info); + else iterate_ccs_singles(ex_singles, info); const double omega_cis = ex_singles.omega; for (size_t iter = 0; iter < parameters.iter_max(); iter++) { @@ -949,7 +935,7 @@ bool CC2::iterate_pair(CCPair& pair, const CC_vecfunction& singles) const { info.mo_bra=CCOPS.mo_bra_.get_vecfunction(); info.parameters=parameters; if (pair.type == GROUND_STATE) omega = CCOPS.compute_pair_correlation_energy(world, info,pair, singles); - if (pair.type == EXCITED_STATE) omega = CCOPS.compute_excited_pair_energy(pair, singles); + if (pair.type == EXCITED_STATE) omega = CCOPS.compute_excited_pair_energy(world, pair, singles, info); if (world.rank() == 0) std::cout << "Correlation Energy of Pair " << pair.name() << " =" << std::fixed << std::setprecision(10) @@ -996,7 +982,7 @@ bool CC2::iterate_pair(CCPair& pair, const CC_vecfunction& singles) const { double omega_new = 0.0; double delta = 0.0; if (pair.type == GROUND_STATE) omega_new = CCOPS.compute_pair_correlation_energy(world, info, pair, singles); - else if (pair.type == EXCITED_STATE) omega_new = CCOPS.compute_excited_pair_energy(pair, singles); + else if (pair.type == EXCITED_STATE) omega_new = CCOPS.compute_excited_pair_energy(world, pair, singles, info); delta = omega - omega_new; const double current_norm = pair.function().norm2(); @@ -1064,6 +1050,8 @@ CC2::initialize_pairs(Pairs& pairs, const CCState ftype, const CalcType output("Initialize " + assign_name(ctype) + " Pairs for " + assign_name(ftype)); bool restarted = false; + std::vector vconst_part; + load_function(world,vconst_part,"constant_part"); for (size_t i = parameters.freeze(); i < CCOPS.mo_ket().size(); i++) { for (size_t j = i; j < CCOPS.mo_ket().size(); j++) { @@ -1089,9 +1077,28 @@ CC2::initialize_pairs(Pairs& pairs, const CCState ftype, const CalcType real_function_6d const_part; CCOPS.load_function(const_part, name + "_const"); CCPair tmp = CCOPS.make_pair_ex(utmp, tau, x, i, j, ctype); + + { + CCPair tmp2=CCPotentials::make_pair_lrcc2(world, ctype, utmp, tau, x, i, j, info); + auto doit =[](const CCPair& p) { + auto functions=consolidate(p.functions); + for (const auto& f : functions) f.print_size(); + }; +// print("jakob's pair"); +// doit(tmp); +// print("Florian's pair"); +// doit(tmp2); + std::swap(tmp,tmp2); + print("going on with Florian's pair"); + // print("going on with Jakob's pair"); + } + // tmp.excitation = excitation; - tmp.constant_part = const_part; + // tmp.constant_part = const_part; + tmp.constant_part = vconst_part[0]; + print_header1("loading constant part"); pairs.insert(i, j, tmp); + CCPotentials::compute_excited_pair_energy(world, pairs(i, j), x, info); } else error("Unknown pairtype"); } } diff --git a/src/madness/chem/CC2.h b/src/madness/chem/CC2.h index 401ce42ddac..7708e82d74f 100644 --- a/src/madness/chem/CC2.h +++ b/src/madness/chem/CC2.h @@ -283,7 +283,7 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { if (ctype == CT_CC2) V = CCPotentials::get_CC2_singles_potential_gs(world, singles, gs_doubles, info); else if (ctype == CT_LRCC2) V = CCPotentials::get_CC2_singles_potential_ex(world, singles2, gs_doubles, singles, ex_doubles, info); -// else if (ctype == CT_LRCCS) V = CCOPS.get_CCS_potential_ex(world,singles,false, info); + else if (ctype == CT_LRCCS) V = CCPotentials::get_CCS_potential_ex(world,singles,false, info); // else if (ctype == CT_ADC2) V = CCOPS.get_ADC2_singles_potential(world, gs_doubles, singles, ex_doubles, info); else MADNESS_EXCEPTION("iterate singles: unknown type", 1); time_V.info(true, norm2(world, V)); diff --git a/src/madness/chem/CCPotentials.cc b/src/madness/chem/CCPotentials.cc index df0b6b76957..46c9e7e453d 100644 --- a/src/madness/chem/CCPotentials.cc +++ b/src/madness/chem/CCPotentials.cc @@ -155,44 +155,12 @@ CCPair CCPotentials::make_pair_lrcc2(World& world, const CalcType& ctype, const auto f_xt=std::vector(1,cpT(f12, ex_singles(i), t(j))); auto f_tx=std::vector(1,cpT(f12, t(i), ex_singles(j))); - functions+=Q12t(f_xt) + Q12t(f_tx) - dQt_1(f_xt) - dQt_2(f_tx); // note the sign change in the last two terms - - -// CCPairFunction f_xt(f12, ex_singles(i), t(j)); -// functions.push_back(f_xt); -// CCPairFunction f_tx(f12, t(i), ex_singles(j)); -// functions.push_back(f_tx); -// { -// CCPairFunction Ot1_xt = apply_Ot(f_xt, pt, 1); // O1t(f|xt>) -// CCPairFunction OtQt_xt = apply_Qt(Ot1_xt, pt, 2, 0.5); // O1t(1-0.5*O2t)f|xt> -// functions.push_back(OtQt_xt.invert_sign()); // - " -// } -// { -// CCPairFunction Ot2_xt = apply_Ot(f_xt, pt, 2); // O2t(f|xt>) -// CCPairFunction QtOt_xt = apply_Qt(Ot2_xt, pt, 1, 0.5); // (1-0.5*O1t)O2t(f|xt>) -// functions.push_back(QtOt_xt.invert_sign()); // - " -// } -// { -// CCPairFunction Ot1_tx = apply_Ot(f_tx, pt, 1); // O1t(f|tx>) -// CCPairFunction OtQt_tx = apply_Qt(Ot1_tx, pt, 2, 0.5); // O1t(1-0.5*O2t)f|tx> -// functions.push_back(OtQt_tx.invert_sign()); // - " -// } -// { -// CCPairFunction Ot2_tx = apply_Ot(f_tx, pt, 2); // O2t(f|tx>) -// CCPairFunction QtOt_tx = apply_Qt(Ot2_tx, pt, 1, 0.5); // (1-0.5*O1t)O2t(f|tx>) -// functions.push_back(QtOt_tx.invert_sign()); // - " -// } -// -// CCPairFunction ftt(f12, t(i), t(j)); // f|tt> -// CCPairFunction O1x_tt = apply_Ot(ftt, ex_singles, 1); // O1x(f|tt>) -// CCPairFunction OxQt_tt = apply_Qt(O1x_tt, pt, 2); // O1xQt(f|tt>) -// functions.push_back(OxQt_tt.invert_sign()); // - " -// CCPairFunction O2x_tt = apply_Ot(ftt, ex_singles, 2); // O2x(f|tt>) -// CCPairFunction QtOx_tt = apply_Qt(O2x_tt, pt, 1); // Q1tO2x(f|tt>) -// functions.push_back(QtOx_tt.invert_sign()); // - " + auto f_tt=std::vector(1,cpT(f12, t(i), t(j))); + + functions+=(Q12t(f_xt) + Q12t(f_tx) - dQt_1(f_tt) -dQt_2(f_tt)); // note the sign change in the last two terms + functions=consolidate(functions); CCPair pair(i, j, EXCITED_STATE, ctype, functions); - MADNESS_ASSERT(functions.size() == 9); MADNESS_ASSERT(ex_singles.omega != 0.0); const double bsh_eps = get_epsilon(i, j, info) + ex_singles.omega; pair.bsh_eps = bsh_eps; @@ -422,6 +390,7 @@ CCPotentials::make_pair_ex(const real_function_6d& u, const CC_vecfunction& tau, functions.push_back(res); } } + functions=consolidate(functions); CCPair pair(i, j, EXCITED_STATE, ctype, functions); if (parameters.decompose_Q()) { if (parameters.QtAnsatz()) MADNESS_ASSERT(functions.size() == 9); @@ -541,16 +510,20 @@ CCPotentials::compute_cis_expectation_value(World& world, const CC_vecfunction& } double -CCPotentials::compute_excited_pair_energy(const CCPair& d, const CC_vecfunction& x) const { - const CC_vecfunction xbra(make_bra(x), RESPONSE, parameters.freeze()); +CCPotentials::compute_excited_pair_energy(World& world, const CCPair& d, const CC_vecfunction& x, const Info& info) { + // const CC_vecfunction xbra(make_bra(x), RESPONSE, info.parameters.freeze()); + // for (const auto& f: d.functions) f.print_size("doubles functions in ex pair energy"); + const CC_vecfunction xbra(info.R_square*x.get_vecfunction(), RESPONSE, info.parameters.freeze()); const CCFunction& xbi = xbra(d.i); - const CCFunction& mobj = mo_bra_(d.j); + const CCFunction& mobj = info.mo_bra[d.j]; + auto g12=CCConvolutionOperatorPtr(world,OT_G12,info.parameters); double result = 0.0; double s2b = 2.0 * make_xy_op_u(xbi, mobj, *g12, d.functions) - make_xy_op_u(mobj, xbi, *g12, d.functions); double s2c = 0.0; for (const auto& ktmp : x.functions) { const size_t k = ktmp.first; - const real_function_3d j_igk = (*g12)(mo_bra_(d.i), mo_ket_(k)) * mo_bra_(d.j).function; + // const real_function_3d j_igk = (*g12)(info.mo_bra[d.i], info.mo_ket[k]) * info.mo_bra[d.j].function; + const real_function_3d j_igk = (*g12)(info.mo_bra[d.i]* info.mo_ket[k]) * info.mo_bra[d.j]; s2c -= 2.0 * make_xy_u(xbra(k), j_igk, d.functions) - make_xy_u(j_igk, xbra(k), d.functions); } result = s2b + s2c; @@ -1117,14 +1090,18 @@ CCPotentials::update_pair_mp2_macrotask(World& world, const CCPair& pair, const CCPair CCPotentials::iterate_pair_macrotask(World& world, - const CCPair& pair, const CC_vecfunction& singles, - const real_function_6d& coupling, - const Info& info, const long maxiter) { + const CCPair& pair, + const CC_vecfunction& gs_singles, + const CC_vecfunction& ex_singles, + const real_function_6d& coupling, + const Info& info, + const long maxiter) { if (world.rank()==0) print_header2("Iterate Pair " + pair.name()); - if (pair.ctype == CT_CC2) MADNESS_ASSERT(singles.type == PARTICLE); - if (pair.ctype == CT_CISPD) MADNESS_ASSERT(singles.type == RESPONSE); - if (pair.ctype == CT_MP2) MADNESS_ASSERT(singles.get_vecfunction().empty()); - if (pair.ctype == CT_ADC2)MADNESS_ASSERT(singles.type == RESPONSE); + if (pair.ctype == CT_CC2) MADNESS_ASSERT(gs_singles.type == PARTICLE); + if (pair.ctype == CT_CISPD) MADNESS_ASSERT(ex_singles.type == RESPONSE); + if (pair.ctype == CT_MP2) MADNESS_ASSERT(gs_singles.get_vecfunction().empty()); + if (pair.ctype == CT_MP2) MADNESS_ASSERT(ex_singles.get_vecfunction().empty()); + if (pair.ctype == CT_ADC2)MADNESS_ASSERT(ex_singles.type == RESPONSE); real_function_6d constant_part = pair.constant_part; constant_part.truncate().reduce_rank(); @@ -1140,38 +1117,40 @@ CCPair CCPotentials::iterate_pair_macrotask(World& world, NonlinearSolverND<6> solver(info.parameters.kain_subspace()); solver.do_print = (world.rank() == 0); - double omega = 0.0; - // if (pair.type == GROUND_STATE) omega = CCOPS.compute_pair_correlation_energy(pair, singles); - // if (pair.type == EXCITED_STATE) omega = CCOPS.compute_excited_pair_energy(pair, singles); - - // if (world.rank() == 0) - // std::cout << "Correlation Energy of Pair " << pair.name() << " =" << std::fixed << std::setprecision(10) - // << omega << "\n"; - CCPair result=pair; + try { + real_function_6d tmp(world); + load(tmp,"iteration00"); + result.update_u(tmp); + print("loading iteration from file"); + tmp.print_size("iteration00 from file"); + return result; + } catch (...) {} + // only the u-part of omega + double omega_partial=CCPotentials::compute_excited_pair_energy(world, result, ex_singles, info); for (size_t iter = 0; iter < maxiter; iter++) { - if (world.rank()==0) print_header3(assign_name(pair.ctype) + "-Microiteration"); - CCTimer timer_mp2(world, "MP2-Microiteration of pair " + pair.name()); + if (world.rank()==0) print_header3(assign_name(result.ctype) + "-Microiteration"); + CCTimer timer_mp2(world, "MP2-Microiteration of pair " + result.name()); - CCTimer timer_mp2_potential(world, "MP2-Potential of pair " + pair.name()); - // real_function_6d mp2_potential = -2.0 * CCOPS.fock_residue_6d(pair); + CCTimer timer_mp2_potential(world, "MP2-Potential of pair " + result.name()); + // real_function_6d mp2_potential = -2.0 * CCOPS.fock_residue_6d(result); real_function_6d mp2_potential = -2.0 * fock_residue_6d_macrotask(world,result,info.parameters, info.molecular_coordinates,info.mo_ket,info.mo_bra, info.U1,info.U2); mp2_potential += 2.0 * coupling; - if (info.parameters.debug()) mp2_potential.print_size(assign_name(pair.ctype) + " Potential"); + if (info.parameters.debug()) mp2_potential.print_size(assign_name(result.ctype) + " Potential"); mp2_potential.truncate().reduce_rank(); timer_mp2_potential.info(true, mp2_potential.norm2()); - CCTimer timer_G(world, "Apply Greens Operator on MP2-Potential of pair " + pair.name()); + CCTimer timer_G(world, "Apply Greens Operator on MP2-Potential of pair " + result.name()); const real_function_6d GVmp2 = G(mp2_potential); if (info.parameters.debug()) GVmp2.print_size("GVmp2"); timer_G.info(true, GVmp2.norm2()); - CCTimer timer_addup(world, "Add constant parts and update pair " + pair.name()); + CCTimer timer_addup(world, "Add constant parts and update pair " + result.name()); real_function_6d unew = Q12(GVmp2 + constant_part); // unew.print_size("unew"); // unew = CCOPS.apply_Q12t(unew, CCOPS.mo_ket()); @@ -1188,10 +1167,10 @@ CCPair CCPotentials::iterate_pair_macrotask(World& world, kain_update.print_size("Kain-Update-Function not truncated"); kain_update.truncate().reduce_rank(); kain_update.print_size("Kain-Update-Function truncated"); - // pair.update_u(copy(kain_update)); + // result.update_u(copy(kain_update)); result.update_u(copy(kain_update)); } else { - // pair.update_u(unew); + // result.update_u(unew); result.update_u(unew); } @@ -1199,26 +1178,26 @@ CCPair CCPotentials::iterate_pair_macrotask(World& world, double omega_new = 0.0; double delta = 0.0; - if (pair.ctype == CT_MP2) omega_new = CCPotentials::compute_pair_correlation_energy(world, info, result); - // else if (pair.type == EXCITED_STATE) omega_new = CCOPS.compute_excited_pair_energy(pair, singles); - delta = omega - omega_new; + if (result.ctype == CT_MP2) omega_new = CCPotentials::compute_pair_correlation_energy(world, info, result); + else if (result.type == EXCITED_STATE) omega_new = CCPotentials::compute_excited_pair_energy(world, result, ex_singles, info); + delta = omega_partial - omega_new; const double current_norm = result.function().norm2(); - omega = omega_new; + omega_partial = omega_new; if (world.rank() == 0) { std::cout << std::fixed << std::setw(50) << std::setfill('#') - << "\n" << "Iteration " << iter << " of pair " << pair.name() + << "\n" << "Iteration " << iter << " of pair " << result.name() << std::setprecision(4) << "||u|| = " << current_norm - << "\n" << std::setprecision(10) << "error = " << error << "\nomega = " << omega << "\ndelta = " + << "\n" << std::setprecision(10) << "error = " << error << "\nomega(partial) = " << omega_partial << "\ndelta = " << delta << "\n" << std::setw(50) << std::setfill('#') << "\n"; } // output("\n--Iteration " + stringify(iter) + " ended--"); - // save(pair.function(), pair.name()); + // save(result.function(), result.name()); // timer_mp2.info(); bool converged=(fabs(error) < info.parameters.dconv_6D()) and (fabs(delta) < info.parameters.econv_pairs()); if (converged) { @@ -2647,7 +2626,7 @@ CCPotentials::apply_gf(World& world, const real_function_3d& f, const Info& info } double -CCPotentials::make_xy_u(const CCFunction& x, const CCFunction& y, const std::vector>& u) const { +CCPotentials::make_xy_u(const CCFunction& x, const CCFunction& y, const std::vector>& u) { double result = 0.0; for (size_t mm = 0; mm < u.size(); mm++) { result += u[mm].make_xy_u(x, y); @@ -2657,33 +2636,36 @@ CCPotentials::make_xy_u(const CCFunction& x, const CCFunction& x, const CCFunction& y, const CCConvolutionOperator& op, - const CCPairFunction& u) const { - double result = 0.0; - if (u.component->is_pure()) { - real_function_6d xy_op = CompositeFactory(world).particle1(copy(x.function)).particle2( - copy(y.function)).g12(op.get_kernel()); - result = inner(u.get_function(), xy_op); - } else if (u.component->is_decomposed()) { - if (u.component->has_operator()) { - if (op.type() == OpType::OT_G12 and u.decomposed().get_operator_ptr()->type() == OpType::OT_F12) - result = make_xy_gf_ab(x, y, u.decomposed().get_a()[0], u.decomposed().get_b()[0]); - else if (op.type() == OpType::OT_F12 and u.decomposed().get_operator_ptr()->type() == OpType::OT_G12) - result = make_xy_gf_ab(x, y, u.decomposed().get_a()[0], u.decomposed().get_b()[0]); - else if (op.type() == OpType::OT_F12 and u.decomposed().get_operator_ptr()->type() == OpType::OT_F12) - result = make_xy_ff_ab(x, y, u.decomposed().get_a()[0], u.decomposed().get_b()[0]); - else MADNESS_EXCEPTION(("xy_" + op.name() + u.name() + " not implemented").c_str(), 1); - } else { - for (size_t i = 0; i < u.decomposed().get_a().size(); i++) - result += (x.function * u.decomposed().get_a()[i]).inner(op(y, u.decomposed().get_b()[i])); - } - } else error("Unknown CCPairFunction type in make_xy_op_u"); - - return result; + const CCPairFunction& u) { + auto ket=CCPairFunction(x.f(),y.f()); + auto bra=std::make_shared>(op)*u; + return inner(bra,ket); +// double result = 0.0; +// if (u.component->is_pure()) { +// real_function_6d xy_op = CompositeFactory(world).particle1(copy(x.function)).particle2( +// copy(y.function)).g12(op.get_kernel()); +// result = inner(u.get_function(), xy_op); +// } else if (u.component->is_decomposed()) { +// if (u.component->has_operator()) { +// if (op.type() == OpType::OT_G12 and u.decomposed().get_operator_ptr()->type() == OpType::OT_F12) +// result = make_xy_gf_ab(x, y, u.decomposed().get_a()[0], u.decomposed().get_b()[0]); +// else if (op.type() == OpType::OT_F12 and u.decomposed().get_operator_ptr()->type() == OpType::OT_G12) +// result = make_xy_gf_ab(x, y, u.decomposed().get_a()[0], u.decomposed().get_b()[0]); +// else if (op.type() == OpType::OT_F12 and u.decomposed().get_operator_ptr()->type() == OpType::OT_F12) +// result = make_xy_ff_ab(x, y, u.decomposed().get_a()[0], u.decomposed().get_b()[0]); +// else MADNESS_EXCEPTION(("xy_" + op.name() + u.name() + " not implemented").c_str(), 1); +// } else { +// for (size_t i = 0; i < u.decomposed().get_a().size(); i++) +// result += (x.function * u.decomposed().get_a()[i]).inner(op(y, u.decomposed().get_b()[i])); +// } +// } else error("Unknown CCPairFunction type in make_xy_op_u"); +// +// return result; } double CCPotentials::make_xy_op_u(const CCFunction& x, const CCFunction& y, const CCConvolutionOperator& op, - const std::vector>& u) const { + const std::vector>& u) { double result = 0.0; for (size_t mm = 0; mm < u.size(); mm++) { const double tmp = make_xy_op_u(x, y, op, u[mm]); @@ -2728,20 +2710,24 @@ CCPotentials::apply_s2b_operation(World& world, const CCFunction& bra, result = u.dirac_convolution(bra, *g12, particle); } else if (u.is_op_decomposed()) { // retunrns _particle - CCFunction a; - CCFunction b; - if (particle == 1) { - a = u.get_a()[0]; - b = u.get_b()[0]; - } else { - a = u.get_b()[0]; - b = u.get_a()[0]; - } - const real_function_3d tmp = (bra.function * a.function).truncate(); - const real_function_3d tmp2 = apply_gf(world, tmp, info); - real_function_3d tmp3 = tmp2 * b.function; - tmp3.truncate(); - result = tmp3; + std::array p1={0,1,2}; + std::array p2={3,4,5}; + auto p = (particle == 1) ? p1 : p2; + result=inner(g12*u,bra.f(),p,p1); +// CCFunction a; +// CCFunction b; +// if (particle == 1) { +// a = u.get_a()[0]; +// b = u.get_b()[0]; +// } else { +// a = u.get_b()[0]; +// b = u.get_a()[0]; +// } +// const real_function_3d tmp = (bra.function * a.function).truncate(); +// const real_function_3d tmp2 = apply_gf(world, tmp, info); +// real_function_3d tmp3 = tmp2 * b.function; +// tmp3.truncate(); +// result = tmp3; } else MADNESS_EXCEPTION("apply_s2b_operation: unknown type", 1) ; @@ -2822,6 +2808,9 @@ CCPotentials::apply_Ot(const CCPairFunction& f, const CC_vecfunction& CC_vecfunction mbra; if (t.size() == mo_bra_.size()) mbra = CC_vecfunction(copy(world, mo_bra_.get_vecfunction()), HOLE); else mbra = CC_vecfunction(copy(world, get_active_mo_bra()), HOLE, parameters.freeze()); + Projector O(mbra.get_vecfunction(), t.get_vecfunction()); + O.set_particle(particle-1); // shift particle index + return O(f); MADNESS_ASSERT(mbra.size() == t.size()); if (f.is_pure()) { @@ -2909,7 +2898,7 @@ CCPotentials::get_CC2_singles_potential_gs(World& world, const CC_vecfunction& s } madness::vector_real_function_3d -CCPotentials::get_CCS_potential_ex(World& world, CC_vecfunction& x, const bool print, Info& info) const { +CCPotentials::get_CCS_potential_ex(World& world, CC_vecfunction& x, const bool print, Info& info) { if (x.type != RESPONSE) error("get_CCS_response_potential: Wrong type of input singles"); Pairs empty_doubles; @@ -2918,9 +2907,11 @@ CCPotentials::get_CCS_potential_ex(World& world, CC_vecfunction& x, const bool p empty_doubles, POT_F3D_, info); vector_real_function_3d potential = potential_singles_ex(world, empty_singles, empty_doubles, x, empty_doubles, POT_cis_, info); // the fock residue does not get projected, but all the rest - potential = apply_Qt(potential, mo_ket_); + QProjector Q(info.mo_bra, info.mo_ket); + // potential = apply_Qt(potential, mo_ket_); + potential=Q(potential); truncate(world, potential); - get_potentials.insert(copy(world, potential), x, POT_singles_); + info.intermediate_potentials.insert(copy(world, potential), x, POT_singles_); vector_real_function_3d result = add(world, fock_residue, potential); truncate(world, result); const double omega = compute_cis_expectation_value(world, x, result, print, info); @@ -3667,6 +3658,9 @@ madness::vector_real_function_3d CCPotentials::s2b(World& world, const CC_vecfunction& singles, const Pairs& doubles, Info& info) { vector_real_function_3d result; + // madness::print_size(world,singles.get_vecfunction(),"singles upon entry"); + // auto functions=doubles.allpairs.begin()->second.functions; + // for (const auto& f : functions) f.print_size("functions"); // see if we can skip the recalculation of the pure 6D part since this does not change during the singles iteration vector_real_function_3d result_u = info.intermediate_potentials(singles, POT_s2b_); bool recalc_u_part = false; diff --git a/src/madness/chem/CCPotentials.h b/src/madness/chem/CCPotentials.h index 7014b4dfc02..665712e1919 100644 --- a/src/madness/chem/CCPotentials.h +++ b/src/madness/chem/CCPotentials.h @@ -278,8 +278,8 @@ class CCPotentials { /// Something like a pair energy for CIS(D)/LRCC2 to estimate energy convergence /// calculates the response part of s2b and s2c which are independent of the mp2 amplitudes - double - compute_excited_pair_energy(const CCPair& d, const CC_vecfunction& x) const; + static double + compute_excited_pair_energy(World& world, const CCPair& d, const CC_vecfunction& x, const Info& info); /// Compute the CIS(D) Energy Correction to CIS double @@ -339,9 +339,9 @@ class CCPotentials { /// iterate a pair for MP2, CC2, LRCC2 on constant singles static CCPair iterate_pair_macrotask(World& world, - const CCPair& pair, const CC_vecfunction& singles, - const real_function_6d& coupling, - const Info& info, const long maxiter); + const CCPair& pair, const CC_vecfunction& gs_singles, + const CC_vecfunction& ex_singles, + const real_function_6d& coupling, const Info& info, const long maxiter); /// Function evaluates the consant part of the ground state for CC2 @@ -531,23 +531,23 @@ class CCPotentials { /// returns /// loops over every entry in the vector and accumulates results /// helper function for CIS(D) energy - double + static double make_xy_op_u(const CCFunction& x, const CCFunction& y, const CCConvolutionOperator& op, - const std::vector>& u) const; + const std::vector>& u); /// returns for a vector of CCPairFunction /// the result is accumulated for every vercotr /// helper functions for CIS(D) energy - double - make_xy_u(const CCFunction& x, const CCFunction& y, const std::vector>& u) const; + static double + make_xy_u(const CCFunction& x, const CCFunction& y, const std::vector>& u); /// Functions which operate with the CCPairFunction structure /// @param[in] function x, if nuclear correlation is used make sure this is the correct bra function /// @param[in] function y, if nuclear correlation is used make sure this is the correct bra function /// @param[in] CCPairFunction u, - double + static double make_xy_op_u(const CCFunction& x, const CCFunction& y, const CCConvolutionOperator& op, - const CCPairFunction& u) const; + const CCPairFunction& u); /// Helper Function which returns /// @return @@ -661,8 +661,8 @@ class CCPotentials { /// Calculates the CCS/CIS singles potential for the excited state: result = Fock_residue + V /// the V part is stored in the intermediate_potentials structure /// the expectation value is calculated and updated - vector_real_function_3d - get_CCS_potential_ex(World& world, CC_vecfunction& x, const bool print, Info& info) const; + static vector_real_function_3d + get_CCS_potential_ex(World& world, CC_vecfunction& x, const bool print, Info& info); /// Calculates the CC2 singles potential for the Excited state: result = Fock_residue + V /// the V part is stored in the intermediate_potentials structure diff --git a/src/madness/chem/CCStructures.cc b/src/madness/chem/CCStructures.cc index 8d79c6b9e02..ea61d645210 100644 --- a/src/madness/chem/CCStructures.cc +++ b/src/madness/chem/CCStructures.cc @@ -106,12 +106,12 @@ madness::vector_real_function_3d CCIntermediatePotentials::operator()(const CC_vecfunction& f, const PotentialType& type) const { output("Getting " + assign_name(type) + " for " + f.name(0)); vector_real_function_3d result; - if (type == POT_singles_ and (f.type == PARTICLE or f.type == MIXED)) return current_singles_potential_gs_; - else if (type == POT_singles_ and f.type == RESPONSE) return current_singles_potential_ex_; - else if (type == POT_s2b_ and f.type == PARTICLE) return current_s2b_potential_gs_; - else if (type == POT_s2b_ and f.type == RESPONSE) return current_s2b_potential_ex_; - else if (type == POT_s2c_ and f.type == PARTICLE) return current_s2c_potential_gs_; - else if (type == POT_s2c_ and f.type == RESPONSE) return current_s2c_potential_ex_; + if (type == POT_singles_ and (f.type == PARTICLE or f.type == MIXED)) result= current_singles_potential_gs_; + else if (type == POT_singles_ and f.type == RESPONSE) result= current_singles_potential_ex_; + else if (type == POT_s2b_ and f.type == PARTICLE) result= current_s2b_potential_gs_; + else if (type == POT_s2b_ and f.type == RESPONSE) result= current_s2b_potential_ex_; + else if (type == POT_s2c_ and f.type == PARTICLE) result= current_s2c_potential_gs_; + else if (type == POT_s2c_ and f.type == RESPONSE) result= current_s2c_potential_ex_; else if (f.type == HOLE) { output(assign_name(type) + " is zero for HOLE states"); // result = zero_functions(f.size()); @@ -120,7 +120,12 @@ CCIntermediatePotentials::operator()(const CC_vecfunction& f, const PotentialTyp MADNESS_EXCEPTION("Potential was not supposed to be stored", 1); } - if (result.empty()) output("!!!WARNING: Potential is empty!!!"); + if (result.empty()) { + output("!!!WARNING: Potential is empty!!!"); + } else { + World& world=result.front().world(); + if (parameters.debug()) print_size(world,result, "potential"); + } return result; } @@ -145,6 +150,10 @@ void CCIntermediatePotentials::insert(const vector_real_function_3d& potential, const CC_vecfunction& f, const PotentialType& type) { output("Storing potential: " + assign_name(type) + " for " + f.name(0)); + if (parameters.debug()) { + World& world=potential.front().world(); + print_size(world, potential, "potential"); + } MADNESS_ASSERT(!potential.empty()); if (type == POT_singles_ && (f.type == PARTICLE || f.type == MIXED)) current_singles_potential_gs_ = potential; else if (type == POT_singles_ && f.type == RESPONSE) current_singles_potential_ex_ = potential; @@ -534,7 +543,7 @@ MacroTaskConstantPart::operator() (const std::vector& pair, World& world =info.mo_ket[0].world(); CC_vecfunction singles(gs_singles, PARTICLE, info.parameters.freeze()); - CC_vecfunction exsingles(gs_singles, PARTICLE, info.parameters.freeze()); + CC_vecfunction exsingles(ex_singles, RESPONSE, info.parameters.freeze()); resultT result = zero_functions_compressed(world, pair.size()); @@ -579,7 +588,8 @@ MacroTaskIteratePair::operator()(const std::vector& pair, resultT result = zero_functions_compressed(world, pair.size()); for (size_t i = 0; i < pair.size(); i++) { - result[i]= CCPotentials::iterate_pair_macrotask(world, pair[i], gs_singles, local_coupling[i], info, maxiter).function(); + result[i]= CCPotentials::iterate_pair_macrotask(world, pair[i], gs_singles, ex_singles, + local_coupling[i], info, maxiter).function(); } return result; diff --git a/src/madness/chem/ccpairfunction.cc b/src/madness/chem/ccpairfunction.cc index 8d2ec9a52a4..f6cb1a0cfdf 100644 --- a/src/madness/chem/ccpairfunction.cc +++ b/src/madness/chem/ccpairfunction.cc @@ -277,6 +277,8 @@ CCPairFunction& CCPairFunction::multiply_with_op_inplace(const s template double CCPairFunction::make_xy_u(const CCFunction& xx, const CCFunction& yy) const { + CCPairFunction bra(xx.function,yy.function); + return inner(bra,*this); T result = 0.0; if (is_pure()) { World& world=xx.function.world(); diff --git a/src/madness/chem/projector.h b/src/madness/chem/projector.h index 00d4ef957c4..ce348ef35a2 100644 --- a/src/madness/chem/projector.h +++ b/src/madness/chem/projector.h @@ -441,6 +441,8 @@ namespace madness { template resultT operator()(const resultT& argument) const { + + if (projector0.type()=="PProjector") return projector1(projector0(argument)); return projector0(projector1(argument)); } }; From ab988a991aeeeed354167567eebb04b09f3d2aed Mon Sep 17 00:00:00 2001 From: fbischoff Date: Wed, 17 Jul 2024 13:52:57 +0200 Subject: [PATCH 19/54] checkpoint: He lrcc2 works --- src/madness/chem/CC2.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/madness/chem/CC2.cc b/src/madness/chem/CC2.cc index 0e4a829e14c..cbcb1a25e6b 100644 --- a/src/madness/chem/CC2.cc +++ b/src/madness/chem/CC2.cc @@ -1050,8 +1050,8 @@ CC2::initialize_pairs(Pairs& pairs, const CCState ftype, const CalcType output("Initialize " + assign_name(ctype) + " Pairs for " + assign_name(ftype)); bool restarted = false; - std::vector vconst_part; - load_function(world,vconst_part,"constant_part"); + // std::vector vconst_part; + // load_function(world,vconst_part,"constant_part"); for (size_t i = parameters.freeze(); i < CCOPS.mo_ket().size(); i++) { for (size_t j = i; j < CCOPS.mo_ket().size(); j++) { @@ -1094,8 +1094,8 @@ CC2::initialize_pairs(Pairs& pairs, const CCState ftype, const CalcType } // tmp.excitation = excitation; - // tmp.constant_part = const_part; - tmp.constant_part = vconst_part[0]; + tmp.constant_part = const_part; + // tmp.constant_part = vconst_part[0]; print_header1("loading constant part"); pairs.insert(i, j, tmp); CCPotentials::compute_excited_pair_energy(world, pairs(i, j), x, info); From ff0ac850637165aff54f493cd23f50c831e70a1a Mon Sep 17 00:00:00 2001 From: fbischoff Date: Wed, 17 Jul 2024 22:53:57 +0200 Subject: [PATCH 20/54] checkpoint: He lrcc2 works -- fixes --- src/madness/chem/CCPotentials.cc | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/src/madness/chem/CCPotentials.cc b/src/madness/chem/CCPotentials.cc index 46c9e7e453d..7f8f03a9631 100644 --- a/src/madness/chem/CCPotentials.cc +++ b/src/madness/chem/CCPotentials.cc @@ -513,6 +513,8 @@ double CCPotentials::compute_excited_pair_energy(World& world, const CCPair& d, const CC_vecfunction& x, const Info& info) { // const CC_vecfunction xbra(make_bra(x), RESPONSE, info.parameters.freeze()); // for (const auto& f: d.functions) f.print_size("doubles functions in ex pair energy"); + MADNESS_CHECK_THROW(x.type == RESPONSE, "x must be of type RESPONSE"); + MADNESS_CHECK_THROW(x.size()==info.get_active_mo_bra().size(), "x must have the same size as the active space"); const CC_vecfunction xbra(info.R_square*x.get_vecfunction(), RESPONSE, info.parameters.freeze()); const CCFunction& xbi = xbra(d.i); const CCFunction& mobj = info.mo_bra[d.j]; @@ -1118,16 +1120,11 @@ CCPair CCPotentials::iterate_pair_macrotask(World& world, solver.do_print = (world.rank() == 0); CCPair result=pair; - try { - real_function_6d tmp(world); - load(tmp,"iteration00"); - result.update_u(tmp); - print("loading iteration from file"); - tmp.print_size("iteration00 from file"); - return result; - } catch (...) {} + // only the u-part of omega - double omega_partial=CCPotentials::compute_excited_pair_energy(world, result, ex_singles, info); + double omega_partial=0.0; + if (result.ctype == CT_MP2) omega_partial = CCPotentials::compute_pair_correlation_energy(world, info, result); + else if (result.type == EXCITED_STATE) omega_partial = CCPotentials::compute_excited_pair_energy(world, result, ex_singles, info); for (size_t iter = 0; iter < maxiter; iter++) { if (world.rank()==0) print_header3(assign_name(result.ctype) + "-Microiteration"); @@ -1152,11 +1149,8 @@ CCPair CCPotentials::iterate_pair_macrotask(World& world, CCTimer timer_addup(world, "Add constant parts and update pair " + result.name()); real_function_6d unew = Q12(GVmp2 + constant_part); - // unew.print_size("unew"); - // unew = CCOPS.apply_Q12t(unew, CCOPS.mo_ket()); - // unew.print_size("Q12unew"); - //unew.truncate().reduce_rank(); // already done in Q12 application at the end if (info.parameters.debug()) unew.print_size("Q12(unew)"); + const real_function_6d residue = result.function() - unew; const double error = residue.norm2(); if (info.parameters.kain()) { @@ -1167,20 +1161,17 @@ CCPair CCPotentials::iterate_pair_macrotask(World& world, kain_update.print_size("Kain-Update-Function not truncated"); kain_update.truncate().reduce_rank(); kain_update.print_size("Kain-Update-Function truncated"); - // result.update_u(copy(kain_update)); result.update_u(copy(kain_update)); } else { - // result.update_u(unew); result.update_u(unew); } timer_addup.info(true, result.function().norm2()); double omega_new = 0.0; - double delta = 0.0; if (result.ctype == CT_MP2) omega_new = CCPotentials::compute_pair_correlation_energy(world, info, result); else if (result.type == EXCITED_STATE) omega_new = CCPotentials::compute_excited_pair_energy(world, result, ex_singles, info); - delta = omega_partial - omega_new; + double delta = omega_partial - omega_new; const double current_norm = result.function().norm2(); From 58b69bdbc53771cc47c741a283e40ac2a9716e90 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Fri, 19 Jul 2024 10:50:54 +0200 Subject: [PATCH 21/54] checkpoint: He lrcc2 works --- src/madness/chem/CC2.cc | 62 +++---- src/madness/chem/CC2.h | 53 ++---- src/madness/chem/CCPotentials.cc | 26 +-- src/madness/chem/CCPotentials.h | 304 ++++++++++++++++++------------- 4 files changed, 223 insertions(+), 222 deletions(-) diff --git a/src/madness/chem/CC2.cc b/src/madness/chem/CC2.cc index cbcb1a25e6b..e1e25eae254 100644 --- a/src/madness/chem/CC2.cc +++ b/src/madness/chem/CC2.cc @@ -494,7 +494,7 @@ double CC2::solve_mp2_coupled(Pairs& doubles, Info& info) { auto residual=u-unew; // some statistics - auto [rmsrnorm, maxrnorm]=residual_stats(residual); + auto [rmsrnorm, maxrnorm]=CCPotentials::residual_stats(residual); // update the pair functions if (parameters.kain()) { @@ -671,53 +671,46 @@ bool CC2::iterate_lrcc2_pairs(World& world, const CC_vecfunction& cc2_s, const CC_vecfunction lrcc2_s, Pairs& lrcc2_d, const Info& info) { // output.section("Solve LRCC2 for Excitation energy " + std::to_string(double(lrcc2_s.omega))); - print_header2("Solve LRCC2 for Excitation energy " + std::to_string(double(lrcc2_s.omega))); + if (world.rank()==0) { + print_header3("Solving LRCC2 doubles equations"); + print("starting at time ",wall_time()); + print("using macrotasks with redirected output"); + } MADNESS_ASSERT(lrcc2_s.type == RESPONSE); auto triangular_map=PairVectorMap::triangular_map(info.parameters.freeze(),info.mo_ket.size()); auto pair_vec=Pairs::pairs2vector(lrcc2_d,triangular_map); - // make new constant part - { - std::vector cp; - // try { - // load_function(world, cp, "constant_part"); - // } catch (...) { - MacroTaskConstantPart tc; - MacroTask task(world, tc); - // std::vector constant_part_vec = task(pair_vec, cc2_s.get_vecfunction(), - cp = task(pair_vec, cc2_s.get_vecfunction(), - lrcc2_s.get_vecfunction(), info) ; - // save_function( cp, "constant_part"); - // } - - for (int i=0; i vdummy_3d; // dummy vectors // temporary fix: create dummy functions to that the cloud is not confused real_function_6d tmp=real_factory_6d(world).functor([](const coord_6d& r){return 0.0;}); std::vector vdummy_6d(pair_vec.size(),tmp); // dummy vectors - const std::size_t maxiter=3; + const std::size_t maxiter=10; auto unew = task1(pair_vec, vdummy_6d, cc2_s, lrcc2_s, info, maxiter); // get some statistics std::vector> uold; for (const auto & p : pair_vec) uold.push_back(p.function()); auto residual=uold-unew; - auto [rmsrnorm, rmsrmax] = residual_stats(residual); + double nold=norm2(world,uold); + double nnew=norm2(world,unew); + print("norm(old), norm(new) ",nold,nnew); + auto [rmsrnorm, rmsrmax] = CCPotentials::residual_stats(residual); + CCPotentials::print_convergence("LRCC2 doubles",rmsrnorm, rmsrmax,0,0); // update the pair functions for (int i=0; i& doubles, Info& info) cons for (int i=0; i::vector2pairs(pair_vec,triangular_map); - auto [rmsrnorm,maxrnorm]=residual_stats(residual); + auto [rmsrnorm,maxrnorm]=CCPotentials::residual_stats(residual); bool doubles_converged=rmsrnorm& gs_doubles, const CC_vecfunction& gs_singles, co const double omega_cis = ex_singles.omega; for (size_t iter = 0; iter < parameters.iter_max(); iter++) { - output.section("Macroiteration " + std::to_string(int(iter)) + " of LRCC2"); - bool dconv = iterate_lrcc2_pairs(world, gs_singles, ex_singles, ex_doubles, info); - bool sconv = iterate_lrcc2_singles(world, gs_singles, gs_doubles, ex_singles, ex_doubles, info); - update_reg_residues_ex(world, gs_singles, ex_singles, ex_doubles, info); - if (dconv and sconv) break; + print_header2("Macroiteration " + std::to_string(int(iter)) + " of LRCC2 for energy "+std::to_string(ex_singles.omega)); + bool sconv = iterate_lrcc2_pairs(world, gs_singles, ex_singles, ex_doubles, info); + bool dconv = iterate_lrcc2_singles(world, gs_singles, gs_doubles, ex_singles, ex_doubles, info); + // update_reg_residues_ex(world, gs_singles, ex_singles, ex_doubles, info); + if (sconv and dconv) break; } + const double omega_cc2 = ex_singles.omega; const std::string msg = "Excitation " + std::to_string(int(excitation)); results_ex.push_back(std::make_pair(msg, std::make_pair(omega_cis, omega_cc2))); diff --git a/src/madness/chem/CC2.h b/src/madness/chem/CC2.h index 7708e82d74f..ed67a07cf45 100644 --- a/src/madness/chem/CC2.h +++ b/src/madness/chem/CC2.h @@ -116,20 +116,6 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { output("Plotted " + msg); } - /// return RMS norm and max norm of residuals - static std::pair residual_stats(const std::vector& residual) { - if (residual.size()==0) return std::make_pair(0.0,0.0); - World& world=residual.front().world(); - auto errors=norm2s(world,residual); - double rnorm=0.0, maxrnorm=0.0; - for (double& e : errors) { - maxrnorm=std::max(maxrnorm,e); - rnorm+=e*e; - } - rnorm=sqrt(rnorm/errors.size()); - return std::make_pair(rnorm,maxrnorm); - } - /// The World World& world; /// Structure holds all the parameters used in the CC2 calculation @@ -234,14 +220,15 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { CC_vecfunction old_singles(singles); for (auto& tmp : singles.functions) old_singles(tmp.first).function = copy(tmp.second.function); + double old_omega=0.0; // KAIN solver typedef vector_function_allocator allocT; typedef XNonlinearSolver >, double, allocT> solverT; - allocT alloc(world, singles.size()); solverT solver(allocT(world, singles.size())); solver.do_print = (world.rank() == 0); + for (size_t iter = 0; iter < maxiter; iter++) { output.subsection("Microiteration " + std::to_string(iter) + " of " + assign_name(ctype) + "-Singles"); CCTimer time(world, "Microiteration " + std::to_string(iter) + " of " + assign_name(ctype) + "-Singles"); @@ -289,6 +276,7 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { time_V.info(true, norm2(world, V)); if (ctype == CT_LRCCS or ctype == CT_LRCC2 or ctype == CT_ADC2) { + old_omega=omega; omega = singles.omega; // computed with the potential } @@ -333,6 +321,7 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { const Tensor R2GVinnerGV = inner(world, info.R_square*GV, GV); const Tensor R2rinnerr = inner(world, info.R_square*residual, residual); const double R2vector_error = sqrt(R2rinnerr.sum()); + auto [rmsresidual, maxresidual]=CCPotentials::residual_stats(residual); // print information if (world.rank() == 0) std::cout << "\n\n-----Results of current interation:-----\n"; @@ -353,44 +342,32 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { // make second order update (only for response) if (ctype == CT_LRCC2 or ctype == CT_LRCCS) { - output("\nMake 2nd order energy update:"); - // include nuclear factors - { - // vector_real_function_3d bra_res = mul(world, nemo->ncf->square(), residual); - // vector_real_function_3d bra_GV = mul(world, nemo->ncf->square(), GV); - double Rtmp = inner(world, info.R_square*residual, V).sum(); - double Rtmp2 = inner(world, info.R_square*GV, GV).sum(); - const double Rdelta = (0.5 * Rtmp / Rtmp2); - double old_omega = omega; - output("Delta-Update is not used"); - if (world.rank() == 0) - std::cout << "omega, old_omega, delta" << std::fixed - << std::setprecision(info.parameters.output_prec() + 2) << omega << ", " << old_omega << ", " - << Rdelta << "\n\n"; - } - + double Rtmp = inner(world, info.R_square*residual, V).sum(); + double Rtmp2 = inner(world, info.R_square*GV, GV).sum(); + const double Rdelta = (0.5 * Rtmp / Rtmp2); + if (world.rank() == 0) std::cout << "omega, second-order update (FYI): " << std::fixed + << std::setprecision(info.parameters.output_prec() + 2) << omega << ", " << Rdelta << "\n\n"; } // update singles singles.omega = omega; - vector_real_function_3d new_singles = GV; + vector_real_function_3d new_singles = truncate(GV); if (info.parameters.kain()) new_singles = solver.update(singles.get_vecfunction(), residual); - print_size(world, new_singles, "new_singles"); - truncate(world, new_singles); - print_size(world, new_singles, "new_singles"); + if (info.parameters.debug()) { + print_size(world, new_singles, "new_singles"); + } for (size_t i = 0; i < GV.size(); i++) { singles(i + info.parameters.freeze()).function = copy(new_singles[i]); } - // update intermediates - // CCOPS.update_intermediates(singles); - // update reg_residues of doubles if (ctype==CT_CC2) update_reg_residues_gs(world, singles,gs_doubles, info); else if(ctype==CT_LRCC2) update_reg_residues_ex(world, singles2,singles,ex_doubles, info); + CCPotentials::print_convergence(singles.name(0),rmsresidual,rmsresidual,omega-old_omega,iter); converged = (R2vector_error < info.parameters.dconv_3D()); + time.info(); if (converged) break; if (ctype == CT_LRCCS) break; // for CCS just one iteration to check convergence diff --git a/src/madness/chem/CCPotentials.cc b/src/madness/chem/CCPotentials.cc index 7f8f03a9631..c1005084ed4 100644 --- a/src/madness/chem/CCPotentials.cc +++ b/src/madness/chem/CCPotentials.cc @@ -1151,16 +1151,15 @@ CCPair CCPotentials::iterate_pair_macrotask(World& world, real_function_6d unew = Q12(GVmp2 + constant_part); if (info.parameters.debug()) unew.print_size("Q12(unew)"); - const real_function_6d residue = result.function() - unew; - const double error = residue.norm2(); + const real_function_6d residual = result.function() - unew; + double rmsresidual=residual.norm2(); + if (info.parameters.kain()) { - real_function_6d kain_update = copy(solver.update(result.function(), residue)); + real_function_6d kain_update = copy(solver.update(result.function(), residual)); // kain_update = CCOPS.apply_Q12t(kain_update, CCOPS.mo_ket()); kain_update = Q12(kain_update); - kain_update.print_size("Kain-Update-Function not truncated"); - kain_update.truncate().reduce_rank(); - kain_update.print_size("Kain-Update-Function truncated"); + if (info.parameters.debug()) kain_update.print_size("Kain-Update-Function"); result.update_u(copy(kain_update)); } else { result.update_u(unew); @@ -1172,25 +1171,14 @@ CCPair CCPotentials::iterate_pair_macrotask(World& world, if (result.ctype == CT_MP2) omega_new = CCPotentials::compute_pair_correlation_energy(world, info, result); else if (result.type == EXCITED_STATE) omega_new = CCPotentials::compute_excited_pair_energy(world, result, ex_singles, info); double delta = omega_partial - omega_new; - - const double current_norm = result.function().norm2(); - omega_partial = omega_new; - if (world.rank() == 0) { - std::cout << std::fixed - << std::setw(50) << std::setfill('#') - << "\n" << "Iteration " << iter << " of pair " << result.name() - << std::setprecision(4) << "||u|| = " << current_norm - << "\n" << std::setprecision(10) << "error = " << error << "\nomega(partial) = " << omega_partial << "\ndelta = " - << delta << "\n" - << std::setw(50) << std::setfill('#') << "\n"; - } + print_convergence(pair.name(),rmsresidual,rmsresidual,delta,iter); // output("\n--Iteration " + stringify(iter) + " ended--"); // save(result.function(), result.name()); // timer_mp2.info(); - bool converged=(fabs(error) < info.parameters.dconv_6D()) and (fabs(delta) < info.parameters.econv_pairs()); + bool converged=(rmsresidual < info.parameters.dconv_6D()) and (fabs(delta) < info.parameters.econv_pairs()); if (converged) { if (world.rank()==0) print("Iteration converged after",iter,"iterations"); break; diff --git a/src/madness/chem/CCPotentials.h b/src/madness/chem/CCPotentials.h index 665712e1919..0a00f506f0f 100644 --- a/src/madness/chem/CCPotentials.h +++ b/src/madness/chem/CCPotentials.h @@ -16,30 +16,29 @@ #include namespace madness { - /// Class which calculates all types of CC2 Potentials class CCPotentials { public: CCPotentials(World& world_, const std::shared_ptr nemo, const CCParameters& param); - void reset_nemo(const std::shared_ptr nemo){ - nemo_=nemo; - mo_ket_=(make_mo_ket(*nemo)); - mo_bra_=(make_mo_bra(*nemo)); - orbital_energies_=init_orbital_energies(*nemo); + void reset_nemo(const std::shared_ptr nemo) { + nemo_ = nemo; + mo_ket_ = (make_mo_ket(*nemo)); + mo_bra_ = (make_mo_bra(*nemo)); + orbital_energies_ = init_orbital_energies(*nemo); }; Info update_info(const CCParameters& parameters, const std::shared_ptr nemo) const { Info info; - info.mo_bra=mo_bra().get_vecfunction(); - info.mo_ket=mo_ket().get_vecfunction(); - info.molecular_coordinates=nemo->get_calc()->molecule.get_all_coords_vec(); - info.parameters=parameters; - info.R_square=nemo->R_square; - info.U1=nemo->ncf->U1vec(); - info.U2=nemo->ncf->U2(); - info.intermediate_potentials=get_potentials; - info.orbital_energies=orbital_energies_; + info.mo_bra = mo_bra().get_vecfunction(); + info.mo_ket = mo_ket().get_vecfunction(); + info.molecular_coordinates = nemo->get_calc()->molecule.get_all_coords_vec(); + info.parameters = parameters; + info.R_square = nemo->R_square; + info.U1 = nemo->ncf->U1vec(); + info.U2 = nemo->ncf->U2(); + info.intermediate_potentials = get_potentials; + info.orbital_energies = orbital_energies_; return info; } @@ -47,7 +46,8 @@ class CCPotentials { ~CCPotentials() {}; /// forms the regularized functions from Q and Qt Ansatz for CIS(D) where tau=0 and t=mo so that Qt=Q - void test_pair_consistency(const CCPairFunction& u, const size_t i, const size_t j, const CC_vecfunction& x) const; + void test_pair_consistency(const CCPairFunction& u, const size_t i, const size_t j, + const CC_vecfunction& x) const; bool test_compare_pairs(const CCPair& pair1, const CCPair& pair2) const; @@ -64,9 +64,10 @@ class CCPotentials { /// @param[in] f the function which will be loaded /// @param[in] name of the file in which the function was stored /// @return true or false depending on if the data was found on disc - template + template bool load_function(Function& f, const std::string name) const { - bool exists = archive::ParallelInputArchive::exists(world, name.c_str()); + bool exists = archive::ParallelInputArchive< + archive::BinaryFstreamInputArchive>::exists(world, name.c_str()); if (exists) { if (world.rank() == 0) print("loading function", name); archive::ParallelInputArchive ar(world, name.c_str()); @@ -76,7 +77,8 @@ class CCPotentials { f.truncate(); f.print_size(name); return true; - } else return false; + } + else return false; } /// Plotting (convenience) @@ -86,7 +88,7 @@ class CCPotentials { void plot(const real_function_3d& f, const std::string& msg, const bool doprint = true) const; /// print size of a function - template + template void print_size(const Function& f, const std::string& msg, const bool print = true) const { if (print) f.print_size(msg); } @@ -121,14 +123,14 @@ class CCPotentials { /// get the corresponding mo bra vectors to a ket vector vector_real_function_3d get_mo_bra(const CC_vecfunction& ket) const { vector_real_function_3d result; - for (const auto& ktmp:ket.functions) { + for (const auto& ktmp : ket.functions) { result.push_back(mo_bra_(ktmp.first).function); } return result; } /// returns a specific mo - CCFunction mo_ket(const size_t& i) const { + CCFunction mo_ket(const size_t& i) const { return mo_ket_(i); } @@ -138,7 +140,7 @@ class CCPotentials { } /// returns a specific mo multiplied with the squared nuclear correlation factor - CCFunction mo_bra(const size_t& i) const { + CCFunction mo_bra(const size_t& i) const { return mo_bra_(i); } @@ -182,7 +184,7 @@ class CCPotentials { /// makes the t intermediates /// t_i = mo_ket_(i) + tau /// i = tau.i - CCFunction make_t_intermediate(const CCFunction& tau) const; + CCFunction make_t_intermediate(const CCFunction& tau) const; private: /// Helper function to initialize the const mo_bra and ket elements adn orbital energies @@ -198,17 +200,17 @@ class CCPotentials { init_orbital_energies(const Nemo& nemo) const; public: - /// return the regularized MP2 ansatz: |\tau_ij> = |u_ij> + Q12 f12 |ij> static CCPair make_pair_mp2(const real_function_6d& u, const size_t i, const size_t j, const Info& info); /// return the regularized CC2 ansatz: |\tau_ij> = |u_ij> + Q12t f12 |t_i t_j> static CCPair make_pair_cc2(const real_function_6d& u, const CC_vecfunction& gs_singles, - const size_t i, const size_t j, const Info& info); + const size_t i, const size_t j, const Info& info); /// return the regularized CC2 ansatz: |x_ij> = |u_ij> + Q12t f12 |t_i t_j> + ????? static CCPair make_pair_lrcc2(World& world, const CalcType& ctype, const real_function_6d& u, - const CC_vecfunction& gs_singles, const CC_vecfunction& ex_singles, const size_t i, const size_t j, const Info& info); + const CC_vecfunction& gs_singles, const CC_vecfunction& ex_singles, + const size_t i, const size_t j, const Info& info); // Pair functions @@ -253,9 +255,9 @@ class CCPotentials { /// @param[out] 2* - , where i and j are determined by u (see CC_Pair class) static double compute_pair_correlation_energy(World& world, - const Info& info, - const CCPair& u, - const CC_vecfunction& singles = CC_vecfunction(PARTICLE)); + const Info& info, + const CCPair& u, + const CC_vecfunction& singles = CC_vecfunction(PARTICLE)); /// Compute CC2 correlation energy /// @param[in] The Pair_function @@ -265,7 +267,8 @@ class CCPotentials { /// @param world /// @param info static double - compute_cc2_correlation_energy(World& world, const CC_vecfunction& singles, const Pairs& doubles, const Info& info); + compute_cc2_correlation_energy(World& world, const CC_vecfunction& singles, const Pairs& doubles, + const Info& info); static double @@ -299,7 +302,7 @@ class CCPotentials { /// Static function for the 6D Fock residue for use in macrotask static madness::real_function_6d fock_residue_6d_macrotask(World& world, const CCPair& u, const CCParameters& parameters, - const std::vector< madness::Vector >& all_coords_vec, + const std::vector>& all_coords_vec, const std::vector& mo_ket, const std::vector& mo_bra, const std::vector& U1, @@ -308,10 +311,10 @@ class CCPotentials { /// Static version of make_constant_part_mp2 to be called from macrotask. static madness::real_function_6d make_constant_part_mp2_macrotask(World& world, const CCPair& pair, const std::vector& mo_ket, - const std::vector& mo_bra, - const CCParameters& parameters, const real_function_3d& Rsquare, - const std::vector& U1, - const std::vector argument); + const std::vector& mo_bra, + const CCParameters& parameters, const real_function_3d& Rsquare, + const std::vector& U1, + const std::vector argument); /// Compute the constant part of MP2, CC2 or LR-CC2 /// @@ -330,11 +333,11 @@ class CCPotentials { /// Static function to iterate the mp2 pairs from macrotask static madness::real_function_6d update_pair_mp2_macrotask(World& world, const CCPair& pair, const CCParameters& parameters, - const std::vector< madness::Vector >& all_coords_vec, - const std::vector& mo_ket, - const std::vector& mo_bra, - const std::vector& U1, - const real_function_3d& U2, const real_function_6d& mp2_coupling); + const std::vector>& all_coords_vec, + const std::vector& mo_ket, + const std::vector& mo_bra, + const std::vector& U1, + const real_function_3d& U2, const real_function_6d& mp2_coupling); /// iterate a pair for MP2, CC2, LRCC2 on constant singles @@ -355,7 +358,7 @@ class CCPotentials { /// where t(1/2) = |i> + 1/2|tau_i> , t(1/2) = th real_function_6d make_constant_part_cc2_gs(const CCPair& u, const CC_vecfunction& tau, - const real_convolution_6d *Gscreen = NULL) const; + const real_convolution_6d* Gscreen = NULL) const; /// Function evaluates the consant part of the ground state for CC2 if the Qt Ansatz is used /// @param[out]The result is \f$ Q12(G(Qt12((Vreg+V_{coupling})|titj> + [F,Qt]f12|titj>))) \f$ with \f$ |t_k> = |tau_k> + |k> and Qt = Q - \sum_k |tau_k> + 1/2|tau_i> , t(1/2) = th real_function_6d make_constant_part_cc2_Qt_gs(const CCPair& u, const CC_vecfunction& tau, - const real_convolution_6d *Gscreen = NULL) const; + const real_convolution_6d* Gscreen = NULL) const; /// Function evaluates the consant part of the Excited state for CIS(D) if the Q Ansatz is used real_function_6d - make_constant_part_cispd(const CCPair& u, const CC_vecfunction& x, const real_convolution_6d *Gscreen = NULL) const; + make_constant_part_cispd(const CCPair& u, const CC_vecfunction& x, + const real_convolution_6d* Gscreen = NULL) const; /// Function evaluates the consant part of the Excited state for CIS(D) if the Qt Ansatz is used real_function_6d make_constant_part_cispd_Qt(const CCPair& u, const CC_vecfunction& x, - const real_convolution_6d *Gscreen = NULL) const; + const real_convolution_6d* Gscreen = NULL) const; /// Function evaluates the consant part of the Excited state for CC2 if the Q Ansatz is used real_function_6d make_constant_part_cc2_ex(const CCPair& u, const CC_vecfunction& tau, const CC_vecfunction& x, - const real_convolution_6d *Gscreen = NULL); + const real_convolution_6d* Gscreen = NULL); /// Function evaluates the consant part of the Excited state for CC2 if the Qt Ansatz is used real_function_6d make_constant_part_cc2_Qt_ex(const CCPair& u, const CC_vecfunction& tau, const CC_vecfunction& x, - const real_convolution_6d *Gscreen = NULL); + const real_convolution_6d* Gscreen = NULL); /// Apply the Regularization potential /// \f$ V_{reg} = [ U_e - [K,f12] + f12(F12-eij) ]|titj> \f$ @@ -396,7 +400,8 @@ class CCPotentials { /// @param[in] pointer to bsh operator (in order to screen) /// @param[out] the regularization potential (unprojected), see equation above real_function_6d - apply_Vreg(const CCFunction& ti, const CCFunction& tj, const real_convolution_6d *Gscreen = NULL) const; + apply_Vreg(const CCFunction& ti, const CCFunction& tj, + const real_convolution_6d* Gscreen = NULL) const; /// Apply the Regularization potential /// \f$ V_{reg} = [ U_e - [K,f12] + f12(F12-eij) + [F,Qt] ]|titj> \f$ @@ -404,8 +409,8 @@ class CCPotentials { /// @param[in] tj, second function in the ket ... /// @param[in] pointer to bsh operator (in order to screen) /// @param[out] the regularization potential (unprojected), see equation above - std::vector> - static apply_Vreg(World& world, const CCFunction& ti, const CCFunction& tj, + std::vector> + static apply_Vreg(World& world, const CCFunction& ti, const CCFunction& tj, const CC_vecfunction& gs_singles, const CC_vecfunction& ex_singles, const Info& info, const std::vector& argument, const double bsh_eps); @@ -413,12 +418,12 @@ class CCPotentials { madness::real_function_6d static apply_Vreg_macrotask(World& world, const std::vector& mo_ket, - const std::vector& mo_bra, - const CCParameters& parameters, const real_function_3d& Rsquare, - const std::vector& U1, const size_t& i, const size_t& j, - const FuncType& x_type, const FuncType& y_type, - const std::vector argument, - const real_convolution_6d *Gscreen = NULL); + const std::vector& mo_bra, + const CCParameters& parameters, const real_function_3d& Rsquare, + const std::vector& U1, const size_t& i, const size_t& j, + const FuncType& x_type, const FuncType& y_type, + const std::vector argument, + const real_convolution_6d* Gscreen = NULL); /// evaluates: \f$ (F(1)-ei)|ti> (x) |tj> + |ti> (x) (F(2)-ej)|tj> \f$ with the help of the singles potential /// singles equation is: (F-ei)|ti> = - V(ti) @@ -429,7 +434,8 @@ class CCPotentials { /// @param[in] tj, second function in the ket ... /// @param[in] pointer to bsh operator (in order to screen) real_function_6d - apply_reduced_F1(const CCFunction& ti, const CCFunction& tj, const real_convolution_6d *Gscreen = NULL) const; + apply_reduced_F1(const CCFunction& ti, const CCFunction& tj, + const real_convolution_6d* Gscreen = NULL) const; /// evaluates: \f$ (F(1)-ei)|ti> (x) |tj> + |ti> (x) (F(2)-ej)|tj> \f$ with the help of the singles potential /// singles equation is: (F-ei)|ti> = - V(ti) @@ -440,8 +446,8 @@ class CCPotentials { /// @param[in] tj, second function in the ket ... /// @param[in] pointer to bsh operator (in order to screen) real_function_6d - static apply_reduced_F(World& world, const CCFunction& ti, const CCFunction& tj, - const Info& info, const real_convolution_6d *Gscreen = NULL); + static apply_reduced_F(World& world, const CCFunction& ti, const CCFunction& tj, + const Info& info, const real_convolution_6d* Gscreen = NULL); /// Apply Ue on a tensor product of two 3d functions: Ue(1,2) |x(1)y(2)> (will be either |ij> or |\tau_i\tau_j> or mixed forms) /// The Transformed electronic regularization potential (Kutzelnigg) is R_{12}^{-1} U_e R_{12} with R_{12} = R_1*R_2 @@ -454,7 +460,8 @@ class CCPotentials { /// @param[in] The BSH operator to screen: Has to be in NS form, Gscreen->modified == true /// @return R^-1U_eR|x,y> the transformed electronic smoothing potential applied on |x,y> : real_function_6d - apply_transformed_Ue(const CCFunction& x, const CCFunction& y, const real_convolution_6d *Gscreen = NULL) const; + apply_transformed_Ue(const CCFunction& x, const CCFunction& y, + const real_convolution_6d* Gscreen = NULL) const; /// Static version of apply_transformed_Ue for the use in a macrotask. /// Will eventually replace the former. @@ -463,25 +470,25 @@ class CCPotentials { const CCParameters& parameters, const real_function_3d& Rsquare, const std::vector& U1, const size_t& i, const size_t& j, const FuncType& x_type, const FuncType& y_type, - const real_convolution_6d *Gscreen = NULL); + const real_convolution_6d* Gscreen = NULL); real_function_6d - static apply_Ue(World& world, const CCFunction& phi_i, const CCFunction& phi_j, - const Info& info, const real_convolution_6d *Gscreen); + static apply_Ue(World& world, const CCFunction& phi_i, const CCFunction& phi_j, + const Info& info, const real_convolution_6d* Gscreen); static real_function_6d - apply_KffK(World& world, const CCFunction& phi_i, const CCFunction& phi_j, - const Info& info, const real_convolution_6d *Gscreen) ; - static CCPairFunction - apply_commutator_F_Qt_f12(World& world, const CCFunction& phi_i, const CCFunction& phi_j, - const CC_vecfunction& gs_singles, const CC_vecfunction& ex_singles, - const Info& info, const real_convolution_6d *Gscreen) ; - - static CCPairFunction - apply_commutator_F_dQt_f12(World& world, const CCFunction& phi_i, const CCFunction& phi_j, - const CC_vecfunction& gs_singles, const CC_vecfunction& ex_singles, - const Info& info, const real_convolution_6d *Gscreen) ; + apply_KffK(World& world, const CCFunction& phi_i, const CCFunction& phi_j, + const Info& info, const real_convolution_6d* Gscreen); + static CCPairFunction + apply_commutator_F_Qt_f12(World& world, const CCFunction& phi_i, const CCFunction& phi_j, + const CC_vecfunction& gs_singles, const CC_vecfunction& ex_singles, + const Info& info, const real_convolution_6d* Gscreen); + + static CCPairFunction + apply_commutator_F_dQt_f12(World& world, const CCFunction& phi_i, const CCFunction& phi_j, + const CC_vecfunction& gs_singles, const CC_vecfunction& ex_singles, + const Info& info, const real_convolution_6d* Gscreen); /// Apply Ue on a tensor product of two 3d functions: Ue(1,2) |x(1)y(2)> (will be either |ij> or |\tau_i\tau_j> or mixed forms) /// The Transformed electronic regularization potential (Kutzelnigg) is R_{12}^{-1} U_e R_{12} with R_{12} = R_1*R_2 @@ -495,20 +502,21 @@ class CCPotentials { /// the f12K|xy> part will be screened with the BSH while the Kf12|xy> can not be screened with the BSH operator but maybe with the coulomb /// @return R^-1U_eR|x,y> the transformed electronic smoothing potential applied on |x,y> : real_function_6d - apply_exchange_commutator(const CCFunction& x, const CCFunction& y, - const real_convolution_6d *Gscreen = NULL) const; + apply_exchange_commutator(const CCFunction& x, const CCFunction& y, + const real_convolution_6d* Gscreen = NULL) const; - real_function_6d - static apply_exchange_commutator_macrotask(World& world, const std::vector& mo_ket, - const std::vector& mo_bra, const real_function_3d& Rsquare, - const size_t& i, const size_t& j, const CCParameters& parameters, - const FuncType& x_type, const FuncType& y_type, - const real_convolution_6d *Gscreen = NULL); + real_function_6d + static apply_exchange_commutator_macrotask(World& world, const std::vector& mo_ket, + const std::vector& mo_bra, + const real_function_3d& Rsquare, + const size_t& i, const size_t& j, const CCParameters& parameters, + const FuncType& x_type, const FuncType& y_type, + const real_convolution_6d* Gscreen = NULL); /// This applies the exchange commutator, see apply_exchange_commutator function for information real_function_6d - apply_exchange_commutator1(const CCFunction& x, const CCFunction& y, - const real_convolution_6d *Gscreen = NULL) const; + apply_exchange_commutator1(const CCFunction& x, const CCFunction& y, + const real_convolution_6d* Gscreen = NULL) const; /// Helper Function which performs the operation \f$ \f$ /// @param[in] function x, if nuclear correlation is used make sure this is the correct bra function @@ -516,9 +524,11 @@ class CCPotentials { /// @param[in] function a, /// @param[in] function b, double - make_xy_gf_ab(const CCFunction& x, const CCFunction& y, const CCFunction& a, const CCFunction& b) const; + make_xy_gf_ab(const CCFunction& x, const CCFunction& y, const CCFunction& a, + const CCFunction& b) const; - double make_xy_ff_ab(const CCFunction& x, const CCFunction& y, const CCFunction& a, const CCFunction& b) const { + double make_xy_ff_ab(const CCFunction& x, const CCFunction& y, + const CCFunction& a, const CCFunction& b) const { error("xy_ff_ab not yet implemented"); return 0.0; } @@ -532,22 +542,25 @@ class CCPotentials { /// loops over every entry in the vector and accumulates results /// helper function for CIS(D) energy static double - make_xy_op_u(const CCFunction& x, const CCFunction& y, const CCConvolutionOperator& op, - const std::vector>& u); + make_xy_op_u(const CCFunction& x, const CCFunction& y, + const CCConvolutionOperator& op, + const std::vector>& u); /// returns for a vector of CCPairFunction /// the result is accumulated for every vercotr /// helper functions for CIS(D) energy static double - make_xy_u(const CCFunction& x, const CCFunction& y, const std::vector>& u); + make_xy_u(const CCFunction& x, const CCFunction& y, + const std::vector>& u); /// Functions which operate with the CCPairFunction structure /// @param[in] function x, if nuclear correlation is used make sure this is the correct bra function /// @param[in] function y, if nuclear correlation is used make sure this is the correct bra function /// @param[in] CCPairFunction u, static double - make_xy_op_u(const CCFunction& x, const CCFunction& y, const CCConvolutionOperator& op, - const CCPairFunction& u); + make_xy_op_u(const CCFunction& x, const CCFunction& y, + const CCConvolutionOperator& op, + const CCPairFunction& u); /// Helper Function which returns /// @return @@ -556,19 +569,21 @@ class CCPotentials { /// @param[in] function a, /// @param[in] function b, double - make_xy_op_ab(const CCFunction& x, const CCFunction& y, const CCConvolutionOperator& op, const CCFunction& a, - const CCFunction& b) const; + make_xy_op_ab(const CCFunction& x, const CCFunction& y, + const CCConvolutionOperator& op, const CCFunction& a, + const CCFunction& b) const; /// get the correct pair function as vector of CCPairFunction functions /// @param[in] The pair functions /// @param[out] The demanded pair function as vector of CCPairFunction functions (includes regularization tails) - static std::vector> - get_pair_function(const Pairs& pairs, const size_t i, const size_t j) ; + static std::vector> + get_pair_function(const Pairs& pairs, const size_t i, const size_t j); /// returns _2 static real_function_3d - apply_s2b_operation(World& world, const CCFunction& bra, const CCPairFunction& u, const size_t particle, const Info& info); + apply_s2b_operation(World& world, const CCFunction& bra, const CCPairFunction& u, + const size_t particle, const Info& info); /// dummy to avoid confusion and for convenience real_function_6d swap_particles(const real_function_6d& f) const { @@ -576,8 +591,8 @@ class CCPotentials { } /// swap the particles of the CCPairFunction and return a new vector of swapped functions - static std::vector> swap_particles(const std::vector>& f) { - std::vector> swapped; + static std::vector> swap_particles(const std::vector>& f) { + std::vector> swapped; for (size_t i = 0; i < f.size(); i++) swapped.push_back(f[i].swap_particles()); return swapped; } @@ -586,8 +601,8 @@ class CCPotentials { /// @param[in] 6D function 1 /// @param[in] 6D function 2 double - overlap(const CCPairFunction& f1, const CCPairFunction& f2) const { - return inner(f1,f2,nemo_->ncf->square()); + overlap(const CCPairFunction& f1, const CCPairFunction& f2) const { + return inner(f1, f2, nemo_->ncf->square()); }; /// Computes the squared norm of the pair function @@ -620,8 +635,9 @@ class CCPotentials { /// Apply the Qt projector on a CCPairFunction /// works in principle like apply_Ot - CCPairFunction - apply_Qt(const CCPairFunction& f, const CC_vecfunction& t, const size_t particle, const double c = 1.0) const; + CCPairFunction + apply_Qt(const CCPairFunction& f, const CC_vecfunction& t, const size_t particle, + const double c = 1.0) const; /// Apply Ot projector on decomposed or op_decomposed 6D function /// The function does not work with type==pure right now (not needed) @@ -632,14 +648,14 @@ class CCPotentials { /// for CCPairFunction type == op_decomposd the function si f=op|xy> and we have for particle==1 /// \f$ a_k = t_k \f$ /// \f$ b_k = *y \f$ - CCPairFunction - apply_Ot(const CCPairFunction& f, const CC_vecfunction& t, const size_t particle) const; + CCPairFunction + apply_Ot(const CCPairFunction& f, const CC_vecfunction& t, const size_t particle) const; /// Apply the Greens Operator to a CCPairFunction /// For CCPairFunction only type pure and type decomposed is supported /// for the op_decomposed type a pure function can be constructed (not needed therefore not implemented yet) real_function_6d - apply_G(const CCPairFunction& u, const real_convolution_6d& G) const; + apply_G(const CCPairFunction& u, const real_convolution_6d& G) const; /// Apply BSH Operator and count time real_function_6d apply_G(const real_function_6d& f, const real_convolution_6d& G) const { @@ -656,7 +672,8 @@ class CCPotentials { /// Calculates the CC2 singles potential for the ground state: result = Fock_residue + V /// the V part is stored in the intermediate_potentials structure static vector_real_function_3d - get_CC2_singles_potential_gs(World& world, const CC_vecfunction& singles, const Pairs& doubles, Info& info); + get_CC2_singles_potential_gs(World& world, const CC_vecfunction& singles, const Pairs& doubles, + Info& info); /// Calculates the CCS/CIS singles potential for the excited state: result = Fock_residue + V /// the V part is stored in the intermediate_potentials structure @@ -668,7 +685,8 @@ class CCPotentials { /// the V part is stored in the intermediate_potentials structure static vector_real_function_3d get_CC2_singles_potential_ex(World& world, const CC_vecfunction& gs_singles, - const Pairs& gs_doubles, CC_vecfunction& ex_singles, const Pairs& response_doubles, Info& info); + const Pairs& gs_doubles, CC_vecfunction& ex_singles, + const Pairs& response_doubles, Info& info); /// Calculates the CC2 singles potential for the Excited state: result = Fock_residue + V /// the V part is stored in the intermediate_potentials structure @@ -741,7 +759,7 @@ class CCPotentials { /// the K operator runs over ALL orbitals (also the frozen ones) static real_function_3d - K(World& world, const CCFunction& f, const Info& info); + K(World& world, const CCFunction& f, const Info& info); /// static version of k above for access from macrotask. will eventually replace former. real_function_3d @@ -773,13 +791,13 @@ class CCPotentials { /// Static version of apply_K above for access from macrotask. Will eventually replace former. real_function_6d static apply_K_macrotask(World& world, const std::vector& mo_ket, - const std::vector& mo_bra, - const real_function_6d& u, const size_t& particle, const CCParameters& parameters); + const std::vector& mo_bra, + const real_function_6d& u, const size_t& particle, const CCParameters& parameters); /// Apply the Exchange operator on a tensor product multiplied with f12 /// !!! Prefactor of (-1) is not inclued in K here !!!! real_function_6d - apply_Kf(const CCFunction& x, const CCFunction& y) const; + apply_Kf(const CCFunction& x, const CCFunction& y) const; /// Apply fK on a tensor product of two 3D functions /// fK|xy> = fK_1|xy> + fK_2|xy> @@ -787,23 +805,25 @@ class CCPotentials { /// @param[in] y, the second 3D function in |xy> structure holds index i and type (HOLE, PARTICLE, MIXED, UNDEFINED) /// @param[in] BSH operator to screen, has to be in modified NS form, Gscreen->modified()==true; real_function_6d - apply_fK(const CCFunction& x, const CCFunction& y, const real_convolution_6d *Gscreen = NULL) const; + apply_fK(const CCFunction& x, const CCFunction& y, + const real_convolution_6d* Gscreen = NULL) const; /// Creates a 6D function with the correlation factor and two given CCFunctions real_function_6d - make_f_xy(const CCFunction& x, const CCFunction& y, const real_convolution_6d *Gscreen = NULL) const; + make_f_xy(const CCFunction& x, const CCFunction& y, + const real_convolution_6d* Gscreen = NULL) const; /// Creates a 6D function with the correlation factor and two given CCFunctions real_function_6d - static make_f_xy(World& world, const CCFunction& x, const CCFunction& y, - const Info& info, const real_convolution_6d *Gscreen = NULL); + static make_f_xy(World& world, const CCFunction& x, const CCFunction& y, + const Info& info, const real_convolution_6d* Gscreen = NULL); real_function_6d - static make_f_xy_macrotask( World& world, const real_function_3d& x_ket, const real_function_3d& y_ket, - const real_function_3d& x_bra, const real_function_3d& y_bra, - const size_t& i, const size_t& j, const CCParameters& parameters, - const FuncType& x_type, const FuncType& y_type, - const real_convolution_6d *Gscreen = NULL); + static make_f_xy_macrotask(World& world, const real_function_3d& x_ket, const real_function_3d& y_ket, + const real_function_3d& x_bra, const real_function_3d& y_bra, + const size_t& i, const size_t& j, const CCParameters& parameters, + const FuncType& x_type, const FuncType& y_type, + const real_convolution_6d* Gscreen = NULL); /// unprojected ccs potential /// returns 2kgtk|ti> - kgti|tk> @@ -811,6 +831,30 @@ class CCPotentials { static vector_real_function_3d ccs_unprojected(World& world, const CC_vecfunction& ti, const CC_vecfunction& tk, const Info& info); + /// return RMS norm and max norm of residuals + template + static std::pair residual_stats(const std::vector>& residual) { + if (residual.size() == 0) return std::make_pair(0.0, 0.0); + World& world = residual.front().world(); + auto errors = norm2s(world, residual); + double rnorm = 0.0, maxrnorm = 0.0; + for (double& e : errors) { + maxrnorm = std::max(maxrnorm, e); + rnorm += e * e; + } + rnorm = sqrt(rnorm / errors.size()); + return std::make_pair(rnorm, maxrnorm); + } + + static void print_convergence(const std::string name, const double rmsresidual, const double maxresidual, + const double energy_diff, const int iteration) { + const std::size_t bufsize = 255; + char msg[bufsize]; + std::snprintf(msg, bufsize, + "convergence of %s in iteration %2d at time %8.1fs: rms/max residual, energy change %.1e %.1e %.1e", + name.c_str(), iteration, wall_time(), rmsresidual, maxresidual,energy_diff); + print(msg); + } // integrals from singles potentials @@ -836,7 +880,8 @@ class CCPotentials { /// -(2 - )* double - x_s6(const CC_vecfunction& x, const CC_vecfunction& t1, const CC_vecfunction& t2, const CC_vecfunction& t3) const; + x_s6(const CC_vecfunction& x, const CC_vecfunction& t1, const CC_vecfunction& t2, + const CC_vecfunction& t3) const; /// 2.0 - double @@ -909,27 +954,25 @@ class CCPotentials { // update the intermediates void update_intermediates(const CC_vecfunction& t) { g12->update_elements(mo_bra_, t); -// g12.sanity(); + // g12.sanity(); f12->update_elements(mo_bra_, t); -// f12.sanity(); + // f12.sanity(); } /// clear stored potentials /// if a response function is given only the response potentials are cleared (the GS potentials dont change anymore) void clear_potentials(const CC_vecfunction& t) const { - if (t.type == RESPONSE) { output("Clearing Response Singles-Potentials"); get_potentials.clear_response(); - } else { + } + else { output("Clearing all stored Singles-Potentials"); get_potentials.clear_all(); } } public: - - // member variables /// MPI World World& world; @@ -945,21 +988,20 @@ class CCPotentials { std::vector orbital_energies_; /// the coulomb operator with all intermediates public: - std::shared_ptr> g12; + std::shared_ptr> g12; /// the f12 operator with all intermediates - std::shared_ptr> f12; + std::shared_ptr> f12; /// the correlation factor, holds necessary regularized potentials CorrelationFactor corrfac; /// Manager for stored intermediate potentials which are s2c, s2b and the whole singles potentials without fock-residue for GS and EX state mutable CCIntermediatePotentials get_potentials; /// POD for basis and intermediates Info info; + public: /// Messenger structure for formated output and to store warnings CCMessenger output; - }; - } /* namespace madness */ #endif /* SRC_APPS_CHEM_CCPOTENTIALS_H_ */ From 41393a8ddf44f275125a2e3b32aa01f43a93438e Mon Sep 17 00:00:00 2001 From: fbischoff Date: Fri, 19 Jul 2024 23:23:19 +0200 Subject: [PATCH 22/54] checkpoint: He lrcc2 works --- src/madness/chem/CC2.cc | 8 ++++---- src/madness/chem/CC2.h | 14 ++++++++------ src/madness/chem/CCPotentials.h | 1 + src/madness/chem/CCStructures.h | 2 +- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/madness/chem/CC2.cc b/src/madness/chem/CC2.cc index e1e25eae254..b293c011f27 100644 --- a/src/madness/chem/CC2.cc +++ b/src/madness/chem/CC2.cc @@ -859,9 +859,9 @@ CC2::solve_lrcc2(Pairs& gs_doubles, const CC_vecfunction& gs_singles, co const double omega_cis = ex_singles.omega; for (size_t iter = 0; iter < parameters.iter_max(); iter++) { - print_header2("Macroiteration " + std::to_string(int(iter)) + " of LRCC2 for energy "+std::to_string(ex_singles.omega)); - bool sconv = iterate_lrcc2_pairs(world, gs_singles, ex_singles, ex_doubles, info); - bool dconv = iterate_lrcc2_singles(world, gs_singles, gs_doubles, ex_singles, ex_doubles, info); + print_header2("Macroiteration " + std::to_string(int(iter)) + " of LRCC2 for excitation energy "+std::to_string(ex_singles.omega)); + bool dconv = iterate_lrcc2_pairs(world, gs_singles, ex_singles, ex_doubles, info); + bool sconv = iterate_lrcc2_singles(world, gs_singles, gs_doubles, ex_singles, ex_doubles, info); // update_reg_residues_ex(world, gs_singles, ex_singles, ex_doubles, info); if (sconv and dconv) break; } @@ -1090,7 +1090,7 @@ CC2::initialize_pairs(Pairs& pairs, const CCState ftype, const CalcType // tmp.excitation = excitation; tmp.constant_part = const_part; // tmp.constant_part = vconst_part[0]; - print_header1("loading constant part"); + // print_header1("loading constant part"); pairs.insert(i, j, tmp); CCPotentials::compute_excited_pair_energy(world, pairs(i, j), x, info); } else error("Unknown pairtype"); diff --git a/src/madness/chem/CC2.h b/src/madness/chem/CC2.h index ed67a07cf45..5823e053ce7 100644 --- a/src/madness/chem/CC2.h +++ b/src/madness/chem/CC2.h @@ -307,9 +307,10 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { // Normalize Singles if it is excited state if (ctype == CT_LRCCS or ctype == CT_LRCC2 or ctype == CT_ADC2) { - output("Normalizing new singles"); - const double norm=inner(GV,info.R_square*GV); - scale(world, GV, 1.0 / norm); + Nemo::normalize(GV, info.R); + // output("Normalizing new singles"); + // const double norm=inner(GV,info.R_square*GV); + // scale(world, GV, 1.0 / norm); } else output("Singles not normalized"); // residual @@ -353,9 +354,10 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { singles.omega = omega; vector_real_function_3d new_singles = truncate(GV); if (info.parameters.kain()) new_singles = solver.update(singles.get_vecfunction(), residual); - if (info.parameters.debug()) { - print_size(world, new_singles, "new_singles"); - } + if (info.parameters.debug()) print_size(world, new_singles, "new_singles"); + if (ctype == CT_LRCCS or ctype == CT_LRCC2 or ctype == CT_ADC2) Nemo::normalize(new_singles, info.R); + if (info.parameters.debug()) print_size(world, new_singles, "new_singles normalized"); + for (size_t i = 0; i < GV.size(); i++) { singles(i + info.parameters.freeze()).function = copy(new_singles[i]); } diff --git a/src/madness/chem/CCPotentials.h b/src/madness/chem/CCPotentials.h index 0a00f506f0f..4c5683bd104 100644 --- a/src/madness/chem/CCPotentials.h +++ b/src/madness/chem/CCPotentials.h @@ -35,6 +35,7 @@ class CCPotentials { info.molecular_coordinates = nemo->get_calc()->molecule.get_all_coords_vec(); info.parameters = parameters; info.R_square = nemo->R_square; + info.R = nemo->R; info.U1 = nemo->ncf->U1vec(); info.U2 = nemo->ncf->U2(); info.intermediate_potentials = get_potentials; diff --git a/src/madness/chem/CCStructures.h b/src/madness/chem/CCStructures.h index 3cfac06239e..98cf0b4b7a9 100644 --- a/src/madness/chem/CCStructures.h +++ b/src/madness/chem/CCStructures.h @@ -1209,7 +1209,7 @@ struct Info { CCParameters parameters; std::vector orbital_energies; CCIntermediatePotentials intermediate_potentials; - Function R_square, U2; + Function R_square, U2, R;; std::vector> U1; vector_real_function_3d get_active_mo_ket() const { From 9b2a7410d67e4c7d4498312695bd077f1ca9e3c2 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Mon, 22 Jul 2024 09:45:43 +0200 Subject: [PATCH 23/54] checkpoint: update thresholds --- src/madness/chem/CC2.cc | 4 ++++ src/madness/chem/CC2.h | 2 ++ src/madness/chem/CCStructures.cc | 12 +++--------- src/madness/chem/CCStructures.h | 12 ++++++------ 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/madness/chem/CC2.cc b/src/madness/chem/CC2.cc index b293c011f27..af31f502d72 100644 --- a/src/madness/chem/CC2.cc +++ b/src/madness/chem/CC2.cc @@ -685,6 +685,7 @@ CC2::iterate_lrcc2_pairs(World& world, const CC_vecfunction& cc2_s, MacroTaskConstantPart tc; MacroTask task(world, tc); auto cp = task(pair_vec, cc2_s.get_vecfunction(), lrcc2_s.get_vecfunction(), info) ; + print_size(world,cp,"constant part in iter"); for (int i=0; i> uold; for (const auto & p : pair_vec) uold.push_back(p.function()); @@ -860,6 +863,7 @@ CC2::solve_lrcc2(Pairs& gs_doubles, const CC_vecfunction& gs_singles, co for (size_t iter = 0; iter < parameters.iter_max(); iter++) { print_header2("Macroiteration " + std::to_string(int(iter)) + " of LRCC2 for excitation energy "+std::to_string(ex_singles.omega)); + update_reg_residues_ex(world, gs_singles, ex_singles, ex_doubles, info); bool dconv = iterate_lrcc2_pairs(world, gs_singles, ex_singles, ex_doubles, info); bool sconv = iterate_lrcc2_singles(world, gs_singles, gs_doubles, ex_singles, ex_doubles, info); // update_reg_residues_ex(world, gs_singles, ex_singles, ex_doubles, info); diff --git a/src/madness/chem/CC2.h b/src/madness/chem/CC2.h index 5823e053ce7..536052ed832 100644 --- a/src/madness/chem/CC2.h +++ b/src/madness/chem/CC2.h @@ -228,6 +228,7 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { solverT solver(allocT(world, singles.size())); solver.do_print = (world.rank() == 0); + print_size(world, singles.get_vecfunction(), "singles before iteration"); for (size_t iter = 0; iter < maxiter; iter++) { output.subsection("Microiteration " + std::to_string(iter) + " of " + assign_name(ctype) + "-Singles"); @@ -375,6 +376,7 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { if (ctype == CT_LRCCS) break; // for CCS just one iteration to check convergence } time_all.info(); + print_size(world, singles.get_vecfunction(), "singles after iteration"); // Assign the overall changes bool no_change = true; diff --git a/src/madness/chem/CCStructures.cc b/src/madness/chem/CCStructures.cc index ea61d645210..32b5aa0a8d1 100644 --- a/src/madness/chem/CCStructures.cc +++ b/src/madness/chem/CCStructures.cc @@ -175,19 +175,13 @@ void CCParameters::set_derived_values() { set_derived_value("tight_thresh_6d",thresh_6D()*0.1); set_derived_value("thresh_3d",thresh_6D()*0.01); set_derived_value("tight_thresh_3d",thresh_3D()*0.1); -// if (thresh_operators == uninitialized) thresh_operators = 1.e-6; -// if (thresh_operators_3D == uninitialized) thresh_operators_3D = thresh_operators; -// if (thresh_operators_6D == uninitialized) thresh_operators_6D = thresh_operators; -// if (thresh_bsh_3D == uninitialized) thresh_bsh_3D = thresh_operators_3D; -// if (thresh_bsh_6D == uninitialized) thresh_bsh_6D = thresh_operators_6D; -// if (thresh_poisson == uninitialized) thresh_poisson = thresh_operators_3D; -// if (thresh_f12 == uninitialized) thresh_f12 = thresh_operators_3D; set_derived_value("thresh_ue",tight_thresh_6D()); - set_derived_value("dconv_6d",thresh_6D()); - set_derived_value("dconv_3d",thresh_6D()); + set_derived_value("dconv_6d",3.0*thresh_6D()); + set_derived_value("dconv_3d",3.0*thresh_3D()); set_derived_value("econv",0.1*dconv_6D()); set_derived_value("econv_pairs",econv()); + set_derived_value("no_compute_gs",no_compute()); set_derived_value("no_compute_mp2",no_compute() and no_compute_gs()); set_derived_value("no_compute_cc2",no_compute() and no_compute_gs()); diff --git a/src/madness/chem/CCStructures.h b/src/madness/chem/CCStructures.h index 98cf0b4b7a9..669970abb73 100644 --- a/src/madness/chem/CCStructures.h +++ b/src/madness/chem/CCStructures.h @@ -230,11 +230,11 @@ struct CCParameters : public QCCalculationParametersBase { initialize < double > ("thresh_Ue", thresh_operators, "ue threshold"); initialize < double > ("econv", thresh, "overal convergence threshold "); initialize < double > ("econv_pairs", 0.1*thresh, "convergence threshold for pairs"); - initialize < double > ("dconv_3d", 0.01*thresh, "convergence for cc singles"); - initialize < double > ("dconv_6d", thresh, "convergence for cc doubles"); + initialize < double > ("dconv_3d", 0.03*thresh, "convergence for cc singles"); + initialize < double > ("dconv_6d", 3.0*thresh, "convergence for cc doubles"); initialize < std::size_t > ("iter_max", 10, "max iterations"); - initialize < std::size_t > ("iter_max_3d", 10, "max iterations"); - initialize < std::size_t > ("iter_max_6d", 10, "max iterations"); + initialize < std::size_t > ("iter_max_3d", 10, "max iterations for singles"); + initialize < std::size_t > ("iter_max_6d", 10, "max iterations for doubles"); initialize < std::pair> ("only_pair", {-1, -1}, "compute only a single pair"); initialize < bool > ("restart", false, "restart"); initialize < bool > ("no_compute", false, "no compute"); @@ -254,11 +254,11 @@ struct CCParameters : public QCCalculationParametersBase { initialize < long > ("freeze", -1, "number of frozen orbitals: -1: automatic"); initialize < bool > ("test", false, ""); // choose if Q for the constant part of MP2 and related calculations should be decomposed: GQV or GV - GO12V - initialize < bool > ("decompose_Q", true, ""); + initialize < bool > ("decompose_Q", true, "always true",{true}); // if true the ansatz for the CC2 ground state pairs is |tau_ij> = |u_ij> + Qtf12|titj>, with Qt = Q - |tau> ("QtAnsatz", true, ""); + initialize < bool > ("QtAnsatz", true, "always true",{true}); // a vector containing the excitations which shall be optizmized later (with CIS(D) or CC2) initialize < std::vector> ("excitations", {}, "vector containing the excitations"); From e3491158895b8f773babd4775e36693450b3471f Mon Sep 17 00:00:00 2001 From: fbischoff Date: Tue, 23 Jul 2024 14:57:59 +0200 Subject: [PATCH 24/54] fixing frozen orbitals bugs --- src/madness/chem/CCPotentials.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/madness/chem/CCPotentials.cc b/src/madness/chem/CCPotentials.cc index c1005084ed4..37f72d80215 100644 --- a/src/madness/chem/CCPotentials.cc +++ b/src/madness/chem/CCPotentials.cc @@ -130,7 +130,7 @@ CCPair CCPotentials::make_pair_lrcc2(World& world, const CalcType& ctype, const MADNESS_ASSERT(!(j < info.parameters.freeze())); // compute the t intermediates for active orbitals only -- they go into the ansatz - const CC_vecfunction t = info.get_active_mo_ket()+gs_singles.get_vecfunction(); + const auto t = CC_vecfunction(info.get_active_mo_ket()+gs_singles.get_vecfunction(),MIXED,info.parameters.freeze()); MADNESS_ASSERT(t.size() == (info.mo_ket.size()-info.parameters.freeze())); // compute the t intermediates for all orbitals -- they go into the projector @@ -390,7 +390,6 @@ CCPotentials::make_pair_ex(const real_function_6d& u, const CC_vecfunction& tau, functions.push_back(res); } } - functions=consolidate(functions); CCPair pair(i, j, EXCITED_STATE, ctype, functions); if (parameters.decompose_Q()) { if (parameters.QtAnsatz()) MADNESS_ASSERT(functions.size() == 9); @@ -398,6 +397,8 @@ CCPotentials::make_pair_ex(const real_function_6d& u, const CC_vecfunction& tau, MADNESS_ASSERT(functions.size() == 7); } else MADNESS_ASSERT(functions.size() == 2); + functions=consolidate(functions); + MADNESS_ASSERT(functions.size() == 3); MADNESS_ASSERT(x.omega != 0.0); const double bsh_eps = get_epsilon(i, j) + x.omega; From 46869c032666a424efc7319b266372811a197321 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Thu, 25 Jul 2024 14:02:18 +0200 Subject: [PATCH 25/54] fixing normalization bug, BH now working --- src/madness/chem/CC2.cc | 2 +- src/madness/chem/CC2.h | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/madness/chem/CC2.cc b/src/madness/chem/CC2.cc index af31f502d72..2901b504cd8 100644 --- a/src/madness/chem/CC2.cc +++ b/src/madness/chem/CC2.cc @@ -761,7 +761,7 @@ CC2::solve_cc2(CC_vecfunction& singles, Pairs& doubles, Info& info) cons ex_singles_dummy.get_vecfunction(), info) ; for (int i=0; i Date: Mon, 29 Jul 2024 18:22:02 -0400 Subject: [PATCH 26/54] local orbitals in lrcc2 --- src/madness/chem/CC2.cc | 39 ++++++++++++++++++++------------ src/madness/chem/CC2.h | 9 ++++---- src/madness/chem/CCPotentials.cc | 2 +- src/madness/chem/CCPotentials.h | 1 + src/madness/chem/CCStructures.cc | 2 +- src/madness/chem/CCStructures.h | 5 +++- 6 files changed, 36 insertions(+), 22 deletions(-) diff --git a/src/madness/chem/CC2.cc b/src/madness/chem/CC2.cc index 2901b504cd8..bffeef0de4c 100644 --- a/src/madness/chem/CC2.cc +++ b/src/madness/chem/CC2.cc @@ -474,7 +474,7 @@ double CC2::solve_mp2_coupled(Pairs& doubles, Info& info) { if (world.rank()==0) print_header3("Starting iteration " + std::to_string(int(iter)) + " of MP2"); // compute the coupling between the pair functions - Pairs coupling=compute_local_coupling(pair_vec); + Pairs coupling=compute_local_coupling(pair_vec, info); auto coupling_vec=Pairs::pairs2vector(coupling,triangular_map); if (parameters.debug()) print_size(world, coupling_vec, "couplingvector"); @@ -556,15 +556,16 @@ double CC2::solve_mp2_coupled(Pairs& doubles, Info& info) { /// add the coupling terms for local MP2 /// @return \sum_{k\neq i} f_ki |u_kj> + \sum_{l\neq j} f_lj |u_il> -Pairs CC2::compute_local_coupling(const Pairs& pairs) const { +Pairs CC2::compute_local_coupling(const Pairs& pairs, const Info& info) { - const int nmo = nemo->get_calc()->amo.size(); + const int nmo = info.mo_ket.size(); + World& world=pairs.allpairs.begin()->second.world(); // temporarily make all N^2 pair functions typedef std::map, real_function_6d> pairsT; pairsT quadratic; - for (int k = parameters.freeze(); k < nmo; ++k) { - for (int l = parameters.freeze(); l < nmo; ++l) { + for (int k = info.parameters.freeze(); k < nmo; ++k) { + for (int l = info.parameters.freeze(); l < nmo; ++l) { if (l >= k) { quadratic[std::make_pair(k, l)] = pairs(k, l); } else { @@ -577,28 +578,29 @@ Pairs CC2::compute_local_coupling(const Pairs fock1 = nemo->compute_fock_matrix(nemo->get_calc()->amo, nemo->get_calc()->aocc); + // Tensor fock1 = nemo->compute_fock_matrix(nemo->get_calc()->amo, nemo->get_calc()->aocc); + Tensor fock1 = copy(info.fock); for (int k = 0; k < nmo; ++k) { if (fock1(k, k) > 0.0) MADNESS_EXCEPTION("positive orbital energies", 1); fock1(k, k) = 0.0; } Pairs coupling; - for (int i = parameters.freeze(); i < nmo; ++i) { + for (int i = info.parameters.freeze(); i < nmo; ++i) { for (int j = i; j < nmo; ++j) { coupling.insert(i, j, real_factory_6d(world).compressed()); } } - for (int i = parameters.freeze(); i < nmo; ++i) { + for (int i = info.parameters.freeze(); i < nmo; ++i) { for (int j = i; j < nmo; ++j) { - for (int k = parameters.freeze(); k < nmo; ++k) { + for (int k = info.parameters.freeze(); k < nmo; ++k) { if (fock1(k, i) != 0.0) { coupling(i, j).gaxpy(1.0, quadratic[std::make_pair(k, j)], fock1(k, i), false); } } - for (int l = parameters.freeze(); l < nmo; ++l) { + for (int l = info.parameters.freeze(); l < nmo; ++l) { if (fock1(l, j) != 0.0) { coupling(i, j).gaxpy(1.0, quadratic[std::make_pair(i, l)], fock1(l, j), false); } @@ -695,14 +697,21 @@ CC2::iterate_lrcc2_pairs(World& world, const CC_vecfunction& cc2_s, } for (const auto& p : pair_vec) p.function().print_size("u before iter"); + // compute the coupling between the pair functions + if (world.rank()==0) print("computing local coupling in the universe"); + Pairs coupling=compute_local_coupling(pair_vec, info); + auto coupling_vec=Pairs::pairs2vector(coupling,triangular_map); + if (info.parameters.debug()) print_size(world, coupling_vec, "couplingvector"); + + // iterate the pair MacroTaskIteratePair t1; MacroTask task1(world, t1); // temporary fix: create dummy functions to that the cloud is not confused - real_function_6d tmp=real_factory_6d(world).functor([](const coord_6d& r){return 0.0;}); - std::vector vdummy_6d(pair_vec.size(),tmp); // dummy vectors + // real_function_6d tmp=real_factory_6d(world).functor([](const coord_6d& r){return 0.0;}); + // std::vector vdummy_6d(pair_vec.size(),tmp); // dummy vectors const std::size_t maxiter=10; - auto unew = task1(pair_vec, vdummy_6d, cc2_s, lrcc2_s, info, maxiter); + auto unew = task1(pair_vec, coupling_vec, cc2_s, lrcc2_s, info, maxiter); for (const auto& u : unew) u.print_size("u after iter"); // get some statistics @@ -770,7 +779,7 @@ CC2::solve_cc2(CC_vecfunction& singles, Pairs& doubles, Info& info) cons // compute the coupling between the pair functions if (world.rank()==0) print("computing local coupling in the universe"); - Pairs coupling=compute_local_coupling(pair_vec); + Pairs coupling=compute_local_coupling(pair_vec, info); auto coupling_vec=Pairs::pairs2vector(coupling,triangular_map); timer1.tag("computing local coupling"); @@ -862,7 +871,7 @@ CC2::solve_lrcc2(Pairs& gs_doubles, const CC_vecfunction& gs_singles, co const double omega_cis = ex_singles.omega; for (size_t iter = 0; iter < parameters.iter_max(); iter++) { - print_header2("Macroiteration " + std::to_string(int(iter)) + " of LRCC2 for excitation energy "+std::to_string(ex_singles.omega)); + if (world.rank()==0) print_header2("Macroiteration " + std::to_string(int(iter)) + " of LRCC2 for excitation energy "+std::to_string(ex_singles.omega)); update_reg_residues_ex(world, gs_singles, ex_singles, ex_doubles, info); bool dconv = iterate_lrcc2_pairs(world, gs_singles, ex_singles, ex_doubles, info); bool sconv = iterate_lrcc2_singles(world, gs_singles, gs_doubles, ex_singles, ex_doubles, info); diff --git a/src/madness/chem/CC2.h b/src/madness/chem/CC2.h index 35171dbb181..aca311ad8a2 100644 --- a/src/madness/chem/CC2.h +++ b/src/madness/chem/CC2.h @@ -366,7 +366,8 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { if (ctype==CT_CC2) update_reg_residues_gs(world, singles,gs_doubles, info); else if(ctype==CT_LRCC2) update_reg_residues_ex(world, singles2,singles,ex_doubles, info); - CCPotentials::print_convergence(singles.name(0),rmsresidual,rmsresidual,omega-old_omega,iter); + if (world.rank()==0) CCPotentials::print_convergence(singles.name(0),rmsresidual, + rmsresidual,omega-old_omega,iter); converged = (R2vector_error < info.parameters.dconv_3D()); time.info(); @@ -485,19 +486,19 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { } /// forward to the other function (converting CCPair to real_function) - Pairs compute_local_coupling(const std::vector &vpairs) const { + static Pairs compute_local_coupling(const std::vector &vpairs, const Info& info) { // create new pairs structure Pairs pairs; for (auto& tmp_pair : vpairs) pairs.insert(tmp_pair.i, tmp_pair.j, tmp_pair); auto ccpair2function = [](const CCPair& a) {return a.function();}; - return compute_local_coupling(pairs.convert(pairs,ccpair2function)); + return compute_local_coupling(pairs.convert(pairs,ccpair2function), info); }; /// add the coupling terms for local MP2 /// \sum_{k\neq i} f_ki |u_kj> + \sum_{l\neq j} f_lj |u_il> - Pairs compute_local_coupling(const Pairs& pairs) const; + static Pairs compute_local_coupling(const Pairs& pairs, const Info& info); double solve_mp2_coupled(Pairs &doubles, Info& info); diff --git a/src/madness/chem/CCPotentials.cc b/src/madness/chem/CCPotentials.cc index 37f72d80215..6fb7a411d9b 100644 --- a/src/madness/chem/CCPotentials.cc +++ b/src/madness/chem/CCPotentials.cc @@ -2939,7 +2939,7 @@ CCPotentials::get_CC2_singles_potential_ex(World& world, const CC_vecfunction& g const double s4a = inner(world, xbra, Vs4a).sum(); const double s4b = inner(world, xbra, Vs4b).sum(); const double s4c = inner(world, xbra, Vs4c).sum(); - std::cout << std::fixed << std::setprecision(10) << "functional response energies:" << "\n=" << ccs + if (world.rank()==0) std::cout << std::fixed << std::setprecision(10) << "functional response energies:" << "\n=" << ccs << "\n=" << s2b << "\n=" << s2c << "\n=" << s4a << "\n=" << s4b << "\n=" << s4c << "\n"; // debug end diff --git a/src/madness/chem/CCPotentials.h b/src/madness/chem/CCPotentials.h index 4c5683bd104..e2f3ccd6b84 100644 --- a/src/madness/chem/CCPotentials.h +++ b/src/madness/chem/CCPotentials.h @@ -40,6 +40,7 @@ class CCPotentials { info.U2 = nemo->ncf->U2(); info.intermediate_potentials = get_potentials; info.orbital_energies = orbital_energies_; + info.fock=nemo->compute_fock_matrix(nemo->get_calc()->amo, nemo->get_calc()->aocc); return info; } diff --git a/src/madness/chem/CCStructures.cc b/src/madness/chem/CCStructures.cc index 32b5aa0a8d1..c7d63baa003 100644 --- a/src/madness/chem/CCStructures.cc +++ b/src/madness/chem/CCStructures.cc @@ -177,7 +177,7 @@ void CCParameters::set_derived_values() { set_derived_value("tight_thresh_3d",thresh_3D()*0.1); set_derived_value("thresh_ue",tight_thresh_6D()); set_derived_value("dconv_6d",3.0*thresh_6D()); - set_derived_value("dconv_3d",3.0*thresh_3D()); + set_derived_value("dconv_3d",0.3*thresh_6D()); set_derived_value("econv",0.1*dconv_6D()); set_derived_value("econv_pairs",econv()); diff --git a/src/madness/chem/CCStructures.h b/src/madness/chem/CCStructures.h index 669970abb73..10696bb9a50 100644 --- a/src/madness/chem/CCStructures.h +++ b/src/madness/chem/CCStructures.h @@ -230,7 +230,7 @@ struct CCParameters : public QCCalculationParametersBase { initialize < double > ("thresh_Ue", thresh_operators, "ue threshold"); initialize < double > ("econv", thresh, "overal convergence threshold "); initialize < double > ("econv_pairs", 0.1*thresh, "convergence threshold for pairs"); - initialize < double > ("dconv_3d", 0.03*thresh, "convergence for cc singles"); + initialize < double > ("dconv_3d", 0.3*thresh, "convergence for cc singles"); initialize < double > ("dconv_6d", 3.0*thresh, "convergence for cc doubles"); initialize < std::size_t > ("iter_max", 10, "max iterations"); initialize < std::size_t > ("iter_max_3d", 10, "max iterations for singles"); @@ -1208,6 +1208,7 @@ struct Info { std::vector> molecular_coordinates; CCParameters parameters; std::vector orbital_energies; + Tensor fock; CCIntermediatePotentials intermediate_potentials; Function R_square, U2, R;; std::vector> U1; @@ -1233,6 +1234,7 @@ struct Info { records+=cloud.store(world,mo_ket); records+=cloud.store(world,parameters); records+=cloud.store(world,orbital_energies); + records+=cloud.store(world,fock); records+=cloud.store(world,intermediate_potentials); records+=cloud.store(world,R_square); records+=cloud.store(world,molecular_coordinates); @@ -1251,6 +1253,7 @@ struct Info { mo_ket=cloud.forward_load>>(world,recordlist); parameters=cloud.forward_load(world,recordlist); orbital_energies=cloud.forward_load>(world,recordlist); + fock=cloud.forward_load>(world,recordlist); intermediate_potentials=cloud.forward_load(world,recordlist); R_square=cloud.forward_load>(world,recordlist); molecular_coordinates=cloud.forward_load>>(world,recordlist); From f9dc6a211d285c3cbf2510a24ad3286262d56f48 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Mon, 5 Aug 2024 12:45:47 -0400 Subject: [PATCH 27/54] update --- src/madness/chem/BSHApply.h | 8 +++- src/madness/chem/CC2.h | 93 ++++++++++++++++++++++--------------- 2 files changed, 62 insertions(+), 39 deletions(-) diff --git a/src/madness/chem/BSHApply.h b/src/madness/chem/BSHApply.h index 137481911f3..f2038877db6 100644 --- a/src/madness/chem/BSHApply.h +++ b/src/madness/chem/BSHApply.h @@ -24,6 +24,7 @@ template class BSHApply { public: + enum return_value {update, residual}; World& world; double levelshift=0.0; double lo=1.e-6; @@ -31,6 +32,7 @@ class BSHApply { bool printme=false; bool destroy_Vpsi=false; Function metric; + return_value ret_value=residual; // return the new orbitals/functions or the residuals public: BSHApply(World& world) : world(world), @@ -91,7 +93,11 @@ class BSHApply { double cpu1=cpu_time(); if (printme) printf("time in BSHApply() %8.4fs\n",cpu1-cpu0); - return std::make_tuple(res,delta_eps); + if (ret_value==update) return std::make_tuple(tmp,delta_eps); + else if (ret_value==residual) return std::make_tuple(res,delta_eps); + else { + MADNESS_EXCEPTION("unknown return value in BSHApply",1); + } } diff --git a/src/madness/chem/CC2.h b/src/madness/chem/CC2.h index aca311ad8a2..4828998fe31 100644 --- a/src/madness/chem/CC2.h +++ b/src/madness/chem/CC2.h @@ -21,6 +21,8 @@ #include #include +#include "BSHApply.h" + namespace madness { class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { @@ -240,29 +242,29 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { // consistency check switch (ctype) { - case CT_CC2: - if (singles.type != PARTICLE) - output.warning("iterate_singles: CC2 demanded but singles are not of type PARTICLE"); - break; - case CT_MP2: MADNESS_EXCEPTION("Demanded Singles Calculation for MP2 ????", 1); - break; - case CT_LRCC2: - if (singles.type != RESPONSE or singles2.type != PARTICLE) - output.warning("iterate_singles: CC2_response_ singles have wrong types"); - break; - case CT_LRCCS: - if (singles.type != RESPONSE) - output.warning("iterate_singles: CCS_response_ singles have wrong types"); - break; - case CT_CISPD: MADNESS_EXCEPTION("Demanded Singles Calculation for CIS(D)", 1); - break; - case CT_ADC2: - MADNESS_ASSERT(singles.type == RESPONSE); - break; - case CT_TEST: MADNESS_EXCEPTION("Iterate Singles not implemented for Experimental calculation", 1); - break; - default: MADNESS_EXCEPTION( - ("Unknown calculation type in iterate singles: " + assign_name(ctype)).c_str(), 1); + case CT_CC2: + if (singles.type != PARTICLE) + output.warning("iterate_singles: CC2 demanded but singles are not of type PARTICLE"); + break; + case CT_MP2: MADNESS_EXCEPTION("Demanded Singles Calculation for MP2 ????", 1); + break; + case CT_LRCC2: + if (singles.type != RESPONSE or singles2.type != PARTICLE) + output.warning("iterate_singles: CC2_response_ singles have wrong types"); + break; + case CT_LRCCS: + if (singles.type != RESPONSE) + output.warning("iterate_singles: CCS_response_ singles have wrong types"); + break; + case CT_CISPD: MADNESS_EXCEPTION("Demanded Singles Calculation for CIS(D)", 1); + break; + case CT_ADC2: + MADNESS_ASSERT(singles.type == RESPONSE); + break; + case CT_TEST: MADNESS_EXCEPTION("Iterate Singles not implemented for Experimental calculation", 1); + break; + default: MADNESS_EXCEPTION( + ("Unknown calculation type in iterate singles: " + assign_name(ctype)).c_str(), 1); } // get potentials @@ -272,7 +274,7 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { else if (ctype == CT_LRCC2) V = CCPotentials::get_CC2_singles_potential_ex(world, singles2, gs_doubles, singles, ex_doubles, info); else if (ctype == CT_LRCCS) V = CCPotentials::get_CCS_potential_ex(world,singles,false, info); -// else if (ctype == CT_ADC2) V = CCOPS.get_ADC2_singles_potential(world, gs_doubles, singles, ex_doubles, info); + // else if (ctype == CT_ADC2) V = CCOPS.get_ADC2_singles_potential(world, gs_doubles, singles, ex_doubles, info); else MADNESS_EXCEPTION("iterate singles: unknown type", 1); time_V.info(true, norm2(world, V)); @@ -281,29 +283,44 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { omega = singles.omega; // computed with the potential } - scale(world, V, -2.0); + // scale(world, V, -2.0); // moved to BSHApply truncate(world, V); - // make bsh operators - CCTimer time_makebsh(world, "Make G-Operators"); - std::vector > > G(singles.size()); - for (size_t i = 0; i < G.size(); i++) { - const double bsh_eps = info.orbital_energies[i + info.parameters.freeze()] + omega; - G[i] = std::shared_ptr >( - BSHOperatorPtr3D(world, sqrt(-2.0 * bsh_eps), info.parameters.lo(), info.parameters.thresh_bsh_3D())); + BSHApply bsh_apply(world); + bsh_apply.ret_value=BSHApply::update; // return the new singles functions, not the residual + bsh_apply.metric=info.R_square; + + // coupling between singles involves the active fock matrix shifted by the excitation energy + auto nfreeze=info.parameters.freeze(); + Tensor fock=info.fock(Slice(nfreeze,-1),Slice(nfreeze,-1)); + for (int i=0; i > > G(singles.size()); +// for (size_t i = 0; i < G.size(); i++) { +// const double bsh_eps = info.orbital_energies[i + info.parameters.freeze()] + omega; +// G[i] = std::shared_ptr >( +// BSHOperatorPtr3D(world, sqrt(-2.0 * bsh_eps), info.parameters.lo(), info.parameters.thresh_bsh_3D())); +// } +// world.gop.fence(); +// time_makebsh.info(); +// +// // apply bsh operators CCTimer time_applyG(world, "Apply G-Operators"); - vector_real_function_3d GV = apply, double, 3>(world, G, V); - world.gop.fence(); + auto [GV, energy_update] = bsh_apply(singles.get_vecfunction(), fock, V); + // vector_real_function_3d GV = apply, double, 3>(world, G, V); +// world.gop.fence(); + // auto GV=res-singles.get_vecfunction(); time_applyG.info(); // apply Q-Projector to result QProjector Q(info.mo_bra,info.mo_ket); - // GV = CCOPS.apply_Qt(GV, CCOPS.mo_ket()); GV = Q(GV); // Normalize Singles if it is excited state From f5100a377390ab300814cc408596d96dc14fc5cb Mon Sep 17 00:00:00 2001 From: fbischoff Date: Tue, 6 Aug 2024 12:09:36 -0400 Subject: [PATCH 28/54] update --- src/madness/chem/CC2.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/madness/chem/CC2.cc b/src/madness/chem/CC2.cc index bffeef0de4c..ef3726512ae 100644 --- a/src/madness/chem/CC2.cc +++ b/src/madness/chem/CC2.cc @@ -792,14 +792,23 @@ CC2::solve_cc2(CC_vecfunction& singles, Pairs& doubles, Info& info) cons auto unew = task1(pair_vec, coupling_vec, singles, dummy_ex_singles, info, maxiter); + std::vector u_old; for (auto p : pair_vec) u_old.push_back(p.function()); + auto residual=u_old-unew; timer1.tag("computing pair function update via macrotasks"); for (int i=0; i::vector2pairs(pair_vec,triangular_map); + // save latest iteration + if (world.rank()==0) print("saving latest iteration to file"); + for (const auto& pair : pair_vec) { + save(pair.constant_part, pair.name() + "_const"); + save(pair.function(), pair.name()); + } + auto [rmsrnorm,maxrnorm]=CCPotentials::residual_stats(residual); bool doubles_converged=rmsrnorm Date: Wed, 7 Aug 2024 11:07:45 -0500 Subject: [PATCH 29/54] remove compiler type warning --- src/madness/world/worldgop.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/madness/world/worldgop.h b/src/madness/world/worldgop.h index 490a457a115..34817a755c5 100644 --- a/src/madness/world/worldgop.h +++ b/src/madness/world/worldgop.h @@ -788,7 +788,7 @@ namespace madness { auto buf0 = std::unique_ptr(new T[nelem_per_maxmsg]); auto buf1 = std::unique_ptr(new T[nelem_per_maxmsg]); - auto reduce_impl = [&,this](T* buf, int nelem) { + auto reduce_impl = [&,this](T* buf, size_t nelem) { MADNESS_ASSERT(nelem <= nelem_per_maxmsg); SafeMPI::Request req0, req1; Tag gsum_tag = world_.mpi.unique_tag(); From 5dc6de51505861bd8262502b4504f51c1eb4557f Mon Sep 17 00:00:00 2001 From: "Robert J. Harrison" Date: Wed, 7 Aug 2024 11:08:15 -0500 Subject: [PATCH 30/54] testing optimized parallel container serialization --- src/madness/world/test_dc.cc | 156 +++++++++++++++++++++++++++++++++-- 1 file changed, 149 insertions(+), 7 deletions(-) diff --git a/src/madness/world/test_dc.cc b/src/madness/world/test_dc.cc index 5197b006dac..930079dd8a5 100644 --- a/src/madness/world/test_dc.cc +++ b/src/madness/world/test_dc.cc @@ -29,10 +29,18 @@ fax: 865-572-0680 */ +//#define MAD_ARCHIVE_DEBUG_ENABLE + +#include + #include #include +#include #include +#include +#include + using namespace madness; using namespace std; @@ -240,16 +248,150 @@ void test_local(World& world) { } +namespace madness { + namespace archive { + /// Write container to parallel archive + template + struct ArchiveStoreImpl< ParallelOutputArchive, WorldContainer > { + static void store(const ParallelOutputArchive& ar, const WorldContainer& t) { + using localarchiveT = VectorOutputArchive; + const long magic = -5881828; // Sitar Indian restaurant in Knoxville (negative to indicate parallel!) + typedef WorldContainer dcT; + using const_iterator = typename dcT::const_iterator; + + const size_t default_size = 100*1024*1024; + + World* world = ar.get_world(); + world->gop.fence(); + + std::vector v; + v.reserve(default_size); + size_t count = 0; + + class op : public TaskInterface { + const size_t ntasks; + const size_t taskid; + const dcT& t; + std::vector& vtotal; + size_t& total_count; + Mutex& mutex; + + public: + op(size_t ntasks, size_t taskid, const dcT& t, std::vector& vtotal, size_t& total_count, Mutex& mutex) + : ntasks(ntasks), taskid(taskid), t(t), vtotal(vtotal), total_count(total_count), mutex(mutex) {} + void run(World& world) { + std::vector v; + v.reserve(std::max(size_t(1024*1024),vtotal.capacity()/ntasks)); + VectorOutputArchive var(v); + const_iterator it=t.begin(); + size_t count = 0; + size_t n = 0; + while (it!=t.end()) { + if ((n%ntasks) == taskid) { + var & *it; + ++count; + } + ++it; + n++; + } + + if (count) { + mutex.lock(); + vtotal.insert(vtotal.end(), v.begin(), v.end()); + total_count += count; + mutex.unlock(); + } + } + }; + + Mutex mutex; + size_t ntasks = std::max(size_t(1), ThreadPool::size()); + for (size_t taskid=0; taskidtaskq.add(new op(ntasks, taskid, t, v, count, mutex)); + world->gop.fence(); + + // Gather all buffers to process 0 + // first gather all of the sizes and counts to a vector in process 0 + int size = v.size(); + std::vector sizes(world->size()); + MPI_Gather(&size, 1, MPI_INT, sizes.data(), 1, MPI_INT, 0, world->mpi.comm().Get_mpi_comm()); + world->gop.sum(count); // just need total number of elements + + // build the cumulative sum of sizes + std::vector offsets(world->size()); + offsets[0] = 0; + for (int i=1; isize(); ++i) offsets[i] = offsets[i-1] + sizes[i-1]; + int total_size = offsets.back() + sizes.back(); + + // gather the vector of data v from each process to process 0 + unsigned char* all_data=0; + if (world->rank() == 0) { + all_data = new unsigned char[total_size]; + } + MPI_Gatherv(v.data(), v.size(), MPI_BYTE, all_data, sizes.data(), offsets.data(), MPI_BYTE, 0, world->mpi.comm().Get_mpi_comm()); + + if (world->rank() == 0) { + auto& localar = ar.local_archive(); + localar & magic & 1; // 1 client + // localar & t; + ArchivePrePostImpl::preamble_store(localar); + localar & -magic & count; + localar.store(all_data, total_size); + ArchivePrePostImpl::postamble_store(localar); + + delete[] all_data; + } + world->gop.fence(); + } + }; + } +} + +void test_florian(World& world) { + WorldContainer c(world); + + Key key1(1); + Node node1(1); + + if (world.rank() == 0) { + for (int i=0; i<100; ++i) { + c.replace(Key(i),Node(i)); + } + } + world.gop.fence(); + + std::vector v; + { + archive::VectorOutputArchive var(v); + archive::ParallelOutputArchive ar(world,var); + ar & c; + } + + WorldContainer c2(world); + { + archive::VectorInputArchive var2(v); + archive::ParallelInputArchive ar2(world,var2); + ar2 & c2; + } + + for (int i=0; i<100; ++i) { + MADNESS_CHECK(c2.find(Key(i)).get()->second.get() == i); + } + + world.gop.fence(); + print("test_florian passed"); +} + int main(int argc, char** argv) { - initialize(argc, argv); - World world(SafeMPI::COMM_WORLD); try { - test0(world); - test1(world); - test1(world); - test1(world); - test_local(world); + World& world = initialize(argc, argv); + // test0(world); + // test1(world); + // test1(world); + // test1(world); + // test_local(world); + test_florian(world); } catch (const SafeMPI::Exception& e) { error("caught an MPI exception"); From 85f305201bdf6c6f0b9c258e506b934c78d43d55 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Wed, 7 Aug 2024 12:21:53 -0400 Subject: [PATCH 31/54] moving serialization to VectorOutputArchive into worlddc.h --- src/madness/world/test_dc.cc | 99 ------------------------------------ src/madness/world/worlddc.h | 95 ++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 99 deletions(-) diff --git a/src/madness/world/test_dc.cc b/src/madness/world/test_dc.cc index 930079dd8a5..d95154c08ad 100644 --- a/src/madness/world/test_dc.cc +++ b/src/madness/world/test_dc.cc @@ -248,105 +248,6 @@ void test_local(World& world) { } -namespace madness { - namespace archive { - /// Write container to parallel archive - template - struct ArchiveStoreImpl< ParallelOutputArchive, WorldContainer > { - static void store(const ParallelOutputArchive& ar, const WorldContainer& t) { - using localarchiveT = VectorOutputArchive; - const long magic = -5881828; // Sitar Indian restaurant in Knoxville (negative to indicate parallel!) - typedef WorldContainer dcT; - using const_iterator = typename dcT::const_iterator; - - const size_t default_size = 100*1024*1024; - - World* world = ar.get_world(); - world->gop.fence(); - - std::vector v; - v.reserve(default_size); - size_t count = 0; - - class op : public TaskInterface { - const size_t ntasks; - const size_t taskid; - const dcT& t; - std::vector& vtotal; - size_t& total_count; - Mutex& mutex; - - public: - op(size_t ntasks, size_t taskid, const dcT& t, std::vector& vtotal, size_t& total_count, Mutex& mutex) - : ntasks(ntasks), taskid(taskid), t(t), vtotal(vtotal), total_count(total_count), mutex(mutex) {} - void run(World& world) { - std::vector v; - v.reserve(std::max(size_t(1024*1024),vtotal.capacity()/ntasks)); - VectorOutputArchive var(v); - const_iterator it=t.begin(); - size_t count = 0; - size_t n = 0; - while (it!=t.end()) { - if ((n%ntasks) == taskid) { - var & *it; - ++count; - } - ++it; - n++; - } - - if (count) { - mutex.lock(); - vtotal.insert(vtotal.end(), v.begin(), v.end()); - total_count += count; - mutex.unlock(); - } - } - }; - - Mutex mutex; - size_t ntasks = std::max(size_t(1), ThreadPool::size()); - for (size_t taskid=0; taskidtaskq.add(new op(ntasks, taskid, t, v, count, mutex)); - world->gop.fence(); - - // Gather all buffers to process 0 - // first gather all of the sizes and counts to a vector in process 0 - int size = v.size(); - std::vector sizes(world->size()); - MPI_Gather(&size, 1, MPI_INT, sizes.data(), 1, MPI_INT, 0, world->mpi.comm().Get_mpi_comm()); - world->gop.sum(count); // just need total number of elements - - // build the cumulative sum of sizes - std::vector offsets(world->size()); - offsets[0] = 0; - for (int i=1; isize(); ++i) offsets[i] = offsets[i-1] + sizes[i-1]; - int total_size = offsets.back() + sizes.back(); - - // gather the vector of data v from each process to process 0 - unsigned char* all_data=0; - if (world->rank() == 0) { - all_data = new unsigned char[total_size]; - } - MPI_Gatherv(v.data(), v.size(), MPI_BYTE, all_data, sizes.data(), offsets.data(), MPI_BYTE, 0, world->mpi.comm().Get_mpi_comm()); - - if (world->rank() == 0) { - auto& localar = ar.local_archive(); - localar & magic & 1; // 1 client - // localar & t; - ArchivePrePostImpl::preamble_store(localar); - localar & -magic & count; - localar.store(all_data, total_size); - ArchivePrePostImpl::postamble_store(localar); - - delete[] all_data; - } - world->gop.fence(); - } - }; - } -} - void test_florian(World& world) { WorldContainer c(world); diff --git a/src/madness/world/worlddc.h b/src/madness/world/worlddc.h index d375c7b9de3..2c5aa4523fc 100644 --- a/src/madness/world/worlddc.h +++ b/src/madness/world/worlddc.h @@ -1680,6 +1680,101 @@ namespace madness { } }; + /// Write container to parallel archive + template + struct ArchiveStoreImpl< ParallelOutputArchive, WorldContainer > { + static void store(const ParallelOutputArchive& ar, const WorldContainer& t) { + using localarchiveT = VectorOutputArchive; + const long magic = -5881828; // Sitar Indian restaurant in Knoxville (negative to indicate parallel!) + typedef WorldContainer dcT; + using const_iterator = typename dcT::const_iterator; + + const size_t default_size = 100*1024*1024; + + World* world = ar.get_world(); + world->gop.fence(); + + std::vector v; + v.reserve(default_size); + size_t count = 0; + + class op : public TaskInterface { + const size_t ntasks; + const size_t taskid; + const dcT& t; + std::vector& vtotal; + size_t& total_count; + Mutex& mutex; + + public: + op(size_t ntasks, size_t taskid, const dcT& t, std::vector& vtotal, size_t& total_count, Mutex& mutex) + : ntasks(ntasks), taskid(taskid), t(t), vtotal(vtotal), total_count(total_count), mutex(mutex) {} + void run(World& world) { + std::vector v; + v.reserve(std::max(size_t(1024*1024),vtotal.capacity()/ntasks)); + VectorOutputArchive var(v); + const_iterator it=t.begin(); + size_t count = 0; + size_t n = 0; + while (it!=t.end()) { + if ((n%ntasks) == taskid) { + var & *it; + ++count; + } + ++it; + n++; + } + + if (count) { + mutex.lock(); + vtotal.insert(vtotal.end(), v.begin(), v.end()); + total_count += count; + mutex.unlock(); + } + } + }; + + Mutex mutex; + size_t ntasks = std::max(size_t(1), ThreadPool::size()); + for (size_t taskid=0; taskidtaskq.add(new op(ntasks, taskid, t, v, count, mutex)); + world->gop.fence(); + + // Gather all buffers to process 0 + // first gather all of the sizes and counts to a vector in process 0 + int size = v.size(); + std::vector sizes(world->size()); + MPI_Gather(&size, 1, MPI_INT, sizes.data(), 1, MPI_INT, 0, world->mpi.comm().Get_mpi_comm()); + world->gop.sum(count); // just need total number of elements + + // build the cumulative sum of sizes + std::vector offsets(world->size()); + offsets[0] = 0; + for (int i=1; isize(); ++i) offsets[i] = offsets[i-1] + sizes[i-1]; + int total_size = offsets.back() + sizes.back(); + + // gather the vector of data v from each process to process 0 + unsigned char* all_data=0; + if (world->rank() == 0) { + all_data = new unsigned char[total_size]; + } + MPI_Gatherv(v.data(), v.size(), MPI_BYTE, all_data, sizes.data(), offsets.data(), MPI_BYTE, 0, world->mpi.comm().Get_mpi_comm()); + + if (world->rank() == 0) { + auto& localar = ar.local_archive(); + localar & magic & 1; // 1 client + // localar & t; + ArchivePrePostImpl::preamble_store(localar); + localar & -magic & count; + localar.store(all_data, total_size); + ArchivePrePostImpl::postamble_store(localar); + + delete[] all_data; + } + world->gop.fence(); + } + }; + template struct ArchiveLoadImpl< ParallelInputArchive, WorldContainer > { /// Read container from parallel archive From b9b87d09a6109846d644a564753f78b6bb9b0f70 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Wed, 7 Aug 2024 14:23:29 -0400 Subject: [PATCH 32/54] moving serialization to VectorOutputArchive into worlddc.h --- src/madness/world/parallel_dc_archive.h | 17 ++- src/madness/world/worlddc.h | 136 ++++++++++++------------ 2 files changed, 84 insertions(+), 69 deletions(-) diff --git a/src/madness/world/parallel_dc_archive.h b/src/madness/world/parallel_dc_archive.h index 7ceb9210267..d178d26cba3 100644 --- a/src/madness/world/parallel_dc_archive.h +++ b/src/madness/world/parallel_dc_archive.h @@ -36,7 +36,10 @@ namespace madness { { close(); } - + + VectorOutputArchive& get_archive() { + return ar; + } template inline typename std::enable_if< madness::is_trivially_serializable::value, void >::type @@ -97,7 +100,17 @@ namespace madness { void close() {} }; - + + + template + struct ArchiveStoreImpl< ParallelOutputArchive, WorldContainer > { + static void store(const ParallelOutputArchive& ar, const WorldContainer& t) { + ParallelOutputArchive par(*(ar.get_world()), ar.local_archive().get_archive()); + par & t; + + } + }; + } diff --git a/src/madness/world/worlddc.h b/src/madness/world/worlddc.h index 2c5aa4523fc..91e57e52c9f 100644 --- a/src/madness/world/worlddc.h +++ b/src/madness/world/worlddc.h @@ -1613,74 +1613,8 @@ namespace madness { } namespace archive { - /// Write container to parallel archive with optional fence - /// \ingroup worlddc - /// Each node (process) is served by a designated IO node. - /// The IO node has a binary local file archive to which is - /// first written a cookie and the number of servers. The IO - /// node then loops thru all of its clients and in turn tells - /// each to write its data over an MPI stream, which is copied - /// directly to the output file. The stream contents are then - /// cookie, no. of clients, foreach client (usual sequential archive). - /// - /// If ar.dofence() is true (default) fence is invoked before and - /// after the IO. The fence is optional but it is of course - /// necessary to be sure that all updates have completed - /// before doing IO, and that all IO has completed before - /// subsequent modifications. Also, there is always at least - /// some synchronization between a client and its IO server. - template - struct ArchiveStoreImpl< ParallelOutputArchive, WorldContainer > { - static void store(const ParallelOutputArchive& ar, const WorldContainer& t) { - const long magic = -5881828; // Sitar Indian restaurant in Knoxville (negative to indicate parallel!) - typedef WorldContainer dcT; - // typedef typename dcT::const_iterator iterator; // unused? - typedef typename dcT::pairT pairT; - World* world = ar.get_world(); - Tag tag = world->mpi.unique_tag(); - ProcessID me = world->rank(); - if (ar.dofence()) world->gop.fence(); - if (ar.is_io_node()) { - auto& localar = ar.local_archive(); - localar & magic & ar.num_io_clients(); - for (ProcessID p=0; psize(); ++p) { - if (p == me) { - localar & t; - } - else if (ar.io_node(p) == me) { - world->mpi.Send(int(1),p,tag); // Tell client to start sending - archive::MPIInputArchive source(*world, p); - long cookie = 0l; - unsigned long count = 0ul; - - ArchivePrePostImpl::preamble_store(localar); - - source & cookie & count; - localar & cookie & count; - while (count--) { - pairT datum; - source & datum; - localar & datum; - } - - ArchivePrePostImpl::postamble_store(localar); - } - } - } - else { - ProcessID p = ar.my_io_node(); - int flag; - world->mpi.Recv(flag,p,tag); - MPIOutputArchive dest(*world, p); - dest & t; - dest.flush(); - } - if (ar.dofence()) world->gop.fence(); - } - }; - - /// Write container to parallel archive + /// Write container to parallel archive template struct ArchiveStoreImpl< ParallelOutputArchive, WorldContainer > { static void store(const ParallelOutputArchive& ar, const WorldContainer& t) { @@ -1775,6 +1709,74 @@ namespace madness { } }; + + /// Write container to parallel archive with optional fence + + /// \ingroup worlddc + /// Each node (process) is served by a designated IO node. + /// The IO node has a binary local file archive to which is + /// first written a cookie and the number of servers. The IO + /// node then loops thru all of its clients and in turn tells + /// each to write its data over an MPI stream, which is copied + /// directly to the output file. The stream contents are then + /// cookie, no. of clients, foreach client (usual sequential archive). + /// + /// If ar.dofence() is true (default) fence is invoked before and + /// after the IO. The fence is optional but it is of course + /// necessary to be sure that all updates have completed + /// before doing IO, and that all IO has completed before + /// subsequent modifications. Also, there is always at least + /// some synchronization between a client and its IO server. + template + struct ArchiveStoreImpl< ParallelOutputArchive, WorldContainer > { + static void store(const ParallelOutputArchive& ar, const WorldContainer& t) { + const long magic = -5881828; // Sitar Indian restaurant in Knoxville (negative to indicate parallel!) + typedef WorldContainer dcT; + // typedef typename dcT::const_iterator iterator; // unused? + typedef typename dcT::pairT pairT; + World* world = ar.get_world(); + Tag tag = world->mpi.unique_tag(); + ProcessID me = world->rank(); + if (ar.dofence()) world->gop.fence(); + if (ar.is_io_node()) { + auto& localar = ar.local_archive(); + localar & magic & ar.num_io_clients(); + for (ProcessID p=0; psize(); ++p) { + if (p == me) { + localar & t; + } + else if (ar.io_node(p) == me) { + world->mpi.Send(int(1),p,tag); // Tell client to start sending + archive::MPIInputArchive source(*world, p); + long cookie = 0l; + unsigned long count = 0ul; + + ArchivePrePostImpl::preamble_store(localar); + + source & cookie & count; + localar & cookie & count; + while (count--) { + pairT datum; + source & datum; + localar & datum; + } + + ArchivePrePostImpl::postamble_store(localar); + } + } + } + else { + ProcessID p = ar.my_io_node(); + int flag; + world->mpi.Recv(flag,p,tag); + MPIOutputArchive dest(*world, p); + dest & t; + dest.flush(); + } + if (ar.dofence()) world->gop.fence(); + } + }; + template struct ArchiveLoadImpl< ParallelInputArchive, WorldContainer > { /// Read container from parallel archive From 41020aab73b17c3753af50a6c060986b109550d6 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Wed, 7 Aug 2024 14:48:43 -0400 Subject: [PATCH 33/54] looking for the lost time in WorldContainer serialization --- src/madness/world/cloud.h | 6 ++++++ src/madness/world/worlddc.h | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/madness/world/cloud.h b/src/madness/world/cloud.h index ecc18b6bdcf..ae05897c9f8 100644 --- a/src/madness/world/cloud.h +++ b/src/madness/world/cloud.h @@ -206,9 +206,11 @@ class Cloud { void print_timings(World &universe) const { double rtime = double(reading_time); double wtime = double(writing_time); + double wtime1 = double(writing_time1); double ptime = double(replication_time); universe.gop.max(rtime); universe.gop.max(wtime); + universe.gop.max(wtime1); universe.gop.max(ptime); long creads = long(cache_reads); long cstores = long(cache_stores); @@ -218,6 +220,7 @@ class Cloud { auto precision = std::cout.precision(); std::cout << std::fixed << std::setprecision(1); print("cloud storing wall time", wtime * 0.001); + print("cloud storing wall time inner loop", wtime1 * 0.001); print("cloud replication wall time", ptime * 0.001); print("cloud reading wall time", rtime * 0.001, std::defaultfloat); std::cout << std::setprecision(precision) << std::scientific; @@ -234,6 +237,7 @@ class Cloud { void clear_timings() { reading_time=0l; writing_time=0l; + writing_time1=0l; replication_time=0l; cache_stores=0l; cache_reads=0l; @@ -332,6 +336,7 @@ class Cloud { mutable std::atomic reading_time=0l; // in ms mutable std::atomic writing_time=0l; // in ms + mutable std::atomic writing_time1=0l; // in ms mutable std::atomic replication_time=0l; // in ms mutable std::atomic cache_reads=0l; mutable std::atomic cache_stores=0l; @@ -423,6 +428,7 @@ class Cloud { if (is_already_present) { if (world.rank()==0) cache_stores++; } else { + cloudtimer t(world,writing_time1); madness::archive::ContainerRecordOutputArchive ar(world, container, record); madness::archive::ParallelOutputArchive par(world, ar); par & source; diff --git a/src/madness/world/worlddc.h b/src/madness/world/worlddc.h index 91e57e52c9f..125fae64efa 100644 --- a/src/madness/world/worlddc.h +++ b/src/madness/world/worlddc.h @@ -1615,6 +1615,10 @@ namespace madness { namespace archive { /// Write container to parallel archive + + /// specialization for parallel serialization of a WorldContainer: + /// all threads on each process serialize some values into a buffer, which gets concatenated + /// and finally serialized to localarchive (aka VectorOutputArchive). template struct ArchiveStoreImpl< ParallelOutputArchive, WorldContainer > { static void store(const ParallelOutputArchive& ar, const WorldContainer& t) { @@ -1650,6 +1654,7 @@ namespace madness { const_iterator it=t.begin(); size_t count = 0; size_t n = 0; + /// threads serialize round-robin over the container while (it!=t.end()) { if ((n%ntasks) == taskid) { var & *it; @@ -1659,6 +1664,7 @@ namespace madness { n++; } + // concatenate the buffers from each thread if (count) { mutex.lock(); vtotal.insert(vtotal.end(), v.begin(), v.end()); From fe29acfaed63ae388692a0fd32ef895b07e95261 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Wed, 7 Aug 2024 16:22:03 -0400 Subject: [PATCH 34/54] looking for the lost time in WorldContainer serialization --- src/madness/world/test_dc.cc | 43 +++++++++++++++++++++++------- src/madness/world/vector_archive.h | 1 + src/madness/world/worlddc.h | 17 +++++++++--- 3 files changed, 47 insertions(+), 14 deletions(-) diff --git a/src/madness/world/test_dc.cc b/src/madness/world/test_dc.cc index d95154c08ad..bf03c72ee6f 100644 --- a/src/madness/world/test_dc.cc +++ b/src/madness/world/test_dc.cc @@ -89,6 +89,26 @@ struct Node { ~Node() {} }; +struct LargeNode { + std::vector k; + + LargeNode() : k() {} + + LargeNode(int val) { + k=std::vector(10000,val); + } + + int get() const { + return k[0]; + } + + template + void serialize(const Archive& ar) { + ar & k; + } + + ~LargeNode() {} +}; ostream& operator<<(ostream&s, const Node& node) { s << "Node(" << node.k << ")"; return s; @@ -249,34 +269,37 @@ void test_local(World& world) { } void test_florian(World& world) { - WorldContainer c(world); - - Key key1(1); - Node node1(1); + WorldContainer c(world); + long nlarge=200000; if (world.rank() == 0) { - for (int i=0; i<100; ++i) { - c.replace(Key(i),Node(i)); + for (int i=0; i v; { archive::VectorOutputArchive var(v); archive::ParallelOutputArchive ar(world,var); ar & c; } + double wall1=wall_time(); + printf("ending at time %8.4f after %8.4fs\n",wall1,wall1-wall0); - WorldContainer c2(world); + WorldContainer c2(world); { archive::VectorInputArchive var2(v); archive::ParallelInputArchive ar2(world,var2); ar2 & c2; } - for (int i=0; i<100; ++i) { - MADNESS_CHECK(c2.find(Key(i)).get()->second.get() == i); + if (world.rank()==0) { + for (int i=0; isecond.get() == i); + } } world.gop.fence(); diff --git a/src/madness/world/vector_archive.h b/src/madness/world/vector_archive.h index 8dfa56179d5..129c35e44e9 100644 --- a/src/madness/world/vector_archive.h +++ b/src/madness/world/vector_archive.h @@ -53,6 +53,7 @@ namespace madness { /// Wraps an archive around an STL \c vector for output. class VectorOutputArchive : public BaseOutputArchive { + public: mutable std::vector* v; ///< The STL vector being wrapped. public: diff --git a/src/madness/world/worlddc.h b/src/madness/world/worlddc.h index 125fae64efa..f10ff355fcf 100644 --- a/src/madness/world/worlddc.h +++ b/src/madness/world/worlddc.h @@ -1627,7 +1627,8 @@ namespace madness { typedef WorldContainer dcT; using const_iterator = typename dcT::const_iterator; - const size_t default_size = 100*1024*1024; + // const size_t default_size = 100*1024*1024; + const size_t default_size = 8ul<<30; World* world = ar.get_world(); world->gop.fence(); @@ -1649,8 +1650,8 @@ namespace madness { : ntasks(ntasks), taskid(taskid), t(t), vtotal(vtotal), total_count(total_count), mutex(mutex) {} void run(World& world) { std::vector v; - v.reserve(std::max(size_t(1024*1024),vtotal.capacity()/ntasks)); - VectorOutputArchive var(v); + std::size_t hint_size=std::max(size_t(1024*1024),vtotal.capacity()/ntasks); + VectorOutputArchive var(v,hint_size+taskid); const_iterator it=t.begin(); size_t count = 0; size_t n = 0; @@ -1663,7 +1664,7 @@ namespace madness { ++it; n++; } - + print("count, n, ntasks, taskid, size",count,n,ntasks,taskid,var.v->capacity()); // concatenate the buffers from each thread if (count) { mutex.lock(); @@ -1674,12 +1675,16 @@ namespace madness { } }; + world->gop.fence(); + double wall0=wall_time(); Mutex mutex; size_t ntasks = std::max(size_t(1), ThreadPool::size()); for (size_t taskid=0; taskidtaskq.add(new op(ntasks, taskid, t, v, count, mutex)); world->gop.fence(); + double wall1=wall_time(); + if (world->rank()==0) printf("time in the taskq: %8.4fs\n",wall1-wall0); // Gather all buffers to process 0 // first gather all of the sizes and counts to a vector in process 0 int size = v.size(); @@ -1687,12 +1692,14 @@ namespace madness { MPI_Gather(&size, 1, MPI_INT, sizes.data(), 1, MPI_INT, 0, world->mpi.comm().Get_mpi_comm()); world->gop.sum(count); // just need total number of elements + print("time 3",wall_time()); // build the cumulative sum of sizes std::vector offsets(world->size()); offsets[0] = 0; for (int i=1; isize(); ++i) offsets[i] = offsets[i-1] + sizes[i-1]; int total_size = offsets.back() + sizes.back(); + print("time 4",wall_time()); // gather the vector of data v from each process to process 0 unsigned char* all_data=0; if (world->rank() == 0) { @@ -1700,6 +1707,7 @@ namespace madness { } MPI_Gatherv(v.data(), v.size(), MPI_BYTE, all_data, sizes.data(), offsets.data(), MPI_BYTE, 0, world->mpi.comm().Get_mpi_comm()); + print("time 5",wall_time()); if (world->rank() == 0) { auto& localar = ar.local_archive(); localar & magic & 1; // 1 client @@ -1712,6 +1720,7 @@ namespace madness { delete[] all_data; } world->gop.fence(); + print("time 6",wall_time()); } }; From c80f0e1dd044126e0c994aadd8b24849b5103b74 Mon Sep 17 00:00:00 2001 From: "Robert J. Harrison" Date: Wed, 7 Aug 2024 16:13:27 -0500 Subject: [PATCH 35/54] bug in serialize --- src/madness/world/worlddc.h | 62 +++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 27 deletions(-) diff --git a/src/madness/world/worlddc.h b/src/madness/world/worlddc.h index f10ff355fcf..671e2964071 100644 --- a/src/madness/world/worlddc.h +++ b/src/madness/world/worlddc.h @@ -1633,45 +1633,39 @@ namespace madness { World* world = ar.get_world(); world->gop.fence(); - std::vector v; - v.reserve(default_size); - size_t count = 0; - - class op : public TaskInterface { + class op_serialize : public TaskInterface { const size_t ntasks; const size_t taskid; const dcT& t; - std::vector& vtotal; - size_t& total_count; - Mutex& mutex; + std::vector& v; public: - op(size_t ntasks, size_t taskid, const dcT& t, std::vector& vtotal, size_t& total_count, Mutex& mutex) - : ntasks(ntasks), taskid(taskid), t(t), vtotal(vtotal), total_count(total_count), mutex(mutex) {} + op_serialize(size_t ntasks, size_t taskid, const dcT& t, std::vector& v) + : ntasks(ntasks), taskid(taskid), t(t), v(v) {} void run(World& world) { - std::vector v; - std::size_t hint_size=std::max(size_t(1024*1024),vtotal.capacity()/ntasks); - VectorOutputArchive var(v,hint_size+taskid); + std::size_t hint_size=(1ul<<30)/ntasks; + VectorOutputArchive var(v,hint_size); const_iterator it=t.begin(); - size_t count = 0; size_t n = 0; /// threads serialize round-robin over the container while (it!=t.end()) { if ((n%ntasks) == taskid) { var & *it; - ++count; } ++it; n++; } - print("count, n, ntasks, taskid, size",count,n,ntasks,taskid,var.v->capacity()); - // concatenate the buffers from each thread - if (count) { - mutex.lock(); - vtotal.insert(vtotal.end(), v.begin(), v.end()); - total_count += count; - mutex.unlock(); - } + } + }; + + class op_concat : public TaskInterface { + unsigned char* all_data; + const std::vector& v; + public: + op_concat(unsigned char* all_data, const std::vector& v) + : all_data(all_data), v(v) {} + void run(World& world) { + memcpy(all_data, v.data(), v.size()); } }; @@ -1679,15 +1673,29 @@ namespace madness { double wall0=wall_time(); Mutex mutex; size_t ntasks = std::max(size_t(1), ThreadPool::size()); + + std::vector> v(ntasks); for (size_t taskid=0; taskidtaskq.add(new op(ntasks, taskid, t, v, count, mutex)); + world->taskq.add(new op_serialize(ntasks, taskid, t, v[taskid])); world->gop.fence(); + // total size of all vectors + size_t total_size = 0; + for (size_t taskid=0; taskid vtotal(total_size); + + size_t offset = 0; + for (size_t taskid=0; taskidtaskq.add(new op_concat(&vtotal[offset], v[taskid])); + offset += v[taskid].size(); + } + v.clear(); double wall1=wall_time(); if (world->rank()==0) printf("time in the taskq: %8.4fs\n",wall1-wall0); // Gather all buffers to process 0 // first gather all of the sizes and counts to a vector in process 0 - int size = v.size(); + int size = vtotal.size(); + int count = t.size(); std::vector sizes(world->size()); MPI_Gather(&size, 1, MPI_INT, sizes.data(), 1, MPI_INT, 0, world->mpi.comm().Get_mpi_comm()); world->gop.sum(count); // just need total number of elements @@ -1697,7 +1705,7 @@ namespace madness { std::vector offsets(world->size()); offsets[0] = 0; for (int i=1; isize(); ++i) offsets[i] = offsets[i-1] + sizes[i-1]; - int total_size = offsets.back() + sizes.back(); + MADNESS_CHECK(offsets.back() + sizes.back() == total_size); print("time 4",wall_time()); // gather the vector of data v from each process to process 0 @@ -1705,7 +1713,7 @@ namespace madness { if (world->rank() == 0) { all_data = new unsigned char[total_size]; } - MPI_Gatherv(v.data(), v.size(), MPI_BYTE, all_data, sizes.data(), offsets.data(), MPI_BYTE, 0, world->mpi.comm().Get_mpi_comm()); + MPI_Gatherv(vtotal.data(), vtotal.size(), MPI_BYTE, all_data, sizes.data(), offsets.data(), MPI_BYTE, 0, world->mpi.comm().Get_mpi_comm()); print("time 5",wall_time()); if (world->rank() == 0) { From ef21872ab8f3222a314ea028c7078f9df9e28c1b Mon Sep 17 00:00:00 2001 From: fbischoff Date: Thu, 8 Aug 2024 11:32:19 -0400 Subject: [PATCH 36/54] do some benchmarking --- src/madness/world/test_dc.cc | 11 ++++++++++- src/madness/world/worlddc.h | 12 ++++++++---- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/madness/world/test_dc.cc b/src/madness/world/test_dc.cc index bf03c72ee6f..6eacee5c6cd 100644 --- a/src/madness/world/test_dc.cc +++ b/src/madness/world/test_dc.cc @@ -270,7 +270,16 @@ void test_local(World& world) { void test_florian(World& world) { WorldContainer c(world); - long nlarge=200000; + + long nlarge=20000; + // get nlarge variable from the environment and convert it into long + char* nlarge_env = getenv("NLARGE"); + if (nlarge_env) { + nlarge = atol(nlarge_env); + } + if (world.rank()==0) print("size of the container",nlarge); + + if (world.rank() == 0) { for (int i=0; igop.fence(); @@ -1678,6 +1678,9 @@ namespace madness { for (size_t taskid=0; taskidtaskq.add(new op_serialize(ntasks, taskid, t, v[taskid])); world->gop.fence(); + double wall1=wall_time(); + if (world->rank()==0) printf("time in op_serialize: %8.4fs\n",wall1-wall0); + wall0=wall1; // total size of all vectors size_t total_size = 0; for (size_t taskid=0; taskidrank()==0) printf("time in the taskq: %8.4fs\n",wall1-wall0); + wall1=wall_time(); + if (world->rank()==0) printf("time in op_concat: %8.4fs\n",wall1-wall0); // Gather all buffers to process 0 // first gather all of the sizes and counts to a vector in process 0 int size = vtotal.size(); @@ -1705,6 +1708,7 @@ namespace madness { std::vector offsets(world->size()); offsets[0] = 0; for (int i=1; isize(); ++i) offsets[i] = offsets[i-1] + sizes[i-1]; + print("total_size, offsets.back()+sizes.back()",total_size,offsets.back()+sizes.back()); MADNESS_CHECK(offsets.back() + sizes.back() == total_size); print("time 4",wall_time()); @@ -1721,7 +1725,7 @@ namespace madness { localar & magic & 1; // 1 client // localar & t; ArchivePrePostImpl::preamble_store(localar); - localar & -magic & count; + localar & -magic & (unsigned long)(count); localar.store(all_data, total_size); ArchivePrePostImpl::postamble_store(localar); From c6a562fb75d3117fb409a22d0ea8881281551554 Mon Sep 17 00:00:00 2001 From: "Robert J. Harrison" Date: Thu, 8 Aug 2024 13:00:05 -0500 Subject: [PATCH 37/54] disable type checking on vector archives for efficiency --- src/madness/world/vector_archive.h | 34 ++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/madness/world/vector_archive.h b/src/madness/world/vector_archive.h index 129c35e44e9..3530a5a258d 100644 --- a/src/madness/world/vector_archive.h +++ b/src/madness/world/vector_archive.h @@ -144,6 +144,40 @@ namespace madness { void close() {} }; + /// Implementation of functions for storing the pre/postamble in Vector archives. + + /// \attention No type checking over Vector buffers, for efficiency. + /// \tparam T The data type. + template + struct ArchivePrePostImpl { + /// Store the preamble. + + /// \param[in] ar The archive. + static void preamble_store(const VectorOutputArchive& ar) {}; + + /// Store the postamble. + + /// \param[in] ar The archive. + static inline void postamble_store(const VectorOutputArchive& ar) {}; + }; + + /// Implementation of functions for loading the pre/postamble in Vector archives. + + /// \attention No type checking over Vector buffers, for efficiency. + /// \tparam T The data type. + template + struct ArchivePrePostImpl { + /// Load the preamble. + + /// \param[in] ar The archive. + static inline void preamble_load(const VectorInputArchive& ar) {}; + + /// Load the postamble. + + /// \param[in] ar The archive. + static inline void postamble_load(const VectorInputArchive& ar) {}; + }; + /// @} } } From 3a9698e4a9138effa1fa96426a1d30d8e44d0287 Mon Sep 17 00:00:00 2001 From: "Robert J. Harrison" Date: Thu, 8 Aug 2024 13:00:42 -0500 Subject: [PATCH 38/54] bug and performance fixes in parallel archive --- src/madness/world/test_dc.cc | 6 +++--- src/madness/world/worlddc.h | 36 +++++++++++++++++++++++++----------- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/madness/world/test_dc.cc b/src/madness/world/test_dc.cc index 6eacee5c6cd..580739f33b7 100644 --- a/src/madness/world/test_dc.cc +++ b/src/madness/world/test_dc.cc @@ -271,7 +271,7 @@ void test_local(World& world) { void test_florian(World& world) { WorldContainer c(world); - long nlarge=20000; + long nlarge=10000; // get nlarge variable from the environment and convert it into long char* nlarge_env = getenv("NLARGE"); if (nlarge_env) { @@ -288,7 +288,7 @@ void test_florian(World& world) { } world.gop.fence(); double wall0=wall_time(); - printf("starting at time %8.4f with %ld items\n",wall0,nlarge); + if (world.rank() == 0) printf("starting at time %8.4f with %ld items\n",wall0,nlarge); std::vector v; { archive::VectorOutputArchive var(v); @@ -296,7 +296,7 @@ void test_florian(World& world) { ar & c; } double wall1=wall_time(); - printf("ending at time %8.4f after %8.4fs\n",wall1,wall1-wall0); + if (world.rank() == 0) printf("ending at time %8.4f after %8.4fs\n",wall1,wall1-wall0); WorldContainer c2(world); { diff --git a/src/madness/world/worlddc.h b/src/madness/world/worlddc.h index 5c6cd05e6b3..78660159df7 100644 --- a/src/madness/world/worlddc.h +++ b/src/madness/world/worlddc.h @@ -1631,7 +1631,7 @@ namespace madness { // const size_t default_size = 8ul<<30; World* world = ar.get_world(); - world->gop.fence(); + world->gop.fence(); // Global fence here class op_serialize : public TaskInterface { const size_t ntasks; @@ -1669,21 +1669,26 @@ namespace madness { } }; - world->gop.fence(); + // No need for LOCAL fence here since only master thread is busy double wall0=wall_time(); Mutex mutex; - size_t ntasks = std::max(size_t(1), ThreadPool::size()); + const size_t ntasks = std::max(size_t(1), ThreadPool::size()); std::vector> v(ntasks); for (size_t taskid=0; taskidtaskq.add(new op_serialize(ntasks, taskid, t, v[taskid])); - world->gop.fence(); + world->taskq.fence(); // just need LOCAL fence + double wall1=wall_time(); if (world->rank()==0) printf("time in op_serialize: %8.4fs\n",wall1-wall0); wall0=wall1; // total size of all vectors size_t total_size = 0; - for (size_t taskid=0; taskid vtotal(total_size); size_t offset = 0; @@ -1691,10 +1696,13 @@ namespace madness { world->taskq.add(new op_concat(&vtotal[offset], v[taskid])); offset += v[taskid].size(); } + world->taskq.fence(); // just need LOCAL fence v.clear(); wall1=wall_time(); if (world->rank()==0) printf("time in op_concat: %8.4fs\n",wall1-wall0); + wall0 = wall1; + // Gather all buffers to process 0 // first gather all of the sizes and counts to a vector in process 0 int size = vtotal.size(); @@ -1703,15 +1711,15 @@ namespace madness { MPI_Gather(&size, 1, MPI_INT, sizes.data(), 1, MPI_INT, 0, world->mpi.comm().Get_mpi_comm()); world->gop.sum(count); // just need total number of elements - print("time 3",wall_time()); + //print("time 3",wall_time()); // build the cumulative sum of sizes std::vector offsets(world->size()); offsets[0] = 0; for (int i=1; isize(); ++i) offsets[i] = offsets[i-1] + sizes[i-1]; - print("total_size, offsets.back()+sizes.back()",total_size,offsets.back()+sizes.back()); - MADNESS_CHECK(offsets.back() + sizes.back() == total_size); + total_size = offsets.back()+sizes.back(); + if (world->rank() == 0) print("total_size",total_size); - print("time 4",wall_time()); + // print("time 4",wall_time()); // gather the vector of data v from each process to process 0 unsigned char* all_data=0; if (world->rank() == 0) { @@ -1719,7 +1727,11 @@ namespace madness { } MPI_Gatherv(vtotal.data(), vtotal.size(), MPI_BYTE, all_data, sizes.data(), offsets.data(), MPI_BYTE, 0, world->mpi.comm().Get_mpi_comm()); - print("time 5",wall_time()); + wall1=wall_time(); + if (world->rank()==0) printf("time in gather+gatherv: %8.4fs\n",wall1-wall0); + wall0 = wall1; + + // print("time 5",wall_time()); if (world->rank() == 0) { auto& localar = ar.local_archive(); localar & magic & 1; // 1 client @@ -1728,11 +1740,13 @@ namespace madness { localar & -magic & (unsigned long)(count); localar.store(all_data, total_size); ArchivePrePostImpl::postamble_store(localar); + wall1=wall_time(); + if (world->rank()==0) printf("time in final copy on node 0: %8.4fs\n",wall1-wall0); delete[] all_data; } world->gop.fence(); - print("time 6",wall_time()); + // print("time 6",wall_time()); } }; From ca74a448e1518e022bb5f2788792a3b59fb677f9 Mon Sep 17 00:00:00 2001 From: "Robert J. Harrison" Date: Thu, 8 Aug 2024 14:47:58 -0500 Subject: [PATCH 39/54] in parallel archive of container significant reduction of data motion, better parallelism, reduced traversal of data structure --- src/madness/world/test_dc.cc | 4 +- src/madness/world/worlddc.h | 119 +++++++++++++++++++++-------------- 2 files changed, 73 insertions(+), 50 deletions(-) diff --git a/src/madness/world/test_dc.cc b/src/madness/world/test_dc.cc index 580739f33b7..f908df1dc64 100644 --- a/src/madness/world/test_dc.cc +++ b/src/madness/world/test_dc.cc @@ -271,7 +271,7 @@ void test_local(World& world) { void test_florian(World& world) { WorldContainer c(world); - long nlarge=10000; + long nlarge=20000; // get nlarge variable from the environment and convert it into long char* nlarge_env = getenv("NLARGE"); if (nlarge_env) { @@ -312,7 +312,7 @@ void test_florian(World& world) { } world.gop.fence(); - print("test_florian passed"); + if (world.rank() == 0) print("test_florian passed"); } int main(int argc, char** argv) { diff --git a/src/madness/world/worlddc.h b/src/madness/world/worlddc.h index 78660159df7..74bdb032a10 100644 --- a/src/madness/world/worlddc.h +++ b/src/madness/world/worlddc.h @@ -1626,6 +1626,7 @@ namespace madness { const long magic = -5881828; // Sitar Indian restaurant in Knoxville (negative to indicate parallel!) typedef WorldContainer dcT; using const_iterator = typename dcT::const_iterator; + int count = t.size(); // Must be INT for MPI and NOT const since we'll do a global sum eventually // const size_t default_size = 100*1024*1024; // const size_t default_size = 8ul<<30; @@ -1633,80 +1634,100 @@ namespace madness { World* world = ar.get_world(); world->gop.fence(); // Global fence here - class op_serialize : public TaskInterface { - const size_t ntasks; - const size_t taskid; - const dcT& t; - std::vector& v; - + class op_inspector : public TaskInterface { + const_iterator start, end; + size_t& size; public: - op_serialize(size_t ntasks, size_t taskid, const dcT& t, std::vector& v) - : ntasks(ntasks), taskid(taskid), t(t), v(v) {} + op_inspector(const_iterator start, const_iterator end, size_t& size) + : start(start), end(end), size(size) {} void run(World& world) { - std::size_t hint_size=(1ul<<30)/ntasks; - VectorOutputArchive var(v,hint_size); - const_iterator it=t.begin(); - size_t n = 0; - /// threads serialize round-robin over the container - while (it!=t.end()) { - if ((n%ntasks) == taskid) { - var & *it; - } - ++it; - n++; - } + BufferOutputArchive bo; + for (const_iterator it=start; it!=end; ++it) bo & *it; + size = bo.size(); } }; - class op_concat : public TaskInterface { - unsigned char* all_data; - const std::vector& v; + class op_executor : public TaskInterface { + const_iterator start, end; + unsigned char* buf; + const size_t size; public: - op_concat(unsigned char* all_data, const std::vector& v) - : all_data(all_data), v(v) {} + op_executor(const_iterator start, const_iterator end, unsigned char* buf, size_t size) + : start(start), end(end), buf(buf), size(size) {} void run(World& world) { - memcpy(all_data, v.data(), v.size()); + BufferOutputArchive bo(buf, size); + for (const_iterator it=start; it!=end; ++it) { + bo & *it; + } + MADNESS_CHECK(size == bo.size()); } }; // No need for LOCAL fence here since only master thread is busy double wall0=wall_time(); - Mutex mutex; - const size_t ntasks = std::max(size_t(1), ThreadPool::size()); - - std::vector> v(ntasks); - for (size_t taskid=0; taskidtaskq.add(new op_serialize(ntasks, taskid, t, v[taskid])); + const size_t ntasks = std::min(size_t(count), std::max(size_t(1), ThreadPool::size())); + const size_t max_items_per_task = (std::max(1,count)-1)/ntasks + 1; + + // Compute the size of the buffer needed by each task + const_iterator starts[ntasks], ends[ntasks]; + size_t local_sizes[ntasks]; + const_iterator start = t.begin(); + size_t nleft = count; + for (size_t taskid=0; taskidtaskq.add(new op_inspector(start, end, local_sizes[taskid])); // Be sure to pass iterators by value!! + start = end; + } world->taskq.fence(); // just need LOCAL fence - double wall1=wall_time(); - if (world->rank()==0) printf("time in op_serialize: %8.4fs\n",wall1-wall0); + if (world->rank()==0) printf("time in op_inspector: %8.4fs\n",wall1-wall0); wall0=wall1; - // total size of all vectors - size_t total_size = 0; + + // total size over all threads + size_t local_size = 0; for (size_t taskid=0; taskid vtotal(total_size); - + // Allocate the buffer for all threads + unsigned char* buf = new unsigned char[local_size]; + + // Now execute the serialization size_t offset = 0; for (size_t taskid=0; taskidtaskq.add(new op_concat(&vtotal[offset], v[taskid])); - offset += v[taskid].size(); + world->taskq.add(new op_executor(starts[taskid], ends[taskid], buf+offset, local_sizes[taskid])); + offset += local_sizes[taskid]; } world->taskq.fence(); // just need LOCAL fence - v.clear(); wall1=wall_time(); - if (world->rank()==0) printf("time in op_concat: %8.4fs\n",wall1-wall0); + if (world->rank()==0) printf("time in op_executor: %8.4fs\n",wall1-wall0); wall0 = wall1; + + // VERify that the serialization worked!! + // { + // BufferInputArchive bi(buf, local_size); + // for (int item=0; item datum; + // bi & datum; + // print("deserializing",datum.first); + // } + // } // Gather all buffers to process 0 // first gather all of the sizes and counts to a vector in process 0 - int size = vtotal.size(); - int count = t.size(); + const int size = local_size; std::vector sizes(world->size()); MPI_Gather(&size, 1, MPI_INT, sizes.data(), 1, MPI_INT, 0, world->mpi.comm().Get_mpi_comm()); world->gop.sum(count); // just need total number of elements @@ -1716,7 +1737,7 @@ namespace madness { std::vector offsets(world->size()); offsets[0] = 0; for (int i=1; isize(); ++i) offsets[i] = offsets[i-1] + sizes[i-1]; - total_size = offsets.back()+sizes.back(); + size_t total_size = offsets.back()+sizes.back(); if (world->rank() == 0) print("total_size",total_size); // print("time 4",wall_time()); @@ -1725,11 +1746,13 @@ namespace madness { if (world->rank() == 0) { all_data = new unsigned char[total_size]; } - MPI_Gatherv(vtotal.data(), vtotal.size(), MPI_BYTE, all_data, sizes.data(), offsets.data(), MPI_BYTE, 0, world->mpi.comm().Get_mpi_comm()); + MPI_Gatherv(buf, local_size, MPI_BYTE, all_data, sizes.data(), offsets.data(), MPI_BYTE, 0, world->mpi.comm().Get_mpi_comm()); wall1=wall_time(); if (world->rank()==0) printf("time in gather+gatherv: %8.4fs\n",wall1-wall0); wall0 = wall1; + + delete[] buf; // print("time 5",wall_time()); if (world->rank() == 0) { From 692289a38708b050f7fc4f643e03cf4260e13092 Mon Sep 17 00:00:00 2001 From: "Robert J. Harrison" Date: Fri, 9 Aug 2024 09:40:11 -0500 Subject: [PATCH 40/54] reduce compilation noise --- src/madness/tensor/srconf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/madness/tensor/srconf.h b/src/madness/tensor/srconf.h index 9ecb4858b48..6e5797c60d8 100644 --- a/src/madness/tensor/srconf.h +++ b/src/madness/tensor/srconf.h @@ -663,7 +663,7 @@ namespace madness { public: /// return the number of physical dimensions int dim_per_vector(int idim) const { - MADNESS_ASSERT(vector_.size()>idim); + MADNESS_ASSERT(vector_.size()>size_t(idim)); return vector_[idim].ndim()-1; // remove dimension for the rank } From 23f1fa7eb95621a1077d725594c1d0219fe7837a Mon Sep 17 00:00:00 2001 From: "Robert J. Harrison" Date: Fri, 9 Aug 2024 09:41:12 -0500 Subject: [PATCH 41/54] fixes for parallel container record archive --- src/madness/world/parallel_archive.h | 34 +++++++++---------- src/madness/world/parallel_dc_archive.h | 44 ++++++++++++++++++++++++- src/madness/world/worlddc.h | 8 +++-- 3 files changed, 66 insertions(+), 20 deletions(-) diff --git a/src/madness/world/parallel_archive.h b/src/madness/world/parallel_archive.h index bcfedf9e2af..45cb9c8a61c 100644 --- a/src/madness/world/parallel_archive.h +++ b/src/madness/world/parallel_archive.h @@ -104,7 +104,7 @@ namespace madness { /// \return The process doing I/O for this node. ProcessID my_io_node() const { - MADNESS_ASSERT(world); + MADNESS_CHECK(world); return io_node(world->rank()); } @@ -112,7 +112,7 @@ namespace madness { /// \return The number of I/O clients for this node, including self (zero if not an I/O node). int num_io_clients() const { - MADNESS_ASSERT(world); + MADNESS_CHECK(world); return nclient; } @@ -120,7 +120,7 @@ namespace madness { /// \return True if this node is doing physical I/O. bool is_io_node() const { - MADNESS_ASSERT(world); + MADNESS_CHECK(world); return world->rank() == my_io_node(); } @@ -128,7 +128,7 @@ namespace madness { /// \return A pointer to the world. World* get_world() const { - MADNESS_ASSERT(world); + MADNESS_CHECK(world); return world; } @@ -166,12 +166,12 @@ namespace madness { if (nio > maxio) nio = maxio; // Sanity? if (nio > world.size()) nio = world.size(); - MADNESS_ASSERT(filename); - MADNESS_ASSERT(strlen(filename)-1::value || std::is_same::value, bool> exists(World& world, const char* filename) { - constexpr std::size_t bufsize=256; + constexpr std::size_t bufsize=512; char buf[bufsize]; - MADNESS_ASSERT(strlen(filename)+7 <= sizeof(buf)); + MADNESS_CHECK(strlen(filename)+7 <= sizeof(buf)); snprintf(buf,bufsize, "%s.%5.5d", filename, world.rank()); bool status; if (world.rank() == 0) @@ -237,7 +237,7 @@ namespace madness { /// Closes the parallel archive. void close() { - MADNESS_ASSERT(world); + MADNESS_CHECK(world); if (is_io_node()) ar.close(); } @@ -246,8 +246,8 @@ namespace madness { /// \throw MadnessException If not an I/O node. /// \return A reference to the local archive. Archive& local_archive() const { - MADNESS_ASSERT(world); - MADNESS_ASSERT(is_io_node()); + MADNESS_CHECK(world); + MADNESS_CHECK(is_io_node()); return ar; } @@ -273,9 +273,9 @@ namespace madness { void> remove(World& world, const char* filename) { if (world.rank() == 0) { - constexpr std::size_t bufsize=268; + constexpr std::size_t bufsize=512; char buf[bufsize]; - MADNESS_ASSERT(strlen(filename)+7 <= sizeof(buf)); + MADNESS_CHECK(strlen(filename)+7 <= sizeof(buf)); for (ProcessID p=0; p + struct ArchivePrePostImpl { + /// Store the preamble. + + /// \param[in] ar The archive. + static void preamble_store(const ContainerRecordOutputArchive& ar) {}; + + /// Store the postamble. + + /// \param[in] ar The archive. + static inline void postamble_store(const ContainerRecordOutputArchive& ar) {}; + }; + + /// Implementation of functions for loading the pre/postamble in ContainerRecord archives. + + /// \attention No type checking over ContainerRecord buffers, for efficiency. + /// \tparam T The data type. + template + struct ArchivePrePostImpl { + /// Load the preamble. + + /// \param[in] ar The archive. + static inline void preamble_load(const ContainerRecordInputArchive& ar) {}; + + /// Load the postamble. + + /// \param[in] ar The archive. + static inline void postamble_load(const ContainerRecordInputArchive& ar) {}; + }; + + // Forward storing to VectorOutputArchive template struct ArchiveStoreImpl< ParallelOutputArchive, WorldContainer > { static void store(const ParallelOutputArchive& ar, const WorldContainer& t) { - ParallelOutputArchive par(*(ar.get_world()), ar.local_archive().get_archive()); + std::vector v; + VectorOutputArchive dummyar(v,0); + const int me = ar.get_world()->rank(); + + // Need to pass local archive by reference + ParallelOutputArchive par(*(ar.get_world()), (me==0) ? ar.local_archive().get_archive() : dummyar); par & t; } }; + + } diff --git a/src/madness/world/worlddc.h b/src/madness/world/worlddc.h index 74bdb032a10..a6a3a0d410f 100644 --- a/src/madness/world/worlddc.h +++ b/src/madness/world/worlddc.h @@ -1628,8 +1628,12 @@ namespace madness { using const_iterator = typename dcT::const_iterator; int count = t.size(); // Must be INT for MPI and NOT const since we'll do a global sum eventually - // const size_t default_size = 100*1024*1024; - // const size_t default_size = 8ul<<30; + // Strategy: + // 1. Serialize local data to a buffer in parallel over threads + // a) Compute the size of the buffer needed by each task + // b) Sum sizes and allocate the buffer of exact sizes needed for all threads + // c) Serialize the data into the buffer in parallel over threads + // 2. Gather all buffers to process 0 World* world = ar.get_world(); world->gop.fence(); // Global fence here From 0e31c9fbbf82b8b83294434978e26ed8ec2f5aa5 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Fri, 9 Aug 2024 15:13:13 -0400 Subject: [PATCH 42/54] update --- src/madness/chem/CC2.cc | 74 ++++++++++++++++---------------- src/madness/chem/CC2.h | 64 ++++++++++++++------------- src/madness/chem/CCPotentials.cc | 3 +- 3 files changed, 74 insertions(+), 67 deletions(-) diff --git a/src/madness/chem/CC2.cc b/src/madness/chem/CC2.cc index ef3726512ae..c94d2d43481 100644 --- a/src/madness/chem/CC2.cc +++ b/src/madness/chem/CC2.cc @@ -85,7 +85,7 @@ CC2::solve() { if (need_cc2) { // check if singles or/and doubles to restart are there - initialize_singles(cc2singles, PARTICLE); + initialize_singles(PARTICLE); const bool load_doubles = initialize_pairs(cc2pairs, GROUND_STATE, CT_CC2, cc2singles, CC_vecfunction(RESPONSE), 0, info); // nothing to restart -> make MP2 @@ -255,6 +255,10 @@ CC2::solve() { auto vccs=solve_ccs(); + print_header3("solving CCS"); + iterate_ccs_singles(vccs[0], info); + print_header3("end solving CCS"); + for (size_t iexcitation = 0; iexcitation < vccs.size(); iexcitation++) { print_header1("Solving LRCC2 for excitation " + std::to_string(iexcitation) + " with omega "+std::to_string(vccs[iexcitation].omega)); @@ -405,6 +409,8 @@ std::vector CC2::solve_ccs() const 1); result.push_back(excitations[x]); } + print_header3("Solution of the CCS equations"); + tdhf->analyze(result); return result; } @@ -525,11 +531,8 @@ double CC2::solve_mp2_coupled(Pairs& doubles, Info& info) { } if (world.rank()==0) { - std::cout << "convergence: rms/max residual, energy change " - << std::scientific << std::setprecision(1) - << rmsrnorm << " " << maxrnorm << " " - << std::abs(old_energy - total_energy) << std::endl; - // << std::abs(old_norm - total_norm); + double delta=old_energy - total_energy; + CCPotentials::print_convergence("MP2 doubles",rmsrnorm,maxrnorm,delta,iter); printf("finished MP2 iteration %2d at time %8.1fs with energy %12.8f\n", int(iter), wall_time(), total_energy); } @@ -722,12 +725,19 @@ CC2::iterate_lrcc2_pairs(World& world, const CC_vecfunction& cc2_s, double nnew=norm2(world,unew); print("norm(old), norm(new) ",nold,nnew); auto [rmsrnorm, rmsrmax] = CCPotentials::residual_stats(residual); - CCPotentials::print_convergence("LRCC2 doubles",rmsrnorm, rmsrmax,0,0); + if (world.rank()==0) CCPotentials::print_convergence("LRCC2 doubles",rmsrnorm, rmsrmax,0,0); // update the pair functions for (int i=0; i::vector2pairs(pair_vec,triangular_map); + // save latest iteration + if (world.rank()==0) print("saving latest iteration of LRCC2 to file"); + for (const auto& pair : pair_vec) { + save(pair.constant_part, pair.name() + "_const"); + save(pair.function(), pair.name()); + } + return (rmsrnorm& doubles, Info& info) cons if (world.rank() == 0) std::cout << std::fixed << std::setprecision(10) << "Difference = " << delta << "\n"; - std::cout << "convergence: rms/max residual, energy change " - << std::scientific << std::setprecision(1) - << rmsrnorm << " " << maxrnorm << " " - << std::abs(delta) << std::endl; - // << std::abs(old_norm - total_norm); - printf("finished CC2 iteration %2d at time %8.1fs with energy %12.8f\n", - int(iter), wall_time(), omega); + if (world.rank()==0) { + CCPotentials::print_convergence("CC2 macro",rmsrnorm,maxrnorm,delta,iter); + printf("finished CC2 macro iteration %2d at time %8.1fs with energy %12.8f\n", + int(iter), wall_time(), omega); + } if (doubles_converged and singles_converged and omega_converged) break; time_miter.info(); @@ -1030,33 +1038,34 @@ bool CC2::iterate_pair(CCPair& pair, const CC_vecfunction& singles) const { return converged; } -bool -CC2::initialize_singles(CC_vecfunction& singles, const FuncType type, const int ex) const { - MADNESS_ASSERT(singles.size() == 0); - bool restarted = false; - std::vector> vs; +CC_vecfunction +CC2::initialize_singles(const FuncType type, const int ex) const { + if (world.rank()==0) print("trying to read",singles.name(ex),"from file"); + CC_vecfunction singles=CC_vecfunction::load_restartdata(singles.name(ex)); + bool found_on_file=false; + for (size_t i = parameters.freeze(); i < CCOPS.mo_ket().size(); i++) { CCFunction single_i; single_i.type = type; single_i.i = i; - std::string name; - if (ex < 0) name = single_i.name(); - else name = std::to_string(ex) + "_" + single_i.name(); + std::string name=single_i.name(); + if (ex>=0) name = std::to_string(ex) + "_" + single_i.name(); real_function_3d tmpi = real_factory_3d(world); - const bool found = CCOPS.load_function(tmpi, name); - if (found) restarted = true; - else output("Initialized " + single_i.name() + " of type " + assign_name(type) + " as zero-function"); + found_on_file = CCOPS.load_function(tmpi, name); single_i.function = copy(tmpi); - vs.push_back(single_i); + singles.insert(i,single_i); } - singles = CC_vecfunction(vs, type); -// if (type == RESPONSE) singles.excitation = ex; + if (world.rank()==0) { + if (found_on_file) print("singles found on file"); + else print("singles not found on file"); + } - return restarted; + return singles; } + bool CC2::initialize_pairs(Pairs& pairs, const CCState ftype, const CalcType ctype, const CC_vecfunction& tau, const CC_vecfunction& x, const size_t excitation, const Info& info) const { @@ -1100,19 +1109,12 @@ CC2::initialize_pairs(Pairs& pairs, const CCState ftype, const CalcType auto functions=consolidate(p.functions); for (const auto& f : functions) f.print_size(); }; -// print("jakob's pair"); -// doit(tmp); -// print("Florian's pair"); -// doit(tmp2); std::swap(tmp,tmp2); print("going on with Florian's pair"); // print("going on with Jakob's pair"); } -// tmp.excitation = excitation; tmp.constant_part = const_part; - // tmp.constant_part = vconst_part[0]; - // print_header1("loading constant part"); pairs.insert(i, j, tmp); CCPotentials::compute_excited_pair_energy(world, pairs(i, j), x, info); } else error("Unknown pairtype"); diff --git a/src/madness/chem/CC2.h b/src/madness/chem/CC2.h index 4828998fe31..d7aadfc99fa 100644 --- a/src/madness/chem/CC2.h +++ b/src/madness/chem/CC2.h @@ -199,7 +199,7 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { Pairs empty; // CCOPS.clear_potentials(x); info.intermediate_potentials.clear_response(); - return iterate_singles(world, x, CC_vecfunction(PARTICLE), empty, empty, CT_LRCCS, 1, info); + return iterate_singles(world, x, CC_vecfunction(PARTICLE), empty, empty, CT_LRCCS, info.parameters.iter_max_3D(), info); } static bool @@ -233,8 +233,8 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { print_size(world, singles.get_vecfunction(), "singles before iteration"); for (size_t iter = 0; iter < maxiter; iter++) { - output.subsection("Microiteration " + std::to_string(iter) + " of " + assign_name(ctype) + "-Singles"); - CCTimer time(world, "Microiteration " + std::to_string(iter) + " of " + assign_name(ctype) + "-Singles"); + // output.subsection("Microiteration " + std::to_string(iter) + " of " + assign_name(ctype) + "-Singles"); + // CCTimer time(world, "Microiteration " + std::to_string(iter) + " of " + assign_name(ctype) + "-Singles"); double omega = 0.0; if (ctype == CT_LRCC2) omega = singles.omega; else if (ctype == CT_LRCCS) omega = singles.omega; @@ -283,38 +283,38 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { omega = singles.omega; // computed with the potential } - // scale(world, V, -2.0); // moved to BSHApply + scale(world, V, -2.0); // moved to BSHApply truncate(world, V); - BSHApply bsh_apply(world); - bsh_apply.ret_value=BSHApply::update; // return the new singles functions, not the residual - bsh_apply.metric=info.R_square; - - // coupling between singles involves the active fock matrix shifted by the excitation energy - auto nfreeze=info.parameters.freeze(); - Tensor fock=info.fock(Slice(nfreeze,-1),Slice(nfreeze,-1)); - for (int i=0; i > > G(singles.size()); -// for (size_t i = 0; i < G.size(); i++) { -// const double bsh_eps = info.orbital_energies[i + info.parameters.freeze()] + omega; -// G[i] = std::shared_ptr >( -// BSHOperatorPtr3D(world, sqrt(-2.0 * bsh_eps), info.parameters.lo(), info.parameters.thresh_bsh_3D())); -// } -// world.gop.fence(); -// time_makebsh.info(); + CCTimer time_makebsh(world, "Make G-Operators"); + std::vector > > G(singles.size()); + for (size_t i = 0; i < G.size(); i++) { + const double bsh_eps = info.orbital_energies[i + info.parameters.freeze()] + omega; + G[i] = std::shared_ptr >( + BSHOperatorPtr3D(world, sqrt(-2.0 * bsh_eps), info.parameters.lo(), info.parameters.thresh_bsh_3D())); + } + world.gop.fence(); + time_makebsh.info(); // // // apply bsh operators CCTimer time_applyG(world, "Apply G-Operators"); - auto [GV, energy_update] = bsh_apply(singles.get_vecfunction(), fock, V); - // vector_real_function_3d GV = apply, double, 3>(world, G, V); + // auto [GV, energy_update] = bsh_apply(singles.get_vecfunction(), fock, V); + vector_real_function_3d GV = apply, double, 3>(world, G, V); // world.gop.fence(); // auto GV=res-singles.get_vecfunction(); time_applyG.info(); @@ -387,7 +387,7 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { rmsresidual,omega-old_omega,iter); converged = (R2vector_error < info.parameters.dconv_3D()); - time.info(); + // time.info(); if (converged) break; if (ctype == CT_LRCCS) break; // for CCS just one iteration to check convergence } @@ -397,7 +397,7 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { // Assign the overall changes bool no_change = true; if (world.rank() == 0) - std::cout << "Change in Singles functions after all the CC2-Single-Microiterations" << std::endl; + std::cout << "Change in Singles functions after all the Microiterations" << std::endl; for (auto& tmp : singles.functions) { const double change = (tmp.second.function - old_singles(tmp.first).function).norm2(); tmp.second.current_error = change; @@ -414,9 +414,13 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { return no_change; } + /// store singles to file + void store_singles(const CC_vecfunction& singles, const int ex = -1) const; - bool initialize_singles(CC_vecfunction& singles, const FuncType type, const int ex = -1) const; + /// read singles from file or initialize new ones + CC_vecfunction initialize_singles(const FuncType type, const int ex = -1) const; + /// read pairs from file or initialize new ones bool initialize_pairs(Pairs& pairs, const CCState ftype, const CalcType ctype, const CC_vecfunction& tau, const CC_vecfunction& x, const size_t extitation, const Info& info) const; diff --git a/src/madness/chem/CCPotentials.cc b/src/madness/chem/CCPotentials.cc index 6fb7a411d9b..92d5500ba7c 100644 --- a/src/madness/chem/CCPotentials.cc +++ b/src/madness/chem/CCPotentials.cc @@ -1174,7 +1174,8 @@ CCPair CCPotentials::iterate_pair_macrotask(World& world, double delta = omega_partial - omega_new; omega_partial = omega_new; - print_convergence(pair.name(),rmsresidual,rmsresidual,delta,iter); + if (world.rank()==0) + print_convergence(pair.name(),rmsresidual,rmsresidual,delta,iter); // output("\n--Iteration " + stringify(iter) + " ended--"); // save(result.function(), result.name()); From 598acd688ae060a00d68686e7992f8747f80a207 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Mon, 12 Aug 2024 11:27:47 -0400 Subject: [PATCH 43/54] update --- src/madness/chem/CC2.cc | 217 +++++++++++++++--------------- src/madness/chem/CCStructures.cc | 9 -- src/madness/chem/CCStructures.h | 4 +- src/madness/chem/ccpairfunction.h | 14 ++ 4 files changed, 125 insertions(+), 119 deletions(-) diff --git a/src/madness/chem/CC2.cc b/src/madness/chem/CC2.cc index c94d2d43481..7ea46818053 100644 --- a/src/madness/chem/CC2.cc +++ b/src/madness/chem/CC2.cc @@ -85,7 +85,7 @@ CC2::solve() { if (need_cc2) { // check if singles or/and doubles to restart are there - initialize_singles(PARTICLE); + cc2singles=initialize_singles(PARTICLE); const bool load_doubles = initialize_pairs(cc2pairs, GROUND_STATE, CT_CC2, cc2singles, CC_vecfunction(RESPONSE), 0, info); // nothing to restart -> make MP2 @@ -255,12 +255,12 @@ CC2::solve() { auto vccs=solve_ccs(); - print_header3("solving CCS"); + if (world.rank()==0) print_header3("reiterating CCS"); iterate_ccs_singles(vccs[0], info); - print_header3("end solving CCS"); + if (world.rank()==0) print_header3("end reiterating CCS"); for (size_t iexcitation = 0; iexcitation < vccs.size(); iexcitation++) { - print_header1("Solving LRCC2 for excitation " + std::to_string(iexcitation) + if (world.rank()==0) print_header1("Solving LRCC2 for excitation " + std::to_string(iexcitation) + " with omega "+std::to_string(vccs[iexcitation].omega)); solve_lrcc2(cc2pairs,cc2singles,vccs[iexcitation],iexcitation,info); } @@ -694,18 +694,21 @@ CC2::iterate_lrcc2_pairs(World& world, const CC_vecfunction& cc2_s, for (int i=0; i coupling=compute_local_coupling(pair_vec, info); - auto coupling_vec=Pairs::pairs2vector(coupling,triangular_map); - if (info.parameters.debug()) print_size(world, coupling_vec, "couplingvector"); + // compute the coupling between the pair functions + if (world.rank()==0) print("computing local coupling in the universe"); + Pairs coupling=compute_local_coupling(pair_vec, info); + auto coupling_vec=Pairs::pairs2vector(coupling,triangular_map); + if (info.parameters.debug()) print_size(world, coupling_vec, "couplingvector"); // iterate the pair MacroTaskIteratePair t1; @@ -754,105 +757,105 @@ CC2::solve_cc2(CC_vecfunction& singles, Pairs& doubles, Info& info) cons double omega = CCPotentials::compute_cc2_correlation_energy(world, singles, doubles, info); if (world.rank() == 0) std::cout << std::fixed << std::setprecision(10) << "Current Correlation Energy = " << omega << "\n"; - CC_vecfunction ex_singles_dummy; - if (not parameters.no_compute_cc2()) { - // first singles iteration - output.section("Initialize Singles to the Doubles"); + if (parameters.no_compute_cc2()) { + if (world.rank()==0) print("found no_compute_cc2 key -- returning without further computation"); + return omega; + } - // given the doubles, we can solve the singles equations - iterate_cc2_singles(world, singles, doubles, info); - // the doubles ansatz depends on the singles and must be updated: |\tau_ij> = |u_ij> + Q12 f12 |t_i t_j> - update_reg_residues_gs(world, singles, doubles, info); - omega = CCPotentials::compute_cc2_correlation_energy(world, singles, doubles, info); + CC_vecfunction ex_singles_dummy; - for (size_t iter = 0; iter < parameters.iter_max(); iter++) { - CCTimer time_miter(world, "Macroiteration " + std::to_string(int(iter)) + " of CC2"); - output.section("Macroiteration " + std::to_string(int(iter)) + " of CC2"); + // first singles iteration + output.section("Initialize Singles to the Doubles"); - if (world.rank()==0) print("computing the constant part via macrotasks -- output redirected"); - timer timer1(world); + // given the doubles, we can solve the singles equations + iterate_cc2_singles(world, singles, doubles, info); + // the doubles ansatz depends on the singles and must be updated: |\tau_ij> = |u_ij> + Q12 f12 |t_i t_j> + update_reg_residues_gs(world, singles, doubles, info); + omega = CCPotentials::compute_cc2_correlation_energy(world, singles, doubles, info); - std::vector pair_vec=Pairs::pairs2vector(doubles,triangular_map); - MacroTaskConstantPart t; - MacroTask task(world, t); - std::vector constant_part_vec = task(pair_vec, singles.get_vecfunction(), - ex_singles_dummy.get_vecfunction(), info) ; - for (int i=0; i pair_vec=Pairs::pairs2vector(doubles,triangular_map); + MacroTaskConstantPart t; + MacroTask task(world, t); + std::vector constant_part_vec = task(pair_vec, singles.get_vecfunction(), + ex_singles_dummy.get_vecfunction(), info) ; + for (int i=0; i coupling=compute_local_coupling(pair_vec, info); - auto coupling_vec=Pairs::pairs2vector(coupling,triangular_map); - timer1.tag("computing local coupling"); + timer1.tag("computing constant part via macrotasks"); - if (world.rank()==0) print("update the pair functions via macrotasks -- output redirected"); - MacroTaskIteratePair t1; - MacroTask task1(world, t1); - CC_vecfunction dummy_ex_singles; - std::vector vdummy_3d; // dummy vectors - const std::size_t maxiter=3; - auto unew = task1(pair_vec, coupling_vec, singles, dummy_ex_singles, - info, maxiter); + // compute the coupling between the pair functions + if (world.rank()==0) print("computing local coupling in the universe"); + Pairs coupling=compute_local_coupling(pair_vec, info); + auto coupling_vec=Pairs::pairs2vector(coupling,triangular_map); + timer1.tag("computing local coupling"); - std::vector u_old; - for (auto p : pair_vec) u_old.push_back(p.function()); + if (world.rank()==0) print("update the pair functions via macrotasks -- output redirected"); + MacroTaskIteratePair t1; + MacroTask task1(world, t1); + CC_vecfunction dummy_ex_singles; + std::vector vdummy_3d; // dummy vectors + const std::size_t maxiter=3; + auto unew = task1(pair_vec, coupling_vec, singles, dummy_ex_singles, + info, maxiter); - auto residual=u_old-unew; - timer1.tag("computing pair function update via macrotasks"); - for (int i=0; i::vector2pairs(pair_vec,triangular_map); + std::vector u_old; + for (auto p : pair_vec) u_old.push_back(p.function()); - // save latest iteration - if (world.rank()==0) print("saving latest iteration to file"); - for (const auto& pair : pair_vec) { - save(pair.constant_part, pair.name() + "_const"); - save(pair.function(), pair.name()); - } + auto residual=u_old-unew; + timer1.tag("computing pair function update via macrotasks"); - auto [rmsrnorm,maxrnorm]=CCPotentials::residual_stats(residual); - bool doubles_converged=rmsrnorm::vector2pairs(pair_vec,triangular_map); - // check if singles converged - const bool singles_converged = iterate_cc2_singles(world, singles, doubles, info); + // save latest iteration + if (world.rank()==0) print("saving latest iteration to file"); + for (const auto& pair : pair_vec) { + save(pair.constant_part, pair.name() + "_const"); + save(pair.function(), pair.name()); + singles.save_restartdata(world,madness::name(singles.type)); + } - // check if energy converged - const double omega_new = CCPotentials::compute_cc2_correlation_energy(world, singles, doubles, info); - timer1.tag("computing cc2 energy"); - const double delta = omega_new - omega; - const bool omega_converged(delta < parameters.econv()); - omega = omega_new; - if (world.rank() == 0) - std::cout << std::fixed << std::setprecision(10) << "Current Correlation Energy = " << omega << "\n"; - if (world.rank() == 0) - std::cout << std::fixed << std::setprecision(10) << "Difference = " << delta << "\n"; + auto [rmsrnorm,maxrnorm]=CCPotentials::residual_stats(residual); + bool doubles_converged=rmsrnorm single_i; - single_i.type = type; - single_i.i = i; - std::string name=single_i.name(); - if (ex>=0) name = std::to_string(ex) + "_" + single_i.name(); real_function_3d tmpi = real_factory_3d(world); - found_on_file = CCOPS.load_function(tmpi, name); - single_i.function = copy(tmpi); + CCFunction single_i(tmpi, i, type); singles.insert(i,single_i); } - - if (world.rank()==0) { - if (found_on_file) print("singles found on file"); - else print("singles not found on file"); - } - return singles; } @@ -1072,7 +1072,10 @@ CC2::initialize_pairs(Pairs& pairs, const CCState ftype, const CalcType MADNESS_ASSERT(tau.type == PARTICLE); MADNESS_ASSERT(x.type == RESPONSE); MADNESS_ASSERT(pairs.empty()); - output("Initialize " + assign_name(ctype) + " Pairs for " + assign_name(ftype)); + + std::string fname=assign_name(ftype); + if (world.rank()==0) print("initializing doubles",fname); + // output("Initialize " + assign_name(ctype) + " Pairs for " + assign_name(ftype)); bool restarted = false; // std::vector vconst_part; @@ -1105,10 +1108,6 @@ CC2::initialize_pairs(Pairs& pairs, const CCState ftype, const CalcType { CCPair tmp2=CCPotentials::make_pair_lrcc2(world, ctype, utmp, tau, x, i, j, info); - auto doit =[](const CCPair& p) { - auto functions=consolidate(p.functions); - for (const auto& f : functions) f.print_size(); - }; std::swap(tmp,tmp2); print("going on with Florian's pair"); // print("going on with Jakob's pair"); diff --git a/src/madness/chem/CCStructures.cc b/src/madness/chem/CCStructures.cc index c7d63baa003..85dcc049cc5 100644 --- a/src/madness/chem/CCStructures.cc +++ b/src/madness/chem/CCStructures.cc @@ -65,15 +65,6 @@ CCTimer::info(const bool debug, const double norm) { -std::string -CC_vecfunction::name(const int ex) const { - if (type == PARTICLE) return "tau"; - else if (type == HOLE) return "phi"; - else if (type == MIXED) return "t"; - else if (type == RESPONSE) return std::to_string(ex) + "_" + "x"; - else return "UNKNOWN"; -} - void CC_vecfunction::print_size(const std::string& msg) const { if (functions.size() == 0) { diff --git a/src/madness/chem/CCStructures.h b/src/madness/chem/CCStructures.h index 10696bb9a50..37ef03c7cc0 100644 --- a/src/madness/chem/CCStructures.h +++ b/src/madness/chem/CCStructures.h @@ -649,7 +649,9 @@ struct CC_vecfunction : public archive::ParallelSerializableObject { std::string irrep = "null"; /// excitation irrep (direct product of x function and corresponding orbital) std::string - name(const int ex) const; + name(const int ex) const { + return madness::name(type,ex); + }; bool is_converged(const double econv, const double dconv) const { return (current_error=0,"ex must be >=0"); + return std::to_string(ex) + "_" + "x"; + } + else { + MADNESS_EXCEPTION("unknown FuncType",1); + } + return "undefined"; +} + /// structure for a CC Function 3D which holds an index and a type // the type is defined by the enum FuncType (definition at the start of this file) template From 0e8faf920a7d7035bec3d8b140021706407257ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Chborchert=E2=80=9D?= <“hannes.borchert@stonybrook.edu”> Date: Mon, 12 Aug 2024 15:33:46 -0400 Subject: [PATCH 44/54] fixed division by zero (ntasks) in store in worlddc.h and formatting --- src/madness/world/worlddc.h | 1315 ++++++++++++++++++++--------------- 1 file changed, 756 insertions(+), 559 deletions(-) diff --git a/src/madness/world/worlddc.h b/src/madness/world/worlddc.h index a6a3a0d410f..88a61dc3f43 100644 --- a/src/madness/world/worlddc.h +++ b/src/madness/world/worlddc.h @@ -48,7 +48,8 @@ #include #include -namespace madness { +namespace madness +{ template class WorldContainer; @@ -57,37 +58,40 @@ namespace madness { class WorldContainerImpl; template - void swap(WorldContainer&, WorldContainer&); + void swap(WorldContainer &, WorldContainer &); template class WorldDCPmapInterface; template - class WorldDCRedistributeInterface { + class WorldDCRedistributeInterface + { public: virtual std::size_t size() const = 0; - virtual void redistribute_phase1(const std::shared_ptr< WorldDCPmapInterface >& newmap) = 0; + virtual void redistribute_phase1(const std::shared_ptr> &newmap) = 0; virtual void redistribute_phase2() = 0; virtual void redistribute_phase3() = 0; - virtual ~WorldDCRedistributeInterface() {}; + virtual ~WorldDCRedistributeInterface() {}; }; - /// Interface to be provided by any process map /// \ingroup worlddc template - class WorldDCPmapInterface { + class WorldDCPmapInterface + { public: - typedef WorldDCRedistributeInterface* ptrT; + typedef WorldDCRedistributeInterface *ptrT; + private: std::set ptrs; + public: /// Maps key to processor /// @param[in] key Key for container /// @return Processor that logically owns the key - virtual ProcessID owner(const keyT& key) const = 0; + virtual ProcessID owner(const keyT &key) const = 0; virtual ~WorldDCPmapInterface() {} @@ -96,14 +100,16 @@ namespace madness { /// Registers object for receipt of redistribute callbacks /// @param[in] ptr Pointer to class derived from WorldDCRedistributedInterface - void register_callback(ptrT ptr) { + void register_callback(ptrT ptr) + { ptrs.insert(ptr); } /// Deregisters object for receipt of redistribute callbacks /// @param[in] ptr Pointer to class derived from WorldDCRedistributedInterface - void deregister_callback(ptrT ptr) { + void deregister_callback(ptrT ptr) + { ptrs.erase(ptr); } @@ -113,26 +119,30 @@ namespace madness { /// new map and no objects will be registered in the current map. /// @param[in] world The associated world /// @param[in] newpmap The new process map - void redistribute(World& world, const std::shared_ptr< WorldDCPmapInterface >& newpmap) { + void redistribute(World &world, const std::shared_ptr> &newpmap) + { print_data_sizes(world, "before redistributing"); world.gop.fence(); for (typename std::set::iterator iter = ptrs.begin(); iter != ptrs.end(); - ++iter) { + ++iter) + { (*iter)->redistribute_phase1(newpmap); } world.gop.fence(); for (typename std::set::iterator iter = ptrs.begin(); iter != ptrs.end(); - ++iter) { + ++iter) + { (*iter)->redistribute_phase2(); newpmap->register_callback(*iter); } world.gop.fence(); for (typename std::set::iterator iter = ptrs.begin(); iter != ptrs.end(); - ++iter) { - (*iter)->redistribute_phase3(); + ++iter) + { + (*iter)->redistribute_phase3(); } world.gop.fence(); ptrs.clear(); @@ -142,7 +152,8 @@ namespace madness { /// Counts global number of entries in all containers associated with this process map /// Collective operation with global fence - std::size_t global_size(World& world) const { + std::size_t global_size(World &world) const + { world.gop.fence(); std::size_t sum = local_size(); world.gop.sum(sum); @@ -151,9 +162,11 @@ namespace madness { } /// Counts local number of entries in all containers associated with this process map - std::size_t local_size() const { + std::size_t local_size() const + { std::size_t sum = 0; - for (typename std::set::iterator iter = ptrs.begin(); iter != ptrs.end(); ++iter) { + for (typename std::set::iterator iter = ptrs.begin(); iter != ptrs.end(); ++iter) + { sum += (*iter)->size(); } return sum; @@ -162,17 +175,20 @@ namespace madness { /// Prints size info to std::cout /// Collective operation with global fence - void print_data_sizes(World& world, const std::string msg="") const { + void print_data_sizes(World &world, const std::string msg = "") const + { world.gop.fence(); std::size_t total = global_size(world); std::vector sizes(world.size()); sizes[world.rank()] = local_size(); - world.gop.sum(&sizes[0],world.size()); - if (world.rank() == 0) { + world.gop.sum(&sizes[0], world.size()); + if (world.rank() == 0) + { madness::print("data distribution info", msg); madness::print(" total: ", total); std::cout << " procs: "; - for (int i=0; i > - class WorldDCDefaultPmap : public WorldDCPmapInterface { + template > + class WorldDCDefaultPmap : public WorldDCPmapInterface + { private: const int nproc; hashfunT hashfun; + public: - WorldDCDefaultPmap(World& world, const hashfunT& hf = hashfunT()) : - nproc(world.mpi.nproc()), - hashfun(hf) - { } + WorldDCDefaultPmap(World &world, const hashfunT &hf = hashfunT()) : nproc(world.mpi.nproc()), + hashfun(hf) + { + } - ProcessID owner(const keyT& key) const { - if (nproc == 1) return 0; - return hashfun(key)%nproc; + ProcessID owner(const keyT &key) const + { + if (nproc == 1) + return 0; + return hashfun(key) % nproc; } }; /// Local process map will always return the current process as owner /// \ingroup worlddc - template > - class WorldDCLocalPmap : public WorldDCPmapInterface { + template > + class WorldDCLocalPmap : public WorldDCPmapInterface + { private: - ProcessID me; + ProcessID me; + public: - WorldDCLocalPmap(World& world) : me(world.rank()) { } - ProcessID owner(const keyT& key) const { - return me; - } + WorldDCLocalPmap(World &world) : me(world.rank()) {} + ProcessID owner(const keyT &key) const + { + return me; + } }; /// Iterator for distributed container wraps the local iterator /// \ingroup worlddc template - class WorldContainerIterator { + class WorldContainerIterator + { public: - typedef typename std::iterator_traits::iterator_category iterator_category; - typedef typename std::iterator_traits::value_type value_type; - typedef typename std::iterator_traits::difference_type difference_type; - typedef typename std::iterator_traits::pointer pointer; - typedef typename std::iterator_traits::reference reference; + typedef typename std::iterator_traits::iterator_category iterator_category; + typedef typename std::iterator_traits::value_type value_type; + typedef typename std::iterator_traits::difference_type difference_type; + typedef typename std::iterator_traits::pointer pointer; + typedef typename std::iterator_traits::reference reference; private: - internal_iteratorT it; ///< Iterator from local container + internal_iteratorT it; ///< Iterator from local container // TODO: Convert this to a scoped pointer. - mutable value_type* value; ///< holds the remote values + mutable value_type *value; ///< holds the remote values public: /// Default constructor makes a local uninitialized value explicit WorldContainerIterator() - : it(), value(nullptr) {} + : it(), value(nullptr) {} /// Initializes from a local iterator - explicit WorldContainerIterator(const internal_iteratorT& it) - : it(it), value(nullptr) {} + explicit WorldContainerIterator(const internal_iteratorT &it) + : it(it), value(nullptr) {} /// Initializes to cache a remote value - explicit WorldContainerIterator(const value_type& v) - : it(), value(nullptr) + explicit WorldContainerIterator(const value_type &v) + : it(), value(nullptr) { value = new value_type(v); } - WorldContainerIterator(const WorldContainerIterator& other) - : it(), value(nullptr) + WorldContainerIterator(const WorldContainerIterator &other) + : it(), value(nullptr) { copy(other); } template - WorldContainerIterator(const WorldContainerIterator& other) - : it(), value(nullptr) + WorldContainerIterator(const WorldContainerIterator &other) + : it(), value(nullptr) { copy(other); } - ~WorldContainerIterator() { + ~WorldContainerIterator() + { delete value; } /// Assignment - WorldContainerIterator& operator=(const WorldContainerIterator& other) { + WorldContainerIterator &operator=(const WorldContainerIterator &other) + { copy(other); return *this; } /// Determines if two iterators are identical - bool operator==(const WorldContainerIterator& other) const { + bool operator==(const WorldContainerIterator &other) const + { return (((!is_cached()) && (!other.is_cached())) && it == other.it) || - ((is_cached() && other.is_cached()) && value->first == other.value->first); + ((is_cached() && other.is_cached()) && value->first == other.value->first); } - /// Determines if two iterators are different - bool operator!=(const WorldContainerIterator& other) const { + bool operator!=(const WorldContainerIterator &other) const + { return !(*this == other); } - /// Pre-increment of an iterator (i.e., ++it) --- \em local iterators only /// Trying to increment a remote iterator will throw - WorldContainerIterator& operator++() { - MADNESS_ASSERT( !is_cached() ); + WorldContainerIterator &operator++() + { + MADNESS_ASSERT(!is_cached()); ++it; return *this; } - WorldContainerIterator operator++(int) { - MADNESS_ASSERT( !is_cached() ); + WorldContainerIterator operator++(int) + { + MADNESS_ASSERT(!is_cached()); WorldContainerIterator result(*this); ++it; return result; } /// Iterators dereference to std::pair - pointer operator->() const { - return (is_cached() ? value : it.operator->() ); + pointer operator->() const + { + return (is_cached() ? value : it.operator->()); } /// Iterators dereference to std::pair - reference operator*() const { - return (is_cached() ? *value : *it ); + reference operator*() const + { + return (is_cached() ? *value : *it); } /// Private: (or should be) Returns iterator of internal container - const internal_iteratorT& get_internal_iterator() const { + const internal_iteratorT &get_internal_iterator() const + { return it; } /// Returns true if this is non-local or cached value - bool is_cached() const { + bool is_cached() const + { return value != nullptr; } template - void serialize(const Archive&) { + void serialize(const Archive &) + { MADNESS_EXCEPTION("Serializing DC iterator ... why?", false); } @@ -328,13 +361,18 @@ namespace madness { friend class WorldContainerIterator; template - void copy(const WorldContainerIterator& other) { - if (static_cast(this) != static_cast(&other)) { + void copy(const WorldContainerIterator &other) + { + if (static_cast(this) != static_cast(&other)) + { delete value; - if(other.is_cached()) { - value = new value_type(* other.value); + if (other.is_cached()) + { + value = new value_type(*other.value); it = internal_iteratorT(); - } else { + } + else + { it = other.it; value = nullptr; } @@ -345,22 +383,23 @@ namespace madness { /// Internal implementation of distributed container to facilitate shallow copy /// \ingroup worlddc - template + template class WorldContainerImpl - : public WorldObject< WorldContainerImpl > - , public WorldDCRedistributeInterface + : public WorldObject>, + public WorldDCRedistributeInterface #ifndef MADNESS_DISABLE_SHARED_FROM_THIS - , public std::enable_shared_from_this > + , + public std::enable_shared_from_this> #endif // MADNESS_DISABLE_SHARED_FROM_THIS { public: - typedef typename std::pair pairT; + typedef typename std::pair pairT; typedef const pairT const_pairT; - typedef WorldContainerImpl implT; + typedef WorldContainerImpl implT; - typedef ConcurrentHashMap< keyT,valueT,hashfunT > internal_containerT; + typedef ConcurrentHashMap internal_containerT; - //typedef WorldObject< WorldContainerImpl > worldobjT; + // typedef WorldObject< WorldContainerImpl > worldobjT; typedef typename internal_containerT::iterator internal_iteratorT; typedef typename internal_containerT::const_iterator internal_const_iteratorT; @@ -371,82 +410,87 @@ namespace madness { typedef WorldContainerIterator const_iteratorT; typedef WorldContainerIterator const_iterator; - friend class WorldContainer; + friend class WorldContainer; -// template -// inline -// static -// typename containerT::iterator replace(containerT& c, const datumT& d) { -// std::pair p = c.insert(d); -// if (!p.second) p.first->second = d.second; // Who's on first? -// return p.first; -// } + // template + // inline + // static + // typename containerT::iterator replace(containerT& c, const datumT& d) { + // std::pair p = c.insert(d); + // if (!p.second) p.first->second = d.second; // Who's on first? + // return p.first; + // } private: + WorldContainerImpl(); // Inhibit default constructor - WorldContainerImpl(); // Inhibit default constructor - - std::shared_ptr< WorldDCPmapInterface > pmap;///< Function/class to map from keys to owning process - const ProcessID me; ///< My MPI rank - internal_containerT local; ///< Locally owned data - std::vector* move_list; ///< Tempoary used to record data that needs redistributing + std::shared_ptr> pmap; ///< Function/class to map from keys to owning process + const ProcessID me; ///< My MPI rank + internal_containerT local; ///< Locally owned data + std::vector *move_list; ///< Tempoary used to record data that needs redistributing /// Handles find request - void find_handler(ProcessID requestor, const keyT& key, const RemoteReference< FutureImpl >& ref) { + void find_handler(ProcessID requestor, const keyT &key, const RemoteReference> &ref) + { internal_iteratorT r = local.find(key); - if (r == local.end()) { - //print("find_handler: failure:", key); + if (r == local.end()) + { + // print("find_handler: failure:", key); this->send(requestor, &implT::find_failure_handler, ref); } - else { - //print("find_handler: success:", key, r->first, r->second); + else + { + // print("find_handler: success:", key, r->first, r->second); this->send(requestor, &implT::find_success_handler, ref, *r); } } /// Handles successful find response - void find_success_handler(const RemoteReference< FutureImpl >& ref, const pairT& datum) { - FutureImpl* f = ref.get(); + void find_success_handler(const RemoteReference> &ref, const pairT &datum) + { + FutureImpl *f = ref.get(); f->set(iterator(datum)); - //print("find_success_handler: success:", datum.first, datum.second, f->get()->first, f->get()->second); - // Todo: Look at this again. -// ref.reset(); // Matching inc() in find() where ref was made + // print("find_success_handler: success:", datum.first, datum.second, f->get()->first, f->get()->second); + // Todo: Look at this again. + // ref.reset(); // Matching inc() in find() where ref was made } /// Handles unsuccessful find response - void find_failure_handler(const RemoteReference< FutureImpl >& ref) { - FutureImpl* f = ref.get(); + void find_failure_handler(const RemoteReference> &ref) + { + FutureImpl *f = ref.get(); f->set(end()); - //print("find_failure_handler"); - // Todo: Look at this again. -// ref.reset(); // Matching inc() in find() where ref was made + // print("find_failure_handler"); + // Todo: Look at this again. + // ref.reset(); // Matching inc() in find() where ref was made } public: - - WorldContainerImpl(World& world, - const std::shared_ptr< WorldDCPmapInterface >& pm, - const hashfunT& hf) - : WorldObject< WorldContainerImpl >(world) - , pmap(pm) - , me(world.mpi.rank()) - , local(5011, hf) { + WorldContainerImpl(World &world, + const std::shared_ptr> &pm, + const hashfunT &hf) + : WorldObject>(world), pmap(pm), me(world.mpi.rank()), local(5011, hf) + { pmap->register_callback(this); } - virtual ~WorldContainerImpl() { + virtual ~WorldContainerImpl() + { pmap->deregister_callback(this); } - const std::shared_ptr< WorldDCPmapInterface >& get_pmap() const { + const std::shared_ptr> &get_pmap() const + { return pmap; } - std::shared_ptr< WorldDCPmapInterface >& get_pmap() { + std::shared_ptr> &get_pmap() + { return pmap; } - void reset_pmap_to_local() { + void reset_pmap_to_local() + { pmap->deregister_callback(this); pmap.reset(new WorldDCLocalPmap(this->get_world())); pmap->register_callback(this); @@ -454,51 +498,61 @@ namespace madness { /// replicates this WorldContainer on all ProcessIDs and generates a /// ProcessMap where all nodes are local - void replicate(bool fence) { - - World& world=this->get_world(); - pmap->deregister_callback(this); - pmap.reset(new WorldDCLocalPmap(world)); - pmap->register_callback(this); - - for (ProcessID rank=0; rankfirst; - valueT value = it->second; - world.gop.broadcast_serializable(key, rank); - world.gop.broadcast_serializable(value, rank); - } - } - else { - size_t sz; - world.gop.broadcast_serializable(sz, rank); - for (size_t i=0; iget_world(); + pmap->deregister_callback(this); + pmap.reset(new WorldDCLocalPmap(world)); + pmap->register_callback(this); + + for (ProcessID rank = 0; rank < world.size(); rank++) + { + if (rank == world.rank()) + { + std::size_t sz = size(); + world.gop.broadcast_serializable(sz, rank); + + for (auto it = begin(); it != end(); ++it) + { + keyT key = it->first; + valueT value = it->second; + world.gop.broadcast_serializable(key, rank); + world.gop.broadcast_serializable(value, rank); + } + } + else + { + size_t sz; + world.gop.broadcast_serializable(sz, rank); + for (size_t i = 0; i < sz; i++) + { + keyT key; + valueT value; + world.gop.broadcast_serializable(key, rank); + world.gop.broadcast_serializable(value, rank); + insert(pairT(key, value)); + } + } + } + if (fence) + world.gop.fence(); + } + + hashfunT &get_hash() const { return local.get_hash(); } + + bool is_local(const keyT &key) const + { return owner(key) == me; } - ProcessID owner(const keyT& key) const { + ProcessID owner(const keyT &key) const + { return pmap->owner(key); } - bool probe(const keyT& key) const { + bool probe(const keyT &key) const + { ProcessID dest = owner(key); if (dest == me) return local.find(key) != local.end(); @@ -506,123 +560,146 @@ namespace madness { return false; } - std::size_t size() const { + std::size_t size() const + { return local.size(); } - void insert(const pairT& datum) { + void insert(const pairT &datum) + { ProcessID dest = owner(datum.first); - if (dest == me) { + if (dest == me) + { // Was using iterator ... try accessor ????? accessor acc; // N.B. key might already exist if want to simply replace - [[maybe_unused]] auto inserted = local.insert(acc,datum.first); + [[maybe_unused]] auto inserted = local.insert(acc, datum.first); acc->second = datum.second; } - else { - // Must be send (not task) for sequential consistency (and relies on single-threaded remote server) + else + { + // Must be send (not task) for sequential consistency (and relies on single-threaded remote server) this->send(dest, &implT::insert, datum); } } - bool insert_acc(accessor& acc, const keyT& key) { + bool insert_acc(accessor &acc, const keyT &key) + { MADNESS_ASSERT(owner(key) == me); - return local.insert(acc,key); + return local.insert(acc, key); } - bool insert_const_acc(const_accessor& acc, const keyT& key) { + bool insert_const_acc(const_accessor &acc, const keyT &key) + { MADNESS_ASSERT(owner(key) == me); - return local.insert(acc,key); + return local.insert(acc, key); } - void clear() { + void clear() + { local.clear(); } - - void erase(const keyT& key) { + void erase(const keyT &key) + { ProcessID dest = owner(key); - if (dest == me) { + if (dest == me) + { [[maybe_unused]] auto erased = local.try_erase(key); MADNESS_ASSERT(erased); } - else { - void(implT::*eraser)(const keyT&) = &implT::erase; + else + { + void (implT::*eraser)(const keyT &) = &implT::erase; this->send(dest, eraser, key); } } template - void erase(InIter it) { + void erase(InIter it) + { MADNESS_ASSERT(!it.is_cached()); MADNESS_ASSERT(it != end()); erase(it->first); } template - void erase(InIter first, InIter last) { + void erase(InIter first, InIter last) + { InIter it = first; - do { + do + { first++; erase(it->first); it = first; - } while(first != last); + } while (first != last); } - iterator begin() { + iterator begin() + { return iterator(local.begin()); } - const_iterator begin() const { + const_iterator begin() const + { return const_iterator(local.begin()); } - iterator end() { + iterator end() + { return iterator(local.end()); } - const_iterator end() const { + const_iterator end() const + { return const_iterator(local.end()); } - Future find(const keyT& key) const { + Future find(const keyT &key) const + { // Ugliness here to avoid replicating find() and // associated handlers for const. Assumption is that // const and non-const iterators are identical except for // const attribute ... at some point probably need to do // the right thing. - Future r = const_cast(this)->find(key); - return *(Future*)(&r); + Future r = const_cast(this)->find(key); + return *(Future *)(&r); } - - Future find(const keyT& key) { + Future find(const keyT &key) + { ProcessID dest = owner(key); - if (dest == me) { + if (dest == me) + { return Future(iterator(local.find(key))); - } else { + } + else + { Future result; this->send(dest, &implT::find_handler, me, key, result.remote_ref(this->get_world())); return result; } } - bool find(accessor& acc, const keyT& key) { - if (owner(key) != me) return false; - return local.find(acc,key); + bool find(accessor &acc, const keyT &key) + { + if (owner(key) != me) + return false; + return local.find(acc, key); } - - bool find(const_accessor& acc, const keyT& key) const { - if (owner(key) != me) return false; - return local.find(acc,key); + bool find(const_accessor &acc, const keyT &key) const + { + if (owner(key) != me) + return false; + return local.find(acc, key); } - // Used to forward call to item member function template MEMFUN_RETURNT(memfunT) - itemfun(const keyT& key, memfunT memfun) { + itemfun(const keyT &key, memfunT memfun) + { accessor acc; // N.B. key may already exist, this is just to ensure lock is held by acc [[maybe_unused]] auto inserted = local.insert(acc, key); @@ -632,7 +709,8 @@ namespace madness { // Used to forward call to item member function template MEMFUN_RETURNT(memfunT) - itemfun(const keyT& key, memfunT memfun, const arg1T& arg1) { + itemfun(const keyT &key, memfunT memfun, const arg1T &arg1) + { accessor acc; // N.B. key may already exist, this is just to ensure lock is held by acc [[maybe_unused]] auto inserted = local.insert(acc, key); @@ -642,110 +720,122 @@ namespace madness { // Used to forward call to item member function template MEMFUN_RETURNT(memfunT) - itemfun(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2) { + itemfun(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2) + { accessor acc; // N.B. key may already exist, this is just to ensure lock is held by acc [[maybe_unused]] auto inserted = local.insert(acc, key); - return (acc->second.*memfun)(arg1,arg2); + return (acc->second.*memfun)(arg1, arg2); } // Used to forward call to item member function template MEMFUN_RETURNT(memfunT) - itemfun(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3) { + itemfun(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3) + { accessor acc; // N.B. key may already exist, this is just to ensure lock is held by acc [[maybe_unused]] auto inserted = local.insert(acc, key); - return (acc->second.*memfun)(arg1,arg2,arg3); + return (acc->second.*memfun)(arg1, arg2, arg3); } // Used to forward call to item member function template MEMFUN_RETURNT(memfunT) - itemfun(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, const arg4T& arg4) { + itemfun(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4) + { accessor acc; // N.B. key may already exist, this is just to ensure lock is held by acc [[maybe_unused]] auto inserted = local.insert(acc, key); - return (acc->second.*memfun)(arg1,arg2,arg3,arg4); + return (acc->second.*memfun)(arg1, arg2, arg3, arg4); } // Used to forward call to item member function template MEMFUN_RETURNT(memfunT) - itemfun(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, const arg4T& arg4, const arg5T& arg5) { + itemfun(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5) + { accessor acc; // N.B. key may already exist, this is just to ensure lock is held by acc [[maybe_unused]] auto inserted = local.insert(acc, key); - return (acc->second.*memfun)(arg1,arg2,arg3,arg4,arg5); + return (acc->second.*memfun)(arg1, arg2, arg3, arg4, arg5); } // Used to forward call to item member function template MEMFUN_RETURNT(memfunT) - itemfun(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, const arg4T& arg4, const arg5T& arg5, const arg6T& arg6) { + itemfun(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5, const arg6T &arg6) + { accessor acc; // N.B. key may already exist, this is just to ensure lock is held by acc [[maybe_unused]] auto inserted = local.insert(acc, key); - return (acc->second.*memfun)(arg1,arg2,arg3,arg4,arg5,arg6); + return (acc->second.*memfun)(arg1, arg2, arg3, arg4, arg5, arg6); } // Used to forward call to item member function template MEMFUN_RETURNT(memfunT) - itemfun(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, - const arg4T& arg4, const arg5T& arg5, const arg6T& arg6, const arg7T& arg7) { + itemfun(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, + const arg4T &arg4, const arg5T &arg5, const arg6T &arg6, const arg7T &arg7) + { accessor acc; // N.B. key may already exist, this is just to ensure lock is held by acc [[maybe_unused]] auto inserted = local.insert(acc, key); - return (acc->second.*memfun)(arg1,arg2,arg3,arg4,arg5,arg6,arg7); + return (acc->second.*memfun)(arg1, arg2, arg3, arg4, arg5, arg6, arg7); } // First phase of redistributions changes pmap and makes list of stuff to move - void redistribute_phase1(const std::shared_ptr< WorldDCPmapInterface >& newpmap) { + void redistribute_phase1(const std::shared_ptr> &newpmap) + { pmap = newpmap; move_list = new std::vector(); - for (typename internal_containerT::iterator iter=local.begin(); iter!=local.end(); ++iter) { - if (owner(iter->first) != me) move_list->push_back(iter->first); + for (typename internal_containerT::iterator iter = local.begin(); iter != local.end(); ++iter) + { + if (owner(iter->first) != me) + move_list->push_back(iter->first); } } - struct P2Op { - implT * impl; - typedef Range::const_iterator> rangeT; - P2Op(implT* impl) : impl(impl) {} - P2Op(const P2Op& p) : impl(p.impl) {} - bool operator()(typename rangeT::iterator& iterator) const { - typename internal_containerT::iterator iter = impl->local.find(*iterator); - MADNESS_ASSERT(iter != impl->local.end()); - - //impl->insert(*iter); - impl->task(impl->owner(*iterator), &implT::insert, *iter); - - impl->local.erase(iter); // delete local copy of the data - return true; - } - }; + struct P2Op + { + implT *impl; + typedef Range::const_iterator> rangeT; + P2Op(implT *impl) : impl(impl) {} + P2Op(const P2Op &p) : impl(p.impl) {} + bool operator()(typename rangeT::iterator &iterator) const + { + typename internal_containerT::iterator iter = impl->local.find(*iterator); + MADNESS_ASSERT(iter != impl->local.end()); + + // impl->insert(*iter); + impl->task(impl->owner(*iterator), &implT::insert, *iter); + + impl->local.erase(iter); // delete local copy of the data + return true; + } + }; // Second phase moves data - void redistribute_phase2() { - this->get_world().taskq.for_each(typename P2Op::rangeT(move_list->begin(), move_list->end()), P2Op(this)); - //std::vector& mvlist = *move_list; - //for (unsigned int i=0; isize(); ++i) { - // typename internal_containerT::iterator iter = local.find(mvlist[i]); - // MADNESS_ASSERT(iter != local.end()); - // insert(*iter); - // local.erase(iter); - //} - //delete move_list; + void redistribute_phase2() + { + this->get_world().taskq.for_each(typename P2Op::rangeT(move_list->begin(), move_list->end()), P2Op(this)); + // std::vector& mvlist = *move_list; + // for (unsigned int i=0; isize(); ++i) { + // typename internal_containerT::iterator iter = local.find(mvlist[i]); + // MADNESS_ASSERT(iter != local.end()); + // insert(*iter); + // local.erase(iter); + // } + // delete move_list; } // Third phase cleans up - void redistribute_phase3() { - delete move_list; + void redistribute_phase3() + { + delete move_list; } }; - /// Makes a distributed container with specified attributes /// \ingroup worlddc @@ -771,11 +861,12 @@ namespace madness { /// All operations, including constructors and destructors, are /// non-blocking and return immediately. If communication occurs /// it is asynchronous, otherwise operations are local. - template > - class WorldContainer : public archive::ParallelSerializableObject { + template > + class WorldContainer : public archive::ParallelSerializableObject + { public: - typedef WorldContainer containerT; - typedef WorldContainerImpl implT; + typedef WorldContainer containerT; + typedef WorldContainerImpl implT; typedef typename implT::pairT pairT; typedef typename implT::iterator iterator; typedef typename implT::const_iterator const_iterator; @@ -787,20 +878,21 @@ namespace madness { private: std::shared_ptr p; - inline void check_initialized() const { + inline void check_initialized() const + { MADNESS_ASSERT(p); } - public: + public: /// Makes an uninitialized container (no communication) /// The container is useless until assigned to from a fully /// constructed container. There is no need to worry about /// default constructors being executed in order. WorldContainer() - : p() - {} - + : p() + { + } /// Makes an initialized, empty container with default data distribution (no communication) @@ -809,12 +901,12 @@ namespace madness { /// making a container, we have to assume that all processes /// execute this constructor in the same order (does not apply /// to the non-initializing, default constructor). - WorldContainer(World& world, bool do_pending=true, const hashfunT& hf = hashfunT()) + WorldContainer(World &world, bool do_pending = true, const hashfunT &hf = hashfunT()) : p(new implT(world, - std::shared_ptr< WorldDCPmapInterface >(new WorldDCDefaultPmap(world, hf)), + std::shared_ptr>(new WorldDCDefaultPmap(world, hf)), hf)) { - if(do_pending) + if (do_pending) p->process_pending(); } @@ -825,22 +917,21 @@ namespace madness { /// making a container, we have to assume that all processes /// execute this constructor in the same order (does not apply /// to the non-initializing, default constructor). - WorldContainer(World& world, - const std::shared_ptr< WorldDCPmapInterface >& pmap, - bool do_pending=true, - const hashfunT& hf = hashfunT()) + WorldContainer(World &world, + const std::shared_ptr> &pmap, + bool do_pending = true, + const hashfunT &hf = hashfunT()) : p(new implT(world, pmap, hf)) { - if(do_pending) + if (do_pending) p->process_pending(); } - /// Copy constructor is shallow (no communication) /// The copy refers to exactly the same container as other /// which must be initialized. - WorldContainer(const WorldContainer& other) + WorldContainer(const WorldContainer &other) : p(other.p) { check_initialized(); @@ -850,8 +941,10 @@ namespace madness { /// The copy refers to exactly the same container as other /// which must be initialized. - containerT& operator=(const containerT& other) { - if (this != &other) { + containerT &operator=(const containerT &other) + { + if (this != &other) + { other.check_initialized(); p = other.p; } @@ -859,140 +952,146 @@ namespace madness { } /// Returns the world associated with this container - World& get_world() const { + World &get_world() const + { check_initialized(); return p->get_world(); } - std::shared_ptr< WorldDCPmapInterface >& get_impl() { + std::shared_ptr> &get_impl() + { check_initialized(); return p; } /// replicates this WorldContainer on all ProcessIDs - void replicate(bool fence=true) { - p->replicate(fence); + void replicate(bool fence = true) + { + p->replicate(fence); } /// Inserts/replaces key+value pair (non-blocking communication if key not local) - void replace(const pairT& datum) { + void replace(const pairT &datum) + { check_initialized(); p->insert(datum); } - /// Inserts/replaces key+value pair (non-blocking communication if key not local) - void replace(const keyT& key, const valueT& value) { - replace(pairT(key,value)); + void replace(const keyT &key, const valueT &value) + { + replace(pairT(key, value)); } - /// Write access to LOCAL value by key. Returns true if found, false otherwise (always false for remote). - bool find(accessor& acc, const keyT& key) { + bool find(accessor &acc, const keyT &key) + { check_initialized(); - return p->find(acc,key); + return p->find(acc, key); } - /// Read access to LOCAL value by key. Returns true if found, false otherwise (always false for remote). - bool find(const_accessor& acc, const keyT& key) const { + bool find(const_accessor &acc, const keyT &key) const + { check_initialized(); - return p->find(acc,key); + return p->find(acc, key); } - /// Write access to LOCAL value by key. Returns true if inserted, false if already exists (throws if remote) - bool insert(accessor& acc, const keyT& key) { + bool insert(accessor &acc, const keyT &key) + { check_initialized(); - return p->insert_acc(acc,key); + return p->insert_acc(acc, key); } - /// Read access to LOCAL value by key. Returns true if inserted, false if already exists (throws if remote) - bool insert(const_accessor& acc, const keyT& key) { + bool insert(const_accessor &acc, const keyT &key) + { check_initialized(); - return p->insert_acc(acc,key); + return p->insert_acc(acc, key); } - /// Inserts pairs (non-blocking communication if key(s) not local) template - void replace(input_iterator& start, input_iterator& end) { + void replace(input_iterator &start, input_iterator &end) + { check_initialized(); using std::placeholders::_1; - std::for_each(start,end,std::bind(this,std::mem_fn(&containerT::insert),_1)); + std::for_each(start, end, std::bind(this, std::mem_fn(&containerT::insert), _1)); } - /// Returns true if local data is immediately available (no communication) - bool probe(const keyT& key) const { + bool probe(const keyT &key) const + { check_initialized(); return p->probe(key); } - /// Returns processor that logically owns key (no communication) /// Local remapping may have changed its physical location, but all /// operations should forward correctly. - inline ProcessID owner(const keyT& key) const { + inline ProcessID owner(const keyT &key) const + { check_initialized(); return p->owner(key); } - /// Returns true if the key maps to the local processor (no communication) - bool is_local(const keyT& key) const { + bool is_local(const keyT &key) const + { check_initialized(); return p->is_local(key); } - /// Returns a future iterator (non-blocking communication if key not local) /// Like an std::map an iterator "points" to an std::pair. /// /// Refer to Future for info on how to avoid blocking. - Future find(const keyT& key) { // + Future find(const keyT &key) + { // check_initialized(); return p->find(key); } - /// Returns a future iterator (non-blocking communication if key not local) /// Like an std::map an iterator "points" to an std::pair. /// /// Refer to Future for info on how to avoid blocking. - Future find(const keyT& key) const { + Future find(const keyT &key) const + { check_initialized(); - return const_cast(p.get())->find(key); + return const_cast(p.get())->find(key); } - /// Returns an iterator to the beginning of the \em local data (no communication) - iterator begin() { + iterator begin() + { check_initialized(); return p->begin(); } - /// Returns an iterator to the beginning of the \em local data (no communication) - const_iterator begin() const { + const_iterator begin() const + { check_initialized(); - return const_cast(p.get())->begin(); + return const_cast(p.get())->begin(); } /// Returns an iterator past the end of the \em local data (no communication) - iterator end() { + iterator end() + { check_initialized(); return p->end(); } /// Returns an iterator past the end of the \em local data (no communication) - const_iterator end() const { + const_iterator end() const + { check_initialized(); - return const_cast(p.get())->end(); + return const_cast(p.get())->end(); } /// Erases entry from container (non-blocking comm if remote) @@ -1003,51 +1102,58 @@ namespace madness { /// remote end. This is just the same as what happens when /// using STL iterators on an STL container in a sequential /// algorithm. - void erase(const keyT& key) { + void erase(const keyT &key) + { check_initialized(); p->erase(key); } /// Erases entry corresponding to \em local iterator (no communication) - void erase(const iterator& it) { + void erase(const iterator &it) + { check_initialized(); p->erase(it); } /// Erases range defined by \em local iterators (no communication) - void erase(const iterator& start, const iterator& finish) { + void erase(const iterator &start, const iterator &finish) + { check_initialized(); - p->erase(start,finish); + p->erase(start, finish); } - /// Clears all \em local data (no communication) /// Invalidates all iterators - void clear() { + void clear() + { check_initialized(); p->clear(); } /// Returns the number of \em local entries (no communication) - std::size_t size() const { + std::size_t size() const + { check_initialized(); return p->size(); } /// Returns shared pointer to the process mapping - inline const std::shared_ptr< WorldDCPmapInterface >& get_pmap() const { + inline const std::shared_ptr> &get_pmap() const + { check_initialized(); return p->get_pmap(); } /// Returns shared pointer to the process mapping - inline void reset_pmap_to_local() { + inline void reset_pmap_to_local() + { p->reset_pmap_to_local(); } /// Returns a reference to the hashing functor - hashfunT& get_hash() const { + hashfunT &get_hash() const + { check_initialized(); return p->get_hash(); } @@ -1057,7 +1163,8 @@ namespace madness { /// If the constructor was given \c do_pending=false then you /// \em must invoke this routine in order to process both /// prior and future messages. - inline void process_pending() { + inline void process_pending() + { check_initialized(); p->process_pending(); } @@ -1072,14 +1179,15 @@ namespace madness { /// /// The method executes with a write lock on the item. template - Future< MEMFUN_RETURNT(memfunT) > - send(const keyT& key, memfunT memfun) { + Future + send(const keyT &key, memfunT memfun) + { check_initialized(); - MEMFUN_RETURNT(memfunT)(implT::*itemfun)(const keyT&, memfunT) = &implT:: template itemfun; + MEMFUN_RETURNT(memfunT) + (implT::*itemfun)(const keyT &, memfunT) = &implT::template itemfun; return p->send(owner(key), itemfun, key, memfun); } - /// Sends message "resultT memfun(arg1T)" to item (non-blocking comm if remote) /// If item does not exist it is made with the default constructor. @@ -1090,18 +1198,19 @@ namespace madness { /// /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - send(const keyT& key, const memfunT& memfun, const arg1T& arg1) { + Future + send(const keyT &key, const memfunT &memfun, const arg1T &arg1) + { check_initialized(); // To work around bug in g++ 4.3.* use static cast as alternative mechanism to force type deduction - MEMFUN_RETURNT(memfunT) (implT::*itemfun)(const keyT&, memfunT, const arg1T&) = &implT:: template itemfun; + MEMFUN_RETURNT(memfunT) + (implT::*itemfun)(const keyT &, memfunT, const arg1T &) = &implT::template itemfun; return p->send(owner(key), itemfun, key, memfun, arg1); /*return p->send(owner(key), static_cast(&implT:: template itemfun), key, memfun, arg1);*/ } - /// Sends message "resultT memfun(arg1T,arg2T)" to item (non-blocking comm if remote) /// If item does not exist it is made with the default constructor. @@ -1112,17 +1221,18 @@ namespace madness { /// /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - send(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2) { + Future + send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2) + { check_initialized(); // To work around bug in g++ 4.3.* use static cast as alternative mechanism to force type deduction - MEMFUN_RETURNT(memfunT) (implT::*itemfun)(const keyT&, memfunT, const arg1T&, const arg2T&) = &implT:: template itemfun; + MEMFUN_RETURNT(memfunT) + (implT::*itemfun)(const keyT &, memfunT, const arg1T &, const arg2T &) = &implT::template itemfun; return p->send(owner(key), itemfun, key, memfun, arg1, arg2); /*return p->send(owner(key), static_cast(&implT:: template itemfun), key, memfun, arg1, arg2);*/ } - /// Sends message "resultT memfun(arg1T,arg2T,arg3T)" to item (non-blocking comm if remote) /// If item does not exist it is made with the default constructor. @@ -1133,14 +1243,15 @@ namespace madness { /// /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - send(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3) { + Future + send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3) + { check_initialized(); - MEMFUN_RETURNT(memfunT)(implT::*itemfun)(const keyT&, memfunT, const arg1T&, const arg2T&, const arg3T&) = &implT:: template itemfun; + MEMFUN_RETURNT(memfunT) + (implT::*itemfun)(const keyT &, memfunT, const arg1T &, const arg2T &, const arg3T &) = &implT::template itemfun; return p->send(owner(key), itemfun, key, memfun, arg1, arg2, arg3); } - /// Sends message "resultT memfun(arg1T,arg2T,arg3T,arg4T)" to item (non-blocking comm if remote) /// If item does not exist it is made with the default constructor. @@ -1151,14 +1262,15 @@ namespace madness { /// /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - send(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, const arg4T& arg4) { + Future + send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4) + { check_initialized(); - MEMFUN_RETURNT(memfunT)(implT::*itemfun)(const keyT&, memfunT, const arg1T&, const arg2T&, const arg3T&, const arg4T&) = &implT:: template itemfun; + MEMFUN_RETURNT(memfunT) + (implT::*itemfun)(const keyT &, memfunT, const arg1T &, const arg2T &, const arg3T &, const arg4T &) = &implT::template itemfun; return p->send(owner(key), itemfun, key, memfun, arg1, arg2, arg3, arg4); } - /// Sends message "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T)" to item (non-blocking comm if remote) /// If item does not exist it is made with the default constructor. @@ -1169,14 +1281,15 @@ namespace madness { /// /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - send(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, const arg4T& arg4, const arg5T& arg5) { + Future + send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5) + { check_initialized(); - MEMFUN_RETURNT(memfunT)(implT::*itemfun)(const keyT&, memfunT, const arg1T&, const arg2T&, const arg3T&, const arg4T&, const arg5T&) = &implT:: template itemfun; + MEMFUN_RETURNT(memfunT) + (implT::*itemfun)(const keyT &, memfunT, const arg1T &, const arg2T &, const arg3T &, const arg4T &, const arg5T &) = &implT::template itemfun; return p->send(owner(key), itemfun, key, memfun, arg1, arg2, arg3, arg4, arg5); } - /// Sends message "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T,arg6T)" to item (non-blocking comm if remote) /// If item does not exist it is made with the default constructor. @@ -1187,14 +1300,15 @@ namespace madness { /// /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - send(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, const arg4T& arg4, const arg5T& arg5, const arg6T& arg6) { + Future + send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5, const arg6T &arg6) + { check_initialized(); - MEMFUN_RETURNT(memfunT)(implT::*itemfun)(const keyT&, memfunT, const arg1T&, const arg2T&, const arg3T&, const arg4T&, const arg5T&, const arg6T&) = &implT:: template itemfun; + MEMFUN_RETURNT(memfunT) + (implT::*itemfun)(const keyT &, memfunT, const arg1T &, const arg2T &, const arg3T &, const arg4T &, const arg5T &, const arg6T &) = &implT::template itemfun; return p->send(owner(key), itemfun, key, memfun, arg1, arg2, arg3, arg4, arg5, arg6); } - /// Sends message "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T,arg6T,arg7T)" to item (non-blocking comm if remote) /// If item does not exist it is made with the default constructor. @@ -1205,91 +1319,98 @@ namespace madness { /// /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - send(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, const arg4T& arg4, - const arg5T& arg5, const arg6T& arg6, const arg7T& arg7) { + Future + send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, + const arg5T &arg5, const arg6T &arg6, const arg7T &arg7) + { check_initialized(); - MEMFUN_RETURNT(memfunT)(implT::*itemfun)(const keyT&, memfunT, const arg1T&, const arg2T&, const arg3T&, const arg4T&, const arg5T&, const arg6T&, const arg7T&) = &implT:: template itemfun; + MEMFUN_RETURNT(memfunT) + (implT::*itemfun)(const keyT &, memfunT, const arg1T &, const arg2T &, const arg3T &, const arg4T &, const arg5T &, const arg6T &, const arg7T &) = &implT::template itemfun; return p->send(owner(key), itemfun, key, memfun, arg1, arg2, arg3, arg4, arg5, arg6, arg7); } - /// Sends message "resultT memfun() const" to item (non-blocking comm if remote) /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - send(const keyT& key, memfunT memfun) const { - return const_cast(this)->send(key,memfun); + Future + send(const keyT &key, memfunT memfun) const + { + return const_cast(this)->send(key, memfun); } /// Sends message "resultT memfun(arg1T) const" to item (non-blocking comm if remote) /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - send(const keyT& key, memfunT memfun, const arg1T& arg1) const { - return const_cast(this)->send(key,memfun,arg1); + Future + send(const keyT &key, memfunT memfun, const arg1T &arg1) const + { + return const_cast(this)->send(key, memfun, arg1); } /// Sends message "resultT memfun(arg1T,arg2T) const" to item (non-blocking comm if remote) /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - send(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2) const { - return const_cast(this)->send(key,memfun,arg1,arg2); + Future + send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2) const + { + return const_cast(this)->send(key, memfun, arg1, arg2); } - /// Sends message "resultT memfun(arg1T,arg2T,arg3T) const" to item (non-blocking comm if remote) /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - send(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3) const { - return const_cast(this)->send(key,memfun,arg1,arg2,arg3); + Future + send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3) const + { + return const_cast(this)->send(key, memfun, arg1, arg2, arg3); } /// Sends message "resultT memfun(arg1T,arg2T,arg3T,arg4T) const" to item (non-blocking comm if remote) /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - send(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, const arg4T& arg4) const { - return const_cast(this)->send(key,memfun,arg1,arg2,arg3,arg4); + Future + send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4) const + { + return const_cast(this)->send(key, memfun, arg1, arg2, arg3, arg4); } /// Sends message "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T) const" to item (non-blocking comm if remote) /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - send(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, const arg4T& arg4, const arg5T& arg5) const { - return const_cast(this)->send(key,memfun,arg1,arg2,arg3,arg4,arg5); + Future + send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5) const + { + return const_cast(this)->send(key, memfun, arg1, arg2, arg3, arg4, arg5); } /// Sends message "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T,arg6T) const" to item (non-blocking comm if remote) /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - send(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, - const arg4T& arg4, const arg5T& arg5, const arg6T& arg6) const { - return const_cast(this)->send(key,memfun,arg1,arg2,arg3,arg4,arg5,arg6); + Future + send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, + const arg4T &arg4, const arg5T &arg5, const arg6T &arg6) const + { + return const_cast(this)->send(key, memfun, arg1, arg2, arg3, arg4, arg5, arg6); } /// Sends message "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T,arg6T,arg7T) const" to item (non-blocking comm if remote) /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - send(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, - const arg4T& arg4, const arg5T& arg5, const arg6T& arg6, const arg7T& arg7) const { - return const_cast(this)->send(key,memfun,arg1,arg2,arg3,arg4,arg5,arg6,arg7); + Future + send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, + const arg4T &arg4, const arg5T &arg5, const arg6T &arg6, const arg7T &arg7) const + { + return const_cast(this)->send(key, memfun, arg1, arg2, arg3, arg4, arg5, arg6, arg7); } - /// Adds task "resultT memfun()" in process owning item (non-blocking comm if remote) /// If item does not exist it is made with the default constructor. @@ -1301,10 +1422,12 @@ namespace madness { /// /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - task(const keyT& key, memfunT memfun, const TaskAttributes& attr = TaskAttributes()) { + Future + task(const keyT &key, memfunT memfun, const TaskAttributes &attr = TaskAttributes()) + { check_initialized(); - MEMFUN_RETURNT(memfunT)(implT::*itemfun)(const keyT&, memfunT) = &implT:: template itemfun; + MEMFUN_RETURNT(memfunT) + (implT::*itemfun)(const keyT &, memfunT) = &implT::template itemfun; return p->task(owner(key), itemfun, key, memfun, attr); } @@ -1319,11 +1442,13 @@ namespace madness { /// /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - task(const keyT& key, memfunT memfun, const arg1T& arg1, const TaskAttributes& attr = TaskAttributes()) { + Future + task(const keyT &key, memfunT memfun, const arg1T &arg1, const TaskAttributes &attr = TaskAttributes()) + { check_initialized(); typedef REMFUTURE(arg1T) a1T; - MEMFUN_RETURNT(memfunT)(implT::*itemfun)(const keyT&, memfunT, const a1T&) = &implT:: template itemfun; + MEMFUN_RETURNT(memfunT) + (implT::*itemfun)(const keyT &, memfunT, const a1T &) = &implT::template itemfun; return p->task(owner(key), itemfun, key, memfun, arg1, attr); } @@ -1338,12 +1463,14 @@ namespace madness { /// /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - task(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const TaskAttributes& attr = TaskAttributes()) { + Future + task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const TaskAttributes &attr = TaskAttributes()) + { check_initialized(); typedef REMFUTURE(arg1T) a1T; typedef REMFUTURE(arg2T) a2T; - MEMFUN_RETURNT(memfunT)(implT::*itemfun)(const keyT&, memfunT, const a1T&, const a2T&) = &implT:: template itemfun; + MEMFUN_RETURNT(memfunT) + (implT::*itemfun)(const keyT &, memfunT, const a1T &, const a2T &) = &implT::template itemfun; return p->task(owner(key), itemfun, key, memfun, arg1, arg2, attr); } @@ -1358,13 +1485,15 @@ namespace madness { /// /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - task(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, const TaskAttributes& attr = TaskAttributes()) { + Future + task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const TaskAttributes &attr = TaskAttributes()) + { check_initialized(); typedef REMFUTURE(arg1T) a1T; typedef REMFUTURE(arg2T) a2T; typedef REMFUTURE(arg3T) a3T; - MEMFUN_RETURNT(memfunT)(implT::*itemfun)(const keyT&, memfunT, const a1T&, const a2T&, const a3T&) = &implT:: template itemfun; + MEMFUN_RETURNT(memfunT) + (implT::*itemfun)(const keyT &, memfunT, const a1T &, const a2T &, const a3T &) = &implT::template itemfun; return p->task(owner(key), itemfun, key, memfun, arg1, arg2, arg3, attr); } @@ -1379,14 +1508,16 @@ namespace madness { /// /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - task(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, const arg4T& arg4, const TaskAttributes& attr = TaskAttributes()) { + Future + task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const TaskAttributes &attr = TaskAttributes()) + { check_initialized(); typedef REMFUTURE(arg1T) a1T; typedef REMFUTURE(arg2T) a2T; typedef REMFUTURE(arg3T) a3T; typedef REMFUTURE(arg4T) a4T; - MEMFUN_RETURNT(memfunT)(implT::*itemfun)(const keyT&, memfunT, const a1T&, const a2T&, const a3T&, const a4T&) = &implT:: template itemfun; + MEMFUN_RETURNT(memfunT) + (implT::*itemfun)(const keyT &, memfunT, const a1T &, const a2T &, const a3T &, const a4T &) = &implT::template itemfun; return p->task(owner(key), itemfun, key, memfun, arg1, arg2, arg3, arg4, attr); } @@ -1401,15 +1532,17 @@ namespace madness { /// /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - task(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, const arg4T& arg4, const arg5T& arg5, const TaskAttributes& attr = TaskAttributes()) { + Future + task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5, const TaskAttributes &attr = TaskAttributes()) + { check_initialized(); typedef REMFUTURE(arg1T) a1T; typedef REMFUTURE(arg2T) a2T; typedef REMFUTURE(arg3T) a3T; typedef REMFUTURE(arg4T) a4T; typedef REMFUTURE(arg5T) a5T; - MEMFUN_RETURNT(memfunT)(implT::*itemfun)(const keyT&, memfunT, const a1T&, const a2T&, const a3T&, const a4T&, const a5T&) = &implT:: template itemfun; + MEMFUN_RETURNT(memfunT) + (implT::*itemfun)(const keyT &, memfunT, const a1T &, const a2T &, const a3T &, const a4T &, const a5T &) = &implT::template itemfun; return p->task(owner(key), itemfun, key, memfun, arg1, arg2, arg3, arg4, arg5, attr); } @@ -1424,8 +1557,9 @@ namespace madness { /// /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - task(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, const arg4T& arg4, const arg5T& arg5, const arg6T& arg6, const TaskAttributes& attr = TaskAttributes()) { + Future + task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5, const arg6T &arg6, const TaskAttributes &attr = TaskAttributes()) + { check_initialized(); typedef REMFUTURE(arg1T) a1T; typedef REMFUTURE(arg2T) a2T; @@ -1433,7 +1567,8 @@ namespace madness { typedef REMFUTURE(arg4T) a4T; typedef REMFUTURE(arg5T) a5T; typedef REMFUTURE(arg6T) a6T; - MEMFUN_RETURNT(memfunT)(implT::*itemfun)(const keyT&, memfunT, const a1T&, const a2T&, const a3T&, const a4T&, const a5T&, const a6T&) = &implT:: template itemfun; + MEMFUN_RETURNT(memfunT) + (implT::*itemfun)(const keyT &, memfunT, const a1T &, const a2T &, const a3T &, const a4T &, const a5T &, const a6T &) = &implT::template itemfun; return p->task(owner(key), itemfun, key, memfun, arg1, arg2, arg3, arg4, arg5, arg6, attr); } @@ -1448,8 +1583,9 @@ namespace madness { /// /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - task(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, const arg4T& arg4, const arg5T& arg5, const arg6T& arg6, const arg7T& arg7, const TaskAttributes& attr = TaskAttributes()) { + Future + task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5, const arg6T &arg6, const arg7T &arg7, const TaskAttributes &attr = TaskAttributes()) + { check_initialized(); typedef REMFUTURE(arg1T) a1T; typedef REMFUTURE(arg2T) a2T; @@ -1458,7 +1594,8 @@ namespace madness { typedef REMFUTURE(arg5T) a5T; typedef REMFUTURE(arg6T) a6T; typedef REMFUTURE(arg7T) a7T; - MEMFUN_RETURNT(memfunT)(implT::*itemfun)(const keyT&, memfunT, const a1T&, const a2T&, const a3T&, const a4T&, const a5T&, const a6T&, const a7T&) = &implT:: template itemfun; + MEMFUN_RETURNT(memfunT) + (implT::*itemfun)(const keyT &, memfunT, const a1T &, const a2T &, const a3T &, const a4T &, const a5T &, const a6T &, const a7T &) = &implT::template itemfun; return p->task(owner(key), itemfun, key, memfun, arg1, arg2, arg3, arg4, arg5, arg6, arg7, attr); } @@ -1466,80 +1603,88 @@ namespace madness { /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - task(const keyT& key, memfunT memfun, const TaskAttributes& attr = TaskAttributes()) const { - return const_cast(this)->task(key,memfun,attr); + Future + task(const keyT &key, memfunT memfun, const TaskAttributes &attr = TaskAttributes()) const + { + return const_cast(this)->task(key, memfun, attr); } /// Adds task "resultT memfun(arg1T) const" in process owning item (non-blocking comm if remote) /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - task(const keyT& key, memfunT memfun, const arg1T& arg1, const TaskAttributes& attr = TaskAttributes()) const { - return const_cast(this)->task(key,memfun,arg1,attr); + Future + task(const keyT &key, memfunT memfun, const arg1T &arg1, const TaskAttributes &attr = TaskAttributes()) const + { + return const_cast(this)->task(key, memfun, arg1, attr); } /// Adds task "resultT memfun(arg1T,arg2T) const" in process owning item (non-blocking comm if remote) /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - task(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const TaskAttributes& attr = TaskAttributes()) const { - return const_cast(this)->task(key,memfun,arg1,arg2,attr); + Future + task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const TaskAttributes &attr = TaskAttributes()) const + { + return const_cast(this)->task(key, memfun, arg1, arg2, attr); } /// Adds task "resultT memfun(arg1T,arg2T,arg3T) const" in process owning item (non-blocking comm if remote) /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - task(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, const TaskAttributes& attr = TaskAttributes()) const { - return const_cast(this)->task(key,memfun,arg1,arg2,arg3,attr); + Future + task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const TaskAttributes &attr = TaskAttributes()) const + { + return const_cast(this)->task(key, memfun, arg1, arg2, arg3, attr); } /// Adds task "resultT memfun(arg1T,arg2T,arg3T, arg4T) const" in process owning item (non-blocking comm if remote) /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - task(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, const arg4T& arg4, const TaskAttributes& attr = TaskAttributes()) const { - return const_cast(this)->task(key,memfun,arg1,arg2,arg3,arg4,attr); + Future + task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const TaskAttributes &attr = TaskAttributes()) const + { + return const_cast(this)->task(key, memfun, arg1, arg2, arg3, arg4, attr); } /// Adds task "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T) const" in process owning item (non-blocking comm if remote) /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - task(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, const arg4T& arg4, const arg5T& arg5, const TaskAttributes& attr = TaskAttributes()) const { - return const_cast(this)->task(key,memfun,arg1,arg2,arg3,arg4,arg5,attr); + Future + task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5, const TaskAttributes &attr = TaskAttributes()) const + { + return const_cast(this)->task(key, memfun, arg1, arg2, arg3, arg4, arg5, attr); } /// Adds task "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T,arg6T) const" in process owning item (non-blocking comm if remote) /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - task(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, const arg4T& arg4, const arg5T& arg5, const arg6T& arg6, const TaskAttributes& attr = TaskAttributes()) const { - return const_cast(this)->task(key,memfun,arg1,arg2,arg3,arg4,arg5,arg6,attr); + Future + task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5, const arg6T &arg6, const TaskAttributes &attr = TaskAttributes()) const + { + return const_cast(this)->task(key, memfun, arg1, arg2, arg3, arg4, arg5, arg6, attr); } /// Adds task "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T,arg6T,arg7T) const" in process owning item (non-blocking comm if remote) /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - task(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, const arg4T& arg4, const arg5T& arg5, const arg6T& arg6, const arg7T& arg7, const TaskAttributes& attr = TaskAttributes()) const { - return const_cast(this)->task(key,memfun,arg1,arg2,arg3,arg4,arg5,arg6,arg7,attr); + Future + task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5, const arg6T &arg6, const arg7T &arg7, const TaskAttributes &attr = TaskAttributes()) const + { + return const_cast(this)->task(key, memfun, arg1, arg2, arg3, arg4, arg5, arg6, arg7, attr); } - /// (de)Serialize --- *Local* data only to/from anything *except* Buffer*Archive and Parallel*Archive /// Advisable for *you* to fence before and after this to ensure consistency template - void serialize(const Archive& ar) { + void serialize(const Archive &ar) + { // // !! If you change the format of this stream make sure that // !! the parallel in/out archive below is compatible @@ -1548,18 +1693,23 @@ namespace madness { unsigned long count = 0; check_initialized(); - if (Archive::is_output_archive) { + if (Archive::is_output_archive) + { ar & magic; - for (iterator it=begin(); it!=end(); ++it) count++; + for (iterator it = begin(); it != end(); ++it) + count++; ar & count; - for (iterator it=begin(); it!=end(); ++it) ar & *it; + for (iterator it = begin(); it != end(); ++it) + ar &*it; } - else { + else + { long cookie = 0l; ar & cookie; MADNESS_ASSERT(cookie == magic); ar & count; - while (count--) { + while (count--) + { pairT datum; ar & datum; replace(datum); @@ -1570,49 +1720,55 @@ namespace madness { /// (de)Serialize --- !! ONLY for purpose of interprocess communication /// This just writes/reads the unique id to/from the Buffer*Archive. - void serialize(const archive::BufferOutputArchive& ar) { + void serialize(const archive::BufferOutputArchive &ar) + { check_initialized(); - ar & static_cast*>(p.get()); + ar &static_cast *>(p.get()); } /// (de)Serialize --- !! ONLY for purpose of interprocess communication /// This just writes/reads the unique id to/from the Buffer*Archive. - void serialize(const archive::BufferInputArchive& ar) { - WorldObject* ptr = nullptr; + void serialize(const archive::BufferInputArchive &ar) + { + WorldObject *ptr = nullptr; ar & ptr; MADNESS_ASSERT(ptr); #ifdef MADNESS_DISABLE_SHARED_FROM_THIS - p.reset(static_cast(ptr), [] (implT *p_) -> void {}); + p.reset(static_cast(ptr), [](implT *p_) -> void{}); #else - p = static_cast(ptr)->shared_from_this(); + p = static_cast(ptr)->shared_from_this(); #endif // MADNESS_DISABLE_SHARED_FROM_THIS } /// Returns the associated unique id ... must be initialized - const uniqueidT& id() const { + const uniqueidT &id() const + { check_initialized(); return p->id(); } /// Destructor passes ownership of implementation to world for deferred cleanup - virtual ~WorldContainer() { + virtual ~WorldContainer() + { detail::deferred_cleanup(p->get_world(), p); } - friend void swap<>(WorldContainer&, WorldContainer&); + friend void swap<>(WorldContainer &, WorldContainer &); }; /// Swaps the content of two WorldContainer objects. It should be called on all nodes. /// \ingroup worlddc template - void swap(WorldContainer& dc0, WorldContainer& dc1) { - std::swap(dc0.p, dc1.p); + void swap(WorldContainer &dc0, WorldContainer &dc1) + { + std::swap(dc0.p, dc1.p); } - namespace archive { + namespace archive + { /// Write container to parallel archive @@ -1620,11 +1776,13 @@ namespace madness { /// all threads on each process serialize some values into a buffer, which gets concatenated /// and finally serialized to localarchive (aka VectorOutputArchive). template - struct ArchiveStoreImpl< ParallelOutputArchive, WorldContainer > { - static void store(const ParallelOutputArchive& ar, const WorldContainer& t) { + struct ArchiveStoreImpl, WorldContainer> + { + static void store(const ParallelOutputArchive &ar, const WorldContainer &t) + { using localarchiveT = VectorOutputArchive; const long magic = -5881828; // Sitar Indian restaurant in Knoxville (negative to indicate parallel!) - typedef WorldContainer dcT; + typedef WorldContainer dcT; using const_iterator = typename dcT::const_iterator; int count = t.size(); // Must be INT for MPI and NOT const since we'll do a global sum eventually @@ -1635,90 +1793,108 @@ namespace madness { // c) Serialize the data into the buffer in parallel over threads // 2. Gather all buffers to process 0 - World* world = ar.get_world(); + World *world = ar.get_world(); world->gop.fence(); // Global fence here - class op_inspector : public TaskInterface { + class op_inspector : public TaskInterface + { const_iterator start, end; - size_t& size; + size_t &size; + public: - op_inspector(const_iterator start, const_iterator end, size_t& size) + op_inspector(const_iterator start, const_iterator end, size_t &size) : start(start), end(end), size(size) {} - void run(World& world) { + void run(World &world) + { BufferOutputArchive bo; - for (const_iterator it=start; it!=end; ++it) bo & *it; + for (const_iterator it = start; it != end; ++it) + bo &*it; size = bo.size(); } }; - class op_executor : public TaskInterface { + class op_executor : public TaskInterface + { const_iterator start, end; - unsigned char* buf; + unsigned char *buf; const size_t size; + public: - op_executor(const_iterator start, const_iterator end, unsigned char* buf, size_t size) + op_executor(const_iterator start, const_iterator end, unsigned char *buf, size_t size) : start(start), end(end), buf(buf), size(size) {} - void run(World& world) { + void run(World &world) + { BufferOutputArchive bo(buf, size); - for (const_iterator it=start; it!=end; ++it) { - bo & *it; + for (const_iterator it = start; it != end; ++it) + { + bo &*it; } MADNESS_CHECK(size == bo.size()); } }; // No need for LOCAL fence here since only master thread is busy - double wall0=wall_time(); + double wall0 = wall_time(); const size_t ntasks = std::min(size_t(count), std::max(size_t(1), ThreadPool::size())); - const size_t max_items_per_task = (std::max(1,count)-1)/ntasks + 1; - - // Compute the size of the buffer needed by each task - const_iterator starts[ntasks], ends[ntasks]; - size_t local_sizes[ntasks]; - const_iterator start = t.begin(); - size_t nleft = count; - for (size_t taskid=0; taskid 0) + { + const size_t max_items_per_task = (std::max(1, count) - 1) / ntasks + 1; + // Compute the size of the buffer needed by each task + const_iterator starts[ntasks], ends[ntasks]; + size_t local_sizes[ntasks]; + const_iterator start = t.begin(); + size_t nleft = count; + for (size_t taskid = 0; taskid < ntasks; taskid++) + { + const_iterator end = start; + if (taskid == (ntasks - 1)) + { + end = t.end(); + } + else + { + size_t nitems = std::min(max_items_per_task, nleft); + std::advance(end, max_items_per_task); + nleft -= nitems; + } + starts[taskid] = start; + ends[taskid] = end; + world->taskq.add(new op_inspector(start, end, local_sizes[taskid])); // Be sure to pass iterators by value!! + start = end; } - else { - size_t nitems = std::min(max_items_per_task, nleft); - std::advance(end, max_items_per_task); - nleft -= nitems; + world->taskq.fence(); // just need LOCAL fence + wall1 = wall_time(); + if (world->rank() == 0) + printf("time in op_inspector: %8.4fs\n", wall1 - wall0); + wall0 = wall1; + + // total size over all threads + for (size_t taskid = 0; taskid < ntasks; taskid++) + { + local_size += local_sizes[taskid]; + // print("taskid",taskid,"size",local_sizes[taskid]); } - starts[taskid] = start; - ends[taskid] = end; - world->taskq.add(new op_inspector(start, end, local_sizes[taskid])); // Be sure to pass iterators by value!! - start = end; - } - world->taskq.fence(); // just need LOCAL fence - double wall1=wall_time(); - if (world->rank()==0) printf("time in op_inspector: %8.4fs\n",wall1-wall0); - wall0=wall1; - // total size over all threads - size_t local_size = 0; - for (size_t taskid=0; taskidtaskq.add(new op_executor(starts[taskid], ends[taskid], buf + offset, local_sizes[taskid])); + offset += local_sizes[taskid]; + } + world->taskq.fence(); // just need LOCAL fence - // Now execute the serialization - size_t offset = 0; - for (size_t taskid=0; taskidtaskq.add(new op_executor(starts[taskid], ends[taskid], buf+offset, local_sizes[taskid])); - offset += local_sizes[taskid]; + wall1 = wall_time(); + if (world->rank() == 0) + printf("time in op_executor: %8.4fs\n", wall1 - wall0); + wall0 = wall1; } - world->taskq.fence(); // just need LOCAL fence - - wall1=wall_time(); - if (world->rank()==0) printf("time in op_executor: %8.4fs\n",wall1-wall0); - wall0 = wall1; - // VERify that the serialization worked!! // { // BufferInputArchive bi(buf, local_size); @@ -1728,7 +1904,7 @@ namespace madness { // print("deserializing",datum.first); // } // } - + // Gather all buffers to process 0 // first gather all of the sizes and counts to a vector in process 0 const int size = local_size; @@ -1736,39 +1912,45 @@ namespace madness { MPI_Gather(&size, 1, MPI_INT, sizes.data(), 1, MPI_INT, 0, world->mpi.comm().Get_mpi_comm()); world->gop.sum(count); // just need total number of elements - //print("time 3",wall_time()); - // build the cumulative sum of sizes + // print("time 3",wall_time()); + // build the cumulative sum of sizes std::vector offsets(world->size()); offsets[0] = 0; - for (int i=1; isize(); ++i) offsets[i] = offsets[i-1] + sizes[i-1]; - size_t total_size = offsets.back()+sizes.back(); - if (world->rank() == 0) print("total_size",total_size); + for (int i = 1; i < world->size(); ++i) + offsets[i] = offsets[i - 1] + sizes[i - 1]; + size_t total_size = offsets.back() + sizes.back(); + if (world->rank() == 0) + print("total_size", total_size); // print("time 4",wall_time()); // gather the vector of data v from each process to process 0 - unsigned char* all_data=0; - if (world->rank() == 0) { + unsigned char *all_data = 0; + if (world->rank() == 0) + { all_data = new unsigned char[total_size]; } MPI_Gatherv(buf, local_size, MPI_BYTE, all_data, sizes.data(), offsets.data(), MPI_BYTE, 0, world->mpi.comm().Get_mpi_comm()); - wall1=wall_time(); - if (world->rank()==0) printf("time in gather+gatherv: %8.4fs\n",wall1-wall0); + wall1 = wall_time(); + if (world->rank() == 0) + printf("time in gather+gatherv: %8.4fs\n", wall1 - wall0); wall0 = wall1; delete[] buf; - + // print("time 5",wall_time()); - if (world->rank() == 0) { - auto& localar = ar.local_archive(); + if (world->rank() == 0) + { + auto &localar = ar.local_archive(); localar & magic & 1; // 1 client // localar & t; - ArchivePrePostImpl::preamble_store(localar); - localar & -magic & (unsigned long)(count); + ArchivePrePostImpl::preamble_store(localar); + localar & -magic &(unsigned long)(count); localar.store(all_data, total_size); - ArchivePrePostImpl::postamble_store(localar); - wall1=wall_time(); - if (world->rank()==0) printf("time in final copy on node 0: %8.4fs\n",wall1-wall0); + ArchivePrePostImpl::postamble_store(localar); + wall1 = wall_time(); + if (world->rank() == 0) + printf("time in final copy on node 0: %8.4fs\n", wall1 - wall0); delete[] all_data; } @@ -1777,7 +1959,6 @@ namespace madness { } }; - /// Write container to parallel archive with optional fence /// \ingroup worlddc @@ -1796,57 +1977,68 @@ namespace madness { /// subsequent modifications. Also, there is always at least /// some synchronization between a client and its IO server. template - struct ArchiveStoreImpl< ParallelOutputArchive, WorldContainer > { - static void store(const ParallelOutputArchive& ar, const WorldContainer& t) { + struct ArchiveStoreImpl, WorldContainer> + { + static void store(const ParallelOutputArchive &ar, const WorldContainer &t) + { const long magic = -5881828; // Sitar Indian restaurant in Knoxville (negative to indicate parallel!) - typedef WorldContainer dcT; + typedef WorldContainer dcT; // typedef typename dcT::const_iterator iterator; // unused? typedef typename dcT::pairT pairT; - World* world = ar.get_world(); + World *world = ar.get_world(); Tag tag = world->mpi.unique_tag(); ProcessID me = world->rank(); - if (ar.dofence()) world->gop.fence(); - if (ar.is_io_node()) { - auto& localar = ar.local_archive(); + if (ar.dofence()) + world->gop.fence(); + if (ar.is_io_node()) + { + auto &localar = ar.local_archive(); localar & magic & ar.num_io_clients(); - for (ProcessID p=0; psize(); ++p) { - if (p == me) { + for (ProcessID p = 0; p < world->size(); ++p) + { + if (p == me) + { localar & t; } - else if (ar.io_node(p) == me) { - world->mpi.Send(int(1),p,tag); // Tell client to start sending + else if (ar.io_node(p) == me) + { + world->mpi.Send(int(1), p, tag); // Tell client to start sending archive::MPIInputArchive source(*world, p); long cookie = 0l; unsigned long count = 0ul; - ArchivePrePostImpl::preamble_store(localar); + ArchivePrePostImpl::preamble_store(localar); source & cookie & count; localar & cookie & count; - while (count--) { + while (count--) + { pairT datum; source & datum; localar & datum; } - ArchivePrePostImpl::postamble_store(localar); + ArchivePrePostImpl::postamble_store(localar); } } } - else { + else + { ProcessID p = ar.my_io_node(); int flag; - world->mpi.Recv(flag,p,tag); + world->mpi.Recv(flag, p, tag); MPIOutputArchive dest(*world, p); dest & t; dest.flush(); } - if (ar.dofence()) world->gop.fence(); + if (ar.dofence()) + world->gop.fence(); } }; template - struct ArchiveLoadImpl< ParallelInputArchive, WorldContainer > { + struct ArchiveLoadImpl, WorldContainer> + { /// Read container from parallel archive /// \ingroup worlddc @@ -1856,24 +2048,29 @@ namespace madness { /// can always run a separate job to copy to a different number. /// /// The IO node simply reads all data and inserts entries. - static void load(const ParallelInputArchive& ar, WorldContainer& t) { + static void load(const ParallelInputArchive &ar, WorldContainer &t) + { const long magic = -5881828; // Sitar Indian restaurant in Knoxville (negative to indicate parallel!) // typedef WorldContainer dcT; // unused // typedef typename dcT::iterator iterator; // unused // typedef typename dcT::pairT pairT; // unused - World* world = ar.get_world(); - if (ar.dofence()) world->gop.fence(); - if (ar.is_io_node()) { + World *world = ar.get_world(); + if (ar.dofence()) + world->gop.fence(); + if (ar.is_io_node()) + { long cookie = 0l; int nclient = 0; - auto& localar = ar.local_archive(); + auto &localar = ar.local_archive(); localar & cookie & nclient; MADNESS_CHECK(cookie == magic); - while (nclient--) { + while (nclient--) + { localar & t; } } - if (ar.dofence()) world->gop.fence(); + if (ar.dofence()) + world->gop.fence(); } }; } From 072796c2725878d73acc1ece743979fe6d96ff6b Mon Sep 17 00:00:00 2001 From: fbischoff Date: Tue, 13 Aug 2024 11:06:52 -0400 Subject: [PATCH 45/54] fixing expectation value of using the singles --- src/madness/chem/BSHApply.h | 9 +++-- src/madness/chem/CC2.h | 57 +++++++++++++++++--------------- src/madness/chem/CCPotentials.cc | 14 ++++---- src/madness/chem/CCPotentials.h | 6 ++-- 4 files changed, 48 insertions(+), 38 deletions(-) diff --git a/src/madness/chem/BSHApply.h b/src/madness/chem/BSHApply.h index f2038877db6..f3f5dc727d7 100644 --- a/src/madness/chem/BSHApply.h +++ b/src/madness/chem/BSHApply.h @@ -29,7 +29,7 @@ class BSHApply { double levelshift=0.0; double lo=1.e-6; double bshtol=1.e-5; - bool printme=false; + bool printme=true; bool destroy_Vpsi=false; Function metric; return_value ret_value=residual; // return the new orbitals/functions or the residuals @@ -64,6 +64,7 @@ class BSHApply { std::vector < std::shared_ptr > > ops(psi.size()); for (int i=0; i >( BSHOperatorPtr(world, sqrt(-2.0*eps_in_green(e_i)), lo, bshtol)); ops[i]->destructive()=true; @@ -130,7 +131,7 @@ class BSHApply { const Tensor fock1) const { // check dimensions - bool consistent=(psi.size()==size_t(fock1.dim(0))); + bool consistent=(psi.size()==size_t(fock1.dim(0))); if ((fock1.ndim()==2) and not (psi.size()==size_t(fock1.dim(1)))) consistent=false; if (not consistent) { @@ -150,6 +151,10 @@ class BSHApply { for (int i=0; i bsh_apply(world); -// bsh_apply.ret_value=BSHApply::update; // return the new singles functions, not the residual -// bsh_apply.metric=info.R_square; -// -// // coupling between singles involves the active fock matrix shifted by the excitation energy -// auto nfreeze=info.parameters.freeze(); -// Tensor fock=info.fock(Slice(nfreeze,-1),Slice(nfreeze,-1)); -// for (int i=0; i > > G(singles.size()); for (size_t i = 0; i < G.size(); i++) { const double bsh_eps = info.orbital_energies[i + info.parameters.freeze()] + omega; @@ -309,14 +301,11 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { BSHOperatorPtr3D(world, sqrt(-2.0 * bsh_eps), info.parameters.lo(), info.parameters.thresh_bsh_3D())); } world.gop.fence(); - time_makebsh.info(); -// -// // apply bsh operators + + // apply bsh operators CCTimer time_applyG(world, "Apply G-Operators"); - // auto [GV, energy_update] = bsh_apply(singles.get_vecfunction(), fock, V); vector_real_function_3d GV = apply, double, 3>(world, G, V); -// world.gop.fence(); - // auto GV=res-singles.get_vecfunction(); + world.gop.fence(); time_applyG.info(); // apply Q-Projector to result @@ -513,9 +502,23 @@ class CC2 : public OptimizationTargetInterface, public QCPropertyInterface { for (auto& tmp_pair : vpairs) pairs.insert(tmp_pair.i, tmp_pair.j, tmp_pair); auto ccpair2function = [](const CCPair& a) {return a.function();}; return compute_local_coupling(pairs.convert(pairs,ccpair2function), info); - }; + /// compute the coupling of singles function if orbitals are localized + + /// @return the coupling terms c_i = -\sum_(j\neq i) f_ij |\phi_j> (for whatever phi is) + static std::vector compute_local_coupling(const std::vector& singles, + const Info& info) { + + MADNESS_CHECK_THROW(singles.size()>0,"compute_local_coupling: singles vector is empty"); + World& world=singles.front().world(); + auto active=Slice(info.parameters.freeze(),-1); + Tensor Fact=info.fock(active,active); + for (int i=0; i + \sum_{l\neq j} f_lj |u_il> diff --git a/src/madness/chem/CCPotentials.cc b/src/madness/chem/CCPotentials.cc index 92d5500ba7c..e524b0ed4bb 100644 --- a/src/madness/chem/CCPotentials.cc +++ b/src/madness/chem/CCPotentials.cc @@ -486,10 +486,16 @@ CCPotentials::compute_kinetic_energy(World& world, const vector_real_function_3d return kinetic; } + double CCPotentials::compute_cis_expectation_value(World& world, const CC_vecfunction& x, const vector_real_function_3d& V, const bool print, const Info& info) { + // following eq. (34) of the CIS paper Kottmann et al, PCCP, 17, 31453, (2015) + // doi: https://doi.org/10.1039/C5CP00345H + // the expectation value of the CIS wave function is computed by projecting the + // CIS wave function onto eq. (22) + // the potential V must contain the coupling term when using localized orbitals const vector_real_function_3d xbra = info.R_square*(x.get_vecfunction()); const vector_real_function_3d xket = x.get_vecfunction(); const double kinetic = compute_kinetic_energy(world, xbra, xket); @@ -2879,7 +2885,7 @@ CCPotentials::get_CC2_singles_potential_gs(World& world, const CC_vecfunction& s } madness::vector_real_function_3d -CCPotentials::get_CCS_potential_ex(World& world, CC_vecfunction& x, const bool print, Info& info) { +CCPotentials::get_CCS_potential_ex(World& world, const CC_vecfunction& x, const bool print, Info& info) { if (x.type != RESPONSE) error("get_CCS_response_potential: Wrong type of input singles"); Pairs empty_doubles; @@ -2895,14 +2901,12 @@ CCPotentials::get_CCS_potential_ex(World& world, CC_vecfunction& x, const bool p info.intermediate_potentials.insert(copy(world, potential), x, POT_singles_); vector_real_function_3d result = add(world, fock_residue, potential); truncate(world, result); - const double omega = compute_cis_expectation_value(world, x, result, print, info); - x.omega = omega; return result; } madness::vector_real_function_3d CCPotentials::get_CC2_singles_potential_ex(World& world, const CC_vecfunction& gs_singles, - const Pairs& gs_doubles, CC_vecfunction& ex_singles, + const Pairs& gs_doubles, const CC_vecfunction& ex_singles, const Pairs& response_doubles, Info& info) { MADNESS_ASSERT(gs_singles.type == PARTICLE); @@ -2949,8 +2953,6 @@ CCPotentials::get_CC2_singles_potential_ex(World& world, const CC_vecfunction& g info.intermediate_potentials.insert(copy(world, potential), ex_singles, POT_singles_); vector_real_function_3d result = add(world, fock_residue, potential); truncate(world, result); - const double omega = compute_cis_expectation_value(world, ex_singles, result, true, info); - ex_singles.omega = omega; return result; } diff --git a/src/madness/chem/CCPotentials.h b/src/madness/chem/CCPotentials.h index e2f3ccd6b84..4fa36bcb859 100644 --- a/src/madness/chem/CCPotentials.h +++ b/src/madness/chem/CCPotentials.h @@ -276,7 +276,7 @@ class CCPotentials { static double compute_kinetic_energy(World& world, const vector_real_function_3d& xbra, const vector_real_function_3d& xket); - /// returns \f$ + \f$ + /// compute the expectation value excitation energy using the CIS/CCS/CC2 singles static double compute_cis_expectation_value(World& world, const CC_vecfunction& x, const vector_real_function_3d& V, const bool print, const Info& info); @@ -681,13 +681,13 @@ class CCPotentials { /// the V part is stored in the intermediate_potentials structure /// the expectation value is calculated and updated static vector_real_function_3d - get_CCS_potential_ex(World& world, CC_vecfunction& x, const bool print, Info& info); + get_CCS_potential_ex(World& world, const CC_vecfunction& x, const bool print, Info& info); /// Calculates the CC2 singles potential for the Excited state: result = Fock_residue + V /// the V part is stored in the intermediate_potentials structure static vector_real_function_3d get_CC2_singles_potential_ex(World& world, const CC_vecfunction& gs_singles, - const Pairs& gs_doubles, CC_vecfunction& ex_singles, + const Pairs& gs_doubles, const CC_vecfunction& ex_singles, const Pairs& response_doubles, Info& info); /// Calculates the CC2 singles potential for the Excited state: result = Fock_residue + V From 159cf5a0def8c396d0292636734a4bf2db56b650 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Wed, 14 Aug 2024 14:21:49 -0400 Subject: [PATCH 46/54] LRCC2 working with local orbitals? --- src/madness/chem/BSHApply.h | 2 +- src/madness/chem/CC2.cc | 5 +++-- src/madness/chem/CCStructures.cc | 19 +++++++++++-------- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/madness/chem/BSHApply.h b/src/madness/chem/BSHApply.h index f3f5dc727d7..dfb59f0ba02 100644 --- a/src/madness/chem/BSHApply.h +++ b/src/madness/chem/BSHApply.h @@ -29,7 +29,7 @@ class BSHApply { double levelshift=0.0; double lo=1.e-6; double bshtol=1.e-5; - bool printme=true; + bool printme=false; bool destroy_Vpsi=false; Function metric; return_value ret_value=residual; // return the new orbitals/functions or the residuals diff --git a/src/madness/chem/CC2.cc b/src/madness/chem/CC2.cc index 7ea46818053..a023e8696c0 100644 --- a/src/madness/chem/CC2.cc +++ b/src/madness/chem/CC2.cc @@ -759,7 +759,8 @@ CC2::solve_cc2(CC_vecfunction& singles, Pairs& doubles, Info& info) cons std::cout << std::fixed << std::setprecision(10) << "Current Correlation Energy = " << omega << "\n"; if (parameters.no_compute_cc2()) { - if (world.rank()==0) print("found no_compute_cc2 key -- returning without further computation"); + if (world.rank()==0) print("found no_compute_cc2 key -- recompute singles for the singles-potentials"); + iterate_cc2_singles(world, singles, doubles, info); return omega; } @@ -1099,7 +1100,7 @@ CC2::initialize_pairs(Pairs& pairs, const CCState ftype, const CalcType } else if (ftype == EXCITED_STATE) { name = std::to_string(int(excitation)) + "_" + name; - real_function_6d utmp = real_factory_6d(world); + real_function_6d utmp;// = real_factory_6d(world); const bool found = CCOPS.load_function(utmp, name); if (found) restarted = true; real_function_6d const_part; diff --git a/src/madness/chem/CCStructures.cc b/src/madness/chem/CCStructures.cc index 85dcc049cc5..ffc38ebbd51 100644 --- a/src/madness/chem/CCStructures.cc +++ b/src/madness/chem/CCStructures.cc @@ -124,17 +124,20 @@ CCIntermediatePotentials::operator()(const CC_vecfunction& f, const PotentialTyp madness::real_function_3d CCIntermediatePotentials::operator()(const CCFunction& f, const PotentialType& type) const { output("Getting " + assign_name(type) + " for " + f.name()); - if (type == POT_singles_ and (f.type == PARTICLE or f.type == MIXED)) return current_singles_potential_gs_[f.i - parameters.freeze()]; - else if (type == POT_singles_ and f.type == RESPONSE) return current_singles_potential_ex_[f.i - parameters.freeze()]; - else if (type == POT_s2b_ and f.type == PARTICLE) return current_s2b_potential_gs_[f.i - parameters.freeze()]; - else if (type == POT_s2b_ and f.type == RESPONSE) return current_s2b_potential_ex_[f.i - parameters.freeze()]; - else if (type == POT_s2c_ and f.type == PARTICLE) return current_s2c_potential_gs_[f.i - parameters.freeze()]; - else if (type == POT_s2c_ and f.type == RESPONSE) return current_s2c_potential_ex_[f.i - parameters.freeze()]; + std::vector result; + if (type == POT_singles_ and (f.type == PARTICLE or f.type == MIXED)) result= current_singles_potential_gs_; + else if (type == POT_singles_ and f.type == RESPONSE) result= current_singles_potential_ex_; + else if (type == POT_s2b_ and f.type == PARTICLE) result= current_s2b_potential_gs_; + else if (type == POT_s2b_ and f.type == RESPONSE) result= current_s2b_potential_ex_; + else if (type == POT_s2c_ and f.type == PARTICLE) result= current_s2c_potential_gs_; + else if (type == POT_s2c_ and f.type == RESPONSE) result= current_s2c_potential_ex_; else if (f.type == HOLE) output(assign_name(type) + " is zero for HOLE states"); else MADNESS_EXCEPTION("Potential was not supposed to be stored", 1); - - return real_function_3d(); + std::string errmsg="CCIntermediatePotential was not computed/stored "+assign_name(type) + " " +assign_name(f.type); + errmsg+="\n --> you might need to iterate the corresponding singles"; + MADNESS_CHECK_THROW(result.size()>(f.i-parameters.freeze()),errmsg.c_str()); + return result[f.i-parameters.freeze()]; } void From 4f0df9b68b43e4a9683054a0864aa9efe44163c7 Mon Sep 17 00:00:00 2001 From: "Robert J. Harrison" Date: Thu, 15 Aug 2024 10:24:01 -0400 Subject: [PATCH 47/54] merged gnuplot from bspline branch --- src/madness/misc/CMakeLists.txt | 8 +- src/madness/misc/gnuplot.h | 198 +++++++++++++++++++++++++++++++ src/madness/misc/test_gnuplot.cc | 7 ++ 3 files changed, 209 insertions(+), 4 deletions(-) create mode 100644 src/madness/misc/gnuplot.h create mode 100644 src/madness/misc/test_gnuplot.cc diff --git a/src/madness/misc/CMakeLists.txt b/src/madness/misc/CMakeLists.txt index 790a0d1e09a..f825dcfa6a3 100644 --- a/src/madness/misc/CMakeLists.txt +++ b/src/madness/misc/CMakeLists.txt @@ -1,8 +1,8 @@ # src/madness/misc -set(MADMISC_HEADERS misc.h ran.h phandler.h interpolation_1d.h cfft.h info.h) +set(MADMISC_HEADERS misc.h ran.h phandler.h interpolation_1d.h cfft.h info.h gnuplot.h) set(MADMISC_SOURCES - checksum_file.cc position_stream.cc gprofexit.cc ran.cc cfft.cc info.cc unique_filename.cc) + checksum_file.cc position_stream.cc gprofexit.cc ran.cc cfft.cc info.cc) # retrieve git metadata include(GetGitMetadata) vgkit_cmake_git_metadata() @@ -20,8 +20,8 @@ add_mad_library(misc MADMISC_SOURCES MADMISC_HEADERS "world" "madness/misc/") if(BUILD_TESTING) # The list of unit test source files - set(MISC_TEST_SOURCES interp3.cc) + set(MISC_TEST_SOURCES interp3.cc test_gnuplot.cc) add_unittests(misc "${MISC_TEST_SOURCES}" "MADmisc;MADgtest" "unittests;short") -endif() \ No newline at end of file +endif() diff --git a/src/madness/misc/gnuplot.h b/src/madness/misc/gnuplot.h new file mode 100644 index 00000000000..465d298cdb7 --- /dev/null +++ b/src/madness/misc/gnuplot.h @@ -0,0 +1,198 @@ +#ifndef MADNESS_GNUPLOT_H__INCUDED +#define MADNESS_GNUPLOT_H__INCUDED + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +namespace madness { + class Gnuplot { + FILE *f; // pipe connection to gnuplot process + pid_t pid; // pid of gnuplot process + FILE *ftee; // filestream for data tee'd from gnuplot process + + // base case for unpacking datablock value + template + void dbvalue(size_t i, const T& t) { + char buf[256]; + snprintf(buf,sizeof(buf),"%16.8e",double(t[i])); + (*this)(buf); // newline + } + + // recursion case for unpacking datablock value + template + void dbvalue(size_t i, const T& t, Ts... values) { + char buf[256]; + snprintf(buf,sizeof(buf),"%16.8e ",double(t[i])); // space + (*this)(buf,false); + dbvalue(i,values...); + } + + // base case for unpacking plot value + template + void doplot(const char* name, const T& value0) { + char buf[256]; + snprintf(buf, sizeof(buf), "%s using 1:%d", name, n); + (*this)(buf); + } + + // recursion case for unpacking plot value + template + void doplot(const char* name, const T& value0, Ts... values) { + char buf[256]; + snprintf(buf, sizeof(buf), "%s using 1:%d, ", name, n); + (*this)(buf,false); + + doplot(name, values...); + } + + public: + Gnuplot& operator=(Gnuplot&&) = delete; + Gnuplot& operator=(const Gnuplot&) = delete; + Gnuplot(const Gnuplot&) = delete; + Gnuplot(const std::string& cmd = "", const std::string& teefile = "") : f(0), ftee(0) { + int p[2]; + if (pipe (p)) { + throw "Pipe failed."; + } + pid = fork (); + if (pid == 0) { // Child process. + close(p[1]); + dup2(p[0],STDIN_FILENO); + close(p[0]); + if (execlp ("gnuplot", "gnuplot", "-persist", NULL) == -1) { + //if (execlp ("cat", "cat", "-", NULL) == -1) { + fprintf(stderr,"Gnuplot: execlp failed for gnuplot ... plotting disabled\n"); + exit(1); + } + } + else if (pid < (pid_t) 0) { // Failure + throw "Fork failed."; + } + else { // Parent process + close (p[0]); + f = fdopen (p[1], "w"); + } + if (teefile.size() > 0) { + ftee = fopen(teefile.c_str(),"w"); + if (!ftee) { + fprintf(stderr,"Gnuplot: fopen failed for tee file %s ... tee of plotting disabled\n",teefile.c_str()); + } + } + + if (cmd.size() > 0) (*this)(cmd); + } + + // outputs string to gnuplot process + void operator()(const char* cmd, bool EOL=true) { + + if (f) { + if (!fprintf(f,"%s",cmd)) { + fprintf(stderr,"Gnuplot: failed writing to gnuplot pipe ... plotting disabled\n"); + fclose(f); + f = NULL; + } + } + if (ftee) fprintf(ftee,"%s",cmd); + + const int n = strlen(cmd); + if (EOL && ((n==0) || (cmd[n-1] != '\n') ) ) { + if (f) { + if (!fprintf(f,"\n")) { + fprintf(stderr,"Gnuplot: failed writing newline to gnuplot pipe ... plotting disabled\n"); + fclose(f); + f = NULL; + } + } + if (ftee) fprintf(ftee,"\n"); + } + if (f) fflush(f); + } + + // outputs string to gnuplot process + void operator()(const std::string& cmd, bool EOL=true) { + (*this)(cmd.c_str(), EOL); + } + + // Define a gnuplot data block with given name assuming 1-d indexing via [] with explicit size + template + void db(const std::string& name, size_t size, const T& x, Ts... values) { + (*this)("$",false); + (*this)(name,false); + (*this)(" << EOD"); + for (size_t i = 0; i + void db(const std::string& name, const T& x, Ts... values) { + db(name,(size_t) x.size(),x,values...); // have to force x.size() to be size_t since Tensor::size() returns long + } + + // Plots data in 2 or more vectors by generating the following gnuplot commands: + // $data << EOD + // + // EOD + // plot $data using 1:2, $data using 1:3, ... + template + void plot(const T& x, Ts... values) { + db("data", x, values...); + (*this)("plot ",false); + doplot<2,Ts...>("$data", values...); // note we peeled off the x values + } + + ~Gnuplot() { + if (f) { + fclose(f); + waitpid(pid,0,0); + } + if (ftee) fclose(ftee); + } + + static void test() { + std::vector x = {1.0,2.0,3.0}; + std::vector y = {-1.0,-2.0,3.0}; + std::vector z = {10.0,11.0,12.0}; + { + Gnuplot g("set style data lp; set grid"); + g.plot(x,y,z); + } + { + Gnuplot g; + //g("set term png"); + //g("set output \"test.png\""); + g.db("xyz",x,y,z); + g("plot $xyz using 1:2 with linespoints"); + } + { + // use x11 to work around bug (https://sourceforge.net/p/gnuplot/bugs/2634/) ... wxt temporarily needs GDK_BACKEND=x11 + Gnuplot g("set term x11; set xrange [-10:10]; set yrange [0:1]; set grid; set style data l", "test3.gnuplot"); + size_t npts = 100; + std::vector x(npts), y(npts); + for (size_t i = 0; i + +int main (void) +{ + madness::Gnuplot::test(); + return 0; +} From 21f1e5aeb6cefc513361f50e6a41700f4165442e Mon Sep 17 00:00:00 2001 From: "Robert J. Harrison" Date: Thu, 15 Aug 2024 10:44:50 -0400 Subject: [PATCH 48/54] beginning of test directory for periodic stuff --- src/examples/periodic/test.cc | 403 ++++++++++++++++++++++++++++++++++ 1 file changed, 403 insertions(+) create mode 100644 src/examples/periodic/test.cc diff --git a/src/examples/periodic/test.cc b/src/examples/periodic/test.cc new file mode 100644 index 00000000000..88854f1baf2 --- /dev/null +++ b/src/examples/periodic/test.cc @@ -0,0 +1,403 @@ +#include +#include +#include +#include +#include + +#include +#include + +#include + +/***************** + +Use FFT to comupute the electrostatic potential due to some test +charge densities. Note that FFT produces a result with + + a) mean value that is zero because it projects out the constant (k=0) mode. + + b) an opposing electric field to cancel that arising from the periodic + sum of the dipole moment potential + +Test cases --- select by number +1) Gaussian spheropole +2) Gaussian dipole +3) Gaussian quadrupole +4) Cosine function + +Compile with "g++ -O3 -Wall test.cc -I.. -lfftw3 -llapacke" + + *****************/ + +const int test_case = 1; // 1, 2, 3, 4 + +const double pi = 3.14159265358979323846; +const double L = 1.0; // must be integer for cosine test to work, and > 1 for gaussian tests to work +const double xshift = 0.0; // shift from origin of charge distributions to test the periodicity in [-0.5*L,0.5*L] +const double yshift = 0.0; +const double zshift = 0.0; + +// Will be assigned by main program based on test_case selection +double (*f)(double, double, double) = nullptr; +double (*exact)(double, double, double) = nullptr; + +// Evaluate erf(a*r)/r with correct limit at origin +double erfaroverr(double a, double r) { + if (a*r*r/3.0 < 1e-8) { + return 2*a/std::sqrt(pi); + } + else { + return std::erf(a*r)/r; + } +} + +// Solve M[m,n] c[n] = f[m] in least squares sense +// M is the fitting matrix corresponding to m observations and n parameters +// f is the vector of m observations +// return the vector c of n fitted parameters +std::vector solve(size_t m, size_t n, const std::vector& M, const std::vector& f) { + std::vector c = f; + std::vector M1 = M; + lapack_int mm = m, nn = n, nrhs = 1, lda = n, ldb = 1; + LAPACKE_dgels(LAPACK_ROW_MAJOR,'N',mm,nn,nrhs,M1.data(),lda,c.data(),ldb); + + return std::vector(c.data(), c.data()+n); +} + +// print the matrix M[m,n] in row-major order +template +void print(size_t m, size_t n, const std::vector& M) { + for (size_t i=0; i fit(size_t m, size_t n, const std::vector N, const std::vector& f) { + //print(1,n,N); + //print(m,1,f); + + std::vector M; + for (size_t i=0; i tabulate(double(*f)(double, double, double), std::vector x, std::vector y, std::vector z) { + const size_t nx = x.size(); + const size_t ny = y.size(); + const size_t nz = z.size(); + std::vector F(nx * ny * nz); + for (size_t i = 0; i < nx; i++) { + for (size_t j = 0; j < ny; j++) { + for (size_t k = 0; k < nz; k++) { + F[i*ny*nz + j*nz + k] = f(x[i], y[j], z[k]); + } + } + } + return F; +} + +// Periodic sum of functions +double periodic_sum(double x, double y, double z, double(*f)(double, double, double), const int N = 50) { + // N number of lattice points summed in each direction + double sum = 0.0; + for (int X=-N; X<=N; X++) { + for (int Y=-N; Y<=N; Y++) { + for (int Z=-N; Z<=N; Z++) { + sum += f(x+X*L,y+Y*L,z+Z*L); + } + } + } + return sum; +} + +// Periodic sum of functions returning vector of values of partial sums in order of increasing cube size +std::vector periodic_sum_partial(double x, double y, double z, double(*f)(double, double, double), const int N) { + std::vector sums; + double sum = f(x,y,z); + sums.push_back(sum); + int count = 1; + // Dumb loop structure since attempt to be smart failed! + for (int n = 1; n <= N; n++) { + for (int X=-n; X<=n; X++) { + for (int Y=-n; Y<=n; Y++) { + for (int Z=-n; Z<=n; Z++) { + if (std::abs(X) == n || std::abs(Y) == n || std::abs(Z) == n) { + sum += f(x+X*L,y+Y*L,z+Z*L); + count++; + } + } + } + } + sums.push_back(sum); + } + return sums; +} + +// Periodic sum of functions accelerated by fitting t to a polynomial in 1/N +double periodic_sum_accelerated(double x, double y, double z, double(*f)(double, double, double), const size_t N=9, const size_t p=7) { + std::vector sums = periodic_sum_partial(x,y,z,f,N); + // Extract the last p terms of the series in v + std::vector v(&sums[N-p], &sums[N]); + std::vector n(p); + for (size_t j=0; j c = fit(p, p, n, v); + return c[0]; +} + +double distancesq(double x, double y, double z, double x0, double y0, double z0) { + double dx = x - x0; + double dy = y - y0; + double dz = z - z0; + return dx*dx + dy*dy + dz*dz; +} + +// Gaussian spheropole test function +const double a = 100.0; +const double b = 200.0; +double f_spheropole(double x, double y, double z) { + const double afac = std::pow(a/pi, 1.5); + const double bfac = std::pow(b/pi, 1.5); + const double rsq = distancesq(x,y,z,xshift,yshift,zshift); + return afac*exp(-a*rsq) - bfac*exp(-b*rsq); +} + +// No need for periodic summation since the potential is zero exterior to the charge density +double exact_spheropole(double x, double y, double z) { + const double mean = pi*(1/b - 1/a)/(L*L*L); // the mean of the potential over the domain + const double rsq = distancesq(x,y,z,xshift,yshift,zshift); + const double r = std::sqrt(rsq); + //return std::erf(std::sqrt(a)*r)/r - std::erf(std::sqrt(b)*r)/r - mean; + return erfaroverr(std::sqrt(a),r) - erfaroverr(std::sqrt(b),r) - mean; +}; + +// Gaussian dipole test function +const double offset = 0.1; +double f_dipole(double x, double y, double z) { + const double bfac = std::pow(b/pi, 1.5); + const double r1sq = distancesq(x,y,z,xshift,yshift,zshift-offset); + const double r2sq = distancesq(x,y,z,xshift,yshift,zshift+offset); + return bfac*(std::exp(-b*r1sq) - std::exp(-b*r2sq)); +} + +// Potential due to single Gaussian dipole +double exact_dipoleX(double x, double y, double z) { + const double r1sq = distancesq(x,y,z,xshift,yshift,zshift-offset); + const double r2sq = distancesq(x,y,z,xshift,yshift,zshift+offset); + const double r1 = std::sqrt(r1sq); + const double r2 = std::sqrt(r2sq); + //return std::erf(std::sqrt(b)*r1)/r1 - std::erf(std::sqrt(b)*r2)/r2; + double sb = std::sqrt(b); + return erfaroverr(sb,r1) - erfaroverr(sb,r2); +}; + +// Potential due to opposing electric field generated by FT to satisty the periodic boundary conditions and continuity +double opposing_field_potential(double x, double y, double z) { + // center of charge is at (xshift,yshift,zshift) + const double mu = 2*offset; + return mu*4*pi/(3*L*L*L) * (z-zshift); +} + +// Periodic sum of dipole potentials +double exact_dipole(double x, double y, double z) { + // const double mean = 0.0; // the mean of the potential over the domain(zero due to dipole symmetry) + return periodic_sum_accelerated(x, y, z, exact_dipoleX) + opposing_field_potential(x,y,z); +} + +// Gaussian quadrupole test function in yz plane +double f_quadrupole(double x, double y, double z) { + const double bfac = std::pow(b/pi, 1.5); + const double r1sq = distancesq(x, y, z, xshift, yshift, zshift-offset); + const double r2sq = distancesq(x, y, z, xshift, yshift, zshift+offset); + const double r3sq = distancesq(x, y, z, xshift, yshift-offset, zshift); + const double r4sq = distancesq(x, y, z, xshift, yshift+offset, zshift); + return bfac*(std::exp(-b*r1sq) + std::exp(-b*r2sq) - std::exp(-b*r3sq) - std::exp(-b*r4sq) ); +} + +// Potential due to single Gaussian quadrupole +double exact_quadrupoleX(double x, double y, double z) { + const double r1sq = distancesq(x, y, z, xshift, yshift, zshift-offset); + const double r2sq = distancesq(x, y, z, xshift, yshift, zshift+offset); + const double r3sq = distancesq(x, y, z, xshift, yshift-offset, zshift); + const double r4sq = distancesq(x, y, z, xshift, yshift+offset, zshift); + const double r1 = std::sqrt(r1sq); + const double r2 = std::sqrt(r2sq); + const double r3 = std::sqrt(r3sq); + const double r4 = std::sqrt(r4sq); + //return std::erf(std::sqrt(b)*r1)/r1 + std::erf(std::sqrt(b)*r2)/r2 - std::erf(std::sqrt(b)*r3)/r3 - std::erf(std::sqrt(b)*r4)/r4; + double sb = std::sqrt(b); + return erfaroverr(sb,r1) + erfaroverr(sb,r2) - erfaroverr(sb,r3) - erfaroverr(sb,r4); +}; + +// Periodic sum of quadrupole potentials +double exact_quadrupole(double x, double y, double z) { + // const double mean = 0.0; // the mean of the potential over the domain(zero due to dipole symmetry) + //return periodic_sum(x, y, z, exact_quadrupoleX); + return periodic_sum_accelerated(x, y, z, exact_quadrupoleX); +} + + +// Cosine test function +const double wx = 1; +const double wy = 2; +const double wz = 3; +double f_cosine(double x, double y, double z) { + return std::cos(wx*2*pi*(x-xshift)/L)*std::cos(wy*2*pi*(y-yshift)/L)*std::cos(wz*2*pi*(z-zshift)/L); +} + +double exact_cosine(double x, double y, double z) { + return f_cosine(x,y,z) / (pi*(wx*wx + wy*wy + wz*wz)/(L*L)); +} + +// Return a vector with n equally spaced values between a and b, optionally including the right endpoint +std::vector linspace(double a, double b, size_t n, bool include_right_endpoint = true) { + double h = (b - a) / (include_right_endpoint ? (n - 1) : n); + std::vector v(n); + for (size_t i = 0; i < n; i++) { + v[i] = a + i*h; + } + return v; +} + +int main() { + std::cout.precision(15); + + if (test_case == 1) { + f = f_spheropole; + exact = exact_spheropole; + } else if (test_case == 2) { + f = f_dipole; + exact = exact_dipole; + } else if (test_case == 3) { + f = f_quadrupole; + exact = exact_quadrupole; + } else if (test_case == 4) { + f = f_cosine; + exact = exact_cosine; + } else { + std::cerr << "Invalid test case number" << std::endl; + return 1; + } + + const size_t n = 50*L; // number of lattice points in each direction + const size_t nh = n/2+1; // for real to complex transform last dimension + const size_t mid = n/2; // for mapping hermitian symmetry in transform (and testing and plotting) + + const double lo = -0.5*L; + const double hi = 0.5*L; + const double h = (hi - lo) / (n - 1); + std::vector x = linspace(lo,hi,n,false); // exclude right endpoint + std::vector y = x; // Presently assuming cubic domain with equal spacing in x, y, and z + std::vector z = x; + + std::vector F = tabulate(f, x, y, z); + { + madness::Gnuplot g("set style data l"); + // Extract the middle z column? + std::vector col(&F[mid*n*n + mid*n], &F[mid*n*n + mid*n + n]); + g.plot(z, col); + } + + // sum the values in F to get the total charge + double norm = std::reduce(F.begin(), F.end(), 0.0)*h*h*h; + std::cout << "norm = " << norm << std::endl; + + // Perform a 3D Fourier transform of F and store the result in G + std::vector G(n*n*nh); + { + fftw_plan plan = fftw_plan_dft_r2c_3d(n, n, n, F.data() , G.data(), FFTW_ESTIMATE); + fftw_execute(plan); + fftw_destroy_plan(plan); + } + + // Navigate the way FFTW stores the Hermitian symmetric data + auto fudge = [=](size_t j) {return j 1.0e-20) { + double kfac = kscale/ksq; + size_t j = jx*n*nh + jy*nh + jz; + //if (std::abs(G[j][0]) > 1e-6) { + //std::cout << jx << " (" << fudge(jx) << ") " << jy << " (" << fudge(jy) << ") " << jz << " " << ksq << " " << G[j][0] << " " << G[j][1] << std::endl; + //} + G[j][0] *= kfac; + G[j][1] *= kfac; + } + } + } + } + + // Do the reverse transform into FF + std::vector FF(n*n*n); + { + fftw_plan plan = fftw_plan_dft_c2r_3d(n, n, n, G.data() , FF.data(), FFTW_ESTIMATE); + fftw_execute(plan); + fftw_destroy_plan(plan); + const double scale = 1.0/(n*n*n); // FFTW transforms are not normalized + for (double& u : FF) u *= scale; + } + + // Check the mean potential --- expected to be zero + double FFmean = std::reduce(FF.begin(), FF.end(), 0.0)*h*h*h / (L*L*L); + std::cout << "FFmean = " << FFmean << std::endl; + + size_t j = mid; //mid+3; // test point (avoid origin) -- don't need to avoid origin now we are treating erf(0)/0 correctly + { + madness::Gnuplot g("set style data l"); + std::vector col(&FF[j*n*n + j*n], &FF[j*n*n + j*n + n]); + std::vector col2(n); + std::vector col3(n); + for (size_t i = 0; i < n; i++) { + double v = exact(x[j],y[j],z[i]); + std::cout << i << " " << z[i] << " " << col[i] << " " << v << " " << col[i]-v << std::endl; + col2[i] = v; + col3[i] = col[i] - v; + } + + //g.plot(z, col, col2); + g.plot(z, col3); + + } + + // std::vector sums = periodic_sum_partial(x[j],y[j],z[0],exact_quadrupoleX,50); + // //std::vector sums = periodic_sum_partial(x[j],y[j],z[0],exact_dipoleX,50); + // for (size_t i = 0; i < sums.size(); i++) { + // std::cout << i << " " << sums[i] << " " << exact(x[j],y[j],z[0]) << std::endl; + // } + // std::cout << exact(x[j],y[j],z[0]) << " " << FF[j*n*n + j*n + 0] << " !! " << periodic_sum_accelerated(x[j],y[j],z[0],exact_quadrupoleX) << std::endl; + + // size_t p = 7; // no. of terms in the polynomial fit --- 7 is best for quadrupole + // for (size_t i=p+1; i f(&sums[i], &sums[i+p]); + // std::vector N(p); + // for (size_t j=0; j c = fit(p, p, N, f); + // std::cout << i << " " << c[0] << " " << sums[i]-FF[j*n*n + j*n + 0] << " " << c[0]-FF[j*n*n + j*n + 0] << std::endl; + // } + + return 0; +} From 6af7837c1727969dea5c737f3f481cdaa4315ae5 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Thu, 15 Aug 2024 16:14:23 -0400 Subject: [PATCH 49/54] fix --- src/madness/chem/CC2.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/madness/chem/CC2.cc b/src/madness/chem/CC2.cc index a023e8696c0..20c28e3917a 100644 --- a/src/madness/chem/CC2.cc +++ b/src/madness/chem/CC2.cc @@ -1100,7 +1100,7 @@ CC2::initialize_pairs(Pairs& pairs, const CCState ftype, const CalcType } else if (ftype == EXCITED_STATE) { name = std::to_string(int(excitation)) + "_" + name; - real_function_6d utmp;// = real_factory_6d(world); + real_function_6d utmp = real_factory_6d(world); const bool found = CCOPS.load_function(utmp, name); if (found) restarted = true; real_function_6d const_part; From f3907732bcf4c324933eab307d7224de5a44ca44 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Fri, 16 Aug 2024 10:23:24 -0400 Subject: [PATCH 50/54] fix merging master --- src/madness/world/cloud.h | 1 + src/madness/world/worlddc.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/madness/world/cloud.h b/src/madness/world/cloud.h index 43508ca4773..df0017606ad 100644 --- a/src/madness/world/cloud.h +++ b/src/madness/world/cloud.h @@ -374,6 +374,7 @@ class Cloud { mutable std::atomic reading_time=0l; // in ms mutable std::atomic writing_time=0l; // in ms + mutable std::atomic writing_time1=0l; // in ms mutable std::atomic replication_time=0l; // in ms mutable std::atomic cache_reads=0l; mutable std::atomic cache_stores=0l; diff --git a/src/madness/world/worlddc.h b/src/madness/world/worlddc.h index 671e2964071..c6ead97b07e 100644 --- a/src/madness/world/worlddc.h +++ b/src/madness/world/worlddc.h @@ -1628,7 +1628,7 @@ namespace madness { using const_iterator = typename dcT::const_iterator; // const size_t default_size = 100*1024*1024; - const size_t default_size = 8ul<<30; + // const size_t default_size = 8ul<<30; World* world = ar.get_world(); world->gop.fence(); From e74d0005724edc55cae8a9a8e6a5af79d7c2f9c9 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Fri, 16 Aug 2024 10:50:47 -0400 Subject: [PATCH 51/54] fix merging master --- src/madness/misc/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/madness/misc/CMakeLists.txt b/src/madness/misc/CMakeLists.txt index f825dcfa6a3..ff5f0a7219b 100644 --- a/src/madness/misc/CMakeLists.txt +++ b/src/madness/misc/CMakeLists.txt @@ -2,7 +2,7 @@ set(MADMISC_HEADERS misc.h ran.h phandler.h interpolation_1d.h cfft.h info.h gnuplot.h) set(MADMISC_SOURCES - checksum_file.cc position_stream.cc gprofexit.cc ran.cc cfft.cc info.cc) + checksum_file.cc position_stream.cc gprofexit.cc ran.cc cfft.cc info.cc unique_filename.cc) # retrieve git metadata include(GetGitMetadata) vgkit_cmake_git_metadata() From 917acf237e93708141dc1fd293ba88a3f7e710cc Mon Sep 17 00:00:00 2001 From: fbischoff Date: Fri, 16 Aug 2024 13:39:15 -0400 Subject: [PATCH 52/54] LRCC2 seems to work with water, but hangs in the singles equations -> need to run them in macrotasks to reduce communication --- src/madness/chem/CC2.cc | 10 ++++++++-- src/madness/chem/CCPotentials.h | 4 +++- src/madness/world/cloud.h | 19 +++++++++++++------ src/madness/world/worlddc.h | 20 ++++++++++---------- 4 files changed, 34 insertions(+), 19 deletions(-) diff --git a/src/madness/chem/CC2.cc b/src/madness/chem/CC2.cc index 20c28e3917a..97d1ee2e1cd 100644 --- a/src/madness/chem/CC2.cc +++ b/src/madness/chem/CC2.cc @@ -701,12 +701,18 @@ CC2::iterate_lrcc2_pairs(World& world, const CC_vecfunction& cc2_s, // if no function has been computed so far use the constant part (first iteration) for (auto& pair : pair_vec) if (not pair.function().is_initialized()) pair.update_u(pair.constant_part); + for (const auto& p : pair_vec) p.constant_part.print_size("constant_part before iter"); for (const auto& p : pair_vec) p.function().print_size("u before iter"); // compute the coupling between the pair functions if (world.rank()==0) print("computing local coupling in the universe"); Pairs coupling=compute_local_coupling(pair_vec, info); auto coupling_vec=Pairs::pairs2vector(coupling,triangular_map); + reconstruct(world,coupling_vec); + for (auto& p : pair_vec) { + p.constant_part.reconstruct(); + p.function().reconstruct(); + } if (info.parameters.debug()) print_size(world, coupling_vec, "couplingvector"); @@ -1099,7 +1105,7 @@ CC2::initialize_pairs(Pairs& pairs, const CCState ftype, const CalcType pairs.insert(i, j, tmp); } else if (ftype == EXCITED_STATE) { - name = std::to_string(int(excitation)) + "_" + name; + // name = std::to_string(int(excitation)) + "_" + name; real_function_6d utmp = real_factory_6d(world); const bool found = CCOPS.load_function(utmp, name); if (found) restarted = true; @@ -1116,7 +1122,7 @@ CC2::initialize_pairs(Pairs& pairs, const CCState ftype, const CalcType tmp.constant_part = const_part; pairs.insert(i, j, tmp); - CCPotentials::compute_excited_pair_energy(world, pairs(i, j), x, info); + // CCPotentials::compute_excited_pair_energy(world, pairs(i, j), x, info); } else error("Unknown pairtype"); } } diff --git a/src/madness/chem/CCPotentials.h b/src/madness/chem/CCPotentials.h index 4fa36bcb859..5abf3043af1 100644 --- a/src/madness/chem/CCPotentials.h +++ b/src/madness/chem/CCPotentials.h @@ -79,8 +79,10 @@ class CCPotentials { f.truncate(); f.print_size(name); return true; + } else { + if (world.rank()==0) print("could not find function",name); } - else return false; + return false; } /// Plotting (convenience) diff --git a/src/madness/world/cloud.h b/src/madness/world/cloud.h index df0017606ad..38f58a7302c 100644 --- a/src/madness/world/cloud.h +++ b/src/madness/world/cloud.h @@ -190,12 +190,17 @@ class Cloud { void print_size(World& universe) { std::size_t memsize=0; - for (auto& item : container) memsize+=item.second.size(); + std::size_t max_record_size=0; + for (auto& item : container) { + memsize+=item.second.size(); + max_record_size=std::max(max_record_size,item.second.size()); + } std::size_t global_memsize=memsize; std::size_t max_memsize=memsize; std::size_t min_memsize=memsize; universe.gop.sum(global_memsize); universe.gop.max(max_memsize); + universe.gop.max(max_record_size); universe.gop.min(min_memsize); auto local_size=container.size(); @@ -207,13 +212,15 @@ class Cloud { print("Cloud memory:"); print(" replicated:",is_replicated); print("size of cloud (total)"); - print(" number of records:",global_size); - print(" memory in GBytes: ",global_memsize*byte2gbyte); + print(" number of records: ",global_size); + print(" memory in GBytes: ",global_memsize*byte2gbyte); print("size of cloud (average per node)"); - print(" number of records:",double(global_size)/universe.size()); - print(" memory in GBytes: ",global_memsize*byte2gbyte/universe.size()); + print(" number of records: ",double(global_size)/universe.size()); + print(" memory in GBytes: ",global_memsize*byte2gbyte/universe.size()); print("min/max of node"); - print(" memory in GBytes: ",min_memsize*byte2gbyte,max_memsize*byte2gbyte); + print(" memory in GBytes: ",min_memsize*byte2gbyte,max_memsize*byte2gbyte); + print(" max record size in GBytes:",max_record_size*byte2gbyte); + } } diff --git a/src/madness/world/worlddc.h b/src/madness/world/worlddc.h index 88a61dc3f43..4cf178cafda 100644 --- a/src/madness/world/worlddc.h +++ b/src/madness/world/worlddc.h @@ -1867,8 +1867,8 @@ namespace madness } world->taskq.fence(); // just need LOCAL fence wall1 = wall_time(); - if (world->rank() == 0) - printf("time in op_inspector: %8.4fs\n", wall1 - wall0); + // if (world->rank() == 0) + // printf("time in op_inspector: %8.4fs\n", wall1 - wall0); wall0 = wall1; // total size over all threads @@ -1891,8 +1891,8 @@ namespace madness world->taskq.fence(); // just need LOCAL fence wall1 = wall_time(); - if (world->rank() == 0) - printf("time in op_executor: %8.4fs\n", wall1 - wall0); + // if (world->rank() == 0) + // printf("time in op_executor: %8.4fs\n", wall1 - wall0); wall0 = wall1; } // VERify that the serialization worked!! @@ -1919,8 +1919,8 @@ namespace madness for (int i = 1; i < world->size(); ++i) offsets[i] = offsets[i - 1] + sizes[i - 1]; size_t total_size = offsets.back() + sizes.back(); - if (world->rank() == 0) - print("total_size", total_size); + // if (world->rank() == 0) + // print("total_size", total_size); // print("time 4",wall_time()); // gather the vector of data v from each process to process 0 @@ -1932,8 +1932,8 @@ namespace madness MPI_Gatherv(buf, local_size, MPI_BYTE, all_data, sizes.data(), offsets.data(), MPI_BYTE, 0, world->mpi.comm().Get_mpi_comm()); wall1 = wall_time(); - if (world->rank() == 0) - printf("time in gather+gatherv: %8.4fs\n", wall1 - wall0); + // if (world->rank() == 0) + // printf("time in gather+gatherv: %8.4fs\n", wall1 - wall0); wall0 = wall1; delete[] buf; @@ -1949,8 +1949,8 @@ namespace madness localar.store(all_data, total_size); ArchivePrePostImpl::postamble_store(localar); wall1 = wall_time(); - if (world->rank() == 0) - printf("time in final copy on node 0: %8.4fs\n", wall1 - wall0); + // if (world->rank() == 0) + // printf("time in final copy on node 0: %8.4fs\n", wall1 - wall0); delete[] all_data; } From e69f63ad1f71cfce95fe9b67bdb0aa644bcca97a Mon Sep 17 00:00:00 2001 From: fbischoff Date: Mon, 19 Aug 2024 13:31:14 -0400 Subject: [PATCH 53/54] fixed failing tests --- src/madness/mra/QCCalculationParametersBase.h | 3 ++- src/madness/world/cloud.h | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/madness/mra/QCCalculationParametersBase.h b/src/madness/mra/QCCalculationParametersBase.h index 9d6d7fbb951..b563911bd89 100644 --- a/src/madness/mra/QCCalculationParametersBase.h +++ b/src/madness/mra/QCCalculationParametersBase.h @@ -388,7 +388,7 @@ class QCCalculationParametersBase { std::transform(key_lower.begin(), key_lower.end(), key_lower.begin(), ::tolower); std::transform(svalue.begin(), svalue.end(), svalue.begin(), ::tolower); std::vector av_lower_vec; - for (auto av : allowed_values) { + for (const T& av : allowed_values) { std::string av_lower=tostring(av); std::transform(av_lower.begin(), av_lower.end(), av_lower.begin(), ::tolower); av_lower_vec.push_back(av_lower); @@ -598,6 +598,7 @@ class QCCalculationParametersBase { static std::string tostring(const T& arg) { using madness::operators::operator<<; std::ostringstream ss; + static_assert(not std::is_same::value, "you need to specialize tostring for this type"); ss< && has_member_id>::value) { return hash_value(arg->id()); } else { - return hash_value(arg); + // compute hash_code for fundamental types + std::size_t hashtype = typeid(T).hash_code(); + hash_combine(hashtype,hash_value(arg)); + return hashtype; } } From 7df9447c5667bdf14b9979e1b63d9966a946f3d7 Mon Sep 17 00:00:00 2001 From: fbischoff Date: Fri, 23 Aug 2024 12:19:00 -0400 Subject: [PATCH 54/54] analyze MOs in complex calculations --- src/madness/chem/SCF.cc | 14 +++++++++----- src/madness/chem/SCF.h | 7 +++++-- src/madness/chem/molecularbasis.h | 2 +- src/madness/chem/oep.cc | 5 ++++- src/madness/chem/znemo.cc | 11 +++++++++++ 5 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/madness/chem/SCF.cc b/src/madness/chem/SCF.cc index 7572602fa06..01be3b90f46 100644 --- a/src/madness/chem/SCF.cc +++ b/src/madness/chem/SCF.cc @@ -592,8 +592,11 @@ vecfuncT SCF::project_ao_basis_only(World& world, const AtomicBasisSet& aobasis, return ao; } -void SCF::analyze_vectors(World& world, const vecfuncT& mo, const tensorT& occ, - const tensorT& energy, const std::vector& set) { +void SCF::analyze_vectors(World& world, const vecfuncT& mo, + const vecfuncT& ao, double vtol, + const Molecule& molecule, const int print_level, + const AtomicBasisSet& aobasis, const tensorT& occ, + const tensorT& energy, const std::vector& set) { START_TIMER(world); PROFILE_MEMBER_FUNC(SCF); tensorT Saomo = matrix_inner(world, ao, mo); @@ -624,7 +627,8 @@ void SCF::analyze_vectors(World& world, const vecfuncT& mo, const tensorT& occ, for (long i = 0; i < nmo; ++i) { size_t ncoeffi = mo[i].size(); ncoeff += ncoeffi; - if (world.rank() == 0 and (param.print_level() > 1)) { + // if (world.rank() == 0 and (param.print_level() > 1)) { + if (world.rank() == 0 and (print_level > 1)) { printf(" MO%4ld : ", i); if (set.size()) printf("set=%d : ", set[i]); @@ -2355,12 +2359,12 @@ void SCF::solve(World& world) { } if (param.nwfile() == "none") { - analyze_vectors(world, amo, aocc, aeps); + analyze_vectors(world, amo, ao, vtol, molecule, param.print_level(), aobasis, aocc, aeps); if (param.nbeta() != 0 && !param.spin_restricted()) { if (world.rank() == 0 and (param.print_level() > 1)) print("Analysis of beta MO vectors"); - analyze_vectors(world, bmo, bocc, beps); + analyze_vectors(world, bmo, ao, vtol, molecule, param.print_level(), aobasis, bocc, beps); } } diff --git a/src/madness/chem/SCF.h b/src/madness/chem/SCF.h index 2e284fdd593..b99fc21b4eb 100644 --- a/src/madness/chem/SCF.h +++ b/src/madness/chem/SCF.h @@ -352,8 +352,11 @@ class SCF { std::vector group_orbital_sets(World& world, const tensorT& eps, const tensorT& occ, const int nmo) const; - void analyze_vectors(World& world, const vecfuncT& mo, const tensorT& occ = tensorT(), - const tensorT& energy = tensorT(), const std::vector& set = std::vector()); + static void analyze_vectors(World& world, const vecfuncT& mo, + const vecfuncT& ao, double vtol, + const Molecule& molecule, const int print_level, + const AtomicBasisSet& aobasis, const tensorT& occ = tensorT(), + const tensorT& energy = tensorT(), const std::vector& set = std::vector()); distmatT kinetic_energy_matrix(World& world, const vecfuncT& v) const; diff --git a/src/madness/chem/molecularbasis.h b/src/madness/chem/molecularbasis.h index d201e519124..51205321656 100644 --- a/src/madness/chem/molecularbasis.h +++ b/src/madness/chem/molecularbasis.h @@ -683,7 +683,7 @@ class AtomicBasisSet { /// - basis function number /// - MO coeff template - void print_anal(const Molecule& molecule, const Tensor& v) { + void print_anal(const Molecule& molecule, const Tensor& v) const { const double thresh = 0.2*v.normf(); if (thresh == 0.0) { printf(" zero vector\n"); diff --git a/src/madness/chem/oep.cc b/src/madness/chem/oep.cc index f9adb8d0b38..f9509963654 100644 --- a/src/madness/chem/oep.cc +++ b/src/madness/chem/oep.cc @@ -244,7 +244,10 @@ double OEP::iterate(const std::string model, const vecfuncT& HF_nemo, const tens if (param.do_localize()) { for (size_t i=0; iaeps(i)=KS_Fock(i,i); KS_nemo=localize(KS_nemo,param.econv(),iter==0); - if (param.print_level()>=10) calc->analyze_vectors(world,KS_nemo,calc->aocc,tensorT(),calc->aset); + if (param.print_level()>=10) + SCF::analyze_vectors(world, KS_nemo, calc->ao, calc->vtol, calc->molecule, param.print_level(), + calc->aobasis, calc->aocc, tensorT(), calc->aset ); + // calc->analyze_vectors(world,KS_nemo,calc->aocc,tensorT(),calc->aset); } if (do_symmetry()) { std::vector str_irreps; diff --git a/src/madness/chem/znemo.cc b/src/madness/chem/znemo.cc index 3c68b8c8a8a..701d31a3455 100644 --- a/src/madness/chem/znemo.cc +++ b/src/madness/chem/znemo.cc @@ -426,6 +426,17 @@ double Znemo::analyze() { save_orbitals("plot"); save(density,"density"); save(spindensity,"spindensity"); + + auto components=std::vector>({real(amo),imag(amo),real(bmo),imag(bmo)}); + auto component_names=std::vector({"real_amo","imag_amo","real_bmo","imag_bmo"}); + std::vector real_aos=SCF::project_ao_basis_only(world, aobasis, mol); + for (size_t i=0; i0) SCF::analyze_vectors(world, components[i], real_aos, + FunctionDefaults<3>::get_thresh()*0.1, molecule(), cparam.print_level(), aobasis); + + } + return energy; }