QNANO
Manybody_Perturbative_Correction_Template.h
1 #ifndef QNANO_NEW_MANYBODY_PERTURBATIVE_CORRECTION_TEMPLATE_DEFINED_H
2 #define QNANO_NEW_MANYBODY_PERTURBATIVE_CORRECTION_TEMPLATE_DEFINED_H
3 
4 
5 template <class Tsolver> void Communicate_Complex_Vector_Template(Tsolver *solver, std::vector<std::complex<double> > &EV2){
6 }
7 
8 #ifdef QNANO_NEW_SLEPC_SOLVER_DEFINED_H_
9 template <> void Communicate_Complex_Vector_Template<SLEPc_Solver>(SLEPc_Solver* solver, std::vector<std::complex<double> > &EV2){
10  MPI_Allreduce(MPI_IN_PLACE, &EV2[0], EV2.size()*2, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
11 }
12 #endif
13 
14 
15 
16 template <class Tsolver> void Communicate_Append_Int_Vector_Template(Tsolver *solver, std::vector<int> &newstates_indices){
17 }
18 #ifdef QNANO_NEW_SLEPC_SOLVER_DEFINED_H_
19 template <> void Communicate_Append_Int_Vector_Template<SLEPc_Solver>(SLEPc_Solver *solver, std::vector<int> &newstates_indices){
20  int MPI_rank, MPI_size;
21  MPI_Comm_size(MPI_COMM_WORLD, &MPI_size);
22  MPI_Comm_rank(MPI_COMM_WORLD, &MPI_rank);
23 
24  if(MPI_rank==0){
25  for(size_t j=1; (int)j<MPI_size; j++){
26  int vectorsize;
27  MPI_Recv(&vectorsize, 1, MPI_INT, j, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
28  size_t oldsize=newstates_indices.size();
29  newstates_indices.resize(oldsize+vectorsize);
30  MPI_Recv(&newstates_indices[oldsize], vectorsize, MPI_INT, j, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
31  }
32  }else{
33  int vectorsize=newstates_indices.size();
34  MPI_Send(&vectorsize, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
35  MPI_Send(&newstates_indices[0], vectorsize, MPI_INT, 0, 0, MPI_COMM_WORLD);
36  }
37 }
38 #endif
39 
40 template <class Tsolver> void Calculate_Manybody_Perturbation(Parameter_Map &param_map, Tsolver *solver, Eigenvector_Printer *EVprinter, Manybody_Hamiltonian *hamil){
41 
42  std::string PT_outfile=param_map.get_as_string("PT_outfile","");
43  if(PT_outfile=="")return;
44 
45  int nr_print=EVprinter->get_actual_nr_print();
46  nr_print=param_map.get_as_double("nr_PT",nr_print);
47  if(nr_print>EVprinter->get_n_converged())nr_print=EVprinter->get_n_converged();
48  if(nr_print<1)return;
49 
50  bool should_print=solver->should_print(); //true for Eigen, or if MPI_rank=0 for SLEPc
51 
52  double small_denominator_threshold=param_map.get_as_double("small_denominator_threshold", 1e-5);
53 
54 
55  //Hamiltonian in extended Hilbert space:
56  if(should_print)std::cout<<"Setting up manybody Hamiltonian for perturbative corrections..."<<std::endl;
57 
58  int nr_e2=param_map.get_as_sizet("nr_e_PT",0);
59  int nr_h2=param_map.get_as_sizet("nr_h_PT",0);
60  if(nr_e2<hamil->hilbert->get_nr_e()){
61  std::cerr<<"nr_e_PT < nr_e !"<<std::endl;
62  exit(1);
63  }
64  if(nr_h2<hamil->hilbert->get_nr_h()){
65  std::cerr<<"nr_h_PT < nr_h !"<<std::endl;
66  exit(1);
67  }
68  int s_nr_e=param_map.get_as_sizet("selected_nr_e");
69  if(!param_map.is_specified("selected_nr_e")){
70  s_nr_e=hamil->hilbert->get_nr_e();
71  }
72  int s_nr_h=param_map.get_as_sizet("selected_nr_h");
73  if(!param_map.is_specified("selected_nr_h")){
74  s_nr_h=hamil->hilbert->get_nr_h();
75  }
76 
77 
78  Parameter_Map param_map2(param_map);
79  param_map2.override_parameter("nr_e", Reader::toString(nr_e2));
80  param_map2.override_parameter("nr_h", Reader::toString(nr_h2));
81  param_map2.override_parameter("selected_nr_e", Reader::toString(s_nr_e));
82  param_map2.override_parameter("selected_nr_h", Reader::toString(s_nr_h));
83 
84  Manybody_Hamiltonian hamil2(param_map2);
85  {
86  Selected_Manybody_Hilbert_Space hilbert2(*hamil->hilbert);
87  hilbert2.nr_e=nr_e2;
88  hilbert2.nr_h=nr_h2;
89  hilbert2.add_singles();
90  hilbert2.add_singles();
91 
92  hamil2.replace_hilbert_space(hilbert2);
93  }
94 
95 
96  if(should_print){
97  std::cout<<"Dimension of original Hilbert space: "<<hamil->get_DIM()<<std::endl;
98  std::cout<<"Dimension of new Hilbert space: "<<hamil2.get_DIM()<<std::endl;
99  }
100 
101 
102  //print new states if contribution is above a certail threshold
104  std::vector<int> newstates_indices;
105  double threshold=param_map.get_as_double("threshold");
106 
107  if(param_map.is_specified("new_states_file") &&
108  param_map.is_specified("add_new_states_file") ){
109  std::cerr<<"Please set either 'new_states_file' or 'add_new_states_file', but not both!"<<std::endl;
110  exit(1);
111  }
112 
113  int existing_states_in_new_states_file=0;
114  std::string new_states_file=param_map.get_as_string("new_states_file");
115  if(param_map.is_specified("add_new_states_file")){
116  new_states_file=param_map.get_as_string("add_new_states_file");
117  newstates.add_from_file(new_states_file, \
118  hamil2.hilbert->get_rank_e(), hamil2.hilbert->get_rank_h(),
119  hamil2.hilbert->get_nr_e(), hamil2.hilbert->get_nr_h());
120  existing_states_in_new_states_file=newstates.size();
121  }
122 
123  bool print_new_states=false;
124  if(new_states_file!=""){
125  print_new_states=true;
126  }
127 
128 
129  // Prepare output stream
130  std::ofstream ofs;
131  if(should_print){
132  ofs.open(PT_outfile.c_str());
133  ofs<<"#DIM "<<hamil->get_DIM()<<" -> "<<hamil2.get_DIM()<<std::endl;
134  std::cout<<std::setprecision(10);
135  ofs<<std::setprecision(10);
136  }
137 
138 
139  Distribute_Block_Local *db=solver->new_Distribute_Block_Local(hamil->get_DIM());
140  Distribute_Block_Local *db2=solver->new_Distribute_Block_Local(hamil2.get_DIM());
141  Communicator *comm=solver->new_Communicator();
142 
143 
144  //Handle EVs block-wise to save memory
145  size_t nr_blocks=param_map.get_as_sizet("nr_blocks",1);
146  if(param_map.is_specified("EV_per_block")){
147  size_t EV_per_block=param_map.get_as_sizet("EV_per_block");
148  if(EV_per_block<1){std::cerr<<"EV_per_block<1!"<<std::endl;exit(1);}
149  nr_blocks=nr_print/EV_per_block;
150  if((int)(nr_blocks*EV_per_block)<(int)nr_print)nr_blocks++;
151  }
152 
153  std::cout<<"nr_blocks: "<<nr_blocks<<std::endl;
154  Distribute_Block db_EV(nr_print,nr_blocks);
155 
156 
157  for(size_t bl=0; bl<db_EV.get_nr_blocks(); bl++){
158  size_t this_nr=db_EV.get_blocksize(bl);
159  if(should_print){
160  std::cout<<"block: "<<bl<<"/"<<db_EV.get_nr_blocks()<<std::endl;
161  }
162 
163  // EV2[i] = H * EV[i] :
164  std::vector<std::vector<std::complex<double> > > EV2(this_nr, \
165  std::vector<std::complex<double> >(hamil2.get_DIM(),0.));
166 
167  std::vector<double> eigenvalue(this_nr,0);
168  std::vector<std::vector<std::complex<double> > >EV_local(this_nr, \
169  std::vector<std::complex<double> >(db->get_local_blocksize(),0.));
170 
171  for(size_t i=0; i<this_nr; i++){ //For all eigenvectors:
172  eigenvalue[i]=solver->get_eigenvalue(db_EV.get_start(bl)+i);
173  solver->get_EV_local_part(db_EV.get_start(bl)+i, &EV_local[i][0]);
174  }
175 
176  for(size_t j=0; j<db->get_local_blocksize(); j++){
177  int j2=db->get_local_start()+j;
178  std::vector< col_val > col_val_vec;
179  Fermion_Double_Index fi=hamil->hilbert->get_Fermion_Double_Index(j2);
180  hamil2.get_Matrix_row_block(col_val_vec, fi);
181  for(size_t k=0; k<col_val_vec[0].size(); k++){
182  int Hcol=col_val_vec[0][k].first;
183  std::complex<double> Hval=std::conj(col_val_vec[0][k].second);
184  for(size_t i=0; i<this_nr; i++){
185  EV2[i][Hcol]+=Hval*EV_local[i][j];
186  }
187  }
188  }
189 
190  //Communicate EV2 to all threads
191  if(should_print){
192  std::cout<<"Communicating EV2..."<<std::endl;
193  }
194  for(size_t i=0; i<this_nr; i++){
195  Communicate_Complex_Vector_Template<Tsolver>(solver, EV2[i]);
196  }
197 
198 
199  //Calculate actual correction:
200  if(should_print){
201  std::cout<<"Calculating corrections..."<<std::endl;
202  }
203 
204  std::vector<double> corr(this_nr,0.);
205 // std::vector<double> norm_corr(this_nr,0.);
206  std::vector<double> maxcontrib(this_nr,0.);
207  std::vector<int> nr_small_denominator(this_nr,0);
208 
209  for(size_t j=db2->get_local_start(); j<db2->get_local_start()+db2->get_local_blocksize(); j++){
210  //For those states that are not already in the smaller Hilbert space:
211  Fermion_Double_Index fi=hamil2.hilbert->get_Fermion_Double_Index(j);
212  int k=hamil->hilbert->get_index(fi);
213  if(k<0){
214  double e=hamil2.get_diagonal(fi);
215  bool added=false;
216  for(size_t i=0; i<this_nr; i++){
217  double numerator=(std::conj(EV2[i][j])*EV2[i][j]).real();
218  double denominator=(e-eigenvalue[i]);
219 
220  if(print_new_states && fabs(denominator)<small_denominator_threshold){
221  nr_small_denominator[i]++;
222  newstates_indices.push_back(j);
223  added=true;
224  break;
225  }
226  corr[i]-=numerator/denominator;
227 // norm_corr[i]+=numerator/(denominator*denominator);
228  if(print_new_states){
229  double contrib=abs(EV2[i][j]/denominator);
230  if(contrib>maxcontrib[i])maxcontrib[i]=contrib;
231  if(!added && contrib>threshold){
232  newstates_indices.push_back(j);
233  added=true;
234  }
235  }
236  }
237  }
238  }
239 
240  //printing individual eigenvalues/corrections
241  if(should_print){
242  std::cout<<"Communicating and printing perturbative corrections..."<<std::endl;
243  }
244  for(size_t i=0; i<this_nr; i++){
245  //Communicate corr;
246  {std::vector<std::complex<double> > c_corr(1,corr[i]);
247  Communicate_Complex_Vector_Template<Tsolver>(solver, c_corr);
248  corr[i]=c_corr[0].real();}
249  //Communicate norm_corr;
250 /* {std::vector<std::complex<double> > c_norm_corr(1,norm_corr[i]);
251  Communicate_Complex_Vector_Template<Tsolver>(solver, c_norm_corr);
252  norm_corr[i]=c_norm_corr[0].real();}
253 */
254 
255  comm->Reduce_Max_Double(maxcontrib[i]);
256 
257  if(should_print){
258  std::cout<<eigenvalue[i]<<" ";
259  ofs<<eigenvalue[i]<<" ";
260  if(nr_small_denominator[i]>0){
261  std::cout<<"ILL_DEFINED_"<<nr_small_denominator[i]<<"_";
262  ofs<<"ILL_DEFINED_"<<nr_small_denominator[i]<<"_";
263  }
264  std::cout<<corr[i];
265 // std::cout<<" "<<norm_corr[i]
266  std::cout<<std::endl;
267  std::cout<<"Maximum contribution from new state: "<<maxcontrib[i]<<std::endl;
268  ofs<<corr[i];
269 // ofs<<" "<<norm_corr[i];
270  ofs<<" "<<maxcontrib[i];
271  ofs<<std::endl;
272  }
273  }//<- loop over eigenvectors i
274  }//<- loop over blocks
275 
276 
277  //TODO: Communicate new states:
278  if(should_print){
279  std::cout<<"Communicating and printing new states..."<<std::endl;
280  }
281  Communicate_Append_Int_Vector_Template<Tsolver>(solver, newstates_indices);
282 
283 
284 
285  if(should_print)for(size_t j=0; j<newstates_indices.size(); j++){
286  Fermion_Double_Index fi=hamil2.hilbert->get_Fermion_Double_Index(newstates_indices[j]);
287  newstates.add_if_not_contained(fi);
288  }
289 
290 
291  //print:
292  if(should_print){
293  newstates.print(new_states_file);
294  std::cout<<"Threshold: "<<threshold<<std::endl;
295  std::cout<<"Adding "<<newstates.size()-existing_states_in_new_states_file;
296  std::cout<<" states to new_states_file '"<<new_states_file;
297  std::cout<<"' gives a total of "<<newstates.size()<<" states."<<std::endl;
298  std::cout<<"Perturbative corrections done."<<std::endl;
299  }
300 
301  delete comm;
302  delete db2;
303  delete db;
304 }
305 
306 
307 
308 #endif
Definition: Parameter_Map.h:12
Definition: Communicator.h:19
Definition: SLEPc_Solver.h:12
Definition: Fermion_Double_Index.h:14
Definition: Distribute_Block.h:7
Definition: Distribute_Block_Local.h:15
virtual void Reduce_Max_Double(double &d) const
Maximal value from all thread is communicated to the root.
Definition: Communicator.h:31
Definition: Selected_Manybody_Hilbert_Space.h:7
Definition: Eigenvector_Printer.h:8
Definition: Selected_Manybody_States_with_Hash_Table.h:8
Definition: Manybody_Hamiltonian.h:14