NESSi  v1.0.2
The NonEquilibrium Systems Simulation Library
cntr_differentiation_impl.hpp
Go to the documentation of this file.
1 #ifndef CNTR_DIFFERENTIATION_IMPL_H
2 #define CNTR_DIFFERENTIATION_IMPL_H
3 
5 //#include "cntr_exception.hpp"
7 
8 namespace cntr {
9 
10 /*###########################################################################################
11 #
12 # DIFFERENTIATION dA(t,t') = id/dt A(t,t') or dA(t,t') = -id/dt' A(t,t')
13 #
14 # ... currently only implemented for herm_matrix of size1=1 -> solve using ptr
15 # ... Acc is the conjugate function to A (similar as in convolution).
16 # Used only in for ret and les. If A is hermitian, simply provide Acc=A.
17 # ... For the computation of timestep tstp, A(t,t') is addressed at t,t' <= max(n,k),
18 # where k is the Integartion order (see Integrator). I.e., tstp=0..k can be computed
19 # only if A is given for t,t'<=k.
20 #
21 #
22 ###########################################################################################*/
23 // left derivative (1)
25 template <typename T>
26 void deriv1_timestep(int tstp, herm_matrix<T> &dA, herm_matrix<T> &A, herm_matrix<T> &Acc,
27  integration::Integrator<T> &I, T beta, T h) {
28  int tstp2, nt = A.nt();
29  if (tstp == -1) {
30  deriv1_matsubara(dA, A, I, beta);
31  } // matsubara
32  else {
33  for (tstp2 = 0; tstp2 <= nt; tstp2++)
34  deriv1_element(tstp, tstp2, dA, A, Acc, I, h); // ret and less
35  deriv1_tv(tstp, dA, A, I, h); // tv
36  }
37 }
38 
39 // right derivative (2)
41 template <typename T>
42 void deriv2_timestep(int tstp, herm_matrix<T> &dA, herm_matrix<T> &A, herm_matrix<T> &Acc,
43  integration::Integrator<T> &I, T beta, T h) {
44  int tstp2, nt = A.nt();
45  if (tstp == -1) {
46  deriv1_matsubara(dA, A, I, beta);
47  } // matsubara: deriv1=deriv2
48  else {
49  for (tstp2 = 0; tstp2 <= nt; tstp2++)
50  deriv2_element(tstp, tstp2, dA, A, Acc, I, h); // ret and less
51  deriv2_tv(tstp, dA, A, I, beta); // tv
52  }
53 }
54 
55 // matsubara: left and right derivative equal
56 // deriv1 = -d/dtau
57 // deriv2 = +d/dtau' A(tau-tau') = -d/dtau A(tau-tau') = deriv1
58 // computed for all imaginary time directly
60 template <typename T>
61 void deriv1_matsubara(herm_matrix<T> &dA, herm_matrix<T> &A, integration::Integrator<T> &I,
62  T beta) {
63  typedef std::complex<T> cplx;
64  int tstp2, l, k = I.get_k(), k1 = k + 1, k2 = int(k1 / 2), ntau = A.ntau();
65  cplx a, c;
66  double hv = beta / ntau;
67  // matsubara: use midpoint to keep possible symmetry, use fwd/bwd near endpoints
68  // PROBLEM WITH MIDPOINT, USE FWD AND BWD ONLY
69  // for(tstp2=0;tstp2<k2;tstp2++)//imaginary time
70  for (tstp2 = 0; tstp2 < k1; tstp2++) // imaginary time
71  {
72  // fwd diff near tau=0
73  c = 0;
74  for (l = 0; l <= k1; l++) {
75  A.get_mat(tstp2 + l, a);
76  c -= a * I.bd_weights(l); // fwd has same weights as bwd with minus sign
77  }
78  c /= -hv;
79  dA.set_mat(tstp2, c);
80 
81  // bwd diff near tau=beta
82  c = 0;
83  for (l = 0; l <= k1; l++) {
84  A.get_mat(ntau - tstp2 - l, a);
85  c += a * I.bd_weights(l);
86  }
87  c /= -hv;
88  dA.set_mat(ntau - tstp2, c);
89  }
90  // for the rest use midpoint differentiation
91  // PROBLEM WITH MIDPOINT, USE FWD AND BWD ONLY
92  // for(tstp2=k2;tstp2<=ntau-k2;tstp2++)//imaginary time
93  for (tstp2 = k1; tstp2 <= ntau - k1; tstp2++) // imaginary time
94  {
95  c = 0;
96  /*for(l=-k2;l<=k2;l++)
97  {
98  A.get_mat(tstp2-l,a);
99  //c += a*I.mp_weights(l);
100  }*/
101  for (l = 0; l <= k1; l++) {
102  A.get_mat(tstp2 - l, a);
103  c += a * I.bd_weights(l);
104  }
105  c /= -hv;
106  dA.set_mat(tstp2, c);
107  }
108 
109  /*
110 
111  // check symmetry Matsubara function on (0,beta)
112  A.get_mat(0,a);
113  A.get_mat(ntau,c);
114  if( abs(a-c) <= 1e-15 )//symmetric
115  {
116  dA.set_mat(int(ntau/2),0);//dA(ntau/2)=0 due to symmetry
117  for(tstp2=int(ntau/2+1);tstp2<=ntau;tstp2++)//imaginary time
118  {
119  c=0;
120  for(l=0;l<=k1;l++)
121  //for(l=-k2,k2,l++)
122  {
123  A.get_mat(tstp2-l,a);
124  c += a*I.bd_weights(l);
125  //A.get_mat(tstp2-l,a);
126  //c += a*I.mp_weights(l)
127  }
128  c/=-hv;
129  dA.set_mat(tstp2,c);
130  dA.set_mat(ntau-tstp2,-c);
131  }
132  }
133  else if( abs(a+c) <= 1e-15 )//antisymmetric
134  {
135  for(tstp2=int(ntau/2);tstp2<=ntau;tstp2++)//imaginary time
136  {
137  c=0;
138  for(l=0;l<=k1;l++)
139  {
140  A.get_mat(tstp2-l,a);
141  c += a*I.bd_weights(l);
142  }
143  c/=-hv;
144  dA.set_mat(tstp2,c);
145  dA.set_mat(ntau-tstp2,c);//note that tstp2=ntau/2 is set twice, they are indeed
146  identical
147  }
148 
149  }
150  else{ std::cerr << "matsubara function neither symmetic nor antisymmetric" << std::endl;
151  abort();}*/
152 }
153 
154 // lesser/greater: deriv1= +i d/dt
155 // element access only for retarded and lesser
156 // A not hermitian: keep track of boundaries explicitly and use Acc when needed
157 // not very efficient (many if/else...) improve when desired
159 template <typename T>
160 void deriv1_element(int tstp1, int tstp2, herm_matrix<T> &dA, herm_matrix<T> &A,
161  herm_matrix<T> &Acc, integration::Integrator<T> &I, T h) {
162  typedef std::complex<T> cplx;
163  int l, k = I.get_k(), k1 = k + 1;
164  cplx a, c, plusi;
165  plusi = cplx(0, 1);
166  if ((tstp1 == -1) || (tstp2 == -1)) {
167  std::cerr << "deriv1_element only on real times" << std::endl;
168  abort();
169  } else {
170  if (tstp2 <= tstp1) {
171  // retarded
172  c = 0;
173  if (tstp1 < k1) {
174  for (l = 0; l <= k; l++) // NB one order less then differentiation!!
175  {
176  // Use get_ret but keep track of i<j by hand (non-hermitian)
177  // Later: replace get_ret with pointer
178  // Even later: use function increment
179  if (l < tstp2) {
180  Acc.get_ret(tstp2, l, a);
181  a.real(-a.real()); // make minus conjugate by hand
182  } else {
183  A.get_ret(l, tstp2, a);
184  }
185  c += a * I.poly_differentiation(tstp1, l);
186  }
187  } else {
188  for (l = 0; l <= k1; l++) {
189  if ((tstp1 - l) < tstp2) {
190  Acc.get_ret(tstp2, tstp1 - l, a);
191  a.real(-a.real()); // make minus conjugate by hand
192  } else {
193  A.get_ret(tstp1 - l, tstp2, a);
194  }
195  c += a * I.bd_weights(l);
196  }
197  }
198  c = c * plusi / h;
199  dA.set_ret(tstp1, tstp2, c);
200  }
201  if (tstp2 >= tstp1) {
202  // lesser
203  c = 0;
204  if (tstp1 < k1) {
205  for (l = 0; l <= k; l++) // NB one order less then differentiation!!
206  {
207  if (l > tstp2) {
208  Acc.get_les(tstp2, l, a);
209  a.real(-a.real()); // make minus conjugate by hand
210  } else {
211  A.get_les(l, tstp2, a);
212  }
213  c += a * I.poly_differentiation(tstp1, l);
214  }
215  } else {
216  for (l = 0; l <= k1; l++) {
217  // get_les automatically returns -conj(Gles(tstp2,tstp-l)) for
218  // tsp1-l>tstp2
219  if (l > tstp2) {
220  Acc.get_les(tstp2, tstp1 - l, a);
221  a.real(-a.real()); // make minus conjugate by hand
222  } else {
223  A.get_les(tstp1 - l, tstp2, a);
224  }
225  c += a * I.bd_weights(l);
226  }
227  }
228  c = c * plusi / h;
229  dA.set_les(tstp1, tstp2, c);
230  }
231  }
232 }
233 
234 // lesser/greater: deriv2= -i d/dt
235 // element access only for retarded and lesser
236 // not very efficient (many if/else...) improve when needed
238 template <typename T>
239 void deriv2_element(int tstp1, int tstp2, herm_matrix<T> &dA, herm_matrix<T> &A,
240  herm_matrix<T> &Acc, integration::Integrator<T> &I, T h) {
241  typedef std::complex<T> cplx;
242  int l, k = I.get_k(), k1 = k + 1;
243  cplx a, c, minusi;
244  minusi = cplx(0, -1);
245  if ((tstp1 == -1) || (tstp2 == -1)) {
246  std::cerr << "deriv2_element only on real times" << std::endl;
247  abort();
248  } else {
249  if (tstp2 <= tstp1) {
250  // retarded
251  c = 0;
252  if (tstp2 < k1) {
253  for (l = 0; l <= k; l++) // NB one order less then differentiation!!
254  {
255  if (tstp1 < l) {
256  Acc.get_ret(l, tstp1, a);
257  a.real(-a.real());
258  } else {
259  A.get_ret(tstp1, l, a);
260  }
261  c += a * I.poly_differentiation(tstp2, l);
262  }
263  } else {
264  for (l = 0; l <= k1; l++) {
265  if (tstp1 < (tstp2 - l)) {
266  Acc.get_ret(tstp2 - l, tstp1, a);
267  a.real(-a.real());
268  } else {
269  A.get_ret(tstp1, tstp2 - l, a);
270  }
271  c += a * I.bd_weights(l);
272  }
273  }
274  c = c * minusi / h;
275  dA.set_ret(tstp1, tstp2, c);
276  }
277  if (tstp2 >= tstp1) {
278  // lesser
279  c = 0;
280  if (tstp2 < k1) {
281  for (l = 0; l <= k; l++) // NB one order less then differentiation!!
282  {
283  if (tstp1 > l) {
284  Acc.get_les(l, tstp1, a);
285  a.real(-a.real());
286  } else {
287  A.get_les(tstp1, l, a);
288  }
289  c += a * I.poly_differentiation(tstp2, l);
290  }
291  } else {
292  for (l = 0; l <= k1; l++) {
293  // get_les automatically returns -conj(Gles(tstp2,tstp-l)) for
294  // tsp1-l>tstp2
295  if (tstp1 > tstp2 - l) {
296  Acc.get_les(tstp2 - l, tstp1, a);
297  a.real(-a.real());
298  } else {
299  A.get_les(tstp1, tstp2 - l, a);
300  }
301  c += a * I.bd_weights(l);
302  }
303  }
304  c = c * minusi / h;
305  dA.set_les(tstp1, tstp2, c);
306  }
307  }
308 }
309 
310 // mixed tv: deriv1 = +i d/dt
311 // calculated directly whole timestep (sum imaginary time)
313 template <typename T>
314 void deriv1_tv(int tstp, herm_matrix<T> &dA, herm_matrix<T> &A,
316  typedef std::complex<T> cplx;
317  int tstp2, l, k = I.get_k(), k1 = k + 1, ntau = A.ntau();
318  cplx a, c, plusi;
319  plusi = cplx(0, 1);
320  if (tstp == -1) {
321  std::cerr << "deriv1_tv requires real time (left)" << std::endl;
322  abort();
323  } else {
324  // tv (mixed: left real, right imag)
325  for (tstp2 = 0; tstp2 <= ntau; tstp2++) // imaginary time
326  {
327  c = 0;
328  if (tstp < k1) {
329  for (l = 0; l <= k; l++) // NB one order less then differentiation!!
330  {
331  // tv well-behaved for all t and tau
332  A.get_tv(l, tstp2, a);
333  c += a * I.poly_differentiation(tstp, l);
334  }
335  } else {
336  for (l = 0; l <= k1; l++) {
337  // tv well-behaved for all t and tau
338  A.get_tv(tstp - l, tstp2, a);
339  c += a * I.bd_weights(l);
340  }
341  }
342  c = c * plusi / h;
343  dA.set_tv(tstp, tstp2, c);
344  }
345  }
346 }
347 
348 // mixed tv: deriv2 = +d/dtau'
349 // calculates directly whole timestep (sum imaginary time)
351 template <typename T>
352 void deriv2_tv(int tstp, herm_matrix<T> &dA, herm_matrix<T> &A,
353  integration::Integrator<T> &I, T beta) {
354  typedef std::complex<T> cplx;
355  int tstp2, l, k = I.get_k(), k1 = k + 1, ntau = A.ntau();
356  cplx a, c;
357  double hv = beta / ntau;
358  if (tstp == -1) {
359  std::cerr << "deriv2_tv requires real time (left)" << std::endl;
360  abort();
361  } else {
362  // tv (mixed: left real, right imag)
363  for (tstp2 = 0; tstp2 <= ntau; tstp2++) // imaginary time
364  {
365  c = 0;
366  if (tstp2 < k1) {
367  for (l = 0; l <= k; l++) // NB one order less then differentiation!!
368  {
369  // tv well-behaved for all t and tau
370  A.get_tv(tstp, l, a);
371  c += a * I.poly_differentiation(tstp2, l);
372  }
373  } else {
374  for (l = 0; l <= k1; l++) {
375  // tv well-behaved for all t and tau
376  A.get_tv(tstp, tstp2 - l, a);
377  c += a * I.bd_weights(l);
378  }
379  }
380  c /= hv;
381  dA.set_tv(tstp, tstp2, c);
382  }
383  }
384 }
385 
386 
387 // ============================== new interfaces ==============================
388 
389 template <typename T>
390 void deriv1_matsubara(herm_matrix<T> &dA, herm_matrix<T> &A, T beta, int SolveOrder){
391  deriv1_matsubara(dA, A, integration::I<T>(SolveOrder), beta);
392 }
393 template <typename T>
394 void deriv1_element(int tstp1, int tstp2, herm_matrix<T> &dA, herm_matrix<T> &A,
395  herm_matrix<T> &Acc, T h, int SolveOrder){
396  deriv1_element(tstp1, tstp2, dA, A, Acc, integration::I<T>(SolveOrder), h);
397 }
398 template <typename T>
399 void deriv2_element(int tstp1, int tstp2, herm_matrix<T> &dA, herm_matrix<T> &A,
400  herm_matrix<T> &Acc, T h, int SolveOrder){
401  deriv2_element(tstp1, tstp2, dA, A, Acc, integration::I<T>(SolveOrder), h);
402 }
403 template <typename T>
404 void deriv1_tv(int tstp, herm_matrix<T> &dA, herm_matrix<T> &A,
405  T h, int SolveOrder){
406  deriv1_tv(tstp, dA, A, integration::I<T>(SolveOrder), h);
407 }
408 template <typename T>
409 void deriv2_tv(int tstp, herm_matrix<T> &dA, herm_matrix<T> &A,
410  T beta, int SolveOrder){
411  deriv2_tv(tstp, dA, A, integration::I<T>(SolveOrder), beta);
412 }
413 template <typename T>
414 void deriv1_timestep(int tstp, herm_matrix<T> &dA, herm_matrix<T> &A, herm_matrix<T> &Acc,
415  T beta, T h, int SolveOrder){
416  deriv1_timestep(tstp, dA, A, Acc, integration::I<T>(SolveOrder), beta, h);
417 }
418 template <typename T>
419 void deriv2_timestep(int tstp, herm_matrix<T> &dA, herm_matrix<T> &A, herm_matrix<T> &Acc,
420  T beta, T h, int SolveOrder){
421  deriv2_timestep(tstp, dA, A, Acc, integration::I<T>(SolveOrder), beta, h);
422 }
423 
424 } // namespace cntr
425 
426 #endif // CNTR_DIFFERENTIATION_IMPL_H
Class Integrator contains all kinds of weights for integration and differentiation of a function at ...
std::complex< double > cplx
Definition: fourier.cpp:11
Integrator< T > & I(int k)
Class herm_matrix for two-time contour objects with hermitian symmetry.