def pi_plus_ec(posi, nega, lamb, qval, disp, ksft, area): '''使用能量cutoff作为flow parameter的bubble\n posi是能量为+LAMBDA的边,nega是能量为-LAMBDA的边, lamb是LAMBDA\n disp是色散关系,qval是需要平移的大小,应该用一个Point来包装,\n kshf是动量相加的函数, 这个函数应该能处理好到第一布里渊区的映射\n area是第一布里渊区的面积\n ```(10.112)本身已经处理好了动量守恒,k, k-q是需要满足动量守恒的关系的,而处理好``` ```k-q到第一布里渊区的映射就处理好了Umklapp``` ''' ''' 10.112中的 PI^+(n, q) = +LAMBDA (2pi)^-2 beta^-1 Int_{k in k_n} G'(k)G(k - Q) 其中有一个beta是频率积分带来的,2pi^2是动量积分带来的 G(k)=CITA(LAMBDA < abs(disp(k))) / i*omega - disp(k) G'(k)=-DELTA(abs(disp(k))-LAMBDA) / i*omege - disp(k) 在零温的情况下10.112中的频率部分可以积分出来,此后的k都是不包含频率的 = +LAMBDA (2pi)^-2 Int_{k in k_n} CITA() -DELTA() { beta^-1 sum_{omega} [(i*omega-disp(k))(i*omega-disp(k - q))]^-1 } 花括号中的内容求和完之后等于 - CITA(-disp(k)disp(k-q)) / (abs(disp(k)) + abs(disp(k-p))) 积分会变成 = +LAMBDA (2pi)^-2 Int_{k in k_n} DELTA(abs(disp(k))-LAMBDA) CITA(LAMBDA<abs(disp(k-q))) CITA(-disp(k)disp(k-q)) / (abs(disp(k)) + abs(disp(k-p))) 因为采用的能量cutoff中有一个 DELTA(abs(disp(k))-LAMBDA),disp(k)等于正的或者负的LAMBDA 而CITA(-disp(k)disp(k-q))限制了disp(k)和disp(k-q)符号相反 所以上式变成 (第一项disp(k)=LAMBDA>0,于是disp(k-q)<0,而且abs(disp(k))=-disp(k)>LAMBDA) (第二项类似,分子中的abs(disp(k))都可以直接换成LAMBDA,abs(disp(k-q))也都知道符号) = +LAMBDA (2pi)^-2 Int_{k in kn} { DELTA(disp(k)-LAMBDA)CITA(-disp(k-q)-LAMBDA) / (LAMBDA - disp(k - q)) DELTA(disp(k)+LAMBDA)CITA(disp(k-q)-LAMBDA) / (LAMBDA + disp(k - q)) } 还可以从积分里面把DELTA给积分掉,这样对于二维平面的积分也会变成对 disp(k) = LAMBDA 或者 -LAMBDA的线的积分 = +LAMBDA (2pi)^-2 * [Int_{disp(k) = +LAMBDA} CITA(-disp(k-q)-LAMBDA) / (LAMBDA - disp(k - q))] +[Int_{disp(k) = -LAMBDA} CITA(disp(k-q)-LAMBDA) / (LAMBDA + disp(k - q)) ] ''' nega_q = Point(-qval.coord[0], -qval.coord[1], 1) #积分正LAMBDA的线 intposi = 0. for edg in posi: kval = middle_point(edg.ends[0], edg.ends[1]) kprim = ksft(kval, nega_q) #CITA disp_kprim = disp(kprim.coord[0], kprim.coord[1]) if -disp_kprim < lamb: continue #线积分,计算线元的长度 intposi += edg.length / (lamb - disp_kprim) #积分负LAMBDA的线 intnega = 0. for edg in nega: kval = middle_point(edg.ends[0], edg.ends[1]) kprim = ksft(kval, nega_q) #CITA disp_kprim = disp(kprim.coord[0], kprim.coord[1]) if disp_kprim < lamb: continue intnega += edg.length / (lamb + disp_kprim) #乘上系数 result = lamb * (intposi + intnega) / area #numpy.square(numpy.pi*2) return result
def _trapezoid_split(lseg: Segment, sseg: Segment, length): '''将一个等腰梯形切分成等边三角形,底和x轴平行\n 切分六边形的时候,把半和下半都处理成等腰梯形\n 需要输入等腰梯形的两个底,第一个是比较长的底,第二个是短的,\n 然后还需要等边三角形的边长 ''' assert numpy.isclose(lseg.length - sseg.length, length) parts = sseg.length / length assert numpy.isclose(parts, numpy.round(parts)) parts = numpy.int(numpy.round(parts)) # lpt = numpy.ndarray(parts+2, dtype=Point) spt = numpy.ndarray(parts+1, dtype=Point) # spt[0] = sseg.ends[0] lpt[0] = lseg.ends[0] for idx in range(parts): coef = (idx + 1) / parts coefb = 1 - coef spt[idx+1] = middle_point(sseg.ends[0], sseg.ends[1], coefb, coef) coef = (idx + 1) / (parts+1) coefb = 1 - coef lpt[idx+1] = middle_point(lseg.ends[0], lseg.ends[1], coefb, coef) lpt[-1] = lseg.ends[1] #pts = numpy.concatenate([spt, lpt]) #draw_components(pts, [sseg, lseg], []) #从长的开始计,第二个点到倒数第二个点 eqtris = [Eqtriangle([lpt[0], spt[0], lpt[1]])] for idx in range(1, parts+1): eqtris.append(Eqtriangle([lpt[idx], spt[idx], spt[idx-1]])) eqtris.append(Eqtriangle([lpt[idx], spt[idx], lpt[idx+1]])) #draw_components(pts, [sseg, lseg], eqtris) return eqtris
def pi_ab_minus_ec(posia, negaa, lamb, qval, dispb, ksft, area): '''使用能量cutoff作为flow parameter的bubble\n posi是dispa为+LAMBDA的边,nega是dispa为-LAMBDA的边, lamb是LAMBDA\n 这两个边应该是限制在dispa这个带的第n个patch中的,这两个边也就暗含了n\n dispa和dispb是两个带的色散关系\n qval是需要平移的大小,应该用一个Point来包装,\n kshf是动量相加的函数, 这个函数应该能处理好到第一布里渊区的映射\n ```(10.112)本身已经处理好了动量守恒,k, k-q是需要满足动量守恒的关系的,而处理好``` ```k-q到第一布里渊区的映射就处理好了Umklapp``` ''' ''' 10.112中的 PI^-(n, q) = -LAMBDA (2pi)^-2 beta^-1 Int_{k in k_n} G'(k)G(- k + Q) = -LAMBDA (2pi)^-2 Int_{k in k_n} CITA() -DELTA() { beta^-1 sum_{omega} [(i*omega-disp(k))(-i*omega-disp(-k + q))]^-1 } 在零温下这个频率积分等于,注意-k那里把频率也给反过来了 +CITA(+disp(k)disp(-k+q)) / (abs(disp(k)) + abs(disp(-k+q))) 原式就等于 = LAMBDA (2pi)^-2 Int_{k in k_n} { DELTA(abs(disp(k))-LAMBDA) CITA(abs(disp(-k+q)-LAMBDA)) CITA(disp(k)disp(-k+q)) / (abs(disp(k)) + abs(disp(-k+q))) } 第二个CITA限制了disp(k)和disp(-k+q)同号,积分积掉DELTA,分类讨论正负 = LAMBDA (2pi)^-2 { Int_{disp(k) = +LAMBDA} CITA(disp(-k+q) - LAMBDA) / (LAMBDA + disp(-k+q)) + Int_{disp(k) = -LAMBDA} CITA(-disp(-k+q) -LAMBDA) / (LAMBDA - disp(-k+q)) } ''' #积分正LAMBDA的线 intposi = 0. for edg in posia: kval = middle_point(edg.ends[0], edg.ends[1]) nega_k = Point(-kval.coord[0], -kval.coord[1], 1) kprim = ksft(nega_k, qval) #CITA disp_kprim = dispb(kprim.coord[0], kprim.coord[1]) if disp_kprim < lamb: continue #要计算线元的长度 intposi += edg.length / (lamb + disp_kprim) #积分负LAMBDA的线 intnega = 0. for edg in negaa: kval = middle_point(edg.ends[0], edg.ends[1]) nega_k = Point(-kval.coord[0], -kval.coord[1], 1) kprim = ksft(nega_k, qval) #CITA disp_kprim = dispb(kprim.coord[0], kprim.coord[1]) if -disp_kprim < lamb: continue intnega += edg.length / (lamb - disp_kprim) #乘上系数 result = lamb * (intposi + intnega) / area#numpy.square(numpy.pi*2) return result
def get_von_hove_patches(npat): '''获取平分von Hove的patches''' #pylint: disable=cell-var-from-loop #一共有6个M点 mpts = [ Point(3.1415926, 3.1415926 / 1.7320508, 1), Point(0, 2*3.1415926 / 1.7320508, 1), Point(-3.1415926, 3.1415926 / 1.7320508, 1), Point(-3.1415926, -3.1415926 / 1.7320508, 1), Point(0, -2*3.1415926 / 1.7320508, 1), Point(3.1415926, -3.1415926 / 1.7320508, 1) ] angs = [] pat_per_k = npat // 6 gap = 1 / pat_per_k for idx in range(6): ridx = idx + 1 if idx + 1 < 6 else 0 for pidx in range(pat_per_k): omega = (pidx + 0.5) * gap vpt = middle_point(mpts[idx], mpts[ridx], sc1=1-omega, sc2=omega) angs.append(get_absolute_angle(vpt.coord[0], vpt.coord[1])) pats = [] for ang in angs: rrad = optimize.bisect( lambda rad: dispersion(rad*numpy.cos(ang), rad*numpy.sin(ang)), 0, 2*numpy.pi/numpy.sqrt(3) ) pats.append(Point(rrad*numpy.cos(ang), rrad*numpy.sin(ang), 1)) return pats
def eqtriangle_split(eqt: Eqtriangle, nps): '''将一个正三角形切分成nps个块''' #从两个边开始计算 #nps条分界线,包含本来的底边 btmlines = [] for idx in range(nps): coef = (idx+1) / nps coefb = 1 - coef btmlines.append( Segment( middle_point(eqt.vertex[0], eqt.vertex[1], coefb, coef), middle_point(eqt.vertex[0], eqt.vertex[2], coefb, coef) ) ) #从这些底边开始切分成新的三角形,找到每条底边上的点 btmpts = [] for idx, btml in enumerate(btmlines): num = idx + 1 ptslist = [btml.ends[0]] for nid in range(num): coef = (nid + 1) / num coefb = 1 - coef ptslist.append(middle_point(btml.ends[0], btml.ends[1], coefb, coef)) btmpts.append(ptslist) #从上面的点开始,添加新的等边三角形 eqtris = [Eqtriangle([eqt.vertex[0], btmpts[0][0], btmpts[0][1]])] for idx in range(1, nps): num = idx + 1 #每一层有idx+2个点在ptlist里面实际上 #底在这条线上的三角形 for ptidx in range(num): eqtris.append( Eqtriangle( [btmpts[idx-1][ptidx], btmpts[idx][ptidx],btmpts[idx][ptidx+1]] ) ) #顶在这条线上的三角形 if ptidx < idx: eqtris.append( Eqtriangle( [btmpts[idx-1][ptidx], btmpts[idx][ptidx+1], btmpts[idx-1][ptidx+1]] ) ) return btmlines, btmpts, eqtris
def hexagon_split(hexa: Hexagon, nps): ''' 将一个六边形切分成小的正三角形 ''' #六边形分成两个等腰梯形 topedge = hexa.edges[1] midedge = Segment(hexa.vertex[0], hexa.vertex[3]) btmedge = hexa.edges[4] #所有的小三角形 eqtris = [] length = numpy.sum([edg.length for edg in hexa.edges]) length /= 6 length /= nps #先处理上面半个梯形 #注意这里由于Hexagon是逆时针对顶点进行的排序 #所以梯形和三角形增长的方向是从右往左 llines = [topedge] for idx in range(nps): coef = (idx + 1) / nps coefb = 1 - coef llines.append( Segment( middle_point(topedge.ends[0], midedge.ends[0], coefb, coef), middle_point(topedge.ends[1], midedge.ends[1], coefb, coef) ) ) #llines中一共有nps+1个线 #注意由于梯形的点是逆时针的,所以这边三角形的增长也是从右向左的 for idx in range(nps): ets = _trapezoid_split(llines[idx+1], llines[idx], length) assert len(ets) == 2*nps + 1 + 2*idx eqtris.extend(ets) #再处理下面半个梯形的 #这里需要注意下半个梯形的点的顺序问题 llines = [midedge] for idx in range(nps): coef = (idx + 1) / nps coefb = 1 - coef llines.append( Segment( middle_point(midedge.ends[0], btmedge.ends[1], coefb, coef), middle_point(midedge.ends[1], btmedge.ends[0], coefb, coef) ) ) #llines中共有nps+1条线 for idx in range(nps): ets = _trapezoid_split(llines[idx], llines[idx+1], length) assert len(ets) == 4*nps - 1 - 2*idx eqtris.extend(ets) #开始计算相邻的三角形 #这个时候,所有的编号都是从右向左,一层一层在增加的 ladjs = numpy.ndarray(len(eqtris), dtype=object) # Warning: 这个ladjs中的相邻的三角形的顺序一定和Eqtriangle的边的顺序是一样的 #先是nps个上半层,其中三角形的数量是2*nps+1+2*idx #idx从0到nps-1 #先处理最上面的一层的相邻 #最上面一层就是从[0,2*nps+1)这个范围内的所有 for idx in range(2*nps+1): #每个三角都有三条边,于是有三个相邻 #这些是底边在下面的相邻的有下一个,和下一行正对的 #上半部分中,底边在下面的三角形的点是按照右下-上-左下的顺序来的 if idx % 2 == 0: rightone = None if idx == 0 else eqtris[idx-1] leftone = None if idx == 2*nps else eqtris[idx+1] ladjs[idx] = [rightone, leftone, eqtris[idx+2*nps+2]] #这些是底边在上面的,相邻的有上一个和下一个 #上半部分中,底边在上面的三角形是按照下-左上-右上的顺序来的 else: ladjs[idx] = [eqtris[idx+1], None, eqtris[idx-1]] #之后,还有nps-2个上半部分的梯形 startrange = 2*nps+1 for npsidx in range(1, nps): #startrange是前面0~npsidx-1行包含的数目 #这行包含的数目 #如果到了最后一个,下面的一行的三角形的数量和这一行是一样多的 #计算的时候不需要多添加一个1 offset = 1 if npsidx != nps-1 else 0 stoprange = 2*nps+1+2*npsidx for idx in range(stoprange): tot_idx = startrange + idx #这些是底边在下面的相邻的有下一个,和下一行正对的 #上半部分中,底边在下面的三角形的点是按照右下-上-左下的顺序来的 if idx % 2 == 0: rightone = None if idx == 0 else eqtris[tot_idx-1] leftone = None if idx == stoprange - 1 else eqtris[tot_idx+1] ladjs[tot_idx] =\ [rightone, leftone, eqtris[tot_idx+stoprange+offset]] else: #上半部分中,底边在上面的三角形是按照下-左上-右上的顺序来的 ladjs[tot_idx] =\ [eqtris[tot_idx+1], eqtris[tot_idx-stoprange+1],\ eqtris[tot_idx-1]] startrange += stoprange #下班部分从后往前开始处理 #最下面的一个梯形 for idx in range(2*nps+1): #每个三角都有三条边,于是有三个相邻 #这些是底边在上面的,相邻的有下一个,上面对的,还有上一个 #下半部分中,底边在上面的三角形是按照右上-下-左上的顺序来的 tot_idx = len(eqtris) - (2*nps+1) + idx if idx % 2 == 0: rightone = None if idx == 0 else eqtris[tot_idx-1] leftone = None if idx == 2*nps else eqtris[tot_idx+1] ladjs[tot_idx] = [rightone, leftone, eqtris[tot_idx-2-2*nps]] #下半部分中,底边在下面的三角形是按照上-左下-右下的顺序来的 else: ladjs[tot_idx] = [eqtris[tot_idx+1], None, eqtris[tot_idx-1]] startrange = len(eqtris) - (2*nps+1) for npsidx in range(1, nps): offset = 1 if npsidx != nps-1 else 0 stoprange = 2*nps+1+2*npsidx for idx in range(stoprange): tot_idx = startrange - stoprange + idx #下半部分中,底边在上面的三角形是按照右上-下-左上的顺序来的 if idx % 2 == 0: rightone = None if idx == 0 else eqtris[tot_idx-1] leftone = None if idx == stoprange - 1 else eqtris[tot_idx+1] ladjs[tot_idx] = [rightone, leftone, eqtris[tot_idx-offset-stoprange]] #下半部分中,底边在下面的三角形是按照上-左下-右下的顺序来的 else: ladjs[tot_idx] = [eqtris[tot_idx+1], eqtris[tot_idx+stoprange-1], eqtris[tot_idx-1]] startrange = startrange - stoprange return numpy.array(eqtris, dtype=Eqtriangle), ladjs