Changeset d5014e4 in sasmodels


Ignore:
Timestamp:
Jan 17, 2018 8:21:59 AM (6 years ago)
Author:
Paul Kienzle <pkienzle@…>
Children:
6ceca44
Parents:
5ab99b7 (diff), ff431ca (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge remote-tracking branch 'omer/master'

Files:
3 deleted
7 edited

Legend:

Unmodified
Added
Removed
  • sasmodels/py2c.py

    rd7f33e5 rd5014e4  
    112112# Update Notes 
    113113# ============ 
    114 # 11/22/2017, O.E.  Each 'visit_*' method is to build a C statement string. It 
    115 #                     shold insert 4 blanks per indentation level. 
    116 #                     The 'body' method will combine all the strings, by adding 
    117 #                     the 'current_statement' to the c_proc string list 
    118 #    11/2017, OE: variables, argument definition implemented. 
    119 #    Note: An argument is considered an array if it is the target of an 
    120 #         assignment. In that case it is translated to <var>[0] 
    121 # 11/27/2017, OE: 'pow' basicly working 
    122 #   /12/2017, OE: Multiple assignment: a1,a2,...,an=b1,b2,...bn implemented 
    123 #   /12/2017, OE: Power function, including special cases of 
     114# 2017-11-22, OE: Each 'visit_*' method is to build a C statement string. It 
     115#                 shold insert 4 blanks per indentation level. The 'body' 
     116#                 method will combine all the strings, by adding the 
     117#                 'current_statement' to the c_proc string list 
     118# 2017-11-22, OE: variables, argument definition implemented.  Note: An 
     119#                argument is considered an array if it is the target of an 
     120#                 assignment. In that case it is translated to <var>[0] 
     121# 2017-11-27, OE: 'pow' basicly working 
     122# 2017-12-07, OE: Multiple assignment: a1,a2,...,an=b1,b2,...bn implemented 
     123# 2017-12-07, OE: Power function, including special cases of 
    124124#                 square(x)(pow(x,2)) and cube(x)(pow(x,3)), implemented in 
    125125#                 translate_power, called from visit_BinOp 
    126 # 12/07/2017, OE: Translation of integer division, '\\' in python, implemented 
     126# 2017-12-07, OE: Translation of integer division, '\\' in python, implemented 
    127127#                 in translate_integer_divide, called from visit_BinOp 
    128 # 12/07/2017, OE: C variable definition handled in 'define_c_vars' 
     128# 2017-12-07, OE: C variable definition handled in 'define_c_vars' 
    129129#               : Python integer division, '//', translated to C in 
    130130#                 'translate_integer_divide' 
    131 # 12/15/2017, OE: Precedence maintained by writing opening and closing 
     131# 2017-12-15, OE: Precedence maintained by writing opening and closing 
    132132#                 parenthesesm '(',')', in procedure 'visit_BinOp'. 
    133 # 12/18/2017, OE: Added call to 'add_current_line()' at the beginning 
     133# 2017-12-18, OE: Added call to 'add_current_line()' at the beginning 
    134134#                 of visit_Return 
    135135# 2018-01-03, PK: Update interface for use in sasmodels 
     
    140140# 2018-01-03, PK: simplistic print function, for debugging 
    141141# 2018-01-03, PK: while expr: ... => while (expr) { ... } 
     142# 2018-01-04, OE: Fixed bug in 'visit_If': visiting node.orelse in case else exists. 
    142143 
    143144from __future__ import print_function 
     
    184185 
    185186 
    186 def to_source(tree, constants=None, fname=None, lineno=0): 
    187     """ 
    188     This function can convert a syntax tree into C sourcecode. 
    189     """ 
    190     generator = SourceGenerator(constants=constants, fname=fname, lineno=lineno) 
    191     generator.visit(tree) 
    192     c_code = "".join(generator.c_proc) 
    193     return c_code 
    194  
     187# TODO: should not allow eval of arbitrary python 
    195188def isevaluable(s): 
    196189    try: 
     
    329322                except AttributeError: 
    330323                    arg_name = arg.id 
    331                 w_str = ("Default Parameters are unknown to C: '%s = %s" 
     324                w_str = ("C does not support default parameters: %s=%s" 
    332325                         % (arg_name, str(default.n))) 
    333326                self.warnings.append(w_str) 
     
    508501        self.current_function = node.name 
    509502 
     503        # remember the location of the next warning that will be inserted 
     504        # so that we can stuff the function name ahead of the warning list 
     505        # if any warnings are generated by the function. 
     506        warning_index = len(self.warnings) 
     507 
    510508        self.newline(extra=1) 
    511509        self.decorators(node) 
     
    523521        del self.c_pointers[:] 
    524522        self.current_function = "" 
     523        if warning_index != len(self.warnings): 
     524            self.warnings.insert(warning_index, "Warning in function '" + node.name + "':") 
    525525 
    526526    def visit_ClassDef(self, node): 
     
    586586                self.newline() 
    587587                self.write_c('else {') 
    588                 self.body(node.body) 
     588                self.body(else_) 
    589589                self.add_c_line('}') 
    590590                break 
     
    615615        return start, stop, step 
    616616 
     617    def add_c_int_var(self, name): 
     618        if name not in self.c_int_vars: 
     619            self.c_int_vars.append(name) 
     620 
    617621    def visit_For(self, node): 
    618622        # node: for iterator is stored in node.target. 
     
    627631                    iterator = self.current_statement 
    628632                    self.current_statement = '' 
    629                     if iterator not in self.c_int_vars: 
    630                         self.c_int_vars.append(iterator) 
     633                    self.add_c_int_var(iterator) 
    631634                    start, stop, step = self.get_for_range(node) 
    632635                    self.write_c("for (" + iterator + "=" + str(start) + 
     
    736739            self.write_c('return') 
    737740        else: 
    738             self.write_c('return(') 
     741            self.write_c('return ') 
    739742            self.visit(node.value) 
    740         self.write_c(')') 
    741743        self.add_semi_colon() 
    742744        self.in_expr = False 
     
    855857                name not in self.c_constants and not name.isdigit()): 
    856858            if self.in_subscript: 
    857                 self.c_int_vars.append(node.id) 
     859                self.add_c_int_var(node.id) 
    858860            else: 
    859861                self.c_vars.append(node.id) 
     
    12521254    Convert a list of functions to a list of C code strings. 
    12531255 
     1256    Returns list of corresponding code snippets (with trailing lines in 
     1257    each block) and a list of warnings generated by the translator. 
     1258 
    12541259    A function is given by the tuple (source, filename, line number). 
    12551260 
     
    12661271    """ 
    12671272    snippets = [] 
    1268     #snippets.append("#include <math.h>") 
    1269     #snippets.append("") 
     1273    warnings = [] 
    12701274    for source, fname, lineno in functions: 
    12711275        line_directive = '#line %d "%s"\n'%(lineno, fname.replace('\\', '\\\\')) 
     
    12751279        source = PRINT_STR.sub(SUBST_STR, source) 
    12761280        tree = ast.parse(source) 
    1277         c_code = to_source(tree, constants=constants, fname=fname, lineno=lineno) 
     1281        generator = SourceGenerator(constants=constants, fname=fname, lineno=lineno) 
     1282        generator.visit(tree) 
     1283        c_code = "".join(generator.c_proc) 
    12781284        snippets.append(c_code) 
    1279     return snippets 
    1280  
    1281 def main(): 
    1282     import os 
    1283     #print("Parsing...using Python" + sys.version) 
    1284     if len(sys.argv) == 1: 
    1285         print("""\ 
    1286 Usage: python py2c.py <infile> [<outfile>] 
    1287  
    1288 if outfile is omitted, output file is '<infile>.c' 
    1289 """) 
    1290         return 
    1291  
    1292     fname_in = sys.argv[1] 
    1293     if len(sys.argv) == 2: 
    1294         fname_base = os.path.splitext(fname_in)[0] 
    1295         fname_out = str(fname_base) + '.c' 
    1296     else: 
    1297         fname_out = sys.argv[2] 
    1298  
    1299     with open(fname_in, "r") as python_file: 
    1300         code = python_file.read() 
    1301     name = "gauss" 
    1302     code = (code 
    1303             .replace(name+'.n', 'GAUSS_N') 
    1304             .replace(name+'.z', 'GAUSS_Z') 
    1305             .replace(name+'.w', 'GAUSS_W') 
    1306             .replace('if __name__ == "__main__"', "def main()") 
    1307     ) 
    1308  
    1309  
    1310     c_code = "".join(translate([(code, fname_in, 1)])) 
    1311     c_code = c_code.replace("double main()", "int main(int argc, char *argv[])") 
    1312  
    1313     with open(fname_out, "w") as file_out: 
    1314         file_out.write(""" 
     1285        warnings.extend(generator.warnings) 
     1286    return snippets, warnings 
     1287 
     1288def to_source(tree, constants=None, fname=None, lineno=0): 
     1289    """ 
     1290    This function can convert a syntax tree into C sourcecode. 
     1291    """ 
     1292    c_code = "".join(generator.c_proc) 
     1293    return c_code 
     1294 
     1295 
     1296C_HEADER = """ 
    13151297#include <stdio.h> 
    13161298#include <stdbool.h> 
     
    13301312    return ans; 
    13311313} 
    1332  
    1333 """) 
     1314""" 
     1315 
     1316USAGE = """\ 
     1317Usage: python py2c.py <infile> [<outfile>] 
     1318 
     1319if outfile is omitted, output file is '<infile>.c' 
     1320""" 
     1321 
     1322def main(): 
     1323    import os 
     1324    #print("Parsing...using Python" + sys.version) 
     1325    if len(sys.argv) == 1: 
     1326        print(USAGE) 
     1327        return 
     1328 
     1329    fname_in = sys.argv[1] 
     1330    if len(sys.argv) == 2: 
     1331        fname_base = os.path.splitext(fname_in)[0] 
     1332        fname_out = str(fname_base) + '.c' 
     1333    else: 
     1334        fname_out = sys.argv[2] 
     1335 
     1336    with open(fname_in, "r") as python_file: 
     1337        code = python_file.read() 
     1338    name = "gauss" 
     1339    code = (code 
     1340            .replace(name+'.n', 'GAUSS_N') 
     1341            .replace(name+'.z', 'GAUSS_Z') 
     1342            .replace(name+'.w', 'GAUSS_W') 
     1343            .replace('if __name__ == "__main__"', "def main()") 
     1344           ) 
     1345 
     1346    translation, warnings = translate([(code, fname_in, 1)]) 
     1347    c_code = "".join(translation) 
     1348    c_code = c_code.replace("double main()", "int main(int argc, char *argv[])") 
     1349 
     1350    with open(fname_out, "w") as file_out: 
     1351        file_out.write(C_HEADER) 
    13341352        file_out.write(c_code) 
     1353 
     1354    if warnings: 
     1355        print("\n".join(warnings)) 
    13351356    #print("...Done") 
    13361357 
  • doc/guide/orientation/orientation.rst

    r82592da r5fb0634  
    44================== 
    55 
    6 With two dimensional small angle diffraction data SasView will calculate 
     6With two dimensional small angle diffraction data sasmodels will calculate 
    77scattering from oriented particles, applicable for example to shear flow 
    88or orientation in a magnetic field. 
    99 
    1010In general we first need to define the reference orientation 
    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. 
     11of the particle's $a$-$b$-$c$ axes with respect to the incoming 
     12neutron or X-ray beam. This is done using three angles: $\theta$ and $\phi$ 
     13define the orientation of the $c$-axis of the particle, and angle $\Psi$ is 
     14defined as the orientation of the major axis of the particle cross section 
     15with respect to its starting position along the beam direction (or 
     16equivalently, as rotation about the $c$ axis). There is an unavoidable 
     17ambiguity when $c$ is aligned with $z$ in that $\phi$ and $\Psi$ both 
     18serve to rotate the particle about $c$, but this symmetry is destroyed 
     19when $\theta$ is not a multiple of 180. 
     20 
     21The figures below are for an elliptical cross section cylinder, but may 
     22be applied analogously to other shapes of particle. 
    1823 
    1924.. note:: 
     
    2934 
    3035    Definition of angles for oriented elliptical cylinder, where axis_ratio 
    31     b/a is shown >1, Note that rotation $\theta$, initially in the $x$-$z$ 
     36    b/a is shown >1. Note that rotation $\theta$, initially in the $x$-$z$ 
    3237    plane, is carried out first, then rotation $\phi$ about the $z$-axis, 
    3338    finally rotation $\Psi$ is around the axis of the cylinder. The neutron 
    34     or X-ray beam is along the $z$ axis. 
     39    or X-ray beam is along the $-z$ axis. 
    3540 
    3641.. figure:: 
     
    4045    with $\Psi$ = 0. 
    4146 
    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. 
     47Having established the mean direction of the particle (the view) we can then 
     48apply angular orientation distributions (jitter). This is done by a numerical 
     49integration over a range of angles in a similar way to particle size 
     50dispersity. 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, 
     52yaw angle $\theta$ about the $b$-axis and pitch angle $\phi$ about the 
     53$a$-axis. 
     54 
     55More formally, starting with axes $a$-$b$-$c$ of the particle aligned 
     56with axes $x$-$y$-$z$ of the laboratory frame, the orientation dispersity 
     57is 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$. 
     60The 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 
     63using 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 
     70To transform detector $(q_x, q_y)$ values into $(q_a, q_b, q_c)$ for the 
     71shape 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 
     78The inverse rotation is easily calculated by rotating the opposite directions 
     79in 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 
    4786 
    4887The $\theta$ and $\phi$ orientation parameters for the cylinder only appear 
    49 when fitting 2d data. On introducing "Orientational Distribution" in 
    50 the angles, "distribution of theta" and "distribution of phi" parameters will 
     88when fitting 2d data. On introducing "Orientational Distribution" in the 
     89angles, "distribution of theta" and "distribution of phi" parameters will 
    5190appear. These are actually rotations about the axes $\delta_1$ and $\delta_2$ 
    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` . 
     91of the cylinder, which correspond to the $b$ and $a$ axes of the cylinder 
     92cross section. (When $\theta = \phi = 0$ these are parallel to the $Y$ and 
     93$X$ axes of the instrument.) The third orientation distribution, in $\Psi$, 
     94is about the $c$ axis of the particle. Some experimentation may be required 
     95to understand the 2d patterns fully. A number of different shapes of 
     96distribution are available, as described for size dispersity, see 
     97:ref:`polydispersityhelp`. 
    5898 
    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. 
     99Given that the angular dispersion distribution is defined in cartesian space, 
     100over 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 
     108but the orientation is defined over a sphere, we are left with a 
     109`map projection <https://en.wikipedia.org/wiki/List_of_map_projections>`_ 
     110problem, with different tradeoffs depending on how values in $\Delta\theta$ 
     111and $\Delta\phi$ are translated into latitude/longitude on the sphere. 
     112 
     113Sasmodels is using the 
     114`equirectangular projection <https://en.wikipedia.org/wiki/Equirectangular_projection>`_. 
     115In this projection, square patches in angular dispersity become wedge-shaped 
     116patches on the sphere. To correct for the changing point density, there is a 
     117scale factor of $\sin(\Delta\theta)$ that applies to each point in the 
     118integral. This is not enough, though. Consider a shape which is tumbling 
     119freely 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 
     121a distinct angular preference. If the spin axis is along the beam (which 
     122will be the case for $\theta=90$ and $\Psi=90$) the scattering pattern 
     123should 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 
     125that 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$ 
     127and adjust $\Psi$ by 90. This works with the current sasmodels shapes due to 
     128symmetry. 
     129 
     130Alternative projections were considered. 
     131The `sinusoidal projection <https://en.wikipedia.org/wiki/Sinusoidal_projection>`_ 
     132works by scaling $\Delta\phi$ as $\Delta\theta$ increases, and dropping those 
     133points outside $[-180, 180]$. The distortions are a little less for middle 
     134ranges of $\Delta\theta$, but they are still severe for large $\Delta\theta$ 
     135and the model is much harder to explain. 
     136The `azimuthal equidistance projection <https://en.wikipedia.org/wiki/Azimuthal_equidistant_projection>`_ 
     137also improves on the equirectangular projection by extending the range of 
     138reasonable values for the $\Delta\theta$ range, with $\Delta\phi$ forming a 
     139wedge that cuts to the opposite side of the sphere rather than cutting to the 
     140pole. This projection has the nice property that distance from the center are 
     141preserved, and that $\Delta\theta$ and $\Delta\phi$ act the same. 
     142The `azimuthal equal area projection <https://en.wikipedia.org/wiki/Lambert_azimuthal_equal-area_projection>`_ 
     143is like the azimuthal equidistance projection, but it preserves area instead 
     144of distance. It also has the same behaviour for $\Delta\theta$ and $\Delta\phi$. 
     145The `Guyou projection <https://en.wikipedia.org/wiki/Guyou_hemisphere-in-a-square_projection>`_ 
     146has an excellent balance with reasonable distortion in both $\Delta\theta$ 
     147and $\Delta\phi$, as well as preserving small patches. However, it requires 
     148considerably more computational overhead, and we have not yet derived the 
     149formula for the distortion correction, measuring the degree of stretch at 
     150the point $(\Delta\theta, \Delta\phi)$ on the map. 
    63151 
    64152.. note:: 
    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. 
     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. 
    76159 
    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  
     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 
     166Users can experiment with the values of *Npts* and *Nsigs*, the number of steps 
     167used in the integration and the range spanned in number of standard deviations. 
     168The standard deviation is entered in units of degrees. For a "rectangular" 
     169distribution the full width should be $\pm \sqrt(3)$ ~ 1.73 standard deviations. 
     170The new "uniform" distribution avoids this by letting you directly specify the 
    82171half width. 
    83172 
    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.) 
     173The angular distributions may be truncated outside of the range -180 to +180 
     174degrees, so beware of using saying a broad Gaussian distribution with large 
     175value of *Nsigs*, as the array of *Npts* may be truncated to many fewer 
     176points than would give a good integration,as well as becoming rather 
     177meaningless. (At some point in the future the actual dispersion arrays may be 
     178made available to the user for inspection.) 
    90179 
    91180Some more detailed technical notes are provided in the developer section of 
    92181this manual :ref:`orientation_developer` . 
    93182 
     183This definition of orientation is new to SasView 4.2.  In earlier versions, 
     184the orientation distribution appeared as a distribution of view angles. 
     185This led to strange effects when $c$ was aligned with $z$, where changes 
     186to the $\phi$ angle served only to rotate the shape about $c$, rather than 
     187having a consistent interpretation as the pitch of the shape relative to 
     188the flow field defining the reference orientation.  Prior to SasView 4.1, 
     189the reference orientation was defined using a Tait-Bryan convention, making 
     190it difficult to control.  Now, rotation in $\theta$ modifies the spacings 
     191in the refraction pattern, and rotation in $\phi$ rotates it in the detector 
     192plane. 
     193 
     194 
    94195*Document History* 
    95196 
    96197| 2017-11-06 Richard Heenan 
     198| 2017-12-20 Paul Kienzle 
  • doc/guide/plugin.rst

    rc654160 r7e6bc45e  
    538538If the scattering is dependent on the orientation of the shape, then you 
    539539will need to include *orientation* parameters *theta*, *phi* and *psi* 
    540 at the end of the parameter table.  Shape orientation uses *a*, *b* and *c* 
    541 axes, corresponding to the *x*, *y* and *z* axes in the laboratory coordinate 
    542 system, with *z* along the beam and *x*-*y* in the detector plane, with *x* 
    543 horizontal and *y* vertical.  The *psi* parameter rotates the shape 
    544 about its *c* axis, the *theta* parameter then rotates the *c* axis toward 
    545 the *x* axis of the detector, then *phi* rotates the shape in the detector 
    546 plane.  (Prior to these rotations, orientation dispersity will be applied 
    547 as roll-pitch-yaw, rotating *c*, then *b* then *a* in the shape coordinate 
    548 system.)  A particular *qx*, *qy* point on the detector, then corresponds 
    549 to *qa*, *qb*, *qc* with respect to the shape. 
    550  
    551 The oriented C model is called as *Iqabc(qa, qb, qc, par1, par2, ...)* where 
     540at the end of the parameter table.  As described in the section 
     541:ref:`orientation`, the individual $(q_x, q_y)$ points on the detector will 
     542be rotated into $(q_a, q_b, q_c)$ points relative to the sample in its 
     543canonical orientation with $a$-$b$-$c$ aligned with $x$-$y$-$z$ in the 
     544laboratory frame and beam travelling along $-z$. 
     545 
     546The oriented C model is called using *Iqabc(qa, qb, qc, par1, par2, ...)* where 
    552547*par1*, etc. are the parameters to the model.  If the shape is rotationally 
    553548symmetric about *c* then *psi* is not needed, and the model is called 
  • explore/jitter.py

    rff10479 r8cfb486  
    165165    # constants in kernel_iq.c 
    166166    'equirectangular', 'sinusoidal', 'guyou', 'azimuthal_equidistance', 
     167    'azimuthal_equal_area', 
    167168] 
    168169def draw_mesh(ax, view, jitter, radius=1.2, n=11, dist='gaussian', 
  • sasmodels/autoc.py

    r67cc0ff r15be191  
    44from __future__ import print_function 
    55 
    6 import ast 
    76import inspect 
    8 from functools import reduce 
    97 
    108import numpy as np 
     
    9593                constants[name] = obj 
    9694                # Claim all constants are declared on line 1 
    97                 snippets.append('#line 1 "%s"'%escaped_filename) 
    98                 snippets.append(define_constant(name, obj)) 
     95                snippets.append('#line 1 "%s"\n'%escaped_filename) 
     96                snippets.append(py2c.define_constant(name, obj)) 
    9997            elif isinstance(obj, special.Gauss): 
    10098                for var, value in zip(("N", "Z", "W"), (obj.n, obj.z, obj.w)): 
    10199                    var = "GAUSS_"+var 
    102100                    constants[var] = value 
    103                     snippets.append('#line 1 "%s"'%escaped_filename) 
    104                     snippets.append(define_constant(var, value)) 
     101                    snippets.append('#line 1 "%s"\n'%escaped_filename) 
     102                    snippets.append(py2c.define_constant(var, value)) 
    105103                #libs.append('lib/gauss%d.c'%obj.n) 
    106104                source = (source.replace(name+'.n', 'GAUSS_N') 
     
    121119 
    122120    # translate source 
    123     ordered_code = [code[name] for name in ordered_dag(depends) if name in code] 
     121    ordered_code = [code[name] for name in py2c.ordered_dag(depends) if name in code] 
    124122    functions = py2c.translate(ordered_code, constants) 
    125123    snippets.extend(functions) 
     
    127125    # update model info 
    128126    info.source = unique_libs 
    129     info.c_code = "\n".join(snippets) 
     127    info.c_code = "".join(snippets) 
    130128    info.Iq = info.Iqac = info.Iqabc = info.Iqxy = info.form_volume = None 
    131  
    132 def define_constant(name, value): 
    133     if isinstance(value, int): 
    134         parts = ["int ", name, " = ", "%d"%value, ";"] 
    135     elif isinstance(value, float): 
    136         parts = ["double ", name, " = ", "%.15g"%value, ";"] 
    137     else: 
    138         # extend constant arrays to a multiple of 4; not sure if this 
    139         # is necessary, but some OpenCL targets broke if the number 
    140         # of parameters in the parameter table was not a multiple of 4, 
    141         # so do it for all constant arrays to be safe. 
    142         if len(value)%4 != 0: 
    143             value = list(value) + [0.]*(4 - len(value)%4) 
    144         elements = ["%.15g"%v for v in value] 
    145         parts = ["double ", name, "[]", " = ", 
    146                  "{\n   ", ", ".join(elements), "\n};"] 
    147     return "".join(parts) 
    148  
    149  
    150 # Modified from the following: 
    151 # 
    152 #    http://code.activestate.com/recipes/578272-topological-sort/ 
    153 #    Copyright (C) 2012 Sam Denton 
    154 #    License: MIT 
    155 def ordered_dag(dag): 
    156     # type: (Dict[T, Set[T]]) -> Iterator[T] 
    157     dag = dag.copy() 
    158  
    159     # make leaves depend on the empty set 
    160     leaves = reduce(set.union, dag.values()) - set(dag.keys()) 
    161     dag.update({node: set() for node in leaves}) 
    162     while True: 
    163         leaves = set(node for node, links in dag.items() if not links) 
    164         if not leaves: 
    165             break 
    166         for node in leaves: 
    167             yield node 
    168         dag = {node: (links-leaves) 
    169                for node, links in dag.items() if node not in leaves} 
    170     if dag: 
    171         raise ValueError("Cyclic dependes exists amongst these items:\n%s" 
    172                             % ", ".join(str(node) for node in dag.keys())) 
  • sasmodels/modelinfo.py

    r67cc0ff r5ab99b7  
    794794    info.structure_factor = getattr(kernel_module, 'structure_factor', False) 
    795795    info.profile_axes = getattr(kernel_module, 'profile_axes', ['x', 'y']) 
    796     info.c_code = getattr(kernel_module, 'c_code', None) 
    797796    info.source = getattr(kernel_module, 'source', []) 
    798797    info.c_code = getattr(kernel_module, 'c_code', None) 
     
    810809    info.sesans = getattr(kernel_module, 'sesans', None) # type: ignore 
    811810    # Default single and opencl to True for C models.  Python models have callable Iq. 
    812     info.opencl = getattr(kernel_module, 'opencl', not callable(info.Iq)) 
    813     info.single = getattr(kernel_module, 'single', not callable(info.Iq)) 
    814811    info.random = getattr(kernel_module, 'random', None) 
    815812 
     
    827824        except Exception as exc: 
    828825            logger.warn(str(exc) + " while converting %s from C to python"%name) 
     826 
     827    # Needs to come after autoc.convert since the Iq symbol may have been 
     828    # converted from python to C 
     829    info.opencl = getattr(kernel_module, 'opencl', not callable(info.Iq)) 
     830    info.single = getattr(kernel_module, 'single', not callable(info.Iq)) 
    829831 
    830832    if callable(info.Iq) and parameters.has_2d: 
  • sasmodels/models/_cylpy.py

    r67cc0ff rc01ed3e  
    140140py2c = True 
    141141 
     142# TODO: "#define INVALID (expr)" is not supported 
    142143def invalid(v): 
    143144    return v.radius < 0 or v.length < 0 
     
    206207            phi_pd=10, phi_pd_n=5) 
    207208 
    208 qx, qy = 0.2 * np.cos(2.5), 0.2 * np.sin(2.5) 
     209qx, qy = 0.2 * cos(2.5), 0.2 * sin(2.5) 
    209210# After redefinition of angles, find new tests values.  Was 10 10 in old coords 
    210211tests = [ 
Note: See TracChangeset for help on using the changeset viewer.