You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

NRG_State_Selector.cc 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. /**********************************************************
  2. This software is part of J.-S. Caux's ABACUS library.
  3. Copyright (c) J.-S. Caux.
  4. -----------------------------------------------------------
  5. File: NRG_State_Selector.cc
  6. Purpose: select states for numerical RG method,
  7. collaboration with Robert Konik.
  8. ***********************************************************/
  9. #include "ABACUS.h"
  10. using namespace std;
  11. using namespace ABACUS;
  12. namespace ABACUS {
  13. DP Estimate_Contribution_of_Single_ph_Annihilation_Path_to_2nd_Order_PT (LiebLin_Bethe_State& TopState,
  14. LiebLin_Bethe_State& GroundState,
  15. Vect<complex <DP> >& FT_of_potential)
  16. {
  17. DP contrib_estimate = 0.0;
  18. // Define OriginIx2 for labelling:
  19. Vect<int> OriginIx2 = GroundState.Ix2;
  20. // Calculate the number of particles in this state:
  21. State_Label_Data topdata = Read_State_Label (TopState.label, OriginIx2);
  22. int nphpairs = topdata.nexc[0];
  23. if (nphpairs == 0) ABACUSerror("Trying to annihilate ground state in Estimate_Contribution...");
  24. DP densityME = real(exp(ln_Density_ME (GroundState, TopState)));
  25. if (is_nan(densityME)) {
  26. cout << "ME is nan: label = " << TopState.label << endl;
  27. ABACUSerror("ME didn't return value.");
  28. }
  29. int nr_cont = 0;
  30. // Add first-order PT contribution, and 2nd order from ground state (V_{00} == 1)
  31. contrib_estimate += abs(FT_of_potential[FT_of_potential.size()/2 + (TopState.iK - GroundState.iK)]
  32. * (densityME/(GroundState.E - TopState.E))
  33. * (1.0 - (GroundState.N/GroundState.L)/(GroundState.E - TopState.E)));
  34. nr_cont++;
  35. // Add second order PT contribution coming from TopState:
  36. contrib_estimate += abs(FT_of_potential[FT_of_potential.size()/2 + 0]
  37. * FT_of_potential[FT_of_potential.size()/2 + (TopState.iK - GroundState.iK)]
  38. * 1.0 * densityME * (GroundState.N/GroundState.L) // 1.0 is V_{TopState, TopState}
  39. /((GroundState.E - TopState.E) * (GroundState.E - TopState.E)));
  40. nr_cont++;
  41. // Now add 2nd order terms coming from single particle-hole annihilation paths:
  42. // this is only to be included for states with at least 4 excitations (2 ph pairs)
  43. if (nphpairs >= 2) {
  44. for (int ipart = 0; ipart < nphpairs; ++ipart) {
  45. for (int ihole = 0; ihole < nphpairs; ++ihole) {
  46. LiebLin_Bethe_State DescendedState = TopState;
  47. DescendedState.Annihilate_ph_pair(ipart, ihole, OriginIx2);
  48. DescendedState.Compute_All(true);
  49. DP densityME_top_desc = real(exp(ln_Density_ME (TopState, DescendedState)));
  50. DP densityME_desc_ground = real(exp(ln_Density_ME (DescendedState, GroundState)));
  51. // if intermediate state has momentum within allowable window, OK, otherwise discard contribution:
  52. if (abs(TopState.iK - DescendedState.iK) < FT_of_potential.size()/2 &&
  53. abs(DescendedState.iK - GroundState.iK) < FT_of_potential.size()/2) {
  54. contrib_estimate += abs(FT_of_potential[FT_of_potential.size()/2 + (TopState.iK - DescendedState.iK)]
  55. * FT_of_potential[FT_of_potential.size()/2 + (DescendedState.iK - GroundState.iK)]
  56. * densityME_top_desc * densityME_desc_ground
  57. /((GroundState.E - TopState.E) * (GroundState.E - DescendedState.E)));
  58. nr_cont++;
  59. }
  60. if (nphpairs >= 3) { // go one step further
  61. for (int ipart2 = ipart; ipart2 < nphpairs - 1; ++ipart2) {
  62. for (int ihole2 = ihole; ihole2 < nphpairs - 1; ++ihole2) {
  63. LiebLin_Bethe_State DescendedState2 = DescendedState;
  64. DescendedState2.Annihilate_ph_pair(ipart2, ihole2, OriginIx2);
  65. DescendedState2.Compute_All(true);
  66. DP densityME_top_desc2 = real(exp(ln_Density_ME (TopState, DescendedState2)));
  67. DP densityME_desc2_ground = real(exp(ln_Density_ME (DescendedState2, GroundState)));
  68. // if intermediate state has momentum within allowable window, OK, otherwise discard contribution:
  69. if (abs(TopState.iK - DescendedState2.iK) < FT_of_potential.size()/2 &&
  70. abs(DescendedState2.iK - GroundState.iK) < FT_of_potential.size()/2) {
  71. contrib_estimate += abs(FT_of_potential[FT_of_potential.size()/2 + (TopState.iK - DescendedState2.iK)]
  72. * FT_of_potential[FT_of_potential.size()/2 + (DescendedState2.iK - GroundState.iK)]
  73. * densityME_top_desc2 * densityME_desc2_ground
  74. /((GroundState.E - TopState.E) * (GroundState.E - DescendedState2.E)));
  75. nr_cont++;
  76. }
  77. if (nphpairs >= 4) { // go one step further
  78. for (int ipart3 = ipart2; ipart3 < nphpairs - 2; ++ipart3) {
  79. for (int ihole3 = ihole2; ihole3 < nphpairs - 2; ++ihole3) {
  80. LiebLin_Bethe_State DescendedState3 = DescendedState2;
  81. DescendedState3.Annihilate_ph_pair(ipart3, ihole3, OriginIx2);
  82. DescendedState3.Compute_All(true);
  83. DP densityME_top_desc3 = real(exp(ln_Density_ME (TopState, DescendedState3)));
  84. DP densityME_desc3_ground = real(exp(ln_Density_ME (DescendedState3, GroundState)));
  85. // if intermediate state has momentum within allowable window, OK, otherwise discard contribution:
  86. if (abs(TopState.iK - DescendedState3.iK) < FT_of_potential.size()/2 &&
  87. abs(DescendedState3.iK - GroundState.iK) < FT_of_potential.size()/2) {
  88. contrib_estimate += abs(FT_of_potential[FT_of_potential.size()/2 + (TopState.iK - DescendedState3.iK)]
  89. * FT_of_potential[FT_of_potential.size()/2
  90. + (DescendedState3.iK - GroundState.iK)]
  91. * densityME_top_desc3 * densityME_desc3_ground
  92. /((GroundState.E - TopState.E) * (GroundState.E - DescendedState3.E)));
  93. nr_cont++;
  94. }
  95. } // for ihole3
  96. } // for ipart3
  97. } // if (nphpairs >= 4)
  98. } // for ihole2
  99. } // for ipart2
  100. } // if (nphpairs >= 3)
  101. } // for ihole
  102. } // for ipart
  103. } // if nphpairs >= 2
  104. return(contrib_estimate);
  105. }
  106. void Select_States_for_NRG (DP c_int, DP L, int N, int iKmin, int iKmax, int Nstates_required,
  107. bool symmetric_states, int iKmod, int weighing_option, Vect<complex <DP> >& FT_of_potential)
  108. {
  109. // This function reads an existing partition function file and determines whether
  110. // each state is to be included in NRG by applying an energy, momentum and form factor criterion.
  111. // The weighing function flag determines what kind of ordering is required:
  112. // weighing_option == 0: ordering in energy
  113. // weighing_option == 1: ordering according to perturbation theory in single p-h annihilation path
  114. // weighing_option == 2: same as 1, but output of list is ordered in weight
  115. stringstream filenameprefix;
  116. Data_File_Name (filenameprefix, 'Z', c_int, L, N, iKmin, iKmax, 0.0, 0.0, "");
  117. string prefix = filenameprefix.str();
  118. stringstream RAW_stringstream; string RAW_string;
  119. RAW_stringstream << prefix << ".raw";
  120. stringstream NRG_stringstream; string NRG_string;
  121. NRG_stringstream << "States_c_" << c_int << "_L_" << L << "_N_" << N
  122. << "_iKmin_" << iKmin << "_iKmax_" << iKmax << "_Nstates_" << Nstates_required
  123. << "_Sym_" << symmetric_states << "_iKmod_" << iKmod << "_wopt_" << weighing_option << ".nrg";
  124. RAW_string = RAW_stringstream.str();
  125. const char* RAW_Cstr = RAW_string.c_str();
  126. NRG_string = NRG_stringstream.str();
  127. const char* NRG_Cstr = NRG_string.c_str();
  128. ifstream infile;
  129. infile.open(RAW_Cstr);
  130. if (infile.fail()) {
  131. cout << RAW_Cstr << endl;
  132. ABACUSerror("The input file was not opened successfully in Select_States_for_NRG. ");
  133. }
  134. ofstream NRG_outfile;
  135. NRG_outfile.open(NRG_Cstr);
  136. if (NRG_outfile.fail()) ABACUSerror("Could not open NRG_outfile... ");
  137. NRG_outfile.precision(16);
  138. // Read the whole data file:
  139. // Count the number of entries in raw file:
  140. int estimate_nr_entries = 0;
  141. string line;
  142. while (!infile.eof()) {
  143. getline(infile, line);
  144. estimate_nr_entries++;
  145. }
  146. const int MAXDATA = estimate_nr_entries;
  147. DP* E = new DP[MAXDATA];
  148. int* iK = new int[MAXDATA];
  149. string* label = new string[MAXDATA];
  150. bool* sym = new bool[MAXDATA];
  151. int Ndata = 0;
  152. infile.close();
  153. infile.open(RAW_Cstr);
  154. while (((infile.peek()) != EOF) && (Ndata < MAXDATA)) {
  155. infile >> E[Ndata];
  156. infile >> iK[Ndata];
  157. infile >> label[Ndata];
  158. Ndata++;
  159. }
  160. infile.close();
  161. // Define the ground state:
  162. LiebLin_Bethe_State GroundState (c_int, L, N);
  163. GroundState.Compute_All(true);
  164. // Define OriginIx2 for labelling:
  165. Vect<int> OriginIx2 = GroundState.Ix2;
  166. Scan_State_List<LiebLin_Bethe_State> ScanStateList ('d', GroundState);
  167. // Build the momentum-dependent weight integral matrix:
  168. // To cover negative and positive momenta (in case potential is not symmetric),
  169. // we define the Weight_integral vector entry with index size/2 as corresponding to iK == 0.
  170. // Calculate weight of states using selection criterion function
  171. DP* weight = new DP[Ndata];
  172. // For weighing using 2nd order PT, we only trace over 2 excitation states (1 p-h pair)
  173. // Start by constructing these four classes once and for all:
  174. for (int i = 0; i < Ndata; ++i) {
  175. if (abs(iK[i]) % iKmod != 0) { // if iK not a multiple of iKmod: give stupidly high weight.
  176. weight[i] = 1.0e+100;
  177. sym[i] = false; // doesn't matter
  178. }
  179. else {
  180. // Construct the state again, so that the density ME can be calculated
  181. LiebLin_Bethe_State ScanState = ScanStateList.Return_State(Extract_Base_Label(label[i]));
  182. ScanState.Set_to_Label (label[i]);
  183. if (weighing_option == 1 || weighing_option == 2) ScanState.Compute_All(true);
  184. sym[i] = ScanState.Check_Symmetry();
  185. State_Label_Data currentdata = Read_State_Label (label[i], OriginIx2);
  186. if (currentdata.nexc[0] == 0) weight[i] = 0.0;
  187. else if (symmetric_states && iK[i] < 0 || iK[i] < iKmin || iK[i] > iKmax) weight[i] = 1.0e+100;
  188. else if (symmetric_states && iK[i] == 0 && !sym[i]) {
  189. // This state is at zero momentum but not symmetric. we keep it only if
  190. // the first non-symmetric pair of quantum numbers is right-weighted:
  191. int icheck = 0;
  192. while (ScanState.Ix2[N-1-icheck] == -ScanState.Ix2[icheck]) icheck++;
  193. if (ScanState.Ix2[N-1-icheck] > -ScanState.Ix2[icheck]) {
  194. if (weighing_option == 0) weight[i] = E[i];
  195. else if (weighing_option == 1 || weighing_option == 2)
  196. weight[i] = 1.0/(1.0e-100 + fabs(Estimate_Contribution_of_Single_ph_Annihilation_Path_to_2nd_Order_PT
  197. (ScanState, GroundState, FT_of_potential)));
  198. }
  199. else weight[i] = 1.0e+100;
  200. }
  201. else {
  202. if (weighing_option == 0) weight[i] = E[i];
  203. else if (weighing_option == 1 || weighing_option == 2)
  204. weight[i] = 1.0/(1.0e-100 + fabs(Estimate_Contribution_of_Single_ph_Annihilation_Path_to_2nd_Order_PT
  205. (ScanState, GroundState, FT_of_potential)));
  206. }
  207. }
  208. } // for i
  209. // Now order the states in increasing weight
  210. int* index = new int[Ndata];
  211. for (int i = 0; i < Ndata; ++i) index[i] = i;
  212. QuickSort(weight, index, 0, Ndata - 1);
  213. // Select states by increasing weight, with a max of Nstates_required entries
  214. DP* E_kept = new DP[Nstates_required];
  215. int* iK_kept = new int[Nstates_required];
  216. string* label_kept = new string[Nstates_required];
  217. bool* sym_kept = new bool[Nstates_required];
  218. DP* weight_kept = new DP[Nstates_required];
  219. // Copy selected states into new vectors:
  220. for (int i = 0; i < ABACUS::min(Ndata, Nstates_required); ++i) {
  221. E_kept[i] = E[index[i] ];
  222. iK_kept[i] = iK[index[i] ];
  223. //conv_kept[i] = conv[index[i] ];
  224. label_kept[i] = label[index[i] ];
  225. sym_kept[i] = sym[index[i] ];
  226. weight_kept[i] = weight[i];
  227. }
  228. // If needed, order selected states by increasing energy:
  229. int* index_kept = new int[Nstates_required];
  230. for (int i = 0; i < Nstates_required; ++i) index_kept[i] = i;
  231. if (weighing_option == 1) // only need to do this if energy ordering is chosen
  232. QuickSort (E_kept, index_kept, 0, Nstates_required - 1);
  233. // Output selected states:
  234. for (int i = 0; i < Nstates_required; ++i) {
  235. if (i > 0) NRG_outfile << endl;
  236. NRG_outfile << i << "\t" << E_kept[i] << "\t" << iK_kept[index_kept[i] ]
  237. << "\t" << label_kept[index_kept[i] ]
  238. << "\t" << sym_kept[index_kept[i] ] << "\t" << weight_kept[index_kept[i] ];
  239. }
  240. delete[] E;
  241. delete[] iK;
  242. delete[] label;
  243. delete[] sym;
  244. delete[] E_kept;
  245. delete[] iK_kept;
  246. delete[] label_kept;
  247. delete[] sym_kept;
  248. delete[] weight;
  249. NRG_outfile.close();
  250. return;
  251. }
  252. } // namespace ABACUS