File: two_power_law.py

package info (click to toggle)
mccode 3.5.19%2Bds5-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,113,256 kB
  • sloc: ansic: 40,697; python: 25,137; yacc: 8,438; sh: 5,405; javascript: 4,596; lex: 1,632; cpp: 742; perl: 296; lisp: 273; makefile: 226; fortran: 132
file content (146 lines) | stat: -rw-r--r-- 4,410 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
r"""
Definition
----------

The scattering intensity $I(q)$ is calculated as

.. math::

    I(q) = \begin{cases}
    A q^{-m1} + \text{background} & q <= q_c \\
    C q^{-m2} + \text{background} & q > q_c
    \end{cases}

where $q_c$ = the location of the crossover from one slope to the other,
$A$ = the scaling coefficient that sets the overall intensity of the lower Q
power law region, $m1$ = power law exponent at low Q, and $m2$ = power law
exponent at high Q.  The scaling of the second power law region (coefficient C)
is then automatically scaled to match the first by following formula:

.. math::
    C = \frac{A q_c^{m2}}{q_c^{m1}}

.. note::
    Be sure to enter the power law exponents as positive values!

For 2D data the scattering intensity is calculated in the same way as 1D,
where the $q$ vector is defined as

.. math::

    q = \sqrt{q_x^2 + q_y^2}


References
----------

None.

Authorship and Verification
----------------------------

* **Author:** NIST IGOR/DANSE **Date:** pre 2010
* **Last Modified by:** Wojciech Wpotrzebowski **Date:** February 18, 2016
* **Last Reviewed by:** Paul Butler **Date:** March 21, 2016
"""

import numpy as np
from numpy import inf, power, empty, errstate

name = "two_power_law"
title = "This model calculates an empirical functional form for SAS data \
characterized by two power laws."
description = """
            I(q) = coef_A*pow(qval,-1.0*power1) + background for q<=q_c
            =C*pow(qval,-1.0*power2) + background for q>q_c
            where C=coef_A*pow(q_c,-1.0*power1)/pow(q_c,-1.0*power2).

            coef_A = scaling coefficient
            q_c = crossover location [1/A]
            power_1 (=m1) = power law exponent at low Q
            power_2 (=m2) = power law exponent at high Q
            background = Incoherent background [1/cm]
        """
category = "shape-independent"

# pylint: disable=bad-whitespace, line-too-long
#   ["name", "units", default, [lower, upper], "type", "description"],
parameters = [
    ["coefficent_1", "",       1.0, [-inf, inf], "", "coefficent A in low Q region"],
    ["crossover",    "1/Ang",  0.04,[0, inf],    "", "crossover location"],
    ["power_1",      "",       1.0, [0, inf],    "", "power law exponent at low Q"],
    ["power_2",      "",       4.0, [0, inf],    "", "power law exponent at high Q"],
    ]
# pylint: enable=bad-whitespace, line-too-long


def Iq(q,
       coefficent_1=1.0,
       crossover=0.04,
       power_1=1.0,
       power_2=4.0,
      ):
    """
    :param q:                   Input q-value (float or [float, float])
    :param coefficent_1:        Scaling coefficent at low Q
    :param crossover:           Crossover location
    :param power_1:             Exponent of power law function at low Q
    :param power_2:             Exponent of power law function at high Q
    :return:                    Calculated intensity
    """
    result = empty(q.shape, 'd')
    index = (q <= crossover)
    with errstate(divide='ignore'):
        coefficent_2 = coefficent_1 * power(crossover, power_2 - power_1)
        result[index] = coefficent_1 * power(q[index], -power_1)
        result[~index] = coefficent_2 * power(q[~index], -power_2)
    return result

Iq.vectorized = True  # Iq accepts an array of q values

def random():
    """Return a random parameter set for the model."""
    coefficient_1 = 1
    crossover = 10**np.random.uniform(-3, -1)
    power_1 = np.random.uniform(1, 6)
    power_2 = np.random.uniform(1, 6)
    pars = dict(
        scale=1, #background=0,
        coefficient_1=coefficient_1,
        crossover=crossover,
        power_1=power_1,
        power_2=power_2,
    )
    return pars

tests = [
    # Accuracy tests based on content in test/utest_extra_models.py
    [{'coefficent_1':     1.0,
      'crossover':  0.04,
      'power_1':    1.0,
      'power_2':    4.0,
      'background': 0.0,
     }, 0.001, 1000],

    [{'coefficent_1':     1.0,
      'crossover':  0.04,
      'power_1':    1.0,
      'power_2':    4.0,
      'background': 0.0,
     }, 0.150141, 0.125945],

    [{'coefficent_1':    1.0,
      'crossover':  0.04,
      'power_1':    1.0,
      'power_2':    4.0,
      'background': 0.0,
     }, 0.442528, 0.00166884],

    [{'coefficent_1':    1.0,
      'crossover':  0.04,
      'power_1':    1.0,
      'power_2':    4.0,
      'background': 0.0,
     }, (0.442528, 0.00166884), 0.00166884],

]