3
0
mirror of https://github.com/triqs/dft_tools synced 2024-12-24 13:23:37 +01:00

gf : new wrapper

This commit is contained in:
Olivier Parcollet 2014-05-09 10:43:55 +02:00
parent 3a9f986461
commit 3a31077d51
49 changed files with 992 additions and 210 deletions

View File

@ -1,5 +1,6 @@
SET(PYTHON_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/__init__.py
${CMAKE_CURRENT_SOURCE_DIR}/block_gf.py
${CMAKE_CURRENT_SOURCE_DIR}/descriptors.py
${CMAKE_CURRENT_SOURCE_DIR}/gf_generic.py
@ -10,21 +11,17 @@ SET(PYTHON_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/gf_retime.py
${CMAKE_CURRENT_SOURCE_DIR}/gf_two_real_times.py
${CMAKE_CURRENT_SOURCE_DIR}/impl_plot.py
${CMAKE_CURRENT_SOURCE_DIR}/__init__.py
${CMAKE_CURRENT_SOURCE_DIR}/inverse.py
${CMAKE_CURRENT_SOURCE_DIR}/lazy_expressions.py
${CMAKE_CURRENT_SOURCE_DIR}/nothing.py
${CMAKE_CURRENT_SOURCE_DIR}/tools.py
)
# Install python sources
install (FILES ${PYTHON_SOURCES} DESTINATION ${TRIQS_PYTHON_LIB_DEST}/gf/local)
# Build cython module
cython_module( GF3 gf gf/local )
cython_module( MS matrix_stack gf/local )
# Build C extension module
triqs_python_extension(gf gf/local)
# ?? was not needed ? triqs_set_rpath_for_target(my_module)
FILE(GLOB all_pxd_files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.pxd )
install (FILES ${all_pxd_files} DESTINATION "include/pytriqs/gf/local")
install (FILES ${CMAKE_SOURCE_DIR}/pytriqs/__init__.py.template DESTINATION "include/pytriqs/gf/local" RENAME __init__.py)

View File

@ -191,13 +191,13 @@ class GfGeneric:
#-------- LAZY expression system -----------------------------------------
def __lazy_expr_eval_context__(self):
def _lazy_expr_eval_context_(self):
return LazyCTX(self)
def __eq__(self, other):
raise RuntimeError, " Operator not defined "
def __ilshift__(self, A):
def _ilshift_(self, A):
""" A can be two things:
* G <<= any_init will init the GFBloc with the initializer
* G <<= g2 where g2 is a GFBloc will copy g2 into self

View File

@ -26,17 +26,27 @@ It is imported with the command::
>>> from pytriqs.gf.local import *
"""
from gf import TailGf
from gf import *
from inverse import inverse
from gf_imfreq import GfImFreq
from gf_imtime import GfImTime
from gf_refreq import GfReFreq
from gf_retime import GfReTime
#from gf_imfreq import GfImFreq
#from gf_imtime import GfImTime
#from gf_refreq import GfReFreq
#from gf_retime import GfReTime
#from gf_two_real_times import GfTwoRealTime
from gf_legendre import GfLegendre
#from gf_legendre import GfLegendre
from block_gf import BlockGf
from descriptors import Omega, iOmega_n, SemiCircular, Wilson, Fourier, InverseFourier, LegendreToMatsubara, MatsubaraToLegendre
__all__ = ['Omega','iOmega_n','SemiCircular','Wilson','Fourier','InverseFourier','LegendreToMatsubara','MatsubaraToLegendre','lazy_expressions','TailGf','GfImFreq','GfImTime','GfReFreq','GfReTime','GfLegendre','BlockGf','inverse'] #,'GfTwoRealTime']
#__all__ = ['TailGf','GfImFreq','MeshImFreq']
__all__ = ['Omega','iOmega_n','SemiCircular','Wilson','Fourier','InverseFourier','LegendreToMatsubara','MatsubaraToLegendre','lazy_expressions','TailGf',
'GfImFreq','MeshImFreq',
'GfImTime', 'MeshImTime',
'GfReFreq', 'MeshReFreq',
'GfReTime', 'MeshReTime',
'make_gf_from_inverse_fourier',
'BlockGf','inverse'] #,'GfTwoRealTime']
#__all__ = ['Omega','iOmega_n','SemiCircular','Wilson','Fourier','InverseFourier','LegendreToMatsubara','MatsubaraToLegendre','lazy_expressions','TailGf','GfImFreq','GfImTime','GfReFreq','GfReTime','GfLegendre','BlockGf','inverse'] #,'GfTwoRealTime']

View File

@ -0,0 +1,156 @@
################################################################################
#
# TRIQS: a Toolbox for Research in Interacting Quantum Systems
#
# Copyright (C) 2011-2012 by M. Ferrero, O. Parcollet
#
# TRIQS is free software: you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# TRIQS is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# TRIQS. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
import numpy
import lazy_expressions, descriptor_base
#from gf import MeshImFreq
from types import IntType, SliceType, StringType
from tools import LazyCTX #, IndicesConverter, get_indices_in_dict, py_deserialize
from _gf_plot import PlotWrapperPartialReduce
#from gf import TailGf
#--------------------- [ ] operator ------------------------------------------
def __getitem__(self, key):
"""Key is a tuple of index (n1, n2) as defined at construction"""
if len(key) !=2: raise KeyError, "[ ] must be given two arguments"
sl1, sl2 = key
if type(sl1) == StringType and type(sl2) == StringType:
# Convert the indices to integer
indices_converter = [ IndicesConverter(self.indicesL), IndicesConverter(self.indicesR)]
sl1, sl2 = [ indices_converter[i].convertToNumpyIndex(k) for i, k in enumerate(key) ]
if type (sl1) != slice: sl1 = slice (sl1, sl1+1)
if type (sl2) != slice: sl2 = slice (sl2, sl2+1)
return self.__class__(indicesL = list(self.indicesL)[sl1],
indicesR = list(self.indicesR)[sl2],
name = self.name,
mesh = self.mesh,
data = self.data[:,sl1,sl2],
tail = self.tail._make_slice(sl1, sl2))
def __setitem__(self, key, val):
g = self.__getitem__(key)
g <<= val
#-------------- PLOT ---------------------------------------
def _real_plot(self):
"""Use self.real in a plot to plot only the real part"""
return PlotWrapperPartialReduce(self, RI='R')
def _imag_plot(self):
"""Use self.imag in a plot to plot only the imag part"""
return PlotWrapperPartialReduce(self, RI='I')
#-------- LAZY expression system -----------------------------------------
def add_precall (self, y):
if descriptor_base.is_lazy(y): return lazy_expressions.make_lazy(self) + y
def sub_precall (self, y):
if descriptor_base.is_lazy(y): return lazy_expressions.make_lazy(self) - y
def mul_precall (self, y):
if descriptor_base.is_lazy(y): return lazy_expressions.make_lazy(self) * y
def div_precall (self, y):
if descriptor_base.is_lazy(y): return lazy_expressions.make_lazy(self) / y
def _ilshift_(self, A):
""" A can be two things:
* G <<= any_init will init the GFBloc with the initializer
* G <<= g2 where g2 is a GFBloc will copy g2 into self
"""
import descriptors
if isinstance(A, self.__class__):
if self is not A: self.copy_from(A) # otherwise it is useless AND does not work !!
elif isinstance(A, lazy_expressions.LazyExpr): # A is a lazy_expression made of GF, scalars, descriptors
A2= descriptors.convert_scalar_to_const(A)
def e_t (x):
if not isinstance(x, descriptors.Base): return x
tmp = self.copy()
x(tmp)
return tmp
self.copy_from (lazy_expressions.eval_expr_with_context(e_t, A2) )
elif isinstance(A, lazy_expressions.LazyExprTerminal): #e.g. g<<= SemiCircular (...)
self <<= lazy_expressions.LazyExpr(A)
elif descriptors.is_scalar(A): #in the case it is a scalar ....
self <<= lazy_expressions.LazyExpr(A)
else:
raise RuntimeError, " <<= operator: RHS not understood"
return self
#---------------------------------------------------
def from_L_G_R(self, L, G, R):
N1 = self.data.shape[1]
N2 = self.data.shape[2]
assert L.shape[0] == N1
assert L.shape[1] == G.data.shape[1]
assert R.shape[0] == G.data.shape[2]
assert R.shape[1] == N2
MatrixStack(self.data).matmul_L_R(L, G.data, R)
# this might be a bit slow
for o in range(G.tail.order_min, G.tail.order_max+1):
self.tail[o] = numpy.dot(L, numpy.dot(G.tail[o], R))
self.tail.mask.fill(G.tail.order_max)
#---------------------------------------------------
def invert(self):
"""Invert the matrix for all arguments"""
MatrixStack(self.data).invert()
self.tail.invert()
#---------------------------------------------------
def transpose(self):
"""Transposes the GF Bloc: return a new transposed view"""
### WARNING: this depends on the C++ layering ....
return self.__class__(
indices = list(self.indices),
mesh = self.mesh,
data = self.data.transpose( (0, 2, 1) ),
tail = self.tail.transpose(),
name = self.name+'(t)')
#---------------------------------------------------
def conjugate(self):
"""Complex conjugate of the GF Bloc. It follow the policy of numpy and
make a copy only if the Green function is complex valued"""
return self.__class__(
indices = list(self.indices),
mesh = self.mesh,
data = self.data.conjugate(),
tail = self.tail.conjugate(),
name = self.name+'*')
#------------------ Density -----------------------------------
def total_density(self):
"""Trace density"""
return numpy.trace(self.density())

View File

@ -0,0 +1,112 @@
from scipy.optimize import leastsq
from tools import get_indices_in_dict
import _gf_plot
import numpy
def init( mesh= None, shape =None, name = 'g', **d):
"""
"""
if mesh is None :
from gf import MeshImFreq
if 'beta' not in d : raise ValueError, "beta not provided"
beta = float(d.pop('beta'))
n_points = d.pop('n_points',1025)
stat = d.pop('statistic','Fermion')
positive_only = d.pop('positive_only',True)
mesh = MeshImFreq(beta,stat,n_points, positive_only)
indices_pack = get_indices_in_dict(d)
if not shape :
assert indices_pack, "No shape, no indices !"
indicesL, indicesR = indices_pack
shape = len(indicesL),len(indicesR)
#data = d.pop('data') if 'data' in d else numpy.zeros((len(mesh),N1,N2), self.dtype )
#tail = d.pop('tail') if 'tail' in d else TailGf(shape = (N1,N2))
#symmetry = d.pop('symmetry', Nothing())
return (mesh, shape, indices_pack, name), {}
#return mesh, data, tail, symmetry, indices_pack, name
#-------------- PLOT ---------------------------------------
def plot(self, opt_dict):
""" Plot protocol. opt_dict can contain :
* :param RIS: 'R', 'I', 'S', 'RI' [ default]
* :param x_window: (xmin,xmax) or None [default]
* :param name: a string [default ='']. If not '', it remplaces the name of the function just for this plot.
"""
return _gf_plot.plot_base( self, opt_dict, r'$\omega_n$',
lambda name : r'%s$(i\omega_n)$'%name, True, [x.imag for x in self.mesh] )
#-------------- OTHER OPERATIONS -----------------------------------------------------
def replace_by_tail(self,start) :
d = self.data
t = self.tail
for n, om in enumerate(self.mesh) :
if n >= start : d[n,:,:] = t(om)
def fit_tail(self, fixed_coef, order_max, fit_start, fit_stop, replace_tail = True):
"""
Fit the tail of the Green's function
Input:
- fixed_coef: a 3-dim array of known coefficients for the fit starting from the order -1
- order_max: highest order in the fit
- fit_start, fit_stop: fit the data between fit_start and fit_stop
Output:
On output all the data above fit_start is replaced by the fitted tail
and the new moments are included in the Green's function
"""
# Turn known_coefs into a numpy array if ever it is not already the case
known_coef = fixed_coef
# Change the order_max
# It is assumed that any known_coef will start at order -1
self.tail.zero()
self.tail.mask.fill(order_max)
# Fill up two arrays with the frequencies and values over the range of interest
ninit, nstop = 0, -1
x = []
for om in self.mesh:
if (om.imag < fit_start): ninit = ninit+1
if (om.imag <= fit_stop): nstop = nstop+1
if (om.imag <= fit_stop and om.imag >= fit_start): x += [om]
omegas = numpy.array(x)
values = self.data[ninit:nstop+1,:,:]
# Loop over the indices of the Green's function
for n1,indR in enumerate(self.indicesR):
for n2,indL in enumerate(self.indicesL):
# Construct the part of the fitting functions which is known
f_known = numpy.zeros((len(omegas)),numpy.complex)
for order in range(len(known_coef[n1][n2])):
f_known += known_coef[n1][n2][order]*omegas**(1-order)
# Compute how many free parameters we have and give an initial guess
len_param = order_max-len(known_coef[n1][n2])+2
p0 = len_param*[1.0]
# This is the function to be minimized, the diff between the original
# data in values and the fitting function
def fct(p):
y_fct = 1.0*f_known
for order in range(len_param):
y_fct += p[order]*omegas**(1-len(known_coef[n1][n2])-order)
y_fct -= values[:,n1,n2]
return abs(y_fct)
# Now call the minimizing function
sol = leastsq(fct, p0, maxfev=1000*len_param)
# Put the known and the new found moments in the tail
for order in range(len(known_coef[n1][n2])):
self.tail[order-1][n1,n2] = numpy.array([[ known_coef[n1][n2][order] ]])
for order, moment in enumerate(sol[0]):
self.tail[len(known_coef[n1][n2])+order-1][n1,n2] = numpy.array([[ moment ]])
self.tail.mask.fill(order_max)
# Replace then end of the Green's function by the tail
if replace_tail: self.replace_by_tail(ninit);

View File

@ -0,0 +1,40 @@
from tools import get_indices_in_dict
import _gf_plot
import numpy
def init( mesh= None, shape =None, name = 'g', **d):
"""
"""
if mesh is None :
from gf import MeshImTime
if 'beta' not in d : raise ValueError, "beta not provided"
beta = float(d.pop('beta'))
n_max = d.pop('n_points',10000)
stat = d.pop('statistic','Fermion')
kind = d.pop('kind','half_bins')
mesh = MeshImTime(beta,stat,n_max,kind)
indices_pack = get_indices_in_dict(d)
if not shape :
assert indices_pack, "No shape, no indices !"
indicesL, indicesR = indices_pack
shape = len(indicesL),len(indicesR)
#data = d.pop('data') if 'data' in d else numpy.zeros((len(mesh),N1,N2), self.dtype )
#tail = d.pop('tail') if 'tail' in d else TailGf(shape = (N1,N2))
#symmetry = d.pop('symmetry', Nothing())
return (mesh, shape, indices_pack, name), {}
#return mesh, data, tail, symmetry, indices_pack, name
#-------------- PLOT ---------------------------------------
def plot(self, opt_dict):
""" Plot protocol. opt_dict can contain :
* :param RI: 'R', 'I', 'RI' [ default]
* :param x_window: (xmin,xmax) or None [default]
* :param name: a string [default ='']. If not '', it remplaces the name of the function just for this plot.
"""
has_complex_value = False
return _gf_plot.plot_base( self, opt_dict, r'$\tau$', lambda name : r'%s$(\tau)$'%name, has_complex_value , list(self.mesh) )

View File

@ -31,8 +31,8 @@ def plot_base (self, opt_dict, xlabel, ylabel, use_ris, X):
'xlabel' : xlabel,
'ylabel' : ylabel (self.name),
'xdata' : X[sl],
'label' : Name if Name else prefix + B.name ,
'ydata' : f( B.data[sl,0,0] ) } for (i,j,B) in self ]
'label' : Name if Name else prefix + "%s_%s"%(i,j),
'ydata' : f( self.data[sl,i,j] ) } for i in range(self.target_shape[0]) for j in range(self.target_shape[1])]
if use_ris :
ris = opt_dict.pop('RI','RI')
@ -51,3 +51,25 @@ def plot_base (self, opt_dict, xlabel, ylabel, use_ris, X):
if NamePrefix: self.name = name_save
return res
#------------------
def x_data_view(self, x_window = None, flatten_y = False):
"""
:param x_window: the window of x variable (omega/omega_n/t/tau) for which data is requested
if None, take the full window
:param flatten_y: If the Green function is of size (1, 1) flatten the array as a 1d array
:rtype: a tuple (X, data) where
* X is a 1d numpy of the x variable inside the window requested
* data is a 3d numpy array of dim (:,:, len(X)), the corresponding slice of data
If flatten_y is True and dim is (1, 1, *), returns a 1d numpy
"""
X = [x.imag for x in self.mesh] if type(self.mesh) == MeshImFreq else [x for x in self.mesh]
X, data = numpy.array(X), self.data
if x_window:
sl = clip_array (X, *x_window) if x_window else slice(len(X)) # the slice due to clip option x_window
X, data = X[sl], data[sl,:,:]
if flatten_y and data.shape[1:3]==(1, 1): data = data[:,0,0]
return X, data

