1 // 2 // BAGEL - Brilliantly Advanced General Electronic Structure Library 3 // Filename: gamma_task.h 4 // Copyright (C) 2013 Toru Shiozaki 5 // 6 // Author: Shane Parker <shane.parker@u.northwestern.edu> 7 // Maintainer: Toru Shiozaki 8 // 9 // This file is part of the BAGEL package. 10 // 11 // This program is free software: you can redistribute it and/or modify 12 // it under the terms of the GNU General Public License as published by 13 // the Free Software Foundation, either version 3 of the License, or 14 // (at your option) any later version. 15 // 16 // This program is distributed in the hope that it will be useful, 17 // but WITHOUT ANY WARRANTY; without even the implied warranty of 18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 // GNU General Public License for more details. 20 // 21 // You should have received a copy of the GNU General Public License 22 // along with this program. If not, see <http://www.gnu.org/licenses/>. 23 // 24 25 #ifndef __ASD_GAMMA_TASK_H 26 #define __ASD_GAMMA_TASK_H 27 28 #include <src/asd/gamma_tree.h> 29 #include <src/ci/ras/apply_block.h> 30 31 namespace bagel { 32 33 template <typename VecType> 34 class GammaTask { 35 protected: 36 const int a_; // Orbital 37 const GammaSQ operation_; // Which operation 38 const std::shared_ptr<GammaTree<VecType>> tree_; // destination 39 40 public: GammaTask(const std::shared_ptr<GammaTree<VecType>> tree,const GammaSQ operation,const int a)41 GammaTask(const std::shared_ptr<GammaTree<VecType>> tree, const GammaSQ operation, const int a) : a_(a), operation_(operation), tree_(tree) {} 42 compute()43 void compute() { 44 constexpr int nops = 4; 45 const int norb = tree_->norb(); 46 47 auto action = [] (const int op) { return is_creation(GammaSQ(op)); }; 48 auto spin = [] (const int op) { return is_alpha(GammaSQ(op)); }; 49 50 std::shared_ptr<GammaBranch<VecType>> first = tree_->base()->branch(operation_); 51 assert(first->active()); // This should have been checked before sending it to the TaskQueue 52 53 std::shared_ptr<const VecType> avec = tree_->ket()->apply(a_, action(static_cast<int>(operation_)), spin(static_cast<int>(operation_))); 54 for (auto& ibra : first->bras()) 55 dot_product(ibra.second, avec, first->gammas().find(ibra.first)->second->element_ptr(0,a_)); 56 57 for (int j = 0; j < nops; ++j) { 58 auto second = first->branch(j); 59 if (!second->active()) continue; 60 61 for (int b = 0; b < norb; ++b) { 62 if (b==a_ && j==static_cast<int>(operation_)) continue; 63 std::shared_ptr<const VecType> bvec = avec->apply(b, action(j), spin(j)); 64 for (auto& jbra : second->bras()) 65 dot_product(jbra.second, bvec, second->gammas().find(jbra.first)->second->element_ptr(0, a_*norb + b)); 66 67 for (int k = 0; k < nops; ++k) { 68 std::shared_ptr<GammaBranch<VecType>> third = second->branch(k); 69 if (!third->active()) continue; 70 71 for (int c = 0; c < norb; ++c) { 72 if (b==c && k==j) continue; 73 std::shared_ptr<const VecType> cvec = bvec->apply(c, action(k), spin(k)); 74 for (auto& kbra : third->bras()) 75 dot_product(kbra.second, cvec, third->gammas().find(kbra.first)->second->element_ptr(0, a_*norb*norb + b*norb + c)); 76 } 77 } 78 } 79 } 80 } 81 82 private: dot_product(std::shared_ptr<const VecType> bras,std::shared_ptr<const VecType> kets,double * target)83 void dot_product(std::shared_ptr<const VecType> bras, std::shared_ptr<const VecType> kets, double* target) const { 84 const int nbras = bras->ij(); 85 const int nkets = kets->ij(); 86 87 for (int iket = 0; iket < nkets; ++iket) { 88 for (int jbra = 0; jbra < nbras; ++jbra, ++target) { 89 *target = bras->data(jbra)->dot_product(*kets->data(iket)); 90 } 91 } 92 } 93 }; 94 95 template <> 96 void GammaTask<CASDvec>::compute(); 97 98 99 template <class Branch> 100 class RASTask { 101 protected: 102 const int holes_; 103 const int particles_; 104 105 public: RASTask(const int h,const int p)106 RASTask(const int h, const int p) : holes_(h), particles_(p) {} 107 virtual std::shared_ptr<const RASString> stringspace(const int, const int, const int, const int , const int, const int) = 0; 108 next_block(std::shared_ptr<Branch> branch,std::shared_ptr<const RASBlock<double>> base_block,const int & orbital,const bool & action,const bool & spin)109 std::shared_ptr<RASBlock<double>> next_block(std::shared_ptr<Branch> branch, std::shared_ptr<const RASBlock<double>> base_block, 110 const int& orbital, const bool& action, const bool& spin) { 111 std::shared_ptr<const RASString> sa = base_block->stringsa(); 112 std::shared_ptr<const RASString> sb = base_block->stringsb(); 113 114 std::array<int, 3> ras{{sa->ras<0>().second, sa->ras<1>().second, sa->ras<2>().second}}; 115 116 const int ras_space = ( orbital >= ras[0] ) + ( orbital >= (ras[0]+ras[1]) ); 117 std::array<int, 6> info{{ras[0] - sa->nholes(), ras[0] - sb->nholes(), sa->nele2(), sb->nele2(), sa->nparticles(), sb->nparticles()}}; 118 119 const int mod = action ? +1 : -1; 120 info[2*ras_space] += spin ? mod : 0; 121 info[2*ras_space+1] += spin ? 0 : mod; 122 123 // make sure it is a valid result 124 for (int i = 0; i < 6; ++i) 125 if (info[i] < 0 || info[i] > ras[i/2]) return nullptr; 126 127 // is it out of space? 128 const int nholes = 2*ras[0] - (info[0] + info[1]); 129 const int nparts = info[4] + info[5]; 130 if (nholes > holes_ || nparts > particles_) { 131 // peek ahead along the branch to see whether it will come back into the space 132 133 // set of operations that would bring state back 134 std::set<int> needed; 135 if (nholes == (holes_+1)) { 136 if (info[0] == ras[0]) { 137 // no alpha holes, only beta holes 138 needed.insert(static_cast<int>(GammaSQ::CreateBeta)); 139 } else if (info[1] == ras[0]) { 140 // no beta holes, only alpha holes 141 needed.insert(static_cast<int>(GammaSQ::CreateAlpha)); 142 } else { 143 // both types of holes present 144 needed.insert(static_cast<int>(GammaSQ::CreateAlpha)); 145 needed.insert(static_cast<int>(GammaSQ::CreateBeta)); 146 } 147 } else if (nparts == (particles_+1)) { 148 if (info[4] == 0) { 149 // no alpha particles, only beta particles 150 needed.insert(static_cast<int>(GammaSQ::AnnihilateBeta)); 151 } else if (info[5] == 0) { 152 // no beta particles, only alpha particles 153 needed.insert(static_cast<int>(GammaSQ::AnnihilateAlpha)); 154 } else { 155 // both present 156 needed.insert(static_cast<int>(GammaSQ::AnnihilateBeta)); 157 needed.insert(static_cast<int>(GammaSQ::AnnihilateAlpha)); 158 } 159 } else { 160 // impossible to contribute 161 return nullptr; 162 } 163 164 // search down branch for active branches with needed operations 165 if (!branch->if_contributes(needed)) 166 return nullptr; 167 } 168 169 std::shared_ptr<const RASString> ta = spin ? stringspace(info[0], ras[0], info[2], ras[1], info[4], ras[2]) : sa; 170 std::shared_ptr<const RASString> tb = spin ? sb : stringspace(info[1], ras[0], info[3], ras[1], info[5], ras[2]); 171 172 auto out = std::make_shared<RASBlock_alloc<double>>(ta,tb); 173 174 RAS::Apply_block apply_block(orbital, action, spin); 175 apply_block(base_block, out, branch->is_distterminal()); 176 177 return out; 178 } 179 }; 180 181 template <> 182 class GammaTask<RASDvec> : public RASTask<GammaBranch<RASDvec>> { 183 protected: 184 const int a_; // Orbital 185 const GammaSQ operation_; // Which operation 186 const std::shared_ptr<GammaTree<RASDvec>> tree_; // destination 187 188 // to avoid rebuilding the stringspaces repeatedly 189 std::map<std::tuple<int, int, int, int, int, int>, std::shared_ptr<const RASString>> stringspaces_; 190 191 public: GammaTask(const std::shared_ptr<GammaTree<RASDvec>> tree,const GammaSQ operation,const int a)192 GammaTask(const std::shared_ptr<GammaTree<RASDvec>> tree, const GammaSQ operation, const int a) 193 : RASTask<GammaBranch<RASDvec>>(tree->ket()->det()->max_holes(), tree->ket()->det()->max_particles()), 194 a_(a), operation_(operation), tree_(tree) {} 195 compute()196 void compute() { 197 constexpr int nops = 4; 198 const int norb = tree_->norb(); 199 200 auto action = [] (const int op) { return is_creation(GammaSQ(op)); }; 201 auto spin = [] (const int op) { return is_alpha(GammaSQ(op)); }; 202 203 std::shared_ptr<GammaBranch<RASDvec>> first = tree_->base()->branch(operation_); 204 assert(first->active()); // This should have been checked before sending it to the TaskQueue 205 206 std::shared_ptr<const RASDeterminants> base_det = tree_->ket()->det(); 207 208 const int nkets = tree_->ket()->ij(); 209 for (int iket = 0; iket < nkets; ++iket) { 210 std::shared_ptr<const RASCivec> ketvec = tree_->ket()->data(iket); 211 for (auto& ketblock : ketvec->blocks()) { 212 if (!ketblock) continue; 213 std::shared_ptr<const RASBlock<double>> ablock 214 = next_block(first, ketblock, a_, action(static_cast<int>(operation_)), spin(static_cast<int>(operation_))); 215 if (!ablock) continue; 216 217 for (auto& ibra : first->bras()) 218 dot_product(ibra.second, ablock, first->gammas().find(ibra.first)->second->element_ptr(iket*ibra.second->ij(), a_)); 219 220 for (int j = 0; j < nops; ++j) { 221 auto second = first->branch(j); 222 if (!second->active()) continue; 223 224 for (int b = 0; b < norb; ++b) { 225 if (b==a_ && j==static_cast<int>(operation_)) continue; 226 std::shared_ptr<const RASBlock<double>> bblock = next_block(second, ablock, b, action(j), spin(j)); 227 if (!bblock) continue; 228 229 for (auto& jbra : second->bras()) 230 dot_product(jbra.second, bblock, second->gammas().find(jbra.first)->second->element_ptr(iket*jbra.second->ij(), a_*norb + b)); 231 232 for (int k = 0; k < nops; ++k) { 233 std::shared_ptr<GammaBranch<RASDvec>> third = second->branch(k); 234 if (!third->active()) continue; 235 236 for (int c = 0; c < norb; ++c) { 237 if (b==c && k==j) continue; 238 std::shared_ptr<const RASBlock<double>> cblock = next_block(third, bblock, c, action(k), spin(k)); 239 if (!cblock) continue; 240 for (auto& kbra : third->bras()) 241 dot_product(kbra.second, cblock, third->gammas().find(kbra.first)->second->element_ptr(iket*kbra.second->ij(), a_*norb*norb + b*norb + c)); 242 } 243 } 244 } 245 } 246 } 247 } 248 } 249 250 private: dot_product(std::shared_ptr<const RASDvec> bras,std::shared_ptr<const RASBlock<double>> ketblock,double * target)251 void dot_product(std::shared_ptr<const RASDvec> bras, std::shared_ptr<const RASBlock<double>> ketblock, double* target) const { 252 const int nbras = bras->ij(); 253 254 if (bras->det()->allowed(ketblock->stringsb(), ketblock->stringsa())) { 255 for (int jbra = 0; jbra < nbras; ++jbra, ++target) { 256 std::shared_ptr<const RASBlock<double>> brablock = bras->data(jbra)->block(ketblock->stringsb(), ketblock->stringsa()); 257 if (brablock) 258 *target += blas::dot_product(brablock->data(), brablock->size(), ketblock->data()); 259 } 260 } 261 } 262 stringspace(const int a,const int b,const int c,const int d,const int e,const int f)263 std::shared_ptr<const RASString> stringspace(const int a, const int b, const int c, const int d, const int e, const int f) final { 264 auto iter = stringspaces_.find(std::make_tuple(a,b,c,d,e,f)); 265 if (iter != stringspaces_.end()) { 266 return iter->second; 267 } 268 else { 269 stringspaces_.emplace(std::make_tuple(a,b,c,d,e,f), std::make_shared<RASString>(a,b,c,d,e,f)); 270 return stringspaces_[std::make_tuple(a,b,c,d,e,f)]; 271 } 272 } 273 }; 274 275 } 276 277 #endif 278