Changeset 6ceca44 in sasmodels
- Timestamp:
- Jan 17, 2018 10:24:15 AM (7 years ago)
- Children:
- 5dd7cfb
- Parents:
- d5014e4 (diff), 1258e32 (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. - Files:
-
- 3 added
- 15 edited
Legend:
- Unmodified
- Added
- Removed
-
.gitignore
r67cc0ff r6ceca44 24 24 /example/Fit_*/ 25 25 /example/batch_fit.csv 26 # Note: changes to gauss20, gauss76 and gauss150 are still tracked since they 27 # are part of the repo and required by some models. 26 28 /sasmodels/models/lib/gauss*.c -
.travis.yml
rce8c388 r2d09df1 6 6 env: 7 7 - PY=2.7 8 - DEPLOY=True 8 9 - os: linux 9 10 env: … … 51 52 on: 52 53 branch: master 54 condition: $DEPLOY = True 53 55 notifications: 54 56 slack: -
appveyor.yml
rd810d96 r1258e32 67 67 - cmd: conda install --yes --quiet obvious-ci 68 68 - cmd: conda install --yes --quiet numpy toolchain scipy cython cffi 69 - cmd: conda install --yes --channel conda-forge pyopencl69 #- cmd: conda install --yes --channel conda-forge pyopencl 70 70 - cmd: pip install bumps unittest-xml-reporting tinycc 71 71 -
doc/developer/overview.rst
r3d40839 r2a7e20e 185 185 jitter applied before particle orientation. 186 186 187 When computing the orientation dispersity integral, the weights for 188 the individual points depends on the map projection used to translate jitter 189 angles into latitude/longitude. The choice of projection is set by 190 *sasmodels.generate.PROJECTION*, with the default *PROJECTION=1* for 191 equirectangular and *PROJECTION=2* for sinusoidal. The more complicated 192 Guyou and Postel projections are not implemented. See explore.jitter.draw_mesh 193 for details. 194 187 195 For numerical integration within form factors etc. sasmodels is mostly using 188 196 Gaussian quadrature with 20, 76 or 150 points depending on the model. It also … … 199 207 Useful testing routines include: 200 208 201 :mod:`asymint` a direct implementation of the surface integral for certain 202 models to get a more trusted value for the 1D integral using a 203 reimplementation of the 2D kernel in python and mpmath (which computes math 204 functions to arbitrary precision). It uses $\theta$ ranging from 0 to $\pi$ 205 and $\phi$ ranging from 0 to $2\pi$. It perhaps would benefit from including 206 the U-substitution for $\theta$. 207 208 :mod:`check1d` uses sasmodels 1D integration and compares that with a 209 The *sascomp* utility is used to view and compare models with different 210 parameters and calculation engines. The usual case is to simply plot a 211 model that you are developing:: 212 213 python sascomp path/to/model.py 214 215 Once the obvious problems are addressed, check the numerical precision 216 across a variety of randomly generated inputs:: 217 218 python sascomp -engine=single,double path/to/model.py -sets=10 219 220 You can compare different parameter values for the same or different models. 221 For example when looking along the long axis of a cylinder ($\theta=0$), 222 dispersity in $\theta$ should be equivalent to dispersity in $\phi$ 223 when $\phi=90$:: 224 225 python sascomp -2d cylinder theta=0 phi=0,90 theta_pd_type=rectangle \\ 226 phi_pd_type=rectangle phi_pd=10,1 theta_pd=1,10 length=500 radius=10 227 228 It turns out that they are not because the equirectangular map projection 229 weights the points by $\cos(\theta)$ so $\Delta\theta$ is not identical 230 to $\Delta\phi$. Setting *PROJECTION=2* in :mod:`sasmodels.generate` helps 231 somewhat. Postel would help even more in this case, though leading 232 to distortions elsewhere. See :mod:`sasmodels.compare` for many more details. 233 234 *sascomp -ngauss=n* allows you to set the number of quadrature points used 235 for the 1D integration for any model. For example, a carbon nanotube with 236 length 10 $\mu$\ m and radius 1 nm is not computed correctly at high $q$:: 237 238 python sascomp cylinder length=100000 radius=10 -ngauss=76,500 -double -highq 239 240 Note: ticket 702 gives some forms for long rods and thin disks that may 241 be used in place of the integration, depending on $q$, radius and length; if 242 the cylinder model is updated with these corrections then above call will show 243 no difference. 244 245 *explore/check1d.py* uses sasmodels 1D integration and compares that with a 209 246 rectangle distribution in $\theta$ and $\phi$, with $\theta$ limits set to 210 247 $\pm 90/\sqrt(3)$ and $\phi$ limits set to $\pm 180/\sqrt(3)$ [The rectangle … … 214 251 similar reasoning.] This should rotate the sample through the entire 215 252 $\theta$-$\phi$ surface according to the pattern that you see in jitter.py when 216 you modify it to use 'rectangle' rather than 'gaussian' for its distribution217 without changing the viewing angle. In order to match the 1-D pattern for 218 an arbitraryviewing angle on triaxial shapes, we need to integrate253 you use 'rectangle' rather than 'gaussian' for its distribution without 254 changing the viewing angle. In order to match the 1-D pattern for an arbitrary 255 viewing angle on triaxial shapes, we need to integrate 219 256 over $\theta$, $\phi$ and $\Psi$. 220 257 221 When computing the dispersity integral, weights are scaled by 222 $|\cos(\delta \theta)|$ to account for the points in $\phi$ getting closer 223 together as $\delta \theta$ increases. 224 [This will probably change so that instead of adjusting the weights, we will 225 adjust $\delta\theta$-$\delta\phi$ mesh so that the point density in 226 $\delta\phi$ is lower at larger $\delta\theta$. The flag USE_SCALED_PHI in 227 *kernel_iq.c* selects an alternative algorithm.] 228 229 The integrated dispersion is computed at a set of $(qx, qy)$ points $(q 230 \cos(\alpha), q \sin(\alpha))$ at some angle $\alpha$ (currently angle=0) for 231 each $q$ used in the 1-D integration. The individual $q$ points should be 232 equivalent to asymint rect-n when the viewing angle is set to 233 $(\theta,\phi,\Psi) = (90, 0, 0)$. Such tests can help to validate that 2d 234 models are consistent with 1d models. 235 236 :mod:`sascomp -sphere=n` uses the same rectangular distribution as check1d to 237 compute the pattern of the $q_x$-$q_y$ grid. 238 239 The :mod:`sascomp` utility can be used for 2d as well as 1d calculations to 240 compare results for two sets of parameters or processor types, for example 241 these two oriented cylinders here should be equivalent. 242 243 :mod:`\./sascomp -2d cylinder theta=0 phi=0,90 theta_pd_type=rectangle phi_pd_type=rectangle phi_pd=10,1 theta_pd=1,10 length=500 radius=10` 244 258 *sascomp -sphere=n* uses the same rectangular distribution as check1d to 259 compute the pattern of the $q_x$-$q_y$ grid. This ought to produce a 260 spherically symmetric pattern. 261 262 *explore/precision.py* investigates the accuracy of individual functions 263 on the different execution platforms. This includes the basic special 264 functions as well as more complex expressions used in scattering. In many 265 cases the OpenCL function in sasmodels will use a polynomial approximation 266 over part of the range to improve accuracy, as shown in:: 267 268 python explore/precision.py 3j1/x 269 270 *explore/realspace.py* allows you to set up a Monte Carlo simulation of your 271 model by sampling random points within and computing the 1D and 2D scattering 272 patterns. This was used to check the core shell parallelepiped example. This 273 is similar to the general sas calculator in sasview, though it uses different 274 code. 275 276 *explore/jitter.py* is for exploring different options for handling 277 orientation and orientation dispersity. It uses *explore/guyou.py* to 278 generate the Guyou projection. 279 280 *explore/asymint.py* is a direct implementation of the 1D integration for 281 a number of different models. It calculates the integral for a particular 282 $q$ using several different integration schemes, including mpmath with 100 283 bits of precision (33 digits), so you can use it to check the target values 284 for the 1D model tests. This is not a general purpose tool; you will need to 285 edit the file to change the model parameters. It does not currently 286 apply the $u=cos(\theta)$ substitution that many models are using 287 internally so the 76-point gaussian quadrature may not match the value 288 produced by the eqivalent model from sasmodels. 289 290 *explore/symint.py* is for rotationally symmetric models (just cylinder for 291 now), so it can compute an entire curve rather than a single $q$ point. It 292 includes code to compare the long cylinder approximation to cylinder. 293 294 *explore/rpa.py* is for checking different implementations of the RPA model 295 against calculations for specific blends. This is a work in (suspended) 296 progress. 297 298 There are a few modules left over in *explore* that can probably be removed. 299 *angular_pd.py* was an early version of *jitter.py*. *sc.py* and *sc.c* 300 was used to explore different calculations for paracrystal models; it has 301 been absorbed into *asymint.py*. *transform_angles.py* translates orientation 302 parameters from the SasView 3.x definition to sasmodels. 303 304 *explore/angles.py* generates code for the view and jitter transformations. 305 Keep this around since it may be needed if we add new projections. 245 306 246 307 Testing -
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() -
sasmodels/compare.py
ra261a83 r2a7e20e 92 92 -accuracy=Low accuracy of the resolution calculation Low, Mid, High, Xhigh 93 93 -neval=1 sets the number of evals for more accurate timing 94 -ngauss=0 overrides the number of points in the 1-D gaussian quadrature 94 95 95 96 === precision options === -
sasmodels/kernel_iq.c
r108e70e r924a119 174 174 static double 175 175 qac_apply( 176 QACRotation rotation,176 QACRotation *rotation, 177 177 double qx, double qy, 178 178 double *qa_out, double *qc_out) 179 179 { 180 const double dqc = rotation .R31*qx + rotation.R32*qy;180 const double dqc = rotation->R31*qx + rotation->R32*qy; 181 181 // Indirect calculation of qab, from qab^2 = |q|^2 - qc^2 182 182 const double dqa = sqrt(-dqc*dqc + qx*qx + qy*qy); … … 247 247 static double 248 248 qabc_apply( 249 QABCRotation rotation,249 QABCRotation *rotation, 250 250 double qx, double qy, 251 251 double *qa_out, double *qb_out, double *qc_out) 252 252 { 253 *qa_out = rotation .R11*qx + rotation.R12*qy;254 *qb_out = rotation .R21*qx + rotation.R22*qy;255 *qc_out = rotation .R31*qx + rotation.R32*qy;253 *qa_out = rotation->R11*qx + rotation->R12*qy; 254 *qb_out = rotation->R21*qx + rotation->R22*qy; 255 *qc_out = rotation->R31*qx + rotation->R32*qy; 256 256 } 257 257 … … 454 454 // theta, phi, dtheta, dphi are defined below in projection to avoid repeated code. 455 455 #define BUILD_ROTATION() qac_rotation(&rotation, theta, phi, dtheta, dphi); 456 #define APPLY_ROTATION() qac_apply( rotation, qx, qy, &qa, &qc)456 #define APPLY_ROTATION() qac_apply(&rotation, qx, qy, &qa, &qc) 457 457 #define CALL_KERNEL() CALL_IQ_AC(qa, qc, local_values.table) 458 458 … … 468 468 local_values.table.psi = 0.; 469 469 #define BUILD_ROTATION() qabc_rotation(&rotation, theta, phi, psi, dtheta, dphi, local_values.table.psi) 470 #define APPLY_ROTATION() qabc_apply( rotation, qx, qy, &qa, &qb, &qc)470 #define APPLY_ROTATION() qabc_apply(&rotation, qx, qy, &qa, &qb, &qc) 471 471 #define CALL_KERNEL() CALL_IQ_ABC(qa, qb, qc, local_values.table) 472 472 #elif defined(CALL_IQ_XY) … … 479 479 #endif 480 480 481 // D oing jitter projection code outside the previous if block so that we don't482 // need to repeat the identical logic in the IQ_AC and IQ_ABC branches. This483 // will become more important if we implement more projections, or more484 // complicated projections.485 #if defined(CALL_IQ) || defined(CALL_IQ_A) 481 // Define APPLY_PROJECTION depending on model symmetries. We do this outside 482 // the previous if block so that we don't need to repeat the identical 483 // logic in the IQ_AC and IQ_ABC branches. This will become more important 484 // if we implement more projections, or more complicated projections. 485 #if defined(CALL_IQ) || defined(CALL_IQ_A) // no orientation 486 486 #define APPLY_PROJECTION() const double weight=weight0 487 #elif defined(CALL_IQ_XY) 487 #elif defined(CALL_IQ_XY) // pass orientation to the model 488 488 // CRUFT: support oriented model which define Iqxy rather than Iqac or Iqabc 489 489 // Need to plug the values for the orientation angles back into parameter … … 515 515 #define APPLY_PROJECTION() const double weight=weight0 516 516 #endif 517 #else // !spherosymmetric projection517 #else // apply jitter and view before calling the model 518 518 // Grab the "view" angles (theta, phi, psi) from the initial parameter table. 519 519 const double theta = values[details->theta_par+2]; … … 526 526 // we go through the mesh. 527 527 double dtheta, dphi, weight; 528 #if PROJECTION == 1 528 #if PROJECTION == 1 // equirectangular 529 529 #define APPLY_PROJECTION() do { \ 530 530 dtheta = local_values.table.theta; \ … … 532 532 weight = fabs(cos(dtheta*M_PI_180)) * weight0; \ 533 533 } while (0) 534 #elif PROJECTION == 2 534 #elif PROJECTION == 2 // sinusoidal 535 535 #define APPLY_PROJECTION() do { \ 536 536 dtheta = local_values.table.theta; \ … … 542 542 } while (0) 543 543 #endif 544 #endif // !spherosymmetric projection544 #endif // done defining APPLY_PROJECTION 545 545 546 546 // ** define looping macros ** -
sasmodels/models/core_shell_parallelepiped.c
r108e70e re077231 43 43 // Code converted from functions CSPPKernel and CSParallelepiped in libCylinder.c 44 44 // Did not understand the code completely, it should be rechecked (Miguel Gonzalez) 45 // Code is rewritten, the code is compliant with Diva Singhs thesis now (Dirk Honecker)46 // Code rewritten (PAK)45 // Code is rewritten, the code is compliant with Diva Singh's thesis now (Dirk Honecker) 46 // Code rewritten; cross checked against hollow rectangular prism and realspace (PAK) 47 47 48 48 const double half_q = 0.5*q; … … 121 121 const double drC = crim_sld-solvent_sld; 122 122 123 // The definitions of ta, tb, tc are not the same as in the 1D case because there is no124 // the scaling by B.125 123 const double tA = length_a + 2.0*thick_rim_a; 126 124 const double tB = length_b + 2.0*thick_rim_b; -
sasmodels/models/core_shell_parallelepiped.py
r10ee838 r97be877 136 136 * **Author:** NIST IGOR/DANSE **Date:** pre 2010 137 137 * **Converted to sasmodels by:** Miguel Gonzales **Date:** February 26, 2016 138 * **Last Modified by:** Wojciech Potrzebowski **Date:** January 11, 2017 139 * **Currently Under review by:** Paul Butler 138 * **Last Modified by:** Paul Kienzle **Date:** October 17, 2017 139 * Cross-checked against hollow rectangular prism and rectangular prism for 140 equal thickness overlapping sides, and by Monte Carlo sampling of points 141 within the shape for non-uniform, non-overlapping sides. 140 142 """ 141 143 -
sasmodels/models/lib/gauss150.c
r74768cb r99b84ec 1 /* 2 * GaussWeights.c 3 * SANSAnalysis 4 * 5 * Created by Andrew Jackson on 4/23/07. 6 * Copyright 2007 __MyCompanyName__. All rights reserved. 7 * 8 */ 1 // Created by Andrew Jackson on 4/23/07 2 9 3 #ifdef GAUSS_N 10 4 # undef GAUSS_N … … 16 10 #define GAUSS_W Gauss150Wt 17 11 18 // Note: using array size 152 so that it is a multiple of 419 12 20 // Gaussians 13 // Note: using array size 152 rather than 150 so that it is a multiple of 4. 14 // Some OpenCL devices prefer that vectors start and end on nice boundaries. 21 15 constant double Gauss150Z[152]={ 22 16 -0.9998723404457334, … … 170 164 0.9993274305065947, 171 165 0.9998723404457334, 172 0., 173 0. 166 0., // zero padding is ignored 167 0. // zero padding is ignored 174 168 }; 175 169 … … 325 319 0.0007624720924706, 326 320 0.0003276086705538, 327 0., 328 0. 321 0., // zero padding is ignored 322 0. // zero padding is ignored 329 323 }; -
sasmodels/models/lib/gauss20.c
r74768cb r99b84ec 1 /* 2 * GaussWeights.c 3 * SANSAnalysis 4 * 5 * Created by Andrew Jackson on 4/23/07. 6 * Copyright 2007 __MyCompanyName__. All rights reserved. 7 * 8 */ 1 // Created by Andrew Jackson on 4/23/07 2 9 3 #ifdef GAUSS_N 10 4 # undef GAUSS_N -
sasmodels/models/lib/gauss76.c
r74768cb r99b84ec 1 /* 2 * GaussWeights.c 3 * SANSAnalysis 4 * 5 * Created by Andrew Jackson on 4/23/07. 6 * Copyright 2007 __MyCompanyName__. All rights reserved. 7 * 8 */ 1 // Created by Andrew Jackson on 4/23/07 2 9 3 #ifdef GAUSS_N 10 4 # undef GAUSS_N -
sasmodels/kerneldll.py
r2d81cfe r1ddb794 185 185 subprocess.check_output(command, shell=shell, stderr=subprocess.STDOUT) 186 186 except subprocess.CalledProcessError as exc: 187 raise RuntimeError("compile failed.\n%s\n%s"%(command_str, exc.output)) 187 raise RuntimeError("compile failed.\n%s\n%s" 188 % (command_str, exc.output.decode())) 188 189 if not os.path.exists(output): 189 190 raise RuntimeError("compile failed. File is in %r"%source) -
sasmodels/modelinfo.py
r108e70e r5ab99b7 12 12 from os.path import abspath, basename, splitext 13 13 import inspect 14 import logging 14 15 15 16 import numpy as np # type: ignore 17 18 from . import autoc 16 19 17 20 # Optional typing … … 32 35 TestCondition = Tuple[ParameterSetUser, TestInput, TestValue] 33 36 # pylint: enable=unused-import 37 38 logger = logging.getLogger(__name__) 34 39 35 40 # If MAX_PD changes, need to change the loop macros in kernel_iq.c … … 804 809 info.sesans = getattr(kernel_module, 'sesans', None) # type: ignore 805 810 # Default single and opencl to True for C models. Python models have callable Iq. 806 info.opencl = getattr(kernel_module, 'opencl', not callable(info.Iq))807 info.single = getattr(kernel_module, 'single', not callable(info.Iq))808 811 info.random = getattr(kernel_module, 'random', None) 809 812 … … 814 817 info.hidden = getattr(kernel_module, 'hidden', None) # type: ignore 815 818 819 info.lineno = {} 820 _find_source_lines(info, kernel_module) 821 if getattr(kernel_module, 'py2c', False): 822 try: 823 autoc.convert(info, kernel_module) 824 except Exception as exc: 825 logger.warn(str(exc) + " while converting %s from C to python"%name) 826 827 # Needs to come after autoc.convert since the Iq symbol may have been 828 # converted from python to C 829 info.opencl = getattr(kernel_module, 'opencl', not callable(info.Iq)) 830 info.single = getattr(kernel_module, 'single', not callable(info.Iq)) 831 816 832 if callable(info.Iq) and parameters.has_2d: 817 833 raise ValueError("oriented python models not supported") 818 819 info.lineno = {}820 _find_source_lines(info, kernel_module)821 834 822 835 return info
Note: See TracChangeset
for help on using the changeset viewer.