View File

@ -0,0 +1,38 @@
from tools import get_indices_in_dict
import _gf_plot
import numpy
def init( mesh= None, shape =None, name = 'g', **d):
"""
"""
if mesh is None :
from gf import MeshReFreq
window = d.pop('window')
omega_min = window[0]
omega_max = window[1]
n_max = d.pop('n_points',10000)
kind = d.pop('kind','full_bins')
mesh = MeshReFreq(omega_min, omega_max, n_max, kind)
indices_pack = get_indices_in_dict(d)
if not shape :
assert indices_pack, "No shape, no indices !"
indicesL, indicesR = indices_pack
shape = len(indicesL),len(indicesR)
#data = d.pop('data') if 'data' in d else numpy.zeros((len(mesh),N1,N2), self.dtype )
#tail = d.pop('tail') if 'tail' in d else TailGf(shape = (N1,N2))
#symmetry = d.pop('symmetry', Nothing())
return (mesh, shape, indices_pack, name), {}
#-------------- PLOT ---------------------------------------
def plot(self, opt_dict):
""" Plot protocol. opt_dict can contain :
* :param RI: 'R', 'I', 'RI' [ default]
* :param x_window: (xmin,xmax) or None [default]
* :param name: a string [default ='']. If not '', it remplaces the name of the function just for this plot.
"""
return _gf_plot.plot_base(self, opt_dict, r'$\omega$', lambda name : r'%s$(\omega)$'%name, True, list(self.mesh))

