Program Listing for File fdmSpectrum.hpp#
↰ Return to documentation for file (dynamics/fdmSpectrum.hpp
)
#pragma once
#include "nrgcore/qOperator.hpp"
#include "utils/qmatrix.hpp"
#include "utils/timer.hpp"
#include <algorithm> // std::min_element
#include <cmath>
#include <iostream>
#include <iterator>
#include <map>
#include <numeric>
#include <optional>
#include <tuple>
#include <vector>
template <typename nrgcore_type> // nrgcore_type is a type of
// We don't want to inherit the nrgcore_type.
// Just want to use few of its objects as a pointer
// We don't want to reference to any specific model here.
//
// Warning: this class DOES NOT take care of the fermion sign.
// You need to provide the operator with sign
// TODO(sp): : kBt != 0 and a = b^\dag
class fdmSpectrum {
nrgcore_type *nrg_object;
double kBT{0}; // Temperature of nrg system i.e., in FDM formalism
public:
// fdmSpectrum() {}
explicit fdmSpectrum(nrgcore_type *t_nrg_object // nrgcore_type
) {
setup(t_nrg_object);
}
void setup(nrgcore_type *t_nrg_object) {
lastiteration = true;
nrg_object = t_nrg_object;
globalGroundStateEnergy = 0; //= nrg_object->all_eigenvalue[0];
}
void calcSpectrum(double energyScale) {
energyRescale = energyScale;
// Clear the operator
setCurrentIndex();
setRhoZero();
rhoDotOperators();
setReduceDensityMatrix();
lastiteration = false;
}
void setReduceDensityMatrix() {
// timer t1("setReduceDensityMatrix");
// Set reducedRho
reducedRho.clear();
for (size_t i = 0; i < nrg_object->pre_sysmQ.size(); i++) {
reducedRho.push_back( //
qmatrix<>(nrg_object->eigenvaluesQ_kept_indices[i].size(),
nrg_object->eigenvaluesQ_kept_indices[i].size(), 0));
}
// Rotate the eigen basis
// #pragma omp parallel for
for (size_t i = 0; i < nrg_object->current_sysmQ.size(); i++) {
// U. rhoZero . U.T : TODO: check
rhoZero[i] = nrg_object->current_hamiltonQ[i].dot(
rhoZero[i].dot(nrg_object->current_hamiltonQ[i].cTranspose()));
}
// Set reducedRho
for (size_t i = 0; i < nrg_object->current_sysmQ.size(); i++) {
size_t kidx = 0;
for (auto kindex : nrg_object->coupled_nQ_index[i]) {
auto ii = kindex / nrg_object->nq_bath.size(); // impurity nqi index
auto bb = kindex % nrg_object->nq_bath.size(); // bath nqi index
// create previous bath id matrix
// TODO(sp): Add parallelization here
for (size_t it : nrg_object->eigenvaluesQ_kept_indices[ii]) {
for (size_t it_p : nrg_object->eigenvaluesQ_kept_indices[ii]) {
double aa{0};
for (size_t il = 0; il < nrg_object->bath_eigenvaluesQ[bb].size();
il++) {
aa += rhoZero[i].at(
kidx + it +
nrg_object->eigenvaluesQ_kept_indices[ii].size() * il,
kidx + it_p +
nrg_object->eigenvaluesQ_kept_indices[ii].size() * il);
}
reducedRho[ii].at(it, it_p) += aa;
}
}
kidx += nrg_object->eigenvaluesQ_kept_indices[ii].size() *
nrg_object->bath_eigenvaluesQ[bb].size();
}
// End of matrix generation.
}
}
void setLocalPartitionFunction() {
localGroundStateEnergy = 0;
localPartitionFunction = 0; // Ground state degenarecy
for (auto &aa : nrg_object->eigenvaluesQ) {
if (aa.size() != 0) {
double result = *std::min_element(aa.begin(), aa.end());
localGroundStateEnergy = std::min(localGroundStateEnergy, result);
}
}
for (size_t i = 0; i < nrg_object->current_sysmQ.size(); i++) {
for (size_t ie = 0; ie < nrg_object->eigenvaluesQ[i].size(); ie++) {
double energy =
std::fabs(nrg_object->eigenvaluesQ[i][ie] - localGroundStateEnergy);
if (energy < energyErrorBar) {
localPartitionFunction += 1.;
}
}
} //
// std::cout << "localGroundStateEnergy" << localGroundStateEnergy
// << " localPartitionFunction: " << localPartitionFunction
// << std::endl;
BoltzmannFactor = nrg_object->eigenvaluesQ;
for (size_t i = 0; i < nrg_object->current_sysmQ.size(); i++) {
for (size_t ie = 0; ie < nrg_object->eigenvaluesQ[i].size(); ie++) {
double energy =
std::fabs(nrg_object->eigenvaluesQ[i][ie] - localGroundStateEnergy);
if (energy < energyErrorBar) {
BoltzmannFactor[i][ie] = 1. / localPartitionFunction;
} else {
BoltzmannFactor[i][ie] = 0;
}
}
} //
}
std::vector<std::vector<double>> BoltzmannFactor;
void setRhoZero() {
if (lastiteration) {
setLocalPartitionFunction();
}
double rhoTrace{0};
// Calc partition function of the shell ::
vecPartitions.push_back(localPartitionFunction);
rhoZero.clear();
for (size_t i = 0; i < nrg_object->current_sysmQ.size(); i++) {
size_t kpdim = nrg_object->eigenvaluesQ[i].size();
// std::cout << "--------------------------";
// std::cout << "idx" << idx << " idx_p" << idx_p << std::endl;
qmatrix<> tmat(kpdim, kpdim, 0);
// Discarded states
if (lastiteration) { // Only for the laast iterationT= 0
for (size_t ie = 0; ie < nrg_object->eigenvaluesQ[i].size(); ie++) {
tmat(ie, ie) = BoltzmannFactor[i][ie];
}
}
// Kept states
if (!reducedRho.empty()) { // Condition for the last Wilson site
// Just Override the kept states
for (auto ik : currentKeptIndex[i]) {
for (auto ikp : currentKeptIndex[i]) {
tmat(ik, ikp) = reducedRho[i](ik, ikp);
}
}
}
rhoTrace += tmat.trace();
// Save the matrix
rhoZero.push_back(tmat);
}
std::cout << "rhoTrace: " << rhoTrace << std::endl;
// move the operator
} // End of update_system_operatorQ
void rhoDotOperators() { // NOLINT
double specSum = 0.0;
//
for (size_t i = 0; i < nrg_object->current_sysmQ.size(); i++) {
for (size_t j = 0; j < nrg_object->current_sysmQ.size(); j++) {
size_t kpdim = nrg_object->eigenvaluesQ[i].size();
size_t kpdim_p = nrg_object->eigenvaluesQ[j].size();
// std::cout << "--------------------------";
// std::cout << "idx" << idx << " idx_p" << idx_p << std::endl;
// TODO(sp): This
for (size_t ip = 0; ip < bOperator->size(); ip++) {
auto sys_opr_opt = (*bOperator)[ip].get(i, j);
if (sys_opr_opt) {
auto *sys_opr = sys_opr_opt.value();
qmatrix<> aMatrix;
if (aOperator == nullptr) {
aMatrix = sys_opr_opt.value()->cTranspose();
} // Else this should be just boperator
// set kept-kept part operator
for (auto iv : currentKeptIndex[i]) {
for (auto iv_p : currentKeptIndex[j]) {
aMatrix.at(iv_p, iv) = 0;
}
}
auto rhoA = sys_opr->dot(rhoZero[j]);
auto ARho = rhoZero[i].dot(*sys_opr);
for (size_t iv = 0; iv < kpdim; iv++) {
for (size_t iv_p = 0; iv_p < kpdim_p; iv_p++) {
double aa{0};
double bbv{0};
// for (size_t iv_pp = 0; iv_pp < kpdim_p; iv_pp++) {
// aa += sys_opr->at(iv, iv_pp) * rhoZero[j](iv_pp, iv_p);
//}
// for (size_t iv_pp = 0; iv_pp < kpdim; iv_pp++) {
// bbv += rhoZero[i](iv, iv_pp) * sys_opr->at(iv_pp, iv_p);
//}
aa = rhoA(iv, iv_p) * aMatrix.at(iv_p, iv);
bbv = ARho(iv, iv_p) * aMatrix.at(iv_p, iv);
int tmindex = int(
std::log(1 +
(std::fabs(energyRescale *
(nrg_object->eigenvaluesQ[i][iv] -
nrg_object->eigenvaluesQ[j][iv_p])) /
minEnergy)) *
delE);
if (tmindex < energyPts && tmindex >= 0) {
if (std::fabs(aa) > spWeightErrorBar) {
positiveWeight[ip][tmindex] += std::fabs(aa);
specSum += std::fabs(aa);
// std::cout << "Raw: " << tmindex << " " << std::fabs(aa)
// << " " << std::fabs(bbv) << std::endl;
}
if (std::fabs(bbv) > spWeightErrorBar) {
negativeWeight[ip][tmindex] += std::fabs(bbv);
specSum += std::fabs(bbv);
}
}
}
}
}
}
// all the matrices are set
}
}
std::cout << nrg_object->nrg_iterations_cnt << "specSum: " << specSum
<< " Scale: " << energyRescale << std::endl;
// set the matrix elements
// end of lm loop
// End of matrix generation.
// Rotate the c operator in the eigen basis
}
//
void setTemperature(double at) { kBT = at; }
void setCurrentIndex() {
if (currentKeptIndex.empty()) {
for (size_t i = 0; i < nrg_object->current_sysmQ.size(); i++) {
currentKeptIndex.emplace_back();
}
} else {
currentKeptIndex = previoudKeptIndex;
}
previoudKeptIndex = nrg_object->eigenvaluesQ_kept_indices;
}
void setOperator(std::vector<qOperator> *bopr,
std::vector<qOperator> *aopr = nullptr) {
aOperator = aopr;
bOperator = bopr;
for (size_t i = 0; i < bOperator->size(); i++) {
positiveWeight.emplace_back(energyPts, 0);
negativeWeight.emplace_back(energyPts, 0);
}
}
template <typename filetype> void saveFinalData(filetype *pfile) {
std::vector<double> energyPoints(energyPts, 0);
for (int i = 0; i < energyPts; i++) {
energyPoints[i] = (minEnergy * std::exp(i * 1. / delE));
}
std::string hstr = "GreenFn";
pfile->write(energyPoints, hstr + "EnergyPoints");
pfile->write(positiveWeight, hstr + "PositiveWeight");
pfile->write(negativeWeight, hstr + "NegativeWeight");
for (size_t i = 0; i < bOperator->size(); i++) {
positiveWeight[i].clear();
negativeWeight[i].clear();
}
// pfile->write(vecPartitions, "vecPartitions");
}
private:
double localGroundStateEnergy{0};
double localPartitionFunction{0}; // Ground state degenarecy
std::vector<std::vector<size_t>> previoudKeptIndex;
double spWeightErrorBar{1e-20}; // We dont care for the lower value
double globalGroundStateEnergy{0};
std::vector<qmatrix<>> reducedRho;
std::vector<double> vecPartitions;
// rho.B and B.rho
std::vector<std::vector<double>> positiveWeight;
std::vector<std::vector<double>> negativeWeight;
// value
int energyPts = 100000;
double maxEnergy = 10; // One decade more
double minEnergy = 1e-10;
double delE = (energyPts - 1.0) / (std::log(maxEnergy / minEnergy));
public: // Give access for openchain class
std::vector<std::vector<size_t>> currentKeptIndex;
std::vector<qmatrix<>> rhoZero;
std::vector<qOperator> *aOperator{};
std::vector<qOperator> *bOperator{};
bool lastiteration{true};
double energyRescale{1};
double energyErrorBar{1e-5};
};