diff --git a/hypertiling/CenterContainer.py b/hypertiling/CenterContainer.py index 5b8e454ae8bb2291b969525c0e4bf287026c729b..2fbe2b43ba26decd4931ca5553bff24258ee20e0 100644 --- a/hypertiling/CenterContainer.py +++ b/hypertiling/CenterContainer.py @@ -14,12 +14,15 @@ class HTCenter: r (real) : magnitude phi (real) : angle ''' - if len(args) == 1: + self.layer = 0 + if len(args) == 2: self.z = args[0] self.angle = math.atan2(self.z.imag, self.z.real) - elif len(args) == 2: + self.layer = args[1] + elif len(args) == 3: self.z = args[0]*complex(math.cos(args[1]), math.sin(args[1])) self.angle = args[1] + self.layer = args[2] def __le__(self, other): return self.angle <= other.angle @@ -30,9 +33,9 @@ class HTCenter: def __gt__(self, other): return self.angle > other.angle def __eq__(self, other): - return self.z == other.z + return (self.z == other.z) and (self.layer == other.layer) def __ne__(self, other): - return self.z != other.z + return (self.z != other.z) and (self.layer == other.layer) try: from sortedcontainers import SortedList @@ -41,21 +44,21 @@ try: A Container to store complex numbers and to efficiently decide whether a floating point representative of a given complex number is already present. ''' - def __init__(self, linlength, r, phi): + def __init__(self, linlength, r, phi, l): # Note to self, think of numpy in the alternative implementation self.maxlinlength = linlength# the maximum linear length self.dangle = 0.1 # controls the width of the angle interval and is adapted by repeated searches - self.centers = SortedList([HTCenter(r, phi)]) + self.centers = SortedList([HTCenter(r, phi, l)]) - def add(self, z): + def add(self, z, l): ''' Add z to the container. Parameters: z (complex) A complex number. should not be 0+0*I... ''' - self.centers.add(HTCenter(z)) + self.centers.add(HTCenter(z, l)) def __len__(self): ''' @@ -75,17 +78,30 @@ try: else false. ''' nangle = math.atan2(z.imag, z.real) - centerarray_iterator = self.centers.irange(HTCenter(1, nangle*(1-self.dangle)), HTCenter(1, nangle*(1+self.dangle))) + centerarray_iterator = self.centers.irange(HTCenter(1, nangle*(1-self.dangle), 0), HTCenter(1, nangle*(1+self.dangle), 0)) incontainer = False iterlen = 0 # since we cannot apply len() on the irange iterator we have to determine the length ourselves for c in centerarray_iterator: iterlen += 1 - if abs(z - c.z) < 1E-12: # 1E-12 is the relative acuuracy here, since for the hyperbolic lattice vertices pile up near |z|~1 + if abs(z - c.z) < 1E-12: # 1E-12 is the relative accuracy here, since for the hyperbolic lattice vertices pile up near |z|~1 incontainer = True break if iterlen > self.maxlinlength: self.dangle /= 2.0 return incontainer + + def get(self, z): + ''' + Get an iterator to the object that is similar to z. + ''' + nangle = math.atan2(z.imag, z.real) + centerarray_iterator = self.centers.irange(HTCenter(1, nangle*(1-self.dangle), 0), HTCenter(1, nangle*(1+self.dangle), 0)) + incontainer = False + + for c in centerarray_iterator: + if abs(z - c.z) < 1E-12: # 1E-12 is the relative accuracy here, since for the hyperbolic lattice vertices pile up near |z|~1 + return c # hopefully this returns an iterator by which we can modify the elements + break except ImportError: import bisect diff --git a/hypertiling/kernelflo.py b/hypertiling/kernelflo.py index 8fe6c5027617183b1a8de9a54069da524e35858d..75eb3ce71644f46902ffa9d38ebc19568512b1b8 100644 --- a/hypertiling/kernelflo.py +++ b/hypertiling/kernelflo.py @@ -9,6 +9,11 @@ from .transformation import moeb_rotate_trafo from .util import fund_radius from .CenterContainer import CenterContainer +def find_layer(idx, startpgon, endpgon): + for i in range(len(endpgon)): + if idx < endpgon[i]: + return i + class KernelFlo(KernelCommon): """ High precision kernel written by F. Goth @@ -36,24 +41,24 @@ class KernelFlo(KernelCommon): if self.center == "vertex": sect_angle = self.qhi sect_angle_deg = self.degqhi - centerset_extra = CenterContainer(self.p*self.q, abs(self.fund_poly.centerP()), math.atan2(self.fund_poly.centerP().imag, self.fund_poly.centerP().real)) - centerarray = CenterContainer(self.p*self.q, abs(self.fund_poly.centerP()), math.atan2(self.fund_poly.centerP().imag, self.fund_poly.centerP().real)) + centerset_extra = CenterContainer(self.p*self.q, abs(self.fund_poly.centerP()), math.atan2(self.fund_poly.centerP().imag, self.fund_poly.centerP().real), 0) + centerarray = CenterContainer(self.p*self.q, abs(self.fund_poly.centerP()), math.atan2(self.fund_poly.centerP().imag, self.fund_poly.centerP().real), 0) else: - centerset_extra = CenterContainer(self.p*self.q, abs(self.fund_poly.centerP()), self.phi/2) # the initial poly has a center of (0,0) therefore we set its angle artificially to phi/2 - centerarray = CenterContainer(self.p*self.q, abs(self.fund_poly.centerP()), self.phi/2) + centerset_extra = CenterContainer(self.p*self.q, abs(self.fund_poly.centerP()), self.phi/2, 0) # the initial poly has a center of (0,0) therefore we set its angle artificially to phi/2 + centerarray = CenterContainer(self.p*self.q, abs(self.fund_poly.centerP()), self.phi/2, 0) # prepare sets which will contain the center coordinates # this is used for uniqueness checks later - startpgon = 0 - endpgon = 1 + startpgon = [0] + endpgon = [1] fr = fund_radius(self.p, self.q)/2 # loop over layers to be constructed for l in range(1, self.nlayers): # computes all neighbor polygons of layer l - for pgon in self.polygons[startpgon:endpgon]: + for pgon in self.polygons[startpgon[l-1]:endpgon[l-1]]: # iterate over every vertex of pgon for vert_ind in range(self.p): @@ -67,9 +72,9 @@ class KernelFlo(KernelCommon): # cut away cells outside the fundamental sector # allow some tolerance at the upper boundary - if (self.mangle <= cangle < sect_angle_deg+self.degtol+self.mangle) and (abs(center) > fr): + if (self.mangle*(1 - 0* 100*np.finfo(float).eps) <= cangle < sect_angle_deg+self.degtol+self.mangle) and (abs(center) > fr): if not centerarray.fp_has(center): - centerarray.add(center) + centerarray.add(center, l) # create copy polycopy = copy.deepcopy(pgon) @@ -82,12 +87,12 @@ class KernelFlo(KernelCommon): self.polygons.append(adj_pgon) # if angle is in slice, add to centerset_extra - if self.mangle <= cangle <= self.degtol+self.mangle: + if self.mangle**(1-100*np.finfo(float).eps) <= cangle <= self.degtol+self.mangle: if not centerset_extra.fp_has(center): - centerset_extra.add(center) + centerset_extra.add(center, l) - startpgon = endpgon - endpgon = len(self.polygons) + startpgon.append(endpgon[-1]) + endpgon.append(len(self.polygons)) # free mem of centerset del centerarray @@ -99,5 +104,8 @@ class KernelFlo(KernelCommon): if pgon.angle > sect_angle_deg - self.degtol + self.mangle: center = moeb_rotate_trafo(pgon.centerP(), -sect_angle) if centerset_extra.fp_has(center): + l = centerset_extra.get(center).layer + print(kk, " has been found in layer: ", find_layer(kk, startpgon, endpgon)) + print(center, " already in layer ", l, centerset_extra.get(center).z) deletelist.append(kk) self.polygons = list(np.delete(self.polygons, deletelist)) diff --git a/hypertiling/kernelmanu.py b/hypertiling/kernelmanu.py index ae75e65d3abff30622edf1d036026e2cc187aee2..b70bc0b4a84dea6b4c2191a7a320965ad696449c 100644 --- a/hypertiling/kernelmanu.py +++ b/hypertiling/kernelmanu.py @@ -90,7 +90,7 @@ class KernelManu(KernelCommon): # cut away cells outside the fundamental sector # allow some tolerance at the upper boundary - if self.mangle <= cangle < sect_angle_deg+self.degtol+self.mangle: + if self.mangle-1e-14 <= cangle < sect_angle_deg+self.degtol+self.mangle: # try adding to centerlist; it is a set() and takes care of duplicates center = np.round(center, self.dgts) @@ -111,7 +111,7 @@ class KernelManu(KernelCommon): self.polygons.append(adj_pgon) # if angle is in slice, add to centerset_extra - if self.mangle <= cangle <= self.degtol+self.mangle: + if self.mangle-1e-14 <= cangle <= self.degtol+self.mangle: centerset_extra.add(center) startpgon = endpgon