-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgw_dmft.py
executable file
·3475 lines (2928 loc) · 135 KB
/
gw_dmft.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/usr/bin/env python
""" gw_dmft_new_exp.py
author : Li HUANG (email : li.huang@unifr.ch)
status : unstable
version : Ver.2015/01/07D
"""
# python standard library
import os
import sys
import time
import math
import shutil
import ctypes
# python 3rd-party library
import numpy
import scipy.weave
import scipy.interpolate
# python binding for ALPS
import pyalps.mpi
import pyalps.cthyb
def gw_dmft_config():
""" setup the config parameters for the gw + edmft code.
note: don't modify this function. if you want to change
the config parameters, please edit the in.param file
"""
# setup the parameters
# param : a dict object, used to record all the necessary parameters
param = {
'U' : [2.20 , "Onsite Coulomb interaction" ],
'V' : [0.00 , "Intersite Coulomb interaction" ],
't' : [0.25 , "Hopping parameter for 2D Hubbard model" ],
'mune' : [1.10 , "Chemical potential" ],
'beta' : [100. , "Inverse temperature" ],
'occup' : [1.00 , "Impurity occupation number" ],
'nkx' : [81 , "Number of k-points along x axis" ],
'nky' : [81 , "Number of k-points along y axis" ],
'niter' : [40 , "Maximum iteration number" ],
'alpha' : [0.7 , "Mixing parameter" ],
'nspin' : [2 , "Number of (spin-)orbitals" ],
'ntime' : [1024 , "Number of imaginary time points" ],
'nffrq' : [512 , "Number of fermionic frequencies" ],
'nbfrq' : [512 , "Number of bosonic frequencies" ],
'start' : [True , "Whether start from scratch" ],
'sy_ph' : [True , "Whether enforce symmetrization (PH)" ],
'sy_pm' : [True , "Whether enforce symmetrization (PM)" ],
'gw_ty' : [0 , "Whether the GW or FLEX part is on" ],
'gw_it' : [10000 , "After n-iter the GW or FLEX part is on" ],
'dc_ty' : [1 , "Scheme for double counting term" ],
'alps' : [False , "Whether the ct-hyb in ALPS is used" ],
'sskip' : [False , "Whether skip the ct-qmc impurity solver"],
}
# read config parameters from in.param file
# only master node can do it
if ( pyalps.mpi.rank == 0 ) :
# check whether file in.param exists
if os.path.isfile("in.param"):
in_param = {}
# read data, pay attention to their data type
f_in = open("in.param", "r")
for line in f_in:
A = line.split()
if A[2] == 'float':
in_param[A[0]] = float(A[4])
elif A[2] == 'int' :
in_param[A[0]] = int(A[4])
elif A[2] == 'bool' :
in_param[A[0]] = eval(A[4])
else :
sys.exit("FATAL ERROR : wrong data type")
# close the file handler
f_in.close()
# now the config parameters are stored in in_param dict,
# we need to transfer them to param dict
for key in in_param.iterkeys():
param[key][0] = in_param[key]
# if in.param does not exist, we have to stop the code
else:
sys.exit("FATAL ERROR : in.param does not exist")
# broadcast the param dict to all children processes
param = pyalps.mpi.broadcast(pyalps.mpi.world, param, 0)
pyalps.mpi.world.barrier()
# dump the parameters into the stdout
if pyalps.mpi.rank == 0:
print (">>> Listing parameters:")
for k in sorted(param.keys()):
print (" " + param[k][1].ljust(42) + " : " + k.rjust(5) + " : " + str(param[k][0]).rjust(5))
print ("")
return param
def gw_dmft_sconfig(p):
""" extract some key parameters which are useful for the impurity solver
p : param dictionary
"""
if p["alps"][0]: # just for alps ctqmc impurity solver
s_para = {
'U' : p["U" ][0], # Coulomb interaction
'BETA' : p["beta" ][0], # inversion temperature
'MU' : p["mune" ][0], # chemical potential
'N_MATSUBARA' : p["nffrq"][0], # number of matsubara frequencies
'N_TAU' : p["ntime"][0] - 1, # number of imaginary time points
}
return s_para
def gw_dmft_header():
""" print the header to standard terminal
"""
# only the master node can do it
if pyalps.mpi.rank != 0:
return
print ("GE_2d_new :: MBPT + DMFT")
print ("Ver.2015/01/03D (accelerated by mpi + scipy.weave)")
print ("Developed by Li HUANG (li.huang@unifr.ch)")
print ("Department of Physics, Fribourg University, Switzerland")
print ("")
print (">>> Starting in " + time.asctime())
print (">>> Using %i processors, current rank is %i" % (pyalps.mpi.size, pyalps.mpi.rank))
print ("")
def gw_dmft_iter(p, curr_iter):
""" print the iteration information to standard terminal
p : param dictionary
curr_iter : current iteration number
"""
# only the master node can do it
if pyalps.mpi.rank != 0:
return
for case in switch( p["gw_ty"][0] ):
if case(5):
print ("-"*60)
print (">>> SOPT + DMFT ITER : current => %i maximum => %i" % (curr_iter, p["niter"][0]))
print ("-"*60)
print ("")
break
if case(4):
print ("-"*60)
print (">>> TMA + DMFT ITER : current => %i maximum => %i" % (curr_iter, p["niter"][0]))
print ("-"*60)
print ("")
break
if case(3):
print ("-"*60)
print (">>> FLEX_pp + DMFT ITER : current => %i maximum => %i" % (curr_iter, p["niter"][0]))
print ("-"*60)
print ("")
break
if case(2):
print ("-"*60)
print (">>> FLEX_ph + DMFT ITER : current => %i maximum => %i" % (curr_iter, p["niter"][0]))
print ("-"*60)
print ("")
break
if case(1):
print ("-"*60)
print (">>> SGW + DMFT ITER : current => %i maximum => %i" % (curr_iter, p["niter"][0]))
print ("-"*60)
print ("")
break
if case(0):
print ("-"*60)
print (">>> DMFT ITER : current => %i maximum => %i" % (curr_iter, p["niter"][0]))
print ("-"*60)
print ("")
break
def gw_dmft_footer(gw_type):
""" print the footer to standard terminal
gw_type : the calculating scheme
"""
# only the master node can do it
if pyalps.mpi.rank != 0:
return
for case in switch( gw_type ):
if case(5):
print ("-"*60)
print (">>> SOPT + DMFT ITER : Finished")
print ("-"*60)
break
if case(4):
print ("-"*60)
print (">>> TMA + DMFT ITER : Finished")
print ("-"*60)
break
if case(3):
print ("-"*60)
print (">>> FLEX_pp + DMFT ITER : Finished")
print ("-"*60)
break
if case(2):
print ("-"*60)
print (">>> FLEX_ph + DMFT ITER : Finished")
print ("-"*60)
break
if case(1):
print ("-"*60)
print (">>> SGW + DMFT ITER : Finished")
print ("-"*60)
break
if case(0):
print ("-"*60)
print (">>> DMFT ITER : Finished")
print ("-"*60)
break
print (">>> Ending in " + time.asctime())
class switch(object):
""" This class provides the functionality we want. You only need to look
at this if you want to know how this works. It only needs to be defined
once, no need to muck around with its internals.
"""
def __init__(self, value):
""" class constructor for the switch
"""
self.__value = value
self.__fall = False
def __iter__(self):
""" return the match method once, then stop
"""
yield self.match
raise StopIteration
def match(self, *args):
""" indicate whether or not to enter a case suite
"""
if self.__fall or not args:
return True
elif self.__value in args:
self.__fall = True
return True
else:
return False
class Symm(object):
""" class Symm is used to symmetrize the input data over imaginary time
or spin. it can be also used to get rid of the real part or imaginary
part of the input data.
"""
@staticmethod
def symm_over_time(time_data):
""" perform symmetrization over imaginary time
time_data : imaginary time data
"""
# get number of elements
n = len(time_data)
for i in range(n):
raux = 0.5 * ( time_data[i] + time_data[n-1-i] )
time_data[i] = raux
time_data[n-1-i] = raux
@staticmethod
def symm_over_spin(time_data):
""" perform symmetrization over spin
time_data : imaginary time data
"""
raux = 0.5 * ( time_data[0] + time_data[1] )
time_data[0] = raux.copy()
time_data[1] = raux.copy()
del raux
@staticmethod
def symm_over_real(freq_data):
""" get rid of the imaginary part of the input data
freq_data : matsubara frequency data
"""
# get number of elements
n = len(freq_data)
for i in range(n):
freq_data[i] = freq_data[i].real + 0j
@staticmethod
def symm_over_imag(freq_data):
""" get rid of the real part of the input data
freq_data : matsubara frequency data
"""
# get number of elements
n = len(freq_data)
for i in range(n):
freq_data[i] = 0.0 + 1j * freq_data[i].imag
@staticmethod
def symm_smth_data(data, naver):
""" used to smooth 1-d float data
data : 1-d array
naver : used to define the smooth region
"""
# determine the length of 1-d data
n = len(data)
# create a temporary array
data_s = numpy.zeros_like(data, dtype = numpy.float)
for i in range(n):
# bracketing the smooth region [i1, i2]
i1 = i - naver
if i1 < 0: i1 = 0
i2 = i + naver
if i2 > n - 1: i2 = n - 1
# accumulate the data
count = 0
for j in range(i1, i2):
count = count + 1
data_s[i] = data_s[i] + data[j]
# calculate the average
data_s[i] = data_s[i] / float(count)
# copy smoothed data to original data
for i in range(n):
data[i] = data_s[i]
# release memory
del data_s
class Mesh(object):
""" class Mesh is used to define fermionic and bosonic meshes, imaginary
time mesh is also defined in this class.
note : the k-point mesh is defined in the Lattice class.
"""
def __init__(self, p):
""" class constructor for the Mesh
p : param dictionary
beta : inversion temperature
ntime : number of imaginary time points
nffrq : number of frequencies for fermionic mesh
nbfrq : number of frequencies for bosonic mesh
"""
self.__beta = p["beta"][0]
self.__ntime = p["ntime"][0]
self.__nffrq = p["nffrq"][0]
self.__nbfrq = p["nbfrq"][0]
def create_mesh(self, mesh_type):
""" construct imaginary time, fermionic or bosonic mesh according
to the mesh_type variable.
mesh_type : which type of mesh should be constructed
"""
if mesh_type == 1: # construct imaginary time mesh
tmesh = numpy.zeros(self.__ntime, dtype = numpy.float)
for i in range(len(tmesh)):
tmesh[i] = float(i) * self.__beta / ( self.__ntime - 1 )
return tmesh
elif mesh_type == 2: # construct fermionic mesh
fmesh = numpy.zeros(self.__nffrq, dtype = numpy.float)
for i in range(len(fmesh)):
fmesh[i] = ( 2.0 * i + 1.0 ) * math.pi / self.__beta
return fmesh
else: # construct bosonic mesh
bmesh = numpy.zeros(self.__nbfrq, dtype = numpy.float)
for i in range(len(bmesh)):
bmesh[i] = ( 2.0 * i + 0.0 ) * math.pi / self.__beta
return bmesh
@staticmethod
def create_time_mesh(beta, ntime):
""" construct the imaginary time mesh
beta : inversion temperature
ntime : number of imaginary time points
"""
tmesh = numpy.zeros(ntime, dtype = numpy.float)
for i in range(len(tmesh)):
tmesh[i] = float(i) * beta / ( ntime - 1)
return tmesh
@staticmethod
def create_fermion_mesh(beta, nffrq):
""" construct the fermionic mesh
beta : inversion temperature
nffrq : number of frequencies for fermionic mesh
"""
fmesh = numpy.zeros(nffrq, dtype = numpy.float)
for i in range(len(fmesh)):
fmesh[i] = ( 2.0 * i + 1.0 ) * math.pi / beta
return fmesh
@staticmethod
def create_boson_mesh(beta, nbfrq):
""" create the bosonic mesh
beta : inversion temperature
nbfrq : number of frequencies for bosonic mesh
"""
bmesh = numpy.zeros(nbfrq, dtype = numpy.float)
for i in range(len(bmesh)):
bmesh[i] = ( 2.0 * i + 0.0 ) * math.pi / beta
return bmesh
class Dump(object):
""" class Dump is used to dump the key variables to the disk file.
"""
@staticmethod
def dump_time_data1(file_name, time_mesh, time_data):
""" dump the imaginary time data to the disk file
file_name : file name
time_mesh : imaginary time mesh
time_data : array in imaginary time mesh
"""
f = open(file_name, "w")
for i in range(len(time_mesh)):
f.write( "%6u %16.8s %16.8E\n" %
(i + 1, time_mesh[i], time_data[i]) )
f.close()
@staticmethod
def dump_time_data2(file_name, time_mesh, time_data):
""" dump the imaginary time data to the disk file, spin-resolved version
file_name : file name
time_mesh : imaginary time mesh
time_data : array in imaginary time mesh
"""
f = open(file_name, "w")
for i in range(len(time_mesh)):
f.write( "%6u %16.8s %16.8E %16.8E\n" %
(i + 1, time_mesh[i], time_data[0][i], time_data[1][i]) )
f.close()
@staticmethod
def dump_freq_data1(file_name, freq_mesh, freq_data):
""" dump the matsubara frequency data to the disk file
file_name : file name
freq_mesh : matsubara frequency mesh
freq_data : array in matsubara frequency mesh
"""
f = open(file_name, "w")
for i in range(len(freq_mesh)):
f.write( "%6u %16.8s %16.8E %16.8E\n" %
(i + 1, freq_mesh[i], freq_data[i].real, freq_data[i].imag) )
f.close()
@staticmethod
def dump_freq_data2(file_name, freq_mesh, freq_data):
""" dump the matsubara frequency data to the disk file, spin-resolved version
file_name : file name
freq_mesh : matsubara frequency mesh
freq_data : array in matsubara frequency mesh
"""
f = open(file_name, "w")
for i in range(len(freq_mesh)):
f.write( "%6u %16.8s %16.8E %16.8E %16.8E %16.8E\n" %
(i + 1, freq_mesh[i], freq_data[0][i].real, freq_data[0][i].imag,
freq_data[1][i].real, freq_data[1][i].imag) )
f.close()
@staticmethod
def dump_htau_data(file_name, time_mesh, htau_data):
""" dump the hybridization function \Delta(\tau) to the disk file,
spin-resolved version, this function is designed for the ctqmc
impurity solver contained in ALPS package
file_name : file name
time_mesh : imaginary time mesh
htau_data : array in imaginary time mesh
"""
f = open(file_name, "w")
for i in range(len(time_mesh)):
f.write( "%6u %16.8E %16.8E\n" % (i, htau_data[0][i], htau_data[1][i]) )
f.close()
@staticmethod
def dump_kdep_data(file_name, nfreq, nkx, nky, kdep_data):
""" dump k-dependent data in matsubara frequency axis to the disk file
file_name : file name
nfreq : number of frequency points
nkx : number of k-points
nky : number of k-points
kdep_data : array in matsubara frequency axis
"""
is_complex = isinstance(kdep_data[0,0,0], complex)
fk = open(file_name, "w")
for f in range(nfreq):
if is_complex:
# write real part
for ikx in range(nkx):
for iky in range(nky):
fk.write( "%16.8E" % ( kdep_data[f,ikx,iky].real ) )
fk.write("\n")
fk.write("\n") # write two blank lines
fk.write("\n")
# write imaginary part
for ikx in range(nkx):
for iky in range(nky):
fk.write( "%16.8E" % ( kdep_data[f,ikx,iky].imag ) )
fk.write("\n")
fk.write("\n") # write two blank lines
fk.write("\n")
else:
for ikx in range(nkx):
for iky in range(nky):
fk.write( "%16.8E" % ( kdep_data[f,ikx,iky] ) )
fk.write("\n")
fk.write("\n") # write two blank lines
fk.write("\n")
fk.close()
class Fourier(object):
""" class Fourier is used to perform forward and backward fourier
transformations between imaginary time and matsubara frequency
spaces.
"""
def __init__(self, p, ftype):
""" class constructor for the Fourier
p : param dictionary
ftype : fourier type
beta : inversion temperature
ntime : number of imaginary time points
nfreq : number of frequencies for fermionic/bosonic mesh
"""
self.__beta = p["beta"][0]
self.__ntime = p["ntime"][0]
if ftype == 1: # for fermionic system
# set nfreq to number of fermionic frequency
self.__nfreq = p["nffrq"][0]
else: # for bosonic system
# set nfreq to number of bosonic frequency
self.__nfreq = p["nbfrq"][0]
def __tails(self, freq_mesh, freq_data):
""" calculate high frequency tails using K. Haule's trick
freq_mesh : matsubara frequency grid
freq_data : function on matsubara frequency space
"""
Sn = 0.0
Sx = 0.0
Sy = 0.0
Sxx = 0.0
Sxy = 0.0
for j in range(self.__nfreq - 128, self.__nfreq):
Sn = Sn + 1.0
Sx = Sx + 1.0 / freq_mesh[j]**2
Sy = Sy + freq_data[j].imag * freq_mesh[j]
Sxx = Sxx + 1.0 / freq_mesh[j]**4
Sxy = Sxy + freq_data[j].imag * freq_mesh[j] / freq_mesh[j]**2
return (Sx * Sxy - Sxx * Sy) / (Sn * Sxx - Sx * Sx)
def freq_to_time_F(self, time_mesh, time_data, freq_mesh, freq_data, fast = True):
""" backward fourier transformation from matsubara frequency to imaginary time,
this function is only suitable for the fermionic system
time_mesh : imaginary time mesh
time_data : function on imaginary time axis
freq_mesh : matsubara frequency mesh
freq_data : function on matsubara frequency axis
fast : whether scipy.weave is used to accelerate the code
"""
# calculate high frequency tails need to be subtracted
tail = self.__tails(freq_mesh, freq_data)
# perform backward fourier transformation
if fast: # scipy weave version
# build weave arguments
ntime = self.__ntime
nfreq = self.__nfreq
beta = self.__beta
ftail = float(tail) # attention: tail is in numpy.float64 type, while ftail is in float type
# define c++ code
code = """
#include <complex>
double raux;
for ( int i = 0; i < ntime; i++ ) {
raux = 0.0;
for ( int j = 0; j < nfreq; j++ ) {
raux = raux + cos( freq_mesh(j) * time_mesh(i) ) * real(freq_data(j));
raux = raux + sin( freq_mesh(j) * time_mesh(i) ) * ( imag(freq_data(j)) + ftail / freq_mesh(j));
}
time_data(i) = 2.0 * raux / beta - 0.5 * ftail;
}
"""
# inline c++ code using weave
scipy.weave.inline(code, ['ntime', 'nfreq', 'beta', 'ftail', 'freq_mesh', 'freq_data', 'time_mesh', 'time_data'],
type_converters=scipy.weave.converters.blitz)
else: # pure python + numpy version
for i in range(self.__ntime):
raux = 0.0
for j in range(self.__nfreq):
raux = raux + math.cos( freq_mesh[j] * time_mesh[i] ) * freq_data[j].real
raux = raux + math.sin( freq_mesh[j] * time_mesh[i] ) * ( freq_data[j].imag + tail / freq_mesh[j])
time_data[i] = 2.0 * raux / self.__beta - 0.5 * tail
# corrections for the boundary point
raux = freq_data[self.__nfreq-1].real * freq_mesh[self.__nfreq-1] / math.pi
time_data[0] = time_data[0] + raux
time_data[self.__ntime-1] = time_data[self.__ntime-1] - raux
def time_to_freq_F(self, time_mesh, time_data, freq_mesh, freq_data, fast = True):
""" forward fourier transformation from imaginary time to matsubara frequency,
this function is only suitable for the fermionic system
time_mesh : imaginary time mesh
time_data : function on imaginary time axis
freq_mesh : matsubara frequency mesh
freq_data : function on matsubara frequency axis
fast : whether scipy.weave is used to accelerate the code
"""
# perform fourier transformation
if fast : # scipy weave version
# build weave arguments
ntime = self.__ntime
nfreq = self.__nfreq
# define c++ code
code = """
#include <complex>
std::complex<double> ci(0.0, 1.0);
for ( int i = 0; i < nfreq; i++ ) {
double sre = 0.0;
double sim = 0.0;
for ( int j = 0; j < ntime - 1; j++ ) {
double c0 = cos( time_mesh(j) * freq_mesh(i) );
double c1 = cos( time_mesh(j+1) * freq_mesh(i) );
double s0 = sin( time_mesh(j) * freq_mesh(i) );
double s1 = sin( time_mesh(j+1) * freq_mesh(i) );
double g0 = time_data(j);
double g1 = time_data(j+1);
double dg = ( g1 - g0 ) / ( time_mesh(j+1) - time_mesh(j) );
sim = sim + ( c0 * g0 - c1 * g1 + dg * (s1 - s0) / freq_mesh(i) ) / freq_mesh(i);
sre = sre + ( s1 * g1 - s0 * g0 + dg * (c1 - c0) / freq_mesh(i) ) / freq_mesh(i);
}
freq_data(i) = sre + ci*sim;
}
"""
# inline c++ code using weave
scipy.weave.inline(code, ['ntime', 'nfreq', 'freq_mesh', 'freq_data', 'time_mesh', 'time_data'],
type_converters=scipy.weave.converters.blitz)
else : # pure python + numpy version
for i in range(self.__nfreq):
sre = 0.0
sim = 0.0
for j in range(self.__ntime-1):
c0 = math.cos( time_mesh[j] * freq_mesh[i] )
c1 = math.cos( time_mesh[j+1] * freq_mesh[i] )
s0 = math.sin( time_mesh[j] * freq_mesh[i] )
s1 = math.sin( time_mesh[j+1] * freq_mesh[i] )
g0 = time_data[j]
g1 = time_data[j+1]
dg = ( g1 - g0 ) / ( time_mesh[j+1] - time_mesh[j] )
sim = sim + ( c0 * g0 - c1 * g1 + dg * (s1 - s0) / freq_mesh[i] ) / freq_mesh[i]
sre = sre + ( s1 * g1 - s0 * g0 + dg * (c1 - c0) / freq_mesh[i] ) / freq_mesh[i]
freq_data[i] = sre + 1j*sim
def freq_to_time_B(self, time_mesh, time_data, freq_mesh, freq_data, fast = True):
""" backward fourier transformation from matsubara frequency to imaginary time,
this function is only suitable for the bosonic function
time_mesh : imaginary time mesh
time_data : function on imaginary time axis
freq_mesh : matsubara frequency mesh
freq_data : function on matsubara frequency axis
fast : whether scipy.weave is used to accelerate the code
"""
# perform backward fourier transformation
if fast: # scipy weave version
# build weave arguments
ntime = self.__ntime
nfreq = self.__nfreq
beta = self.__beta
# define c++ code
code = """
#include <complex>
std::complex<double> ci(0.0, 1.0);
std::complex<double> caux;
for ( int t = 0; t < ntime; t++ ) {
caux = freq_data(0);
for ( int f = 1; f < nfreq; f++ ) {
caux = caux + 2.0 * freq_data(f) * exp(-ci * freq_mesh(f) * time_mesh(t) );
}
time_data(t) = real(caux) / beta;
}
"""
# inline c++ code using weave
scipy.weave.inline(code, ['ntime', 'nfreq', 'beta', 'freq_mesh', 'freq_data', 'time_mesh', 'time_data'],
type_converters=scipy.weave.converters.blitz)
else: # pure python + numpy version
for t in range(self.__ntime):
caux = freq_data[0]
for f in range(1,self.__nfreq):
caux = caux + 2.0 * freq_data[f] * numpy.exp(-1j * freq_mesh[f] * time_mesh[t])
time_data[t] = caux.real / self.__beta
def time_to_freq_B(self, time_mesh, time_data, freq_mesh, freq_data, fast = True):
""" forward fourier transformation from imaginary time to matsubara frequency,
this function is only suitable for the bosonic function
time_mesh : imaginary time mesh
time_data : function on imaginary time axis
freq_mesh : matsubara frequency mesh
freq_data : function on matsubara frequency axis
fast : whether scipy.weave is used to accelerate the code
"""
fit = scipy.interpolate.InterpolatedUnivariateSpline(time_mesh, time_data)
ntime_dense = 4 * self.__ntime # used to build a dense imaginary time mesh
# denser time mesh
time_mesh_dense = Mesh.create_time_mesh(self.__beta, ntime_dense)
# denser time data
time_data_dense = fit(time_mesh_dense)
for im in range(self.__nfreq):
faux = time_data_dense * numpy.exp(1j * freq_mesh[im] * time_mesh_dense)
# calculate \int^{\beta}_{0} f(\tau) e^{i \omega \tau} d\tau
# now faux = f(\tau) e^{i \omega \tau}
freq_data[im] = numpy.trapz(faux, time_mesh_dense)
def time_to_freq_C(self, time_mesh, time_data, freq_mesh, freq_data):
""" forward fourier transformation from imaginary time to matsubara frequency,
this function is only suitable for the bosonic function \chi
time_mesh : imaginary time mesh
time_data : function on imaginary time axis
freq_mesh : matsubara frequency mesh
freq_data : function on matsubara frequency axis
"""
# spline interpolation to evaluate the high-frequency tail
fit = scipy.interpolate.InterpolatedUnivariateSpline(time_mesh, time_data)
deriv_0 = fit.derivatives(0.0)
deriv_beta = fit.derivatives(self.__beta)
c1 = deriv_beta[0] - deriv_0[0]
c2 = -(deriv_beta[1] - deriv_0[1])
c3 = deriv_beta[2] - deriv_0[2]
for im in range(1,self.__nfreq): # im = 0 will cause invalid arithmetic opeartion
freq_data[im] = c1 / (1j*freq_mesh[im]) \
+ c2 / (1j*freq_mesh[im])**2 \
+ c3 / (1j*freq_mesh[im])**3
# contribution from the rest part
ntime_dense = 2 * self.__ntime # used to build a dense imaginary time mesh
time_mesh_dense = Mesh.create_time_mesh(self.__beta, ntime_dense)
time_data_dense = fit(time_mesh_dense)
for i in range(ntime_dense):
time_data_dense[i] = time_data_dense[i] \
- c1 * ( time_mesh_dense[i] - self.__beta/2 ) / self.__beta \
+ c2 * ( time_mesh_dense[i] - self.__beta/2 )**2 / (2.0*self.__beta) - c2 * self.__beta / 24.0 \
- c3 * ( time_mesh_dense[i] - self.__beta/2 )**3 / (6.0*self.__beta)
cutoff = min(self.__ntime, self.__nfreq)
for im in range(cutoff):
faux = time_data_dense * numpy.exp(1j * freq_mesh[im] * time_mesh_dense)
# calculate \int^{\beta}_{0} f(\tau) e^{i \omega \tau} d\tau
# now faux = f(\tau) e^{i \omega \tau}
freq_data[im] += numpy.trapz(faux, time_mesh_dense)
class Lattice(object):
""" class Lattice is used to define a square lattice.
please pay attention to the definition of k-mesh
"""
def __init__(self, p):
""" class constructor for the Lattice
p : param dictionary
U : onsite interaction
V : intersite interaction
t : hopping parameter
nkx : k-mesh densities in x-axis
nky : k-mesh densities in y-axis
"""
self.__U = p["U"][0]
self.__V = p["V"][0]
self.__t = p["t"][0]
self.__nkx = p["nkx"][0]
self.__nky = p["nky"][0]
def create_kxky(self, bz_ty = 1):
""" build k-mesh along x and y-axis
bz_ty : type of k-mesh distribution in brillouin zone
"""
kx = numpy.zeros(self.__nkx, dtype = numpy.float)
for i in range(self.__nkx):
if bz_ty == 0: # kx \in [0,1\pi]
kx[i] = i * math.pi / ( self.__nkx - 1 )
else: # kx \in [0,2\pi]
kx[i] = i * ( math.pi * 2 ) / ( self.__nkx - 1 )
ky = numpy.zeros(self.__nky, dtype = numpy.float)
for j in range(self.__nky):
if bz_ty == 0: # ky \in [0,1\pi]
ky[j] = j * math.pi / ( self.__nky - 1 )
else: # ky \in [0,2\pi]
ky[j] = j * ( math.pi * 2 ) / ( self.__nky - 1 )
# return them as a tuple
return (kx, ky)
@staticmethod
def create_kxky(nkx, nky, bz_ty = 1):
""" build k-mesh along x and y-axis
nkx : k-mesh densities in x-axis
nky : k-mesh densities in y-axis
bz_ty : type of k-mesh distribution in brillouin zone
"""
kx = numpy.zeros(nkx, dtype = numpy.float)
for i in range(nkx):
if bz_ty == 0: # kx \in [0,1\pi]
kx[i] = i * math.pi / ( nkx - 1 )
else: # kx \in [0,2\pi]
kx[i] = i * ( math.pi * 2 ) / ( nkx - 1 )
ky = numpy.zeros(nky, dtype = numpy.float)
for j in range(nky):
if bz_ty == 0: # ky \in [0,1\pi]
ky[j] = j * math.pi / ( nky - 1 )
else: # ky \in [0,2\pi]
ky[j] = j * ( math.pi * 2 ) / ( nky - 1 )
# return them as a tuple
return (kx, ky)
def create_ek(self, bz_ty = 1):
""" build the band dispersion for the square lattice
bz_ty : type of k-mesh distribution in brillouin zone
"""
ek = numpy.zeros((self.__nkx, self.__nky), dtype = numpy.float)
for i in range(self.__nkx):
if bz_ty == 0: # kx \in [0,1\pi]
kx = i * math.pi / ( self.__nkx - 1 )
else: # kx \in [0,2\pi]
kx = i * ( math.pi * 2 ) / ( self.__nkx - 1 )
for j in range(self.__nky):
if bz_ty == 0: # ky \in [0,1\pi]
ky = j * math.pi / ( self.__nky - 1 )
else: # ky \in [0,2\pi]
ky = j * ( math.pi * 2 ) / ( self.__nky - 1 )
ek[i,j] = -2 * self.__t * ( math.cos(kx) + math.cos(ky) )
return ek
@staticmethod
def create_ek(t, nkx, nky, bz_ty = 1):
""" build the band dispersion for the square lattice
t : hopping parameter
nkx : k-mesh densities in x-axis
nky : k-mesh densities in y-axis
bz_ty : type of k-mesh distribution in brillouin zone
"""
ek = numpy.zeros((nkx, nky), dtype = numpy.float)
for i in range(nkx):
if bz_ty == 0: # kx \in [0,1\pi]
kx = i * math.pi / ( nkx - 1 )
else: # kx \in [0,2\pi]
kx = i * ( math.pi * 2 ) / ( nkx - 1 )
for j in range(nky):
if bz_ty == 0: # ky \in [0,1\pi]
ky = j * math.pi / ( nky - 1 )
else: # ky \in [0,2\pi]
ky = j * ( math.pi * 2 ) / ( nky - 1 )
ek[i,j] = -2 * t * ( math.cos(kx) + math.cos(ky) )
return ek
def create_vk(self, bz_ty = 1):
""" build the general interaction
bz_ty : type of k-mesh distribution in brillouin zone
"""
vk = numpy.zeros((self.__nkx, self.__nky), dtype = numpy.float)
for i in range(self.__nkx):
if bz_ty == 0: # kx \in [0,1\pi]
kx = i * math.pi / ( self.__nkx - 1 )
else: # kx \in [0,2\pi]
kx = i * ( math.pi * 2 ) / ( self.__nkx - 1 )
for j in range(self.__nky):
if bz_ty == 0: # ky \in [0,1\pi]
ky = j * math.pi / ( self.__nky - 1 )
else: # ky \in [0,2\pi]
ky = j * ( math.pi * 2 ) / ( self.__nky - 1 )
vk[i,j] = self.__U + 2 * self.__V * ( math.cos(kx) + math.cos(ky) )
return vk
@staticmethod
def create_vk(U, V, nkx, nky, bz_ty = 1):
""" build the general interaction
U : onsite interaction
V : intersite interaction
nkx : k-mesh densities in x-axis
nky : k-mesh densities in y-axis
bz_ty : type of k-mesh distribution in brillouin zone
"""
vk = numpy.zeros((nkx, nky), dtype = numpy.float)
for i in range(nkx):
if bz_ty == 0: # kx \in [0,1\pi]
kx = i * math.pi / ( nkx - 1 )
else: # kx \in [0,2\pi]
kx = i * ( math.pi * 2 ) / ( nkx - 1 )
for j in range(nky):
if bz_ty == 0: # ky \in [0,1\pi]
ky = j * math.pi / ( nky - 1 )
else: # ky \in [0,2\pi]
ky = j * ( math.pi * 2 ) / ( nky - 1 )
vk[i,j] = U + 2 * V * ( math.cos(kx) + math.cos(ky) )
return vk
class Mixer(object):
""" class Mixer is used to mix the old and new vectors to produce a
newer one.
"""
def __init__(self, p):
""" class constructor for the Mixer
p : param dictionary
alpha : mixing parameter
"""
self.__alpha = p["alpha"][0]
def linear_mixing(self, vec1, vec2):
""" perform the simplest linear mixing
vec1 : old vector on input
vec2 : new vector on input
"""
return vec1 * ( 1 - alpha ) + vec2 * alpha
@staticmethod
def linear_mixing(alpha, vec1, vec2):
""" perform the simplest linear mixing
alpha : mixing parameter
vec1 : old vector on input
vec2 : new vector on input
"""
return vec1 * ( 1 - alpha ) + vec2 * alpha
class AlpsSolver(object):
""" class AlpsSolver is used to drive the hybridization expansion impurity
solver contained in the ALPS package.
"""
def __init__(self, params):
""" class constructor for the AlpsSolver
params : user-supply input parameters
"""
# setup default parameters for the quantum impurity solver
# note : MAX_TIME IS TOO SMALL. IT SHOULD BE MODIFIED BEFORE CALCULATION.
self.__params = {
'N_MEAS' : 100 ,
'SWEEPS' : 200000000 ,
'THERMALIZATION' : 1000 ,
'MAX_TIME' : 120 ,
'N_ORBITALS' : 2 ,
'N_TAU' : 1023 ,
'N_nn' : 256 ,
'N_MATSUBARA' : 512 ,
'N_LEGENDRE' : 48 ,
'N_HISTOGRAM_ORDERS' : 128 ,
'MU' : 4.0 ,
'U' : 8.0 ,
'BETA' : 100.0 ,
'MEASURE_time' : 1 ,
'MEASURE_freq' : 1 ,
'MEASURE_nn' : 1 ,
'MEASURE_nnt' : 16 ,
'MEASURE_legendre' : 1 ,
'TEXT_OUTPUT' : 1 ,
'DELTA' : "D.dat" ,
'SEED' : int( time.time() ) + ( pyalps.mpi.rank + 1.0 ) * 1981
}
# setup additional keys and values
for key in params.iterkeys():
self.__params[key] = params[key]
def setup(self):
""" prepare necessary inputs and perform check to ensure everything is OK
"""
# only master node can do it
if pyalps.mpi.rank != 0:
return
# check whether the delta.dat is available
if not self.__params.has_key("DELTA"):
sys.exit("FATAL ERROR : please provide the hybridization function")
if not os.path.isfile(self.__params["DELTA"]):
try:
raise IOError(self.__params["DELTA"])
except IOError as e:
print ('IOError : ' + str(e) + " does not exist!")
sys.exit("FATAL ERROR : please check it and then run this code again")