v2DM-DOCI  1.0
PotentialReduction.cpp
Go to the documentation of this file.
1 /*
2  * @BEGIN LICENSE
3  *
4  * Copyright (C) 2014-2015 Ward Poelmans
5  *
6  * This file is part of v2DM-DOCI.
7  *
8  * v2DM-DOCI is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * Foobar is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
20  *
21  * @END LICENSE
22  */
23 
24 #include <fstream>
25 #include <iomanip>
26 #include <chrono>
27 #include <functional>
28 #include "PotentialReducation.h"
29 #include "Hamiltonian.h"
30 
33 
34 PotentialReduction::PotentialReduction(const CheMPS2::Hamiltonian &hamin)
35 {
36  N = hamin.getNe();
37  L = hamin.getL();
38  nuclrep = hamin.getEconst();
39 
40  ham.reset(new TPM(L,N));
41 
42  rdm.reset(new TPM(L,N));
43 
44  lineq.reset(new Lineq(L,N));
45 
46  BuildHam(hamin);
47 
48  // some default values
49  tolerance = 1.0e-5;
50  target = 1e-11;
51  reductionfac = 1.0/1.01;
52  t = 1;
53 }
54 
56 {
57  N = hamin.gN();
58  L = hamin.gL();
59  nuclrep = 0;
60 
61  ham.reset(new TPM(hamin));
62 
63  rdm.reset(new TPM(L,N));
64 
65  lineq.reset(new Lineq(L,N));
66 
67  BuildHam(hamin);
68 
69  // some default values
70  tolerance = 1.0e-5;
71  target = 1e-12;
72  reductionfac = 1.0/1.1;
73  t = 1;
74 }
75 
77 {
78  N = orig.N;
79  L = orig.L;
80  nuclrep = orig.nuclrep;
81 
82  ham.reset(new TPM(*orig.ham));
83 
84  rdm.reset(new TPM(*orig.rdm));
85 
86  lineq.reset(new Lineq(*orig.lineq));
87 
88  // some default values
89  tolerance = orig.tolerance;
90  target = orig.target;
92  energy = orig.energy;
93  t = orig.t;
94  norm_ham = orig.norm_ham;
95 }
96 
98 {
99  N = orig.N;
100  L = orig.L;
101  nuclrep = orig.nuclrep;
102 
103  (*ham) = *orig.ham;
104 
105  (*rdm) = *orig.rdm;
106 
107  (*lineq) = *orig.lineq;
108 
109  // some default values
110  tolerance = orig.tolerance;
111  target = orig.target;
112  reductionfac = orig.reductionfac;
113  energy = orig.energy;
114  t = orig.t;
115 
116  norm_ham = orig.norm_ham;
117 
118  return *this;
119 }
120 
122 {
123  return new PotentialReduction(*this);
124 }
125 
127 {
128  return new PotentialReduction(std::move(*this));
129 }
130 
137 {
138  std::function<double(int,int)> getT = [&hamin] (int a, int b) -> double { return hamin.getTmat(a,b); };
139  std::function<double(int,int,int,int)> getV = [&hamin] (int a, int b, int c, int d) -> double { return hamin.getVmat(a,b,c,d); };
140 
141  ham->ham(getT, getV);
142 
143  norm_ham = std::sqrt(ham->ddot(*ham));
144  (*ham) /= norm_ham;
145 }
146 
152 {
153  (*ham) = hamin;
154 
155  norm_ham = std::sqrt(ham->ddot(*ham));
156  (*ham) /= norm_ham;
157 }
158 
164 {
165  rdm->init(*lineq);
166 
167  unsigned int tot_iter = 0;
168 
169  t = 1.0;
170  int iter = 0;
171 
172  TPM backup_rdm(*rdm);
173 
174  std::ostream* fp = &std::cout;
175  std::ofstream fout;
176  if(!outfile.empty())
177  {
178  fout.open(outfile, std::ios::out | std::ios::app);
179  fp = &fout;
180  }
181  std::ostream &out = *fp;
182  out.precision(10);
183  out.setf(std::ios::scientific | std::ios::fixed, std::ios_base::floatfield);
184 
185  auto start = std::chrono::high_resolution_clock::now();
186 
187  //outer iteration: scaling of the potential barrier
188  while(t > target)
189  {
190  if(do_output)
191  out << iter << "\t" << std::setw(16) << t << "\t" << std::setw(16) << rdm->getMatrices().trace() << "\t" << std::setw(16) << rdm->getVectors().trace() << "\t" << std::setw(16) << rdm->ddot(*ham)*norm_ham + nuclrep << "\t" << std::setw(16) << rdm->S_2() << std::endl;
192 
193  double convergence = 1.0;
194  int cg_iters = 0;
195  iter++;
196 
197  //inner iteration:
198  //Newton's method for finding the minimum of the current potential
199  while(convergence > tolerance)
200  {
201  tot_iter++;
202 
203  SUP P(L,N);
204 
205  P.fill(*rdm);
206 
207  P.invert();
208 
209  //eerst -gradient aanmaken:
210  TPM grad(L,N);
211 
212  grad.constr_grad(t,P,*ham,*lineq);
213 
214  //dit wordt de stap:
215  TPM delta(L,N);
216 
217  //los het hessiaan stelsel op:
218  cg_iters = delta.solve(t,P,grad,*lineq);
219 
220  //line search
221  double a = delta.line_search(t,P,*ham);
222 
223  //rdm += a*delta;
224  rdm->daxpy(a,delta);
225 
226  convergence = a*a*delta.ddot(delta);
227 
228  if(do_output)
229  out << cg_iters << "\t" << convergence << std::endl;
230 
231  if(cg_iters == -1)
232  break;
233  }
234 
235  if(do_output)
236  out << std::endl;
237 
238  if(cg_iters == -1)
239  {
240  *rdm = backup_rdm;
241  break;
242  }
243 
244  t *= reductionfac;
245 
246  //what is the tolerance for the newton method?
247  tolerance = 1.0e-5*t;
248 
249  if(tolerance < target)
250  tolerance = target;
251 
252  //extrapolatie:
253  TPM extrapol(*rdm);
254 
255  extrapol -= backup_rdm;
256 
257  //overzetten voor volgende stap
258  backup_rdm = *rdm;
259 
260  double a = extrapol.line_search(t,*rdm,*ham);
261 
262  rdm->daxpy(a,extrapol);
263  }
264 
265  auto end = std::chrono::high_resolution_clock::now();
266 
267  energy = norm_ham*ham->ddot(*rdm);
268 
269  out << std::endl;
270  out << "Energy: " << getFullEnergy() << std::endl;
271  out << "Trace: " << rdm->trace() << std::endl;
272  out << "pd gap: " << t*rdm->gn() << std::endl;
273  out << "S^2: " << rdm->S_2() << std::endl;
274  out << "Runtime: " << std::fixed << std::chrono::duration_cast<std::chrono::duration<double,std::ratio<1>>>(end-start).count() << " s" << std::endl;
275 
276  out << std::endl;
277  out << "total nr of iterations = " << tot_iter << std::endl;
278 
279  if(!outfile.empty())
280  fout.close();
281 
282  return tot_iter;
283 }
284 
289 {
290  return energy + nuclrep;
291 }
292 
294 {
295  this->target = tar;
296 }
297 
299 {
300  this->tolerance = tol;
301 }
302 
304 {
305  this->reductionfac = red;
306 }
307 
309 {
310  return (*rdm);
311 }
312 
314 {
315  return (*lineq);
316 }
317 
319 {
320  return *ham;
321 }
322 
328 {
329  return norm_ham*ham->ddot(*rdm) + nuclrep;
330 }
331 
337 {
338  return !(t > target);
339 }
340 
341 /* vim: set ts=3 sw=3 expandtab :*/
int gN() const
Definition: TPM.cpp:110
std::string outfile
Definition: Method.h:77
void BuildHam(const CheMPS2::Hamiltonian &)
PotentialReduction * Clone() const
void invert()
Definition: SUP.cpp:214
std::unique_ptr< TPM > ham
double line_search(double t, SUP &, const TPM &) const
Definition: TPM.cpp:767
std::unique_ptr< Lineq > lineq
double getVmat(const int index1, const int index2, const int index3, const int index4) const
Get a Vmat element.
double ddot(const Container &) const
Definition: Container.cpp:255
bool do_output
Definition: Method.h:75
void constr_grad(double t, const SUP &, const TPM &, const Lineq &)
Definition: TPM.cpp:595
double getTmat(const int index1, const int index2) const
Get a Tmat element.
PotentialReduction(const CheMPS2::Hamiltonian &)
PotentialReduction & operator=(PotentialReduction &&)=default
std::unique_ptr< TPM > rdm
void fill(const TPM &)
Definition: SUP.cpp:231
double energy
Definition: Method.h:73
int gL() const
Definition: TPM.cpp:115
double getEconst() const
Get the constant energy.
int getL() const
Get the number of orbitals.
int solve(double t, const SUP &, TPM &, const Lineq &)
Definition: TPM.cpp:666