def max_smoothing(road: Road, maxh: int): """ Local max smoothing method. Takes all the grains above a certain threshold and puts them onto neighbouring lower positions. :param road: Road class instance :param maxh: positive integer, threshold value, above this value all grains are removed :return: """ # maxh = 7 while max(road) > maxh: for i in range(road.size): if road[i] > maxh: for n in range(1, road.size): right = (i + n) % road.size left = (i - n) % road.size rightr = road[right] leftr = road[left] if rightr < leftr and rightr < maxh: road.add_grain(right) road.remove_grain(i) break elif rightr > leftr and leftr < maxh: road.add_grain(left) road.remove_grain(i) break elif rightr == leftr and rightr < maxh: uniran = np.random.uniform(0, 1) if uniran >= 0.5: road.add_grain(right) road.remove_grain(i) break else: road.add_grain(left) road.remove_grain(i) break
def general_slope_smoothing(road: Road, slope_inverse=3): """ TODO DOES NOT WORK YET General slope smoothing function with an aimed slope of 1/slope_inverse for the heapes. I.e. if slope_inverse=3 the heaps should a an incline of 1/3. :param road: Road class instance :param slope_inverse: positive integer, define the slope as 1/slope_inverse :return: """ if slope_inverse < 1: # do nothing if the slope is not a positive integer return for i in range(0, road.size, slope_inverse): end_segm_slice_point = i + 2 * slope_inverse sum_over_next_segment = np.sum(road.piles[i:end_segm_slice_point]) average_over_next_segment = sum_over_next_segment / (2 * slope_inverse) average_floor_int = int(average_over_next_segment) start_segm_height = road[i] end_segm_index = end_segm_slice_point - 1 end_segm_height = road.piles[end_segm_index] road.piles[i:end_segm_slice_point] = average_floor_int rest_to_distribute = sum_over_next_segment - average_floor_int * 2 * slope_inverse if start_segm_height == end_segm_height: if rest_to_distribute > 0: road.add_random_irregularities(rest_to_distribute, (i, end_segm_slice_point)) elif start_segm_height < end_segm_height: if rest_to_distribute == 0: road.remove_grain(start_segm_height) road.add_grain(end_segm_height) else: k = int(rest_to_distribute / 3) road.add_grains( range(end_segm_slice_point - k, end_segm_slice_point), [2] * k) rest_to_distribute -= 2 * k road.add_grains( range(end_segm_slice_point - k - rest_to_distribute, end_segm_slice_point - k), [1] * rest_to_distribute) elif start_segm_height > end_segm_height: if rest_to_distribute == 0: road.add_grain(start_segm_height) road.remove_grain(end_segm_height) else: k = int(rest_to_distribute / 3) road.add_grains(range(i, i + k), [2] * k) rest_to_distribute -= 2 * k road.add_grains(range(i + k, i + k + rest_to_distribute), [1] * rest_to_distribute)
def random_wind_smoothing(road: Road, maxh: int): """ Global max/wind smoothing function similar to wind_smoothing. The difference is that the grains are randomly distributed over all lowest positions with the lowest height and not to the first position in the road with the lowest height. :param road: Road class instance :param maxh: positive integer, threshold value, above this value all grains are removed :return: """ while max(road) > maxh: for i in range(road.size): if road[i] > maxh: temp_minimum = min(road) temp_minimum_indices = np.where(road.piles == temp_minimum) chosen_index = np.random.choice(temp_minimum_indices[0]) road.remove_grain(i) road.add_grain(chosen_index)
def wind_smoothing(road: Road, maxh: int): """ Global max/wind smoothing function. Takes all the grains above a threshold maxh and puts them to the lowest heights (globally). This methods puts the grains to the first position with the lowest height. :param road: Road class instance :param maxh: positive integer, threshold value, above this value all grains are removed :return: """ while max(road) > maxh: for i in range(road.size): if road[i] > maxh: temp_minimum = min(road) for j in range(road.size): if road[j] == temp_minimum: road.remove_grain(i) road.add_grain(j) break
def slope_smoothing(road: Road, slope=1): """ Pairwise comparison of neighbouring elements in the road. If their height difference is bigger than one they grains from the bigger one are removed and put on the lower position. :param road: Road class :return: """ for i in range(road.size): i2 = (i + 1) % road.size height1 = road[i] height2 = road[i2] diff = height1 - height2 if diff > slope: road.add_grain(i2) road.remove_grain(i) elif diff < -slope: road.add_grain(i) road.remove_grain(i2)