source: sasmodels/sasmodels/resolution.py @ 63b32bb

core_shell_microgelscostrafo411magnetic_modelrelease_v0.94release_v0.95ticket-1257-vesicle-productticket_1156ticket_1265_superballticket_822_more_unit_tests
Last change on this file since 63b32bb was 63b32bb, checked in by Paul Kienzle <pkienzle@…>, 9 years ago

lint cleaning

  • Property mode set to 100644
File size: 2.4 KB
Line 
1from scipy.special import erf
2from numpy import sqrt
3import numpy as np
4
5SLIT_SMEAR_POINTS = 500
6
7def pinhole_resolution(q_calc, q, q_width):
8    """
9    Compute the convolution matrix *W* for pinhole resolution 1-D data.
10
11    Each row *W[i]* determines the normalized weight that the corresponding
12    points *q_calc* contribute to the resolution smeared point *q[i]*.  Given
13    *W*, the resolution smearing can be computed using *dot(W,q)*.
14
15    *q_calc* must be increasing.
16    """
17    edges = bin_edges(q_calc)
18    edges[edges<0.] = 0. # clip edges below zero
19    G = erf( (edges[:,None] - q[None,:]) / (sqrt(2.0)*q_width)[None,:] )
20    weights = G[1:] - G[:-1]
21    weights /= sum(weights, axis=1)
22    return weights
23
24def slit_resolution(q_calc, q, qx_width, qy_width):
25    edges = bin_edges(q_calc) # Note: requires q > 0
26    edges[edges<0.] = 0.0 # clip edges below zero
27    qy_min, qy_max = 0.0, edges[-1]
28
29    weights = np.zeros((len(q),len(q_calc)),'d')
30    # Loop for width (height is analytical).
31    # Condition: height >>> width, otherwise, below is not accurate enough.
32    # Smear weight numerical iteration for width>0 when height>0.
33    # When width = 0, the numerical iteration will be skipped.
34    # The resolution calculation for the height is done by direct integration,
35    # assuming the I(q'=sqrt(q_j^2-(q+shift_w)^2)) is constant within
36    # a q' bin, [q_high, q_low].
37    # In general, this weight numerical iteration for width>0 might be a rough
38    # approximation, but it must be good enough when height >>> width.
39    E_sq = edges**2[:,None]
40    y_points = SLIT_SMEAR_POINTS if np.any(qy_width>0) else 1
41    qy_step = 0 if y_points == 1 else qy_width/(y_points-1)
42    for k in range(-y_points+1,y_points):
43        qy = np.clip(q + qy_step*k, qy_min, qy_max)
44        qx_low = qy
45        qx_high = sqrt(qx_low**2 + qx_width**2)
46        in_x = (q_calc[:,None]>=qx_low[None,:])*(q_calc[:,None]<=qx_high[None,:])
47        qy_sq = qy**2[None,:]
48        weights += (sqrt(E_sq[1:]-qy_sq) - sqrt(E_sq[:-1]-qy_sq))*in_x
49    weights /= sum(weights, axis=1)
50    return weights
51
52def bin_edges(x):
53    if len(x) < 2 or (np.diff(x)<0).any():
54        raise ValueError("Expected bins to be an increasing set")
55    edges = np.hstack([
56        x[0]  - 0.5*(x[1]  - x[0]),  # first point minus half first interval
57        0.5*(x[1:] + x[:-1]),        # mid points of all central intervals
58        x[-1] + 0.5*(x[-1] - x[-2]), # last point plus half last interval
59        ])
60    return edges
Note: See TracBrowser for help on using the repository browser.