View File

@ -0,0 +1,38 @@
from tools import get_indices_in_dict
import _gf_plot
import numpy
def init( mesh= None, shape =None, name = 'g', **d):
"""
"""
if mesh is None :
from gf import MeshReTime
window = d.pop('window')
t_min = window[0]
t_max = window[1]
n_max = d.pop('n_points',10000)
kind = d.pop('kind','full_bins')
mesh = MeshReTime(t_min, t_max, n_max, kind)
indices_pack = get_indices_in_dict(d)
if not shape :
assert indices_pack, "No shape, no indices !"
indicesL, indicesR = indices_pack
shape = len(indicesL),len(indicesR)
#data = d.pop('data') if 'data' in d else numpy.zeros((len(mesh),N1,N2), self.dtype )
#tail = d.pop('tail') if 'tail' in d else TailGf(shape = (N1,N2))
#symmetry = d.pop('symmetry', Nothing())
return (mesh, shape, indices_pack, name), {}
#-------------- PLOT ---------------------------------------
def plot(self, opt_dict):
""" Plot protocol. opt_dict can contain :
* :param RI: 'R', 'I', 'RI' [ default]
* :param x_window: (xmin,xmax) or None [default]
* :param name: a string [default ='']. If not '', it remplaces the name of the function just for this plot.
"""
return _gf_plot.plot_base(self, opt_dict, r'$\t$', lambda name : r'%s$(\t)$'%name, True, list(self.mesh))

