diff --git a/Python/waveform.py b/Python/waveform.py index 1c93946284ec1d979faaa4887b4783f28a2f20fc..e7167d8cc7002d5e7ea62f64724baf9d57ab3cd3 100644 --- a/Python/waveform.py +++ b/Python/waveform.py @@ -136,14 +136,51 @@ def create_path_table(wfm: Waveform) -> any: # return path_table.astype(int), np.sum(path_table.diagonal().T, axis=0, dtype=int) +def stack_left(i_start, i_end, offset, stack_size=0): + # calculate first index where the reduced path algorithm is applied + # threshold = 0.01 + # cutoff = np.ceil(np.log(threshold) / np.log(1-load_p)) + # cutoff = int(cutoff) + # print(cutoff) + if stack_size == 0: + stack_size = np.floor((i_end - i_start) / 2) + stack_last = int(stack_size + i_start) - 1 + dist_mod = (i_end - i_start - stack_size) / (i_end - i_start) # max_distance ratio + dist_add = offset + + # get a list of moves to pre-generate + moves = [] + max_dist = 0 + for i in range(i_start, i_end): + moves.append([]) + j_max = i if i < stack_last else stack_last + dist = np.ceil((i - i_start) * dist_mod + dist_add) + j_min = int(i - dist) if i - dist >= i_start else i_start + for j in range(j_min, j_max + 1): + moves[i - i_start].append(j) # add all paths between j_min and j_max + if max_dist < abs(j-i): + max_dist = abs(j-i) + return moves, max_dist + + +def stack_right(i_start, i_end, offset, stack_size=0): + moves, max_dist = stack_left(i_start, i_end, offset=offset, stack_size=stack_size) + moves.reverse() + for i in range(len(moves)): + moves[i].reverse() + for j in range(len(moves[i])): + moves[i][j] = i_end - 1 - moves[i][j] + i_start + return moves, max_dist + + def create_path_table_reduced( - wfm: Waveform, target_idx, max_dist=np.inf, save_path=None + wfm: Waveform, target_idx, dist_offset=np.inf, save_path=None, partition=False ) -> Tuple[Dict[Tuple[int, int], np.ndarray], np.ndarray]: """ create a dim-3 look up table where the table[i,j] contains a sine wave to move tweezer i to tweezer j :param save_path: file saving path :param target_idx: indices of target pattern - :param max_dist: maximum move distance in indices + :param dist_offset: maximum move distance in indices :param wfm: waveform object already initialized with basic parameters. :return: dictionary containing rearrange paths """ @@ -153,19 +190,38 @@ def create_path_table_reduced( a = wfm.amplitude omega_interp = interp1d(w, a, kind='cubic') - # obtain all move combinations: - n = len(wfm.omega) # total number of tweezers + nt = len(wfm.omega) # total number of tweezers moves = [] + target = np.zeros(nt) + target[target_idx] = 1 dw_max = 0 # longest move, this sets the size of path_table - for i in range(n): - moves.append([]) - for j in target_idx: - if i < j and True: # only allow uni-direction moves - continue - if abs(i - j) <= max_dist: - moves[i].append(j) - dw = abs(wfm.omega[j] - wfm.omega[i]) - if dw_max < dw: dw_max = dw + + if not partition: + # obtain all move combinations, target based, non-partitioned: + for i in range(nt): + moves.append([]) + for j in target_idx: + if i < j and True: # only allow uni-direction moves + continue + if abs(i - j) <= dist_offset: + moves[i].append(j) + dw = abs(wfm.omega[j] - wfm.omega[i]) + if dw_max < dw: dw_max = dw + if partition: + offset = dist_offset + divide_idx = int(np.floor(np.median(target_idx))) + left_size = np.sum(target[:divide_idx], dtype=int) + right_size = np.sum(target[divide_idx:], dtype=int) + moves_l, dw_max_l = stack_right(0, divide_idx, offset, left_size) # stack left side to right + moves_r, dw_max_r = stack_left(divide_idx, nt, offset, right_size) + # print("stack size, half size, middle:", len(t_idx), left_size, right_size) + moves_l.extend(moves_r) + moves = moves_l + dw_max = dw_max_l if dw_max_l > dw_max_r else dw_max_r + dw_max = abs(wfm.omega[dw_max] - wfm.omega[0]) + + print(dw_max / 2 / np.pi) + # setup basic variables twopi = 2 * np.pi vmax = KILO(20) * MEGA(1) # convert units, 20 kHz/us -> 20e3 * 1e6 Hz/s @@ -271,13 +327,13 @@ def create_path_table_reduced( def create_path_table_reduced_gpu( - wfm: Waveform, target_idx, max_dist=np.inf, save_path=None + wfm: Waveform, target_idx, dist_offset=np.inf, save_path=None, partition=False ) -> Tuple[Dict[Tuple[int, int], np.ndarray], np.ndarray]: """ create a dim-3 look up table where the table[i,j] contains a sine wave to move tweezer i to tweezer j :param save_path: file saving path :param target_idx: indices of target pattern - :param max_dist: maximum move distance in indices + :param dist_offset: maximum move distance in indices :param wfm: waveform object already initialized with basic parameters. :return: dictionary containing rearrange paths """ @@ -289,19 +345,37 @@ def create_path_table_reduced_gpu( a = wfm.amplitude omega_interp = interp1d(w, a, kind='cubic') - # obtain all move combinations: - n = len(wfm.omega) # total number of tweezers + nt = len(wfm.omega) # total number of tweezers moves = [] + target = np.zeros(nt) + target[target_idx] = 1 dw_max = 0 # longest move, this sets the size of path_table - for i in range(n): - moves.append([]) - for j in target_idx: - if i < j and True: # only allow uni-direction moves - continue - if abs(i - j) <= max_dist: - moves[i].append(j) - dw = abs(wfm.omega[j] - wfm.omega[i]) - if dw_max < dw: dw_max = dw + + if not partition: + # obtain all move combinations, target based, non-partitioned: + for i in range(nt): + moves.append([]) + for j in target_idx: + if i < j and True: # only allow uni-direction moves + continue + if abs(i - j) <= dist_offset: + moves[i].append(j) + dw = abs(wfm.omega[j] - wfm.omega[i]) + if dw_max < dw: dw_max = dw + if partition: + offset = dist_offset + divide_idx = int(np.floor(np.median(target_idx))) + left_size = np.sum(target[:divide_idx], dtype=int) + right_size = np.sum(target[divide_idx:], dtype=int) + moves_l, dw_max_l = stack_right(0, divide_idx, offset, left_size) # stack left side to right + moves_r, dw_max_r = stack_left(divide_idx, nt, offset, right_size) + # print("stack size, half size, middle:", len(t_idx), left_size, right_size) + moves_l.extend(moves_r) + moves = moves_l + dw_max = dw_max_l if dw_max_l > dw_max_r else dw_max_r + dw_max = abs(wfm.omega[dw_max] - wfm.omega[0]) + + print("max dw:", dw_max / 2 / np.pi) # setup basic variables twopi = 2 * np.pi