Diagram Utilities
The basic building blocks of Feynman diagrams are particle-hole bubbles and particle-particle bubbles, such as:
The figure shows a typical particle-hole (left) and particle-particle (right) bubble, where \(V^c_{ab}\) is an interaction vertex depending on three orbital indices, and \(A\) and \(B\) are Green’s functions. The diagrams above correspond to the following algebraic expressions:
Note on hermitian conjugation: The complex \(i\) factor has been inserted for convenience. With this definition, the hermitian conjugate \(C^\ddagger\) of \(C\) is obtained simply by replacing A and B by their hermitian conjugates, and \(V^c_{a,b}\) by its element-wise complex conjugate. In particular, if \(V\) is real and A and B are hermitian symmetric, then also C is hermitian symmetric (as a matrix-valued Green’s function; its individual components are not hermitian, but \((C_{1,2})^\ddagger = C_{2,1}\)).
The basic building blocks are therefore products of the type \(C(t,t')=iA_{a,a'}(t,t') B_{b',b}(t',t)\) and \(C(t,t')=iA_{a,a'}(t,t') B_{b,b'}(t,t')\), where \(t,t'\) are arbitrary times on the contour. To evaluate those products, one uses Langreth rules. For example:
We provide two basic functions that allow to compute particle-particle and particle-hole Bubbles on a given timestep:
|
\(C_{c1,c2}(t,t')=i A_{a1,a2}(t,t') B_{b2,b1}(t',t)\) is calculated on timestep |
|
\(C_{c1,c2}(t,t')=i A_{a1,a2}(t,t') B_{b1,b2}(t,t')\) is calculated on timestep |
C,A,Acc,B,Bcccan be of typecntr::herm_matrixorcntr::herm_matrix_timestepFor
X``=``AorB:Xcccontains the hermitian conjugate \(X^\ddagger\) of \(X\). If the argumentXccis omitted, it is assumed thatXis hermitian, \(X=X^\ddagger\).If the index pairs
(c1,c2),(a1,a2), or(b1,b2)are omitted, they are assumed to be(0,0)The following size requirements apply:
For all
X=C,A,Acc,B,Bcc:X.tstp()==tstprequired ifXis of typeherm_matrix_timestep, andX.nt()>=tstprequired ifXis of typeherm_matrixA.size1()>=a1,a2required, analogous forC,A,Acc,B,BccX.ntau()must be equal for allX=C,A,Acc,B,Bcc
From (5) one can see that in general
AandBmust be known outside the hermitian domain in order to computeCin the hermitian domain, which is why the hermitian conjugates \(A^\ddagger\) and \(B^\ddagger\) must be provided as arguments.
Example 1:
The following example calculates the second-order self-energy for a general time-dependent interaction \(U(t)\) out of a scalar local Green’s function, \(\Sigma(t,t') = U(t) G(t,t') G(t',t) U(t') G(t,t')\). The diagram is factorised in a particle-hole bubble \(\chi\) and a particle-particle bubble:
int nt=10;
int ntau=100;
int size1=1;
GREEN G(nt,ntau,size1,FERMION);
GREEN Sigma(nt,ntau,size1,FERMION);
CFUNC U(nt,size1);
// ...
// ... do something to set G and U
// ...
// compute Sigma on all timesteps:
for(int tstp=-1;tstp<=nt;tstp++){
GREEN_TSTP tW(tstp,ntau,size1,BOSON); // used as temporary variable; Note that a bubble of two Fermion GF is bosonic
cntr::Bubble1(tstp,W,G,G); // W(t,t') is set to chi=ii*G(t,t')G(t',t);
// Note: Because G is scalar and have hermitian symmetry, many arguments can be replaced by default. The above extends to
// cntr::Bubble1(tstp,W,0,0,G,G,0,0,G,G,0,0,);
W.left_multiply(tstp,U);
W.right_multiply(tstp,U); // now W is set to W(t,t')=U(t)chi(t,t')U(t')
cntr::Bubble2(tstp,Sigma,G,W); // Sigma(t,t') is set to Sigma=ii*G(t,t')W(t',t);
// Note that by construction, W is hermitian, see above
Sigma.smul(tstp,-1.0); // the final -1 sign.
}
Example 2:
Evaluation of the diagrams (3) and (4), where A and B are two-dimensional, C is one-dimensional, and V is a corresponding contraction. The contraction over internal indices is done by an explicit four-dimensional summation.
int nt=10;
int ntau=100;
int size1=2;
int sizec=1;
GREEN A(nt,ntau,size1,FERMION);
GREEN B(nt,ntau,size1,FERMION);
GREEN CPH(nt,ntau,sizec,BOSON);
GREEN CPP(nt,ntau,sizec,BOSON);
// ...
// compute particle-hole bubble (CPH) and particle-particle bubble (CPP) on all timesteps:
for(int tstp=-1;tstp<=nt;tstp++){
GREEN_TSTP ctmp(tstp,ntau,1,BOSON); // temporary
CPH.set_timestep_zero(tstp);
CPP.set_timestep_zero(tstp);
for(int a1=0;a1<size1;a1++){
for(int a2=0;a2<size1;a2++){
for(int b1=0;b1<size1;b1++){
for(int b2=0;b2<size1;b2++){
double v1=get_vertex(a1,b1); // supposed to return V_{a1,b1}
double v2=get_vertex(a2,b2); // supposed to return V_{a2,b2}
cntr::Bubble1(ctmp,0,0,A,A,a1,a2,B,B,b1,b2); // Note the order of the arguments b1,b2!
CPH.incr_timestep(tstp,ctmp,v1*v2);
cntr::Bubble2(ctmp,0,0,A,A,a1,a2,B,B,b1,b2);
CPP.incr_timestep(tstp,ctmp,v1*v2);
}
}
}
}
}