View File

@ -1,4 +1,3 @@
################################################################################
#
# TRIQS: a Toolbox for Research in Interacting Quantum Systems
@ -22,7 +21,7 @@
from itertools import izip
import operator
from impl_plot import PlotWrapperPartialReduce
from _gf_plot import PlotWrapperPartialReduce
def call_factory_from_dict (cl,dic) :
"""Given a class cl and a dict dic, it calls cl.__factory_from_dict__(dic)"""

View File

@ -0,0 +1,150 @@
################################################################################
#
# TRIQS: a Toolbox for Research in Interacting Quantum Systems
#
# Copyright (C) 2011 by M. Ferrero, O. Parcollet
#
# TRIQS is free software: you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# TRIQS is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# TRIQS. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
r""" """
import numpy
from math import *
from lazy_expressions import LazyExprTerminal, LazyExpr, transform
def is_lazy(y):
#return type(y) in [ Omega_, LazyExpr]
return isinstance(y,(Omega_, LazyExpr, LazyExprTerminal))
def is_scalar(x):
return type(x) in [ type(1), type(1.0), type(1j), numpy.ndarray, numpy.int, numpy.int_, numpy.int8, numpy.int16, numpy.int32, numpy.float, numpy.float_, numpy.float32, numpy.float64, numpy.complex, numpy.complex_, numpy.complex64, numpy.complex128 ]
def convert_scalar_to_const(expr):
# if the expression is a pure scalar, replace it by Const
t= expr.get_terminal()
if is_scalar(t): return LazyExpr( Const(t) )
# otherwise: replace all scalar appearing in +/- operations by Const
def act (tag, childs):
if tag in ["+", "-"]:
for n,c in enumerate(childs):
t = c.get_terminal()
if is_scalar(t): childs[n] = Const (t)
return (tag,childs)
return transform(expr, act)
class Base (LazyExprTerminal):
def __init__(self,**kargs):
self.__dict__.update(kargs)
#########################################################################
class Function (Base):
r"""
Stores a python function and a tail.
If the Green's function is defined on an array of points :math:`x_i`, then it will be initialized to :math:`F(x_i)`.
"""
def __init__ (self, function, tail=None):
r"""
:param function: the function :math:`\omega \rightarrow function(\omega)`
:param tail: The tail. Use None if you do not wish to use a tail (will be put to 0)
"""
Base.__init__(self, function=function, tail=tail)
def __call__(self,G):
if not(callable(self.function)): raise RuntimeError, "GFInitializer.Function: f must be callable"
res = G.data[:,:,:]
try:
for n,om in enumerate(G.mesh): res[n,:,:] = self.function(om)
except:
print "The given function has a problem..."
raise
if self.tail: G.tail.copy_from(self.tail)
return G
#########################################################################
class Const(Base):
def __init__ (self, C):
Base.__init__(self, C=C)
def __call__(self,G):
C = self.C
if G.mesh.__class__.__name__ not in ['MeshImFreq', 'MeshReFreq']:
raise TypeError, "This initializer is only correct in frequency"
if not isinstance(C,numpy.ndarray):
assert G.N1==G.N2, "Const only applies to square G"
C = C*numpy.identity(G.N1)
if C.shape !=(G.N1,G.N2): raise RuntimeError, "Size of constant incorrect"
G.tail.zero()
G.tail[0][:,:] = C
Function(lambda om: C, None)(G)
return G
#########################################################################
class Omega_(Base):
r"""The function:math:`\omega \rightarrow \omega` """
def __str__(self): return "Omega"
def __call__(self,G):
if G.mesh.__class__.__name__ not in ['MeshImFreq', 'MeshReFreq']:
raise TypeError, "This initializer is only correct in frequency"
Id = numpy.identity(G.N1)
G.tail.zero()
G.tail[-1][:,:] = Id
for n,om in enumerate(G.mesh): G.data[n,:,:] = om*Id
return G
##########################################################################
Omega = Omega_()
iOmega_n = Omega_()
##########################################################################
class A_Omega_Plus_B(Base):
"deprecated. do not use"
def __init__ (self, A=1, B=0, Invert= False):
Base.__init__(self, A=A, B=B,Invert=Invert)
def __call__(self,G):
A,B = self.A, self.B
if G.mesh.__class__.__name__ not in ['MeshImFreq', 'MeshReFreq']:
raise TypeError, "This initializer is only correct in frequency"
if not isinstance(A,numpy.ndarray): A = A*numpy.identity(G.N1)
if not isinstance(B,numpy.ndarray): B = B*numpy.identity(G.N1)
if A.shape !=(G.N1,G.N2): raise RuntimeError, "Size of A incorrect"
if B.shape !=(G.N1,G.N2): raise RuntimeError, "Size of B incorrect"
G.tail.zero()
G.tail[-1][:,:] = A
G.tail[0][:,:] = B
Function(lambda om: A*om + B, None)(G)
if self.Invert: G.invert()
return G

