Guest User

stackexchange

a guest
Jun 9th, 2020
191
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.65 KB | None | 0 0
  1. import numpy as np
  2. import scipy.optimize as so
  3.  
  4. def synth_I_field_compact(part_params, nd, sigma, x, y, z=np.zeros(0), tol=1e-4):
  5.     nparts = int(np.size(part_params) / (nd + 1))
  6.     xpart = part_params[0:nparts] # must be column vector from reshape
  7.     ypart = part_params[nparts:2 * nparts]
  8.     zpart = part_params[nparts:3 * nparts]
  9.     s = part_params[nd*nparts:]
  10.     nx = np.size(x)
  11.     ny = np.size(y)
  12.     nz = np.size(z)
  13.     I = np.zeros((ny, nx, nz))
  14.     dx = x[1] - x[0]
  15.     dy = y[1] - y[0]
  16.     dz = z[1] - z[0]
  17.     di = np.ceil(max_dist/dx)
  18.  
  19.     for i in range(0,nparts):
  20.         ix = round((xpart[i] - x[0]) / dx)
  21.         iy = round((ypart[i] - y[0]) / dy)
  22.         iz = round((ypart[i] - y[0]) / dz)
  23.         iix = np.arange(max(0, ix - di), min(nx, ix + di), 1, dtype=int)
  24.         iiy = np.arange(max(0, iy - di), min(ny, iy + di), 1, dtype=int)
  25.         iiz = np.arange(max(0, iz - di), min(nz, iz + di), 1, dtype=int)
  26.         ddx = dx * iix - xpart[i]
  27.         ddy = dy * iiy - ypart[i]
  28.         ddz = dz * iiz - zpart[i]
  29.         gx = np.exp(-1 / (2 * sigma ** 2) * ddx ** 2)
  30.         gy = np.exp(-1 / (2 * sigma ** 2) * ddy ** 2)
  31.         gz = np.exp(-1 / (2 * sigma ** 2) * ddz ** 2)
  32.         gx = gx[np.newaxis,:, np.newaxis]
  33.         gy = gy[:,np.newaxis, np.newaxis]
  34.         gz = gz[np.newaxis, np.newaxis, :]
  35.         I[np.ix_(iiy, iix, iiz)] = I[np.ix_(iiy, iix, iiz)] + s[i] * gy*gx*gz
  36.     return I
  37.  
  38. nd = 3
  39. x = np.linspace(0, 1, 29) # spatial domain
  40. y = np.linspace(0, 1, 31)
  41. z = np.linspace(0, 1, 30)
  42.  
  43. xp = np.asarray([0.5]) # particle position
  44. yp = np.asarray([0.5])
  45. zp = np.asarray([0.5])
  46.  
  47. nx = np.size(x)
  48. ny = np.size(y)
  49. nz = np.size(z)
  50.  
  51. I = np.zeros((ny, nx, nz)) # intensity field
  52. dx = x[1] - x[0]
  53. dy = y[1] - y[0]
  54. dz = z[1] - z[0]
  55.  
  56. tolerance = 1e-4 # minimum value of Gaussian for compact representation
  57. sigma = x[1]-x[0] # Gaussian width
  58. max_dist = sigma*(-2*np.log(tolerance))
  59. di = np.ceil(max_dist/dx) # maximum distance in compact representation, in index format
  60.  
  61. # Create intensity field/true Gaussian
  62. # this exists separately as its own function synth_I() where [0] is instead for each particle [i]
  63. ix = round((xp[0] - x[0]) / dx) # index of particle center
  64. iy = round((yp[0] - y[0]) / dy)
  65. iz = round((yp[0] - y[0]) / dz)
  66. iix = np.arange(max(0, ix - di), min(nx, ix + di), 1, dtype=int) # grid points with nonzero intensity values
  67. iiy = np.arange(max(0, iy - di), min(ny, iy + di), 1, dtype=int)
  68. iiz = np.arange(max(0, iz - di), min(nz, iz + di), 1, dtype=int)
  69. ddx = dx * iix - xp[0] # distance between particle center and grid point
  70. ddy = dy * iiy - yp[0]
  71. ddz = dz * iiz - zp[0]
  72. gx = np.exp(-1 / (2 * sigma ** 2) * ddx ** 2) # 1D Gaussian
  73. gy = np.exp(-1 / (2 * sigma ** 2) * ddy ** 2)
  74. gz = np.exp(-1 / (2 * sigma ** 2) * ddz ** 2)
  75. gx = gx[np.newaxis,:, np.newaxis]
  76. gy = gy[:,np.newaxis, np.newaxis]
  77. gz = gz[np.newaxis, np.newaxis, :]
  78. I[np.ix_(iiy, iix, iiz)] = I[np.ix_(iiy, iix, iiz)] + gy*gx*gz
  79.  
  80. # Idea: fit Gaussians centered at grid point to unknown distribution, by adjusting intensity of each
  81. Imin = 0.5
  82. ny, nx, nz = I.shape
  83. X, Y, Z = np.meshgrid(x, y, z)
  84. xpart = X[I > Imin] # estimated particle positions based on minimum intensity threshold
  85. ypart = Y[I > Imin]
  86. zpart = Z[I > Imin]
  87. s_init = I[I> Imin] # initial intensity guess to be used in optimization
  88. Np = np.size(xpart) # number of particles to fit to
  89. # simulate intensity as sum of gaussians.
  90.  
  91. # fit using conjugate gradient algorithm as opposed to least squares, for scalability in real problem
  92. # Objective function: 0.5||I - \sum s[i] * G(x;xpart[i])||^2
  93. # Gradient: g[j] =  - \sum { I - \sum s[i] * G(x;xpart[i]) * G(x;xpart[j]) }
  94.  
  95. def diff_and_grad(s):  # ping test this:
  96.     part_params = np.concatenate((xpart, ypart, zpart, s)) # for own code
  97.     # create an intensity field as a combination of Gaussians as above
  98.     synthI = synth_I_field_compact(part_params, nd, sigma, x, y, z)
  99.     Idiff = I - synthI # difference in measurements
  100.     f = 0.5 * np.sum(np.power(Idiff, 2)) # objective function
  101.     g = np.zeros(Np) # gradient
  102.     for i in range(0, Np):
  103.         ix = round((xpart[i] - x[0]) / dx)
  104.         iy = round((ypart[i] - y[0]) / dy)
  105.         iz = round((zpart[i] - z[0]) / dz)
  106.         iix = np.arange(max(0, ix - di), min(nx, ix + di), 1, dtype=int)
  107.         iiy = np.arange(max(0, iy - di), min(ny, iy + di), 1, dtype=int)
  108.         iiz = np.arange(max(0, iz - di), min(nz, iz + di), 1, dtype=int)
  109.         ddx = dx * iix - xpart[i]
  110.         ddy = dy * iiy - ypart[i]
  111.         ddz = dz * iiz - zpart[i]
  112.         gx = np.exp(-1 / (2 * sigma ** 2) * ddx ** 2)
  113.         gy = np.exp(-1 / (2 * sigma ** 2) * ddy ** 2)
  114.         gz = np.exp(-1 / (2 * sigma ** 2) * ddz ** 2)
  115.         Id = Idiff[np.ix_(iiy, iix, iiz)]
  116.         g[i] = -Id.dot(gz).dot(gx).dot(gy) # gradient is -product of local intensity difference with gaussian centered at grid point
  117.     return f, g
  118.  
  119. # only objective function:
  120. def diff(s):
  121.     part_params = np.concatenate((xpart,ypart,zpart,s))
  122.     synthI = synth_I_field_compact(part_params, nd, sigma, x,y,z)
  123.     Idiff = I - synthI
  124.     f = 0.5*np.sum(np.power(Idiff,2))
  125.     return f
  126.  
  127. # differing gradients:
  128. f_init, g_ana = diff_and_grad(s_init)
  129. g_fd = np.zeros(Np)
  130. delta = 1e-5
  131. for j in range(0, Np):
  132.     ej = np.zeros(Np)
  133.     ej[j] = 1
  134.     fp = diff(s_init+delta*ej)
  135.     fm = diff(s_init-delta*ej)
  136.     g_fd[j] = 1 / (2 * delta) * (fp - fm)
  137. import matplotlib.pyplot as plt
  138. plt.figure()
  139. plt.plot(g_ana)
  140. plt.hold(True)
  141. plt.plot(g_fd)
  142. plt.legend(["analytical", "finite difference"])
  143. plt.hold(False)
  144. plt.show()
  145.  
  146. result = so.minimize(diff_and_grad, s_init, method='cg', jac=True)
  147. result2 = so.minimize(diff, s_init, method='cg')
Advertisement
Add Comment
Please, Sign In to add comment