346 lines
12 KiB
C++
346 lines
12 KiB
C++
/**********************************************************
|
|
|
|
This software is part of J.-S. Caux's ABACUS library.
|
|
|
|
Copyright (c) J.-S. Caux.
|
|
|
|
-----------------------------------------------------------
|
|
|
|
File: NRG_State_Selector.cc
|
|
|
|
Purpose: select states for numerical RG method,
|
|
collaboration with Robert Konik.
|
|
|
|
***********************************************************/
|
|
|
|
#include "ABACUS.h"
|
|
|
|
using namespace std;
|
|
using namespace ABACUS;
|
|
|
|
namespace ABACUS {
|
|
|
|
DP Estimate_Contribution_of_Single_ph_Annihilation_Path_to_2nd_Order_PT (LiebLin_Bethe_State& TopState,
|
|
LiebLin_Bethe_State& GroundState,
|
|
Vect<complex <DP> >& FT_of_potential)
|
|
{
|
|
DP contrib_estimate = 0.0;
|
|
|
|
// Define OriginIx2 for labelling:
|
|
Vect<int> OriginIx2 = GroundState.Ix2;
|
|
|
|
// Calculate the number of particles in this state:
|
|
State_Label_Data topdata = Read_State_Label (TopState.label, OriginIx2);
|
|
int nphpairs = topdata.nexc[0];
|
|
|
|
if (nphpairs == 0) ABACUSerror("Trying to annihilate ground state in Estimate_Contribution...");
|
|
|
|
|
|
DP densityME = real(exp(ln_Density_ME (GroundState, TopState)));
|
|
if (is_nan(densityME)) {
|
|
cout << "ME is nan: label = " << TopState.label << endl;
|
|
ABACUSerror("ME didn't return value.");
|
|
}
|
|
|
|
int nr_cont = 0;
|
|
|
|
// Add first-order PT contribution, and 2nd order from ground state (V_{00} == 1)
|
|
contrib_estimate += abs(FT_of_potential[FT_of_potential.size()/2 + (TopState.iK - GroundState.iK)]
|
|
* (densityME/(GroundState.E - TopState.E))
|
|
* (1.0 - (GroundState.N/GroundState.L)/(GroundState.E - TopState.E)));
|
|
|
|
nr_cont++;
|
|
|
|
// Add second order PT contribution coming from TopState:
|
|
contrib_estimate += abs(FT_of_potential[FT_of_potential.size()/2 + 0]
|
|
* FT_of_potential[FT_of_potential.size()/2 + (TopState.iK - GroundState.iK)]
|
|
* 1.0 * densityME * (GroundState.N/GroundState.L) // 1.0 is V_{TopState, TopState}
|
|
/((GroundState.E - TopState.E) * (GroundState.E - TopState.E)));
|
|
|
|
nr_cont++;
|
|
|
|
// Now add 2nd order terms coming from single particle-hole annihilation paths:
|
|
// this is only to be included for states with at least 4 excitations (2 ph pairs)
|
|
if (nphpairs >= 2) {
|
|
|
|
for (int ipart = 0; ipart < nphpairs; ++ipart) {
|
|
for (int ihole = 0; ihole < nphpairs; ++ihole) {
|
|
|
|
LiebLin_Bethe_State DescendedState = TopState;
|
|
DescendedState.Annihilate_ph_pair(ipart, ihole, OriginIx2);
|
|
DescendedState.Compute_All(true);
|
|
|
|
DP densityME_top_desc = real(exp(ln_Density_ME (TopState, DescendedState)));
|
|
DP densityME_desc_ground = real(exp(ln_Density_ME (DescendedState, GroundState)));
|
|
|
|
// if intermediate state has momentum within allowable window, OK, otherwise discard contribution:
|
|
if (abs(TopState.iK - DescendedState.iK) < FT_of_potential.size()/2 &&
|
|
abs(DescendedState.iK - GroundState.iK) < FT_of_potential.size()/2) {
|
|
|
|
contrib_estimate += abs(FT_of_potential[FT_of_potential.size()/2 + (TopState.iK - DescendedState.iK)]
|
|
* FT_of_potential[FT_of_potential.size()/2 + (DescendedState.iK - GroundState.iK)]
|
|
* densityME_top_desc * densityME_desc_ground
|
|
/((GroundState.E - TopState.E) * (GroundState.E - DescendedState.E)));
|
|
|
|
nr_cont++;
|
|
}
|
|
|
|
if (nphpairs >= 3) { // go one step further
|
|
for (int ipart2 = ipart; ipart2 < nphpairs - 1; ++ipart2) {
|
|
for (int ihole2 = ihole; ihole2 < nphpairs - 1; ++ihole2) {
|
|
|
|
LiebLin_Bethe_State DescendedState2 = DescendedState;
|
|
DescendedState2.Annihilate_ph_pair(ipart2, ihole2, OriginIx2);
|
|
DescendedState2.Compute_All(true);
|
|
|
|
DP densityME_top_desc2 = real(exp(ln_Density_ME (TopState, DescendedState2)));
|
|
DP densityME_desc2_ground = real(exp(ln_Density_ME (DescendedState2, GroundState)));
|
|
|
|
// if intermediate state has momentum within allowable window, OK, otherwise discard contribution:
|
|
if (abs(TopState.iK - DescendedState2.iK) < FT_of_potential.size()/2 &&
|
|
abs(DescendedState2.iK - GroundState.iK) < FT_of_potential.size()/2) {
|
|
|
|
contrib_estimate += abs(FT_of_potential[FT_of_potential.size()/2 + (TopState.iK - DescendedState2.iK)]
|
|
* FT_of_potential[FT_of_potential.size()/2 + (DescendedState2.iK - GroundState.iK)]
|
|
* densityME_top_desc2 * densityME_desc2_ground
|
|
/((GroundState.E - TopState.E) * (GroundState.E - DescendedState2.E)));
|
|
|
|
nr_cont++;
|
|
}
|
|
|
|
if (nphpairs >= 4) { // go one step further
|
|
for (int ipart3 = ipart2; ipart3 < nphpairs - 2; ++ipart3) {
|
|
for (int ihole3 = ihole2; ihole3 < nphpairs - 2; ++ihole3) {
|
|
|
|
LiebLin_Bethe_State DescendedState3 = DescendedState2;
|
|
DescendedState3.Annihilate_ph_pair(ipart3, ihole3, OriginIx2);
|
|
DescendedState3.Compute_All(true);
|
|
|
|
DP densityME_top_desc3 = real(exp(ln_Density_ME (TopState, DescendedState3)));
|
|
DP densityME_desc3_ground = real(exp(ln_Density_ME (DescendedState3, GroundState)));
|
|
|
|
// if intermediate state has momentum within allowable window, OK, otherwise discard contribution:
|
|
if (abs(TopState.iK - DescendedState3.iK) < FT_of_potential.size()/2 &&
|
|
abs(DescendedState3.iK - GroundState.iK) < FT_of_potential.size()/2) {
|
|
|
|
contrib_estimate += abs(FT_of_potential[FT_of_potential.size()/2 + (TopState.iK - DescendedState3.iK)]
|
|
* FT_of_potential[FT_of_potential.size()/2
|
|
+ (DescendedState3.iK - GroundState.iK)]
|
|
* densityME_top_desc3 * densityME_desc3_ground
|
|
/((GroundState.E - TopState.E) * (GroundState.E - DescendedState3.E)));
|
|
|
|
nr_cont++;
|
|
}
|
|
|
|
} // for ihole3
|
|
} // for ipart3
|
|
} // if (nphpairs >= 4)
|
|
} // for ihole2
|
|
} // for ipart2
|
|
} // if (nphpairs >= 3)
|
|
|
|
} // for ihole
|
|
} // for ipart
|
|
} // if nphpairs >= 2
|
|
|
|
return(contrib_estimate);
|
|
}
|
|
|
|
|
|
void Select_States_for_NRG (DP c_int, DP L, int N, int iKmin, int iKmax, int Nstates_required,
|
|
bool symmetric_states, int iKmod, int weighing_option, Vect<complex <DP> >& FT_of_potential)
|
|
{
|
|
// This function reads an existing partition function file and determines whether
|
|
// each state is to be included in NRG by applying an energy, momentum and form factor criterion.
|
|
|
|
// The weighing function flag determines what kind of ordering is required:
|
|
// weighing_option == 0: ordering in energy
|
|
// weighing_option == 1: ordering according to perturbation theory in single p-h annihilation path
|
|
// weighing_option == 2: same as 1, but output of list is ordered in weight
|
|
|
|
stringstream filenameprefix;
|
|
Data_File_Name (filenameprefix, 'Z', c_int, L, N, iKmin, iKmax, 0.0, 0.0, "");
|
|
string prefix = filenameprefix.str();
|
|
stringstream RAW_stringstream; string RAW_string;
|
|
RAW_stringstream << prefix << ".raw";
|
|
|
|
stringstream NRG_stringstream; string NRG_string;
|
|
NRG_stringstream << "States_c_" << c_int << "_L_" << L << "_N_" << N
|
|
<< "_iKmin_" << iKmin << "_iKmax_" << iKmax << "_Nstates_" << Nstates_required
|
|
<< "_Sym_" << symmetric_states << "_iKmod_" << iKmod << "_wopt_" << weighing_option << ".nrg";
|
|
|
|
|
|
RAW_string = RAW_stringstream.str();
|
|
const char* RAW_Cstr = RAW_string.c_str();
|
|
|
|
NRG_string = NRG_stringstream.str();
|
|
const char* NRG_Cstr = NRG_string.c_str();
|
|
|
|
ifstream infile;
|
|
infile.open(RAW_Cstr);
|
|
|
|
if (infile.fail()) {
|
|
cout << RAW_Cstr << endl;
|
|
ABACUSerror("The input file was not opened successfully in Select_States_for_NRG. ");
|
|
}
|
|
|
|
ofstream NRG_outfile;
|
|
|
|
NRG_outfile.open(NRG_Cstr);
|
|
if (NRG_outfile.fail()) ABACUSerror("Could not open NRG_outfile... ");
|
|
|
|
NRG_outfile.precision(16);
|
|
|
|
|
|
// Read the whole data file:
|
|
|
|
// Count the number of entries in raw file:
|
|
int estimate_nr_entries = 0;
|
|
string line;
|
|
while (!infile.eof()) {
|
|
getline(infile, line);
|
|
estimate_nr_entries++;
|
|
}
|
|
const int MAXDATA = estimate_nr_entries;
|
|
|
|
DP* E = new DP[MAXDATA];
|
|
int* iK = new int[MAXDATA];
|
|
string* label = new string[MAXDATA];
|
|
bool* sym = new bool[MAXDATA];
|
|
|
|
int Ndata = 0;
|
|
|
|
infile.close();
|
|
infile.open(RAW_Cstr);
|
|
|
|
while (((infile.peek()) != EOF) && (Ndata < MAXDATA)) {
|
|
infile >> E[Ndata];
|
|
infile >> iK[Ndata];
|
|
infile >> label[Ndata];
|
|
Ndata++;
|
|
}
|
|
|
|
infile.close();
|
|
|
|
// Define the ground state:
|
|
LiebLin_Bethe_State GroundState (c_int, L, N);
|
|
GroundState.Compute_All(true);
|
|
|
|
// Define OriginIx2 for labelling:
|
|
Vect<int> OriginIx2 = GroundState.Ix2;
|
|
|
|
Scan_State_List<LiebLin_Bethe_State> ScanStateList ('d', GroundState);
|
|
|
|
// Build the momentum-dependent weight integral matrix:
|
|
|
|
// To cover negative and positive momenta (in case potential is not symmetric),
|
|
// we define the Weight_integral vector entry with index size/2 as corresponding to iK == 0.
|
|
|
|
// Calculate weight of states using selection criterion function
|
|
|
|
DP* weight = new DP[Ndata];
|
|
|
|
// For weighing using 2nd order PT, we only trace over 2 excitation states (1 p-h pair)
|
|
// Start by constructing these four classes once and for all:
|
|
|
|
for (int i = 0; i < Ndata; ++i) {
|
|
|
|
if (abs(iK[i]) % iKmod != 0) { // if iK not a multiple of iKmod: give stupidly high weight.
|
|
weight[i] = 1.0e+100;
|
|
sym[i] = false; // doesn't matter
|
|
}
|
|
|
|
else {
|
|
|
|
// Construct the state again, so that the density ME can be calculated
|
|
LiebLin_Bethe_State ScanState = ScanStateList.Return_State(Extract_Base_Label(label[i]));
|
|
ScanState.Set_to_Label (label[i]);
|
|
if (weighing_option == 1 || weighing_option == 2) ScanState.Compute_All(true);
|
|
sym[i] = ScanState.Check_Symmetry();
|
|
|
|
State_Label_Data currentdata = Read_State_Label (label[i], OriginIx2);
|
|
if (currentdata.nexc[0] == 0) weight[i] = 0.0;
|
|
|
|
else if (symmetric_states && iK[i] < 0 || iK[i] < iKmin || iK[i] > iKmax) weight[i] = 1.0e+100;
|
|
|
|
else if (symmetric_states && iK[i] == 0 && !sym[i]) {
|
|
// This state is at zero momentum but not symmetric. we keep it only if
|
|
// the first non-symmetric pair of quantum numbers is right-weighted:
|
|
int icheck = 0;
|
|
while (ScanState.Ix2[N-1-icheck] == -ScanState.Ix2[icheck]) icheck++;
|
|
if (ScanState.Ix2[N-1-icheck] > -ScanState.Ix2[icheck]) {
|
|
if (weighing_option == 0) weight[i] = E[i];
|
|
else if (weighing_option == 1 || weighing_option == 2)
|
|
weight[i] = 1.0/(1.0e-100 + fabs(Estimate_Contribution_of_Single_ph_Annihilation_Path_to_2nd_Order_PT
|
|
(ScanState, GroundState, FT_of_potential)));
|
|
}
|
|
else weight[i] = 1.0e+100;
|
|
}
|
|
|
|
else {
|
|
if (weighing_option == 0) weight[i] = E[i];
|
|
else if (weighing_option == 1 || weighing_option == 2)
|
|
weight[i] = 1.0/(1.0e-100 + fabs(Estimate_Contribution_of_Single_ph_Annihilation_Path_to_2nd_Order_PT
|
|
(ScanState, GroundState, FT_of_potential)));
|
|
}
|
|
}
|
|
} // for i
|
|
|
|
// Now order the states in increasing weight
|
|
|
|
int* index = new int[Ndata];
|
|
for (int i = 0; i < Ndata; ++i) index[i] = i;
|
|
|
|
QuickSort(weight, index, 0, Ndata - 1);
|
|
|
|
// Select states by increasing weight, with a max of Nstates_required entries
|
|
|
|
DP* E_kept = new DP[Nstates_required];
|
|
int* iK_kept = new int[Nstates_required];
|
|
string* label_kept = new string[Nstates_required];
|
|
bool* sym_kept = new bool[Nstates_required];
|
|
DP* weight_kept = new DP[Nstates_required];
|
|
|
|
// Copy selected states into new vectors:
|
|
for (int i = 0; i < ABACUS::min(Ndata, Nstates_required); ++i) {
|
|
E_kept[i] = E[index[i] ];
|
|
iK_kept[i] = iK[index[i] ];
|
|
//conv_kept[i] = conv[index[i] ];
|
|
label_kept[i] = label[index[i] ];
|
|
sym_kept[i] = sym[index[i] ];
|
|
weight_kept[i] = weight[i];
|
|
}
|
|
|
|
|
|
// If needed, order selected states by increasing energy:
|
|
int* index_kept = new int[Nstates_required];
|
|
for (int i = 0; i < Nstates_required; ++i) index_kept[i] = i;
|
|
|
|
if (weighing_option == 1) // only need to do this if energy ordering is chosen
|
|
QuickSort (E_kept, index_kept, 0, Nstates_required - 1);
|
|
|
|
// Output selected states:
|
|
for (int i = 0; i < Nstates_required; ++i) {
|
|
if (i > 0) NRG_outfile << endl;
|
|
NRG_outfile << i << "\t" << E_kept[i] << "\t" << iK_kept[index_kept[i] ]
|
|
<< "\t" << label_kept[index_kept[i] ]
|
|
<< "\t" << sym_kept[index_kept[i] ] << "\t" << weight_kept[index_kept[i] ];
|
|
}
|
|
|
|
delete[] E;
|
|
delete[] iK;
|
|
delete[] label;
|
|
delete[] sym;
|
|
delete[] E_kept;
|
|
delete[] iK_kept;
|
|
delete[] label_kept;
|
|
delete[] sym_kept;
|
|
delete[] weight;
|
|
|
|
NRG_outfile.close();
|
|
|
|
return;
|
|
}
|
|
|
|
} // namespace ABACUS
|