越来越多的雪花:优化几何变换

时间:2014-12-15 02:37:38

标签: python optimization numpy

我根据{{3}编写了一个NumPy版本的Reiter算法,用于结晶雪花(Reiter Chaos,Solitons and Fractals 23(2005)1111-1119,感兴趣的here) }。

不出所料,实际的细胞自动机生长步骤现在要快得多,但我无法对影响几何变换的代码进行太多改进,以便将雪花从阵列中的表示“拉直”到正方形图片。那些NumPy专家可以告诉我如何矢量化或以其他方式改善其性能吗?

工作代码是:

import numpy as np
import pylab

# Size of CA field and centre position; maximum number of iterations
nx, ny = 250, 250
cx, cy = nx // 2, ny // 2
maxit = 200

# Snowflake parameters: see C. A. Reiter, Chaos, Solitons and Fractals 23,
# (2005) 1111–1119
alpha, beta, gamma = 1, 0.6, 0.01
# Initialize the CA field with the background water level
ca = beta * np.ones((ny, nx))

# dx, dy displacements from a cell to get to its hexagonal neighbours as
# represented in the ca array
dcell = [(-1,-1), (0,-1), (-1,0), (1,0), (0,1), (1,1)]

# Seed the snowflake at the centre of the field
ca[cx, cy] = 1

for i in range(maxit):
    print('{}/{}'.format(i+1,maxit))
    # Which cells are "receptive"?
    recep = (ca >= 1)
    for i,j in dcell:
        recep |= (np.roll(np.roll(ca, i, 0), j, 1) >= 1)

    # Contrinbutions from receptive and non-receptive cells
    ca_recep = recep * (ca + gamma)
    ca_nonrecep = (~recep) * ca

    # Form the weighted sum of non-receptive cells to the next iteration
    wsum = ca_nonrecep * (1 - alpha / 2)
    wnsum = sum(np.roll(np.roll(ca_nonrecep, i, 0), j, 1) for i,j in dcell)
    wsum += wnsum * alpha / 12
    ca = ca_recep + wsum

# Geometric transformation from CA field to image:
###### This bit is quite slow and could be optimized ######
# cos(-45deg), sin(-45deg), y-scaling factor
sn, cs, sc = np.sin(-np.pi/4), np.cos(-np.pi/4), np.sqrt(3)
# Image height and width; centre position in image
height, width = 2 * ny, 2 * nx
imcy, imcx = height / 2, width / 2
# Image array (0=water, 1=ice)
im = np.zeros((height, width))
for ky in range(height):
    for kx in range(width):
        # Stretch and rotate CA field onto image
        tx, ty = kx - imcx, (ky - imcy) * sc
        tx, ty = tx * cs - ty * sn + imcx, tx * sn + ty * cs + imcy
        # Don't stray outside image bounds
        if 0 <= tx <= width and 0 <= ty <= height:
            c = ca[int((cy-1)*ty/ny), int((cx-1)*tx/nx)]
            if c >= 1:
                im[ky, kx] = 1

pylab.imshow(im, interpolation="nearest")
pylab.show()

我尝试了以下内容:

tx, ty = np.arange(-width/2, width/2), np.arange(-height/2, height/2) * sc
tx, ty = tx * cs - ty * sn + imcx, tx*sn + ty * cs + imcy
im = (ca[((cy-1)*ty/ny).astype(int), ((cx-1)*tx/nx).astype(int)] >= 1)
pylab.imshow(im, interpolation="nearest")
pylab.show()

但只是获取IndexErrors,因为我的索引超出了ca的范围。

1 个答案:

答案 0 :(得分:2)

讨厌的东西,如六边形网格,但下面的代码应该照顾它。

# Indices for the square mesh
ky, kx = np.indices([height, width])

# Map square mesh to hexagonal mesh
tx0 = kx - imcx
ty0 = (ky - imcy) * sc
tx = tx0*cs - ty0*sn + imcx
ty = tx0*sn + ty0*cs + imcy

# Boolean mask to stay within bounds
b = (0 <= tx) & (tx <= width) & (0 <= ty) & (ty <= height)

# Cast to integers and copy values
ci = ((cy-1)*ty[b]/ny).astype(int)
cj = ((cx-1)*tx[b]/nx).astype(int)
im = np.zeros([height, width])
im[b] = ca[ci, cj]

最后一行相当于可能更明显:

im[ky[b],kx[b]] = ca[ci, cj]