def test_invalid_size(self): with self.assertRaises(ValueError): lb.Simulator(0, 0) with self.assertRaises(ValueError): lb.Simulator(0, 1) with self.assertRaises(ValueError): lb.Simulator(1, 0)
def main(): width = 300 height = 300 lb.set_random_seed(randint(0, 32768)) def end_condition(ix, iy): return ix == 0 or ix == width - 1 or iy == 0 or iy == height - 1 def loop(current_loop, max_loop, cells): if current_loop % 100 == 0: print(f'loop:{current_loop}/{max_loop}') return False # Initialize a break model min_guarantee = 0.0 eta = 6.0 model = lb.FastDBM(width, height, min_guarantee=min_guarantee, eta=eta) # Simulate sim = lb.Simulator(width, height, model) sim.breakdown(width // 2, height // 2) sim.simulate(max_loop=10000, callback_on_break=end_condition, callback_on_loop=loop) # Output save(sim.cells, Path(__file__).stem, output_binary=True, output_mono=True, output_gray=True)
def main(): # ValueNoiseBreakModel has randomness more than default model, but slower... save_probability_mask = True width = 300 height = 300 seed = randint(0, 65535) # ValueNoiseBreakModel uses own randomize code scale = 50.0 # zoom factor persistence = 1.0 # contrast octaves = 6 # details model = lb.ValueNoiseBreakModel(width, height, seed=seed, scale=scale, persistence=persistence, octaves=octaves) # Save probability if save_probability_mask: prob = Image.new("L", (width, height)) for y in range(height): for x in range(width): p = model.get(x, y) lum = int(p * 255) prob.putpixel((x, y), (lum, )) prob.save(Path(__file__).stem + '_prob.png') sim = lb.Simulator(width, height, model) sim.breakdown(150, 150) sim.simulate(max_loop=3000) # Save to PNG save(sim.cells, Path(__file__).stem, output_gray=True)
def main(): width = 200 height = 200 sim = lichtenberg.Simulator(width, height) sim.breakdown(0, 0) sim.insulate_square(0, 50, 40, 51) sim.insulate_square(50, 0, 51, 45) sim.simulate(max_loop=1000) # 1. Draw entire tree image = Image.new('RGB', (width, height), (0x00, 0x00, 0x00)) c_max = sim.cells.get_max_count() for y in range(height): for x in range(width): c = sim.cells.get_count(x, y) lm = int(255 * c / c_max) # normalize image.putpixel((x, y), (lm, lm, lm)) image.save(Path(__file__).stem + '_1.png') # 2. Select several paths targets = [(5, 116), (3, 176), (46, 180), (94, 184), (184, 187), (175, 85), (156, 9)] image = Image.new('RGB', (width, height), (0x00, 0x00, 0x00)) tree = lichtenberg.Tree(sim.cells) for target in targets: path = tree.get_path(0, 0, *target) # get the path between (0, 0) and target for point in path: x, y = point image.putpixel((x, y), (255, 255, 255)) image.save(Path(__file__).stem + '_2.png')
def main(): width = 300 height = 300 lb.set_random_seed(randint(0, 32768)) def loop(current_loop, max_loop, cells): if current_loop % 100 == 0: print(f'loop:{current_loop}/{max_loop}') return False # Initialize a break model num_particle = 15000 model = lb.DLABreakModel(width, height, num_particle=num_particle) # Simulate sim = lb.Simulator(width, height, model) sim.breakdown(width // 2, height // 2) sim.simulate(max_loop=10000, callback_on_loop=loop) # Output save(sim.cells, Path(__file__).stem, output_binary=True, output_mono=True, output_gray=True)
def main(): width = 100 height = 100 radius = width // 2 def end_condition(ix, iy): dx = ix - width // 2 dy = iy - height // 2 d = (dx*dx+dy*dy) ** 0.5 end = (d >= radius - 3) if end: print("Reached the outer circle. Break.") return end def loop(current_loop, max_loop, cells): print(f'loop:{current_loop}/{max_loop}') return False # Initialize the field of simulation (width+2) x (height+2) grid = [] for y in range(height+2): row = [] for x in range(width+2): c = lb.DBMCell() c.potential = 0.0 c.lock = False row.append(c) grid.append(row) n = width * height // 2 cx, cy = width // 2, height // 2 R = radius - 2 for i in range(n): # Put potential-1.0 on the circle (x-xc)^2+(y-yc)^2=R^2 t = 2 * math.pi * (i / n) x = int(R * math.cos(t)) + cx y = int(R * math.sin(t)) + cy grid[y][x].lock = True grid[y][x].potential = 1.0 # Initialize a break model eta = 2.0 # Detail level of branching min_guarantee = 0.001 model = lb.DielectricBreakModel(width, height, grid, min_guarantee=min_guarantee, eta=eta) # Simulate sim = lb.Simulator(width, height, model) sim.breakdown(width // 2, height // 2) sim.simulate(max_loop=10000, callback_on_break=end_condition, callback_on_loop=loop) # Output gamma = 1.0 / 1.8 # to remove short branches scale = 1.0 save(sim.cells, Path(__file__).stem, output_binary=True, output_mono=True, output_gray=True, gamma=gamma, scale=scale)
def test_insulate_invalid(self): sim = lb.Simulator(1, 1) with self.assertRaises(ValueError): sim.insulate(-1, 0) with self.assertRaises(ValueError): sim.insulate(0, -1) with self.assertRaises(ValueError): sim.insulate(1, 0) with self.assertRaises(ValueError): sim.insulate(0, 1)
def test_breakdown_invalid(self): # Invalid coordinate sim = lb.Simulator(1, 1) with self.assertRaises(ValueError): sim.breakdown(-1, 0) with self.assertRaises(ValueError): sim.breakdown(0, -1) with self.assertRaises(ValueError): sim.breakdown(1, 0) with self.assertRaises(ValueError): sim.breakdown(0, 1)
def main(): width = 200 height = 200 lb.set_random_seed(randint(0, 65535)) sim = lb.Simulator(width, height) sim.breakdown(100, 50) sim.breakdown(50, 100) sim.breakdown(100, 150) sim.breakdown(150, 100) sim.simulate(max_loop=1000) save(sim.cells, Path(__file__).stem, output_gray=True)
def main(): # Basic Simulation width = 300 height = 300 lb.set_random_seed(randint(0, 65535)) # Set the random seed of C/C++ standard library sim = lb.Simulator(width, height) sim.breakdown(150, 150) # First broken cell is (x,y)=(150, 150) sim.simulate(max_loop=2000) # Save to PNG save(sim.cells, Path(__file__).stem, output_gray=True) # See lichtenberg/archive.py
def main(): width, height = 300, 300 img = Image.new("RGB", (width, height)) # Using FastDBM(see also 10_fastdbm_top.py) def end_condition(ix, iy): return iy == height - 1 def loop(current_loop, max_loop, cells): if current_loop % 100 == 0: print(f'loop:{current_loop}/{max_loop}') return False min_guarantee = 0.0 eta = 2.0 bias = make_bias(BiasDirection.Down, width, height) model = lb.FastDBM(width, height, min_guarantee=min_guarantee, eta=eta, bias=bias) sim = lb.Simulator(width, height, model) sim.breakdown(width // 2, 0) sim.simulate(max_loop=40000, callback_on_break=end_condition, callback_on_loop=loop) # Trimming short tree branches min_count = 50 min_luminance, max_luminance = 0.0, 1.00 points, luminance = [], [] max_count = sim.cells.get_max_count() for y in range(height): for x in range(width): if sim.cells.get_broken(x, y): c = sim.cells.get_count(x, y) # length from the end of branch if c >= min_count: if max_count == min_count: f = 1.0 else: f = (c - min_count) / (max_count - min_count) lum = min_luminance + f * (max_luminance - min_luminance) luminance.append(lum) points.append((x, y)) # Imaging blur_params = [(0, 1.0), (1, 4.0), (2, 8.0)] color = (1.2, 1.0, 1.3) draw_blur_with_points(img, points, blur_params, 1.0, color, luminance) img.save(Path(__file__).stem + ".png")
def simulation_2(): mask_path = './resources/mask.png' image = Image.open(mask_path) width, height = image.size pixels = image_to_array(image) model = lichtenberg.ManualBreakModel(width, height, pixels, min_guarantee=0.01) sim = lichtenberg.Simulator(width, height, model) sim.breakdown(0, 0) sim.simulate(max_loop=1000) figure = gray(sim.cells) figure.save(Path(__file__).stem + "_2_gray.png") img_sum = ImageMath.eval("convert((a+b), 'L')", a=image, b=figure) img_sum.save(Path(__file__).stem + "_2_gray_overlay.png")
def main(): sim = lb.Simulator(100, 100) sim.breakdown(0, 0) sim.simulate() prefix = Path(__file__).stem binary_name = prefix + ".bin" # Dump sim.cells.save(binary_name) # Load cells2 = lb.CellList2D() cells2.load(binary_name) # Imaging & Output save(cells2, prefix, output_gray=True) # see lichtenberg/archive.py
def get_path(start: Tuple[int, int], end: Tuple[int, int], margin: int = 50, randomness: float = 50.0, seed: int = None) \ -> List[Tuple[int, int]]: """ Generate single zig-zag line :param start: Starting Point :param end: Ending Point :param margin: The margin of the working area[pixel] :param randomness: Roughness of the line :param seed: The seed value of the internal random number generator :return: The list of points """ if seed is not None and not isinstance(seed, int): raise ValueError("seed must be int or None") x1, y1 = start x2, y2 = end width = abs(x2 - x1 + 1) height = abs(y2 - y1 + 1) work_width = width + margin * 2 work_height = height + margin * 2 x_start, x_end = 0, width - 1 y_start, y_end = 0, height - 1 if x1 > x2: x_start, x_end = x_end, x_start if y1 > y2: y_start, y_end = y_end, y_start # Simulation if seed is None: seed = randint(0, 2**24) model = lb.ValueNoiseBreakModel(work_width, work_height, seed=seed, scale=randomness) sim = lb.Simulator(work_width, work_height, model) sim.breakdown(x_start + margin, y_start + margin) sim.simulate(max_loop=10**5) # Get Path tree = lb.Tree(sim.cells) points = tree.get_path(x_start + margin, y_start + margin, x_end + margin, y_end + margin) x_offset = x1 - x_start - margin y_offset = y1 - y_start - margin return [(x + x_offset, y + y_offset) for x, y in points]
def main(): width = 200 height = 200 sim = lichtenberg.Simulator(width, height) sim.breakdown(60, 60) sim.insulate_circle(100, 100, 50) sim.simulate(max_loop=1000) image = Image.new('RGB', (width, height), (0x00, 0x00, 0x00)) c_max = sim.cells.get_max_count() for y in range(height): for x in range(width): if sim.cells.get_insulated(x, y): # visualize insulated cells image.putpixel((x, y), (255, 0, 0)) else: c = sim.cells.get_count(x, y) lm = int(255 * c / c_max) # normalize image.putpixel((x, y), (lm, lm, lm)) image.save(Path(__file__).stem + '.png')
def main(): width = 200 height = 200 sim = lichtenberg.Simulator(width, height) sim.breakdown(width // 2, height // 2) sim.insulate_circle(100, 100, 100) sim.simulate(max_loop=1000) tree = lichtenberg.Tree(sim.cells) leaves = tree.get_leaves() # Select and Draw 2048 longest branch image = Image.new('RGB', (width, height), (0x00, 0x00, 0x00)) # Leaf.count is the length from root(the point specified by Simulator.breakdown) longest_leaves = sorted(leaves, key=lambda lf: lf.count)[-2048:] for leaf in longest_leaves: node = leaf.node while node is not None: x, y, _ = node.point image.putpixel((x, y), (255, 255, 255)) node = node.parent image.save(Path(__file__).stem + '_1.png') # Cut down 20-unit from outside image = Image.new('RGB', (width, height), (0x00, 0x00, 0x00)) threshold = 20 for leaf in longest_leaves: node = leaf.node while node is not None: x, y, count = node.point # count is the length from leaf # So omit the end of branch if count >= threshold: image.putpixel((x, y), (255, 255, 255)) node = node.parent image.save(Path(__file__).stem + '_2.png')
def test_run_without_breakdown(self): # At least one break point is needed sim = lb.Simulator(1, 1) with self.assertRaises(RuntimeError): sim.simulate()
def test_insulated_breakpoint(self): sim = lb.Simulator(2, 2) sim.insulate(1, 1) sim.breakdown(1, 1) # invalid with self.assertRaises(RuntimeError): sim.simulate()
def main(): width = 100 height = 100 lb.set_random_seed(156) save_GIF = True GIF_frames: List[Image] = [] # Initialize the field of simulation (width+2) x (height+2) grid = [] for y in range(height+2): row = [] for x in range(width+2): c = lb.DBMCell() c.potential = 0.0 c.lock = False row.append(c) grid.append(row) # Initial Conditions: # - Top row has a minus potentials(attracted) # - Bottom row has a plus potentials(attractor) top, bottom = 0, height+1 for x in range(width+2): grid[top][x].lock = True grid[bottom][x].lock = True grid[bottom][x].potential = 1.0 left, right = 0, width+1 for y in range(height+2): grid[y][left].lock = True grid[y][right].lock = True def end_condition(ix, iy): """ If you return True, the simulation will be interrupted. """ end = (iy == height-1) if end: print("Reached the end line. Break.") return end # Initialize a break model eta = 1.0 # Detail level of branching min_guarantee = 0.005 model = lb.DielectricBreakModel(width, height, grid, min_guarantee=min_guarantee, eta=eta) def loop(current_loop, max_loop, cells): """ If you return True, the simulation will be interrupted. """ # Progress Indicator print(f"loop:{current_loop}/{max_loop}") # True to generate animation frames if save_GIF: if current_loop % 10 == 0: frame = visualize_field(width, height, cells, model) GIF_frames.append(frame) return False # Simulate sim = lb.Simulator(width, height, model, up=False) sim.breakdown(width // 2, 0) sim.simulate(max_loop=10000, callback_on_break=end_condition, callback_on_loop=loop) # Output gamma = 1.0/1.8 scale = 1.0 save(sim.cells, Path(__file__).stem, output_binary=True, output_mono=True, output_gray=True, gamma=gamma, scale=scale) if save_GIF: GIF_frames[0].save(Path(__file__).stem + ".gif", save_all=True, append_images=GIF_frames[1:], optimize=False, duration=100, loop=0)
def main(): width = 300 height = 300 seed = 49057 # randint(0, 65535) print(f"seed={seed}") lb.set_random_seed(seed) # Simulate sim = lb.Simulator(width, height) sim.insulate_circle(75, 225, 150) sim.breakdown(10, 10) sim.simulate(max_loop=2000) # Get Longest Path tree = lb.Tree(sim.cells) leaves = tree.get_leaves() leaves = sorted(leaves, key=lambda lf: lf.count, reverse=True) longest_leaf = leaves[0] longest_points = [] node = longest_leaf.node while node is not None: x, y, _ = node.point longest_points.append((x, y)) node = node.parent # Generate Potential-Points on the path n = len(longest_points) step = 1 potentials = [] potential_curve = func_potential() for i in range(0, n, step): t = i / n x, y = longest_points[i] p = potential_curve(t) potentials.append((x, y, p)) # Output margin = 50 field_width = width + margin * 2 field_height = height + margin * 2 time_factors = [1.0, 0.5, 0.1] for i, t in enumerate(time_factors): print(f"{i + 1}/{len(time_factors)}") # Simulate potential field flares: List[FlarePoint] = [] for x, y, p in potentials: flares.append((margin + x, margin + y, p * t)) field = lb.make_electric_field(field_width, field_height, flares) # Make Images gamma = 1.0 img = Image.new("L", (width, height)) for y in range(height): for x in range(width): p = field[margin + y][margin + x] p = p**gamma c = int(p * 255) img.putpixel((x, y), (c, )) img.save(Path(__file__).stem + f"_{i:02}.png") img = Image.new("L", (width, height)) draw = ImageDraw.Draw(img) n = len(potentials) for i in range(n - 1): x1, y1, _ = potentials[i] x2, y2, _ = potentials[i + 1] draw.line((x1, y1, x2, y2), fill=(255, ), width=10) img.save(Path(__file__).stem + "_line.png")
def test_manual_model_normal(self): values = [[0.5]] model = lb.ManualBreakModel(1, 1, values) sim = lb.Simulator(1, 1, model) sim.breakdown(0, 0) sim.simulate()
def test_breakdown(self): sim = lb.Simulator(1, 1) sim.breakdown(0, 0) self.assertTrue(sim.cells.get_broken(0, 0))
def test_run_with_breakdown(self): sim = lb.Simulator(1, 1) sim.breakdown(0, 0) sim.simulate()
def test_value_noise_model_normal(self): model = lb.ValueNoiseBreakModel(1, 1) sim = lb.Simulator(1, 1, model) sim.breakdown(0, 0) sim.simulate()
def test_valid_size(self): self.assertIsNotNone(lb.Simulator(1, 1)) self.assertIsNotNone(lb.Simulator(1000, 1000))
def test_default_model(self): model = lb.DefaultBreakModel() sim = lb.Simulator(1, 1, model) sim.breakdown(0, 0) sim.simulate()
def test_insulate(self): sim = lb.Simulator(1, 1) sim.insulate(0, 0) self.assertTrue(sim.cells.get_insulated(0, 0))