View File

@ -21,134 +21,8 @@
r""" """
import numpy
from math import *
from descriptor_base import *
from gf import MeshImFreq, MeshReFreq
from lazy_expressions import LazyExprTerminal, LazyExpr, transform
def is_lazy(y):
#return type(y) in [ Omega_, LazyExpr]
return isinstance(y,(Omega_, LazyExpr, LazyExprTerminal))
def is_scalar(x):
return type(x) in [ type(1), type(1.0), type(1j), numpy.ndarray, numpy.int, numpy.int_, numpy.int8, numpy.int16, numpy.int32, numpy.float, numpy.float_, numpy.float32, numpy.float64, numpy.complex, numpy.complex_, numpy.complex64, numpy.complex128 ]
def convert_scalar_to_const(expr):
# if the expression is a pure scalar, replace it by Const
t= expr.get_terminal()
if is_scalar(t): return LazyExpr( Const(t) )
# otherwise: replace all scalar appearing in +/- operations by Const
def act (tag, childs):
if tag in ["+", "-"]:
for n,c in enumerate(childs):
t = c.get_terminal()
if is_scalar(t): childs[n] = Const (t)
return (tag,childs)
return transform(expr, act)
#########################################################################
class Base (LazyExprTerminal):
def __init__(self,**kargs):
self.__dict__.update(kargs)
#########################################################################
class Function (Base):
r"""
Stores a python function and a tail.
If the Green's function is defined on an array of points :math:`x_i`, then it will be initialized to :math:`F(x_i)`.
"""
def __init__ (self, function, tail=None):
r"""
:param function: the function :math:`\omega \rightarrow function(\omega)`
:param tail: The tail. Use None if you do not wish to use a tail (will be put to 0)
"""
Base.__init__(self, function=function, tail=tail)
def __call__(self,G):
if not(callable(self.function)): raise RuntimeError, "GFInitializer.Function: f must be callable"
res = G.data[:,:,:]
try:
for n,om in enumerate(G.mesh): res[n,:,:] = self.function(om)
except:
print "The given function has a problem..."
raise
if self.tail: G.tail.copy_from(self.tail)
return G
#########################################################################
class Const(Base):
def __init__ (self, C):
Base.__init__(self, C=C)
def __call__(self,G):
C = self.C
if G.mesh.__class__.__name__ not in ['MeshImFreq', 'MeshReFreq']:
raise TypeError, "This initializer is only correct in frequency"
if not isinstance(C,numpy.ndarray):
assert G.N1==G.N2, "Const only applies to square G"
C = C*numpy.identity(G.N1)
if C.shape !=(G.N1,G.N2): raise RuntimeError, "Size of constant incorrect"
G.tail.zero()
G.tail[0][:,:] = C
Function(lambda om: C, None)(G)
return G
#########################################################################
class Omega_(Base):
r"""The function:math:`\omega \rightarrow \omega` """
def __str__(self): return "Omega"
def __call__(self,G):
if G.mesh.__class__.__name__ not in ['MeshImFreq', 'MeshReFreq']:
raise TypeError, "This initializer is only correct in frequency"
Id = numpy.identity(G.N1)
G.tail.zero()
G.tail[-1][:,:] = Id
for n,om in enumerate(G.mesh): G.data[n,:,:] = om*Id
return G
##########################################################################
Omega = Omega_()
iOmega_n = Omega_()
##########################################################################
class A_Omega_Plus_B(Base):
"deprecated. do not use"
def __init__ (self, A=1, B=0, Invert= False):
Base.__init__(self, A=A, B=B,Invert=Invert)
def __call__(self,G):
A,B = self.A, self.B
if G.mesh.__class__.__name__ not in ['MeshImFreq', 'MeshReFreq']:
raise TypeError, "This initializer is only correct in frequency"
if not isinstance(A,numpy.ndarray): A = A*numpy.identity(G.N1)
if not isinstance(B,numpy.ndarray): B = B*numpy.identity(G.N1)
if A.shape !=(G.N1,G.N2): raise RuntimeError, "Size of A incorrect"
if B.shape !=(G.N1,G.N2): raise RuntimeError, "Size of B incorrect"
G.tail.zero()
G.tail[-1][:,:] = A
G.tail[0][:,:] = B
Function(lambda om: A*om + B, None)(G)
if self.Invert: G.invert()
return G
#######################################

395
pytriqs/gf/local/gf_desc.py Normal file
View File

