00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #ifdef __GNUG__
00029 #pragma interface
00030 #endif
00031
00032 #ifndef _chemistry_qc_mbptr12_contracttbinttensor_h
00033 #define _chemistry_qc_mbptr12_contracttbinttensor_h
00034
00035 #include <cmath>
00036 #include <util/misc/regtime.h>
00037 #include <chemistry/qc/mbptr12/pairiter.h>
00038 #include <chemistry/qc/mbptr12/utils.h>
00039 #include <chemistry/qc/mbptr12/utils.impl.h>
00040 #include <chemistry/qc/mbptr12/r12int_eval.h>
00041 #include <chemistry/qc/mbptr12/print.h>
00042
00043 namespace sc {
00044
00045 template <typename DataProcess_Bra,
00046 typename DataProcess_Ket,
00047 typename DataProcess_BraKet,
00048 bool CorrFactorInBra,
00049 bool CorrFactorInKet,
00050 bool CorrFactorInInt>
00051 void
00052 R12IntEval::contract_tbint_tensor(
00053 RefSCMatrix& T,
00054 TwoBodyInt::tbint_type tbint_type_bra,
00055 TwoBodyInt::tbint_type tbint_type_ket,
00056 const Ref<OrbitalSpace>& space1_bra,
00057 const Ref<OrbitalSpace>& space2_bra,
00058 const Ref<OrbitalSpace>& space1_intb,
00059 const Ref<OrbitalSpace>& space2_intb,
00060 const Ref<OrbitalSpace>& space1_ket,
00061 const Ref<OrbitalSpace>& space2_ket,
00062 const Ref<OrbitalSpace>& space1_intk,
00063 const Ref<OrbitalSpace>& space2_intk,
00064 const Ref<LinearR12::TwoParticleContraction>& tpcontract,
00065 bool antisymmetrize,
00066 const std::vector<std::string>& tformkeys_bra,
00067 const std::vector<std::string>& tformkeys_ket
00068 )
00069 {
00070
00071 const bool part1_strong_equiv_part2 = (space1_bra==space2_bra &&
00072 space1_ket==space2_ket);
00073
00074 const bool part1_weak_equiv_part2 = (space1_bra->rank()==space2_bra->rank() &&
00075 space1_ket->rank()==space2_ket->rank());
00076
00077 bool correct_semantics = (antisymmetrize && (part1_weak_equiv_part2 ||
00078 part1_strong_equiv_part2) ) ||
00079 !antisymmetrize;
00080
00081 correct_semantics = ( correct_semantics &&
00082 (space1_intb->rank() == space1_intk->rank()) &&
00083 (space2_intb->rank() == space2_intk->rank()) );
00084
00085 correct_semantics = ( correct_semantics &&
00086 (tpcontract->nrow() == space1_intb->rank()) &&
00087 (tpcontract->ncol() == space2_intb->rank()) );
00088 if (!correct_semantics)
00089 throw ProgrammingError("R12IntEval::contract_tbint_tensor_() -- incorrect call semantics",
00090 __FILE__,__LINE__);
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103 const bool part1_intequiv_part2 = (space1_intb==space2_intb &&
00104 space1_intk==space2_intk);
00105 #if 0
00106
00107
00108 if (!part1_intequiv_part2 && ! part1_strong_equiv_part2 && antisymmetrize)
00109 throw ProgrammingError("R12IntEval::contract_tbint_tensor_() -- dubious call semantics",
00110 __FILE__,__LINE__);
00111 #endif
00112
00113
00114 const bool alphabeta = !(antisymmetrize &&
00115 part1_strong_equiv_part2 &&
00116 part1_intequiv_part2);
00117
00118
00119
00120
00121
00122
00123 const bool CorrFactorInBraInt = CorrFactorInBra && CorrFactorInInt;
00124 const bool CorrFactorInKetInt = CorrFactorInKet && CorrFactorInInt;
00125
00126 const unsigned int nbrasets = (CorrFactorInBra ? corrfactor()->nfunctions() : 1);
00127 const unsigned int nketsets = (CorrFactorInKet ? corrfactor()->nfunctions() : 1);
00128 const unsigned int nintsets = (CorrFactorInInt ? corrfactor()->nfunctions() : 1);
00129 const unsigned int nbraintsets = (CorrFactorInBraInt ? -1 : nbrasets*nintsets);
00130 const unsigned int nketintsets = (CorrFactorInKetInt ? -1 : nketsets*nintsets);
00131
00132
00133
00134
00135
00136 typedef std::vector< Ref<TwoBodyMOIntsTransform> > tformvec;
00137
00138
00139 const size_t num_tforms_bra = tformkeys_bra.size();
00140 tformvec transforms_bra(num_tforms_bra);
00141 for(unsigned int t=0; t<num_tforms_bra; ++t) {
00142 transforms_bra[t] = r12info()->moints_runtime()->get(tformkeys_bra[t]);
00143 }
00144
00145
00146 const size_t num_tforms_ket = tformkeys_ket.size();
00147 tformvec transforms_ket(num_tforms_ket);
00148 for(unsigned int t=0; t<num_tforms_ket; ++t) {
00149 transforms_ket[t] = r12info()->moints_runtime()->get(tformkeys_ket[t]);
00150 }
00151
00152
00153
00154
00155 Timer tim_gen_tensor_contract("Generic tensor contract");
00156 std::string label;
00157 {
00158 std::ostringstream oss_bra;
00159 oss_bra << "<" << space1_bra->id() << " " << space2_bra->id() << (antisymmetrize ? "||" : "|")
00160 << space1_intb->id() << " " << space2_intb->id() << ">";
00161 const std::string label_bra = oss_bra.str();
00162 std::ostringstream oss_ket;
00163 oss_ket << "<" << space1_ket->id() << " " << space2_ket->id() << (antisymmetrize ? "||" : "|")
00164 << space1_intk->id() << " " << space2_intk->id() << ">";
00165 const std::string label_ket = oss_ket.str();
00166 std::ostringstream oss;
00167 oss << "<" << space1_bra->id() << " " << space2_bra->id() << (antisymmetrize ? "||" : "|")
00168 << space1_ket->id() << " " << space2_ket->id() << "> = "
00169 << label_bra << " . " << label_ket << "^T";
00170 label = oss.str();
00171 }
00172 ExEnv::out0() << endl << indent
00173 << "Entered generic contraction (" << label << ")" << endl;
00174 ExEnv::out0() << incindent;
00175
00176
00177
00178
00179
00180
00181 Ref<OrbitalSpace> tspace1_bra = transforms_bra[0]->space1();
00182 Ref<OrbitalSpace> tspace2_bra = transforms_bra[0]->space3();
00183 Ref<OrbitalSpace> tspace1_intb = transforms_bra[0]->space2();
00184 Ref<OrbitalSpace> tspace2_intb = transforms_bra[0]->space4();
00185 Ref<OrbitalSpace> tspace1_ket = transforms_ket[0]->space1();
00186 Ref<OrbitalSpace> tspace2_ket = transforms_ket[0]->space3();
00187 Ref<OrbitalSpace> tspace1_intk = transforms_ket[0]->space2();
00188 Ref<OrbitalSpace> tspace2_intk = transforms_ket[0]->space4();
00189
00190 std::vector<unsigned int> map1_bra, map2_bra, map1_ket, map2_ket,
00191 map1_intb, map2_intb, map1_intk, map2_intk;
00192
00193 std::vector<unsigned int> map12_intb;
00194
00195 std::vector<unsigned int> map21_intb;
00196
00197 std::vector<unsigned int> map12_intk;
00198
00199 std::vector<unsigned int> map21_intk;
00200
00201 {
00202 map1_bra = *tspace1_bra<<*space1_bra;
00203 map2_bra = *tspace2_bra<<*space2_bra;
00204 map1_intb = *tspace1_intb<<*space1_intb;
00205 map2_intb = *tspace2_intb<<*space2_intb;
00206
00207 if (!alphabeta) {
00208 if (tspace1_intb == tspace2_intb) {
00209 map12_intb = map1_intb;
00210 map21_intb = map2_intb;
00211 }
00212 else {
00213 map12_intb = *tspace1_intb<<*space2_intb;
00214 map21_intb = *tspace2_intb<<*space1_intb;
00215 }
00216 }
00217 }
00218 {
00219 map1_ket = *tspace1_ket<<*space1_ket;
00220 map2_ket = *tspace2_ket<<*space2_ket;
00221 map1_intk = *tspace1_intk<<*space1_intk;
00222 map2_intk = *tspace2_intk<<*space2_intk;
00223
00224 if (!alphabeta) {
00225 if (tspace1_intk == tspace2_intk) {
00226 map12_intk = map1_intk;
00227 map21_intk = map2_intk;
00228 }
00229 else {
00230 map12_intk = *tspace1_intk<<*space2_intk;
00231 map21_intk = *tspace2_intk<<*space1_intk;
00232 }
00233 }
00234 }
00235
00236 const unsigned int bratform_block_ncols = tspace2_intb->rank();
00237 const unsigned int kettform_block_ncols = tspace2_intk->rank();
00238 const RefDiagSCMatrix evals1_bra = space1_bra->evals();
00239 const RefDiagSCMatrix evals2_bra = space2_bra->evals();
00240 const RefDiagSCMatrix evals1_ket = space1_ket->evals();
00241 const RefDiagSCMatrix evals2_ket = space2_ket->evals();
00242 const RefDiagSCMatrix evals1_intb = space1_intb->evals();
00243 const RefDiagSCMatrix evals2_intb = space2_intb->evals();
00244 const RefDiagSCMatrix evals1_intk = space1_intk->evals();
00245 const RefDiagSCMatrix evals2_intk = space2_intk->evals();
00246
00247
00248
00249 const SpinCase2 S = (alphabeta ? AlphaBeta : AlphaAlpha);
00250 SpinMOPairIter iterbra(space1_bra,(alphabeta ? space2_bra : space1_bra),S);
00251 SpinMOPairIter iterket(space1_ket,(alphabeta ? space2_ket : space1_ket),S);
00252 SpinMOPairIter iterint(space1_intb,(alphabeta ? space2_intb : space1_intb),S);
00253
00254 const unsigned int nbra = iterbra.nij();
00255
00256 const unsigned int nket = iterket.nij();
00257
00258 const unsigned int nint = iterint.nij();
00259
00260 RefSCMatrix Tcontr;
00261
00262 if (antisymmetrize && alphabeta) {
00263 Tcontr = T.kit()->matrix(new SCDimension(nbra*nbrasets),
00264 new SCDimension(nket*nketsets));
00265 Tcontr.assign(0.0);
00266 }
00267 else
00268 Tcontr = T;
00269
00270
00271 const unsigned int blksize_int = space1_intb->rank() * space2_intb->rank();
00272 double* T_ij = new double[blksize_int];
00273 double* T_kl = new double[blksize_int];
00274
00275
00276
00277
00278
00279
00280 for(unsigned int fint=0; fint<nintsets; ++fint) {
00281
00282 unsigned int fbraoffset = 0;
00283 for(unsigned int fbra=0; fbra<nbrasets; ++fbra,fbraoffset+=nbra) {
00284 const unsigned int fbraint = fbra*nintsets+fint;
00285 Ref<TwoBodyMOIntsTransform> tformb = transforms_bra[fbraint];
00286 const Ref<TwoBodyIntDescr>& intdescrb = tformb->intdescr();
00287 const unsigned int intsetidx_bra = intdescrb->intset(tbint_type_bra);
00288
00289 tformb->compute();
00290 Ref<R12IntsAcc> accumb = tformb->ints_acc();
00291
00292 unsigned int fketoffset = 0;
00293 for(unsigned int fket=0; fket<nketsets; ++fket,fketoffset+=nket) {
00294 const unsigned int fketint = fket*nintsets+fint;
00295 Ref<TwoBodyMOIntsTransform> tformk = transforms_ket[fketint];
00296 const Ref<TwoBodyIntDescr>& intdescrk = tformk->intdescr();
00297 const unsigned int intsetidx_ket = intdescrk->intset(tbint_type_ket);
00298
00299 tformk->compute();
00300 Ref<R12IntsAcc> accumk = tformk->ints_acc();
00301
00302 if (debug_ >= DefaultPrintThresholds::diagnostics) {
00303 ExEnv::out0() << indent << "Using transforms "
00304 << tformb->name() << " and "
00305 << tformk->name() << std::endl;
00306 }
00307
00308
00309
00310 vector<int> proc_with_ints;
00311 const int nproc_with_ints = accumb->tasks_with_access(proc_with_ints);
00312 const int me = r12info()->msg()->me();
00313 const bool nket_ge_nevals = (nket >= nproc_with_ints);
00314
00315 if (accumb->has_access(me)) {
00316
00317 unsigned int ijkl = 0;
00318 for(iterbra.start(); iterbra; iterbra.next()) {
00319 const int ij = iterbra.ij();
00320
00321 bool fetch_ij_block = false;
00322 if (nket_ge_nevals) {
00323 fetch_ij_block = true;
00324 }
00325 else {
00326 const int first_ij_task = ijkl%nproc_with_ints;
00327 const int last_ij_task = (ijkl+nket-1)%nproc_with_ints;
00328
00329 if ( !(first_ij_task > proc_with_ints[me] && proc_with_ints[me] > last_ij_task) )
00330 fetch_ij_block = true;
00331 }
00332 if (!fetch_ij_block)
00333 continue;
00334
00335 const unsigned int i = iterbra.i();
00336 const unsigned int j = iterbra.j();
00337 const unsigned int ii = map1_bra[i];
00338 const unsigned int jj = map2_bra[j];
00339
00340 Timer tim_intsretrieve("MO ints retrieve");
00341 const double *ij_buf = accumb->retrieve_pair_block(ii,jj,intsetidx_bra);
00342 tim_intsretrieve.exit();
00343 if (debug_ >= DefaultPrintThresholds::allO2N2)
00344 ExEnv::outn() << indent << "task " << me << ": obtained ij blocks" << endl;
00345
00346 for(iterket.start(); iterket; iterket.next(),ijkl++) {
00347 const int kl = iterket.ij();
00348
00349 const int ijkl_proc = ijkl%nproc_with_ints;
00350 if (ijkl_proc != proc_with_ints[me])
00351 continue;
00352
00353 const unsigned int k = iterket.i();
00354 const unsigned int l = iterket.j();
00355 const unsigned int kk = map1_ket[k];
00356 const unsigned int ll = map2_ket[l];
00357
00358 if (debug_ >= DefaultPrintThresholds::allO2N2)
00359 ExEnv::outn() << indent << "task " << me << ": working on (i,j | k,l) = ("
00360 << i << "," << j << " | " << k << "," << l << ")" << endl;
00361 tim_intsretrieve.enter("MO ints retrieve");
00362 const double *kl_buf = accumk->retrieve_pair_block(kk,ll,intsetidx_ket);
00363 tim_intsretrieve.exit();
00364 if (debug_ >= DefaultPrintThresholds::allO2N2)
00365 ExEnv::outn() << indent << "task " << me << ": obtained kl blocks" << endl;
00366
00367
00368 memset(T_ij, 0, blksize_int*sizeof(double));
00369 memset(T_kl, 0, blksize_int*sizeof(double));
00370
00371 if (debug_ >= DefaultPrintThresholds::allO2N2) {
00372 ExEnv::out0() << indent << "i = " << i << " j = " << j << " k = " << k << " l = " << l
00373 << incindent << endl;
00374 }
00375
00376 for(iterint.start(); iterint; iterint.next()) {
00377 const unsigned int m = iterint.i();
00378 const unsigned int n = iterint.j();
00379 const int mn = iterint.ij();
00380 int MN_bra, MN_ket;
00381 {
00382 const unsigned int mm = map1_intb[m];
00383 const unsigned int nn = map2_intb[n];
00384 MN_bra = mm*bratform_block_ncols+nn;
00385 }
00386 {
00387 const unsigned int mm = map1_intk[m];
00388 const unsigned int nn = map2_intk[n];
00389 MN_ket = mm*kettform_block_ncols+nn;
00390 }
00391
00392 const double I_ijmn = ij_buf[MN_bra];
00393 const double I_klmn = kl_buf[MN_ket];
00394
00395 if (debug_ >= DefaultPrintThresholds::mostO6) {
00396 ExEnv::out0() << indent << " m = " << m << " n = " << n << endl;
00397 }
00398
00399 if (alphabeta) {
00400 if (debug_ >= DefaultPrintThresholds::mostO6) {
00401 ExEnv::out0() << indent << " <ij|mn> = " << I_ijmn << endl
00402 << indent << " <kl|mn> = " << I_klmn << endl;
00403 }
00404 const double T_ijmn = DataProcess_Bra::I2T(I_ijmn,i,j,m,n,
00405 evals1_bra,evals1_intb,evals2_bra,evals2_intb);
00406 const double T_klmn = DataProcess_Ket::I2T(I_klmn,k,l,m,n,
00407 evals1_ket,evals1_intk,evals2_ket,evals2_intk);
00408 if (debug_ >= DefaultPrintThresholds::mostO6) {
00409 ExEnv::out0() << indent << " <ij|T|mn> = " << T_ijmn << endl
00410 << indent << " <kl|T|mn> = " << T_klmn << endl;
00411 }
00412
00413 T_ij[mn] = T_ijmn;
00414 T_kl[mn] = T_klmn;
00415 }
00416 else {
00417
00418 int NM_bra, NM_ket;
00419 {
00420 const unsigned int mm = map21_intb[m];
00421 const unsigned int nn = map12_intb[n];
00422 NM_bra = nn*bratform_block_ncols+mm;
00423 }
00424 {
00425 const unsigned int mm = map21_intk[m];
00426 const unsigned int nn = map12_intk[n];
00427 NM_ket = nn*kettform_block_ncols+mm;
00428 }
00429
00430 const double I_ijnm = ij_buf[NM_bra];
00431 const double I_klnm = kl_buf[NM_ket];
00432
00433 if (debug_ >= DefaultPrintThresholds::mostO6) {
00434 ExEnv::out0() << " <ij|mn> = " << I_ijmn << endl
00435 << " <ij|nm> = " << I_ijnm << endl
00436 << " <kl|mn> = " << I_klmn << endl
00437 << " <kl|nm> = " << I_klnm << endl;
00438 }
00439
00440 const double T_ijmn = DataProcess_Bra::I2T(I_ijmn-I_ijnm,i,j,m,n,
00441 evals1_bra,evals1_intb,evals2_bra,evals2_intb);
00442 const double T_klmn = DataProcess_Ket::I2T(I_klmn-I_klnm,k,l,m,n,
00443 evals1_ket,evals1_intk,evals2_ket,evals2_intk);
00444 if (debug_ >= DefaultPrintThresholds::mostO6) {
00445 ExEnv::out0() << indent << " <ij|T|mn> = " << T_ijmn << endl
00446 << indent << " <kl|T|mn> = " << T_klmn << endl;
00447 }
00448 T_ij[mn] = T_ijmn;
00449 T_kl[mn] = T_klmn;
00450 }
00451
00452 }
00453
00454
00455 double T_ijkl = tpcontract->contract(T_ij,T_kl);
00456 if (debug_ >= DefaultPrintThresholds::allO2N2) {
00457 ExEnv::out0() << decindent << indent
00458 << " <ij|kl> = " << T_ijkl << endl;
00459 }
00460 T_ijkl = DataProcess_BraKet::I2T(T_ijkl,i,j,k,l,
00461 evals1_bra,evals1_ket,evals2_bra,evals2_ket);
00462 if (debug_ >= DefaultPrintThresholds::allO2N2) {
00463 ExEnv::out0() << indent << " <ij|T|kl>(ref) = " << Tcontr.get_element(ij+fbraoffset,kl+fketoffset) << endl;
00464 ExEnv::out0() << indent << " +<ij|T|kl> = " << T_ijkl << endl;
00465 }
00466 if (debug_ >= DefaultPrintThresholds::allO2N2) {
00467 ExEnv::out0() << indent << " <ij|T|kl>(new) = " << Tcontr.get_element(ij+fbraoffset,kl+fketoffset) << endl;
00468 }
00469 Tcontr.accumulate_element(ij+fbraoffset,kl+fketoffset,T_ijkl);
00470
00471 accumk->release_pair_block(kk,ll,intsetidx_ket);
00472
00473 }
00474
00475 if (fetch_ij_block)
00476 accumb->release_pair_block(ii,jj,intsetidx_bra);
00477
00478 }
00479 }
00480
00481
00482
00483
00484 }
00485 }
00486 }
00487
00488 if (antisymmetrize && alphabeta) {
00489
00490 symmetrize<false>(Tcontr,Tcontr,space1_bra,space1_ket);
00491 sc::antisymmetrize(T,Tcontr,space1_bra,space1_ket,true);
00492 Tcontr = 0;
00493 }
00494
00495 delete[] T_ij;
00496 delete[] T_kl;
00497
00498 ExEnv::out0() << decindent;
00499 ExEnv::out0() << indent << "Exited generic contraction (" << label << ")" << endl;
00500 tim_gen_tensor_contract.exit();
00501 }
00502
00503 }
00504
00505 #endif
00506