Spaces:
Runtime error
Runtime error
| #--------------------------- | |
| # Field generator module | |
| # PabloVD | |
| # Started: 11/5/20 | |
| #--------------------------- | |
| """ | |
| Collection of noise fields for generating maps. | |
| Noises included are: | |
| "gauss": Random gaussian field, with a given power spectrum, computed using the package powerbox | |
| "perlin": Perlin noise, computed using the package noise | |
| "warped_perlin": Perlin noise with domain warping, computed using the package noise | |
| "cos": Sinusoidal noise (to be improved) | |
| "fbm": Fractional Brownian Field | |
| """ | |
| import numpy as np | |
| import powerbox as pbox | |
| import noise | |
| # Define power spectrum as a power law with an spectral index indexlaw | |
| # With lower the spectral indexes (redder noise), small structures are removed | |
| def powerspec(k,indexlaw=-3.): | |
| return k**indexlaw | |
| # Generate a Gaussian field with a power law power spectrum | |
| def gaussian_field(boxsize,seed,indexlaw=-3.): | |
| field = pbox.PowerBox(boxsize, lambda k: powerspec(k,indexlaw), dim=2, boxlength=1.,seed=seed).delta_x() | |
| return field | |
| # Generate a Perlin field | |
| def perlin_field(boxsizex,seed,scale,octaves,persistence,lacunarity,boxsizey=None): | |
| if boxsizey==None: boxsizey=boxsizex | |
| shape = (boxsizex,boxsizey) | |
| field = np.zeros(shape) | |
| for i in range(shape[0]): | |
| for j in range(shape[1]): | |
| field[i,j] = noise.pnoise2(i/scale, | |
| j/scale, | |
| octaves=octaves, | |
| persistence=persistence, | |
| lacunarity=lacunarity, | |
| #repeatx=1024, | |
| #repeaty=1024, | |
| base=seed) | |
| return field | |
| # 2D cosinus (see Hill noise for something similar but better https://blog.bruce-hill.com/hill-noise) | |
| def cos_noise(X,Y,amp,frecx,frecy,phase): | |
| return amp*np.cos( frecx*X +frecy*Y + phase) | |
| #return Amp*(np.cos( frecx*X) +np.cos(frecy*Y + phase)) | |
| # Generate a noise using superposition of cosinus | |
| def cos_field(boxsizex,seed,scale,octaves,persistence,lacunarity,boxsizey=None): | |
| if boxsizey==None: boxsizey=boxsizex | |
| np.random.seed(seed=seed) | |
| frec0 = 5. | |
| x, y = np.linspace(0,boxsizex,num=boxsizex), np.linspace(0,boxsizey,num=boxsizey) | |
| X, Y = np.meshgrid(x,y) | |
| noise_tot = np.zeros((boxsizex,boxsizey)) | |
| for oct in range(octaves): | |
| Amp, frecx, frecy, phase = np.random.random(), 2.*np.pi*frec0*random.uniform(-1.,1.), 2.*np.pi*frec0*random.uniform(-1.,1.), 2.*np.pi*np.random.random() | |
| noise_tot += persistence**oct*cos_noise(X/scale,Y/scale,Amp,frecx*lacunarity**oct,frecy*lacunarity**oct,phase) | |
| return noise_tot | |
| # Generate a Perlin field with warping domain (see e.g. https://iquilezles.org/www/articles/warp/warp.htm) | |
| def warped_perlin_field(boxsizex,seed,scale,octaves,persistence,lacunarity,amplitude=None,boxsizey=None): | |
| if boxsizey==None: boxsizey=boxsizex | |
| shape = (boxsizex,boxsizey) | |
| if amplitude==None: amplitude = np.random.uniform(0.,30.) | |
| field = np.zeros(shape) | |
| for i in range(shape[0]): | |
| for j in range(shape[1]): | |
| vec = np.random.rand(2) | |
| ii = noise.pnoise2(i/scale,j/scale,octaves=octaves,persistence=persistence,lacunarity=lacunarity,base=seed) | |
| jj = noise.pnoise2(i/scale,j/scale,octaves=octaves,persistence=persistence,lacunarity=lacunarity,base=seed) | |
| field[i,j] = noise.pnoise2(i/scale + amplitude*ii,j/scale + amplitude*jj,octaves=octaves,persistence=persistence,lacunarity=lacunarity,base=seed) | |
| return field | |
| # Embedding of covariance function on a [0,R]^2 grid for fractional Brownian field | |
| # From https://gist.github.com/radarsat1/6f8b9b50d1ecd2546d8a765e8a144631 | |
| def rho(x,y,R,alpha): | |
| if alpha <= 1.5: | |
| # alpha=2*H, where H is the Hurst parameter | |
| beta = 0 | |
| c2 = alpha/2 | |
| c0 = 1-alpha/2 | |
| else: | |
| # parameters ensure piecewise function twice differentiable | |
| beta = alpha*(2-alpha)/(3*R*(R**2-1)) | |
| c2 = (alpha-beta*(R-1)**2*(R+2))/2 | |
| c0 = beta*(R-1)**3+1-c2 | |
| # create continuous isotropic function | |
| r = np.sqrt((x[0]-y[0])**2+(x[1]-y[1])**2) | |
| if r<=1: | |
| out=c0-r**alpha+c2*r**2 | |
| elif r<=R: | |
| out=beta*(R-r)**3/r | |
| else: | |
| out=0 | |
| return out, c0, c2 | |
| # Fractional Brownian surface | |
| # The main control is the Hurst parameter: H should be between 0 and 1, where 0 is very noisy, and 1 is smoother. | |
| # From https://gist.github.com/radarsat1/6f8b9b50d1ecd2546d8a765e8a144631 | |
| def brownian_surface(boxsizex, H=0.8): | |
| N = 2*boxsizex | |
| R = 2 # [0,R]^2 grid, may have to extract only [0,R/2]^2 | |
| # size of grid is m*n; covariance matrix is m^2*n^2 | |
| M = N | |
| # create grid for field | |
| tx = np.linspace(0, R, M) | |
| ty = np.linspace(0, R, N) | |
| rows = np.zeros((M,N)) | |
| for i in range(N): | |
| for j in range(M): | |
| # rows of blocks of cov matrix | |
| rows[j,i] = rho([tx[i],ty[j]], | |
| [tx[0],ty[0]], | |
| R, 2*H)[0] | |
| BlkCirc_row = np.vstack( | |
| [np.hstack([rows, rows[:,-1:1:-1]]), | |
| np.hstack([rows[-1:1:-1,:], rows[-1:1:-1, -1:1:-1]])]) | |
| # compute eigen-values | |
| lam = np.real(np.fft.fft2(BlkCirc_row))/(4*(M-1)*(N-1)) | |
| lam = np.sqrt(lam) | |
| # generate field with covariance given by block circular matrix | |
| Z = np.vectorize(complex)(np.random.randn(2*(M-1), 2*(M-1)), | |
| np.random.randn(2*(M-1), 2*(M-1))) | |
| F = np.fft.fft2(lam*Z) | |
| F = F[:M, :N] # extract sub-block with desired covariance | |
| out,c0,c2 = rho([0,0],[0,0],R,2*H) | |
| field1 = np.real(F) # two independent fields | |
| #field2 = np.imag(F) | |
| #field1 = field1 - field1[0,0] # set field zero at origin | |
| #field2 = field2 - field2[0,0] # set field zero at origin | |
| # make correction for embedding with a term c2*r^2 | |
| field1 = field1 + np.kron(np.array([ty]).T * np.random.randn(), np.array([tx]) * np.random.randn())*np.sqrt(2*c2) | |
| #field2 = field2 + np.kron(np.array([ty]).T * np.random.randn(), np.array([tx]) * np.random.randn())*np.sqrt(2*c2) | |
| #X,Y = np.meshgrid(tx,ty) | |
| field1 = field1[:N//2, :M//2] | |
| #field2 = field2[:N//2, :M//2] | |
| return field1 | |