@ -0,0 +1,395 @@
from wrap_generator import *
module = module_(full_name = "pytriqs.gf.local.gf", doc = "Local Green functions ...")
module.add_include("<triqs/gfs.hpp>")
module.add_include("<triqs/gfs/local/functions.hpp>")
module.add_include("<triqs/gfs/local/pade.hpp>")
module.add_using("namespace triqs::arrays")
module.add_using("namespace triqs::gfs")
module.add_using("namespace triqs::gfs::local")
module.add_using("triqs::utility::mini_vector")
########################
## TailGf
########################
t = class_( py_type = "TailGf",
c_type = "local::tail_view",
serializable= "tuple",
is_printable= True,
arithmetic = ("algebra","double")
)
t.add_constructor(signature = "(int N1, int N2, int size=10, int order_min=-1)",
doc = "DOC of constructor")
#t.add_constructor(doc = "DOC of constructor", signature = "(array_view<dcomplex,3> d, array_view<long,2> m, long i)", python_precall = "tail_aux.tail_construct")
t.add_property(name = "data",
getter = cfunction(c_name="data", signature = "array_view<dcomplex,3>()"),
doc = "Access to the data array")
##tail.add_property(name = "shape", getter = cfunction(c_name="shape", signature = "int()", doc = "Shape"))
t.add_property(getter = cfunction(c_name="size", signature = "int()"),
doc = "size")
t.add_property(getter = cfunction(c_name="order_min", signature = "int()"),
doc = "Min order of the expansion")
t.add_property(getter = cfunction(c_name="order_max", signature = "int()"),
doc = "Max order of the expansion")
t.add_property(name = "mask",
getter = cfunction(c_name="mask_view", signature = "array_view<long,2>()"),
doc = "Access to the mask")
t.add_method(py_name = "has_coef",
calling_pattern = "bool result = (i >=self_c.order_min()) && (i<=self_c.order_max())",
signature = "bool(int i)",
doc = "A method which did not exist in C++")
# strange, I should not quality : ADL ??
t.add_method(py_name = "invert",
calling_pattern = "self_c = local::inverse(self_c)",
signature = "void()",
doc = "Invert")
t.add_method(py_name = "zero",
calling_pattern = "self_c = 0",
signature = "void()",
doc = "Sets the expansion to 0")
t.add_method_copy()
t.add_method_copy_from()
t.add_call(calling_pattern = "auto result = self_c.evaluate(u)",
signature = "dcomplex(dcomplex u)",
doc = "")
t.number_protocol['multiply'].add_overload(calling_pattern = "*", signature = "tail(matrix<dcomplex> x,tail_view y)") #'x'), (self.c_type,'y')], rtype = self.c_type)
t.number_protocol['multiply'].add_overload(calling_pattern = "*", signature = "tail(tail_view x,matrix<dcomplex> y)") #'x'), (self.c_type,'y')], rtype = self.c_type)
# ok, but MISSING CHECK SIZE
t.add_getitem(c_name = "operator()",
signature = "matrix_view<dcomplex>(int i)",
doc = "Returns the i-th coefficient of the expansion, or order Om^i")
t.add_setitem(calling_pattern = "self_c(i) = m",
signature = "void(int i, matrix<dcomplex> m)", # I use matrix, not view. It makes a copy, but ensure I can pass double, int, and numpy will convert.
doc = "Sets the i-th coefficient of the expansion, or order Om^i")
module.add_class(t)
########################
## enums
########################
module.add_enum(c_name = "statistic_enum",
values = ["Fermion","Boson"])
module.add_enum(c_name = "mesh_kind",
values = ["half_bins","full_bins","without_last"])
########################
## Mesh generic
########################
def make_mesh( py_type, c_tag, has_kind=True, is_im=False) :
m = class_( py_type = py_type,
c_type = "gf_mesh<%s>"%c_tag,
serializable= "tuple",
is_printable= True,
)
if is_im :
m.add_property(name = "beta",
getter = cfunction(calling_pattern="double result = self_c.domain().beta",
signature = "double()",
doc = "Inverse temperature"))
m.add_property(name = "statistic",
getter = cfunction(calling_pattern="statistic_enum result = self_c.domain().statistic", signature = "statistic_enum()"),
doc = "Statistic")
m.add_len(calling_pattern = "int result = self_c.size()", doc = "Size of the mesh")
m.add_iterator(c_cast_type = "dcomplex")
if has_kind :
m.add_property(name = "kind",
getter = cfunction(calling_pattern="mesh_kind result = self_c.kind()", signature = "mesh_kind()"),
doc = "")
#def __richcmp__(MeshImFreq self, MeshImFreq other,int op) :
# if op ==2 : # ==
# return self._c == other._c
#def __reduce__(self):
# return self.__class__, (self.beta, self.statistic, len(self))
return m
########################
## MeshImFreq
########################
m = make_mesh( py_type = "MeshImFreq", c_tag = "imfreq", has_kind = False, is_im = True)
m.add_constructor(signature = "(double beta, statistic_enum S, int n_max=1025, bool positive_only=true)")
module.add_class(m)
########################
## MeshImTime
########################
m = make_mesh(py_type = "MeshImTime", c_tag = "imtime", is_im = True)
m.add_constructor(signature = "(double beta, statistic_enum S, int n_max, mesh_kind kind)")
module.add_class(m)
########################
## MeshReFreq
########################
m = make_mesh(py_type = "MeshReFreq", c_tag = "refreq")
m.add_constructor(signature = "(double omega_min, double omega_max, int n_max, mesh_kind kind)")
m.add_property(name = "omega_min",
getter = cfunction(calling_pattern="double result = self_c.x_min()",
signature = "double()",
doc = "Inverse temperature"))
m.add_property(name = "omega_max",
getter = cfunction(calling_pattern="double result = self_c.x_max()",
signature = "double()",
doc = "Inverse temperature"))
module.add_class(m)
########################
## MeshReTime
########################
m = make_mesh(py_type = "MeshReTime", c_tag = "retime")
m.add_constructor(signature = "(double t_min, double t_max, int n_max, mesh_kind kind)")
m.add_property(name = "t_min",
getter = cfunction(calling_pattern="double result = self_c.x_min()",
signature = "double()",
doc = "Inverse temperature"))
m.add_property(name = "t_max",
getter = cfunction(calling_pattern="double result = self_c.x_max()",
signature = "double()",
doc = "Inverse temperature"))
module.add_class(m)
########################
## Gf Generic : common to all 5 one variable gf
########################
def make_gf( py_type, c_tag, is_complex_data = True, is_im = False) :
data_type = "std::complex<double>" if is_complex_data else "double"
g = class_(
py_type = py_type,
c_type = "gf_view<%s>"%c_tag,
#serializable= "boost",
serializable= "tuple",
is_printable= True,
hdf5 = True,
arithmetic = ("algebra",data_type)
)
g.add_constructor(signature = "(gf_mesh<%s> mesh, mini_vector<size_t,2> shape, std::vector<std::vector<std::string>> indices = {}, std::string name = "")"%c_tag,
python_precall = "pytriqs.gf.local._gf_%s.init"%c_tag)
g.add_method_copy()
g.add_method_copy_from()
# properties
g.add_member(c_name = "name", c_type ="std::string", doc = "Name of the Green function (used for plotting only)")
if is_im :
g.add_property(name = "beta",
getter = cfunction(calling_pattern="double result = self_c.domain().beta", signature = "double()"),
doc = "Inverse temperature")
g.add_property(name = "statistic",
getter = cfunction(calling_pattern="statistic_enum result = self_c.domain().statistic", signature = "statistic_enum()"),
doc = "Statistic")
g.add_property(name = "mesh",
getter = cfunction(c_name="mesh", signature = "gf_mesh<%s>()"%c_tag),
doc ="The mesh")
g.add_property(name = "data",
getter = cfunction(calling_pattern="auto result = self_c.data()", signature = "array_view<%s,3>()"%data_type),
doc ="The data ")
g.add_property(name = "target_shape",
getter = cfunction(calling_pattern="auto result = get_target_shape(self_c)", signature = "shape_type()"),
doc = "")
g.add_property(name = "tail",
getter = cfunction(c_name="singularity", signature = "local::tail_view()"),
doc ="The high frequency tail")
g.add_property(name = "indices",
getter = cfunction(calling_pattern="auto result = self_c.indices()[0]", signature = "std::vector<std::string>()"),
doc ="The indices(L)")
# backward compatibility
g.add_property(name = "N1",
getter = cfunction(calling_pattern="int result = get_target_shape(self_c)[0]", signature = "int()"),
doc = "")
g.add_property(name = "N2",
getter = cfunction(calling_pattern="int result = get_target_shape(self_c)[1]", signature = "int()"),
doc = "")
# []
g.add_getitem(signature = "gf_view<%s>(range r1, range r2)"%c_tag,
calling_pattern= "auto result = slice_target(self_c,r1,r2)",
doc = " DOC to be written ")
g.add_getitem(signature = "gf_view<%s>(std::string i1, std::string i2)"%c_tag,
calling_pattern= "auto result = slice_target(self_c,self_c.indices().convert_index(i1,0),self_c.indices().convert_index(i2,1))",
doc = " DOC to be written ")
g.add_setitem(signature = "void(PyObject* r1, PyObject* r2, PyObject* val)",
calling_pattern=
"""
pyref gs_py = PyObject_GetItem(self,Py_BuildValue("(NN)", r1,r2)); // gs = self[r1,r2]
pyref res = PyNumber_InPlaceLshift(gs_py,val); // gs <<= val
""",
no_self_c = True, # avoid a warning
doc = " doc [] set ")
# Plot
g.add_property(name = "real",
getter = "pytriqs.gf.local._gf_common._real_plot",
doc ="real option for plotting")
g.add_property(name = "imag",
getter = "pytriqs.gf.local._gf_common._imag_plot",
doc ="imag option for plotting")
# Lazy system
g.add_pure_python_method("pytriqs.gf.local._gf_common.LazyCTX", py_name = "__lazy_expr_eval_context__")
g.number_protocol['add'].python_precall = "pytriqs.gf.local._gf_common.add_precall"
g.number_protocol['subtract'].python_precall = "pytriqs.gf.local._gf_common.sub_precall"
g.number_protocol['multiply'].python_precall = "pytriqs.gf.local._gf_common.mul_precall"
g.number_protocol['divide'].python_precall = "pytriqs.gf.local._gf_common.div_precall"
g.number_protocol['inplace_lshift'] = pyfunction(py_name ="__inplace_lshift__", python_precall = "pytriqs.gf.local._gf_common._ilshift_", arity = 2)
g.add_method(py_name = "invert", calling_pattern = "invert_in_place(self_c)" , signature = "void()", doc = "Invert (in place)")
if c_tag != "imtime" :
g.add_method(py_name = "conjugate", calling_pattern = "auto result = conj(self_c)" , signature = "gf<%s>()"%c_tag, doc = "Return a new function, conjugate of self.")
g.number_protocol['multiply'].add_overload(calling_pattern = "*", signature = "gf<%s>(matrix<%s> x,gf<%s> y)"%(c_tag,data_type,c_tag)) #'x'), (self.c_type,'y')], rtype = self.c_type)
g.number_protocol['multiply'].add_overload(calling_pattern = "*", signature = "gf<%s>(gf<%s> x,matrix<%s> y)"%(c_tag,c_tag,data_type)) #'x'), (self.c_type,'y')], rtype = self.c_type)
g.add_method(py_name = "from_L_G_R",
calling_pattern = "self_c = L_G_R(l,g,r)",
signature = "void(matrix<%s> l,gf<%s> g,matrix<%s> r)"%(data_type,c_tag,data_type),
doc = "self <<= l * g * r")
g.add_method(py_name = "zero",
calling_pattern = "self_c = 0",
signature = "void()",
doc = "Put the Green function to 0")
# Pure python methods
g.add_pure_python_method("pytriqs.gf.local._gf_%s.plot"%c_tag, py_name = "_plot_")
return g
########################
## GfImFreq
########################
g = make_gf(py_type = "GfImFreq", c_tag = "imfreq", is_im = True)
#g.add_method(py_name = "set_from_fourier", c_name = "fourier", signature = "void()", doc = "Fills self with the Fourier transform of gt")
#g.add_method(py_name = "set_from_legendre", c_name = "fourier", signature = "void()", doc = "Fills self with the Legendre transform of gl")
g.add_method(py_name = "density",
calling_pattern = "auto result = density(self_c)",
signature = "matrix_view<double>()",
doc = "Density, as a matrix, computed from a Matsubara sum")
g.add_method(py_name = "total_density",
calling_pattern = "auto result = trace(density(self_c))",
signature = "double()",
doc = "Trace of density")
g.add_method(py_name = "set_from_fourier",
signature = "void(gf_view<imtime> gt)",
calling_pattern = "self_c = fourier(*gt)",
doc = """Fills self with the Fourier transform of gt""")
# Pure python methods
g.add_pure_python_method("pytriqs.gf.local._gf_imfreq.replace_by_tail")
g.add_pure_python_method("pytriqs.gf.local._gf_imfreq.fit_tail")
module.add_class(g)
########################
## GfImTime
########################
g = make_gf(py_type = "GfImTime", c_tag = "imtime", is_complex_data = False, is_im = True)
g.add_method(py_name = "set_from_inverse_fourier",
signature = "void(gf_view<imfreq> gw)",
calling_pattern = "self_c = inverse_fourier(*gw)",
doc = """Fills self with the Inverse Fourier transform of gw""")
module.add_class(g)
########################
## GfReFreq
########################
g = make_gf(py_type = "GfReFreq", c_tag = "refreq")
g.add_method(py_name = "set_from_fourier",
signature = "void(gf_view<retime> gt)",
calling_pattern = "self_c = fourier(*gt)",
doc = """Fills self with the Fourier transform of gt""")
g.add_method(py_name = "set_from_pade",
signature = "void(gf_view<imfreq> gw, int n_points = 100, double freq_offset = 0.0)",
calling_pattern = "pade(self_c,*gw,n_points, freq_offset)",
doc = """ TO BE WRITTEN""")
module.add_class(g)
########################
## GfReTime
########################
g = make_gf(py_type = "GfReTime", c_tag = "retime")
g.add_method(py_name = "set_from_inverse_fourier",
signature = "void(gf_view<refreq> gw)",
calling_pattern = "self_c = inverse_fourier(*gw)",
doc = """Fills self with the Inverse Fourier transform of gw""")
module.add_class(g)
# EXPERIMENTAL : global fourier functions....
module.add_function(name = "make_gf_from_inverse_fourier", signature="gf_view<retime>(gf_view<refreq> gw)", doc ="")
########################
## Code generation
########################
if __name__ == '__main__' :
module.generate_code(mako_template = sys.argv[1], wrap_file = sys.argv[2])

