from pumapy.utilities.workspace import Workspace
from pumapy.utilities.timer import Timer
import pumapy.utilities.generic_checks as check
from pumapy.generation.single_sphere import get_circle_even, get_circle_odd
import numpy as np
[docs]def generate_cylinder_square_array(size, porosity, segmented=True):
""" Generate a 2D periodic array of circles
:param size: length of one side of the output domain
:type size: int
:param porosity: porosity of the output domain
:type porosity: float
:param segmented: return a domain that is already segmented (i.e. each sphere with unique ID) or
with grayscales 0-255 with threshold=128 for the input diameter
:type segmented: bool
:return: array of circles
:rtype: Workspace
:Example:
>>> import pumapy as puma
>>> ws = puma.generate_cylinder_square_array(100, 0.8, segmented=True)
Generated in: ...
>>> # puma.render_volume(ws) # to visualize it
"""
generator = GeneratorSquareArray(size, porosity)
generator.error_check()
generator.log_input()
ws = generator.generate()
generator.log_output()
if segmented:
ws.binarize(128)
return ws
[docs]class GeneratorSquareArray:
def __init__(self, size, porosity):
self._workspace = Workspace()
self._size = (size, size, 1)
self._center = (np.array([size, size]) / 2) + np.array([size, size])
self._porosity = porosity
self._diameter = np.sqrt((1-porosity) * size*size / (2 * np.pi)) * 2
self._size_padded = (self._size[0] * 3, self._size[1]*3, 1)
[docs] def generate(self):
t = Timer()
self._workspace.resize_new_matrix(self._size_padded)
self._generate_circle()
print("Generated in: " + str(t.elapsed()) + " seconds")
return self._workspace
def _generate_circle(self):
if self._size[0] % 2 == 0:
circle, circlesize = get_circle_even(self._diameter)
else:
circle, circlesize = get_circle_odd(self._diameter)
self._circlesize = circlesize
if self._circlesize % 2 == 0:
self._size_m = self._circlesize / 2
self._size_p = self._circlesize / 2
else:
self._size_m = int(self._circlesize / 2.)
self._size_p = int(self._circlesize / 2.) + 1
[x,y] = self._center
xm = int(x - self._size_m)
xp = int(x + self._size_p)
ym = int(y - self._size_m)
yp = int(y + self._size_p)
self._workspace.matrix[xm:xp, ym:yp] += circle[:,:,None]
circle, circlesize = get_circle_even(self._diameter)
self._circlesize = circlesize
if self._circlesize % 2 == 0:
self._size_m = self._circlesize / 2
self._size_p = self._circlesize / 2
else:
self._size_m = int(self._circlesize / 2.)
self._size_p = int(self._circlesize / 2.) + 1
xvec = [self._size[0], self._size[0] * 2]
yvec = [self._size[1], self._size[1] * 2]
for x in xvec:
for y in yvec:
xm = int(x - self._size_m)
xp = int(x + self._size_p)
ym = int(y - self._size_m)
yp = int(y + self._size_p)
self._workspace.matrix[xm:xp, ym:yp] += circle[:, :, None]
self._workspace.matrix = self._workspace.matrix[self._size[0]:2 * self._size[0], self._size[1]:2 * self._size[1]]
[docs] def log_output(self):
self._workspace.log.log_section("Finished Generating Square Array")
self._workspace.log.write_log()
[docs] def error_check(self):
if not check.size_check(self._size):
return False
if self._porosity < 0.214602:
raise Exception("Error, invalid porosity. Cylinders cannot fit with a porosity of < 0.214602")