Program Listing for File fdmThermodynamics.hpp#
↰ Return to documentation for file (static/fdmThermodynamics.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 <utility>
#include <vector>
//
template <typename nrgcore_type> //
class fdmThermodynamics {
nrgcore_type *nrg_object;
int nrgMaxIterations;
size_t bathDimension{0};
std::vector<qOperator> *qsysOPerator{nullptr};
std::vector<std::vector<std::map<size_t, double>>> qsysOPeratorValue;
std::vector<double> temperatureArray;
// Temperature of nrg system i.e., in FDM formalism
public:
explicit fdmThermodynamics(nrgcore_type *t_nrg_object // nrgcore_type
,
std::vector<double> tArray)
: nrg_object(t_nrg_object),
nrgMaxIterations(t_nrg_object->nrg_iterations_cnt),
temperatureArray(std::move(tArray)) {
// Set bathDimension
for (auto &it : t_nrg_object->bath_eigenvaluesQ) {
bathDimension += it.size();
}
std::cout << "bathDimension: " << bathDimension << std::endl;
// Resize the results array
}
void setSystemOperator(std::vector<qOperator> *qsysOPerator_) {
qsysOPerator = qsysOPerator_;
}
void calcThermodynamics(double energyRescale) { // NOLINT
std::cout << "energyRescale" << energyRescale << std::endl;
setCurrentKeptIndex();
std::vector<double> eigVal;
// Sum Discarded states only
for (int i = 0; i < nrg_object->eigenvaluesQ.size(); i++) {
for (size_t j = currentKeptIndex[i].size();
j < nrg_object->eigenvaluesQ[i].size(); j++) {
eigVal.push_back(nrg_object->eigenvaluesQ[i][j] * energyRescale);
}
}
std::cout << "Number of eigen Values: " << eigVal.size() << std::endl;
discardedEigValues.push_back(eigVal);
eigVal.clear();
// add all states
for (int i = 0; i < nrg_object->eigenvaluesQ.size(); i++) {
for (size_t j = 0; j < nrg_object->eigenvaluesQ[i].size(); j++) {
eigVal.push_back(nrg_object->eigenvaluesQ[i][j] * energyRescale);
}
}
allEigValues.push_back(eigVal);
// Save the expectation value of the system operator
if (qsysOPerator != nullptr) {
std::vector<std::map<size_t, double>> qvalue(qsysOPerator->size());
for (size_t iq = 0; iq < qsysOPerator->size(); iq++) {
size_t icounter{0};
for (int i = 0; i < nrg_object->eigenvaluesQ.size(); i++) {
auto qopr = qsysOPerator->at(iq).get(i, i);
if (qopr) {
auto *qmat = qopr.value();
for (size_t j = currentKeptIndex[i].size();
// Only discarded states are saved
j < nrg_object->eigenvaluesQ[i].size(); j++) {
if (icounter + j - currentKeptIndex[i].size() >=
discardedEigValues.back().size()) {
std::cout << "icounter: " << icounter << std::endl;
}
qvalue[iq][icounter + j - currentKeptIndex[i].size()] =
qmat->at(j, j);
}
}
icounter +=
(nrg_object->eigenvaluesQ[i].size() - currentKeptIndex[i].size());
}
}
qsysOPeratorValue.push_back(qvalue);
}
}
//
void setCurrentKeptIndex() {
if (currentKeptIndex.empty()) { // Condition only satisfy at last iteration
for (size_t i = 0; i < nrg_object->current_sysmQ.size(); i++) {
currentKeptIndex.emplace_back();
}
} else {
currentKeptIndex = previoudKeptIndex;
}
previoudKeptIndex = nrg_object->eigenvaluesQ_kept_indices;
}
template <typename filetype> void saveFinalData(filetype *pfile) { // NOLINT
// do the Calculation
// get the Shifted the eigen energies
// for (size_t iq = 0; iq < qsysOPerator->size(); iq++) {
// for (size_t id = 0; id < discardedEigValues.size(); id++) {
// std::cout << "Itr: ";
// for (auto const &[ie, qval] : qsysOPeratorValue[id][iq]) {
// std::cout << qval << " ";
// }
// std::cout << std::endl;
// }
// }
//
std::vector<double> groundStateEnergyArr(allEigValues.size(), 0);
for (int it = 0; it < allEigValues.size(); it++) {
double result =
*std::min_element(allEigValues[it].begin(), allEigValues[it].end());
// shift the energy of the discarded states wrt the ground state
std::transform(discardedEigValues[it].begin(),
discardedEigValues[it].end(),
discardedEigValues[it].begin(),
[result](double x) { return x - result; });
// shift the energy of the discarded states wrt the ground state
groundStateEnergyArr[it] = result;
// std::cout << it << " " << allEigValues[it];
std::cout << it << " " << result << " "
<< *std::max_element(allEigValues[it].begin(),
allEigValues[it].end())
<< std::endl;
// Collect true groumd state
}
// correct wrt last iteration
for (size_t it = 0; it < groundStateEnergyArr.size() - 1; it++) {
groundStateEnergyArr[it] += groundStateEnergyArr[it + 1];
}
//
std::cout << "|Ground State Energy|: " << groundStateEnergyArr << std::endl;
double gren = groundStateEnergyArr[0]; // Ground state energy of the
// last iteration
std::transform(groundStateEnergyArr.begin(), groundStateEnergyArr.end(),
groundStateEnergyArr.begin(),
[gren](double aa) { return aa - gren; });
std::cout << "|Ground State Energy|: " << groundStateEnergyArr << std::endl;
// finish the final Calc
std::vector<double> specificHeat(temperatureArray.size(), 0.0);
std::vector<double> entropy(temperatureArray.size(), 0.0);
std::vector<std::vector<double>> qsysOPeratorExpValue;
if (qsysOPerator != nullptr) {
qsysOPeratorExpValue.resize(
qsysOPerator->size(),
std::vector<double>(temperatureArray.size(), 0.0));
}
std::cout << "Done " << std::endl;
for (int itm = 0; itm < temperatureArray.size(); itm++) {
double kBT = temperatureArray[itm];
// calc partition Function
auto nrgCount = nrgMaxIterations;
// calculate w_m first
std::vector<double> wm(discardedEigValues.size(), 0);
std::vector<double> ZmPrime(discardedEigValues.size(), 0);
for (size_t id = 0; id < discardedEigValues.size(); id++) {
double prefac = std::pow(bathDimension, nrgMaxIterations - nrgCount);
double zi = 0;
for (auto &aa : discardedEigValues[id]) {
zi += regulateExp((groundStateEnergyArr[id] - aa) / kBT);
}
nrgCount--;
wm[id] = zi * prefac;
ZmPrime[id] = zi;
}
// calculate partition function
double lpart = std::accumulate(wm.begin(), wm.end(), 0.0);
for (auto &aa : wm) {
aa = aa / lpart;
}
std::cout << "Done 2" << std::endl;
// Normalize w_m
double eAv = 0;
// Average Energy
double eSqAv = 0;
for (size_t id = 0; id < discardedEigValues.size(); id++) {
for (auto &aa : discardedEigValues[id]) {
double blm =
regulateExp((groundStateEnergyArr[id] - aa) / kBT) / ZmPrime[id];
eAv += (aa - groundStateEnergyArr[id]) * wm[id] * blm;
eSqAv += (aa - groundStateEnergyArr[id]) *
(aa - groundStateEnergyArr[id]) * wm[id] * blm;
}
}
// // calc qsysOPeratorExpValue
if (qsysOPerator != nullptr) {
for (size_t iq = 0; iq < qsysOPerator->size(); iq++) {
double tvalue = 0;
for (size_t id = 0; id < discardedEigValues.size(); id++) {
std::cout << "Itr: " << iq << " "
<< qsysOPeratorValue[id][iq].size() << std::endl;
for (auto const &[ie, qval] : qsysOPeratorValue[id][iq]) {
if (ie >= discardedEigValues[id].size()) {
std::cout << "Error: " << ie << " "
<< discardedEigValues[id].size() << std::endl;
}
double blm = regulateExp((groundStateEnergyArr[id] -
discardedEigValues[id][ie]) /
kBT) /
ZmPrime[id];
tvalue += qval * wm[id] * blm;
}
}
qsysOPeratorExpValue[iq][itm] = tvalue;
}
}
std::cout << "Done 3" << std::endl;
// calc entropy
if (itm == 0) {
// std::cout << "DiscardedEigValues: "
// << discardedEigValues[0] << std::endl;
std::cout << "W_m : " << wm << std::endl;
std::cout << "kbt" << kBT << std::endl;
std::cout << "eAv: " << eAv << std::endl;
std::cout << "eSqAv: " << eSqAv << std::endl;
std::cout << "Entropy :" << std::log(lpart) + (eAv / kBT) << std::endl;
std::cout << "partitionFunctionArray[i]: " << lpart << std::endl;
}
entropy[itm] = std::log(lpart) + (eAv / kBT);
specificHeat[itm] = (eSqAv - eAv * eAv) / (kBT * kBT);
}
// Save the data
std::string hstr;
pfile->write(temperatureArray, hstr + "temperatureArray");
pfile->write(entropy, hstr + "entropy");
pfile->write(specificHeat, hstr + "specificHeat");
if (qsysOPerator != nullptr) {
pfile->write(qsysOPeratorExpValue, hstr + "qsysOPeratorExpValue");
}
// pfile->write(vecPartitions, "vecPartitions");
}
private:
double maxExpNumber = 100;
double regulateExp(double x) {
if (x > 100) {
return std::exp(100);
}
if (x < -100) {
// return 0;
return std::exp(-100);
}
return std::exp(x);
}
// Results
//
//
std::vector<std::vector<size_t>> previoudKeptIndex;
// rho.B and B.rho
std::vector<std::vector<double>> discardedEigValues;
std::vector<std::vector<double>> allEigValues;
// value
public: // Give access for openchain class
std::vector<std::vector<size_t>> currentKeptIndex;
};