View File

@ -1,5 +1,5 @@
from types import SliceType
import descriptors
import descriptor_base
class LazyCTX:
def __init__ (self, G):
@ -10,60 +10,16 @@ class LazyCTX:
def __eq__ (self, y):
return isinstance(y, self.__class__) and self._is_compatible_for_ops(y.G)
def __call__ (self, x):
if not isinstance(x, descriptors.Base): return x
if not isinstance(x, descriptor_base.Base): return x
tmp = self.G.copy()
x(tmp)
return tmp
class IndicesConverter:
def __init__(self, indices):
if indices == None: # none is a trivial converter
self.indices=None
return
try:
self.indices = list(indices)[:] # make a copy
except:
raise RuntimeError, "Indices must be a list or transformable into a list %s"(indices,)
assert len(set(repr(x) for x in self.indices)) == len(self.indices), "Error: indices are not unique !!!"
assert self.indices != [], "Error: indices are empty!!!"
try:
# a continuous list of ordered integers
self.__indices_are_sliceable = (self.indices== range(min(self.indices),max(self.indices)+1))
self.__indexmin = min(self.indices)
self.__indexmax = max(self.indices)
#self.__indexlen = self.__indexmax - self.__indexmin +1
except:
self.__indices_are_sliceable =False
self.Length = len(self.indices)
def convertToNumpyIndex(self,a,noslice=False):
"""
Transcription of one Python index/slice into the index/slice of the numpy
"""
if self.indices==None:
if type(a)==SliceType: return a
return a if noslice else slice(a,a+1,1)
if type(a)==SliceType:
if not self.__indices_are_sliceable: raise IndexError, "Indices %s can't be sliced"%self.indices
# put the slice to start at 0, and clip it
sta,sto,ste = slice(a.start, a.stop , a.step).indices(self.__indexmax+1)
return slice( max(0,sta-self.__indexmin), sto - self.__indexmin, ste)
try:
s1 = self.indices.index(a)
except:
raise IndexError, "Index %s out of range %s"%(a,self.indices)
return s1 if noslice else slice(s1,s1+1,1)
def get_indices_in_dict( d):
# exclusive: size = (n1,n2) or IndicesL/R
if 'indices_pack' in d:
indicesL, indicesR = d.pop('indices_pack')
else:
indicesL = list ( d.pop('indicesL',()) or d.pop('indices',()) )
indicesR = list ( d.pop('indicesR',()) or indicesL )
if not ( ('indicesL' in d and 'indicesR' in d) or 'indices' in d) : return ()
indicesL = list ( d.pop('indicesL',()) or d.pop('indices',()) )
indicesR = list ( d.pop('indicesR',()) or indicesL )
# Now check the indices
ty = set([type(x) for x in indicesL]+[type(x) for x in indicesR])
@ -76,7 +32,5 @@ def get_indices_in_dict( d):
return indicesL, indicesR
def py_deserialize( cls, s):
return cls(boost_serialization_string = s)

