Ignore:
Timestamp:
Oct 24, 2017 12:44:26 AM (8 years ago)
Author:
Piotr Rozyczko <rozyczko@…>
Branches:
ESS_GUI, ESS_GUI_Docs, ESS_GUI_batch_fitting, ESS_GUI_bumps_abstraction, ESS_GUI_iss1116, ESS_GUI_iss879, ESS_GUI_iss959, ESS_GUI_opencl, ESS_GUI_ordering, ESS_GUI_sync_sascalc
Children:
fca1f50, d6b234b
Parents:
16afe01 (diff), 5582b078 (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 branch 'master' into ESS_GUI

Location:
src/sas/sasgui/perspectives/calculator
Files:
22 added
22 deleted
13 edited

Legend:

Unmodified
Added
Removed
  • src/sas/sasgui/perspectives/calculator/__init__.py

    r959eb01 r5a405bd  
    1818    path = os.path.dirname(__file__) 
    1919    #Look for maximum n_dir up of the current dir to find media 
    20     
     20 
    2121    #for i in range(n_dir): 
    2222    i = 0 
     
    3030             return media_path 
    3131        i += 1 
    32     
     32 
    3333    raise RuntimeError('Could not find calculator media files') 
    3434 
     
    3636    """ 
    3737    Return the data files associated with media calculator. 
    38      
     38 
    3939    The format is a list of (directory, [files...]) pairs which can be 
    4040    used directly in setup(...,data_files=...) for setup.py. 
     
    4242    """ 
    4343    data_files = [] 
    44     path = get_data_path(media="media") 
    45     for f in findall(path): 
    46         data_files.append(('media/calculator_media', [f])) 
     44    data_files.append(('media/calculator_media', findall(get_data_path("media")))) 
    4745    return data_files 
  • src/sas/sasgui/perspectives/calculator/image_viewer.py

    ra1b8fee r412e9e8b  
    5959            _, extension = os.path.splitext(basename) 
    6060            try: 
     61                # Note that matplotlib only reads png natively. 
     62                # Any other formats (tiff, jpeg, etc) are passed 
     63                # to PIL which seems to have a problem in version 
     64                # 1.1.7 that causes a close error which shows up in  
     65                # the log file.  This does not seem to have any adverse 
     66                # effects.  PDB   --- September 17, 2017. 
    6167                img = mpimg.imread(file_path) 
    6268                is_png = extension.lower() == '.png' 
     
    8995        if location is None: 
    9096            location = os.getcwd() 
    91         dlg = wx.FileDialog(self.parent, "Image Viewer: Choose a image file", 
    92                             location, "", "", style=wx.FD_OPEN | wx.FD_MULTIPLE) 
     97        wildcard="Images (*.bmp;*.gif;*jpeg,*jpg;*.png;*tif;*.tiff)|*bmp;\ 
     98            *.gif; *.jpg; *.jpeg;*png;*.png;*.tif;*.tiff|"\ 
     99            "Bitmap (*.bmp)|*.bmp|"\ 
     100            "GIF (*.gif)|*.gif|"\ 
     101            "JPEG (*.jpg;*.jpeg)|*.jpg;*.jpeg|"\ 
     102            "PNG (*.png)|*.png|"\ 
     103            "TIFF (*.tif;*.tiff)|*.tif;*tiff|"\ 
     104            "All Files (*.*)|*.*|" 
     105 
     106        dlg = wx.FileDialog(self.parent, "Image Viewer: Choose an image file", 
     107                            location, "", wildcard, style=wx.FD_OPEN 
     108                            | wx.FD_MULTIPLE) 
    93109        if dlg.ShowModal() == wx.ID_OK: 
    94110            path = dlg.GetPaths() 
  • src/sas/sasgui/perspectives/calculator/media/density_calculator_help.rst

    rd85c194 r6aad2e8  
    29294) Click the 'Calculate' button to perform the calculation. 
    3030 
    31 .. image:: density_tutor.gif 
     31.. image:: density_tutor.png 
    3232 
    3333.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 
  • src/sas/sasgui/perspectives/calculator/media/gen_sas_help.html

    rd85c194 r6aad2e8  
    1919by the particle  
    2020<p> 
    21 <img src="gen_i.gif"/> 
     21<img src="gen_i.png"/> 
    2222</p> 
    2323<br> 
     
    2626of the j'th pixel respectively. And the total volume 
    2727<p> 
    28 <img src="v_j.gif"/> 
     28<img src="v_j.png"/> 
    2929</p> 
    3030<br> 
     
    4444scattering length. (Figure below). 
    4545<p> 
    46 <img src="mag_vector.bmp"/> 
     46<img src="mag_vector.png"/> 
    4747</p> 
    4848<br> 
    4949The magnetic scattering length density is then 
    5050<p> 
    51 <img src="dm_eq.gif"/> 
     51<img src="dm_eq.png"/> 
    5252</p> 
    5353<br> 
     
    6666<br> 
    6767<p> 
    68 <img src="gen_mag_pic.bmp"/> 
     68<img src="gen_mag_pic.png"/> 
    6969</p> 
    7070<br> 
     
    7575densities , including the nuclear scattering length density (&#946; <sub>N</sub>) are given as, for non-spin-flips, 
    7676<p> 
    77 <img src="sld1.gif"/> 
     77<img src="sld1.png"/> 
    7878</p> 
    7979<br> 
     
    8181for spin-flips, 
    8282<p> 
    83 <img src="sld2.gif"/> 
     83<img src="sld2.png"/> 
    8484</p> 
    8585<br> 
     
    8787where 
    8888<p> 
    89 <img src="mxp.gif"/> 
     89<img src="mxp.png"/> 
    9090</p> 
    9191<p> 
    92 <img src="myp.gif"/> 
     92<img src="myp.png"/> 
    9393</p> 
    9494<p> 
    95 <img src="mzp.gif"/> 
     95<img src="mzp.png"/> 
    9696</p> 
    9797<p> 
    98 <img src="mqx.gif"/> 
     98<img src="mqx.png"/> 
    9999</p> 
    100100<p> 
    101 <img src="mqy.gif"/> 
     101<img src="mqy.png"/> 
    102102</p> 
    103103<br> 
     
    110110<br> 
    111111<p> 
    112 <img src="gen_gui_help.bmp"/> 
     112<img src="gen_gui_help.png"/> 
    113113</p> 
    114114<br> 
     
    136136in a 2D output, whileas the scattering calculation averaged over all the orientations uses the Debye equation providing a 1D output: 
    137137 <p> 
    138 <img src="gen_debye_eq.gif"/> 
     138<img src="gen_debye_eq.png"/> 
    139139</p> 
    140140<br> 
  • src/sas/sasgui/perspectives/calculator/media/image_viewer_help.rst

    rda456fb r412e9e8b  
    3434   will be displayed. 
    3535 
    36 .. image:: load_image.bmp 
     36.. image:: load_image.png 
    3737 
    38383) To save, print, or copy the image, or to apply a grid overlay, right-click  
    3939   anywhere in the plot. 
    4040 
    41 .. image:: pic_plot.bmp 
     41.. image:: pic_plot.png 
    4242 
    43434. If the image is taken from a 2D detector, SasView can attempt to convert  
     
    5151   then click the OK. 
    5252 
    53 .. image:: pic_convert.bmp 
     53.. image:: pic_convert.png 
    5454 
    5555.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 
  • src/sas/sasgui/perspectives/calculator/media/kiessig_calculator_help.rst

    r7805458 r5ed76f8  
    1010----------- 
    1111 
    12 This tool is approximately estimates the thickness of a layer or the diameter  
    13 of particles from the position of the Kiessig fringe/Bragg peak in NR/SAS data  
    14 using the relation 
     12This tool estimates real space dimensions from the position or spacing of 
     13features in recipricol space.  In particular a particle of size $d$ will 
     14give rise to Bragg peaks with spacing $\Delta q$ according to the relation 
    1515 
    16 (thickness *or* size) = 2 * |pi| / (fringe_width *or* peak position) 
    17    
     16.. math:: 
     17 
     18    d = 2\pi / \Delta q 
     19 
     20Similarly, the spacing between the peaks in Kiessig fringes in reflectometry 
     21data arise from layers of thickness $d$. 
     22 
    1823.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 
    1924 
     
    2126-------------- 
    2227 
    23 To get a rough thickness or particle size, simply type the fringe or peak  
     28To get a rough thickness or particle size, simply type the fringe or peak 
    2429position (in units of 1/|Ang|\) and click on the *Compute* button. 
    2530 
    2631.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 
    2732 
    28 .. note::  This help document was last changed by Steve King, 01May2015 
    29  
     33.. note::  This help document was last changed by Paul Kienzle, 05Apr2017 
  • src/sas/sasgui/perspectives/calculator/media/resolution_calculator_help.rst

    r7805458 r5ed76f8  
    1010----------- 
    1111 
    12 This tool is approximately estimates the resolution of Q from SAS instrumental  
    13 parameter values assuming that the detector is flat and normal to the  
     12This tool is approximately estimates the resolution of $Q$ from SAS instrumental 
     13parameter values assuming that the detector is flat and normal to the 
    1414incident beam. 
    1515 
     
    23232) Select the source (Neutron or Photon) and source type (Monochromatic or TOF). 
    2424 
    25    *NOTE! The computational difference between the sources is only the  
     25   *NOTE! The computational difference between the sources is only the 
    2626   gravitational contribution due to the mass of the particles.* 
    2727 
    28 3) Change the default values of the instrumental parameters as required. Be  
     283) Change the default values of the instrumental parameters as required. Be 
    2929   careful to note that distances are specified in cm! 
    3030 
    31 4) Enter values for the source wavelength(s), |lambda|\ , and its spread (= FWHM/|lambda|\ ). 
    32     
    33    For monochromatic sources, the inputs are just one value. For TOF sources,  
    34    the minimum and maximum values should be separated by a '-' to specify a  
     314) Enter values for the source wavelength(s), $\lambda$, and its spread (= $\text{FWHM}/\lambda$). 
     32 
     33   For monochromatic sources, the inputs are just one value. For TOF sources, 
     34   the minimum and maximum values should be separated by a '-' to specify a 
    3535   range. 
    36     
    37    Optionally, the wavelength (BUT NOT of the wavelength spread) can be extended  
    38    by adding '; nn' where the 'nn' specifies the number of the bins for the  
    39    numerical integration. The default value is nn = 10. The same number of bins  
     36 
     37   Optionally, the wavelength (BUT NOT of the wavelength spread) can be extended 
     38   by adding '; nn' where the 'nn' specifies the number of the bins for the 
     39   numerical integration. The default value is nn = 10. The same number of bins 
    4040   will be used for the corresponding wavelength spread. 
    4141 
    42 5) For TOF, the default wavelength spectrum is flat. A custom spectral  
    43    distribution file (2-column text: wavelength (|Ang|\) vs Intensity) can also  
     425) For TOF, the default wavelength spectrum is flat. A custom spectral 
     43   distribution file (2-column text: wavelength (|Ang|\) vs Intensity) can also 
    4444   be loaded by selecting *Add new* in the combo box. 
    4545 
    46 6) When ready, click the *Compute* button. Depending on the computation the  
     466) When ready, click the *Compute* button. Depending on the computation the 
    4747   calculation time will vary. 
    4848 
    49 7) 1D and 2D dQ values will be displayed at the bottom of the panel, and a 2D  
    50    resolution weight distribution (a 2D elliptical Gaussian function) will also  
    51    be displayed in the plot panel even if the Q inputs are outside of the  
     497) 1D and 2D $dQ$ values will be displayed at the bottom of the panel, and a 2D 
     50   resolution weight distribution (a 2D elliptical Gaussian function) will also 
     51   be displayed in the plot panel even if the $Q$ inputs are outside of the 
    5252   detector limit (the red lines indicate the limits of the detector). 
    53     
    54    TOF only: green lines indicate the limits of the maximum Q range accessible  
     53 
     54   TOF only: green lines indicate the limits of the maximum $Q$ range accessible 
    5555   for the longest wavelength due to the size of the detector. 
    56      
    57    Note that the effect from the beam block/stop is ignored, so in the small Q  
    58    region near the beam block/stop  
    5956 
    60    [ie., Q < 2. |pi|\ .(beam block diameter) / (sample-to-detector distance) / |lambda|\_min]  
     57   Note that the effect from the beam block/stop is ignored, so in the small $Q$ 
     58   region near the beam block/stop 
     59 
     60   [i.e., $Q < (2 \pi \cdot \text{beam block diameter}) / (\text{sample-to-detector distance} \cdot \lambda_\text{min})$] 
    6161 
    6262   the variance is slightly under estimated. 
    6363 
    64 8) A summary of the calculation is written to the SasView *Console* at the  
     648) A summary of the calculation is written to the SasView *Console* at the 
    6565   bottom of the main SasView window. 
    6666 
    67 .. image:: resolution_tutor.gif 
     67.. image:: resolution_tutor.png 
    6868 
    6969.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 
     
    7474The scattering wave transfer vector is by definition 
    7575 
    76 .. image:: q.gif 
     76.. image:: q.png 
    7777 
    78 In the small-angle limit, the variance of Q is to a first-order  
     78In the small-angle limit, the variance of $Q$ is to a first-order 
    7979approximation 
    8080 
    81 .. image:: sigma_q.gif 
     81.. image:: sigma_q.png 
    8282 
    8383The geometric and gravitational contributions can then be summarised as 
    8484 
    85 .. image:: sigma_table.gif 
     85.. image:: sigma_table.png 
    8686 
    87 Finally, a Gaussian function is used to describe the 2D weighting distribution  
    88 of the uncertainty in Q. 
     87Finally, a Gaussian function is used to describe the 2D weighting distribution 
     88of the uncertainty in $Q$. 
    8989 
    9090.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 
     
    9393---------- 
    9494 
    95 D.F.R. Mildner and J.M. Carpenter  
     95D.F.R. Mildner and J.M. Carpenter 
    9696*J. Appl. Cryst.* 17 (1984) 249-256 
    9797 
    98 D.F.R. Mildner, J.M. Carpenter and D.L. Worcester  
     98D.F.R. Mildner, J.M. Carpenter and D.L. Worcester 
    9999*J. Appl. Cryst.* 19 (1986) 311-319 
    100100 
  • src/sas/sasgui/perspectives/calculator/media/sas_calculator_help.rst

    rda456fb r5ed76f8  
    1919------ 
    2020 
    21 In general, a particle with a volume *V* can be described by an ensemble  
    22 containing *N* 3-dimensional rectangular pixels where each pixel is much  
    23 smaller than *V*. 
     21In general, a particle with a volume $V$ can be described by an ensemble 
     22containing $N$ 3-dimensional rectangular pixels where each pixel is much 
     23smaller than $V$. 
    2424 
    25 Assuming that all the pixel sizes are the same, the elastic scattering  
     25Assuming that all the pixel sizes are the same, the elastic scattering 
    2626intensity from the particle is 
    2727 
    28 .. image:: gen_i.gif 
     28.. image:: gen_i.png 
    2929 
    3030Equation 1. 
    3131 
    32 where |beta|\ :sub:`j` and *r*\ :sub:`j` are the scattering length density and  
    33 the position of the j'th pixel respectively. 
     32where $\beta_j$ and $r_j$ are the scattering length density and 
     33the position of the $j^\text{th}$ pixel respectively. 
    3434 
    35 The total volume *V* 
     35The total volume $V$ 
    3636 
    37 .. image:: v_j.gif 
     37.. math:: 
    3838 
    39 for |beta|\ :sub:`j` |noteql|\0 where *v*\ :sub:`j` is the volume of the j'th  
    40 pixel (or the j'th natural atomic volume (= atomic mass / (natural molar  
     39    V = \sum_j^N v_j 
     40 
     41for $\beta_j \ne 0$ where $v_j$ is the volume of the $j^\text{th}$ 
     42pixel (or the $j^\text{th}$ natural atomic volume (= atomic mass / (natural molar 
    4143density * Avogadro number) for the atomic structures). 
    4244 
    43 *V* can be corrected by users. This correction is useful especially for an  
    44 atomic structure (such as taken from a PDB file) to get the right normalization.  
     45$V$ can be corrected by users. This correction is useful especially for an 
     46atomic structure (such as taken from a PDB file) to get the right normalization. 
    4547 
    46 *NOTE!* |beta|\ :sub:`j` *displayed in the GUI may be incorrect but this will not  
     48*NOTE! $\beta_j$ displayed in the GUI may be incorrect but this will not 
    4749affect the scattering computation if the correction of the total volume V is made.* 
    4850 
    49 The scattering length density (SLD) of each pixel, where the SLD is uniform, is  
    50 a combination of the nuclear and magnetic SLDs and depends on the spin states  
     51The scattering length density (SLD) of each pixel, where the SLD is uniform, is 
     52a combination of the nuclear and magnetic SLDs and depends on the spin states 
    5153of the neutrons as follows. 
    5254 
     
    5456^^^^^^^^^^^^^^^^^^^ 
    5557 
    56 For magnetic scattering, only the magnetization component, *M*\ :sub:`perp`\ ,  
    57 perpendicular to the scattering vector *Q* contributes to the magnetic  
     58For magnetic scattering, only the magnetization component, $M_\perp$, 
     59perpendicular to the scattering vector $Q$ contributes to the magnetic 
    5860scattering length. 
    5961 
    60 .. image:: mag_vector.bmp 
     62.. image:: mag_vector.png 
    6163 
    6264The magnetic scattering length density is then 
    6365 
    64 .. image:: dm_eq.gif 
     66.. image:: dm_eq.png 
    6567 
    66 where the gyromagnetic ratio |gamma| = -1.913, |mu|\ :sub:`B` is the Bohr  
    67 magneton, *r*\ :sub:`0` is the classical radius of electron, and |sigma| is the  
     68where the gyromagnetic ratio is $\gamma = -1.913$, $\mu_B$ is the Bohr 
     69magneton, $r_0$ is the classical radius of electron, and $\sigma$ is the 
    6870Pauli spin. 
    6971 
    7072For a polarized neutron, the magnetic scattering is depending on the spin states. 
    7173 
    72 Let us consider that the incident neutrons are polarised both parallel (+) and   
    73 anti-parallel (-) to the x' axis (see below). The possible states after  
    74 scattering from the sample are then  
     74Let us consider that the incident neutrons are polarised both parallel (+) and 
     75anti-parallel (-) to the x' axis (see below). The possible states after 
     76scattering from the sample are then 
    7577 
    7678*  Non-spin flips: (+ +) and (- -) 
    7779*  Spin flips:     (+ -) and (- +) 
    7880 
    79 .. image:: gen_mag_pic.bmp 
     81.. image:: gen_mag_pic.png 
    8082 
    81 Now let us assume that the angles of the *Q* vector and the spin-axis (x')  
    82 to the x-axis are |phi| and |theta|\ :sub:`up` respectively (see above). Then,  
    83 depending upon the polarization (spin) state of neutrons, the scattering  
    84 length densities, including the nuclear scattering length density (|beta|\ :sub:`N`\ )  
     83Now let us assume that the angles of the *Q* vector and the spin-axis (x') 
     84to the x-axis are $\phi$ and $\theta_\text{up}$ respectively (see above). Then, 
     85depending upon the polarization (spin) state of neutrons, the scattering 
     86length densities, including the nuclear scattering length density ($\beta_N$) 
    8587are given as 
    8688 
    8789*  for non-spin-flips 
    8890 
    89    .. image:: sld1.gif 
     91   .. image:: sld1.png 
    9092 
    9193*  for spin-flips 
    9294 
    93    .. image:: sld2.gif 
     95   .. image:: sld2.png 
    9496 
    9597where 
    9698 
    97 .. image:: mxp.gif 
     99.. image:: mxp.png 
    98100 
    99 .. image:: myp.gif 
     101.. image:: myp.png 
    100102 
    101 .. image:: mzp.gif 
     103.. image:: mzp.png 
    102104 
    103 .. image:: mqx.gif 
     105.. image:: mqx.png 
    104106 
    105 .. image:: mqy.gif 
     107.. image:: mqy.png 
    106108 
    107 Here the *M0*\ :sub:`x`\ , *M0*\ :sub:`y` and *M0*\ :sub:`z` are the x, y and z  
    108 components of the magnetisation vector in the laboratory xyz frame.  
     109Here the $M0_x$, $M0_y$ and $M0_z$ are the $x$, $y$ and $z$ 
     110components of the magnetisation vector in the laboratory $xyz$ frame. 
    109111 
    110112.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 
     
    113115-------------- 
    114116 
    115 .. image:: gen_gui_help.bmp 
     117.. image:: gen_gui_help.png 
    116118 
    117 After computation the result will appear in the *Theory* box in the SasView   
     119After computation the result will appear in the *Theory* box in the SasView 
    118120*Data Explorer* panel. 
    119121 
    120 *Up_frac_in* and *Up_frac_out* are the ratio  
     122*Up_frac_in* and *Up_frac_out* are the ratio 
    121123 
    122124   (spin up) / (spin up + spin down) 
    123     
     125 
    124126of neutrons before the sample and at the analyzer, respectively. 
    125127 
    126 *NOTE 1. The values of* Up_frac_in *and* Up_frac_out *must be in the range  
     128*NOTE 1. The values of* Up_frac_in *and* Up_frac_out *must be in the range 
    1271290.0 to 1.0. Both values are 0.5 for unpolarized neutrons.* 
    128130 
    129 *NOTE 2. This computation is totally based on the pixel (or atomic) data fixed  
     131*NOTE 2. This computation is totally based on the pixel (or atomic) data fixed 
    130132in xyz coordinates. No angular orientational averaging is considered.* 
    131133 
    132 *NOTE 3. For the nuclear scattering length density, only the real component  
     134*NOTE 3. For the nuclear scattering length density, only the real component 
    133135is taken account.* 
    134136 
     
    139141 
    140142The SANS Calculator tool can read some PDB, OMF or SLD files but ignores 
    141 polarized/magnetic scattering when doing so, thus related parameters such as  
     143polarized/magnetic scattering when doing so, thus related parameters such as 
    142144*Up_frac_in*, etc, will be ignored. 
    143145 
    144 The calculation for fixed orientation uses Equation 1 above resulting in a 2D  
    145 output, whereas the scattering calculation averaged over all the orientations  
     146The calculation for fixed orientation uses Equation 1 above resulting in a 2D 
     147output, whereas the scattering calculation averaged over all the orientations 
    146148uses the Debye equation below providing a 1D output 
    147149 
    148 .. image:: gen_debye_eq.gif 
     150.. image:: gen_debye_eq.png 
    149151 
    150 where *v*\ :sub:`j` |beta|\ :sub:`j` |equiv| *b*\ :sub:`j` is the scattering  
    151 length of the j'th atom. The calculation output is passed to the *Data Explorer*  
     152where $v_j \beta_j \equiv b_j$ is the scattering 
     153length of the $j^\text{th}$ atom. The calculation output is passed to the *Data Explorer* 
    152154for further use. 
    153155 
  • src/sas/sasgui/perspectives/calculator/media/sld_calculator_help.rst

    rf93b473f r5ed76f8  
    1010----------- 
    1111 
    12 The neutron scattering length density (SLD) is defined as 
     12The neutron scattering length density (SLD, $\beta_N$) is defined as 
    1313 
    14   SLD = (b_c1 + b_c2 + ... + b_cn) / Vm 
     14.. math:: 
    1515 
    16 where b_ci is the bound coherent scattering length of ith of n atoms in a molecule 
    17 with the molecular volume Vm 
     16  \beta_N = (b_{c1} + b_{c2} + ... + b_{cn}) / V_m 
     17 
     18where $b_{ci}$ is the bound coherent scattering length of ith of n atoms in a molecule 
     19with the molecular volume $V_m$. 
    1820 
    1921.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 
     
    2224---------------------------- 
    2325 
    24 To calculate scattering length densities enter the empirical formula of a  
     26To calculate scattering length densities enter the empirical formula of a 
    2527compound and its mass density and click "Calculate". 
    2628 
    27 Entering a wavelength value is optional (a default value of 6.0 |Ang| will  
     29Entering a wavelength value is optional (a default value of 6.0 |Ang| will 
    2830be used). 
    2931 
     
    3840*  Parentheses can be nested, such as "(CaCO3(H2O)6)1". 
    3941 
    40 *  Isotopes are represented by their atomic number in *square brackets*, such  
     42*  Isotopes are represented by their atomic number in *square brackets*, such 
    4143   as "CaCO[18]3+6H2O", H[1], or H[2]. 
    4244 
    4345*  Numbers of atoms can be integer or decimal, such as "CaCO3+(3HO0.5)2". 
    4446 
    45 *  The SLD of mixtures can be calculated as well. For example, for a 70-30  
     47*  The SLD of mixtures can be calculated as well. For example, for a 70-30 
    4648   mixture of H2O/D2O write "H14O7+D6O3" or more simply "H7D3O5" (i.e. this says 
    4749   7 hydrogens, 3 deuteriums, and 5 oxygens) and enter a mass density calculated 
    4850   on the percentages of H2O and D2O. 
    4951 
    50 *  Type "C[13]6 H[2]12 O[18]6" for C(13)6H(2)12O(18)6 (6 Carbon-13 atoms, 12  
     52*  Type "C[13]6 H[2]12 O[18]6" for C(13)6H(2)12O(18)6 (6 Carbon-13 atoms, 12 
    5153   deuterium atoms, and 6 Oxygen-18 atoms). 
    52     
     54 
    5355.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 
    5456 
    55 .. note::  This help document was last changed by Steve King, 01May2015 
     57.. note::  This help document was last changed by Paul Kienzle, 05Apr2017 
    5658 
  • src/sas/sasgui/perspectives/calculator/media/slit_calculator_help.rst

    rf93b473f r5ed76f8  
    1111----------- 
    1212 
    13 This tool enables X-ray users to calculate the slit size (FWHM/2) for smearing  
     13This tool enables X-ray users to calculate the slit size (FWHM/2) for smearing 
    1414based on their half beam profile data. 
    1515 
    1616*NOTE! Whilst it may have some more generic applicability, the calculator has 
    17 only been tested with beam profile data from Anton-Paar SAXSess*\ |TM|\   
    18 *software.* 
     17only been tested with beam profile data from Anton-Paar SAXSess:sup:`TM` software.* 
    1918 
    2019.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 
     
    27262) Load a beam profile file in the *Data* field using the *Browse* button. 
    2827 
    29    *NOTE! To see an example of the beam profile file format, visit the file  
     28   *NOTE! To see an example of the beam profile file format, visit the file 
    3029   beam profile.DAT in your {installation_directory}/SasView/test folder.* 
    3130 
    32 3) Once a data is loaded, the slit size is automatically computed and displayed  
     313) Once a data is loaded, the slit size is automatically computed and displayed 
    3332   in the tool window. 
    3433 
    35 *NOTE! The beam profile file does not carry any information about the units of  
     34*NOTE! The beam profile file does not carry any information about the units of 
    3635the Q data. This calculator assumes the data has units of 1/\ |Ang|\ . If the 
    3736data is not in these units it must be manually converted beforehand.* 
  • src/sas/sasgui/perspectives/calculator/model_editor.py

    ra1b8fee r69363c7  
    3131import re 
    3232import logging 
     33import datetime 
     34 
    3335from wx.py.editwindow import EditWindow 
     36 
    3437from sas.sasgui.guiframe.documentation_window import DocumentationWindow 
     38 
    3539from .pyconsole import show_model_output, check_model 
    3640 
    3741logger = logging.getLogger(__name__) 
    38  
    3942 
    4043if sys.platform.count("win32") > 0: 
     
    7881    a Modal Dialog. 
    7982 
    80     :TODO the build in compiler currently balks at when it tries to import 
     83    :TODO the built in compiler currently balks at when it tries to import 
    8184    a model whose name contains spaces or symbols (such as + ... underscore 
    8285    should be fine).  Have fixed so the editor cannot save such a file name 
     
    106109        self.model2_string = "cylinder" 
    107110        self.name = 'Sum' + M_NAME 
    108         self.factor = 'scale_factor' 
    109111        self._notes = '' 
    110112        self._operator = '+' 
     
    133135        self.model2_name = str(self.model2.GetValue()) 
    134136        self.good_name = True 
    135         self.fill_oprator_combox() 
     137        self.fill_operator_combox() 
    136138 
    137139    def _layout_name(self): 
     
    336338            list_fnames = os.listdir(self.plugin_dir) 
    337339            # fake existing regular model name list 
    338             m_list = [model + ".py" for model in self.model_list] 
     340            m_list = [model.name + ".py" for model in self.model_list] 
    339341            list_fnames.append(m_list) 
    340342            if t_fname in list_fnames and title != mname: 
     
    491493        a sum or multiply model then create the appropriate string 
    492494        """ 
    493  
    494495        name = '' 
    495  
    496496        if operator == '*': 
    497497            name = 'Multi' 
    498             factor = 'BackGround' 
    499             f_oper = '+' 
     498            factor = 'background' 
    500499        else: 
    501500            name = 'Sum' 
    502501            factor = 'scale_factor' 
    503             f_oper = '*' 
    504  
    505         self.factor = factor 
     502 
    506503        self._operator = operator 
    507         self.explanation = "  Plugin Model = %s %s (model1 %s model2)\n" % \ 
    508                            (self.factor, f_oper, self._operator) 
     504        self.explanation = ("  Plugin_model = scale_factor * (model_1 {} " 
     505            "model_2) + background").format(operator) 
    509506        self.explanationctr.SetLabel(self.explanation) 
    510507        self.name = name + M_NAME 
    511508 
    512509 
    513     def fill_oprator_combox(self): 
     510    def fill_operator_combox(self): 
    514511        """ 
    515512        fill the current combobox with the operator 
     
    527524        return [self.model1_name, self.model2_name] 
    528525 
    529     def write_string(self, fname, name1, name2): 
     526    def write_string(self, fname, model1_name, model2_name): 
    530527        """ 
    531528        Write and Save file 
     
    533530        self.fname = fname 
    534531        description = self.desc_tcl.GetValue().lstrip().rstrip() 
    535         if description == '': 
    536             description = name1 + self._operator + name2 
    537         text = self._operator_choice.GetValue() 
    538         if text.count('+') > 0: 
    539             factor = 'scale_factor' 
    540             f_oper = '*' 
    541             default_val = '1.0' 
    542         else: 
    543             factor = 'BackGround' 
    544             f_oper = '+' 
    545             default_val = '0.0' 
    546         path = self.fname 
    547         try: 
    548             out_f = open(path, 'w') 
    549         except: 
    550             raise 
    551         lines = SUM_TEMPLATE.split('\n') 
    552         for line in lines: 
    553             try: 
    554                 if line.count("scale_factor"): 
    555                     line = line.replace('scale_factor', factor) 
    556                     #print "scale_factor", line 
    557                 if line.count("= %s"): 
    558                     out_f.write(line % (default_val) + "\n") 
    559                 elif line.count("import Model as P1"): 
    560                     if self.is_p1_custom: 
    561                         line = line.replace('#', '') 
    562                         out_f.write(line % name1 + "\n") 
    563                     else: 
    564                         out_f.write(line + "\n") 
    565                 elif line.count("import %s as P1"): 
    566                     if not self.is_p1_custom: 
    567                         line = line.replace('#', '') 
    568                         out_f.write(line % (name1) + "\n") 
    569                     else: 
    570                         out_f.write(line + "\n") 
    571                 elif line.count("import Model as P2"): 
    572                     if self.is_p2_custom: 
    573                         line = line.replace('#', '') 
    574                         out_f.write(line % name2 + "\n") 
    575                     else: 
    576                         out_f.write(line + "\n") 
    577                 elif line.count("import %s as P2"): 
    578                     if not self.is_p2_custom: 
    579                         line = line.replace('#', '') 
    580                         out_f.write(line % (name2) + "\n") 
    581                     else: 
    582                         out_f.write(line + "\n") 
    583                 elif line.count("P1 = find_model"): 
    584                     out_f.write(line % (name1) + "\n") 
    585                 elif line.count("P2 = find_model"): 
    586                     out_f.write(line % (name2) + "\n") 
    587  
    588                 elif line.count("self.description = '%s'"): 
    589                     out_f.write(line % description + "\n") 
    590                 #elif line.count("run") and line.count("%s"): 
    591                 #    out_f.write(line % self._operator + "\n") 
    592                 #elif line.count("evalDistribution") and line.count("%s"): 
    593                 #    out_f.write(line % self._operator + "\n") 
    594                 elif line.count("return") and line.count("%s") == 2: 
    595                     #print "line return", line 
    596                     out_f.write(line % (f_oper, self._operator) + "\n") 
    597                 elif line.count("out2")and line.count("%s"): 
    598                     out_f.write(line % self._operator + "\n") 
    599                 else: 
    600                     out_f.write(line + "\n") 
    601             except: 
    602                 raise 
    603         out_f.close() 
    604         #else: 
    605         #    msg = "Name exists already." 
     532        desc_line = '' 
     533        if description.strip() != '': 
     534            # Sasmodels generates a description for us. If the user provides 
     535            # their own description, add a line to overwrite the sasmodels one 
     536            desc_line = "\nmodel_info.description = '{}'".format(description) 
     537        name = os.path.splitext(os.path.basename(self.fname))[0] 
     538        output = SUM_TEMPLATE.format(name=name, model1=model1_name, 
     539            model2=model2_name, operator=self._operator, desc_line=desc_line) 
     540        with open(self.fname, 'w') as out_f: 
     541            out_f.write(output) 
    606542 
    607543    def compile_file(self, path): 
     
    643579        self.name_hsizer = None 
    644580        self.name_tcl = None 
     581        self.overwrite_cb = None 
    645582        self.desc_sizer = None 
    646583        self.desc_tcl = None 
     
    657594        self.warning = "" 
    658595        #This does not seem to be used anywhere so commenting out for now 
    659         #    -- PDB 2/26/17  
     596        #    -- PDB 2/26/17 
    660597        #self._description = "New Plugin Model" 
    661598        self.function_tcl = None 
     
    689626        #title name [string] 
    690627        name_txt = wx.StaticText(self, -1, 'Function Name : ') 
    691         overwrite_cb = wx.CheckBox(self, -1, "Overwrite existing plugin model of this name?", (10, 10)) 
    692         overwrite_cb.SetValue(False) 
    693         overwrite_cb.SetToolTipString("Overwrite it if already exists?") 
    694         wx.EVT_CHECKBOX(self, overwrite_cb.GetId(), self.on_over_cb) 
     628        self.overwrite_cb = wx.CheckBox(self, -1, "Overwrite existing plugin model of this name?", (10, 10)) 
     629        self.overwrite_cb.SetValue(False) 
     630        self.overwrite_cb.SetToolTipString("Overwrite it if already exists?") 
     631        wx.EVT_CHECKBOX(self, self.overwrite_cb.GetId(), self.on_over_cb) 
    695632        self.name_tcl = wx.TextCtrl(self, -1, size=(PANEL_WIDTH * 3 / 5, -1)) 
    696633        self.name_tcl.Bind(wx.EVT_TEXT_ENTER, self.on_change_name) 
     
    700637        self.name_tcl.SetToolTipString(hint_name) 
    701638        self.name_hsizer.AddMany([(self.name_tcl, 0, wx.LEFT | wx.TOP, 0), 
    702                                   (overwrite_cb, 0, wx.LEFT, 20)]) 
     639                                  (self.overwrite_cb, 0, wx.LEFT, 20)]) 
    703640        self.name_sizer.AddMany([(name_txt, 0, wx.LEFT | wx.TOP, 10), 
    704641                                 (self.name_hsizer, 0, 
     
    740677        self.param_sizer.AddMany([(param_txt, 0, wx.LEFT, 10), 
    741678                                  (self.param_tcl, 1, wx.EXPAND | wx.ALL, 10)]) 
    742          
     679 
    743680        # Parameters with polydispersity 
    744681        pd_param_txt = wx.StaticText(self, -1, 'Fit Parameters requiring ' + \ 
     
    755692        self.pd_param_tcl.setDisplayLineNumbers(True) 
    756693        self.pd_param_tcl.SetToolTipString(pd_param_tip) 
    757          
     694 
    758695        self.param_sizer.AddMany([(pd_param_txt, 0, wx.LEFT, 10), 
    759696                                  (self.pd_param_tcl, 1, wx.EXPAND | wx.ALL, 10)]) 
     
    855792                    exec "float(math.%s)" % item 
    856793                    self.math_combo.Append(str(item)) 
    857                 except: 
     794                except Exception: 
    858795                    self.math_combo.Append(str(item) + "()") 
    859796        self.math_combo.Bind(wx.EVT_COMBOBOX, self._on_math_select) 
     
    980917            msg = "Name exists already." 
    981918 
    982         # Prepare the messagebox 
     919        # 
    983920        if self.base is not None and not msg: 
    984921            self.base.update_custom_combo() 
    985             # Passed exception in import test as it will fail for sasmodels.sasview_model class 
    986             # Should add similar test for new style? 
    987             Model = None 
    988             try: 
    989                 exec "from %s import Model" % name 
    990             except: 
    991                 logger.error(sys.exc_value) 
    992922 
    993923        # Prepare the messagebox 
     
    995925            info = 'Error' 
    996926            color = 'red' 
     927            self.overwrite_cb.SetValue(True) 
     928            self.overwrite_name = True 
    997929        else: 
    998930            self._notes = result 
     
    1020952        :param func_str: content of func; Strings 
    1021953        """ 
    1022         try: 
    1023             out_f = open(fname, 'w') 
    1024         except: 
    1025             raise 
    1026         # Prepare the content of the function 
    1027         lines = CUSTOM_TEMPLATE.split('\n') 
    1028  
    1029         has_scipy = func_str.count("scipy.") 
    1030         if has_scipy: 
    1031             lines.insert(0, 'import scipy') 
    1032          
    1033         # Think about 2D later         
    1034         #self.is_2d = func_str.count("#self.ndim = 2") 
    1035         #line_2d = '' 
    1036         #if self.is_2d: 
    1037         #    line_2d = CUSTOM_2D_TEMP.split('\n') 
    1038          
    1039         # Also think about test later         
    1040         #line_test = TEST_TEMPLATE.split('\n') 
    1041         #local_params = '' 
    1042         #spaces = '        '#8spaces 
    1043         spaces4  = ' '*4 
    1044         spaces13 = ' '*13 
    1045         spaces16 = ' '*16      
     954        out_f = open(fname, 'w') 
     955 
     956        out_f.write(CUSTOM_TEMPLATE % { 
     957            'name': name, 
     958            'title': 'User model for ' + name, 
     959            'description': desc_str, 
     960            'date': datetime.datetime.now().strftime('%YYYY-%mm-%dd'), 
     961        }) 
     962 
     963        # Write out parameters 
    1046964        param_names = []    # to store parameter names 
    1047         has_scipy = func_str.count("scipy.") 
    1048         if has_scipy: 
    1049             lines.insert(0, 'import scipy') 
    1050  
    1051         # write function here 
    1052         for line in lines: 
    1053             # The location where to put the strings is 
    1054             # hard-coded in the template as shown below. 
    1055             out_f.write(line + '\n') 
    1056             if line.count('#name'): 
    1057                 out_f.write('name = "%s" \n' % name)                
    1058             elif line.count('#title'): 
    1059                 out_f.write('title = "User model for %s"\n' % name)                
    1060             elif line.count('#description'): 
    1061                 out_f.write('description = "%s"\n' % desc_str)                
    1062             elif line.count('#parameters'): 
    1063                 out_f.write('parameters = [ \n') 
    1064                 for param_line in param_str.split('\n'): 
    1065                     p_line = param_line.lstrip().rstrip() 
    1066                     if p_line: 
    1067                         pname, pvalue = self.get_param_helper(p_line) 
    1068                         param_names.append(pname) 
    1069                         out_f.write("%s['%s', '', %s, [-numpy.inf, numpy.inf], '', ''],\n" % (spaces16, pname, pvalue)) 
    1070                 for param_line in pd_param_str.split('\n'): 
    1071                     p_line = param_line.lstrip().rstrip() 
    1072                     if p_line: 
    1073                         pname, pvalue = self.get_param_helper(p_line) 
    1074                         param_names.append(pname) 
    1075                         out_f.write("%s['%s', '', %s, [-numpy.inf, numpy.inf], 'volume', ''],\n" % (spaces16, pname, pvalue)) 
    1076                 out_f.write('%s]\n' % spaces13) 
    1077              
    1078         # No form_volume or ER available in simple model editor 
    1079         out_f.write('def form_volume(*arg): \n') 
    1080         out_f.write('    return 1.0 \n') 
    1081         out_f.write('\n') 
    1082         out_f.write('def ER(*arg): \n') 
    1083         out_f.write('    return 1.0 \n') 
    1084          
    1085         # function to compute 
    1086         out_f.write('\n') 
    1087         out_f.write('def Iq(x ') 
    1088         for name in param_names: 
    1089             out_f.write(', %s' % name) 
    1090         out_f.write('):\n') 
     965        pd_params = [] 
     966        out_f.write('parameters = [ \n') 
     967        out_f.write('#   ["name", "units", default, [lower, upper], "type", "description"],\n') 
     968        for pname, pvalue, desc in self.get_param_helper(param_str): 
     969            param_names.append(pname) 
     970            out_f.write("    ['%s', '', %s, [-inf, inf], '', '%s'],\n" 
     971                        % (pname, pvalue, desc)) 
     972        for pname, pvalue, desc in self.get_param_helper(pd_param_str): 
     973            param_names.append(pname) 
     974            pd_params.append(pname) 
     975            out_f.write("    ['%s', '', %s, [-inf, inf], 'volume', '%s'],\n" 
     976                        % (pname, pvalue, desc)) 
     977        out_f.write('    ]\n') 
     978 
     979        # Write out function definition 
     980        out_f.write('def Iq(%s):\n' % ', '.join(['x'] + param_names)) 
     981        out_f.write('    """Absolute scattering"""\n') 
     982        if "scipy." in func_str: 
     983            out_f.write('    import scipy') 
     984        if "numpy." in func_str: 
     985            out_f.write('    import numpy') 
     986        if "np." in func_str: 
     987            out_f.write('    import numpy as np') 
    1091988        for func_line in func_str.split('\n'): 
    1092989            out_f.write('%s%s\n' % (spaces4, func_line)) 
    1093          
    1094         Iqxy_string = 'return Iq(numpy.sqrt(x**2+y**2) ' 
    1095              
     990        out_f.write('## uncomment the following if Iq works for vector x\n') 
     991        out_f.write('#Iq.vectorized = True\n') 
     992 
     993        # If polydisperse, create place holders for form_volume, ER and VR 
     994        if pd_params: 
     995            out_f.write('\n') 
     996            out_f.write(CUSTOM_TEMPLATE_PD % {'args': ', '.join(pd_params)}) 
     997 
     998        # Create place holder for Iqxy 
    1096999        out_f.write('\n') 
    1097         out_f.write('def Iqxy(x, y ') 
    1098         for name in param_names: 
    1099             out_f.write(', %s' % name) 
    1100             Iqxy_string += ', ' + name 
    1101         out_f.write('):\n') 
    1102         Iqxy_string += ')' 
    1103         out_f.write('%s%s\n' % (spaces4, Iqxy_string)) 
     1000        out_f.write('#def Iqxy(%s):\n' % ', '.join(["x", "y"] + param_names)) 
     1001        out_f.write('#    """Absolute scattering of oriented particles."""\n') 
     1002        out_f.write('#    ...\n') 
     1003        out_f.write('#    return oriented_form(x, y, args)\n') 
     1004        out_f.write('## uncomment the following if Iqxy works for vector x, y\n') 
     1005        out_f.write('#Iqxy.vectorized = True\n') 
    11041006 
    11051007        out_f.close() 
    11061008 
    1107     def get_param_helper(self, line): 
    1108         """ 
    1109         Get string in line to define the params dictionary 
    1110  
    1111         :param line: one line of string got from the param_str 
    1112         """ 
    1113         items = line.split(";") 
    1114         for item in items: 
    1115             name = item.split("=")[0].lstrip().rstrip() 
    1116             try: 
    1117                 value = item.split("=")[1].lstrip().rstrip() 
    1118                 float(value) 
    1119             except: 
    1120                 value = 1.0 # default 
    1121  
    1122         return name, value 
     1009    def get_param_helper(self, param_str): 
     1010        """ 
     1011        yield a sequence of name, value pairs for the parameters in param_str 
     1012 
     1013        Parameters can be defined by one per line by name=value, or multiple 
     1014        on the same line by separating the pairs by semicolon or comma.  The 
     1015        value is optional and defaults to "1.0". 
     1016        """ 
     1017        for line in param_str.replace(';', ',').split('\n'): 
     1018            for item in line.split(','): 
     1019                defn, desc = item.split('#', 1) if '#' in item else (item, '') 
     1020                name, value = defn.split('=', 1) if '=' in defn else (defn, '1.0') 
     1021                if name: 
     1022                    yield [v.strip() for v in (name, value, desc)] 
    11231023 
    11241024    def set_function_helper(self, line): 
     
    11541054        running "file:///...." 
    11551055 
    1156     :param evt: Triggers on clicking the help button 
    1157     """ 
     1056        :param evt: Triggers on clicking the help button 
     1057        """ 
    11581058 
    11591059        _TreeLocation = "user/sasgui/perspectives/fitting/fitting_help.html" 
     
    11981098## Templates for plugin models 
    11991099 
    1200 CUSTOM_TEMPLATE = """ 
     1100CUSTOM_TEMPLATE = '''\ 
     1101r""" 
     1102Definition 
     1103---------- 
     1104 
     1105Calculates %(name)s. 
     1106 
     1107%(description)s 
     1108 
     1109References 
     1110---------- 
     1111 
     1112Authorship and Verification 
     1113--------------------------- 
     1114 
     1115* **Author:** --- **Date:** %(date)s 
     1116* **Last Modified by:** --- **Date:** %(date)s 
     1117* **Last Reviewed by:** --- **Date:** %(date)s 
     1118""" 
     1119 
    12011120from math import * 
    1202 import os 
    1203 import sys 
    1204 import numpy 
    1205  
    1206 #name  
    1207  
    1208 #title 
    1209  
    1210 #description 
    1211  
    1212 #parameters  
    1213  
     1121from numpy import inf 
     1122 
     1123name = "%(name)s" 
     1124title = "%(title)s" 
     1125description = """%(description)s""" 
     1126 
     1127''' 
     1128 
     1129CUSTOM_TEMPLATE_PD = '''\ 
     1130def form_volume(%(args)s): 
     1131    """ 
     1132    Volume of the particles used to compute absolute scattering intensity 
     1133    and to weight polydisperse parameter contributions. 
     1134    """ 
     1135    return 0.0 
     1136 
     1137def ER(%(args)s): 
     1138    """ 
     1139    Effective radius of particles to be used when computing structure factors. 
     1140 
     1141    Input parameters are vectors ranging over the mesh of polydispersity values. 
     1142    """ 
     1143    return 0.0 
     1144 
     1145def VR(%(args)s): 
     1146    """ 
     1147    Volume ratio of particles to be used when computing structure factors. 
     1148 
     1149    Input parameters are vectors ranging over the mesh of polydispersity values. 
     1150    """ 
     1151    return 1.0 
     1152''' 
     1153 
     1154SUM_TEMPLATE = """ 
     1155from sasmodels.core import load_model_info 
     1156from sasmodels.sasview_model import make_model_from_info 
     1157 
     1158model_info = load_model_info('{model1}{operator}{model2}') 
     1159model_info.name = '{name}'{desc_line} 
     1160Model = make_model_from_info(model_info) 
    12141161""" 
    1215  
    1216 CUSTOM_2D_TEMP = """ 
    1217     def run(self, x=0.0, y=0.0): 
    1218         if x.__class__.__name__ == 'list': 
    1219             x_val = x[0] 
    1220             y_val = y[0]*0.0 
    1221             return self.function(x_val, y_val) 
    1222         elif x.__class__.__name__ == 'tuple': 
    1223             msg = "Tuples are not allowed as input to BaseComponent models" 
    1224             raise ValueError, msg 
    1225         else: 
    1226             return self.function(x, 0.0) 
    1227     def runXY(self, x=0.0, y=0.0): 
    1228         if x.__class__.__name__ == 'list': 
    1229             return self.function(x, y) 
    1230         elif x.__class__.__name__ == 'tuple': 
    1231             msg = "Tuples are not allowed as input to BaseComponent models" 
    1232             raise ValueError, msg 
    1233         else: 
    1234             return self.function(x, y) 
    1235     def evalDistribution(self, qdist): 
    1236         if qdist.__class__.__name__ == 'list': 
    1237             msg = "evalDistribution expects a list of 2 ndarrays" 
    1238             if len(qdist)!=2: 
    1239                 raise RuntimeError, msg 
    1240             if qdist[0].__class__.__name__ != 'ndarray': 
    1241                 raise RuntimeError, msg 
    1242             if qdist[1].__class__.__name__ != 'ndarray': 
    1243                 raise RuntimeError, msg 
    1244             v_model = numpy.vectorize(self.runXY, otypes=[float]) 
    1245             iq_array = v_model(qdist[0], qdist[1]) 
    1246             return iq_array 
    1247         elif qdist.__class__.__name__ == 'ndarray': 
    1248             v_model = numpy.vectorize(self.runXY, otypes=[float]) 
    1249             iq_array = v_model(qdist) 
    1250             return iq_array 
    1251 """ 
    1252 TEST_TEMPLATE = """ 
    1253 ###################################################################### 
    1254 ## THIS IS FOR TEST. DO NOT MODIFY THE FOLLOWING LINES!!!!!!!!!!!!!!!! 
    12551162if __name__ == "__main__": 
    1256     m= Model() 
    1257     out1 = m.runXY(0.0) 
    1258     out2 = m.runXY(0.01) 
    1259     isfine1 = numpy.isfinite(out1) 
    1260     isfine2 = numpy.isfinite(out2) 
    1261     print "Testing the value at Q = 0.0:" 
    1262     print out1, " : finite? ", isfine1 
    1263     print "Testing the value at Q = 0.01:" 
    1264     print out2, " : finite? ", isfine2 
    1265     if isfine1 and isfine2: 
    1266         print "===> Simple Test: Passed!" 
    1267     else: 
    1268         print "===> Simple Test: Failed!" 
    1269 """ 
    1270 SUM_TEMPLATE = """ 
    1271 # A sample of an experimental model function for Sum/Multiply(Pmodel1,Pmodel2) 
    1272 import os 
    1273 import sys 
    1274 import copy 
    1275 import collections 
    1276  
    1277 import numpy 
    1278  
    1279 from sas.sascalc.fit.pluginmodel import Model1DPlugin 
    1280 from sasmodels.sasview_model import find_model 
    1281  
    1282 class Model(Model1DPlugin): 
    1283     name = os.path.splitext(os.path.basename(__file__))[0] 
    1284     is_multiplicity_model = False 
    1285     def __init__(self, multiplicity=1): 
    1286         Model1DPlugin.__init__(self, name='') 
    1287         P1 = find_model('%s') 
    1288         P2 = find_model('%s') 
    1289         p_model1 = P1() 
    1290         p_model2 = P2() 
    1291         ## Setting  model name model description 
    1292         self.description = '%s' 
    1293         if self.name.rstrip().lstrip() == '': 
    1294             self.name = self._get_name(p_model1.name, p_model2.name) 
    1295         if self.description.rstrip().lstrip() == '': 
    1296             self.description = p_model1.name 
    1297             self.description += p_model2.name 
    1298             self.fill_description(p_model1, p_model2) 
    1299  
    1300         ## Define parameters 
    1301         self.params = collections.OrderedDict() 
    1302  
    1303         ## Parameter details [units, min, max] 
    1304         self.details = {} 
    1305         ## Magnetic Panrameters 
    1306         self.magnetic_params = [] 
    1307         # non-fittable parameters 
    1308         self.non_fittable = p_model1.non_fittable 
    1309         self.non_fittable += p_model2.non_fittable 
    1310  
    1311         ##models 
    1312         self.p_model1= p_model1 
    1313         self.p_model2= p_model2 
    1314  
    1315  
    1316         ## dispersion 
    1317         self._set_dispersion() 
    1318         ## Define parameters 
    1319         self._set_params() 
    1320         ## New parameter:scaling_factor 
    1321         self.params['scale_factor'] = %s 
    1322  
    1323         ## Parameter details [units, min, max] 
    1324         self._set_details() 
    1325         self.details['scale_factor'] = ['', 0.0, numpy.inf] 
    1326  
    1327  
    1328         #list of parameter that can be fitted 
    1329         self._set_fixed_params() 
    1330  
    1331         ## parameters with orientation 
    1332         self.orientation_params = [] 
    1333         for item in self.p_model1.orientation_params: 
    1334             new_item = "p1_" + item 
    1335             if not new_item in self.orientation_params: 
    1336                 self.orientation_params.append(new_item) 
    1337  
    1338         for item in self.p_model2.orientation_params: 
    1339             new_item = "p2_" + item 
    1340             if not new_item in self.orientation_params: 
    1341                 self.orientation_params.append(new_item) 
    1342         ## magnetic params 
    1343         self.magnetic_params = [] 
    1344         for item in self.p_model1.magnetic_params: 
    1345             new_item = "p1_" + item 
    1346             if not new_item in self.magnetic_params: 
    1347                 self.magnetic_params.append(new_item) 
    1348  
    1349         for item in self.p_model2.magnetic_params: 
    1350             new_item = "p2_" + item 
    1351             if not new_item in self.magnetic_params: 
    1352                 self.magnetic_params.append(new_item) 
    1353         # get multiplicity if model provide it, else 1. 
    1354         try: 
    1355             multiplicity1 = p_model1.multiplicity 
    1356             try: 
    1357                 multiplicity2 = p_model2.multiplicity 
    1358             except: 
    1359                 multiplicity2 = 1 
    1360         except: 
    1361             multiplicity1 = 1 
    1362             multiplicity2 = 1 
    1363         ## functional multiplicity of the model 
    1364         self.multiplicity1 = multiplicity1 
    1365         self.multiplicity2 = multiplicity2 
    1366         self.multiplicity_info = [] 
    1367  
    1368     def _clone(self, obj): 
    1369         import copy 
    1370         obj.params     = copy.deepcopy(self.params) 
    1371         obj.description     = copy.deepcopy(self.description) 
    1372         obj.details    = copy.deepcopy(self.details) 
    1373         obj.dispersion = copy.deepcopy(self.dispersion) 
    1374         obj.p_model1  = self.p_model1.clone() 
    1375         obj.p_model2  = self.p_model2.clone() 
    1376         #obj = copy.deepcopy(self) 
    1377         return obj 
    1378  
    1379     def _get_name(self, name1, name2): 
    1380         p1_name = self._get_upper_name(name1) 
    1381         if not p1_name: 
    1382             p1_name = name1 
    1383         name = p1_name 
    1384         name += "_and_" 
    1385         p2_name = self._get_upper_name(name2) 
    1386         if not p2_name: 
    1387             p2_name = name2 
    1388         name += p2_name 
    1389         return name 
    1390  
    1391     def _get_upper_name(self, name=None): 
    1392         if name is None: 
    1393             return "" 
    1394         upper_name = "" 
    1395         str_name = str(name) 
    1396         for index in range(len(str_name)): 
    1397             if str_name[index].isupper(): 
    1398                 upper_name += str_name[index] 
    1399         return upper_name 
    1400  
    1401     def _set_dispersion(self): 
    1402         self.dispersion = collections.OrderedDict() 
    1403         ##set dispersion only from p_model 
    1404         for name , value in self.p_model1.dispersion.iteritems(): 
    1405             #if name.lower() not in self.p_model1.orientation_params: 
    1406             new_name = "p1_" + name 
    1407             self.dispersion[new_name]= value 
    1408         for name , value in self.p_model2.dispersion.iteritems(): 
    1409             #if name.lower() not in self.p_model2.orientation_params: 
    1410             new_name = "p2_" + name 
    1411             self.dispersion[new_name]= value 
    1412  
    1413     def function(self, x=0.0): 
    1414         return 0 
    1415  
    1416     def getProfile(self): 
    1417         try: 
    1418             x,y = self.p_model1.getProfile() 
    1419         except: 
    1420             x = None 
    1421             y = None 
    1422  
    1423         return x, y 
    1424  
    1425     def _set_params(self): 
    1426         for name , value in self.p_model1.params.iteritems(): 
    1427             # No 2D-supported 
    1428             #if name not in self.p_model1.orientation_params: 
    1429             new_name = "p1_" + name 
    1430             self.params[new_name]= value 
    1431  
    1432         for name , value in self.p_model2.params.iteritems(): 
    1433             # No 2D-supported 
    1434             #if name not in self.p_model2.orientation_params: 
    1435             new_name = "p2_" + name 
    1436             self.params[new_name]= value 
    1437  
    1438         # Set "scale" as initializing 
    1439         self._set_scale_factor() 
    1440  
    1441  
    1442     def _set_details(self): 
    1443         for name ,detail in self.p_model1.details.iteritems(): 
    1444             new_name = "p1_" + name 
    1445             #if new_name not in self.orientation_params: 
    1446             self.details[new_name]= detail 
    1447  
    1448         for name ,detail in self.p_model2.details.iteritems(): 
    1449             new_name = "p2_" + name 
    1450             #if new_name not in self.orientation_params: 
    1451             self.details[new_name]= detail 
    1452  
    1453     def _set_scale_factor(self): 
    1454         pass 
    1455  
    1456  
    1457     def setParam(self, name, value): 
    1458         # set param to this (p1, p2) model 
    1459         self._setParamHelper(name, value) 
    1460  
    1461         ## setParam to p model 
    1462         model_pre = '' 
    1463         new_name = '' 
    1464         name_split = name.split('_', 1) 
    1465         if len(name_split) == 2: 
    1466             model_pre = name.split('_', 1)[0] 
    1467             new_name = name.split('_', 1)[1] 
    1468         if model_pre == "p1": 
    1469             if new_name in self.p_model1.getParamList(): 
    1470                 self.p_model1.setParam(new_name, value) 
    1471         elif model_pre == "p2": 
    1472              if new_name in self.p_model2.getParamList(): 
    1473                 self.p_model2.setParam(new_name, value) 
    1474         elif name == 'scale_factor': 
    1475             self.params['scale_factor'] = value 
    1476         else: 
    1477             raise ValueError, "Model does not contain parameter %s" % name 
    1478  
    1479     def getParam(self, name): 
    1480         # Look for dispersion parameters 
    1481         toks = name.split('.') 
    1482         if len(toks)==2: 
    1483             for item in self.dispersion.keys(): 
    1484                 # 2D not supported 
    1485                 if item.lower()==toks[0].lower(): 
    1486                     for par in self.dispersion[item]: 
    1487                         if par.lower() == toks[1].lower(): 
    1488                             return self.dispersion[item][par] 
    1489         else: 
    1490             # Look for standard parameter 
    1491             for item in self.params.keys(): 
    1492                 if item.lower()==name.lower(): 
    1493                     return self.params[item] 
    1494         return 
    1495         #raise ValueError, "Model does not contain parameter %s" % name 
    1496  
    1497     def _setParamHelper(self, name, value): 
    1498         # Look for dispersion parameters 
    1499         toks = name.split('.') 
    1500         if len(toks)== 2: 
    1501             for item in self.dispersion.keys(): 
    1502                 if item.lower()== toks[0].lower(): 
    1503                     for par in self.dispersion[item]: 
    1504                         if par.lower() == toks[1].lower(): 
    1505                             self.dispersion[item][par] = value 
    1506                             return 
    1507         else: 
    1508             # Look for standard parameter 
    1509             for item in self.params.keys(): 
    1510                 if item.lower()== name.lower(): 
    1511                     self.params[item] = value 
    1512                     return 
    1513  
    1514         raise ValueError, "Model does not contain parameter %s" % name 
    1515  
    1516  
    1517     def _set_fixed_params(self): 
    1518         self.fixed = [] 
    1519         for item in self.p_model1.fixed: 
    1520             new_item = "p1" + item 
    1521             self.fixed.append(new_item) 
    1522         for item in self.p_model2.fixed: 
    1523             new_item = "p2" + item 
    1524             self.fixed.append(new_item) 
    1525  
    1526         self.fixed.sort() 
    1527  
    1528  
    1529     def run(self, x = 0.0): 
    1530         self._set_scale_factor() 
    1531         return self.params['scale_factor'] %s \ 
    1532 (self.p_model1.run(x) %s self.p_model2.run(x)) 
    1533  
    1534     def runXY(self, x = 0.0): 
    1535         self._set_scale_factor() 
    1536         return self.params['scale_factor'] %s \ 
    1537 (self.p_model1.runXY(x) %s self.p_model2.runXY(x)) 
    1538  
    1539     ## Now (May27,10) directly uses the model eval function 
    1540     ## instead of the for-loop in Base Component. 
    1541     def evalDistribution(self, x = []): 
    1542         self._set_scale_factor() 
    1543         return self.params['scale_factor'] %s \ 
    1544 (self.p_model1.evalDistribution(x) %s \ 
    1545 self.p_model2.evalDistribution(x)) 
    1546  
    1547     def set_dispersion(self, parameter, dispersion): 
    1548         value= None 
    1549         new_pre = parameter.split("_", 1)[0] 
    1550         new_parameter = parameter.split("_", 1)[1] 
    1551         try: 
    1552             if new_pre == 'p1' and \ 
    1553 new_parameter in self.p_model1.dispersion.keys(): 
    1554                 value= self.p_model1.set_dispersion(new_parameter, dispersion) 
    1555             if new_pre == 'p2' and \ 
    1556 new_parameter in self.p_model2.dispersion.keys(): 
    1557                 value= self.p_model2.set_dispersion(new_parameter, dispersion) 
    1558             self._set_dispersion() 
    1559             return value 
    1560         except: 
    1561             raise 
    1562  
    1563     def fill_description(self, p_model1, p_model2): 
    1564         description = "" 
    1565         description += "This model gives the summation or multiplication of" 
    1566         description += "%s and %s. "% ( p_model1.name, p_model2.name ) 
    1567         self.description += description 
    1568  
    1569 if __name__ == "__main__": 
    1570     m1= Model() 
    1571     #m1.setParam("p1_scale", 25) 
    1572     #m1.setParam("p1_length", 1000) 
    1573     #m1.setParam("p2_scale", 100) 
    1574     #m1.setParam("p2_rg", 100) 
    1575     out1 = m1.runXY(0.01) 
    1576  
    1577     m2= Model() 
    1578     #m2.p_model1.setParam("scale", 25) 
    1579     #m2.p_model1.setParam("length", 1000) 
    1580     #m2.p_model2.setParam("scale", 100) 
    1581     #m2.p_model2.setParam("rg", 100) 
    1582     out2 = m2.p_model1.runXY(0.01) %s m2.p_model2.runXY(0.01)\n 
    1583     print "My name is %s."% m1.name 
    1584     print out1, " = ", out2 
    1585     if out1 == out2: 
    1586         print "===> Simple Test: Passed!" 
    1587     else: 
    1588         print "===> Simple Test: Failed!" 
    1589 """ 
    1590  
    1591 if __name__ == "__main__": 
    1592 #    app = wx.PySimpleApp() 
    15931163    main_app = wx.App() 
    15941164    main_frame = TextDialog(id=1, model_list=["SphereModel", "CylinderModel"], 
    1595                        plugin_dir='../fitting/plugin_models') 
     1165                            plugin_dir='../fitting/plugin_models') 
    15961166    main_frame.ShowModal() 
    15971167    main_app.MainLoop() 
    1598  
    1599 #if __name__ == "__main__": 
    1600 #    from sas.sasgui.perspectives.fitting import models 
    1601 #    dir_path = models.find_plugins_dir() 
    1602 #    app = wx.App() 
    1603 #    window = EditorWindow(parent=None, base=None, path=dir_path, title="Editor") 
    1604 #    app.MainLoop() 
  • src/sas/sasgui/perspectives/calculator/pyconsole.py

    r7432acb r4627657  
    3737    Iqxy = model.evalDistribution([qx, qy]) 
    3838 
    39     result = """ 
    40     Iq(%s) = %s 
    41     Iqxy(%s, %s) = %s 
    42     """%(q, Iq, qx, qy, Iqxy) 
     39    # check the model's unit tests run 
     40    from sasmodels.model_test import run_one 
     41    result = run_one(path) 
    4342 
    4443    return result 
     
    8988        ok = wx.Button(self, wx.ID_OK, "OK") 
    9089 
    91         # Mysterious constraint layouts from  
     90        # Mysterious constraint layouts from 
    9291        # https://www.wxpython.org/docs/api/wx.lib.layoutf.Layoutf-class.html 
    9392        lc = layoutf.Layoutf('t=t5#1;b=t5#2;l=l5#1;r=r5#1', (self,ok)) 
  • src/sas/sasgui/perspectives/calculator/resolution_calculator_panel.py

    r7432acb r01cda57  
    934934    def _sigma_strings(self): 
    935935        """ 
    936         Recode sigmas as strins 
     936        Recode sigmas as strings 
    937937        """ 
    938938        sigma_r = self.format_number(self.resolution.sigma_1) 
     
    12081208        source_hint += "Mass of %s: m = %s [g]" % \ 
    12091209                            (selection, str(self.resolution.get_neutron_mass())) 
    1210         #source_tip.SetTip(source_hint) 
     1210        # source_tip.SetTip(source_hint) 
    12111211        self.mass_txt.ToolTip.SetTip(source_hint) 
    12121212 
Note: See TracChangeset for help on using the changeset viewer.