def process(self, timestep=1): ''' Processes the surface depending whether par.ETCHING is set or not. When the initialTime is specified par.ETCHING = True -> etching par.ETCHING = False-> Sputtern When a file is specified, the process is written to a file after each step. >>>surface.process(time, step) ''' if par.ETCHING: vn = par.ETCH_RATE else: vn = sputterVelocity(self) assert len(vn) > 0, 'Error: vn could not be calculated!' self.movePointsByDirection(vn*timestep) if not par.NUMPY: #Umwandlung da delopping ein Liste für korrekte Funktion braucht, wenn par.NUMPY=False self.xvals, self.yvals = np.array(deloop(list(self.xvals), list(self.yvals))) else: self.xvals, self.yvals = deloop(self.xvals, self.yvals) #Berechne neue Winkelsymmetralen für die neuen x & y werte self.xs, self.ys = anglebisect(self.xvals, self.yvals) #Falls die Funktion Adaptive Gitter erwünscht ist, passe Knoten (und Winkelsymmetralen) an if par.ADAPTIVE_GRID: adapt(self)
def __init__(self): interval_start = par.XMIN interval_end = par.XMAX period = interval_start - interval_end assert period != 0, 'Error period is 0.' interval_step = par.DELTA_X amplitudePP = par.FUN_PEAK_TO_PEAK self.surfaceType = par.INITIAL_SURFACE_TYPE self.surfaceFile = par.INITIAL_SURFACE_FILE #arange() creates a half-open interval, which excludes the endpoint self.xvals = np.arange(interval_start, interval_end + interval_step, interval_step) self.yvals = np.zeros_like(self.xvals) func = functions.default if par.INITIAL_SURFACE_TYPE == 'Cosine': func = functions.cosine elif par.INITIAL_SURFACE_TYPE == 'DoubleCosine': func = functions.doubleCosine elif par.INITIAL_SURFACE_TYPE == 'Step': func = functions.step elif par.INITIAL_SURFACE_TYPE == 'V-Shape': func = functions.vShape for i, x in enumerate(self.xvals): self.yvals[i] = amplitudePP * (1 + func(x * 2*pi / period) ) #Berechne Winkelsymmetralen self.xs, self.ys = anglebisect(self.xvals, self.yvals) #Falls Adaptives Grid gewünscht, passe Werte an if par.ADAPTIVE_GRID: adapt(self)
def adapt_grid(self, method='linear'): """Adapts surface so that the distance of adjacent points is not too large or too small (as defined by MAX_SEGLEN) and angles between normal vectors of adjacent knots do not exceed MAX_ANGLE. method : str, optional Method of Possible values are 'linear', 'quadratic'. 'cubic' """ x, y = self.vertices # Check if x-values are monotonically increasing if np.any(x[1:] - x[:-1] < 0): print('Error: X-Values are not monotonically increasing!') sys.exit() # Check if the segments are too short and remove knot if so max_angle = np.deg2rad(par.MAX_ANGLE) status = True while (status): dx = x[2:] - x[:-2] dy = y[2:] - y[:-2] double_seglen = np.hypot(dx, dy) remove_indices, = np.where(double_seglen < par.MAX_SEGLEN) if remove_indices.size == 0: break for remove_index in remove_indices: if abs(self.angles[remove_index + 2] - self.angles[remove_index]) < max_angle: x = np.delete(x, remove_index + 1) y = np.delete(y, remove_index + 1) self.vertices = np.array((x, y)) self.__directions() break else: status = False plt.plot(x, y, 'b+') # Check if the segments are too long and insert knot if so dx = x[1:] - x[:-1] dy = y[1:] - y[:-1] seglen = np.hypot(dx, dy) long_seg_index, = np.where(seglen > par.MAX_SEGLEN) if long_seg_index.size > 0: split_value = seglen[long_seg_index] / par.MAX_SEGLEN split_value = np.ceil(split_value) f = interpolate.interp1d(x, y, method) index_insert = list() x_insert = list() for i in range(long_seg_index.size): index_local = long_seg_index[i] index_new = np.ones(split_value[i] - 1) * (index_local + 1) index_insert.append(index_new) x_new = np.linspace(x[index_local], x[index_local + 1], num=split_value[i], endpoint=False) x_insert.append(x_new[1:]) x_insert = np.hstack(x_insert) y_insert = f(x_insert) index_insert = np.hstack(index_insert) x = np.insert(x, index_insert, x_insert) y = np.insert(y, index_insert, y_insert) self.vertices = np.array((x, y)) self.__directions() # Check if angle between normal vectors of adjacent knots is too large # and insert additional knots (same coordinates, different normal vec) x, y = self.vertices nvx, nvy = self.directions # Calculate angles between segments dx = x[1:] - x[:-1] dy = y[1:] - y[:-1] seglen = np.hypot(dx, dy) seg_angles_diff = dx[:-1] * dx[1:] + dy[:-1] * dy[1:] seg_angles_diff /= (seglen[:-1] * seglen[1:]) seg_angles_diff = np.clip(seg_angles_diff, -1., 1.) seg_angles_diff = np.arccos(seg_angles_diff) max_angle = np.deg2rad(par.MAX_ANGLE) large_angles, = np.where(seg_angles_diff > max_angle) if large_angles.size > 0: index_insert = list() x_insert = list() y_insert = list() nvx_insert = list() nvy_insert = list() for i in range(large_angles.size): index_local = large_angles[i] delta_angle_left = self.angles[index_local + 1] - self.angles[index_local] local_split = np.ceil(abs(delta_angle_left / max_angle)) local_split = int(local_split) rot_angle = delta_angle_left / local_split nvx_new = list() nvy_new = list() for k in range(local_split): nvx_local = nvx[index_local] * np.cos(k * rot_angle) nvx_local -= nvy[index_local] * np.sin(k * rot_angle) nvy_local = nvx[index_local] * np.sin(k * rot_angle) nvy_local += nvy[index_local] * np.cos(k * rot_angle) nvx_new.append(nvx_local) nvy_new.append(nvy_local) index_new = np.array(np.ones(local_split) * index_local + 1, dtype=int) index_insert.append(index_new) x_new = np.ones(local_split) * x[index_local + 1] x_insert.append(x_new) y_new = np.ones(local_split) * y[index_local + 1] y_insert.append(y_new) nvx_insert.append(nvx_new) nvy_insert.append(nvy_new) delta_angle_right = self.angles[index_local + 2] - self.angles[index_local + 1] local_split = np.ceil(abs(delta_angle_right / max_angle)) local_split = int(local_split) rot_angle = delta_angle_right / local_split nvx_new = list() nvy_new = list() for k in range(1, local_split + 1): nvx_local = nvx[index_local + 1] * np.cos(k * rot_angle) nvx_local -= nvy[index_local + 1] * np.sin(k * rot_angle) nvy_local = nvx[index_local + 1] * np.sin(k * rot_angle) nvy_local += nvy[index_local + 1] * np.cos(k * rot_angle) nvx_new.append(nvx_local) nvy_new.append(nvy_local) index_new = np.array(np.ones(local_split) * index_local + 2, dtype=int) index_insert.append(index_new) x_new = np.ones(local_split) * x[index_local + 1] x_insert.append(x_new) y_new = np.ones(local_split) * y[index_local + 1] y_insert.append(y_new) nvx_insert.append(nvx_new) nvy_insert.append(nvy_new) x_insert = np.hstack(x_insert) y_insert = np.hstack(y_insert) nvx_insert = np.hstack(nvx_insert) nvy_insert = np.hstack(nvy_insert) index_insert = np.hstack(index_insert) x = np.insert(x, index_insert, x_insert) y = np.insert(y, index_insert, y_insert) nvx = np.insert(nvx, index_insert, nvx_insert) nvy = np.insert(nvy, index_insert, nvy_insert) self.vertices = np.array((x, y)) self.directions = np.array((nvx, nvy)) self.angles = np.arctan( (self.directions[0] / (-1 * self.directions[1]))) #Berechne Winkelsymmetralen self.xs, self.ys = anglebisect(self.xvals, self.yvals) #Falls Adaptives Grid gewünscht, passe Werte an if par.ADAPTIVE_GRID: adapt(self) #Berechne neue Winkelsymmetralen für die neuen x & y werte self.xs, self.ys = anglebisect(self.xvals, self.yvals) #Falls die Funktion Adaptive Gitter erwünscht ist, passe Knoten (und Winkelsymmetralen) an if par.ADAPTIVE_GRID: adapt(self)