View File

@ -61,17 +61,11 @@ h['ga2'] = ga2
Gc = G.conjugate()
h['Gc'] = Gc
# Some tail stuff:
tailtempl={}
for sig,g in G:
tailtempl[sig] = copy.deepcopy(g.tail)
h['tt'] = tailtempl
# tranpose
g = G['a']
gt = G['a'].transpose()
gt.data[3,0,1] = 100
assert g.data[3,1,0] == 100
if 0 :
gt = G['a'].transpose()
gt.data[3,0,1] = 100
assert g.data[3,1,0] == 100
del h

View File

@ -19,6 +19,7 @@
*
******************************************************************************/
#pragma once
#define TRIQS_GF_INCLUDED
#include <triqs/utility/first_include.hpp>
#include <triqs/utility/std_vector_expr_template.hpp>
#include <triqs/utility/factory.hpp>

View File

@ -148,7 +148,9 @@ namespace gfs {
friend class boost::serialization::access;
/// BOOST Serialization
template <class Archive> void serialize(Archive &ar, const unsigned int version) {
ar &TRIQS_MAKE_NVP("domain", _dom);
ar &TRIQS_MAKE_NVP("beta", _dom.beta);
ar &TRIQS_MAKE_NVP("statistic", _dom.statistic);
//ar &TRIQS_MAKE_NVP("domain", _dom);
ar &TRIQS_MAKE_NVP("size", _n_pts);
ar &TRIQS_MAKE_NVP("kind", _positive_only);
}