void CheMPS2::DMRG::calc2DM(){ //First get the whole MPS into left-canonical form int index = Prob->gL()-2; Sobject * denS = new Sobject(index,denBK->gIrrep(index),denBK->gIrrep(index+1),denBK); denS->Join(MPS[index],MPS[index+1]); Heff Solver(denBK, Prob); double Energy = 0.0; double ** VeffTilde = NULL; if (Exc_activated){ VeffTilde = new double*[nStates-1]; for (int cnt=0; cnt<nStates-1; cnt++){ VeffTilde[cnt] = new double[denS->gKappa2index(denS->gNKappa())]; calcVeffTilde(VeffTilde[cnt], denS, cnt); } } Energy = Solver.SolveDAVIDSON(denS, Ltensors, Atensors, Btensors, Ctensors, Dtensors, S0tensors, S1tensors, F0tensors, F1tensors, Qtensors, Xtensors, nStates-1, VeffTilde); if (Exc_activated){ for (int cnt=0; cnt<nStates-1; cnt++){ delete [] VeffTilde[cnt]; } delete [] VeffTilde; } Energy += Prob->gEconst(); if (Energy<MinEnergy){ MinEnergy = Energy; } denS->Split(MPS[index],MPS[index+1],OptScheme->getD(OptScheme->getNInstructions()-1),true,true); delete denS; cout << "*********************" << endl; cout << "** 2DM calculation **" << endl; cout << "*********************" << endl; updateMovingRightSafe(index); TensorDiag * Norm = new TensorDiag(Prob->gL(), denBK); MPS[Prob->gL()-1]->QR(Norm); delete Norm; //Then calculate step by step the 2DM if (!the2DMallocated){ the2DMallocated = true; the2DM = new TwoDM(denBK, Prob); } for (int siteindex=Prob->gL()-1; siteindex>=0; siteindex--){ the2DM->FillSite(MPS[siteindex], Ltensors, F0tensors, F1tensors, S0tensors, S1tensors); if (siteindex>0){ TensorDiag * Left = new TensorDiag(siteindex, denBK); MPS[siteindex]->LQ(Left); MPS[siteindex-1]->RightMultiply(Left); delete Left; updateMovingLeftSafe2DM(siteindex-1); } } //Then perform two checks: double trace & energy double NtimesNminus1 = the2DM->doubletrace2DMA(); cout << " N(N-1) = " << denBK->gN() * (denBK->gN() - 1) << " and calculated by double trace of the 2DM-A = " << NtimesNminus1 << endl; double Energy2DMA = the2DM->calcEnergy(); cout << " Energy obtained by Heffective at edge = " << Energy << " and as Econst + 0.5*trace(2DM-A*Ham) = " << Energy2DMA << endl; }
void CheMPS2::DMRG::calcVeffTilde(double * result, Sobject * currentS, int state_number){ int dimTot = currentS->gKappa2index(currentS->gNKappa()); for (int cnt=0; cnt<dimTot; cnt++){ result[cnt] = 0.0; } int index = currentS->gIndex(); const int dimL = std::max(denBK->gMaxDimAtBound(index), Exc_BKs[state_number]->gMaxDimAtBound(index) ); const int dimR = std::max(denBK->gMaxDimAtBound(index+2), Exc_BKs[state_number]->gMaxDimAtBound(index+2) ); double * workmem = new double[dimL * dimR]; //Construct Sup Sobject * Sup = new Sobject(index,Exc_BKs[state_number]->gIrrep(index),Exc_BKs[state_number]->gIrrep(index+1),Exc_BKs[state_number]); Sup->Join(Exc_MPSs[state_number][index],Exc_MPSs[state_number][index+1]); //Construct VeffTilde const double prefactor = sqrt(Exc_Eshifts[state_number]) / (Prob->gTwoS() + 1.0); for (int ikappa=0; ikappa<currentS->gNKappa(); ikappa++){ int NL = currentS->gNL(ikappa); int TwoSL = currentS->gTwoSL(ikappa); int IL = currentS->gIL(ikappa); int N1 = currentS->gN1(ikappa); int N2 = currentS->gN2(ikappa); int TwoJ = currentS->gTwoJ(ikappa); int NR = currentS->gNR(ikappa); int TwoSR = currentS->gTwoSR(ikappa); int IR = currentS->gIR(ikappa); //Check if block also exists for other MPS int kappaSup = Sup->gKappa(NL, TwoSL, IL, N1, N2, TwoJ, NR, TwoSR, IR); if (kappaSup!=-1){ int dimLdown = denBK->gCurrentDim(index, NL,TwoSL,IL); int dimLup = Exc_BKs[state_number]->gCurrentDim(index, NL,TwoSL,IL); int dimRdown = denBK->gCurrentDim(index+2,NR,TwoSR,IR); int dimRup = Exc_BKs[state_number]->gCurrentDim(index+2,NR,TwoSR,IR); //Do sqrt( (TwoJR+1) * Eshift ) / (TwoStarget+1) times (OL * Sup)_{block} --> workmem double * SupPart = Sup->gStorage() + Sup->gKappa2index(kappaSup); double alpha = prefactor * sqrt(TwoSR+1.0); if (index==0){ int dimBlock = dimLup * dimRup; int inc = 1; dcopy_(&dimBlock,SupPart,&inc,workmem,&inc); dscal_(&dimBlock,&alpha,workmem,&inc); } else { char notrans = 'N'; double beta = 0.0; double * Opart = Exc_Overlaps[state_number][index-1]->gStorage(NL,TwoSL,IL,NL,TwoSL,IL); dgemm_(¬rans,¬rans,&dimLdown,&dimRup,&dimLup,&alpha,Opart,&dimLdown,SupPart,&dimLup,&beta,workmem,&dimLdown); } //Do (workmem * OR)_{block} --> result + jumpCurrentS int jumpCurrentS = currentS->gKappa2index(ikappa); if (index==Prob->gL()-2){ int dimBlock = dimLdown * dimRdown; int inc = 1; dcopy_(&dimBlock, workmem, &inc, result + jumpCurrentS, &inc); } else { char trans = 'T'; char notrans = 'N'; alpha = 1.0; double beta = 0.0; //set double * Opart = Exc_Overlaps[state_number][index+1]->gStorage(NR,TwoSR,IR,NR,TwoSR,IR); dgemm_(¬rans,&trans,&dimLdown,&dimRdown,&dimRup,&alpha,workmem,&dimLdown,Opart,&dimRdown,&beta,result+jumpCurrentS,&dimLdown); } } } //Deallocate everything delete Sup; delete [] workmem; }