- Timestamp:
- Jan 16, 2018 6:34:23 PM (7 years ago)
- Branches:
- master, core_shell_microgels, magnetic_model, ticket-1257-vesicle-product, ticket_1156, ticket_1265_superball, ticket_822_more_unit_tests
- Children:
- 0014c77
- Parents:
- c1bccff (diff), 8fb2a94 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent. - git-author:
- Paul Butler <butlerpd@…> (01/16/18 18:34:23)
- git-committer:
- GitHub <noreply@…> (01/16/18 18:34:23)
- Location:
- explore
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
explore/jitter.py
rff10479 r8cfb486 165 165 # constants in kernel_iq.c 166 166 'equirectangular', 'sinusoidal', 'guyou', 'azimuthal_equidistance', 167 'azimuthal_equal_area', 167 168 ] 168 169 def draw_mesh(ax, view, jitter, radius=1.2, n=11, dist='gaussian', -
explore/precision.py
ra1c5758 r2a7e20e 345 345 ) 346 346 add_function( 347 name="(1/2 +(1-cos(x))/x^2-sin(x)/x)/x",347 name="(1/2-sin(x)/x+(1-cos(x))/x^2)/x", 348 348 mp_function=lambda x: (0.5 - mp.sin(x)/x + (1-mp.cos(x))/(x*x))/x, 349 349 np_function=lambda x: (0.5 - np.sin(x)/x + (1-np.cos(x))/(x*x))/x, … … 609 609 names = ", ".join(sorted(ALL_FUNCTIONS)) 610 610 print("""\ 611 usage: precision.py [-f/a/r] [-x<range>] name...611 usage: precision.py [-f/a/r] [-x<range>] "name" ... 612 612 where 613 613 -f indicates that the function value should be plotted, … … 620 620 zoom indicates linear stepping in [1000, 1010] 621 621 neg indicates linear stepping in [-100.1, 100.1] 622 and name is "all [first]" or one of:622 and name is "all" or one of: 623 623 """+names) 624 624 sys.exit(1) -
explore/realspace.py
ra1c32c2 r8fb2a94 44 44 """ 45 45 return Rx(phi)*Ry(theta)*Rz(psi) 46 47 def apply_view(points, view): 48 """ 49 Apply the view transform (theta, phi, psi) to a set of points. 50 51 Points are stored in a 3 x n numpy array. 52 53 View angles are in degrees. 54 """ 55 theta, phi, psi = view 56 return np.asarray((Rz(phi)*Ry(theta)*Rz(psi))*np.matrix(points.T)).T 57 58 59 def invert_view(qx, qy, view): 60 """ 61 Return (qa, qb, qc) for the (theta, phi, psi) view angle at detector 62 pixel (qx, qy). 63 64 View angles are in degrees. 65 """ 66 theta, phi, psi = view 67 q = np.vstack((qx.flatten(), qy.flatten(), 0*qx.flatten())) 68 return np.asarray((Rz(-psi)*Ry(-theta)*Rz(-phi))*np.matrix(q)) 69 46 70 47 71 class Shape: … … 219 243 values = self.value.repeat(points.shape[0]) 220 244 return values, self._adjust(points) 245 246 NUMBA = False 247 if NUMBA: 248 from numba import njit 249 @njit("f8[:](f8[:],f8[:],f8[:],f8[:],f8[:],f8[:],f8[:])") 250 def _Iqxy(values, x, y, z, qa, qb, qc): 251 Iq = np.zeros_like(qa) 252 for j in range(len(Iq)): 253 total = 0. + 0j 254 for k in range(len(Iq)): 255 total += values[k]*np.exp(1j*(qa[j]*x[k] + qb[j]*y[k] + qc[j]*z[k])) 256 Iq[j] = abs(total)**2 257 return Iq 258 259 def calc_Iqxy(qx, qy, rho, points, volume=1.0, view=(0, 0, 0)): 260 qx, qy = np.broadcast_arrays(qx, qy) 261 qa, qb, qc = invert_view(qx, qy, view) 262 rho, volume = np.broadcast_arrays(rho, volume) 263 values = rho*volume 264 x, y, z = points.T 265 266 # I(q) = |sum V(r) rho(r) e^(1j q.r)|^2 / sum V(r) 267 if NUMBA: 268 Iq = _Iqxy(values, x, y, z, qa.flatten(), qb.flatten(), qc.flatten()) 269 else: 270 Iq = [abs(np.sum(values*np.exp(1j*(qa_k*x + qb_k*y + qc_k*z))))**2 271 for qa_k, qb_k, qc_k in zip(qa.flat, qb.flat, qc.flat)] 272 return np.asarray(Iq).reshape(qx.shape) / np.sum(volume) 221 273 222 274 def _calc_Pr_nonuniform(r, rho, points): … … 239 291 print("processing %d of %d"%(k, len(rho)-1)) 240 292 Pr = extended_Pr[1:-1] 241 return Pr / Pr.max() 242 243 def calc_Pr(r, rho, points): 244 # P(r) with uniform steps in r is 3x faster; check if we are uniform 245 # before continuing 246 if np.max(np.abs(np.diff(r) - r[0])) > r[0]*0.01: 247 return _calc_Pr_nonuniform(r, rho, points) 248 293 return Pr 294 295 def _calc_Pr_uniform(r, rho, points): 249 296 # Make Pr a little be bigger than necessary so that only distances 250 297 # min < d < max end up in Pr 251 n_max =len(r)298 dr, n_max = r[0], len(r) 252 299 extended_Pr = np.zeros(n_max+1, 'd') 253 300 t0 = time.clock() 254 301 t_next = t0 + 3 255 row_zero = np.zeros(len(rho), 'i')256 302 for k, rho_k in enumerate(rho[:-1]): 257 303 distances = sqrt(np.sum((points[k] - points[k+1:])**2, axis=1)) 258 304 weights = rho_k * rho[k+1:] 259 index = np.minimum(np.asarray(distances/ r[0], 'i'), n_max)305 index = np.minimum(np.asarray(distances/dr, 'i'), n_max) 260 306 # Note: indices may be duplicated, so "Pr[index] += w" will not work!! 261 307 extended_Pr += np.bincount(index, weights, n_max+1) … … 269 315 # we are only accumulating the upper triangular distances. 270 316 #Pr = Pr * 2 / len(rho)**2 271 return Pr / Pr.max()317 return Pr 272 318 273 319 # Can get an additional 2x by going to C. Cuda/OpenCL will allow even … … 291 337 } 292 338 """ 339 340 if NUMBA: 341 @njit("f8[:](f8[:], f8[:], f8[:,:])") 342 def _calc_Pr_uniform_jit(r, rho, points): 343 dr = r[0] 344 n_max = len(r) 345 Pr = np.zeros_like(r) 346 for j in range(len(rho) - 1): 347 x, y, z = points[j, 0], points[j, 1], points[j, 2] 348 for k in range(j+1, len(rho)): 349 distance = sqrt((x - points[k, 0])**2 350 + (y - points[k, 1])**2 351 + (z - points[k, 2])**2) 352 index = int(distance/dr) 353 if index < n_max: 354 Pr[index] += rho[j] * rho[k] 355 # Make Pr independent of sampling density. The factor of 2 comes because 356 # we are only accumulating the upper triangular distances. 357 #Pr = Pr * 2 / len(rho)**2 358 return Pr 359 360 361 def calc_Pr(r, rho, points): 362 # P(r) with uniform steps in r is 3x faster; check if we are uniform 363 # before continuing 364 if np.max(np.abs(np.diff(r) - r[0])) > r[0]*0.01: 365 Pr = _calc_Pr_nonuniform(r, rho, points) 366 else: 367 if NUMBA: 368 Pr = _calc_Pr_uniform_jit(r, rho, points) 369 else: 370 Pr = _calc_Pr_uniform(r, rho, points) 371 return Pr / Pr.max() 372 293 373 294 374 def j0(x): … … 333 413 plt.legend() 334 414 415 def plot_calc_2d(qx, qy, Iqxy, theory=None): 416 import matplotlib.pyplot as plt 417 qx, qy = bin_edges(qx), bin_edges(qy) 418 #qx, qy = np.meshgrid(qx, qy) 419 if theory is not None: 420 plt.subplot(121) 421 plt.pcolormesh(qx, qy, np.log10(Iqxy)) 422 plt.xlabel('qx (1/A)') 423 plt.ylabel('qy (1/A)') 424 if theory is not None: 425 plt.subplot(122) 426 plt.pcolormesh(qx, qy, np.log10(theory)) 427 plt.xlabel('qx (1/A)') 428 335 429 def plot_points(rho, points): 336 430 import mpl_toolkits.mplot3d … … 343 437 pass 344 438 n = len(points) 345 index = np.random.choice(n, size=1000) if n > 1000 else slice(None, None) 439 #print("len points", n) 440 index = np.random.choice(n, size=500) if n > 500 else slice(None, None) 346 441 ax.scatter(points[index, 0], points[index, 1], points[index, 2], c=rho[index]) 347 442 #low, high = points.min(axis=0), points.max(axis=0) 348 443 #ax.axis([low[0], high[0], low[1], high[1], low[2], high[2]]) 349 444 ax.autoscale(True) 445 446 def check_shape(shape, fn=None): 447 rho_solvent = 0 448 q = np.logspace(-3, 0, 200) 449 r = shape.r_bins(q, r_step=0.01) 450 sampling_density = 6*5000 / shape.volume() 451 rho, points = shape.sample(sampling_density) 452 t0 = time.time() 453 Pr = calc_Pr(r, rho-rho_solvent, points) 454 print("calc Pr time", time.time() - t0) 455 Iq = calc_Iq(q, r, Pr) 456 theory = (q, fn(q)) if fn is not None else None 457 458 import pylab 459 #plot_points(rho, points); pylab.figure() 460 plot_calc(r, Pr, q, Iq, theory=theory) 461 pylab.show() 462 463 def check_shape_2d(shape, fn=None, view=(0, 0, 0)): 464 rho_solvent = 0 465 nq, qmax = 100, 1.0 466 qx = np.linspace(0.0, qmax, nq) 467 qy = np.linspace(0.0, qmax, nq) 468 Qx, Qy = np.meshgrid(qx, qy) 469 sampling_density = 50000 / shape.volume() 470 #t0 = time.time() 471 rho, points = shape.sample(sampling_density) 472 #print("sample time", time.time() - t0) 473 t0 = time.time() 474 Iqxy = calc_Iqxy(Qx, Qy, rho, points, view=view) 475 print("calc time", time.time() - t0) 476 theory = fn(Qx, Qy) if fn is not None else None 477 Iqxy += 0.001 * Iqxy.max() 478 if theory is not None: 479 theory += 0.001 * theory.max() 480 481 import pylab 482 #plot_points(rho, points); pylab.figure() 483 plot_calc_2d(qx, qy, Iqxy, theory=theory) 484 pylab.show() 485 486 def sas_sinx_x(x): 487 with np.errstate(all='ignore'): 488 retvalue = sin(x)/x 489 retvalue[x == 0.] = 1. 490 return retvalue 350 491 351 492 def sas_2J1x_x(x): … … 373 514 Iq = Iq/Iq[0] 374 515 return Iq 516 517 def cylinder_Iqxy(qx, qy, radius, length, view=(0, 0, 0)): 518 qa, qb, qc = invert_view(qx, qy, view) 519 qab = np.sqrt(qa**2 + qb**2) 520 Fq = sas_2J1x_x(qab*radius) * j0(qc*length/2) 521 Iq = Fq**2 522 return Iq.reshape(qx.shape) 375 523 376 524 def sphere_Iq(q, radius): … … 415 563 return Iq/Iq[0] 416 564 417 def check_shape(shape, fn=None): 418 rho_solvent = 0 419 q = np.logspace(-3, 0, 200) 420 r = shape.r_bins(q, r_step=0.01) 421 sampling_density = 15000 / shape.volume() 422 rho, points = shape.sample(sampling_density) 423 Pr = calc_Pr(r, rho-rho_solvent, points) 424 Iq = calc_Iq(q, r, Pr) 425 theory = (q, fn(q)) if fn is not None else None 426 427 import pylab 428 #plot_points(rho, points); pylab.figure() 429 plot_calc(r, Pr, q, Iq, theory=theory) 430 pylab.show() 565 def csbox_Iqxy(qx, qy, a, b, c, da, db, dc, slda, sldb, sldc, sld_core, view=(0,0,0)): 566 qa, qb, qc = invert_view(qx, qy, view) 567 568 sld_solvent = 0 569 overlapping = False 570 dr0 = sld_core - sld_solvent 571 drA, drB, drC = slda-sld_solvent, sldb-sld_solvent, sldc-sld_solvent 572 tA, tB, tC = a + 2*da, b + 2*db, c + 2*dc 573 siA = a*sas_sinx_x(a*qa/2) 574 siB = b*sas_sinx_x(b*qb/2) 575 siC = c*sas_sinx_x(c*qc/2) 576 siAt = tA*sas_sinx_x(tA*qa/2) 577 siBt = tB*sas_sinx_x(tB*qb/2) 578 siCt = tC*sas_sinx_x(tC*qc/2) 579 Fq = (dr0*siA*siB*siC 580 + drA*(siAt-siA)*siB*siC 581 + drB*siA*(siBt-siB)*siC 582 + drC*siA*siB*(siCt-siC)) 583 Iq = Fq**2 584 return Iq.reshape(qx.shape) 431 585 432 586 def check_cylinder(radius=25, length=125, rho=2.): … … 434 588 fn = lambda q: cylinder_Iq(q, radius, length) 435 589 check_shape(shape, fn) 590 591 def check_cylinder_2d(radius=25, length=125, rho=2., view=(0, 0, 0)): 592 shape = EllipticalCylinder(radius, radius, length, rho) 593 fn = lambda qx, qy, view=view: cylinder_Iqxy(qx, qy, radius, length, view=view) 594 check_shape_2d(shape, fn, view=view) 595 596 def check_cylinder_2d_lattice(radius=25, length=125, rho=2., 597 view=(0, 0, 0)): 598 nx, dx = 1, 2*radius 599 ny, dy = 30, 2*radius 600 nz, dz = 30, length 601 dx, dy, dz = 2*dx, 2*dy, 2*dz 602 def center(*args): 603 sigma = 0.333 604 space = 2 605 return [(space*n+np.random.randn()*sigma)*x for n, x in args] 606 shapes = [EllipticalCylinder(radius, radius, length, rho, 607 #center=(ix*dx, iy*dy, iz*dz) 608 orientation=np.random.randn(3)*0, 609 center=center((ix, dx), (iy, dy), (iz, dz)) 610 ) 611 for ix in range(nx) 612 for iy in range(ny) 613 for iz in range(nz)] 614 shape = Composite(shapes) 615 fn = lambda qx, qy, view=view: cylinder_Iqxy(qx, qy, radius, length, view=view) 616 check_shape_2d(shape, fn, view=view) 436 617 437 618 def check_sphere(radius=125, rho=2): … … 449 630 side_c2 = copy(side_c).shift(0, 0, -c-dc) 450 631 shape = Composite((core, side_a, side_b, side_c, side_a2, side_b2, side_c2)) 451 fn = lambda q: csbox_Iq(q, a, b, c, da, db, dc, slda, sldb, sldc, sld_core) 452 check_shape(shape, fn) 632 def fn(q): 633 return csbox_Iq(q, a, b, c, da, db, dc, slda, sldb, sldc, sld_core) 634 #check_shape(shape, fn) 635 636 view = (20, 30, 40) 637 def fn_xy(qx, qy): 638 return csbox_Iqxy(qx, qy, a, b, c, da, db, dc, 639 slda, sldb, sldc, sld_core, view=view) 640 check_shape_2d(shape, fn_xy, view=view) 453 641 454 642 if __name__ == "__main__": 455 643 check_cylinder(radius=10, length=40) 644 #check_cylinder_2d(radius=10, length=40, view=(90,30,0)) 645 #check_cylinder_2d_lattice(radius=10, length=50, view=(90,30,0)) 456 646 #check_sphere() 457 647 #check_csbox()
Note: See TracChangeset
for help on using the changeset viewer.