Changes in / [72e41a0:92d330fd] in sasmodels
- Files:
-
- 2 deleted
- 50 edited
Legend:
- Unmodified
- Added
- Removed
-
.gitignore
re9ed2de r8a5f021 22 22 /example/Fit_*/ 23 23 /example/batch_fit.csv 24 # Note: changes to gauss20, gauss76 and gauss150 are still tracked since they25 # are part of the repo and required by some models.26 /sasmodels/models/lib/gauss*.c -
.travis.yml
r2d09df1 rce8c388 6 6 env: 7 7 - PY=2.7 8 - DEPLOY=True9 8 - os: linux 10 9 env: … … 52 51 on: 53 52 branch: master 54 condition: $DEPLOY = True55 53 notifications: 56 54 slack: -
appveyor.yml
r1258e32 rd810d96 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
r2a7e20e r3d40839 185 185 jitter applied before particle orientation. 186 186 187 When computing the orientation dispersity integral, the weights for188 the individual points depends on the map projection used to translate jitter189 angles into latitude/longitude. The choice of projection is set by190 *sasmodels.generate.PROJECTION*, with the default *PROJECTION=1* for191 equirectangular and *PROJECTION=2* for sinusoidal. The more complicated192 Guyou and Postel projections are not implemented. See explore.jitter.draw_mesh193 for details.194 195 187 For numerical integration within form factors etc. sasmodels is mostly using 196 188 Gaussian quadrature with 20, 76 or 150 points depending on the model. It also … … 207 199 Useful testing routines include: 208 200 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 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 246 209 rectangle distribution in $\theta$ and $\phi$, with $\theta$ limits set to 247 210 $\pm 90/\sqrt(3)$ and $\phi$ limits set to $\pm 180/\sqrt(3)$ [The rectangle … … 251 214 similar reasoning.] This should rotate the sample through the entire 252 215 $\theta$-$\phi$ surface according to the pattern that you see in jitter.py when 253 you use 'rectangle' rather than 'gaussian' for its distribution without254 changing the viewing angle. In order to match the 1-D pattern for an arbitrary 255 viewing angle on triaxial shapes, we need to integrate216 you modify it to use 'rectangle' rather than 'gaussian' for its distribution 217 without changing the viewing angle. In order to match the 1-D pattern for 218 an arbitrary viewing angle on triaxial shapes, we need to integrate 256 219 over $\theta$, $\phi$ and $\Psi$. 257 220 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. 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 306 245 307 246 Testing -
doc/guide/orientation/orientation.rst
r5fb0634 r82592da 4 4 ================== 5 5 6 With two dimensional small angle diffraction data sasmodelswill calculate6 With two dimensional small angle diffraction data SasView will calculate 7 7 scattering from oriented particles, applicable for example to shear flow 8 8 or orientation in a magnetic field. 9 9 10 10 In general we first need to define the reference orientation 11 of the particle's $a$-$b$-$c$ axes with respect to the incoming 12 neutron or X-ray beam. This is done using three angles: $\theta$ and $\phi$ 13 define the orientation of the $c$-axis of the particle, and angle $\Psi$ is 14 defined as the orientation of the major axis of the particle cross section 15 with respect to its starting position along the beam direction (or 16 equivalently, as rotation about the $c$ axis). There is an unavoidable 17 ambiguity when $c$ is aligned with $z$ in that $\phi$ and $\Psi$ both 18 serve to rotate the particle about $c$, but this symmetry is destroyed 19 when $\theta$ is not a multiple of 180. 20 21 The figures below are for an elliptical cross section cylinder, but may 22 be applied analogously to other shapes of particle. 11 of the particles with respect to the incoming neutron or X-ray beam. This 12 is done using three angles: $\theta$ and $\phi$ define the orientation of 13 the axis of the particle, angle $\Psi$ is defined as the orientation of 14 the major axis of the particle cross section with respect to its starting 15 position along the beam direction. The figures below are for an elliptical 16 cross section cylinder, but may be applied analogously to other shapes of 17 particle. 23 18 24 19 .. note:: … … 34 29 35 30 Definition of angles for oriented elliptical cylinder, where axis_ratio 36 b/a is shown >1 .Note that rotation $\theta$, initially in the $x$-$z$31 b/a is shown >1, Note that rotation $\theta$, initially in the $x$-$z$ 37 32 plane, is carried out first, then rotation $\phi$ about the $z$-axis, 38 33 finally rotation $\Psi$ is around the axis of the cylinder. The neutron 39 or X-ray beam is along the $ -z$ axis.34 or X-ray beam is along the $z$ axis. 40 35 41 36 .. figure:: … … 45 40 with $\Psi$ = 0. 46 41 47 Having established the mean direction of the particle (the view) we can then 48 apply angular orientation distributions (jitter). This is done by a numerical 49 integration over a range of angles in a similar way to particle size 50 dispersity. The orientation dispersity is defined with respect to the 51 $a$-$b$-$c$ axes of the particle, with roll angle $\Psi$ about the $c$-axis, 52 yaw angle $\theta$ about the $b$-axis and pitch angle $\phi$ about the 53 $a$-axis. 54 55 More formally, starting with axes $a$-$b$-$c$ of the particle aligned 56 with axes $x$-$y$-$z$ of the laboratory frame, the orientation dispersity 57 is applied first, using the 58 `Tait-Bryan <https://en.wikipedia.org/wiki/Euler_angles#Conventions_2>`_ 59 $x$-$y'$-$z''$ convention with angles $\Delta\phi$-$\Delta\theta$-$\Delta\Psi$. 60 The reference orientation then follows, using the 61 `Euler angles <https://en.wikipedia.org/wiki/Euler_angles#Conventions>`_ 62 $z$-$y'$-$z''$ with angles $\phi$-$\theta$-$\Psi$. This is implemented 63 using rotation matrices as 64 65 .. math:: 66 67 R = R_z(\phi)\, R_y(\theta)\, R_z(\Psi)\, 68 R_x(\Delta\phi)\, R_y(\Delta\theta)\, R_z(\Delta\Psi) 69 70 To transform detector $(q_x, q_y)$ values into $(q_a, q_b, q_c)$ for the 71 shape in its canonical orientation, use 72 73 .. math:: 74 75 [q_a, q_b, q_c]^T = R^{-1} \, [q_x, q_y, 0]^T 76 77 78 The inverse rotation is easily calculated by rotating the opposite directions 79 in the reverse order, so 80 81 .. math:: 82 83 R^{-1} = R_z(-\Delta\Psi)\, R_y(-\Delta\theta)\, R_x(-\Delta\phi)\, 84 R_z(-\Psi)\, R_y(-\theta)\, R_z(-\phi) 85 42 Having established the mean direction of the particle we can then apply 43 angular orientation distributions. This is done by a numerical integration 44 over a range of angles in a similar way to particle size dispersity. 45 In the current version of sasview the orientational dispersity is defined 46 with respect to the axes of the particle. 86 47 87 48 The $\theta$ and $\phi$ orientation parameters for the cylinder only appear 88 when fitting 2d data. On introducing "Orientational Distribution" in the89 angles, "distribution of theta" and "distribution of phi" parameters will49 when fitting 2d data. On introducing "Orientational Distribution" in 50 the angles, "distribution of theta" and "distribution of phi" parameters will 90 51 appear. These are actually rotations about the axes $\delta_1$ and $\delta_2$ 91 of the cylinder, which correspond to the $b$ and $a$ axes of the cylinder 92 cross section. (When $\theta = \phi = 0$ these are parallel to the $Y$ and 93 $X$ axes of the instrument.) The third orientation distribution, in $\Psi$, 94 is about the $c$ axis of the particle. Some experimentation may be required 95 to understand the 2d patterns fully. A number of different shapes of 96 distribution are available, as described for size dispersity, see 97 :ref:`polydispersityhelp`. 52 of the cylinder, the $b$ and $a$ axes of the cylinder cross section. (When 53 $\theta = \phi = 0$ these are parallel to the $Y$ and $X$ axes of the 54 instrument.) The third orientation distribution, in $\Psi$, is about the $c$ 55 axis of the particle. Some experimentation may be required to understand the 56 2d patterns fully. A number of different shapes of distribution are 57 available, as described for polydispersity, see :ref:`polydispersityhelp` . 98 58 99 Given that the angular dispersion distribution is defined in cartesian space, 100 over a cube defined by 101 102 .. math:: 103 104 [-\Delta \theta, \Delta \theta] \times 105 [-\Delta \phi, \Delta \phi] \times 106 [-\Delta \Psi, \Delta \Psi] 107 108 but the orientation is defined over a sphere, we are left with a 109 `map projection <https://en.wikipedia.org/wiki/List_of_map_projections>`_ 110 problem, with different tradeoffs depending on how values in $\Delta\theta$ 111 and $\Delta\phi$ are translated into latitude/longitude on the sphere. 112 113 Sasmodels is using the 114 `equirectangular projection <https://en.wikipedia.org/wiki/Equirectangular_projection>`_. 115 In this projection, square patches in angular dispersity become wedge-shaped 116 patches on the sphere. To correct for the changing point density, there is a 117 scale factor of $\sin(\Delta\theta)$ that applies to each point in the 118 integral. This is not enough, though. Consider a shape which is tumbling 119 freely around the $b$ axis, with $\Delta\theta$ uniform in $[-180, 180]$. At 120 $\pm 90$, all points in $\Delta\phi$ map to the pole, so the jitter will have 121 a distinct angular preference. If the spin axis is along the beam (which 122 will be the case for $\theta=90$ and $\Psi=90$) the scattering pattern 123 should be circularly symmetric, but it will go to zero at $q_x = 0$ due to the 124 $\sin(\Delta\theta)$ correction. This problem does not appear for a shape 125 that is tumbling freely around the $a$ axis, with $\Delta\phi$ uniform in 126 $[-180, 180]$, so swap the $a$ and $b$ axes so $\Delta\theta < \Delta\phi$ 127 and adjust $\Psi$ by 90. This works with the current sasmodels shapes due to 128 symmetry. 129 130 Alternative projections were considered. 131 The `sinusoidal projection <https://en.wikipedia.org/wiki/Sinusoidal_projection>`_ 132 works by scaling $\Delta\phi$ as $\Delta\theta$ increases, and dropping those 133 points outside $[-180, 180]$. The distortions are a little less for middle 134 ranges of $\Delta\theta$, but they are still severe for large $\Delta\theta$ 135 and the model is much harder to explain. 136 The `azimuthal equidistance projection <https://en.wikipedia.org/wiki/Azimuthal_equidistant_projection>`_ 137 also improves on the equirectangular projection by extending the range of 138 reasonable values for the $\Delta\theta$ range, with $\Delta\phi$ forming a 139 wedge that cuts to the opposite side of the sphere rather than cutting to the 140 pole. This projection has the nice property that distance from the center are 141 preserved, and that $\Delta\theta$ and $\Delta\phi$ act the same. 142 The `azimuthal equal area projection <https://en.wikipedia.org/wiki/Lambert_azimuthal_equal-area_projection>`_ 143 is like the azimuthal equidistance projection, but it preserves area instead 144 of distance. It also has the same behaviour for $\Delta\theta$ and $\Delta\phi$. 145 The `Guyou projection <https://en.wikipedia.org/wiki/Guyou_hemisphere-in-a-square_projection>`_ 146 has an excellent balance with reasonable distortion in both $\Delta\theta$ 147 and $\Delta\phi$, as well as preserving small patches. However, it requires 148 considerably more computational overhead, and we have not yet derived the 149 formula for the distortion correction, measuring the degree of stretch at 150 the point $(\Delta\theta, \Delta\phi)$ on the map. 59 Earlier versions of SasView had numerical integration issues in some 60 circumstances when distributions passed through 90 degrees. The distributions 61 in particle coordinates are more robust, but should still be approached with 62 care for large ranges of angle. 151 63 152 64 .. note:: 153 Note that the form factors for oriented particles are performing 154 numerical integrations over one or more variables, so care should be 155 taken, especially with very large particles or more extreme aspect 156 ratios. In such cases results may not be accurate, particularly at very 157 high Q, unless the model has been specifically coded to use limiting 158 forms of the scattering equations. 65 Note that the form factors for oriented particles are also performing 66 numerical integrations over one or more variables, so care should be taken, 67 especially with very large particles or more extreme aspect ratios. In such 68 cases results may not be accurate, particularly at very high Q, unless the model 69 has been specifically coded to use limiting forms of the scattering equations. 70 71 For best numerical results keep the $\theta$ distribution narrower than the $\phi$ 72 distribution. Thus for asymmetric particles, such as elliptical_cylinder, you may 73 need to reorder the sizes of the three axes to acheive the desired result. 74 This is due to the issues of mapping a rectangular distribution onto the 75 surface of a sphere. 159 76 160 For best numerical results keep the $\theta$ distribution narrower than 161 the $\phi$ distribution. Thus for asymmetric particles, such as 162 elliptical_cylinder, you may need to reorder the sizes of the three axes 163 to acheive the desired result. This is due to the issues of mapping a 164 rectanglar distribution onto the surface of a sphere. 165 166 Users can experiment with the values of *Npts* and *Nsigs*, the number of steps 167 used in the integration and the range spanned in number of standard deviations. 168 The standard deviation is entered in units of degrees. For a "rectangular" 169 distribution the full width should be $\pm \sqrt(3)$ ~ 1.73 standard deviations. 170 The new "uniform" distribution avoids this by letting you directly specify the 77 Users can experiment with the values of *Npts* and *Nsigs*, the number of steps 78 used in the integration and the range spanned in number of standard deviations. 79 The standard deviation is entered in units of degrees. For a "rectangular" 80 distribution the full width should be $\pm \sqrt(3)$ ~ 1.73 standard deviations. 81 The new "uniform" distribution avoids this by letting you directly specify the 171 82 half width. 172 83 173 The angular distributions may be truncated outside of the range -180 to +180174 degrees, so beware of using saying a broad Gaussian distribution with large 175 value of *Nsigs*, as the array of *Npts* may be truncated to many fewer 176 points than would give a good integration,as well as becoming rather 177 meaningless. (At some point in the future the actual dispersion arrays may be 178 made available to the userfor inspection.)84 The angular distributions will be truncated outside of the range -180 to +180 85 degrees, so beware of using saying a broad Gaussian distribution with large value 86 of *Nsigs*, as the array of *Npts* may be truncated to many fewer points than would 87 give a good integration,as well as becoming rather meaningless. (At some point 88 in the future the actual polydispersity arrays may be made available to the user 89 for inspection.) 179 90 180 91 Some more detailed technical notes are provided in the developer section of 181 92 this manual :ref:`orientation_developer` . 182 93 183 This definition of orientation is new to SasView 4.2. In earlier versions,184 the orientation distribution appeared as a distribution of view angles.185 This led to strange effects when $c$ was aligned with $z$, where changes186 to the $\phi$ angle served only to rotate the shape about $c$, rather than187 having a consistent interpretation as the pitch of the shape relative to188 the flow field defining the reference orientation. Prior to SasView 4.1,189 the reference orientation was defined using a Tait-Bryan convention, making190 it difficult to control. Now, rotation in $\theta$ modifies the spacings191 in the refraction pattern, and rotation in $\phi$ rotates it in the detector192 plane.193 194 195 94 *Document History* 196 95 197 96 | 2017-11-06 Richard Heenan 198 | 2017-12-20 Paul Kienzle -
doc/guide/plugin.rst
r7e6bc45e r3048ec6 292 292 **Note: The order of the parameters in the definition will be the order of the 293 293 parameters in the user interface and the order of the parameters in Iq(), 294 Iqac(), Iqabc() and form_volume(). And** *scale* **and** *background* 295 **parameters are implicit to all models, so they do not need to be included 296 in the parameter table.** 294 Iqxy() and form_volume(). And** *scale* **and** *background* **parameters are 295 implicit to all models, so they do not need to be included in the parameter table.** 297 296 298 297 - **"name"** is the name of the parameter shown on the FitPage. … … 363 362 scattered intensity. 364 363 365 - "volume" parameters are passed to Iq(), Iqac(), Iqabc() and form_volume(), 366 and have polydispersity loops generated automatically. 367 368 - "orientation" parameters are not passed, but instead are combined with 369 orientation dispersity to translate *qx* and *qy* to *qa*, *qb* and *qc*. 370 These parameters should appear at the end of the table with the specific 371 names *theta*, *phi* and for asymmetric shapes *psi*, in that order. 364 - "volume" parameters are passed to Iq(), Iqxy(), and form_volume(), and 365 have polydispersity loops generated automatically. 366 367 - "orientation" parameters are only passed to Iqxy(), and have angular 368 dispersion. 372 369 373 370 Some models will have integer parameters, such as number of pearls in the … … 422 419 That is, the individual models do not need to include polydispersity 423 420 calculations, but instead rely on numerical integration to compute the 424 appropriately smeared pattern. 421 appropriately smeared pattern. Angular dispersion values over polar angle 422 $\theta$ requires an additional $\cos \theta$ weighting due to decreased 423 arc length for the equatorial angle $\phi$ with increasing latitude. 425 424 426 425 Python Models … … 469 468 barbell). If I(q; pars) is NaN for any $q$, then those parameters will be 470 469 ignored, and not included in the calculation of the weighted polydispersity. 470 471 Similar to *Iq*, you can define *Iqxy(qx, qy, par1, par2, ...)* where the 472 parameter list includes any orientation parameters. If *Iqxy* is not defined, 473 then it will default to *Iqxy = Iq(sqrt(qx**2+qy**2), par1, par2, ...)*. 471 474 472 475 Models should define *form_volume(par1, par2, ...)* where the parameter … … 494 497 } 495 498 499 *Iqxy* is similar to *Iq*, except it uses parameters *qx, qy* instead of *q*, 500 and it includes orientation parameters. 501 496 502 *form_volume* defines the volume of the shape. As in python models, it 497 503 includes only the volume parameters. 498 504 505 *Iqxy* will default to *Iq(sqrt(qx**2 + qy**2), par1, ...)* and 506 *form_volume* will default to 1.0. 507 499 508 **source=['fn.c', ...]** includes the listed C source files in the 500 program before *Iq* and *form_volume* are defined. This allows you to 501 extend the library of C functions available to your model. 502 503 *c_code* includes arbitrary C code into your kernel, which can be 504 handy for defining helper functions for *Iq* and *form_volume*. Note that 505 you can put the full function definition for *Iq* and *form_volume* 506 (include function declaration) into *c_code* as well, or put them into an 507 external C file and add that file to the list of sources. 509 program before *Iq* and *Iqxy* are defined. This allows you to extend the 510 library of C functions available to your model. 508 511 509 512 Models are defined using double precision declarations for the … … 530 533 #define INVALID(v) (v.bell_radius < v.radius) 531 534 532 The INVALID define can go into *Iq*, or *c_code*, or an external C file533 listed in *source*.534 535 Oriented Shapes536 ...............537 538 If the scattering is dependent on the orientation of the shape, then you539 will need to include *orientation* parameters *theta*, *phi* and *psi*540 at the end of the parameter table. As described in the section541 :ref:`orientation`, the individual $(q_x, q_y)$ points on the detector will542 be rotated into $(q_a, q_b, q_c)$ points relative to the sample in its543 canonical orientation with $a$-$b$-$c$ aligned with $x$-$y$-$z$ in the544 laboratory frame and beam travelling along $-z$.545 546 The oriented C model is called using *Iqabc(qa, qb, qc, par1, par2, ...)* where547 *par1*, etc. are the parameters to the model. If the shape is rotationally548 symmetric about *c* then *psi* is not needed, and the model is called549 as *Iqac(qab, qc, par1, par2, ...)*. In either case, the orientation550 parameters are not included in the function call.551 552 For 1D oriented shapes, an integral over all angles is usually needed for553 the *Iq* function. Given symmetry and the substitution $u = \cos(\alpha)$,554 $du = -\sin(\alpha)\,d\alpha$ this becomes555 556 .. math::557 558 I(q) &= \frac{1}{4\pi} \int_{-\pi/2}^{pi/2} \int_{-pi}^{pi}559 F(q_a, q_b, q_c)^2 \sin(\alpha)\,d\beta\,d\alpha \\560 &= \frac{8}{4\pi} \int_{0}^{pi/2} \int_{0}^{\pi/2}561 F^2 \sin(\alpha)\,d\beta\,d\alpha \\562 &= \frac{8}{4\pi} \int_1^0 \int_{0}^{\pi/2} - F^2 \,d\beta\,du \\563 &= \frac{8}{4\pi} \int_0^1 \int_{0}^{\pi/2} F^2 \,d\beta\,du564 565 for566 567 .. math::568 569 q_a &= q \sin(\alpha)\sin(\beta) = q \sqrt{1-u^2} \sin(\beta) \\570 q_b &= q \sin(\alpha)\cos(\beta) = q \sqrt{1-u^2} \cos(\beta) \\571 q_c &= q \cos(\alpha) = q u572 573 Using the $z, w$ values for Gauss-Legendre integration in "lib/gauss76.c", the574 numerical integration is then::575 576 double outer_sum = 0.0;577 for (int i = 0; i < GAUSS_N; i++) {578 const double cos_alpha = 0.5*GAUSS_Z[i] + 0.5;579 const double sin_alpha = sqrt(1.0 - cos_alpha*cos_alpha);580 const double qc = cos_alpha * q;581 double inner_sum = 0.0;582 for (int j = 0; j < GAUSS_N; j++) {583 const double beta = M_PI_4 * GAUSS_Z[j] + M_PI_4;584 double sin_beta, cos_beta;585 SINCOS(beta, sin_beta, cos_beta);586 const double qa = sin_alpha * sin_beta * q;587 const double qb = sin_alpha * cos_beta * q;588 const double form = Fq(qa, qb, qc, ...);589 inner_sum += GAUSS_W[j] * form * form;590 }591 outer_sum += GAUSS_W[i] * inner_sum;592 }593 outer_sum *= 0.25; // = 8/(4 pi) * outer_sum * (pi/2) / 4594 595 The *z* values for the Gauss-Legendre integration extends from -1 to 1, so596 the double sum of *w[i]w[j]* explains the factor of 4. Correcting for the597 average *dz[i]dz[j]* gives $(1-0) \cdot (\pi/2-0) = \pi/2$. The $8/(4 \pi)$598 factor comes from the integral over the quadrant. With less symmetry (eg.,599 in the bcc and fcc paracrystal models), then an integral over the entire600 sphere may be necessary.601 602 For simpler models which are rotationally symmetric a single integral603 suffices:604 605 .. math::606 607 I(q) &= \frac{1}{\pi}\int_{-\pi/2}^{\pi/2}608 F(q_{ab}, q_c)^2 \sin(\alpha)\,d\alpha/\pi \\609 &= \frac{2}{\pi} \int_0^1 F^2\,du610 611 for612 613 .. math::614 615 q_{ab} &= q \sin(\alpha) = q \sqrt{1 - u^2} \\616 q_c &= q \cos(\alpha) = q u617 618 619 with integration loop::620 621 double sum = 0.0;622 for (int i = 0; i < GAUSS_N; i++) {623 const double cos_alpha = 0.5*GAUSS_Z[i] + 0.5;624 const double sin_alpha = sqrt(1.0 - cos_alpha*cos_alpha);625 const double qab = sin_alpha * q;626 const double qc = cos_alpha * q;627 const double form = Fq(qab, qc, ...);628 sum += GAUSS_W[j] * form * form;629 }630 sum *= 0.5; // = 2/pi * sum * (pi/2) / 2631 632 Magnetism633 .........634 635 Magnetism is supported automatically for all shapes by modifying the636 effective SLD of particle according to the Halpern-Johnson vector637 describing the interaction between neutron spin and magnetic field. All638 parameters marked as type *sld* in the parameter table are treated as639 possibly magnetic particles with magnitude *M0* and direction640 *mtheta* and *mphi*. Polarization parameters are also provided641 automatically for magnetic models to set the spin state of the measurement.642 643 For more complicated systems where magnetism is not uniform throughout644 the individual particles, you will need to write your own models.645 You should not mark the nuclear sld as type *sld*, but instead leave646 them unmarked and provide your own magnetism and polarization parameters.647 For 2D measurements you will need $(q_x, q_y)$ values for the measurement648 to compute the proper magnetism and orientation, which you can implement649 using *Iqxy(qx, qy, par1, par2, ...)*.650 651 535 Special Functions 652 536 ................. … … 659 543 M_PI, M_PI_2, M_PI_4, M_SQRT1_2, M_E: 660 544 $\pi$, $\pi/2$, $\pi/4$, $1/\sqrt{2}$ and Euler's constant $e$ 661 exp, log, pow(x,y), expm1, log1p, sqrt, cbrt:662 Power functions $e^x$, $\ln x$, $x^y$, $e^x - 1$, $\ ln 1 + x$,663 $\sqrt{x}$, $\sqrt[3]{x}$. The functions expm1(x) and log1p(x)664 are accurate across all $x$, including $x$very close to zero.545 exp, log, pow(x,y), expm1, sqrt: 546 Power functions $e^x$, $\ln x$, $x^y$, $e^x - 1$, $\sqrt{x}$. 547 The function expm1(x) is accurate across all $x$, including $x$ 548 very close to zero. 665 549 sin, cos, tan, asin, acos, atan: 666 550 Trigonometry functions and inverses, operating on radians. … … 673 557 atan(y/x) would return a value in quadrant I. Similarly for 674 558 quadrants II and IV when $x$ and $y$ have opposite sign. 675 f abs(x), fmin(x,y), fmax(x,y), trunc, rint:559 fmin(x,y), fmax(x,y), trunc, rint: 676 560 Floating point functions. rint(x) returns the nearest integer. 677 561 NAN: 678 562 NaN, Not a Number, $0/0$. Use isnan(x) to test for NaN. Note that 679 563 you cannot use :code:`x == NAN` to test for NaN values since that 680 will always return false. NAN does not equal NAN! The alternative, 681 :code:`x != x` may fail if the compiler optimizes the test away. 564 will always return false. NAN does not equal NAN! 682 565 INFINITY: 683 566 $\infty, 1/0$. Use isinf(x) to test for infinity, or isfinite(x) … … 851 734 Similar arrays are available in :code:`gauss20.c` for 20-point 852 735 quadrature and in :code:`gauss150.c` for 150-point quadrature. 853 The macros :code:`GAUSS_N`, :code:`GAUSS_Z` and :code:`GAUSS_W` are854 defined so that you can change the order of the integration by855 selecting an different source without touching the C code.856 736 857 737 :code:`source = ["lib/gauss76.c", ...]` … … 911 791 can be a model that runs 1000x faster on a good card. Even your laptop may 912 792 show a 50x improvement or more over the equivalent pure python model. 793 794 External C Models 795 ................. 796 797 External C models are very much like embedded C models, except that 798 *Iq*, *Iqxy* and *form_volume* are defined in an external source file 799 loaded using the *source=[...]* statement. You need to supply the function 800 declarations for each of these that you need instead of building them 801 automatically from the parameter table. 913 802 914 803 … … 1113 1002 variable name *Rg* for example because $R_g$ is the right name for the model 1114 1003 parameter then ignore the lint errors. Also, ignore *missing-docstring* 1115 for standard model functions *Iq*, *Iq ac*, etc.1004 for standard model functions *Iq*, *Iqxy*, etc. 1116 1005 1117 1006 We will have delinting sessions at the SasView Code Camps, where we can -
explore/asymint.py
ra1c32c2 r1820208 86 86 a, b, c = env.mpf(a), env.mpf(b), env.mpf(c) 87 87 def Fq(qa, qb, qc): 88 siA = env.sas_sinx_x( a*qa/2)89 siB = env.sas_sinx_x( b*qb/2)90 siC = env.sas_sinx_x( c*qc/2)88 siA = env.sas_sinx_x(0.5*a*qa/2) 89 siB = env.sas_sinx_x(0.5*b*qb/2) 90 siC = env.sas_sinx_x(0.5*c*qc/2) 91 91 return siA * siB * siC 92 92 Fq.__doc__ = "parallelepiped a=%g, b=%g c=%g"%(a, b, c) 93 93 volume = a*b*c 94 94 norm = CONTRAST**2*volume/10000 95 return norm, Fq96 97 def make_core_shell_parallelepiped(a, b, c, da, db, dc, slda, sldb, sldc, env=NPenv):98 overlapping = False99 a, b, c = env.mpf(a), env.mpf(b), env.mpf(c)100 da, db, dc = env.mpf(da), env.mpf(db), env.mpf(dc)101 slda, sldb, sldc = env.mpf(slda), env.mpf(sldb), env.mpf(sldc)102 dr0 = CONTRAST103 drA, drB, drC = slda-SLD_SOLVENT, sldb-SLD_SOLVENT, sldc-SLD_SOLVENT104 tA, tB, tC = a + 2*da, b + 2*db, c + 2*dc105 def Fq(qa, qb, qc):106 siA = a*env.sas_sinx_x(a*qa/2)107 siB = b*env.sas_sinx_x(b*qb/2)108 siC = c*env.sas_sinx_x(c*qc/2)109 siAt = tA*env.sas_sinx_x(tA*qa/2)110 siBt = tB*env.sas_sinx_x(tB*qb/2)111 siCt = tC*env.sas_sinx_x(tC*qc/2)112 if overlapping:113 return (dr0*siA*siB*siC114 + drA*(siAt-siA)*siB*siC115 + drB*siAt*(siBt-siB)*siC116 + drC*siAt*siBt*(siCt-siC))117 else:118 return (dr0*siA*siB*siC119 + drA*(siAt-siA)*siB*siC120 + drB*siA*(siBt-siB)*siC121 + drC*siA*siB*(siCt-siC))122 Fq.__doc__ = "core-shell parallelepiped a=%g, b=%g c=%g"%(a, b, c)123 if overlapping:124 volume = a*b*c + 2*da*b*c + 2*tA*db*c + 2*tA*tB*dc125 else:126 volume = a*b*c + 2*da*b*c + 2*a*db*c + 2*a*b*dc127 norm = 1/(volume*10000)128 95 return norm, Fq 129 96 … … 217 184 NORM, KERNEL = make_parallelepiped(A, B, C) 218 185 NORM_MP, KERNEL_MP = make_parallelepiped(A, B, C, env=MPenv) 219 elif shape == 'core_shell_parallelepiped':220 #A, B, C = 4450, 14000, 47221 #A, B, C = 445, 140, 47 # integer for the sake of mpf222 A, B, C = 6800, 114, 1380223 DA, DB, DC = 2300, 21, 58224 SLDA, SLDB, SLDC = "5", "-0.3", "11.5"225 #A,B,C,DA,DB,DC,SLDA,SLDB,SLDC = 10,20,30,100,200,300,1,2,3226 #SLD_SOLVENT,CONTRAST = 0, 4227 if 1: # C shortest228 B, C = C, B229 DB, DC = DC, DB230 SLDB, SLDC = SLDC, SLDB231 elif 0: # C longest232 A, C = C, A233 DA, DC = DC, DA234 SLDA, SLDC = SLDC, SLDA235 NORM, KERNEL = make_core_shell_parallelepiped(A, B, C, DA, DB, DC, SLDA, SLDB, SLDC)236 NORM_MP, KERNEL_MP = make_core_shell_parallelepiped(A, B, C, DA, DB, DC, SLDA, SLDB, SLDC, env=MPenv)237 186 elif shape == 'paracrystal': 238 187 LATTICE = 'bcc' … … 393 342 print("gauss-150", *gauss_quad_2d(Q, n=150)) 394 343 print("gauss-500", *gauss_quad_2d(Q, n=500)) 395 print("gauss-1025", *gauss_quad_2d(Q, n=1025))396 print("gauss-2049", *gauss_quad_2d(Q, n=2049))397 344 #gridded_2d(Q, n=2**8+1) 398 345 gridded_2d(Q, n=2**10+1) 399 #gridded_2d(Q, n=2**1 2+1)346 #gridded_2d(Q, n=2**13+1) 400 347 #gridded_2d(Q, n=2**15+1) 401 if shape not in ('paracrystal', 'core_shell_parallelepiped'): 402 # adaptive forms on models for which the calculations are fast enough 348 if shape != 'paracrystal': # adaptive forms are too slow! 403 349 print("dblquad", *scipy_dblquad_2d(Q)) 404 350 print("semi-romberg-100", *semi_romberg_2d(Q, n=100)) -
explore/jitter.py
r8cfb486 rff10479 165 165 # constants in kernel_iq.c 166 166 'equirectangular', 'sinusoidal', 'guyou', 'azimuthal_equidistance', 167 'azimuthal_equal_area',168 167 ] 169 168 def draw_mesh(ax, view, jitter, radius=1.2, n=11, dist='gaussian', -
explore/precision.py
r2a7e20e r2a602c7 345 345 ) 346 346 add_function( 347 name="(1/2 -sin(x)/x+(1-cos(x))/x^2)/x",347 name="(1/2+(1-cos(x))/x^2-sin(x)/x)/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 " or one of:622 and name is "all [first]" or one of: 623 623 """+names) 624 624 sys.exit(1) -
sasmodels/compare.py
r2a7e20e r2d81cfe 42 42 from .data import plot_theory, empty_data1D, empty_data2D, load_data 43 43 from .direct_model import DirectModel, get_mesh 44 from .generate import FLOAT_RE , set_integration_size44 from .generate import FLOAT_RE 45 45 from .weights import plot_weights 46 46 … … 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 quadrature95 94 96 95 === precision options === … … 694 693 data = empty_data2D(q, resolution=res) 695 694 data.accuracy = opts['accuracy'] 696 set_beam_stop(data, qmin)695 set_beam_stop(data, 0.0004) 697 696 index = ~data.mask 698 697 else: … … 707 706 return data, index 708 707 709 def make_engine(model_info, data, dtype, cutoff , ngauss=0):708 def make_engine(model_info, data, dtype, cutoff): 710 709 # type: (ModelInfo, Data, str, float) -> Calculator 711 710 """ … … 715 714 than OpenCL. 716 715 """ 717 if ngauss:718 set_integration_size(model_info, ngauss)719 720 716 if dtype is None or not dtype.endswith('!'): 721 717 return eval_opencl(model_info, data, dtype=dtype, cutoff=cutoff) … … 958 954 'poly', 'mono', 'cutoff=', 959 955 'magnetic', 'nonmagnetic', 960 'accuracy=', 'ngauss=',956 'accuracy=', 961 957 'neval=', # for timing... 962 958 … … 1093 1089 'show_weights' : False, 1094 1090 'sphere' : 0, 1095 'ngauss' : '0',1096 1091 } 1097 1092 for arg in flags: … … 1120 1115 elif arg.startswith('-engine='): opts['engine'] = arg[8:] 1121 1116 elif arg.startswith('-neval='): opts['count'] = arg[7:] 1122 elif arg.startswith('-ngauss='): opts['ngauss'] = arg[8:]1123 1117 elif arg.startswith('-random='): 1124 1118 opts['seed'] = int(arg[8:]) … … 1175 1169 1176 1170 comparison = any(PAR_SPLIT in v for v in values) 1177 1178 1171 if PAR_SPLIT in name: 1179 1172 names = name.split(PAR_SPLIT, 2) … … 1188 1181 return None 1189 1182 1190 if PAR_SPLIT in opts['ngauss']:1191 opts['ngauss'] = [int(k) for k in opts['ngauss'].split(PAR_SPLIT, 2)]1192 comparison = True1193 else:1194 opts['ngauss'] = [int(opts['ngauss'])]*21195 1196 1183 if PAR_SPLIT in opts['engine']: 1197 1184 opts['engine'] = opts['engine'].split(PAR_SPLIT, 2) … … 1212 1199 opts['cutoff'] = [float(opts['cutoff'])]*2 1213 1200 1214 base = make_engine(model_info[0], data, opts['engine'][0], 1215 opts['cutoff'][0], opts['ngauss'][0]) 1201 base = make_engine(model_info[0], data, opts['engine'][0], opts['cutoff'][0]) 1216 1202 if comparison: 1217 comp = make_engine(model_info[1], data, opts['engine'][1], 1218 opts['cutoff'][1], opts['ngauss'][1]) 1203 comp = make_engine(model_info[1], data, opts['engine'][1], opts['cutoff'][1]) 1219 1204 else: 1220 1205 comp = None … … 1289 1274 if model_info != model_info2: 1290 1275 pars2 = randomize_pars(model_info2, pars2) 1291 limit_dimensions(model_info 2, pars2, maxdim)1276 limit_dimensions(model_info, pars2, maxdim) 1292 1277 # Share values for parameters with the same name 1293 1278 for k, v in pars.items(): -
sasmodels/details.py
r108e70e r2d81cfe 258 258 # type: (...) -> Sequence[np.ndarray] 259 259 """ 260 **Deprecated** Theta weights will be computed in the kernel wrapper if261 they are needed.262 263 260 If there is a theta parameter, update the weights of that parameter so that 264 261 the cosine weighting required for polar integration is preserved. … … 275 272 Returns updated weights vectors 276 273 """ 274 # TODO: explain in a comment why scale and background are missing 277 275 # Apparently the parameters.theta_offset similarly skips scale and 278 276 # and background, so the indexing works out, but they are still shipped … … 281 279 index = parameters.theta_offset 282 280 theta = dispersity[index] 281 # TODO: modify the dispersity vector to avoid the theta=-90,90,270,... 283 282 theta_weight = abs(cos(radians(theta))) 284 283 weights = tuple(theta_weight*w if k == index else w -
sasmodels/generate.py
r108e70e r2d81cfe 7 7 particular dimensions averaged over all orientations. 8 8 9 *Iqac(qab, qc, p1, p2, ...)* returns the scattering at qab, qc 10 for a rotationally symmetric form with particular dimensions. 11 qab, qc are determined from shape orientation and scattering angles. 12 This call is used if the shape has orientation parameters theta and phi. 13 14 *Iqabc(qa, qb, qc, p1, p2, ...)* returns the scattering at qa, qb, qc 15 for a form with particular dimensions. qa, qb, qc are determined from 16 shape orientation and scattering angles. This call is used if the shape 17 has orientation parameters theta, phi and psi. 18 19 *Iqxy(qx, qy, p1, p2, ...)* returns the scattering at qx, qy. Use this 20 to create an arbitrary 2D theory function, needed for q-dependent 21 background functions and for models with non-uniform magnetism. 9 *Iqxy(qx, qy, p1, p2, ...)* returns the scattering at qx, qy for a form 10 with particular dimensions for a single orientation. 11 12 *Imagnetic(qx, qy, result[], p1, p2, ...)* returns the scattering for the 13 polarized neutron spin states (up-up, up-down, down-up, down-down) for 14 a form with particular dimensions for a single orientation. 22 15 23 16 *form_volume(p1, p2, ...)* returns the volume of the form with particular … … 38 31 scale and background parameters for each model. 39 32 40 C code should be stylized C-99 functions written for OpenCL. All functions 41 need prototype declarations even if the are defined before they are used. 42 Although OpenCL supports *#include* preprocessor directives, the list of 43 includes should be given as part of the metadata in the kernel module 44 definition. The included files should be listed using a path relative to the 45 kernel module, or if using "lib/file.c" if it is one of the standard includes 46 provided with the sasmodels source. The includes need to be listed in order 47 so that functions are defined before they are used. 33 *Iq*, *Iqxy*, *Imagnetic* and *form_volume* should be stylized C-99 34 functions written for OpenCL. All functions need prototype declarations 35 even if the are defined before they are used. OpenCL does not support 36 *#include* preprocessor directives, so instead the list of includes needs 37 to be given as part of the metadata in the kernel module definition. 38 The included files should be listed using a path relative to the kernel 39 module, or if using "lib/file.c" if it is one of the standard includes 40 provided with the sasmodels source. The includes need to be listed in 41 order so that functions are defined before they are used. 48 42 49 43 Floating point values should be declared as *double*. For single precision … … 113 107 present, the volume ratio is 1. 114 108 115 *form_volume*, *Iq*, *Iq ac*, *Iqabc* are strings containing116 the C source code for the body of the volume, Iq, and Iqacfunctions109 *form_volume*, *Iq*, *Iqxy*, *Imagnetic* are strings containing the 110 C source code for the body of the volume, Iq, and Iqxy functions 117 111 respectively. These can also be defined in the last source file. 118 112 119 *Iq* , *Iqac*, *Iqabc* also be instead be python functions defining the113 *Iq* and *Iqxy* also be instead be python functions defining the 120 114 kernel. If they are marked as *Iq.vectorized = True* then the 121 115 kernel is passed the entire *q* vector at once, otherwise it is … … 174 168 from zlib import crc32 175 169 from inspect import currentframe, getframeinfo 176 import logging177 170 178 171 import numpy as np # type: ignore … … 188 181 pass 189 182 # pylint: enable=unused-import 190 191 logger = logging.getLogger(__name__)192 183 193 184 # jitter projection to use in the kernel code. See explore/jitter.py … … 279 270 """ 280 271 281 282 def set_integration_size(info, n):283 # type: (ModelInfo, int) -> None284 """285 Update the model definition, replacing the gaussian integration with286 a gaussian integration of a different size.287 288 Note: this really ought to be a method in modelinfo, but that leads to289 import loops.290 """291 if (info.source and any(lib.startswith('lib/gauss') for lib in info.source)):292 import os.path293 from .gengauss import gengauss294 path = os.path.join(MODEL_PATH, "lib", "gauss%d.c"%n)295 if not os.path.exists(path):296 gengauss(n, path)297 info.source = ["lib/gauss%d.c"%n if lib.startswith('lib/gauss')298 else lib for lib in info.source]299 272 300 273 def format_units(units): … … 635 608 636 609 """ 637 def _gen_fn( model_info, name, pars):638 # type: ( ModelInfo, str, List[Parameter]) -> str610 def _gen_fn(name, pars, body, filename, line): 611 # type: (str, List[Parameter], str, str, int) -> str 639 612 """ 640 613 Generate a function given pars and body. … … 648 621 """ 649 622 par_decl = ', '.join(p.as_function_argument() for p in pars) if pars else 'void' 650 body = getattr(model_info, name)651 filename = model_info.filename652 # Note: if symbol is defined strangely in the module then default it to 1653 lineno = model_info.lineno.get(name, 1)654 623 return _FN_TEMPLATE % { 655 624 'name': name, 'pars': par_decl, 'body': body, 656 'filename': filename.replace('\\', '\\\\'), 'line': line no,625 'filename': filename.replace('\\', '\\\\'), 'line': line, 657 626 } 658 627 … … 669 638 670 639 # type in IQXY pattern could be single, float, double, long double, ... 671 _IQXY_PATTERN = re.compile( r"(^|\s)double\s+I(?P<mode>q(ab?c|xy))\s*[(]",640 _IQXY_PATTERN = re.compile("^((inline|static) )? *([a-z ]+ )? *Iqxy *([(]|$)", 672 641 flags=re.MULTILINE) 673 def find_xy_mode(source):642 def _have_Iqxy(sources): 674 643 # type: (List[str]) -> bool 675 644 """ 676 Return t he xy mode as qa, qac, qabc orqxy.645 Return true if any file defines Iqxy. 677 646 678 647 Note this is not a C parser, and so can be easily confused by 679 648 non-standard syntax. Also, it will incorrectly identify the following 680 as having 2D models::649 as having Iqxy:: 681 650 682 651 /* 683 double Iq ac(qab, qc, ...) { ... fill this in later ... }652 double Iqxy(qx, qy, ...) { ... fill this in later ... } 684 653 */ 685 654 686 If you want to comment out the function, use // on the front of the 687 line:: 688 689 /* 690 // double Iqac(qab, qc, ...) { ... fill this in later ... } 691 */ 692 693 """ 694 for code in source: 695 m = _IQXY_PATTERN.search(code) 696 if m is not None: 697 return m.group('mode') 698 return 'qa' 699 700 701 def _add_source(source, code, path, lineno=1): 655 If you want to comment out an Iqxy function, use // on the front of the 656 line instead. 657 """ 658 for _path, code in sources: 659 if _IQXY_PATTERN.search(code): 660 return True 661 return False 662 663 664 def _add_source(source, code, path): 702 665 """ 703 666 Add a file to the list of source code chunks, tagged with path and line. 704 667 """ 705 668 path = path.replace('\\', '\\\\') 706 source.append('#line %d "%s"' % (lineno, path))669 source.append('#line 1 "%s"' % path) 707 670 source.append(code) 708 671 … … 735 698 user_code = [(f, open(f).read()) for f in model_sources(model_info)] 736 699 700 # What kind of 2D model do we need? 701 xy_mode = ('qa' if not _have_Iqxy(user_code) and not isinstance(model_info.Iqxy, str) 702 else 'qac' if not partable.is_asymmetric 703 else 'qabc') 704 737 705 # Build initial sources 738 706 source = [] … … 741 709 _add_source(source, code, path) 742 710 743 if model_info.c_code:744 _add_source(source, model_info.c_code, model_info.filename,745 lineno=model_info.lineno.get('c_code', 1))746 747 711 # Make parameters for q, qx, qy so that we can use them in declarations 748 q, qx, qy, qab, qa, qb, qc \ 749 = [Parameter(name=v) for v in 'q qx qy qab qa qb qc'.split()] 712 q, qx, qy = [Parameter(name=v) for v in ('q', 'qx', 'qy')] 750 713 # Generate form_volume function, etc. from body only 751 714 if isinstance(model_info.form_volume, str): 752 715 pars = partable.form_volume_parameters 753 source.append(_gen_fn(model_info, 'form_volume', pars)) 716 source.append(_gen_fn('form_volume', pars, model_info.form_volume, 717 model_info.filename, model_info._form_volume_line)) 754 718 if isinstance(model_info.Iq, str): 755 719 pars = [q] + partable.iq_parameters 756 source.append(_gen_fn(model_info, 'Iq', pars)) 720 source.append(_gen_fn('Iq', pars, model_info.Iq, 721 model_info.filename, model_info._Iq_line)) 757 722 if isinstance(model_info.Iqxy, str): 758 pars = [qx, qy] + partable.iq_parameters + partable.orientation_parameters 759 source.append(_gen_fn(model_info, 'Iqxy', pars)) 760 if isinstance(model_info.Iqac, str): 761 pars = [qab, qc] + partable.iq_parameters 762 source.append(_gen_fn(model_info, 'Iqac', pars)) 763 if isinstance(model_info.Iqabc, str): 764 pars = [qa, qb, qc] + partable.iq_parameters 765 source.append(_gen_fn(model_info, 'Iqabc', pars)) 766 767 # What kind of 2D model do we need? Is it consistent with the parameters? 768 xy_mode = find_xy_mode(source) 769 if xy_mode == 'qabc' and not partable.is_asymmetric: 770 raise ValueError("asymmetric oriented models need to define Iqabc") 771 elif xy_mode == 'qac' and partable.is_asymmetric: 772 raise ValueError("symmetric oriented models need to define Iqac") 773 elif not partable.orientation_parameters and xy_mode in ('qac', 'qabc'): 774 raise ValueError("Unexpected function I%s for unoriented shape"%xy_mode) 775 elif partable.orientation_parameters and xy_mode not in ('qac', 'qabc'): 776 if xy_mode == 'qxy': 777 logger.warn("oriented shapes should define Iqac or Iqabc") 778 else: 779 raise ValueError("Expected function Iqac or Iqabc for oriented shape") 723 pars = [qx, qy] + partable.iqxy_parameters 724 source.append(_gen_fn('Iqxy', pars, model_info.Iqxy, 725 model_info.filename, model_info._Iqxy_line)) 780 726 781 727 # Define the parameter table … … 803 749 if xy_mode == 'qabc': 804 750 pars = ",".join(["_qa", "_qb", "_qc"] + model_refs) 805 call_iqxy = "#define CALL_IQ_ABC(_qa,_qb,_qc,_v) Iq abc(%s)" % pars751 call_iqxy = "#define CALL_IQ_ABC(_qa,_qb,_qc,_v) Iqxy(%s)" % pars 806 752 clear_iqxy = "#undef CALL_IQ_ABC" 807 753 elif xy_mode == 'qac': 808 754 pars = ",".join(["_qa", "_qc"] + model_refs) 809 call_iqxy = "#define CALL_IQ_AC(_qa,_qc,_v) Iq ac(%s)" % pars755 call_iqxy = "#define CALL_IQ_AC(_qa,_qc,_v) Iqxy(%s)" % pars 810 756 clear_iqxy = "#undef CALL_IQ_AC" 811 el if xy_mode == 'qa':757 else: # xy_mode == 'qa' 812 758 pars = ",".join(["_qa"] + model_refs) 813 759 call_iqxy = "#define CALL_IQ_A(_qa,_v) Iq(%s)" % pars 814 760 clear_iqxy = "#undef CALL_IQ_A" 815 elif xy_mode == 'qxy':816 orientation_refs = _call_pars("_v.", partable.orientation_parameters)817 pars = ",".join(["_qx", "_qy"] + model_refs + orientation_refs)818 call_iqxy = "#define CALL_IQ_XY(_qx,_qy,_v) Iqxy(%s)" % pars819 clear_iqxy = "#undef CALL_IQ_XY"820 if partable.orientation_parameters:821 call_iqxy += "\n#define HAVE_THETA"822 clear_iqxy += "\n#undef HAVE_THETA"823 if partable.is_asymmetric:824 call_iqxy += "\n#define HAVE_PSI"825 clear_iqxy += "\n#undef HAVE_PSI"826 827 761 828 762 magpars = [k-2 for k, p in enumerate(partable.call_parameters) -
sasmodels/kernel_header.c
r108e70e r8698a0d 150 150 inline double cube(double x) { return x*x*x; } 151 151 inline double sas_sinx_x(double x) { return x==0 ? 1.0 : sin(x)/x; } 152 153 // CRUFT: support old style models with orientation received qx, qy and angles154 155 // To rotate from the canonical position to theta, phi, psi, first rotate by156 // psi about the major axis, oriented along z, which is a rotation in the157 // detector plane xy. Next rotate by theta about the y axis, aligning the major158 // axis in the xz plane. Finally, rotate by phi in the detector plane xy.159 // To compute the scattering, undo these rotations in reverse order:160 // rotate in xy by -phi, rotate in xz by -theta, rotate in xy by -psi161 // The returned q is the length of the q vector and (xhat, yhat, zhat) is a unit162 // vector in the q direction.163 // To change between counterclockwise and clockwise rotation, change the164 // sign of phi and psi.165 166 #if 1167 //think cos(theta) should be sin(theta) in new coords, RKH 11Jan2017168 #define ORIENT_SYMMETRIC(qx, qy, theta, phi, q, sn, cn) do { \169 SINCOS(phi*M_PI_180, sn, cn); \170 q = sqrt(qx*qx + qy*qy); \171 cn = (q==0. ? 1.0 : (cn*qx + sn*qy)/q * sin(theta*M_PI_180)); \172 sn = sqrt(1 - cn*cn); \173 } while (0)174 #else175 // SasView 3.x definition of orientation176 #define ORIENT_SYMMETRIC(qx, qy, theta, phi, q, sn, cn) do { \177 SINCOS(theta*M_PI_180, sn, cn); \178 q = sqrt(qx*qx + qy*qy);\179 cn = (q==0. ? 1.0 : (cn*cos(phi*M_PI_180)*qx + sn*qy)/q); \180 sn = sqrt(1 - cn*cn); \181 } while (0)182 #endif183 184 #if 1185 #define ORIENT_ASYMMETRIC(qx, qy, theta, phi, psi, q, xhat, yhat, zhat) do { \186 q = sqrt(qx*qx + qy*qy); \187 const double qxhat = qx/q; \188 const double qyhat = qy/q; \189 double sin_theta, cos_theta; \190 double sin_phi, cos_phi; \191 double sin_psi, cos_psi; \192 SINCOS(theta*M_PI_180, sin_theta, cos_theta); \193 SINCOS(phi*M_PI_180, sin_phi, cos_phi); \194 SINCOS(psi*M_PI_180, sin_psi, cos_psi); \195 xhat = qxhat*(-sin_phi*sin_psi + cos_theta*cos_phi*cos_psi) \196 + qyhat*( cos_phi*sin_psi + cos_theta*sin_phi*cos_psi); \197 yhat = qxhat*(-sin_phi*cos_psi - cos_theta*cos_phi*sin_psi) \198 + qyhat*( cos_phi*cos_psi - cos_theta*sin_phi*sin_psi); \199 zhat = qxhat*(-sin_theta*cos_phi) \200 + qyhat*(-sin_theta*sin_phi); \201 } while (0)202 #else203 // SasView 3.x definition of orientation204 #define ORIENT_ASYMMETRIC(qx, qy, theta, phi, psi, q, cos_alpha, cos_mu, cos_nu) do { \205 q = sqrt(qx*qx + qy*qy); \206 const double qxhat = qx/q; \207 const double qyhat = qy/q; \208 double sin_theta, cos_theta; \209 double sin_phi, cos_phi; \210 double sin_psi, cos_psi; \211 SINCOS(theta*M_PI_180, sin_theta, cos_theta); \212 SINCOS(phi*M_PI_180, sin_phi, cos_phi); \213 SINCOS(psi*M_PI_180, sin_psi, cos_psi); \214 cos_alpha = cos_theta*cos_phi*qxhat + sin_theta*qyhat; \215 cos_mu = (-sin_theta*cos_psi*cos_phi - sin_psi*sin_phi)*qxhat + cos_theta*cos_psi*qyhat; \216 cos_nu = (-cos_phi*sin_psi*sin_theta + sin_phi*cos_psi)*qxhat + sin_psi*cos_theta*qyhat; \217 } while (0)218 #endif -
sasmodels/kernel_iq.c
rec8d4ac r6aee3ab 31 31 // CALL_IQ_AC(qa, qc, table) : call the Iqxy function for symmetric shapes 32 32 // CALL_IQ_ABC(qa, qc, table) : call the Iqxy function for asymmetric shapes 33 // CALL_IQ_XY(qx, qy, table) : call the Iqxy function for arbitrary models34 33 // INVALID(table) : test if the current point is feesible to calculate. This 35 34 // will be defined in the kernel definition file. … … 174 173 static double 175 174 qac_apply( 176 QACRotation *rotation,175 QACRotation rotation, 177 176 double qx, double qy, 178 177 double *qa_out, double *qc_out) 179 178 { 180 const double dqc = rotation ->R31*qx + rotation->R32*qy;179 const double dqc = rotation.R31*qx + rotation.R32*qy; 181 180 // Indirect calculation of qab, from qab^2 = |q|^2 - qc^2 182 181 const double dqa = sqrt(-dqc*dqc + qx*qx + qy*qy); … … 247 246 static double 248 247 qabc_apply( 249 QABCRotation *rotation,248 QABCRotation rotation, 250 249 double qx, double qy, 251 250 double *qa_out, double *qb_out, double *qc_out) 252 251 { 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;252 *qa_out = rotation.R11*qx + rotation.R12*qy; 253 *qb_out = rotation.R21*qx + rotation.R22*qy; 254 *qc_out = rotation.R31*qx + rotation.R32*qy; 256 255 } 257 256 … … 454 453 // theta, phi, dtheta, dphi are defined below in projection to avoid repeated code. 455 454 #define BUILD_ROTATION() qac_rotation(&rotation, theta, phi, dtheta, dphi); 456 #define APPLY_ROTATION() qac_apply( &rotation, qx, qy, &qa, &qc)455 #define APPLY_ROTATION() qac_apply(rotation, qx, qy, &qa, &qc) 457 456 #define CALL_KERNEL() CALL_IQ_AC(qa, qc, local_values.table) 458 457 … … 468 467 local_values.table.psi = 0.; 469 468 #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)469 #define APPLY_ROTATION() qabc_apply(rotation, qx, qy, &qa, &qb, &qc) 471 470 #define CALL_KERNEL() CALL_IQ_ABC(qa, qb, qc, local_values.table) 472 #elif defined(CALL_IQ_XY) 473 // direct call to qx,qy calculator 474 double qx, qy; 475 #define FETCH_Q() do { qx = q[2*q_index]; qy = q[2*q_index+1]; } while (0) 476 #define BUILD_ROTATION() do {} while(0) 477 #define APPLY_ROTATION() do {} while(0) 478 #define CALL_KERNEL() CALL_IQ_XY(qx, qy, local_values.table) 479 #endif 480 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 471 #endif 472 473 // Doing jitter projection code outside the previous if block so that we don't 474 // need to repeat the identical logic in the IQ_AC and IQ_ABC branches. This 475 // will become more important if we implement more projections, or more 476 // complicated projections. 477 #if defined(CALL_IQ) || defined(CALL_IQ_A) 486 478 #define APPLY_PROJECTION() const double weight=weight0 487 #elif defined(CALL_IQ_XY) // pass orientation to the model 488 // CRUFT: support oriented model which define Iqxy rather than Iqac or Iqabc 489 // Need to plug the values for the orientation angles back into parameter 490 // table in case they were overridden by the orientation offset. This 491 // means that orientation dispersity will not work for these models, but 492 // it was broken anyway, so no matter. Still want to provide Iqxy in case 493 // the user model wants full control of orientation/magnetism. 494 #if defined(HAVE_PSI) 495 const double theta = values[details->theta_par+2]; 496 const double phi = values[details->theta_par+3]; 497 const double psi = values[details->theta_par+4]; 498 double weight; 499 #define APPLY_PROJECTION() do { \ 500 local_values.table.theta = theta; \ 501 local_values.table.phi = phi; \ 502 local_values.table.psi = psi; \ 503 weight=weight0; \ 504 } while (0) 505 #elif defined(HAVE_THETA) 506 const double theta = values[details->theta_par+2]; 507 const double phi = values[details->theta_par+3]; 508 double weight; 509 #define APPLY_PROJECTION() do { \ 510 local_values.table.theta = theta; \ 511 local_values.table.phi = phi; \ 512 weight=weight0; \ 513 } while (0) 514 #else 515 #define APPLY_PROJECTION() const double weight=weight0 516 #endif 517 #else // apply jitter and view before calling the model 479 #else // !spherosymmetric projection 518 480 // Grab the "view" angles (theta, phi, psi) from the initial parameter table. 519 481 const double theta = values[details->theta_par+2]; … … 526 488 // we go through the mesh. 527 489 double dtheta, dphi, weight; 528 #if PROJECTION == 1 // equirectangular490 #if PROJECTION == 1 529 491 #define APPLY_PROJECTION() do { \ 530 492 dtheta = local_values.table.theta; \ … … 532 494 weight = fabs(cos(dtheta*M_PI_180)) * weight0; \ 533 495 } while (0) 534 #elif PROJECTION == 2 // sinusoidal496 #elif PROJECTION == 2 535 497 #define APPLY_PROJECTION() do { \ 536 498 dtheta = local_values.table.theta; \ … … 542 504 } while (0) 543 505 #endif 544 #endif // done defining APPLY_PROJECTION506 #endif // !spherosymmetric projection 545 507 546 508 // ** define looping macros ** -
sasmodels/kernelpy.py
r108e70e r2d81cfe 26 26 # pylint: enable=unused-import 27 27 28 logger = logging.getLogger(__name__)29 30 28 class PyModel(KernelModel): 31 29 """ … … 33 31 """ 34 32 def __init__(self, model_info): 35 # Make sure Iq isavailable and vectorized33 # Make sure Iq and Iqxy are available and vectorized 36 34 _create_default_functions(model_info) 37 35 self.info = model_info 38 36 self.dtype = np.dtype('d') 39 logg er.info("load python model " + self.info.name)37 logging.info("load python model " + self.info.name) 40 38 41 39 def make_kernel(self, q_vectors): 42 40 q_input = PyInput(q_vectors, dtype=F64) 43 return PyKernel(self.info, q_input) 41 kernel = self.info.Iqxy if q_input.is_2d else self.info.Iq 42 return PyKernel(kernel, self.info, q_input) 44 43 45 44 def release(self): … … 90 89 Callable SAS kernel. 91 90 92 *kernel* is the kernel object to call.91 *kernel* is the DllKernel object to call. 93 92 94 93 *model_info* is the module information … … 105 104 Call :meth:`release` when done with the kernel instance. 106 105 """ 107 def __init__(self, model_info, q_input):106 def __init__(self, kernel, model_info, q_input): 108 107 # type: (callable, ModelInfo, List[np.ndarray]) -> None 109 108 self.dtype = np.dtype('d') … … 111 110 self.q_input = q_input 112 111 self.res = np.empty(q_input.nq, q_input.dtype) 112 self.kernel = kernel 113 113 self.dim = '2d' if q_input.is_2d else '1d' 114 114 … … 159 159 # Generate a closure which calls the form_volume if it exists. 160 160 form_volume = model_info.form_volume 161 self._volume = ((lambda: form_volume(*volume_args)) if form_volume else162 (lambda: 1.0))161 self._volume = ((lambda: form_volume(*volume_args)) if form_volume 162 else (lambda: 1.0)) 163 163 164 164 def __call__(self, call_details, values, cutoff, magnetic): … … 261 261 any functions that are not already marked as vectorized. 262 262 """ 263 # Note: must call create_vector_Iq before create_vector_Iqxy264 263 _create_vector_Iq(model_info) 265 _create_vector_Iqxy(model_info) 264 _create_vector_Iqxy(model_info) # call create_vector_Iq() first 266 265 267 266 … … 281 280 model_info.Iq = vector_Iq 282 281 283 284 282 def _create_vector_Iqxy(model_info): 285 283 """ 286 284 Define Iqxy as a vector function if it exists, or default it from Iq(). 287 285 """ 288 Iq xy = getattr(model_info, 'Iqxy', None)286 Iq, Iqxy = model_info.Iq, model_info.Iqxy 289 287 if callable(Iqxy): 290 288 if not getattr(Iqxy, 'vectorized', False): … … 297 295 vector_Iqxy.vectorized = True 298 296 model_info.Iqxy = vector_Iqxy 299 el se:297 elif callable(Iq): 300 298 #print("defaulting Iqxy") 301 299 # Iq is vectorized because create_vector_Iq was already called. 302 Iq = model_info.Iq303 300 def default_Iqxy(qx, qy, *args): 304 301 """ -
sasmodels/modelinfo.py
r108e70e r2d81cfe 37 37 38 38 # assumptions about common parameters exist throughout the code, such as: 39 # (1) kernel functions Iq, Iqxy, Iqac, Iqabc,form_volume, ... don't see them39 # (1) kernel functions Iq, Iqxy, form_volume, ... don't see them 40 40 # (2) kernel drivers assume scale is par[0] and background is par[1] 41 41 # (3) mixture models drop the background on components and replace the scale … … 256 256 257 257 *type* indicates how the parameter will be used. "volume" parameters 258 will be used in all functions. "orientation" parameters are not passed,259 but will be used to convert from *qx*, *qy* to *qa*, *qb*, *qc* in calls to260 *I qxy* and *Imagnetic*. If *type* is the empty string, the parameter will258 will be used in all functions. "orientation" parameters will be used 259 in *Iqxy* and *Imagnetic*. "magnetic* parameters will be used in 260 *Imagnetic* only. If *type* is the empty string, the parameter will 261 261 be used in all of *Iq*, *Iqxy* and *Imagnetic*. "sld" parameters 262 262 can automatically be promoted to magnetic parameters, each of which … … 386 386 with vector parameter p sent as p[]. 387 387 388 * [removed] *iqxy_parameters* is the list of parameters to the Iqxy(qx, qy, ...) 389 function, with vector parameter p sent as p[]. 390 388 391 * *form_volume_parameters* is the list of parameters to the form_volume(...) 389 392 function, with vector parameter p sent as p[]. … … 440 443 self.iq_parameters = [p for p in self.kernel_parameters 441 444 if p.type not in ('orientation', 'magnetic')] 442 self.orientation_parameters = [p for p in self.kernel_parameters 443 if p.type == 'orientation'] 445 # note: orientation no longer sent to Iqxy, so its the same as 446 #self.iqxy_parameters = [p for p in self.kernel_parameters 447 # if p.type != 'magnetic'] 444 448 self.form_volume_parameters = [p for p in self.kernel_parameters 445 449 if p.type == 'volume'] … … 486 490 if p.type != 'orientation': 487 491 raise TypeError("psi must be an orientation parameter") 488 elif p.type == 'orientation':489 raise TypeError("only theta, phi and psi can be orientation parameters")490 492 if theta >= 0 and phi >= 0: 491 last_par = len(self.kernel_parameters) - 1492 493 if phi != theta+1: 493 494 raise TypeError("phi must follow theta") 494 495 if psi >= 0 and psi != phi+1: 495 496 raise TypeError("psi must follow phi") 496 #if (psi >= 0 and psi != last_par) or (psi < 0 and phi != last_par):497 # raise TypeError("orientation parameters must appear at the "498 # "end of the parameter table")499 497 elif theta >= 0 or phi >= 0 or psi >= 0: 500 498 raise TypeError("oriented shapes must have both theta and phi and maybe psi") … … 717 715 718 716 719 #: Set of variables defined in the model that might contain C code720 C_SYMBOLS = ['Imagnetic', 'Iq', 'Iqxy', 'Iqac', 'Iqabc', 'form_volume', 'c_code']721 722 717 def _find_source_lines(model_info, kernel_module): 723 718 # type: (ModelInfo, ModuleType) -> None … … 725 720 Identify the location of the C source inside the model definition file. 726 721 727 This code runs through the source of the kernel module looking for lines 728 that contain C code (because it is a c function definition). Clearly 729 there are all sorts of reasons why this might not work (e.g., code 730 commented out in a triple-quoted line block, code built using string 731 concatenation, code defined in the branch of an 'if' block, code imported 732 from another file), but it should work properly in the 95% case, and for 733 the remainder, getting the incorrect line number will merely be 734 inconvenient. 735 """ 736 # Only need line numbers if we are creating a C module and the C symbols 737 # are defined. 738 if (callable(model_info.Iq) 739 or not any(hasattr(model_info, s) for s in C_SYMBOLS)): 722 This code runs through the source of the kernel module looking for 723 lines that start with 'Iq', 'Iqxy' or 'form_volume'. Clearly there are 724 all sorts of reasons why this might not work (e.g., code commented out 725 in a triple-quoted line block, code built using string concatenation, 726 or code defined in the branch of an 'if' block), but it should work 727 properly in the 95% case, and getting the incorrect line number will 728 be harmless. 729 """ 730 # Check if we need line numbers at all 731 if callable(model_info.Iq): 732 return None 733 734 if (model_info.Iq is None 735 and model_info.Iqxy is None 736 and model_info.Imagnetic is None 737 and model_info.form_volume is None): 740 738 return 741 739 742 # load the module source if we can740 # find the defintion lines for the different code blocks 743 741 try: 744 742 source = inspect.getsource(kernel_module) 745 743 except IOError: 746 744 return 747 748 # look for symbol at the start of the line 749 for lineno, line in enumerate(source.split('\n')): 750 for name in C_SYMBOLS: 751 if line.startswith(name): 752 # Add 1 since some compilers complain about "#line 0" 753 model_info.lineno[name] = lineno + 1 754 break 745 for k, v in enumerate(source.split('\n')): 746 if v.startswith('Imagnetic'): 747 model_info._Imagnetic_line = k+1 748 elif v.startswith('Iqxy'): 749 model_info._Iqxy_line = k+1 750 elif v.startswith('Iq'): 751 model_info._Iq_line = k+1 752 elif v.startswith('form_volume'): 753 model_info._form_volume_line = k+1 754 755 755 756 756 def make_model_info(kernel_module): … … 761 761 Fill in default values for parts of the module that are not provided. 762 762 763 Note: vectorized Iq and Iq ac/Iqabcfunctions will be created for python763 Note: vectorized Iq and Iqxy functions will be created for python 764 764 models when the model is first called, not when the model is loaded. 765 765 """ … … 790 790 info.profile_axes = getattr(kernel_module, 'profile_axes', ['x', 'y']) 791 791 info.source = getattr(kernel_module, 'source', []) 792 info.c_code = getattr(kernel_module, 'c_code', None)793 792 # TODO: check the structure of the tests 794 793 info.tests = getattr(kernel_module, 'tests', []) … … 798 797 info.Iq = getattr(kernel_module, 'Iq', None) # type: ignore 799 798 info.Iqxy = getattr(kernel_module, 'Iqxy', None) # type: ignore 800 info.Iqac = getattr(kernel_module, 'Iqac', None) # type: ignore801 info.Iqabc = getattr(kernel_module, 'Iqabc', None) # type: ignore802 799 info.Imagnetic = getattr(kernel_module, 'Imagnetic', None) # type: ignore 803 800 info.profile = getattr(kernel_module, 'profile', None) # type: ignore … … 814 811 info.hidden = getattr(kernel_module, 'hidden', None) # type: ignore 815 812 816 if callable(info.Iq) and parameters.has_2d:817 raise ValueError("oriented python models not supported")818 819 info.lineno = {}820 813 _find_source_lines(info, kernel_module) 821 814 … … 831 824 832 825 The structure should be mostly static, other than the delayed definition 833 of *Iq* , *Iqac* and *Iqabc* if they need to be defined.826 of *Iq* and *Iqxy* if they need to be defined. 834 827 """ 835 828 #: Full path to the file defining the kernel, if any. … … 913 906 structure_factor = None # type: bool 914 907 #: List of C source files used to define the model. The source files 915 #: should define the *Iq* function, and possibly *Iq ac* or *Iqabc* if the916 #: model defines orientation parameters. Files containing the most basic917 #: functions must appear first in the list, followed by the files that918 #: use those functions. Form factors are indicated by providing919 #: an:attr:`ER` function.908 #: should define the *Iq* function, and possibly *Iqxy*, though a default 909 #: *Iqxy = Iq(sqrt(qx**2+qy**2)* will be created if no *Iqxy* is provided. 910 #: Files containing the most basic functions must appear first in the list, 911 #: followed by the files that use those functions. Form factors are 912 #: indicated by providing a :attr:`ER` function. 920 913 source = None # type: List[str] 921 914 #: The set of tests that must pass. The format of the tests is described … … 942 935 #: See :attr:`ER` for details on the parameters. 943 936 VR = None # type: Optional[Callable[[np.ndarray], Tuple[np.ndarray, np.ndarray]]] 944 #: Arbitrary C code containing supporting functions, etc., to be inserted945 #: after everything in source. This can include Iq and Iqxy functions with946 #: the full function signature, including all parameters.947 c_code = None948 937 #: Returns the form volume for python-based models. Form volume is needed 949 938 #: for volume normalization in the polydispersity integral. If no … … 966 955 #: include the decimal point. See :mod:`generate` for more details. 967 956 Iq = None # type: Union[None, str, Callable[[np.ndarray], np.ndarray]] 968 #: Returns *I(qab, qc, a, b, ...)*. The interface follows :attr:`Iq`. 969 Iqac = None # type: Union[None, str, Callable[[np.ndarray], np.ndarray]] 970 #: Returns *I(qa, qb, qc, a, b, ...)*. The interface follows :attr:`Iq`. 971 Iqabc = None # type: Union[None, str, Callable[[np.ndarray], np.ndarray]] 957 #: Returns *I(qx, qy, a, b, ...)*. The interface follows :attr:`Iq`. 958 Iqxy = None # type: Union[None, str, Callable[[np.ndarray], np.ndarray]] 972 959 #: Returns *I(qx, qy, a, b, ...)*. The interface follows :attr:`Iq`. 973 960 Imagnetic = None # type: Union[None, str, Callable[[np.ndarray], np.ndarray]] … … 985 972 #: Returns a random parameter set for the model 986 973 random = None # type: Optional[Callable[[], Dict[str, float]]] 987 #: Line numbers for symbols defining C code 988 lineno = None # type: Dict[str, int] 974 975 # line numbers within the python file for bits of C source, if defined 976 # NB: some compilers fail with a "#line 0" directive, so default to 1. 977 _Imagnetic_line = 1 978 _Iqxy_line = 1 979 _Iq_line = 1 980 _form_volume_line = 1 981 989 982 990 983 def __init__(self): -
sasmodels/models/_spherepy.py
r108e70e ref07e95 88 88 Iq.vectorized = True # Iq accepts an array of q values 89 89 90 def Iqxy(qx, qy, sld, sld_solvent, radius): 91 return Iq(sqrt(qx ** 2 + qy ** 2), sld, sld_solvent, radius) 92 Iqxy.vectorized = True # Iqxy accepts arrays of qx, qy values 93 90 94 def sesans(z, sld, sld_solvent, radius): 91 95 """ -
sasmodels/models/barbell.c
r108e70e rbecded3 23 23 const double qab_r = radius_bell*qab; // Q*R*sin(theta) 24 24 double total = 0.0; 25 for (int i = 0; i < GAUSS_N; i++){26 const double t = G AUSS_Z[i]*zm + zb;25 for (int i = 0; i < 76; i++){ 26 const double t = Gauss76Z[i]*zm + zb; 27 27 const double radical = 1.0 - t*t; 28 28 const double bj = sas_2J1x_x(qab_r*sqrt(radical)); 29 29 const double Fq = cos(m*t + b) * radical * bj; 30 total += G AUSS_W[i] * Fq;30 total += Gauss76Wt[i] * Fq; 31 31 } 32 32 // translate dx in [-1,1] to dx in [lower,upper] … … 73 73 const double zb = M_PI_4; 74 74 double total = 0.0; 75 for (int i = 0; i < GAUSS_N; i++){76 const double alpha= G AUSS_Z[i]*zm + zb;75 for (int i = 0; i < 76; i++){ 76 const double alpha= Gauss76Z[i]*zm + zb; 77 77 double sin_alpha, cos_alpha; // slots to hold sincos function output 78 78 SINCOS(alpha, sin_alpha, cos_alpha); 79 79 const double Aq = _fq(q*sin_alpha, q*cos_alpha, h, radius_bell, radius, half_length); 80 total += G AUSS_W[i] * Aq * Aq * sin_alpha;80 total += Gauss76Wt[i] * Aq * Aq * sin_alpha; 81 81 } 82 82 // translate dx in [-1,1] to dx in [lower,upper] … … 90 90 91 91 static double 92 Iq ac(double qab, double qc,92 Iqxy(double qab, double qc, 93 93 double sld, double solvent_sld, 94 94 double radius_bell, double radius, double length) -
sasmodels/models/bcc_paracrystal.c
r108e70e rea60e08 81 81 82 82 double outer_sum = 0.0; 83 for(int i=0; i< GAUSS_N; i++) {83 for(int i=0; i<150; i++) { 84 84 double inner_sum = 0.0; 85 const double theta = G AUSS_Z[i]*theta_m + theta_b;85 const double theta = Gauss150Z[i]*theta_m + theta_b; 86 86 double sin_theta, cos_theta; 87 87 SINCOS(theta, sin_theta, cos_theta); 88 88 const double qc = q*cos_theta; 89 89 const double qab = q*sin_theta; 90 for(int j=0;j< GAUSS_N;j++) {91 const double phi = G AUSS_Z[j]*phi_m + phi_b;90 for(int j=0;j<150;j++) { 91 const double phi = Gauss150Z[j]*phi_m + phi_b; 92 92 double sin_phi, cos_phi; 93 93 SINCOS(phi, sin_phi, cos_phi); … … 95 95 const double qb = qab*sin_phi; 96 96 const double form = bcc_Zq(qa, qb, qc, dnn, d_factor); 97 inner_sum += G AUSS_W[j] * form;97 inner_sum += Gauss150Wt[j] * form; 98 98 } 99 99 inner_sum *= phi_m; // sum(f(x)dx) = sum(f(x)) dx 100 outer_sum += G AUSS_W[i] * inner_sum * sin_theta;100 outer_sum += Gauss150Wt[i] * inner_sum * sin_theta; 101 101 } 102 102 outer_sum *= theta_m; … … 107 107 108 108 109 static double Iq abc(double qa, double qb, double qc,109 static double Iqxy(double qa, double qb, double qc, 110 110 double dnn, double d_factor, double radius, 111 111 double sld, double solvent_sld) -
sasmodels/models/capped_cylinder.c
r108e70e rbecded3 30 30 const double qab_r = radius_cap*qab; // Q*R*sin(theta) 31 31 double total = 0.0; 32 for (int i=0; i< GAUSS_N;i++) {33 const double t = G AUSS_Z[i]*zm + zb;32 for (int i=0; i<76 ;i++) { 33 const double t = Gauss76Z[i]*zm + zb; 34 34 const double radical = 1.0 - t*t; 35 35 const double bj = sas_2J1x_x(qab_r*sqrt(radical)); 36 36 const double Fq = cos(m*t + b) * radical * bj; 37 total += G AUSS_W[i] * Fq;37 total += Gauss76Wt[i] * Fq; 38 38 } 39 39 // translate dx in [-1,1] to dx in [lower,upper] … … 95 95 const double zb = M_PI_4; 96 96 double total = 0.0; 97 for (int i=0; i< GAUSS_N;i++) {98 const double theta = G AUSS_Z[i]*zm + zb;97 for (int i=0; i<76 ;i++) { 98 const double theta = Gauss76Z[i]*zm + zb; 99 99 double sin_theta, cos_theta; // slots to hold sincos function output 100 100 SINCOS(theta, sin_theta, cos_theta); … … 103 103 const double Aq = _fq(qab, qc, h, radius_cap, radius, half_length); 104 104 // scale by sin_theta for spherical coord integration 105 total += G AUSS_W[i] * Aq * Aq * sin_theta;105 total += Gauss76Wt[i] * Aq * Aq * sin_theta; 106 106 } 107 107 // translate dx in [-1,1] to dx in [lower,upper] … … 115 115 116 116 static double 117 Iq ac(double qab, double qc,117 Iqxy(double qab, double qc, 118 118 double sld, double solvent_sld, double radius, 119 119 double radius_cap, double length) -
sasmodels/models/core_shell_bicelle.c
r108e70e rbecded3 52 52 53 53 double total = 0.0; 54 for(int i=0;i< GAUSS_N;i++) {55 double theta = (G AUSS_Z[i] + 1.0)*uplim;54 for(int i=0;i<N_POINTS_76;i++) { 55 double theta = (Gauss76Z[i] + 1.0)*uplim; 56 56 double sin_theta, cos_theta; // slots to hold sincos function output 57 57 SINCOS(theta, sin_theta, cos_theta); 58 58 double fq = bicelle_kernel(q*sin_theta, q*cos_theta, radius, thick_radius, thick_face, 59 59 halflength, sld_core, sld_face, sld_rim, sld_solvent); 60 total += G AUSS_W[i]*fq*fq*sin_theta;60 total += Gauss76Wt[i]*fq*fq*sin_theta; 61 61 } 62 62 … … 67 67 68 68 static double 69 Iq ac(double qab, double qc,69 Iqxy(double qab, double qc, 70 70 double radius, 71 71 double thick_rim, -
sasmodels/models/core_shell_bicelle_elliptical.c
r108e70e r82592da 37 37 //initialize integral 38 38 double outer_sum = 0.0; 39 for(int i=0;i< GAUSS_N;i++) {39 for(int i=0;i<76;i++) { 40 40 //setup inner integral over the ellipsoidal cross-section 41 41 //const double va = 0.0; 42 42 //const double vb = 1.0; 43 //const double cos_theta = ( G AUSS_Z[i]*(vb-va) + va + vb )/2.0;44 const double cos_theta = ( G AUSS_Z[i] + 1.0 )/2.0;43 //const double cos_theta = ( Gauss76Z[i]*(vb-va) + va + vb )/2.0; 44 const double cos_theta = ( Gauss76Z[i] + 1.0 )/2.0; 45 45 const double sin_theta = sqrt(1.0 - cos_theta*cos_theta); 46 46 const double qab = q*sin_theta; … … 49 49 const double si2 = sas_sinx_x((halfheight+thick_face)*qc); 50 50 double inner_sum=0.0; 51 for(int j=0;j< GAUSS_N;j++) {51 for(int j=0;j<76;j++) { 52 52 //76 gauss points for the inner integral (WAS 20 points,so this may make unecessarily slow, but playing safe) 53 53 // inner integral limits 54 54 //const double vaj=0.0; 55 55 //const double vbj=M_PI; 56 //const double phi = ( G AUSS_Z[j]*(vbj-vaj) + vaj + vbj )/2.0;57 const double phi = ( G AUSS_Z[j] +1.0)*M_PI_2;56 //const double phi = ( Gauss76Z[j]*(vbj-vaj) + vaj + vbj )/2.0; 57 const double phi = ( Gauss76Z[j] +1.0)*M_PI_2; 58 58 const double rr = sqrt(r2A - r2B*cos(phi)); 59 59 const double be1 = sas_2J1x_x(rr*qab); … … 61 61 const double fq = dr1*si1*be1 + dr2*si2*be2 + dr3*si2*be1; 62 62 63 inner_sum += G AUSS_W[j] * fq * fq;63 inner_sum += Gauss76Wt[j] * fq * fq; 64 64 } 65 65 //now calculate outer integral 66 outer_sum += G AUSS_W[i] * inner_sum;66 outer_sum += Gauss76Wt[i] * inner_sum; 67 67 } 68 68 … … 71 71 72 72 static double 73 Iq abc(double qa, double qb, double qc,73 Iqxy(double qa, double qb, double qc, 74 74 double r_minor, 75 75 double x_core, -
sasmodels/models/core_shell_bicelle_elliptical_belt_rough.c
r108e70e r82592da 7 7 double length) 8 8 { 9 return M_PI*( (r_minor + thick_rim)*(r_minor*x_core + thick_rim)* length + 9 return M_PI*( (r_minor + thick_rim)*(r_minor*x_core + thick_rim)* length + 10 10 square(r_minor)*x_core*2.0*thick_face ); 11 11 } … … 47 47 //initialize integral 48 48 double outer_sum = 0.0; 49 for(int i=0;i< GAUSS_N;i++) {49 for(int i=0;i<76;i++) { 50 50 //setup inner integral over the ellipsoidal cross-section 51 51 // since we generate these lots of times, why not store them somewhere? 52 //const double cos_alpha = ( G AUSS_Z[i]*(vb-va) + va + vb )/2.0;53 const double cos_alpha = ( G AUSS_Z[i] + 1.0 )/2.0;52 //const double cos_alpha = ( Gauss76Z[i]*(vb-va) + va + vb )/2.0; 53 const double cos_alpha = ( Gauss76Z[i] + 1.0 )/2.0; 54 54 const double sin_alpha = sqrt(1.0 - cos_alpha*cos_alpha); 55 55 double inner_sum=0; … … 58 58 si1 = sas_sinx_x(sinarg1); 59 59 si2 = sas_sinx_x(sinarg2); 60 for(int j=0;j< GAUSS_N;j++) {60 for(int j=0;j<76;j++) { 61 61 //76 gauss points for the inner integral (WAS 20 points,so this may make unecessarily slow, but playing safe) 62 //const double beta = ( G AUSS_Z[j]*(vbj-vaj) + vaj + vbj )/2.0;63 const double beta = ( G AUSS_Z[j] +1.0)*M_PI_2;62 //const double beta = ( Gauss76Z[j]*(vbj-vaj) + vaj + vbj )/2.0; 63 const double beta = ( Gauss76Z[j] +1.0)*M_PI_2; 64 64 const double rr = sqrt(r2A - r2B*cos(beta)); 65 65 double besarg1 = q*rr*sin_alpha; … … 67 67 be1 = sas_2J1x_x(besarg1); 68 68 be2 = sas_2J1x_x(besarg2); 69 inner_sum += G AUSS_W[j] *square(dr1*si1*be1 +69 inner_sum += Gauss76Wt[j] *square(dr1*si1*be1 + 70 70 dr2*si1*be2 + 71 71 dr3*si2*be1); 72 72 } 73 73 //now calculate outer integral 74 outer_sum += G AUSS_W[i] * inner_sum;74 outer_sum += Gauss76Wt[i] * inner_sum; 75 75 } 76 76 … … 79 79 80 80 static double 81 Iq abc(double qa, double qb, double qc,81 Iqxy(double qa, double qb, double qc, 82 82 double r_minor, 83 83 double x_core, … … 114 114 return 1.0e-4 * Aq*exp(-0.5*(square(qa) + square(qb) + square(qc) )*square(sigma)); 115 115 } 116 -
sasmodels/models/core_shell_bicelle_elliptical_belt_rough.py
r108e70e r110f69c 149 149 ["sld_rim", "1e-6/Ang^2", 1, [-inf, inf], "sld", "Cylinder rim scattering length density"], 150 150 ["sld_solvent", "1e-6/Ang^2", 6, [-inf, inf], "sld", "Solvent scattering length density"], 151 ["sigma", "Ang", 0, [0, inf], "", "interfacial roughness"],152 151 ["theta", "degrees", 90.0, [-360, 360], "orientation", "cylinder axis to beam angle"], 153 152 ["phi", "degrees", 0, [-360, 360], "orientation", "rotation about beam"], 154 153 ["psi", "degrees", 0, [-360, 360], "orientation", "rotation about cylinder axis"], 154 ["sigma", "Ang", 0, [0, inf], "", "interfacial roughness"] 155 155 ] 156 156 -
sasmodels/models/core_shell_cylinder.c
r108e70e rbecded3 30 30 const double shell_vd = form_volume(radius,thickness,length) * (shell_sld-solvent_sld); 31 31 double total = 0.0; 32 for (int i=0; i< GAUSS_N;i++) {32 for (int i=0; i<76 ;i++) { 33 33 // translate a point in [-1,1] to a point in [0, pi/2] 34 //const double theta = ( G AUSS_Z[i]*(upper-lower) + upper + lower )/2.0;34 //const double theta = ( Gauss76Z[i]*(upper-lower) + upper + lower )/2.0; 35 35 double sin_theta, cos_theta; 36 const double theta = G AUSS_Z[i]*M_PI_4 + M_PI_4;36 const double theta = Gauss76Z[i]*M_PI_4 + M_PI_4; 37 37 SINCOS(theta, sin_theta, cos_theta); 38 38 const double qab = q*sin_theta; … … 40 40 const double fq = _cyl(core_vd, core_r*qab, core_h*qc) 41 41 + _cyl(shell_vd, shell_r*qab, shell_h*qc); 42 total += G AUSS_W[i] * fq * fq * sin_theta;42 total += Gauss76Wt[i] * fq * fq * sin_theta; 43 43 } 44 44 // translate dx in [-1,1] to dx in [lower,upper] … … 48 48 49 49 50 double Iq ac(double qab, double qc,50 double Iqxy(double qab, double qc, 51 51 double core_sld, 52 52 double shell_sld, -
sasmodels/models/core_shell_ellipsoid.c
r108e70e rbecded3 59 59 const double b = 0.5; 60 60 double total = 0.0; //initialize intergral 61 for(int i=0;i< GAUSS_N;i++) {62 const double cos_theta = G AUSS_Z[i]*m + b;61 for(int i=0;i<76;i++) { 62 const double cos_theta = Gauss76Z[i]*m + b; 63 63 const double sin_theta = sqrt(1.0 - cos_theta*cos_theta); 64 64 double fq = _cs_ellipsoid_kernel(q*sin_theta, q*cos_theta, … … 66 66 equat_shell, polar_shell, 67 67 sld_core_shell, sld_shell_solvent); 68 total += G AUSS_W[i] * fq * fq;68 total += Gauss76Wt[i] * fq * fq; 69 69 } 70 70 total *= m; … … 75 75 76 76 static double 77 Iq ac(double qab, double qc,77 Iqxy(double qab, double qc, 78 78 double radius_equat_core, 79 79 double x_core, -
sasmodels/models/core_shell_parallelepiped.c
re077231 rc69d6d6 1 // Set OVERLAPPING to 1 in order to fill in the edges of the box, with2 // c endcaps and b overlapping a. With the proper choice of parameters,3 // (setting rim slds to sld, core sld to solvent, rim thickness to thickness4 // and subtracting 2*thickness from length, this should match the hollow5 // rectangular prism.) Set it to 0 for the documented behaviour.6 #define OVERLAPPING 07 1 static double 8 2 form_volume(double length_a, double length_b, double length_c, 9 3 double thick_rim_a, double thick_rim_b, double thick_rim_c) 10 4 { 11 return 12 #if OVERLAPPING 13 // Hollow rectangular prism only includes the volume of the shell 14 // so uncomment the next line when comparing. Solid rectangular 15 // prism, or parallelepiped want filled cores, so comment when 16 // comparing. 17 //-length_a * length_b * length_c + 18 (length_a + 2.0*thick_rim_a) * 19 (length_b + 2.0*thick_rim_b) * 20 (length_c + 2.0*thick_rim_c); 21 #else 22 length_a * length_b * length_c + 23 2.0 * thick_rim_a * length_b * length_c + 24 2.0 * length_a * thick_rim_b * length_c + 25 2.0 * length_a * length_b * thick_rim_c; 26 #endif 5 //return length_a * length_b * length_c; 6 return length_a * length_b * length_c + 7 2.0 * thick_rim_a * length_b * length_c + 8 2.0 * thick_rim_b * length_a * length_c + 9 2.0 * thick_rim_c * length_a * length_b; 27 10 } 28 11 … … 41 24 double thick_rim_c) 42 25 { 43 // Code converted from functions CSPPKernel and CSParallelepiped in libCylinder.c 26 // Code converted from functions CSPPKernel and CSParallelepiped in libCylinder.c_scaled 44 27 // Did not understand the code completely, it should be rechecked (Miguel Gonzalez) 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) 28 //Code is rewritten,the code is compliant with Diva Singhs thesis now (Dirk Honecker) 47 29 48 const double half_q = 0.5*q;30 const double mu = 0.5 * q * length_b; 49 31 50 const double tA = length_a + 2.0*thick_rim_a; 51 const double tB = length_b + 2.0*thick_rim_b; 52 const double tC = length_c + 2.0*thick_rim_c; 32 //calculate volume before rescaling (in original code, but not used) 33 //double vol = form_volume(length_a, length_b, length_c, thick_rim_a, thick_rim_b, thick_rim_c); 34 //double vol = length_a * length_b * length_c + 35 // 2.0 * thick_rim_a * length_b * length_c + 36 // 2.0 * thick_rim_b * length_a * length_c + 37 // 2.0 * thick_rim_c * length_a * length_b; 53 38 54 // Scale factors 55 const double dr0 = (core_sld-solvent_sld); 56 const double drA = (arim_sld-solvent_sld); 57 const double drB = (brim_sld-solvent_sld); 58 const double drC = (crim_sld-solvent_sld); 39 // Scale sides by B 40 const double a_scaled = length_a / length_b; 41 const double c_scaled = length_c / length_b; 42 43 double ta = a_scaled + 2.0*thick_rim_a/length_b; // incorrect ta = (a_scaled + 2.0*thick_rim_a)/length_b; 44 double tb = 1+ 2.0*thick_rim_b/length_b; // incorrect tb = (a_scaled + 2.0*thick_rim_b)/length_b; 45 double tc = c_scaled + 2.0*thick_rim_c/length_b; //not present 46 47 double Vin = length_a * length_b * length_c; 48 //double Vot = (length_a * length_b * length_c + 49 // 2.0 * thick_rim_a * length_b * length_c + 50 // 2.0 * length_a * thick_rim_b * length_c + 51 // 2.0 * length_a * length_b * thick_rim_c); 52 double V1 = (2.0 * thick_rim_a * length_b * length_c); // incorrect V1 (aa*bb*cc+2*ta*bb*cc) 53 double V2 = (2.0 * length_a * thick_rim_b * length_c); // incorrect V2(aa*bb*cc+2*aa*tb*cc) 54 double V3 = (2.0 * length_a * length_b * thick_rim_c); //not present 55 56 // Scale factors (note that drC is not used later) 57 const double drho0 = (core_sld-solvent_sld); 58 const double drhoA = (arim_sld-solvent_sld); 59 const double drhoB = (brim_sld-solvent_sld); 60 const double drhoC = (crim_sld-solvent_sld); // incorrect const double drC_Vot = (crim_sld-solvent_sld)*Vot; 61 62 63 // Precompute scale factors for combining cross terms from the shape 64 const double scale23 = drhoA*V1; 65 const double scale14 = drhoB*V2; 66 const double scale24 = drhoC*V3; 67 const double scale11 = drho0*Vin; 68 const double scale12 = drho0*Vin - scale23 - scale14 - scale24; 59 69 60 70 // outer integral (with gauss points), integration limits = 0, 1 61 double outer_sum = 0; //initialize integral 62 for( int i=0; i<GAUSS_N; i++) { 63 const double cos_alpha = 0.5 * ( GAUSS_Z[i] + 1.0 ); 64 const double mu = half_q * sqrt(1.0-cos_alpha*cos_alpha); 71 double outer_total = 0; //initialize integral 65 72 66 // inner integral (with gauss points), integration limits = 0, pi/2 67 const double siC = length_c * sas_sinx_x(length_c * cos_alpha * half_q); 68 const double siCt = tC * sas_sinx_x(tC * cos_alpha * half_q); 69 double inner_sum = 0.0; 70 for(int j=0; j<GAUSS_N; j++) { 71 const double beta = 0.5 * ( GAUSS_Z[j] + 1.0 ); 72 double sin_beta, cos_beta; 73 SINCOS(M_PI_2*beta, sin_beta, cos_beta); 74 const double siA = length_a * sas_sinx_x(length_a * mu * sin_beta); 75 const double siB = length_b * sas_sinx_x(length_b * mu * cos_beta); 76 const double siAt = tA * sas_sinx_x(tA * mu * sin_beta); 77 const double siBt = tB * sas_sinx_x(tB * mu * cos_beta); 73 for( int i=0; i<76; i++) { 74 double sigma = 0.5 * ( Gauss76Z[i] + 1.0 ); 75 double mu_proj = mu * sqrt(1.0-sigma*sigma); 78 76 79 #if OVERLAPPING 80 const double f = dr0*siA*siB*siC81 + drA*(siAt-siA)*siB*siC82 + drB*siAt*(siBt-siB)*siC83 + drC*siAt*siBt*(siCt-siC);84 #else 85 const double f = dr0*siA*siB*siC86 + drA*(siAt-siA)*siB*siC87 + drB*siA*(siBt-siB)*siC88 + drC*siA*siB*(siCt-siC);89 #endif 77 // inner integral (with gauss points), integration limits = 0, 1 78 double inner_total = 0.0; 79 double inner_total_crim = 0.0; 80 for(int j=0; j<76; j++) { 81 const double uu = 0.5 * ( Gauss76Z[j] + 1.0 ); 82 double sin_uu, cos_uu; 83 SINCOS(M_PI_2*uu, sin_uu, cos_uu); 84 const double si1 = sas_sinx_x(mu_proj * sin_uu * a_scaled); 85 const double si2 = sas_sinx_x(mu_proj * cos_uu ); 86 const double si3 = sas_sinx_x(mu_proj * sin_uu * ta); 87 const double si4 = sas_sinx_x(mu_proj * cos_uu * tb); 90 88 91 inner_sum += GAUSS_W[j] * f * f; 89 // Expression in libCylinder.c (neither drC nor Vot are used) 90 const double form = scale12*si1*si2 + scale23*si2*si3 + scale14*si1*si4; 91 const double form_crim = scale11*si1*si2; 92 93 // correct FF : sum of square of phase factors 94 inner_total += Gauss76Wt[j] * form * form; 95 inner_total_crim += Gauss76Wt[j] * form_crim * form_crim; 92 96 } 93 inner_sum *= 0.5; 97 inner_total *= 0.5; 98 inner_total_crim *= 0.5; 94 99 // now sum up the outer integral 95 outer_sum += GAUSS_W[i] * inner_sum; 100 const double si = sas_sinx_x(mu * c_scaled * sigma); 101 const double si_crim = sas_sinx_x(mu * tc * sigma); 102 outer_total += Gauss76Wt[i] * (inner_total * si * si + inner_total_crim * si_crim * si_crim); 96 103 } 97 outer_ sum*= 0.5;104 outer_total *= 0.5; 98 105 99 106 //convert from [1e-12 A-1] to [cm-1] 100 return 1.0e-4 * outer_ sum;107 return 1.0e-4 * outer_total; 101 108 } 102 109 103 110 static double 104 Iq abc(double qa, double qb, double qc,111 Iqxy(double qa, double qb, double qc, 105 112 double core_sld, 106 113 double arim_sld, … … 121 128 const double drC = crim_sld-solvent_sld; 122 129 123 const double tA = length_a + 2.0*thick_rim_a;124 const double tB = length_b + 2.0*thick_rim_b;125 const double tC = length_c + 2.0*thick_rim_c;126 const double siA = length_a*sas_sinx_x(0.5*length_a*qa);127 const double siB = length_b*sas_sinx_x(0.5*length_b*qb);128 const double siC = length_c*sas_sinx_x(0.5*length_c*qc);129 const double siAt = tA*sas_sinx_x(0.5*tA*qa);130 const double siBt = tB*sas_sinx_x(0.5*tB*qb);131 const double siCt = tC*sas_sinx_x(0.5*tC*qc);130 double Vin = length_a * length_b * length_c; 131 double V1 = 2.0 * thick_rim_a * length_b * length_c; // incorrect V1(aa*bb*cc+2*ta*bb*cc) 132 double V2 = 2.0 * length_a * thick_rim_b * length_c; // incorrect V2(aa*bb*cc+2*aa*tb*cc) 133 double V3 = 2.0 * length_a * length_b * thick_rim_c; 134 // As for the 1D case, Vot is not used 135 //double Vot = (length_a * length_b * length_c + 136 // 2.0 * thick_rim_a * length_b * length_c + 137 // 2.0 * length_a * thick_rim_b * length_c + 138 // 2.0 * length_a * length_b * thick_rim_c); 132 139 133 #if OVERLAPPING 134 const double f = dr0*siA*siB*siC 135 + drA*(siAt-siA)*siB*siC 136 + drB*siAt*(siBt-siB)*siC 137 + drC*siAt*siBt*(siCt-siC); 138 #else 139 const double f = dr0*siA*siB*siC 140 + drA*(siAt-siA)*siB*siC 141 + drB*siA*(siBt-siB)*siC 142 + drC*siA*siB*(siCt-siC); 143 #endif 140 // The definitions of ta, tb, tc are not the same as in the 1D case because there is no 141 // the scaling by B. 142 double ta = length_a + 2.0*thick_rim_a; 143 double tb = length_b + 2.0*thick_rim_b; 144 double tc = length_c + 2.0*thick_rim_c; 145 //handle arg=0 separately, as sin(t)/t -> 1 as t->0 146 double siA = sas_sinx_x(0.5*length_a*qa); 147 double siB = sas_sinx_x(0.5*length_b*qb); 148 double siC = sas_sinx_x(0.5*length_c*qc); 149 double siAt = sas_sinx_x(0.5*ta*qa); 150 double siBt = sas_sinx_x(0.5*tb*qb); 151 double siCt = sas_sinx_x(0.5*tc*qc); 152 153 154 // f uses Vin, V1, V2, and V3 and it seems to have more sense than the value computed 155 // in the 1D code, but should be checked! 156 double f = ( dr0*siA*siB*siC*Vin 157 + drA*(siAt-siA)*siB*siC*V1 158 + drB*siA*(siBt-siB)*siC*V2 159 + drC*siA*siB*(siCt-siC)*V3); 144 160 145 161 return 1.0e-4 * f * f; -
sasmodels/models/core_shell_parallelepiped.py
r97be877 r2d81cfe 5 5 Calculates the form factor for a rectangular solid with a core-shell structure. 6 6 The thickness and the scattering length density of the shell or 7 "rim" can be different on each (pair) of faces. 7 "rim" can be different on each (pair) of faces. However at this time the 1D 8 calculation does **NOT** actually calculate a c face rim despite the presence 9 of the parameter. Some other aspects of the 1D calculation may be wrong. 10 11 .. note:: 12 This model was originally ported from NIST IGOR macros. However, it is not 13 yet fully understood by the SasView developers and is currently under review. 8 14 9 15 The form factor is normalized by the particle volume $V$ such that … … 15 21 where $\langle \ldots \rangle$ is an average over all possible orientations 16 22 of the rectangular solid. 23 17 24 18 25 The function calculated is the form factor of the rectangular solid below. … … 34 41 V = ABC + 2t_ABC + 2t_BAC + 2t_CAB 35 42 36 **meaning that there are "gaps" at the corners of the solid.** 43 **meaning that there are "gaps" at the corners of the solid.** Again note that 44 $t_C = 0$ currently. 37 45 38 46 The intensity calculated follows the :ref:`parallelepiped` model, with the 39 47 core-shell intensity being calculated as the square of the sum of the 40 amplitudes of the core and the slabs on the edges. 41 42 the scattering amplitude is computed for a particular orientation of the 43 core-shell parallelepiped with respect to the scattering vector and then 44 averaged over all possible orientations, where $\alpha$ is the angle between 45 the $z$ axis and the $C$ axis of the parallelepiped, $\beta$ is 46 the angle between projection of the particle in the $xy$ detector plane 47 and the $y$ axis. 48 amplitudes of the core and shell, in the same manner as a core-shell model. 48 49 49 50 .. math:: 50 51 51 F(Q) 52 &= (\rho_\text{core}-\rho_\text{solvent}) 53 S(Q_A, A) S(Q_B, B) S(Q_C, C) \\ 54 &+ (\rho_\text{A}-\rho_\text{solvent}) 55 \left[S(Q_A, A+2t_A) - S(Q_A, Q)\right] S(Q_B, B) S(Q_C, C) \\ 56 &+ (\rho_\text{B}-\rho_\text{solvent}) 57 S(Q_A, A) \left[S(Q_B, B+2t_B) - S(Q_B, B)\right] S(Q_C, C) \\ 58 &+ (\rho_\text{C}-\rho_\text{solvent}) 59 S(Q_A, A) S(Q_B, B) \left[S(Q_C, C+2t_C) - S(Q_C, C)\right] 60 61 with 62 63 .. math:: 64 65 S(Q, L) = L \frac{\sin \tfrac{1}{2} Q L}{\tfrac{1}{2} Q L} 66 67 and 68 69 .. math:: 70 71 Q_A &= \sin\alpha \sin\beta \\ 72 Q_B &= \sin\alpha \cos\beta \\ 73 Q_C &= \cos\alpha 74 75 76 where $\rho_\text{core}$, $\rho_\text{A}$, $\rho_\text{B}$ and $\rho_\text{C}$ 77 are the scattering length of the parallelepiped core, and the rectangular 78 slabs of thickness $t_A$, $t_B$ and $t_C$, respectively. $\rho_\text{solvent}$ 79 is the scattering length of the solvent. 52 F_{a}(Q,\alpha,\beta)= 53 \left[\frac{\sin(\tfrac{1}{2}Q(L_A+2t_A)\sin\alpha \sin\beta) 54 }{\tfrac{1}{2}Q(L_A+2t_A)\sin\alpha\sin\beta} 55 - \frac{\sin(\tfrac{1}{2}QL_A\sin\alpha \sin\beta) 56 }{\tfrac{1}{2}QL_A\sin\alpha \sin\beta} \right] 57 \left[\frac{\sin(\tfrac{1}{2}QL_B\sin\alpha \sin\beta) 58 }{\tfrac{1}{2}QL_B\sin\alpha \sin\beta} \right] 59 \left[\frac{\sin(\tfrac{1}{2}QL_C\sin\alpha \sin\beta) 60 }{\tfrac{1}{2}QL_C\sin\alpha \sin\beta} \right] 61 62 .. note:: 63 64 Why does t_B not appear in the above equation? 65 For the calculation of the form factor to be valid, the sides of the solid 66 MUST (perhaps not any more?) be chosen such that** $A < B < C$. 67 If this inequality is not satisfied, the model will not report an error, 68 but the calculation will not be correct and thus the result wrong. 80 69 81 70 FITTING NOTES 82 ~~~~~~~~~~~~~83 84 71 If the scale is set equal to the particle volume fraction, $\phi$, the returned 85 value is the scattered intensity per unit volume, $I(q) = \phi P(q)$. However, 86 **no interparticle interference effects are included in this calculation.** 72 value is the scattered intensity per unit volume, $I(q) = \phi P(q)$. 73 However, **no interparticle interference effects are included in this 74 calculation.** 87 75 88 76 There are many parameters in this model. Hold as many fixed as possible with 89 77 known values, or you will certainly end up at a solution that is unphysical. 90 78 79 Constraints must be applied during fitting to ensure that the inequality 80 $A < B < C$ is not violated. The calculation will not report an error, 81 but the results will not be correct. 82 91 83 The returned value is in units of |cm^-1|, on absolute scale. 92 84 93 85 NB: The 2nd virial coefficient of the core_shell_parallelepiped is calculated 94 86 based on the the averaged effective radius $(=\sqrt{(A+2t_A)(B+2t_B)/\pi})$ 95 and length $(C+2t_C)$ values, after appropriately sorting the three dimensions96 to give an oblate or prolate particle, to give an effective radius, 97 for $S(Q)$ when $P(Q) * S(Q)$ is applied.87 and length $(C+2t_C)$ values, after appropriately 88 sorting the three dimensions to give an oblate or prolate particle, to give an 89 effective radius, for $S(Q)$ when $P(Q) * S(Q)$ is applied. 98 90 99 91 For 2d data the orientation of the particle is required, described using 100 angles $\theta$, $\phi$ and $\Psi$ as in the diagrams below, for further 101 details of the calculation and angular dispersions see :ref:`orientation`.92 angles $\theta$, $\phi$ and $\Psi$ as in the diagrams below, for further details 93 of the calculation and angular dispersions see :ref:`orientation` . 102 94 The angle $\Psi$ is the rotational angle around the *long_c* axis. For example, 103 95 $\Psi = 0$ when the *short_b* axis is parallel to the *x*-axis of the detector. 104 105 For 2d, constraints must be applied during fitting to ensure that the106 inequality $A < B < C$ is not violated, and hence the correct definition107 of angles is preserved. The calculation will not report an error,108 but the results may be not correct.109 96 110 97 .. figure:: img/parallelepiped_angle_definition.png … … 127 114 Equations (1), (13-14). (in German) 128 115 .. [#] D Singh (2009). *Small angle scattering studies of self assembly in 129 lipid mixtures*, John s Hopkins University Thesis (2009) 223-225. `Available116 lipid mixtures*, John's Hopkins University Thesis (2009) 223-225. `Available 130 117 from Proquest <http://search.proquest.com/docview/304915826?accountid 131 118 =26379>`_ … … 136 123 * **Author:** NIST IGOR/DANSE **Date:** pre 2010 137 124 * **Converted to sasmodels by:** Miguel Gonzales **Date:** February 26, 2016 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. 125 * **Last Modified by:** Wojciech Potrzebowski **Date:** January 11, 2017 126 * **Currently Under review by:** Paul Butler 142 127 """ 143 128 … … 190 175 Return equivalent radius (ER) 191 176 """ 192 from .parallelepiped import ER as ER_p 193 194 a = length_a + 2*thick_rim_a 195 b = length_b + 2*thick_rim_b 196 c = length_c + 2*thick_rim_c 197 return ER_p(a, b, c) 177 178 # surface average radius (rough approximation) 179 surf_rad = sqrt((length_a + 2.0*thick_rim_a) * (length_b + 2.0*thick_rim_b) / pi) 180 181 height = length_c + 2.0*thick_rim_c 182 183 ddd = 0.75 * surf_rad * (2 * surf_rad * height + (height + surf_rad) * (height + pi * surf_rad)) 184 return 0.5 * (ddd) ** (1. / 3.) 198 185 199 186 # VR defaults to 1.0 … … 229 216 psi_pd=10, psi_pd_n=1) 230 217 231 # rkh 7/4/17 add random unit test for 2d, note make all params different, 232 # 2d values not tested against other codes or models 218 # rkh 7/4/17 add random unit test for 2d, note make all params different, 2d values not tested against other codes or models 233 219 if 0: # pak: model rewrite; need to update tests 234 220 qx, qy = 0.2 * cos(pi/6.), 0.2 * sin(pi/6.) -
sasmodels/models/cylinder.c
r108e70e rbecded3 21 21 22 22 double total = 0.0; 23 for (int i=0; i< GAUSS_N;i++) {24 const double theta = G AUSS_Z[i]*zm + zb;23 for (int i=0; i<76 ;i++) { 24 const double theta = Gauss76Z[i]*zm + zb; 25 25 double sin_theta, cos_theta; // slots to hold sincos function output 26 26 // theta (theta,phi) the projection of the cylinder on the detector plane 27 27 SINCOS(theta , sin_theta, cos_theta); 28 28 const double form = fq(q*sin_theta, q*cos_theta, radius, length); 29 total += G AUSS_W[i] * form * form * sin_theta;29 total += Gauss76Wt[i] * form * form * sin_theta; 30 30 } 31 31 // translate dx in [-1,1] to dx in [lower,upper] … … 45 45 46 46 static double 47 Iq ac(double qab, double qc,47 Iqxy(double qab, double qc, 48 48 double sld, 49 49 double solvent_sld, -
sasmodels/models/ellipsoid.c
r108e70e rbecded3 22 22 23 23 // translate a point in [-1,1] to a point in [0, 1] 24 // const double u = G AUSS_Z[i]*(upper-lower)/2 + (upper+lower)/2;24 // const double u = Gauss76Z[i]*(upper-lower)/2 + (upper+lower)/2; 25 25 const double zm = 0.5; 26 26 const double zb = 0.5; 27 27 double total = 0.0; 28 for (int i=0;i< GAUSS_N;i++) {29 const double u = G AUSS_Z[i]*zm + zb;28 for (int i=0;i<76;i++) { 29 const double u = Gauss76Z[i]*zm + zb; 30 30 const double r = radius_equatorial*sqrt(1.0 + u*u*v_square_minus_one); 31 31 const double f = sas_3j1x_x(q*r); 32 total += G AUSS_W[i] * f * f;32 total += Gauss76Wt[i] * f * f; 33 33 } 34 34 // translate dx in [-1,1] to dx in [lower,upper] … … 39 39 40 40 static double 41 Iq ac(double qab, double qc,41 Iqxy(double qab, double qc, 42 42 double sld, 43 43 double sld_solvent, -
sasmodels/models/elliptical_cylinder.c
r108e70e r82592da 22 22 //initialize integral 23 23 double outer_sum = 0.0; 24 for(int i=0;i< GAUSS_N;i++) {24 for(int i=0;i<76;i++) { 25 25 //setup inner integral over the ellipsoidal cross-section 26 const double cos_val = ( G AUSS_Z[i]*(vb-va) + va + vb )/2.0;26 const double cos_val = ( Gauss76Z[i]*(vb-va) + va + vb )/2.0; 27 27 const double sin_val = sqrt(1.0 - cos_val*cos_val); 28 28 //const double arg = radius_minor*sin_val; 29 29 double inner_sum=0; 30 for(int j=0;j<GAUSS_N;j++) { 31 const double theta = ( GAUSS_Z[j]*(vbj-vaj) + vaj + vbj )/2.0; 30 for(int j=0;j<76;j++) { 31 //20 gauss points for the inner integral, increase to 76, RKH 6Nov2017 32 const double theta = ( Gauss76Z[j]*(vbj-vaj) + vaj + vbj )/2.0; 32 33 const double r = sin_val*sqrt(rA - rB*cos(theta)); 33 34 const double be = sas_2J1x_x(q*r); 34 inner_sum += G AUSS_W[j] * be * be;35 inner_sum += Gauss76Wt[j] * be * be; 35 36 } 36 37 //now calculate the value of the inner integral … … 39 40 //now calculate outer integral 40 41 const double si = sas_sinx_x(q*0.5*length*cos_val); 41 outer_sum += G AUSS_W[i] * inner_sum * si * si;42 outer_sum += Gauss76Wt[i] * inner_sum * si * si; 42 43 } 43 44 outer_sum *= 0.5*(vb-va); … … 54 55 55 56 static double 56 Iq abc(double qa, double qb, double qc,57 Iqxy(double qa, double qb, double qc, 57 58 double radius_minor, double r_ratio, double length, 58 59 double sld, double solvent_sld) -
sasmodels/models/elliptical_cylinder.py
r2d81cfe r2d81cfe 121 121 # pylint: enable=bad-whitespace, line-too-long 122 122 123 source = ["lib/polevl.c", "lib/sas_J1.c", "lib/gauss76.c", "elliptical_cylinder.c"] 123 source = ["lib/polevl.c", "lib/sas_J1.c", "lib/gauss76.c", "lib/gauss20.c", 124 "elliptical_cylinder.c"] 124 125 125 126 demo = dict(scale=1, background=0, radius_minor=100, axis_ratio=1.5, length=400.0, -
sasmodels/models/fcc_paracrystal.c
r108e70e rf728001 53 53 54 54 double outer_sum = 0.0; 55 for(int i=0; i< GAUSS_N; i++) {55 for(int i=0; i<150; i++) { 56 56 double inner_sum = 0.0; 57 const double theta = G AUSS_Z[i]*theta_m + theta_b;57 const double theta = Gauss150Z[i]*theta_m + theta_b; 58 58 double sin_theta, cos_theta; 59 59 SINCOS(theta, sin_theta, cos_theta); 60 60 const double qc = q*cos_theta; 61 61 const double qab = q*sin_theta; 62 for(int j=0;j< GAUSS_N;j++) {63 const double phi = G AUSS_Z[j]*phi_m + phi_b;62 for(int j=0;j<150;j++) { 63 const double phi = Gauss150Z[j]*phi_m + phi_b; 64 64 double sin_phi, cos_phi; 65 65 SINCOS(phi, sin_phi, cos_phi); … … 67 67 const double qb = qab*sin_phi; 68 68 const double form = fcc_Zq(qa, qb, qc, dnn, d_factor); 69 inner_sum += G AUSS_W[j] * form;69 inner_sum += Gauss150Wt[j] * form; 70 70 } 71 71 inner_sum *= phi_m; // sum(f(x)dx) = sum(f(x)) dx 72 outer_sum += G AUSS_W[i] * inner_sum * sin_theta;72 outer_sum += Gauss150Wt[i] * inner_sum * sin_theta; 73 73 } 74 74 outer_sum *= theta_m; … … 80 80 81 81 82 static double Iq abc(double qa, double qb, double qc,82 static double Iqxy(double qa, double qb, double qc, 83 83 double dnn, double d_factor, double radius, 84 84 double sld, double solvent_sld) -
sasmodels/models/flexible_cylinder_elliptical.c
r74768cb r592343f 17 17 double sum=0.0; 18 18 19 for(int i=0;i< GAUSS_N;i++) {20 const double zi = ( G AUSS_Z[i] + 1.0 )*M_PI_4;19 for(int i=0;i<N_POINTS_76;i++) { 20 const double zi = ( Gauss76Z[i] + 1.0 )*M_PI_4; 21 21 double sn, cn; 22 22 SINCOS(zi, sn, cn); 23 23 const double arg = q*sqrt(a*a*sn*sn + b*b*cn*cn); 24 24 const double yyy = sas_2J1x_x(arg); 25 sum += G AUSS_W[i] * yyy * yyy;25 sum += Gauss76Wt[i] * yyy * yyy; 26 26 } 27 27 sum *= 0.5; -
sasmodels/models/hollow_cylinder.c
r108e70e rbecded3 38 38 39 39 double summ = 0.0; //initialize intergral 40 for (int i=0;i< GAUSS_N;i++) {41 const double cos_theta = 0.5*( G AUSS_Z[i] * (upper-lower) + lower + upper );40 for (int i=0;i<76;i++) { 41 const double cos_theta = 0.5*( Gauss76Z[i] * (upper-lower) + lower + upper ); 42 42 const double sin_theta = sqrt(1.0 - cos_theta*cos_theta); 43 43 const double form = _fq(q*sin_theta, q*cos_theta, 44 44 radius, thickness, length); 45 summ += G AUSS_W[i] * form * form;45 summ += Gauss76Wt[i] * form * form; 46 46 } 47 47 … … 52 52 53 53 static double 54 Iq ac(double qab, double qc,54 Iqxy(double qab, double qc, 55 55 double radius, double thickness, double length, 56 56 double sld, double solvent_sld) -
sasmodels/models/hollow_rectangular_prism.c
r108e70e r1e7b0db0 1 1 double form_volume(double length_a, double b2a_ratio, double c2a_ratio, double thickness); 2 double Iq(double q, double sld, double solvent_sld, double length_a, 2 double Iq(double q, double sld, double solvent_sld, double length_a, 3 3 double b2a_ratio, double c2a_ratio, double thickness); 4 4 … … 37 37 const double v2a = 0.0; 38 38 const double v2b = M_PI_2; //phi integration limits 39 40 double outer_sum = 0.0; 41 for(int i=0; i<76; i++) { 39 42 40 double outer_sum = 0.0; 41 for(int i=0; i<GAUSS_N; i++) { 42 43 const double theta = 0.5 * ( GAUSS_Z[i]*(v1b-v1a) + v1a + v1b ); 43 const double theta = 0.5 * ( Gauss76Z[i]*(v1b-v1a) + v1a + v1b ); 44 44 double sin_theta, cos_theta; 45 45 SINCOS(theta, sin_theta, cos_theta); … … 49 49 50 50 double inner_sum = 0.0; 51 for(int j=0; j< GAUSS_N; j++) {51 for(int j=0; j<76; j++) { 52 52 53 const double phi = 0.5 * ( G AUSS_Z[j]*(v2b-v2a) + v2a + v2b );53 const double phi = 0.5 * ( Gauss76Z[j]*(v2b-v2a) + v2a + v2b ); 54 54 double sin_phi, cos_phi; 55 55 SINCOS(phi, sin_phi, cos_phi); … … 66 66 const double AP2 = vol_core * termA2 * termB2 * termC2; 67 67 68 inner_sum += G AUSS_W[j] * square(AP1-AP2);68 inner_sum += Gauss76Wt[j] * square(AP1-AP2); 69 69 } 70 70 inner_sum *= 0.5 * (v2b-v2a); 71 71 72 outer_sum += G AUSS_W[i] * inner_sum * sin(theta);72 outer_sum += Gauss76Wt[i] * inner_sum * sin(theta); 73 73 } 74 74 outer_sum *= 0.5*(v1b-v1a); … … 84 84 return 1.0e-4 * delrho * delrho * form; 85 85 } 86 87 double Iqabc(double qa, double qb, double qc,88 double sld,89 double solvent_sld,90 double length_a,91 double b2a_ratio,92 double c2a_ratio,93 double thickness)94 {95 const double length_b = length_a * b2a_ratio;96 const double length_c = length_a * c2a_ratio;97 const double a_half = 0.5 * length_a;98 const double b_half = 0.5 * length_b;99 const double c_half = 0.5 * length_c;100 const double vol_total = length_a * length_b * length_c;101 const double vol_core = 8.0 * (a_half-thickness) * (b_half-thickness) * (c_half-thickness);102 103 // Amplitude AP from eqn. (13)104 105 const double termA1 = sas_sinx_x(qa * a_half);106 const double termA2 = sas_sinx_x(qa * (a_half-thickness));107 108 const double termB1 = sas_sinx_x(qb * b_half);109 const double termB2 = sas_sinx_x(qb * (b_half-thickness));110 111 const double termC1 = sas_sinx_x(qc * c_half);112 const double termC2 = sas_sinx_x(qc * (c_half-thickness));113 114 const double AP1 = vol_total * termA1 * termB1 * termC1;115 const double AP2 = vol_core * termA2 * termB2 * termC2;116 117 // Multiply by contrast^2. Factor corresponding to volume^2 cancels with previous normalization.118 const double delrho = sld - solvent_sld;119 120 // Convert from [1e-12 A-1] to [cm-1]121 return 1.0e-4 * square(delrho * (AP1-AP2));122 } -
sasmodels/models/hollow_rectangular_prism.py
r2d81cfe r2d81cfe 5 5 This model provides the form factor, $P(q)$, for a hollow rectangular 6 6 parallelepiped with a wall of thickness $\Delta$. 7 7 It computes only the 1D scattering, not the 2D. 8 8 9 9 Definition … … 66 66 (which is unitless). 67 67 68 For 2d data the orientation of the particle is required, described using 69 angles $\theta$, $\phi$ and $\Psi$ as in the diagrams below, for further details 70 of the calculation and angular dispersions see :ref:`orientation` . 71 The angle $\Psi$ is the rotational angle around the long *C* axis. For example, 72 $\Psi = 0$ when the *B* axis is parallel to the *x*-axis of the detector. 73 74 For 2d, constraints must be applied during fitting to ensure that the inequality 75 $A < B < C$ is not violated, and hence the correct definition of angles is preserved. The calculation will not report an error, 76 but the results may be not correct. 77 78 .. figure:: img/parallelepiped_angle_definition.png 79 80 Definition of the angles for oriented hollow rectangular prism. 81 Note that rotation $\theta$, initially in the $xz$ plane, is carried out first, then 82 rotation $\phi$ about the $z$ axis, finally rotation $\Psi$ is now around the axis of the prism. 83 The neutron or X-ray beam is along the $z$ axis. 84 85 .. figure:: img/parallelepiped_angle_projection.png 86 87 Examples of the angles for oriented hollow rectangular prisms against the 88 detector plane. 68 **The 2D scattering intensity is not computed by this model.** 89 69 90 70 … … 133 113 ["thickness", "Ang", 1, [0, inf], "volume", 134 114 "Thickness of parallelepiped"], 135 ["theta", "degrees", 0, [-360, 360], "orientation",136 "c axis to beam angle"],137 ["phi", "degrees", 0, [-360, 360], "orientation",138 "rotation about beam"],139 ["psi", "degrees", 0, [-360, 360], "orientation",140 "rotation about c axis"],141 115 ] 142 116 -
sasmodels/models/hollow_rectangular_prism_thin_walls.c
r74768cb rab2aea8 1 1 double form_volume(double length_a, double b2a_ratio, double c2a_ratio); 2 double Iq(double q, double sld, double solvent_sld, double length_a, 2 double Iq(double q, double sld, double solvent_sld, double length_a, 3 3 double b2a_ratio, double c2a_ratio); 4 4 … … 29 29 const double v2a = 0.0; 30 30 const double v2b = M_PI_2; //phi integration limits 31 31 32 32 double outer_sum = 0.0; 33 for(int i=0; i< GAUSS_N; i++) {34 const double theta = 0.5 * ( G AUSS_Z[i]*(v1b-v1a) + v1a + v1b );33 for(int i=0; i<76; i++) { 34 const double theta = 0.5 * ( Gauss76Z[i]*(v1b-v1a) + v1a + v1b ); 35 35 36 36 double sin_theta, cos_theta; … … 44 44 45 45 double inner_sum = 0.0; 46 for(int j=0; j< GAUSS_N; j++) {47 const double phi = 0.5 * ( G AUSS_Z[j]*(v2b-v2a) + v2a + v2b );46 for(int j=0; j<76; j++) { 47 const double phi = 0.5 * ( Gauss76Z[j]*(v2b-v2a) + v2a + v2b ); 48 48 49 49 double sin_phi, cos_phi; … … 62 62 * ( cos_a*sin_b/cos_phi + cos_b*sin_a/sin_phi ); 63 63 64 inner_sum += G AUSS_W[j] * square(AL+AT);64 inner_sum += Gauss76Wt[j] * square(AL+AT); 65 65 } 66 66 67 67 inner_sum *= 0.5 * (v2b-v2a); 68 outer_sum += G AUSS_W[i] * inner_sum * sin_theta;68 outer_sum += Gauss76Wt[i] * inner_sum * sin_theta; 69 69 } 70 70 -
sasmodels/models/lib/gauss150.c
r99b84ec r994d77f 1 // Created by Andrew Jackson on 4/23/07 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 */ 2 9 3 #ifdef GAUSS_N 4 # undef GAUSS_N 5 # undef GAUSS_Z 6 # undef GAUSS_W 7 #endif 8 #define GAUSS_N 150 9 #define GAUSS_Z Gauss150Z 10 #define GAUSS_W Gauss150Wt 11 12 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. 15 constant double Gauss150Z[152]={ 10 // Gaussians 11 constant double Gauss150Z[150]={ 16 12 -0.9998723404457334, 17 13 -0.9993274305065947, … … 163 159 0.9983473449340834, 164 160 0.9993274305065947, 165 0.9998723404457334, 166 0., // zero padding is ignored 167 0. // zero padding is ignored 161 0.9998723404457334 168 162 }; 169 163 170 constant double Gauss150Wt[15 2]={164 constant double Gauss150Wt[150]={ 171 165 0.0003276086705538, 172 166 0.0007624720924706, … … 318 312 0.0011976474864367, 319 313 0.0007624720924706, 320 0.0003276086705538, 321 0., // zero padding is ignored 322 0. // zero padding is ignored 314 0.0003276086705538 323 315 }; -
sasmodels/models/lib/gauss20.c
r99b84ec r994d77f 1 // Created by Andrew Jackson on 4/23/07 2 3 #ifdef GAUSS_N 4 # undef GAUSS_N 5 # undef GAUSS_Z 6 # undef GAUSS_W 7 #endif 8 #define GAUSS_N 20 9 #define GAUSS_Z Gauss20Z 10 #define GAUSS_W Gauss20Wt 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 */ 11 9 12 10 // Gaussians -
sasmodels/models/lib/gauss76.c
r99b84ec r66d119f 1 // Created by Andrew Jackson on 4/23/07 2 3 #ifdef GAUSS_N 4 # undef GAUSS_N 5 # undef GAUSS_Z 6 # undef GAUSS_W 7 #endif 8 #define GAUSS_N 76 9 #define GAUSS_Z Gauss76Z 10 #define GAUSS_W Gauss76Wt 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 */ 9 #define N_POINTS_76 76 11 10 12 11 // Gaussians 13 constant double Gauss76Wt[ 76]={12 constant double Gauss76Wt[N_POINTS_76]={ 14 13 .00126779163408536, //0 15 14 .00294910295364247, … … 90 89 }; 91 90 92 constant double Gauss76Z[ 76]={91 constant double Gauss76Z[N_POINTS_76]={ 93 92 -.999505948362153, //0 94 93 -.997397786355355, -
sasmodels/models/line.py
r108e70e r2d81cfe 57 57 Iq.vectorized = True # Iq accepts an array of q values 58 58 59 60 59 def Iqxy(qx, qy, *args): 61 60 """ … … 70 69 71 70 Iqxy.vectorized = True # Iqxy accepts an array of qx qy values 72 73 # uncomment the following to test Iqxy in C models74 #del Iq, Iqxy75 #c_code = """76 #static double Iq(double q, double b, double m) { return m*q+b; }77 #static double Iqxy(double qx, double qy, double b, double m)78 #{ return (m*qx+b)*(m*qy+b); }79 #"""80 71 81 72 def random(): -
sasmodels/models/parallelepiped.c
r108e70e r9b7b23f 23 23 double outer_total = 0; //initialize integral 24 24 25 for( int i=0; i< GAUSS_N; i++) {26 const double sigma = 0.5 * ( G AUSS_Z[i] + 1.0 );25 for( int i=0; i<76; i++) { 26 const double sigma = 0.5 * ( Gauss76Z[i] + 1.0 ); 27 27 const double mu_proj = mu * sqrt(1.0-sigma*sigma); 28 28 … … 30 30 // corresponding to angles from 0 to pi/2. 31 31 double inner_total = 0.0; 32 for(int j=0; j< GAUSS_N; j++) {33 const double uu = 0.5 * ( G AUSS_Z[j] + 1.0 );32 for(int j=0; j<76; j++) { 33 const double uu = 0.5 * ( Gauss76Z[j] + 1.0 ); 34 34 double sin_uu, cos_uu; 35 35 SINCOS(M_PI_2*uu, sin_uu, cos_uu); 36 36 const double si1 = sas_sinx_x(mu_proj * sin_uu * a_scaled); 37 37 const double si2 = sas_sinx_x(mu_proj * cos_uu); 38 inner_total += G AUSS_W[j] * square(si1 * si2);38 inner_total += Gauss76Wt[j] * square(si1 * si2); 39 39 } 40 40 inner_total *= 0.5; 41 41 42 42 const double si = sas_sinx_x(mu * c_scaled * sigma); 43 outer_total += G AUSS_W[i] * inner_total * si * si;43 outer_total += Gauss76Wt[i] * inner_total * si * si; 44 44 } 45 45 outer_total *= 0.5; … … 53 53 54 54 static double 55 Iq abc(double qa, double qb, double qc,55 Iqxy(double qa, double qb, double qc, 56 56 double sld, 57 57 double solvent_sld, -
sasmodels/models/pringle.c
r74768cb r1e7b0db0 29 29 double sumC = 0.0; // initialize integral 30 30 double r; 31 for (int i=0; i < GAUSS_N; i++) {32 r = G AUSS_Z[i]*zm + zb;31 for (int i=0; i < 76; i++) { 32 r = Gauss76Z[i]*zm + zb; 33 33 34 34 const double qrs = r*q_sin_psi; 35 35 const double qrrc = r*r*q_cos_psi; 36 36 37 double y = G AUSS_W[i] * r * sas_JN(n, beta*qrrc) * sas_JN(2*n, qrs);37 double y = Gauss76Wt[i] * r * sas_JN(n, beta*qrrc) * sas_JN(2*n, qrs); 38 38 double S, C; 39 39 SINCOS(alpha*qrrc, S, C); … … 86 86 87 87 double sum = 0.0; 88 for (int i = 0; i < GAUSS_N; i++) {89 double psi = G AUSS_Z[i]*zm + zb;88 for (int i = 0; i < 76; i++) { 89 double psi = Gauss76Z[i]*zm + zb; 90 90 double sin_psi, cos_psi; 91 91 SINCOS(psi, sin_psi, cos_psi); … … 93 93 double sinc_term = square(sas_sinx_x(q * thickness * cos_psi / 2.0)); 94 94 double pringle_kernel = 4.0 * sin_psi * bessel_term * sinc_term; 95 sum += G AUSS_W[i] * pringle_kernel;95 sum += Gauss76Wt[i] * pringle_kernel; 96 96 } 97 97 -
sasmodels/models/rectangular_prism.c
r108e70e r1e7b0db0 1 1 double form_volume(double length_a, double b2a_ratio, double c2a_ratio); 2 double Iq(double q, double sld, double solvent_sld, double length_a, 2 double Iq(double q, double sld, double solvent_sld, double length_a, 3 3 double b2a_ratio, double c2a_ratio); 4 4 … … 26 26 const double v2a = 0.0; 27 27 const double v2b = M_PI_2; //phi integration limits 28 28 29 29 double outer_sum = 0.0; 30 for(int i=0; i< GAUSS_N; i++) {31 const double theta = 0.5 * ( G AUSS_Z[i]*(v1b-v1a) + v1a + v1b );30 for(int i=0; i<76; i++) { 31 const double theta = 0.5 * ( Gauss76Z[i]*(v1b-v1a) + v1a + v1b ); 32 32 double sin_theta, cos_theta; 33 33 SINCOS(theta, sin_theta, cos_theta); … … 36 36 37 37 double inner_sum = 0.0; 38 for(int j=0; j< GAUSS_N; j++) {39 double phi = 0.5 * ( G AUSS_Z[j]*(v2b-v2a) + v2a + v2b );38 for(int j=0; j<76; j++) { 39 double phi = 0.5 * ( Gauss76Z[j]*(v2b-v2a) + v2a + v2b ); 40 40 double sin_phi, cos_phi; 41 41 SINCOS(phi, sin_phi, cos_phi); … … 45 45 const double termB = sas_sinx_x(q * b_half * sin_theta * cos_phi); 46 46 const double AP = termA * termB * termC; 47 inner_sum += G AUSS_W[j] * AP * AP;47 inner_sum += Gauss76Wt[j] * AP * AP; 48 48 } 49 49 inner_sum = 0.5 * (v2b-v2a) * inner_sum; 50 outer_sum += G AUSS_W[i] * inner_sum * sin_theta;50 outer_sum += Gauss76Wt[i] * inner_sum * sin_theta; 51 51 } 52 52 53 53 double answer = 0.5*(v1b-v1a)*outer_sum; 54 54 55 // Normalize by Pi (Eqn. 16). 56 // The term (ABC)^2 does not appear because it was introduced before on 55 // Normalize by Pi (Eqn. 16). 56 // The term (ABC)^2 does not appear because it was introduced before on 57 57 // the definitions of termA, termB, termC. 58 // The factor 2 appears because the theta integral has been defined between 58 // The factor 2 appears because the theta integral has been defined between 59 59 // 0 and pi/2, instead of 0 to pi. 60 60 answer /= M_PI_2; //Form factor P(q) … … 64 64 answer *= square((sld-solvent_sld)*volume); 65 65 66 // Convert from [1e-12 A-1] to [cm-1] 66 // Convert from [1e-12 A-1] to [cm-1] 67 67 answer *= 1.0e-4; 68 68 69 69 return answer; 70 70 } 71 72 73 double Iqabc(double qa, double qb, double qc,74 double sld,75 double solvent_sld,76 double length_a,77 double b2a_ratio,78 double c2a_ratio)79 {80 const double length_b = length_a * b2a_ratio;81 const double length_c = length_a * c2a_ratio;82 const double a_half = 0.5 * length_a;83 const double b_half = 0.5 * length_b;84 const double c_half = 0.5 * length_c;85 const double volume = length_a * length_b * length_c;86 87 // Amplitude AP from eqn. (13)88 89 const double termA = sas_sinx_x(qa * a_half);90 const double termB = sas_sinx_x(qb * b_half);91 const double termC = sas_sinx_x(qc * c_half);92 93 const double AP = termA * termB * termC;94 95 // Multiply by contrast^2. Factor corresponding to volume^2 cancels with previous normalization.96 const double delrho = sld - solvent_sld;97 98 // Convert from [1e-12 A-1] to [cm-1]99 return 1.0e-4 * square(volume * delrho * AP);100 } -
sasmodels/models/rectangular_prism.py
r2d81cfe r2d81cfe 12 12 the prism (e.g. setting $b/a = 1$ and $c/a = 1$ and applying polydispersity 13 13 to *a* will generate a distribution of cubes of different sizes). 14 Note also that, contrary to :ref:`parallelepiped`, it does not compute 15 the 2D scattering. 14 16 15 17 … … 24 26 that reference), with $\theta$ corresponding to $\alpha$ in that paper, 25 27 and not to the usual convention used for example in the 26 :ref:`parallelepiped` model. 28 :ref:`parallelepiped` model. As the present model does not compute 29 the 2D scattering, this has no further consequences. 27 30 28 31 In this model the scattering from a massive parallelepiped with an … … 62 65 units) *scale* represents the volume fraction (which is unitless). 63 66 64 For 2d data the orientation of the particle is required, described using 65 angles $\theta$, $\phi$ and $\Psi$ as in the diagrams below, for further details 66 of the calculation and angular dispersions see :ref:`orientation` . 67 The angle $\Psi$ is the rotational angle around the long *C* axis. For example, 68 $\Psi = 0$ when the *B* axis is parallel to the *x*-axis of the detector. 69 70 For 2d, constraints must be applied during fitting to ensure that the inequality 71 $A < B < C$ is not violated, and hence the correct definition of angles is preserved. The calculation will not report an error, 72 but the results may be not correct. 73 74 .. figure:: img/parallelepiped_angle_definition.png 75 76 Definition of the angles for oriented core-shell parallelepipeds. 77 Note that rotation $\theta$, initially in the $xz$ plane, is carried out first, then 78 rotation $\phi$ about the $z$ axis, finally rotation $\Psi$ is now around the axis of the cylinder. 79 The neutron or X-ray beam is along the $z$ axis. 80 81 .. figure:: img/parallelepiped_angle_projection.png 82 83 Examples of the angles for oriented rectangular prisms against the 84 detector plane. 85 67 **The 2D scattering intensity is not computed by this model.** 86 68 87 69 … … 126 108 ["c2a_ratio", "", 1, [0, inf], "volume", 127 109 "Ratio sides c/a"], 128 ["theta", "degrees", 0, [-360, 360], "orientation",129 "c axis to beam angle"],130 ["phi", "degrees", 0, [-360, 360], "orientation",131 "rotation about beam"],132 ["psi", "degrees", 0, [-360, 360], "orientation",133 "rotation about c axis"],134 110 ] 135 111 -
sasmodels/models/sc_paracrystal.c
r108e70e rf728001 54 54 55 55 double outer_sum = 0.0; 56 for(int i=0; i< GAUSS_N; i++) {56 for(int i=0; i<150; i++) { 57 57 double inner_sum = 0.0; 58 const double theta = G AUSS_Z[i]*theta_m + theta_b;58 const double theta = Gauss150Z[i]*theta_m + theta_b; 59 59 double sin_theta, cos_theta; 60 60 SINCOS(theta, sin_theta, cos_theta); 61 61 const double qc = q*cos_theta; 62 62 const double qab = q*sin_theta; 63 for(int j=0;j< GAUSS_N;j++) {64 const double phi = G AUSS_Z[j]*phi_m + phi_b;63 for(int j=0;j<150;j++) { 64 const double phi = Gauss150Z[j]*phi_m + phi_b; 65 65 double sin_phi, cos_phi; 66 66 SINCOS(phi, sin_phi, cos_phi); … … 68 68 const double qb = qab*sin_phi; 69 69 const double form = sc_Zq(qa, qb, qc, dnn, d_factor); 70 inner_sum += G AUSS_W[j] * form;70 inner_sum += Gauss150Wt[j] * form; 71 71 } 72 72 inner_sum *= phi_m; // sum(f(x)dx) = sum(f(x)) dx 73 outer_sum += G AUSS_W[i] * inner_sum * sin_theta;73 outer_sum += Gauss150Wt[i] * inner_sum * sin_theta; 74 74 } 75 75 outer_sum *= theta_m; … … 82 82 83 83 static double 84 Iq abc(double qa, double qb, double qc,84 Iqxy(double qa, double qb, double qc, 85 85 double dnn, double d_factor, double radius, 86 86 double sld, double solvent_sld) -
sasmodels/models/stacked_disks.c
r108e70e rbecded3 81 81 double halfheight = 0.5*thick_core; 82 82 83 for(int i=0; i< GAUSS_N; i++) {84 double zi = (G AUSS_Z[i] + 1.0)*M_PI_4;83 for(int i=0; i<N_POINTS_76; i++) { 84 double zi = (Gauss76Z[i] + 1.0)*M_PI_4; 85 85 double sin_alpha, cos_alpha; // slots to hold sincos function output 86 86 SINCOS(zi, sin_alpha, cos_alpha); … … 95 95 solvent_sld, 96 96 d); 97 summ += G AUSS_W[i] * yyy * sin_alpha;97 summ += Gauss76Wt[i] * yyy * sin_alpha; 98 98 } 99 99 … … 142 142 143 143 static double 144 Iq ac(double qab, double qc,144 Iqxy(double qab, double qc, 145 145 double thick_core, 146 146 double thick_layer, -
sasmodels/models/triaxial_ellipsoid.c
r108e70e rbecded3 21 21 const double zb = M_PI_4; 22 22 double outer = 0.0; 23 for (int i=0;i< GAUSS_N;i++) {24 //const double u = G AUSS_Z[i]*(upper-lower)/2 + (upper + lower)/2;25 const double phi = G AUSS_Z[i]*zm + zb;23 for (int i=0;i<76;i++) { 24 //const double u = Gauss76Z[i]*(upper-lower)/2 + (upper + lower)/2; 25 const double phi = Gauss76Z[i]*zm + zb; 26 26 const double pa_sinsq_phi = pa*square(sin(phi)); 27 27 … … 29 29 const double um = 0.5; 30 30 const double ub = 0.5; 31 for (int j=0;j< GAUSS_N;j++) {31 for (int j=0;j<76;j++) { 32 32 // translate a point in [-1,1] to a point in [0, 1] 33 const double usq = square(G AUSS_Z[j]*um + ub);33 const double usq = square(Gauss76Z[j]*um + ub); 34 34 const double r = radius_equat_major*sqrt(pa_sinsq_phi*(1.0-usq) + 1.0 + pc*usq); 35 35 const double fq = sas_3j1x_x(q*r); 36 inner += G AUSS_W[j] * fq * fq;36 inner += Gauss76Wt[j] * fq * fq; 37 37 } 38 outer += G AUSS_W[i] * inner; // correcting for dx later38 outer += Gauss76Wt[i] * inner; // correcting for dx later 39 39 } 40 40 // translate integration ranges from [-1,1] to [lower,upper] and normalize by 4 pi … … 46 46 47 47 static double 48 Iq abc(double qa, double qb, double qc,48 Iqxy(double qa, double qb, double qc, 49 49 double sld, 50 50 double sld_solvent, -
sasmodels/special.py
rdf69efa re65c3ba 3 3 ................. 4 4 5 This following standard C99 math functions are available: 5 The C code follows the C99 standard, with the usual math functions, 6 as defined in 7 `OpenCL <https://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/mathFunctions.html>`_. 8 This includes the following: 6 9 7 10 M_PI, M_PI_2, M_PI_4, M_SQRT1_2, M_E: 8 11 $\pi$, $\pi/2$, $\pi/4$, $1/\sqrt{2}$ and Euler's constant $e$ 9 12 10 exp, log, pow(x,y), expm1, log1p, sqrt, cbrt:11 Power functions $e^x$, $\ln x$, $x^y$, $e^x - 1$, $\ ln 1 + x$,12 $\sqrt{x}$, $\sqrt[3]{x}$. The functions expm1(x) and log1p(x)13 are accurate across all $x$, including $x$very close to zero.13 exp, log, pow(x,y), expm1, sqrt: 14 Power functions $e^x$, $\ln x$, $x^y$, $e^x - 1$, $\sqrt{x}$. 15 The function expm1(x) is accurate across all $x$, including $x$ 16 very close to zero. 14 17 15 18 sin, cos, tan, asin, acos, atan: … … 26 29 quadrants II and IV when $x$ and $y$ have opposite sign. 27 30 28 f abs(x), fmin(x,y), fmax(x,y), trunc, rint:31 fmin(x,y), fmax(x,y), trunc, rint: 29 32 Floating point functions. rint(x) returns the nearest integer. 30 33 … … 32 35 NaN, Not a Number, $0/0$. Use isnan(x) to test for NaN. Note that 33 36 you cannot use :code:`x == NAN` to test for NaN values since that 34 will always return false. NAN does not equal NAN! The alternative, 35 :code:`x != x` may fail if the compiler optimizes the test away. 37 will always return false. NAN does not equal NAN! 36 38 37 39 INFINITY: … … 87 89 for forcing a constant to stay double precision. 88 90 89 The following special functions and scattering calculations are defined. 91 The following special functions and scattering calculations are defined in 92 `sasmodels/models/lib <https://github.com/SasView/sasmodels/tree/master/sasmodels/models/lib>`_. 90 93 These functions have been tuned to be fast and numerically stable down 91 94 to $q=0$ even in single precision. In some cases they work around bugs … … 181 184 182 185 183 gauss76.n, gauss76.z[i], gauss76.w[i]:186 Gauss76Z[i], Gauss76Wt[i]: 184 187 Points $z_i$ and weights $w_i$ for 76-point Gaussian quadrature, respectively, 185 188 computing $\int_{-1}^1 f(z)\,dz \approx \sum_{i=1}^{76} w_i\,f(z_i)$. 186 When translating the model to C, include 'lib/gauss76.c' in the source 187 and use :code:`GAUSS_N`, :code:`GAUSS_Z`, and :code:`GAUSS_W`. 188 189 Similar arrays are available in :code:`gauss20` for 20-point quadrature 190 and :code:`gauss150.c` for 150-point quadrature. By using 191 :code:`import gauss76 as gauss` it is easy to change the number of 192 points in the integration. 189 190 Similar arrays are available in :code:`gauss20.c` for 20-point 191 quadrature and in :code:`gauss150.c` for 150-point quadrature. 192 193 193 """ 194 194 # pylint: disable=unused-import … … 200 200 201 201 # C99 standard math library functions 202 from numpy import exp, log, power as pow, expm1, log1p, sqrt, cbrt202 from numpy import exp, log, power as pow, expm1, sqrt 203 203 from numpy import sin, cos, tan, arcsin as asin, arccos as acos, arctan as atan 204 204 from numpy import sinh, cosh, tanh, arcsinh as asinh, arccosh as acosh, arctanh as atanh 205 205 from numpy import arctan2 as atan2 206 from numpy import fabs, fmin, fmax, trunc, rint 207 from numpy import pi, nan, inf 206 from numpy import fmin, fmax, trunc, rint 207 from numpy import NAN, inf as INFINITY 208 208 209 from scipy.special import gamma as sas_gamma 209 210 from scipy.special import erf as sas_erf … … 217 218 # C99 standard math constants 218 219 M_PI, M_PI_2, M_PI_4, M_SQRT1_2, M_E = np.pi, np.pi/2, np.pi/4, np.sqrt(0.5), np.e 219 NAN = nan220 INFINITY = inf221 220 222 221 # non-standard constants … … 227 226 """return sin(x), cos(x)""" 228 227 return sin(x), cos(x) 229 sincos = SINCOS230 228 231 229 def square(x): … … 296 294 297 295 # Gaussians 298 class Gauss: 299 def __init__(self, w, z): 300 self.n = len(w) 301 self.w = w 302 self.z = z 303 304 gauss20 = Gauss( 305 w=np.array([ 306 .0176140071391521, 307 .0406014298003869, 308 .0626720483341091, 309 .0832767415767047, 310 .10193011981724, 311 .118194531961518, 312 .131688638449177, 313 .142096109318382, 314 .149172986472604, 315 .152753387130726, 316 .152753387130726, 317 .149172986472604, 318 .142096109318382, 319 .131688638449177, 320 .118194531961518, 321 .10193011981724, 322 .0832767415767047, 323 .0626720483341091, 324 .0406014298003869, 325 .0176140071391521 326 ]), 327 z=np.array([ 328 -.993128599185095, 329 -.963971927277914, 330 -.912234428251326, 331 -.839116971822219, 332 -.746331906460151, 333 -.636053680726515, 334 -.510867001950827, 335 -.37370608871542, 336 -.227785851141645, 337 -.076526521133497, 338 .0765265211334973, 339 .227785851141645, 340 .37370608871542, 341 .510867001950827, 342 .636053680726515, 343 .746331906460151, 344 .839116971822219, 345 .912234428251326, 346 .963971927277914, 347 .993128599185095 348 ]) 349 ) 350 351 gauss76 = Gauss( 352 w=np.array([ 353 .00126779163408536, #0 354 .00294910295364247, 355 .00462793522803742, 356 .00629918049732845, 357 .00795984747723973, 358 .00960710541471375, 359 .0112381685696677, 360 .0128502838475101, 361 .0144407317482767, 362 .0160068299122486, 363 .0175459372914742, #10 364 .0190554584671906, 365 .020532847967908, 366 .0219756145344162, 367 .0233813253070112, 368 .0247476099206597, 369 .026072164497986, 370 .0273527555318275, 371 .028587223650054, 372 .029773487255905, 373 .0309095460374916, #20 374 .0319934843404216, 375 .0330234743977917, 376 .0339977794120564, 377 .0349147564835508, 378 .0357728593807139, 379 .0365706411473296, 380 .0373067565423816, 381 .0379799643084053, 382 .0385891292645067, 383 .0391332242205184, #30 384 .0396113317090621, 385 .0400226455325968, 386 .040366472122844, 387 .0406422317102947, 388 .0408494593018285, 389 .040987805464794, 390 .0410570369162294, 391 .0410570369162294, 392 .040987805464794, 393 .0408494593018285, #40 394 .0406422317102947, 395 .040366472122844, 396 .0400226455325968, 397 .0396113317090621, 398 .0391332242205184, 399 .0385891292645067, 400 .0379799643084053, 401 .0373067565423816, 402 .0365706411473296, 403 .0357728593807139, #50 404 .0349147564835508, 405 .0339977794120564, 406 .0330234743977917, 407 .0319934843404216, 408 .0309095460374916, 409 .029773487255905, 410 .028587223650054, 411 .0273527555318275, 412 .026072164497986, 413 .0247476099206597, #60 414 .0233813253070112, 415 .0219756145344162, 416 .020532847967908, 417 .0190554584671906, 418 .0175459372914742, 419 .0160068299122486, 420 .0144407317482767, 421 .0128502838475101, 422 .0112381685696677, 423 .00960710541471375, #70 424 .00795984747723973, 425 .00629918049732845, 426 .00462793522803742, 427 .00294910295364247, 428 .00126779163408536 #75 (indexed from 0) 429 ]), 430 z=np.array([ 431 -.999505948362153, #0 432 -.997397786355355, 433 -.993608772723527, 434 -.988144453359837, 435 -.981013938975656, 436 -.972229228520377, 437 -.961805126758768, 438 -.949759207710896, 439 -.936111781934811, 440 -.92088586125215, 441 -.904107119545567, #10 442 -.885803849292083, 443 -.866006913771982, 444 -.844749694983342, 445 -.822068037328975, 446 -.7980001871612, 447 -.77258672828181, 448 -.74587051350361, 449 -.717896592387704, 450 -.688712135277641, 451 -.658366353758143, #20 452 -.626910417672267, 453 -.594397368836793, 454 -.560882031601237, 455 -.526420920401243, 456 -.491072144462194, 457 -.454895309813726, 458 -.417951418780327, 459 -.380302767117504, 460 -.342012838966962, 461 -.303146199807908, #30 462 -.263768387584994, 463 -.223945802196474, 464 -.183745593528914, 465 -.143235548227268, 466 -.102483975391227, 467 -.0615595913906112, 468 -.0205314039939986, 469 .0205314039939986, 470 .0615595913906112, 471 .102483975391227, #40 472 .143235548227268, 473 .183745593528914, 474 .223945802196474, 475 .263768387584994, 476 .303146199807908, 477 .342012838966962, 478 .380302767117504, 479 .417951418780327, 480 .454895309813726, 481 .491072144462194, #50 482 .526420920401243, 483 .560882031601237, 484 .594397368836793, 485 .626910417672267, 486 .658366353758143, 487 .688712135277641, 488 .717896592387704, 489 .74587051350361, 490 .77258672828181, 491 .7980001871612, #60 492 .822068037328975, 493 .844749694983342, 494 .866006913771982, 495 .885803849292083, 496 .904107119545567, 497 .92088586125215, 498 .936111781934811, 499 .949759207710896, 500 .961805126758768, 501 .972229228520377, #70 502 .981013938975656, 503 .988144453359837, 504 .993608772723527, 505 .997397786355355, 506 .999505948362153 #75 507 ]) 508 ) 509 510 gauss150 = Gauss( 511 z=np.array([ 512 -0.9998723404457334, 513 -0.9993274305065947, 514 -0.9983473449340834, 515 -0.9969322929775997, 516 -0.9950828645255290, 517 -0.9927998590434373, 518 -0.9900842691660192, 519 -0.9869372772712794, 520 -0.9833602541697529, 521 -0.9793547582425894, 522 -0.9749225346595943, 523 -0.9700655145738374, 524 -0.9647858142586956, 525 -0.9590857341746905, 526 -0.9529677579610971, 527 -0.9464345513503147, 528 -0.9394889610042837, 529 -0.9321340132728527, 530 -0.9243729128743136, 531 -0.9162090414984952, 532 -0.9076459563329236, 533 -0.8986873885126239, 534 -0.8893372414942055, 535 -0.8795995893549102, 536 -0.8694786750173527, 537 -0.8589789084007133, 538 -0.8481048644991847, 539 -0.8368612813885015, 540 -0.8252530581614230, 541 -0.8132852527930605, 542 -0.8009630799369827, 543 -0.7882919086530552, 544 -0.7752772600680049, 545 -0.7619248049697269, 546 -0.7482403613363824, 547 -0.7342298918013638, 548 -0.7198995010552305, 549 -0.7052554331857488, 550 -0.6903040689571928, 551 -0.6750519230300931, 552 -0.6595056411226444, 553 -0.6436719971150083, 554 -0.6275578900977726, 555 -0.6111703413658551, 556 -0.5945164913591590, 557 -0.5776035965513142, 558 -0.5604390262878617, 559 -0.5430302595752546, 560 -0.5253848818220803, 561 -0.5075105815339176, 562 -0.4894151469632753, 563 -0.4711064627160663, 564 -0.4525925063160997, 565 -0.4338813447290861, 566 -0.4149811308476706, 567 -0.3959000999390257, 568 -0.3766465660565522, 569 -0.3572289184172501, 570 -0.3376556177463400, 571 -0.3179351925907259, 572 -0.2980762356029071, 573 -0.2780873997969574, 574 -0.2579773947782034, 575 -0.2377549829482451, 576 -0.2174289756869712, 577 -0.1970082295132342, 578 -0.1765016422258567, 579 -0.1559181490266516, 580 -0.1352667186271445, 581 -0.1145563493406956, 582 -0.0937960651617229, 583 -0.0729949118337358, 584 -0.0521619529078925, 585 -0.0313062657937972, 586 -0.0104369378042598, 587 0.0104369378042598, 588 0.0313062657937972, 589 0.0521619529078925, 590 0.0729949118337358, 591 0.0937960651617229, 592 0.1145563493406956, 593 0.1352667186271445, 594 0.1559181490266516, 595 0.1765016422258567, 596 0.1970082295132342, 597 0.2174289756869712, 598 0.2377549829482451, 599 0.2579773947782034, 600 0.2780873997969574, 601 0.2980762356029071, 602 0.3179351925907259, 603 0.3376556177463400, 604 0.3572289184172501, 605 0.3766465660565522, 606 0.3959000999390257, 607 0.4149811308476706, 608 0.4338813447290861, 609 0.4525925063160997, 610 0.4711064627160663, 611 0.4894151469632753, 612 0.5075105815339176, 613 0.5253848818220803, 614 0.5430302595752546, 615 0.5604390262878617, 616 0.5776035965513142, 617 0.5945164913591590, 618 0.6111703413658551, 619 0.6275578900977726, 620 0.6436719971150083, 621 0.6595056411226444, 622 0.6750519230300931, 623 0.6903040689571928, 624 0.7052554331857488, 625 0.7198995010552305, 626 0.7342298918013638, 627 0.7482403613363824, 628 0.7619248049697269, 629 0.7752772600680049, 630 0.7882919086530552, 631 0.8009630799369827, 632 0.8132852527930605, 633 0.8252530581614230, 634 0.8368612813885015, 635 0.8481048644991847, 636 0.8589789084007133, 637 0.8694786750173527, 638 0.8795995893549102, 639 0.8893372414942055, 640 0.8986873885126239, 641 0.9076459563329236, 642 0.9162090414984952, 643 0.9243729128743136, 644 0.9321340132728527, 645 0.9394889610042837, 646 0.9464345513503147, 647 0.9529677579610971, 648 0.9590857341746905, 649 0.9647858142586956, 650 0.9700655145738374, 651 0.9749225346595943, 652 0.9793547582425894, 653 0.9833602541697529, 654 0.9869372772712794, 655 0.9900842691660192, 656 0.9927998590434373, 657 0.9950828645255290, 658 0.9969322929775997, 659 0.9983473449340834, 660 0.9993274305065947, 661 0.9998723404457334 662 ]), 663 w=np.array([ 664 0.0003276086705538, 665 0.0007624720924706, 666 0.0011976474864367, 667 0.0016323569986067, 668 0.0020663664924131, 669 0.0024994789888943, 670 0.0029315036836558, 671 0.0033622516236779, 672 0.0037915348363451, 673 0.0042191661429919, 674 0.0046449591497966, 675 0.0050687282939456, 676 0.0054902889094487, 677 0.0059094573005900, 678 0.0063260508184704, 679 0.0067398879387430, 680 0.0071507883396855, 681 0.0075585729801782, 682 0.0079630641773633, 683 0.0083640856838475, 684 0.0087614627643580, 685 0.0091550222717888, 686 0.0095445927225849, 687 0.0099300043714212, 688 0.0103110892851360, 689 0.0106876814158841, 690 0.0110596166734735, 691 0.0114267329968529, 692 0.0117888704247183, 693 0.0121458711652067, 694 0.0124975796646449, 695 0.0128438426753249, 696 0.0131845093222756, 697 0.0135194311690004, 698 0.0138484622795371, 699 0.0141714592928592, 700 0.0144882814685445, 701 0.0147987907597169, 702 0.0151028518701744, 703 0.0154003323133401, 704 0.0156911024699895, 705 0.0159750356447283, 706 0.0162520081211971, 707 0.0165218992159766, 708 0.0167845913311726, 709 0.0170399700056559, 710 0.0172879239649355, 711 0.0175283451696437, 712 0.0177611288626114, 713 0.0179861736145128, 714 0.0182033813680609, 715 0.0184126574807331, 716 0.0186139107660094, 717 0.0188070535331042, 718 0.0189920016251754, 719 0.0191686744559934, 720 0.0193369950450545, 721 0.0194968900511231, 722 0.0196482898041878, 723 0.0197911283358190, 724 0.0199253434079123, 725 0.0200508765398072, 726 0.0201676730337687, 727 0.0202756819988200, 728 0.0203748563729175, 729 0.0204651529434560, 730 0.0205465323660984, 731 0.0206189591819181, 732 0.0206824018328499, 733 0.0207368326754401, 734 0.0207822279928917, 735 0.0208185680053983, 736 0.0208458368787627, 737 0.0208640227312962, 738 0.0208731176389954, 739 0.0208731176389954, 740 0.0208640227312962, 741 0.0208458368787627, 742 0.0208185680053983, 743 0.0207822279928917, 744 0.0207368326754401, 745 0.0206824018328499, 746 0.0206189591819181, 747 0.0205465323660984, 748 0.0204651529434560, 749 0.0203748563729175, 750 0.0202756819988200, 751 0.0201676730337687, 752 0.0200508765398072, 753 0.0199253434079123, 754 0.0197911283358190, 755 0.0196482898041878, 756 0.0194968900511231, 757 0.0193369950450545, 758 0.0191686744559934, 759 0.0189920016251754, 760 0.0188070535331042, 761 0.0186139107660094, 762 0.0184126574807331, 763 0.0182033813680609, 764 0.0179861736145128, 765 0.0177611288626114, 766 0.0175283451696437, 767 0.0172879239649355, 768 0.0170399700056559, 769 0.0167845913311726, 770 0.0165218992159766, 771 0.0162520081211971, 772 0.0159750356447283, 773 0.0156911024699895, 774 0.0154003323133401, 775 0.0151028518701744, 776 0.0147987907597169, 777 0.0144882814685445, 778 0.0141714592928592, 779 0.0138484622795371, 780 0.0135194311690004, 781 0.0131845093222756, 782 0.0128438426753249, 783 0.0124975796646449, 784 0.0121458711652067, 785 0.0117888704247183, 786 0.0114267329968529, 787 0.0110596166734735, 788 0.0106876814158841, 789 0.0103110892851360, 790 0.0099300043714212, 791 0.0095445927225849, 792 0.0091550222717888, 793 0.0087614627643580, 794 0.0083640856838475, 795 0.0079630641773633, 796 0.0075585729801782, 797 0.0071507883396855, 798 0.0067398879387430, 799 0.0063260508184704, 800 0.0059094573005900, 801 0.0054902889094487, 802 0.0050687282939456, 803 0.0046449591497966, 804 0.0042191661429919, 805 0.0037915348363451, 806 0.0033622516236779, 807 0.0029315036836558, 808 0.0024994789888943, 809 0.0020663664924131, 810 0.0016323569986067, 811 0.0011976474864367, 812 0.0007624720924706, 813 0.0003276086705538 814 ]) 815 ) 296 297 Gauss20Wt = np.array([ 298 .0176140071391521, 299 .0406014298003869, 300 .0626720483341091, 301 .0832767415767047, 302 .10193011981724, 303 .118194531961518, 304 .131688638449177, 305 .142096109318382, 306 .149172986472604, 307 .152753387130726, 308 .152753387130726, 309 .149172986472604, 310 .142096109318382, 311 .131688638449177, 312 .118194531961518, 313 .10193011981724, 314 .0832767415767047, 315 .0626720483341091, 316 .0406014298003869, 317 .0176140071391521 318 ]) 319 320 Gauss20Z = np.array([ 321 -.993128599185095, 322 -.963971927277914, 323 -.912234428251326, 324 -.839116971822219, 325 -.746331906460151, 326 -.636053680726515, 327 -.510867001950827, 328 -.37370608871542, 329 -.227785851141645, 330 -.076526521133497, 331 .0765265211334973, 332 .227785851141645, 333 .37370608871542, 334 .510867001950827, 335 .636053680726515, 336 .746331906460151, 337 .839116971822219, 338 .912234428251326, 339 .963971927277914, 340 .993128599185095 341 ]) 342 343 Gauss76Wt = np.array([ 344 .00126779163408536, #0 345 .00294910295364247, 346 .00462793522803742, 347 .00629918049732845, 348 .00795984747723973, 349 .00960710541471375, 350 .0112381685696677, 351 .0128502838475101, 352 .0144407317482767, 353 .0160068299122486, 354 .0175459372914742, #10 355 .0190554584671906, 356 .020532847967908, 357 .0219756145344162, 358 .0233813253070112, 359 .0247476099206597, 360 .026072164497986, 361 .0273527555318275, 362 .028587223650054, 363 .029773487255905, 364 .0309095460374916, #20 365 .0319934843404216, 366 .0330234743977917, 367 .0339977794120564, 368 .0349147564835508, 369 .0357728593807139, 370 .0365706411473296, 371 .0373067565423816, 372 .0379799643084053, 373 .0385891292645067, 374 .0391332242205184, #30 375 .0396113317090621, 376 .0400226455325968, 377 .040366472122844, 378 .0406422317102947, 379 .0408494593018285, 380 .040987805464794, 381 .0410570369162294, 382 .0410570369162294, 383 .040987805464794, 384 .0408494593018285, #40 385 .0406422317102947, 386 .040366472122844, 387 .0400226455325968, 388 .0396113317090621, 389 .0391332242205184, 390 .0385891292645067, 391 .0379799643084053, 392 .0373067565423816, 393 .0365706411473296, 394 .0357728593807139, #50 395 .0349147564835508, 396 .0339977794120564, 397 .0330234743977917, 398 .0319934843404216, 399 .0309095460374916, 400 .029773487255905, 401 .028587223650054, 402 .0273527555318275, 403 .026072164497986, 404 .0247476099206597, #60 405 .0233813253070112, 406 .0219756145344162, 407 .020532847967908, 408 .0190554584671906, 409 .0175459372914742, 410 .0160068299122486, 411 .0144407317482767, 412 .0128502838475101, 413 .0112381685696677, 414 .00960710541471375, #70 415 .00795984747723973, 416 .00629918049732845, 417 .00462793522803742, 418 .00294910295364247, 419 .00126779163408536 #75 (indexed from 0) 420 ]) 421 422 Gauss76Z = np.array([ 423 -.999505948362153, #0 424 -.997397786355355, 425 -.993608772723527, 426 -.988144453359837, 427 -.981013938975656, 428 -.972229228520377, 429 -.961805126758768, 430 -.949759207710896, 431 -.936111781934811, 432 -.92088586125215, 433 -.904107119545567, #10 434 -.885803849292083, 435 -.866006913771982, 436 -.844749694983342, 437 -.822068037328975, 438 -.7980001871612, 439 -.77258672828181, 440 -.74587051350361, 441 -.717896592387704, 442 -.688712135277641, 443 -.658366353758143, #20 444 -.626910417672267, 445 -.594397368836793, 446 -.560882031601237, 447 -.526420920401243, 448 -.491072144462194, 449 -.454895309813726, 450 -.417951418780327, 451 -.380302767117504, 452 -.342012838966962, 453 -.303146199807908, #30 454 -.263768387584994, 455 -.223945802196474, 456 -.183745593528914, 457 -.143235548227268, 458 -.102483975391227, 459 -.0615595913906112, 460 -.0205314039939986, 461 .0205314039939986, 462 .0615595913906112, 463 .102483975391227, #40 464 .143235548227268, 465 .183745593528914, 466 .223945802196474, 467 .263768387584994, 468 .303146199807908, 469 .342012838966962, 470 .380302767117504, 471 .417951418780327, 472 .454895309813726, 473 .491072144462194, #50 474 .526420920401243, 475 .560882031601237, 476 .594397368836793, 477 .626910417672267, 478 .658366353758143, 479 .688712135277641, 480 .717896592387704, 481 .74587051350361, 482 .77258672828181, 483 .7980001871612, #60 484 .822068037328975, 485 .844749694983342, 486 .866006913771982, 487 .885803849292083, 488 .904107119545567, 489 .92088586125215, 490 .936111781934811, 491 .949759207710896, 492 .961805126758768, 493 .972229228520377, #70 494 .981013938975656, 495 .988144453359837, 496 .993608772723527, 497 .997397786355355, 498 .999505948362153 #75 499 ]) 500 501 Gauss150Z = np.array([ 502 -0.9998723404457334, 503 -0.9993274305065947, 504 -0.9983473449340834, 505 -0.9969322929775997, 506 -0.9950828645255290, 507 -0.9927998590434373, 508 -0.9900842691660192, 509 -0.9869372772712794, 510 -0.9833602541697529, 511 -0.9793547582425894, 512 -0.9749225346595943, 513 -0.9700655145738374, 514 -0.9647858142586956, 515 -0.9590857341746905, 516 -0.9529677579610971, 517 -0.9464345513503147, 518 -0.9394889610042837, 519 -0.9321340132728527, 520 -0.9243729128743136, 521 -0.9162090414984952, 522 -0.9076459563329236, 523 -0.8986873885126239, 524 -0.8893372414942055, 525 -0.8795995893549102, 526 -0.8694786750173527, 527 -0.8589789084007133, 528 -0.8481048644991847, 529 -0.8368612813885015, 530 -0.8252530581614230, 531 -0.8132852527930605, 532 -0.8009630799369827, 533 -0.7882919086530552, 534 -0.7752772600680049, 535 -0.7619248049697269, 536 -0.7482403613363824, 537 -0.7342298918013638, 538 -0.7198995010552305, 539 -0.7052554331857488, 540 -0.6903040689571928, 541 -0.6750519230300931, 542 -0.6595056411226444, 543 -0.6436719971150083, 544 -0.6275578900977726, 545 -0.6111703413658551, 546 -0.5945164913591590, 547 -0.5776035965513142, 548 -0.5604390262878617, 549 -0.5430302595752546, 550 -0.5253848818220803, 551 -0.5075105815339176, 552 -0.4894151469632753, 553 -0.4711064627160663, 554 -0.4525925063160997, 555 -0.4338813447290861, 556 -0.4149811308476706, 557 -0.3959000999390257, 558 -0.3766465660565522, 559 -0.3572289184172501, 560 -0.3376556177463400, 561 -0.3179351925907259, 562 -0.2980762356029071, 563 -0.2780873997969574, 564 -0.2579773947782034, 565 -0.2377549829482451, 566 -0.2174289756869712, 567 -0.1970082295132342, 568 -0.1765016422258567, 569 -0.1559181490266516, 570 -0.1352667186271445, 571 -0.1145563493406956, 572 -0.0937960651617229, 573 -0.0729949118337358, 574 -0.0521619529078925, 575 -0.0313062657937972, 576 -0.0104369378042598, 577 0.0104369378042598, 578 0.0313062657937972, 579 0.0521619529078925, 580 0.0729949118337358, 581 0.0937960651617229, 582 0.1145563493406956, 583 0.1352667186271445, 584 0.1559181490266516, 585 0.1765016422258567, 586 0.1970082295132342, 587 0.2174289756869712, 588 0.2377549829482451, 589 0.2579773947782034, 590 0.2780873997969574, 591 0.2980762356029071, 592 0.3179351925907259, 593 0.3376556177463400, 594 0.3572289184172501, 595 0.3766465660565522, 596 0.3959000999390257, 597 0.4149811308476706, 598 0.4338813447290861, 599 0.4525925063160997, 600 0.4711064627160663, 601 0.4894151469632753, 602 0.5075105815339176, 603 0.5253848818220803, 604 0.5430302595752546, 605 0.5604390262878617, 606 0.5776035965513142, 607 0.5945164913591590, 608 0.6111703413658551, 609 0.6275578900977726, 610 0.6436719971150083, 611 0.6595056411226444, 612 0.6750519230300931, 613 0.6903040689571928, 614 0.7052554331857488, 615 0.7198995010552305, 616 0.7342298918013638, 617 0.7482403613363824, 618 0.7619248049697269, 619 0.7752772600680049, 620 0.7882919086530552, 621 0.8009630799369827, 622 0.8132852527930605, 623 0.8252530581614230, 624 0.8368612813885015, 625 0.8481048644991847, 626 0.8589789084007133, 627 0.8694786750173527, 628 0.8795995893549102, 629 0.8893372414942055, 630 0.8986873885126239, 631 0.9076459563329236, 632 0.9162090414984952, 633 0.9243729128743136, 634 0.9321340132728527, 635 0.9394889610042837, 636 0.9464345513503147, 637 0.9529677579610971, 638 0.9590857341746905, 639 0.9647858142586956, 640 0.9700655145738374, 641 0.9749225346595943, 642 0.9793547582425894, 643 0.9833602541697529, 644 0.9869372772712794, 645 0.9900842691660192, 646 0.9927998590434373, 647 0.9950828645255290, 648 0.9969322929775997, 649 0.9983473449340834, 650 0.9993274305065947, 651 0.9998723404457334 652 ]) 653 654 Gauss150Wt = np.array([ 655 0.0003276086705538, 656 0.0007624720924706, 657 0.0011976474864367, 658 0.0016323569986067, 659 0.0020663664924131, 660 0.0024994789888943, 661 0.0029315036836558, 662 0.0033622516236779, 663 0.0037915348363451, 664 0.0042191661429919, 665 0.0046449591497966, 666 0.0050687282939456, 667 0.0054902889094487, 668 0.0059094573005900, 669 0.0063260508184704, 670 0.0067398879387430, 671 0.0071507883396855, 672 0.0075585729801782, 673 0.0079630641773633, 674 0.0083640856838475, 675 0.0087614627643580, 676 0.0091550222717888, 677 0.0095445927225849, 678 0.0099300043714212, 679 0.0103110892851360, 680 0.0106876814158841, 681 0.0110596166734735, 682 0.0114267329968529, 683 0.0117888704247183, 684 0.0121458711652067, 685 0.0124975796646449, 686 0.0128438426753249, 687 0.0131845093222756, 688 0.0135194311690004, 689 0.0138484622795371, 690 0.0141714592928592, 691 0.0144882814685445, 692 0.0147987907597169, 693 0.0151028518701744, 694 0.0154003323133401, 695 0.0156911024699895, 696 0.0159750356447283, 697 0.0162520081211971, 698 0.0165218992159766, 699 0.0167845913311726, 700 0.0170399700056559, 701 0.0172879239649355, 702 0.0175283451696437, 703 0.0177611288626114, 704 0.0179861736145128, 705 0.0182033813680609, 706 0.0184126574807331, 707 0.0186139107660094, 708 0.0188070535331042, 709 0.0189920016251754, 710 0.0191686744559934, 711 0.0193369950450545, 712 0.0194968900511231, 713 0.0196482898041878, 714 0.0197911283358190, 715 0.0199253434079123, 716 0.0200508765398072, 717 0.0201676730337687, 718 0.0202756819988200, 719 0.0203748563729175, 720 0.0204651529434560, 721 0.0205465323660984, 722 0.0206189591819181, 723 0.0206824018328499, 724 0.0207368326754401, 725 0.0207822279928917, 726 0.0208185680053983, 727 0.0208458368787627, 728 0.0208640227312962, 729 0.0208731176389954, 730 0.0208731176389954, 731 0.0208640227312962, 732 0.0208458368787627, 733 0.0208185680053983, 734 0.0207822279928917, 735 0.0207368326754401, 736 0.0206824018328499, 737 0.0206189591819181, 738 0.0205465323660984, 739 0.0204651529434560, 740 0.0203748563729175, 741 0.0202756819988200, 742 0.0201676730337687, 743 0.0200508765398072, 744 0.0199253434079123, 745 0.0197911283358190, 746 0.0196482898041878, 747 0.0194968900511231, 748 0.0193369950450545, 749 0.0191686744559934, 750 0.0189920016251754, 751 0.0188070535331042, 752 0.0186139107660094, 753 0.0184126574807331, 754 0.0182033813680609, 755 0.0179861736145128, 756 0.0177611288626114, 757 0.0175283451696437, 758 0.0172879239649355, 759 0.0170399700056559, 760 0.0167845913311726, 761 0.0165218992159766, 762 0.0162520081211971, 763 0.0159750356447283, 764 0.0156911024699895, 765 0.0154003323133401, 766 0.0151028518701744, 767 0.0147987907597169, 768 0.0144882814685445, 769 0.0141714592928592, 770 0.0138484622795371, 771 0.0135194311690004, 772 0.0131845093222756, 773 0.0128438426753249, 774 0.0124975796646449, 775 0.0121458711652067, 776 0.0117888704247183, 777 0.0114267329968529, 778 0.0110596166734735, 779 0.0106876814158841, 780 0.0103110892851360, 781 0.0099300043714212, 782 0.0095445927225849, 783 0.0091550222717888, 784 0.0087614627643580, 785 0.0083640856838475, 786 0.0079630641773633, 787 0.0075585729801782, 788 0.0071507883396855, 789 0.0067398879387430, 790 0.0063260508184704, 791 0.0059094573005900, 792 0.0054902889094487, 793 0.0050687282939456, 794 0.0046449591497966, 795 0.0042191661429919, 796 0.0037915348363451, 797 0.0033622516236779, 798 0.0029315036836558, 799 0.0024994789888943, 800 0.0020663664924131, 801 0.0016323569986067, 802 0.0011976474864367, 803 0.0007624720924706, 804 0.0003276086705538 805 ])
Note: See TracChangeset
for help on using the changeset viewer.