Changeset 840ac87 in sasview for src


Ignore:
Timestamp:
Sep 20, 2018 12:44:12 PM (6 years ago)
Author:
Paul Kienzle <pkienzle@…>
Branches:
ticket-1094-headless
Children:
1dc134e6
Parents:
a072198 (diff), 912e645 (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 ticket-1094-headless

Location:
src/sas
Files:
7 added
25 edited

Legend:

Unmodified
Added
Removed
  • src/sas/sascalc/dataloader/readers/abs_reader.py

    re3775c6 rbd5c3b1  
    171171 
    172172                try: 
    173                     _x = float(toks[0]) 
     173                    _x = float(toks[4]) 
    174174                    _y = float(toks[1]) 
    175175                    _dy = float(toks[2]) 
  • src/sas/sascalc/fit/pagestate.py

    raca687a r840ac87  
    144144################################################################################ 
    145145import time 
     146import re 
    146147import os 
    147148import sys 
     
    773774                    name = value.split(':', 1)[1].strip() 
    774775                    file_value = "File name:" + name 
     776                    #Truncating string so print doesn't complain of being outside margins 
     777                    if sys.platform != "win32": 
     778                        MAX_STRING_LENGHT = 50 
     779                        if len(file_value) > MAX_STRING_LENGHT: 
     780                            file_value = "File name:.."+file_value[-MAX_STRING_LENGHT+10:] 
    775781                    file_name = CENTRE % file_value 
    776782                    if len(title) == 0: 
     
    848854        html_str, text_str, title = self._get_report_string() 
    849855        # Allow 2 figures to append 
    850         image_links = [FEET_2%fig for fig in fig_urls] 
    851  
     856        #Constraining image width for OSX and linux, so print doesn't complain of being outside margins 
     857        if sys.platform == "win32": 
     858            image_links = [FEET_2%fig for fig in fig_urls] 
     859        else: 
     860            image_links = [FEET_2_unix%fig for fig in fig_urls] 
    852861        # final report html strings 
    853862        report_str = html_str + ELINE.join(image_links) 
    854  
     863        report_str += FEET_3 
    855864        return report_str, text_str 
    856865 
     
    10811090        if node.get('version'): 
    10821091            # Get the version for model conversion purposes 
    1083             self.version = tuple(int(e) for e in 
    1084                                  str.split(node.get('version'), ".")) 
     1092            x = re.sub('[^\d.]', '', node.get('version')) 
     1093            self.version = tuple(int(e) for e in str.split(x, ".")) 
    10851094            # The tuple must be at least 3 items long 
    10861095            while len(self.version) < 3: 
     
    14951504""" 
    14961505FEET_2 = \ 
    1497 """<img src="%s" ></img> 
     1506"""<img src="%s"></img> 
     1507""" 
     1508FEET_2_unix = \ 
     1509"""<img src="%s" width="540"></img> 
    14981510""" 
    14991511FEET_3 = \ 
  • src/sas/sasgui/guiframe/config.py

    r1efbc190 r8ac05a5  
    3333_do_aboutbox = True 
    3434_do_acknowledge = True 
     35_do_release = True 
    3536_do_tutorial = True 
    3637_acknowledgement_preamble =\ 
     
    4950_acknowledgement_citation = \ 
    5051'''M. Doucet et al. SasView Version 4.1.2, Zenodo, 10.5281/zenodo.825675''' 
    51  
    5252_acknowledgement =  \ 
    5353'''This work was originally developed as part of the DANSE project funded by the US NSF under Award DMR-0520547,\n but is currently maintained by a collaboration between UTK, UMD, NIST, ORNL, ISIS, ESS, ILL, ANSTO, TU Delft, DLS, and the scattering community.\n\n SasView also contains code developed with funding from the EU Horizon 2020 programme under the SINE2020 project (Grant No 654000).\nA list of individual contributors can be found at: http://www.sasview.org/contact.html 
     
    9494_corner_image = os.path.join(icon_path, "angles_flat.png") 
    9595_welcome_image = os.path.join(icon_path, "SVwelcome.png") 
    96 _copyright = "(c) 2009 - 2017, UTK, UMD, NIST, ORNL, ISIS, ESS, ILL, ANSTO, TU Delft, and DLS" 
     96_copyright = "(c) 2009 - 2018, UTK, UMD, NIST, ORNL, ISIS, ESS, ILL, ANSTO, TU Delft, and DLS" 
    9797marketplace_url = "http://marketplace.sasview.org/" 
    9898 
  • src/sas/sasgui/guiframe/gui_manager.py

    rb963b20 r8ac05a5  
    12761276 
    12771277        wx_id = wx.NewId() 
    1278         self._help_menu.Append(wx_id, '&Documentation', '') 
     1278        self._help_menu.Append(wx_id, '&Documentation', 'Help documentation for SasView') 
    12791279        wx.EVT_MENU(self, wx_id, self._onSphinxDocs) 
    12801280 
    12811281        if config._do_tutorial and (IS_WIN or sys.platform == 'darwin'): 
    12821282            wx_id = wx.NewId() 
    1283             self._help_menu.Append(wx_id, '&Tutorial', 'Software tutorial') 
     1283            # Pluralised both occurences of 'Tutorial' in the line below 
     1284            # S King, Sep 2018 
     1285            self._help_menu.Append(wx_id, '&Tutorials', 'Tutorials on how to use SasView') 
    12841286            wx.EVT_MENU(self, wx_id, self._onTutorial) 
     1287 
     1288        if config.marketplace_url: 
     1289            wx_id = wx.NewId() 
     1290            self._help_menu.Append(wx_id, '&Model marketplace', 'Plug-in fitting models for SasView') 
     1291            wx.EVT_MENU(self, wx_id, self._on_marketplace_click) 
     1292 
     1293        if config._do_release: 
     1294            wx_id = wx.NewId() 
     1295            self._help_menu.Append(wx_id, '&Release notes', 
     1296                                   'SasView release notes and known issues') 
     1297            wx.EVT_MENU(self, wx_id, self._onRelease) 
    12851298 
    12861299        if config._do_acknowledge: 
     
    12931306            logger.info("Doing help menu") 
    12941307            wx_id = wx.NewId() 
    1295             self._help_menu.Append(wx_id, '&About', 'Software information') 
     1308            self._help_menu.Append(wx_id, '&About', 'Information about SasView') 
    12961309            wx.EVT_MENU(self, wx_id, self._onAbout) 
    1297  
    1298         if config.marketplace_url: 
    1299             wx_id = wx.NewId() 
    1300             self._help_menu.Append(wx_id, '&Model marketplace', '') 
    1301             wx.EVT_MENU(self, wx_id, self._on_marketplace_click) 
    13021310 
    13031311        # Checking for updates 
     
    21372145            dialog.ShowModal() 
    21382146 
     2147    def _onRelease(self, evt): 
     2148        """ 
     2149        Pop up the release notes 
     2150 
     2151        :param evt: menu event 
     2152 
     2153        """ 
     2154        # S King, Sep 2018 
     2155 
     2156        from documentation_window import DocumentationWindow 
     2157        _TreeLocation = "user/release.html" 
     2158        DocumentationWindow(self, -1, _TreeLocation, "", 
     2159                            "SasView Documentation") 
     2160 
    21392161    def _onTutorial(self, evt): 
    21402162        """ 
     
    21442166 
    21452167        """ 
    2146         if config._do_tutorial: 
    2147             path = config.TUTORIAL_PATH 
    2148             if IS_WIN: 
    2149                 try: 
    2150                     from sas.sasgui.guiframe.pdfview import PDFFrame 
    2151                     dialog = PDFFrame(None, -1, "Tutorial", path) 
    2152                     # put icon 
    2153                     self.put_icon(dialog) 
    2154                     dialog.Show(True) 
    2155                 except: 
    2156                     logger.error("Error in _onTutorial: %s" % sys.exc_value) 
    2157                     try: 
    2158                         # Try an alternate method 
    2159                         logger.error( 
    2160                             "Could not open the tutorial pdf, trying xhtml2pdf") 
    2161                         from xhtml2pdf import pisa 
    2162                         pisa.startViewer(path) 
    2163                     except: 
    2164                         logger.error( 
    2165                             "Could not open the tutorial pdf with xhtml2pdf") 
    2166                         msg = "This feature requires 'PDF Viewer'\n" 
    2167                         wx.MessageBox(msg, 'Error') 
    2168             else: 
    2169                 try: 
    2170                     command = "open '%s'" % path 
    2171                     os.system(command) 
    2172                 except: 
    2173                     try: 
    2174                         # Try an alternate method 
    2175                         logger.error( 
    2176                             "Could not open the tutorial pdf, trying xhtml2pdf") 
    2177                         from xhtml2pdf import pisa 
    2178                         pisa.startViewer(path) 
    2179                     except: 
    2180                         logger.error( 
    2181                             "Could not open the tutorial pdf with xhtml2pdf") 
    2182                         msg = "This feature requires the Preview application\n" 
    2183                         wx.MessageBox(msg, 'Error') 
     2168        # Action changed from that in 2.x/3.x/4.0.x/4.1.x 
     2169        # Help >> Tutorial used to bring up a pdf of the 
     2170        # original 2.x tutorial. 
     2171        # Code below, implemented from 4.2.0, redirects 
     2172        # action to the Tutorials page of the help  
     2173        # documentation to give access to all available 
     2174        # tutorials 
     2175        # S King, Sep 2018 
     2176 
     2177        from documentation_window import DocumentationWindow 
     2178        _TreeLocation = "user/tutorial.html" 
     2179        DocumentationWindow(self, -1, _TreeLocation, "", 
     2180                            "SasView Documentation") 
    21842181 
    21852182    def _onSphinxDocs(self, evt): 
  • src/sas/sasgui/guiframe/local_perspectives/plotting/parameters_panel_slicer.py

    ra26f67f ra20a255  
    251251            self.bck.Add(self.batch_slicer_button, (iy, ix), (1, 1), 
    252252                         wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15) 
     253            # Help button 
     254 
     255            self.bt_help = wx.Button(self, wx.NewId(), "HELP") 
     256            self.bt_help.SetToolTipString( 
     257                "Help for the slicer parameters and batch slicing.") 
     258            self.bck.Add(self.bt_help, (iy, 1), (1, 1), 
     259                         wx.ALIGN_RIGHT | wx.ADJUST_MINSIZE, 15) 
     260            wx.EVT_BUTTON(self, self.bt_help.GetId(), self.on_help) 
     261 
    253262            iy += 1 
    254263            self.bck.Add((5, 5), (iy, ix), (1, 1), 
    255264                         wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 5) 
     265 
    256266        self.bck.Layout() 
    257267        self.bck.Fit(self) 
     
    535545            self.default_value += "_{0}".format(key).split(" [")[0] 
    536546            self.default_value += "-{:.2f}".format(params[key]) 
     547 
     548    def on_help(self, event=None): 
     549        """ 
     550        Opens a help window for the slicer parameters/batch slicing window 
     551        :param event: 
     552        :return: 
     553        """ 
     554        from sas.sasgui.guiframe.documentation_window import DocumentationWindow 
     555 
     556        _TreeLocation = "user/sasgui/guiframe/graph_help.html" 
     557        _doc_viewer = DocumentationWindow(self, wx.ID_ANY, _TreeLocation, 
     558                                          "#d-data-averaging", 
     559                                          "Data Explorer Help") 
  • src/sas/sasgui/guiframe/media/graph_help.rst

    r5ed76f8 rde68f78  
    266266 
    267267.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 
     268.. _d_data_averaging: 
    268269 
    2692702D data averaging 
     
    301302Alternatively, once a 'slicer' is active you can also select the region to 
    302303average by bringing back the *Dataset Menu* and selecting *Edit Slicer 
    303 Parameters*. A dialog window will appear in which you can enter values to 
    304 define a region or select the number of points to plot (*nbins*). 
     304Parameters and Batch Fitting*. A dialog window will appear in which you can 
     305enter values to define a region, select the number of points to plot (*nbins*), 
     306or apply the slicer to any or all other 2D data plots. 
    305307 
    306308A separate plot window will also have appeared, displaying the requested 
     
    315317 
    316318To remove a 'slicer', bring back the *Dataset menu* and select *Clear Slicer*. 
     319 
     320Batch Slicing 
     321^^^^^^^^^^^^^ 
     322 
     323A slicer can be applied to any or all existing 2D data plots using the 'Slicer 
     324Parameters' window. To open the window, select *Edit Slicer Parameters and Batch 
     325Fitting* in the *Dataset Menu* (see Invoking_the_dataset_menu_). Batch slicing 
     326options are available at the bottom of the window. 
     327 
     328Select the 2D plots you want to apply the slicer to. All 2D plots are selected 
     329by default. The resulting 1D data for all slicers can be saved as a text file 
     330and then sent to fitting by selecting the *Auto save generated 1D* check box. 
     331Sending data to the fitting perspective requires the data be saved. 
     332 
     333Once the auto save check box is selected, you can select where the files are 
     334saved. The file name for the saved data is the slicer name plus the file name 
     335of the original data set, plus what is in the *Append to file name* field. The 
     336default value in the append to field includes the names and values for all of 
     337the slicer parameters. 
     338 
     339The batch of slices can be sent to fitting if desired, with three options 
     340available. The first is to not fit the data, the second is to send the 
     341slices to individual fit pages, and the third is to send all sliced data to a 
     342single batch fit window. 
     343 
     344Clicking *Apply Slicer to Selected Plots* will create a slicer for each selected 
     345plot with the parameters entered in the 'Slicer Parameters' window. Depending on 
     346the options selected the data may then be saved, loaded as separate data sets in 
     347the data manager panel, and finally sent to fitting. 
    317348 
    318349Unmasked circular average 
  • src/sas/sasgui/guiframe/report_dialog.py

    r69a6897 rd0ce666f  
    77import sys 
    88import wx.html as html 
     9from sas.sasgui.guiframe.report_image_handler import ReportImageHandler 
    910 
    1011logger = logging.getLogger(__name__) 
     
    2728class BaseReportDialog(wx.Dialog): 
    2829 
    29     def __init__(self, report_list, *args, **kwds): 
     30    def __init__(self, report_list, imgRAM, fig_urls, *args, **kwds): 
    3031        """ 
    3132        Initialization. The parameters added to Dialog are: 
     
    3738        kwds["image"] = 'Dynamic Image' 
    3839 
     40        #MemoryFSHandle for storing images 
     41        self.imgRAM = imgRAM 
     42        #Images location in urls 
     43        self.fig_urls = fig_urls 
    3944        # title 
    4045        self.SetTitle("Report") 
     
    6671        button_close = wx.Button(self, wx.ID_OK, "Close") 
    6772        button_close.SetToolTipString("Close this report window.") 
     73        button_close.Bind(wx.EVT_BUTTON, self.onClose, 
     74                          id=button_close.GetId()) 
    6875        hbox.Add(button_close) 
    6976        button_close.SetFocus() 
     
    7582        hbox.Add(button_print) 
    7683 
    77         button_save = wx.Button(self, wx.NewId(), "Save") 
    78         button_save.SetToolTipString("Save this report.") 
    79         button_save.Bind(wx.EVT_BUTTON, self.onSave, id=button_save.GetId()) 
    80         hbox.Add(button_save) 
     84        if sys.platform != "darwin": 
     85            button_save = wx.Button(self, wx.NewId(), "Save") 
     86            button_save.SetToolTipString("Save this report.") 
     87            button_save.Bind(wx.EVT_BUTTON, self.onSave, id=button_save.GetId()) 
     88            hbox.Add(button_save) 
    8189 
    8290        # panel for report page 
     
    111119        printh.PrintText(self.report_html) 
    112120 
    113     def OnClose(self, event=None): 
     121 
     122    def onClose(self, event=None): 
    114123        """ 
    115124        Close the Dialog 
    116125        : event: Close button event 
    117126        """ 
    118         self.Close() 
     127        for fig in self.fig_urls: 
     128            ReportImageHandler.remove_figure(fig) 
     129 
     130        self.Destroy() 
    119131 
    120132    def HTML2PDF(self, data, filename): 
  • src/sas/sasgui/perspectives/calculator/media/slit_calculator_help.rst

    r5ed76f8 r346745a  
    1111----------- 
    1212 
    13 This tool enables X-ray users to calculate the slit size (FWHM/2) for smearing 
    14 based on their half beam profile data. 
     13This tool enables X-ray users to calculate the slit size (FWHM/2) for resolution  
     14smearing purposes based on their half beam profile data (as Q vs Intensity; any  
     15other data fields are ignored). 
    1516 
    16 *NOTE! Whilst it may have some more generic applicability, the calculator has 
    17 only been tested with beam profile data from Anton-Paar SAXSess:sup:`TM` software.* 
     17Method 
     18------ 
     19 
     20The tool works by sequentially summing 10 or more intensity values until a  
     21maximum value is attained. It then locates the Q values for the points just before,  
     22and just after, **half** of this maximum value and interpolates between them to get  
     23an accurate value for the Q value for the half maximum. 
     24 
     25NOTE! Whilst it may have some more generic applicability, the calculator has 
     26only been tested with beam profile data from Anton-Paar SAXSess\ :sup:`TM`\  software. 
     27The beam profile file does not carry any information about the units of the  
     28Q data. It is probably |nm^-1| but the resolution calculations assume the slit  
     29height/width has units of |Ang^-1|. If the beam profile data is not in these  
     30units then it, or the result, must be manually converted. 
    1831 
    1932.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 
     
    2740 
    2841   *NOTE! To see an example of the beam profile file format, visit the file 
    29    beam profile.DAT in your {installation_directory}/SasView/test folder.* 
     42   beam profile.DAT in your {installation_directory}/SasView/test_1d folder.* 
    3043 
    31443) Once a data is loaded, the slit size is automatically computed and displayed 
    3245   in the tool window. 
    3346 
    34 *NOTE! The beam profile file does not carry any information about the units of 
    35 the Q data. This calculator assumes the data has units of 1/\ |Ang|\ . If the 
    36 data is not in these units it must be manually converted beforehand.* 
    37  
    3847.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 
    3948 
    40 .. note::  This help document was last changed by Steve King, 01May2015 
     49.. note::  This help document was last changed by Steve King, 09Sep2018 
  • src/sas/sasgui/perspectives/calculator/model_editor.py

    rc6dfb9f r9bf40e7  
    4343if sys.platform.count("win32") > 0: 
    4444    FONT_VARIANT = 0 
    45     PNL_WIDTH = 450 
     45    PNL_WIDTH = 500 
    4646    PNL_HEIGHT = 320 
    4747else: 
    4848    FONT_VARIANT = 1 
    49     PNL_WIDTH = 590 
     49    PNL_WIDTH = 500 
    5050    PNL_HEIGHT = 350 
    5151M_NAME = 'Model' 
     
    495495        Choose the equation to use depending on whether we now have 
    496496        a sum or multiply model then create the appropriate string 
     497         
     498        for the sum model the result will be: 
     499        scale_factor * (scale1 * model_1 + scale2 * model_2) + background 
     500        while for the multiply model it will just be: 
     501        scale_factor * (model_1* model_2) + background 
    497502        """ 
    498503        name = '' 
    499504        if operator == '*': 
    500505            name = 'Multi' 
    501             factor = 'background' 
     506            factor_1 = '' 
     507            factor_2 = '' 
    502508        else: 
    503509            name = 'Sum' 
    504             factor = 'scale_factor' 
     510            factor_1 = 'scale_1 * ' 
     511            factor_2 = 'scale_2 * ' 
    505512 
    506513        self._operator = operator 
    507         self.explanation = ("  Plugin_model = scale_factor * (model_1 {} " 
    508             "model_2) + background").format(operator) 
     514        self.explanation = ("  Plugin_model = scale_factor * ({}model_1 {} " 
     515            "{}model_2) + background").format(factor_1,operator,factor_2) 
    509516        self.explanationctr.SetLabel(self.explanation) 
    510517        self.name = name + M_NAME 
     
    663670        Do the layout for parameter related widgets 
    664671        """ 
    665         param_txt = wx.StaticText(self, -1, 'Fit Parameters NOT requiring' + \ 
    666                                   ' polydispersity (if any): ') 
    667  
    668         param_tip = "#Set the parameters NOT requiring polydispersity " + \ 
    669         "and their initial values.\n" 
     672        param_txt = wx.StaticText(self, -1, 'Fit Parameters: ') 
     673 
     674        param_tip = "#Set the parameters and their initial values.\n" 
    670675        param_tip += "#Example:\n" 
    671676        param_tip += "A = 1\nB = 1" 
     
    681686                                  (self.param_tcl, 1, wx.EXPAND | wx.ALL, 10)]) 
    682687 
    683         # Parameters with polydispersity 
    684         pd_param_txt = wx.StaticText(self, -1, 'Fit Parameters requiring ' + \ 
    685                                      'polydispersity (if any): ') 
    686  
    687         pd_param_tip = "#Set the parameters requiring polydispersity and " + \ 
    688         "their initial values.\n" 
    689         pd_param_tip += "#Example:\n" 
    690         pd_param_tip += "C = 2\nD = 2" 
    691         newid = wx.NewId() 
    692         self.pd_param_tcl = EditWindow(self, newid, wx.DefaultPosition, 
    693                                     wx.DefaultSize, 
    694                                     wx.CLIP_CHILDREN | wx.SUNKEN_BORDER) 
    695         self.pd_param_tcl.setDisplayLineNumbers(True) 
    696         self.pd_param_tcl.SetToolTipString(pd_param_tip) 
    697  
    698         self.param_sizer.AddMany([(pd_param_txt, 0, wx.LEFT, 10), 
    699                                   (self.pd_param_tcl, 1, wx.EXPAND | wx.ALL, 10)]) 
    700688 
    701689    def _layout_function(self): 
     
    899887            description = self.desc_tcl.GetValue() 
    900888            param_str = self.param_tcl.GetText() 
    901             pd_param_str = self.pd_param_tcl.GetText() 
    902889            func_str = self.function_tcl.GetText() 
    903890            # No input for the model function 
     
    905892                if func_str.count('return') > 0: 
    906893                    self.write_file(self.fname, name, description, param_str, 
    907                                     pd_param_str, func_str) 
     894                                    func_str) 
    908895                    try: 
    909896                        result, msg = check_model(self.fname), None 
     
    945932        self.warning = msg 
    946933 
    947     def write_file(self, fname, name, desc_str, param_str, pd_param_str, func_str): 
     934    def write_file(self, fname, name, desc_str, param_str, func_str): 
    948935        """ 
    949936        Write content in file 
     
    952939        :param desc_str: content of the description strings 
    953940        :param param_str: content of params; Strings 
    954         :param pd_param_str: content of params requiring polydispersity; Strings 
    955941        :param func_str: content of func; Strings 
    956942        """ 
     
    966952        # Write out parameters 
    967953        param_names = []    # to store parameter names 
    968         pd_params = [] 
    969954        out_f.write('parameters = [ \n') 
    970955        out_f.write('#   ["name", "units", default, [lower, upper], "type", "description"],\n') 
     
    973958            out_f.write("    ['%s', '', %s, [-inf, inf], '', '%s'],\n" 
    974959                        % (pname, pvalue, desc)) 
    975         for pname, pvalue, desc in self.get_param_helper(pd_param_str): 
    976             param_names.append(pname) 
    977             pd_params.append(pname) 
    978             out_f.write("    ['%s', '', %s, [-inf, inf], 'volume', '%s'],\n" 
    979                         % (pname, pvalue, desc)) 
    980960        out_f.write('    ]\n') 
    981961 
    982962        # Write out function definition 
     963        out_f.write('\n') 
    983964        out_f.write('def Iq(%s):\n' % ', '.join(['x'] + param_names)) 
    984965        out_f.write('    """Absolute scattering"""\n') 
     
    990971            out_f.write('    import numpy as np') 
    991972        for func_line in func_str.split('\n'): 
    992             out_f.write('%s%s\n' % (spaces4, func_line)) 
     973            out_f.write('%s%s\n' % ('    ', func_line)) 
    993974        out_f.write('## uncomment the following if Iq works for vector x\n') 
    994975        out_f.write('#Iq.vectorized = True\n') 
    995  
    996         # If polydisperse, create place holders for form_volume, ER and VR 
    997         if pd_params: 
    998             out_f.write('\n') 
    999             out_f.write(CUSTOM_TEMPLATE_PD % {'args': ', '.join(pd_params)}) 
    1000976 
    1001977        # Create place holder for Iqxy 
     
    11281104description = """%(description)s""" 
    11291105 
    1130 ''' 
    1131  
    1132 CUSTOM_TEMPLATE_PD = '''\ 
    1133 def form_volume(%(args)s): 
    1134     """ 
    1135     Volume of the particles used to compute absolute scattering intensity 
    1136     and to weight polydisperse parameter contributions. 
    1137     """ 
    1138     return 0.0 
    1139  
    1140 def ER(%(args)s): 
    1141     """ 
    1142     Effective radius of particles to be used when computing structure factors. 
    1143  
    1144     Input parameters are vectors ranging over the mesh of polydispersity values. 
    1145     """ 
    1146     return 0.0 
    1147  
    1148 def VR(%(args)s): 
    1149     """ 
    1150     Volume ratio of particles to be used when computing structure factors. 
    1151  
    1152     Input parameters are vectors ranging over the mesh of polydispersity values. 
    1153     """ 
    1154     return 1.0 
    11551106''' 
    11561107 
  • src/sas/sasgui/perspectives/calculator/pyconsole.py

    r4627657 re2663b7  
    2828    Check that the model on the path can run. 
    2929    """ 
     30    # TODO: fix model caching 
     31    # model_test.run_one() is directly forcing a reload of the module, but 
     32    # sasview_model is caching models that have already been loaded. 
     33    # If the sasview load happens before the test, then the module is 
     34    # reloaded out from under it, which causes the global variables in 
     35    # the model function definitions to be cleared (at least in python 2.7). 
     36    # To fix the proximal problem of models failing on test, perform the 
     37    # run_one() tests first.  To fix the deeper problem we should either 
     38    # remove caching from sasmodels.sasview_model.load_custom_model() or 
     39    # add caching to sasmodels.custom.load_custom_kernel_module().  Another 
     40    # option is to add a runTests method to SasviewModel which runs the 
     41    # test suite directly from the model info structure.  Probably some 
     42    # combination of options: 
     43    #    (1) have this function (check_model) operate on a loaded model 
     44    #    so that caching isn't needed in sasview_models.load_custom_model 
     45    #    (2) add the runTests method to SasviewModel so that tests can 
     46    #    be run on a loaded module. 
     47    # 
     48    # Also, note that the model test suite runs the equivalent of the 
     49    # "try running the model" block below, and doesn't need to be run 
     50    # twice.  The reason for duplicating the block here is to generate 
     51    # an exception that show_model_output can catch.  Need to write the 
     52    # runTests method so that it returns success flag as well as output 
     53    # string so that the extra test is not necessary. 
     54 
     55    # check the model's unit tests run 
     56    from sasmodels.model_test import run_one 
     57    result = run_one(path) 
     58 
     59    # remove cached version of the model, if any 
     60    from sasmodels import sasview_model 
     61    sasview_model.MODEL_BY_PATH.pop(path, None) 
     62 
    3063    # try running the model 
    31     from sasmodels.sasview_model import load_custom_model 
    32     Model = load_custom_model(path) 
     64    Model = sasview_model.load_custom_model(path) 
    3365    model = Model() 
    3466    q =  np.array([0.01, 0.1]) 
     
    3668    qx, qy =  np.array([0.01, 0.01]), np.array([0.1, 0.1]) 
    3769    Iqxy = model.evalDistribution([qx, qy]) 
    38  
    39     # check the model's unit tests run 
    40     from sasmodels.model_test import run_one 
    41     result = run_one(path) 
    4270 
    4371    return result 
  • src/sas/sasgui/perspectives/calculator/resolution_calculator_panel.py

    r7432acb r1cf490b6  
    1818matplotlib.use('WXAgg') 
    1919from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas 
    20 from matplotlib.backends.backend_wxagg import NavigationToolbar2Wx as Toolbar 
     20from matplotlib.backends.backend_wxagg import NavigationToolbar2WxAgg as Toolbar 
    2121from matplotlib.backend_bases import FigureManagerBase 
    2222# Wx-Pylab magic for displaying plots within an application's window. 
  • src/sas/sasgui/perspectives/calculator/slit_length_calculator_panel.py

    r7432acb rd788619  
    248248            Complete the loading and compute the slit size 
    249249        """ 
     250        if isinstance(data, list): 
     251            data = data[0] 
    250252        if data is None or data.__class__.__name__ == 'Data2D': 
    251253            if self.parent.parent is None: 
  • src/sas/sasgui/perspectives/fitting/basepage.py

    r1f4d708 ra4a1ac9  
    3131 
    3232from sas.sasgui.guiframe.panel_base import PanelBase 
     33from sas.sasgui.guiframe.report_image_handler import ReportImageHandler 
    3334from sas.sasgui.guiframe.utils import format_number, check_float, IdList, \ 
    3435    check_int 
     
    641642        # get the strings for report 
    642643        report_str, text_str = self.state.report(fig_urls=refs) 
    643  
    644644        # Show the dialog 
    645645        report_list = [report_str, text_str, images] 
    646         dialog = ReportDialog(report_list, None, wx.ID_ANY, "") 
     646        dialog = ReportDialog(report_list, imgRAM, refs, None, wx.ID_ANY, "") 
    647647        dialog.Show() 
    648648 
     
    652652        by plotting, putting it into wx.FileSystem image object 
    653653        """ 
    654         images = [] 
    655         refs = [] 
    656  
    657         # For no figures in the list, prepare empty plot 
    658         if figs is None or len(figs) == 0: 
    659             figs = [None] 
    660  
    661         # Loop over the list of figures 
    662         # use wx.MemoryFSHandler 
    663         imgRAM = wx.MemoryFSHandler() 
    664         for fig in figs: 
    665             if fig is not None: 
    666                 ind = figs.index(fig) 
    667                 canvas = canvases[ind] 
    668  
    669             # store the image in wx.FileSystem Object 
    670             wx.FileSystem.AddHandler(wx.MemoryFSHandler()) 
    671  
    672             # index of the fig 
    673             ind = figs.index(fig) 
    674  
    675             # AddFile, image can be retrieved with 'memory:filename' 
    676             name = 'img_fit%s.png' % ind 
    677             refs.append('memory:' + name) 
    678             imgRAM.AddFile(name, canvas.bitmap, wx.BITMAP_TYPE_PNG) 
    679  
    680             # append figs 
    681             images.append(fig) 
    682  
    683         return imgRAM, images, refs 
    684  
     654        bitmaps = [] 
     655        for canvas in canvases: 
     656            bitmaps.append(canvas.bitmap) 
     657        imgs, refs = ReportImageHandler.set_figs(figs, bitmaps, 'fit') 
     658 
     659        return ReportImageHandler.instance, imgs, refs 
    685660 
    686661    def on_save(self, event): 
     
    14721447            # we need to check here ourselves. 
    14731448            if not is_modified: 
    1474                 is_modified = (self._check_value_enter(self.fittable_param) 
    1475                                or self._check_value_enter(self.fixed_param) 
    1476                                or self._check_value_enter(self.parameters)) 
     1449                is_modified = self._check_value_enter(self.fittable_param) 
     1450                is_modified = self._check_value_enter( 
     1451                    self.fixed_param) or is_modified 
     1452                is_modified = self._check_value_enter( 
     1453                    self.parameters) or is_modified 
    14771454 
    14781455            # Here we should check whether the boundaries have been modified. 
     
    15361513                        data=[self.data]) 
    15371514            # Check the values 
    1538             is_modified = (self._check_value_enter(self.fittable_param) 
    1539                            or self._check_value_enter(self.fixed_param) 
    1540                            or self._check_value_enter(self.parameters)) 
     1515            is_modified = self._check_value_enter(self.fittable_param) 
     1516            is_modified = self._check_value_enter(self.fixed_param) or is_modified 
     1517            is_modified = self._check_value_enter(self.parameters) or is_modified 
    15411518 
    15421519            # If qmin and qmax have been modified, update qmin and qmax and 
     
    23242301 
    23252302            # Update value in model if it has changed 
    2326             if value != self.model.getParam(name): 
     2303            if (value != self.model.getParam(name) or 
     2304                    (np.isnan(value) and np.isnan(self.model.getParam(name)))): 
    23272305                self.model.setParam(name, value) 
    23282306                is_modified = True 
     
    25512529            # draw 
    25522530            self._draw_model() 
     2531            self.Layout() 
    25532532            self.Refresh() 
    25542533        except Exception: 
     
    27992778        Function called when 'Help' button is pressed next to model 
    28002779        of interest.  This calls DocumentationWindow from 
    2801         documentation_window.py. It will load the top level of the model 
    2802         help documenation sphinx generated html if no model is presented. 
    2803         If a model IS present then if documention for that model exists 
    2804         it will load to that  point otherwise again it will go to the top. 
    2805         For Wx2.8 and below is used (i.e. non-released through installer) 
    2806         a browser is loaded and the top of the model documentation only is 
    2807         accessible because webbrowser module does not pass anything after 
    2808         the # to the browser. 
     2780        documentation_window.py. It will load the top level of the html model 
     2781        help documenation sphinx generated if either a plugin model (which 
     2782        normally does not have an html help help file) is selected or if no 
     2783        model is selected. Otherwise, if a regula model is selected, the 
     2784        documention for that model will be sent to a browser window. 
     2785 
     2786        :todo the quick fix for no documentation in plugins is the if statment. 
     2787        However, the right way to do this would be to check whether the hmtl 
     2788        file exists and load the model docs if it does and the general docs if 
     2789        it doesn't - this will become important if we ever figure out how to 
     2790        build docs for plugins on the fly.  Sep 9, 2018 -PDB 
    28092791 
    28102792        :param event: on Help Button pressed event 
    28112793        """ 
    28122794 
    2813         if self.model is not None: 
     2795        if (self.model is not None) and (self.categorybox.GetValue() 
     2796                                         != "Plugin Models"): 
    28142797            name = self.formfactorbox.GetValue() 
    28152798            _TreeLocation = 'user/models/%s.html' % name 
  • src/sas/sasgui/perspectives/fitting/fitpage.py

    re870702 r840ac87  
    705705 
    706706                        ix = 3 
    707                         ctl2 = wx.TextCtrl(self, wx.ID_ANY, 
    708                                            size=(_BOX_WIDTH / 1.3, 20), 
    709                                            style=0) 
     707                        ctl2 = BGTextCtrl(self, wx.ID_ANY, 
     708                                           size=(_BOX_WIDTH / 1.3, 20)) 
    710709 
    711710                        self.sizer4_4.Add(ctl2, (iy, ix), (1, 1), 
     
    19971996        self.on_smear_helper() 
    19981997        self.on_set_focus(None) 
     1998        self.Layout() 
    19991999        self.Refresh() 
    20002000        # update model plot with new data information 
     
    28912891                        text2.Hide() 
    28922892                    ix += 1 
    2893                     ctl2 = wx.TextCtrl(self, wx.ID_ANY, 
    2894                                        size=(_BOX_WIDTH / 1.2, 20), style=0) 
     2893                    ctl2 = BGTextCtrl(self, wx.ID_ANY, 
     2894                                       size=(_BOX_WIDTH / 1.2, 20)) 
    28952895                    sizer.Add(ctl2, (iy, ix), (1, 1), 
    28962896                              wx.EXPAND | wx.ADJUST_MINSIZE, 0) 
  • src/sas/sasgui/perspectives/fitting/gpu_options.py

    r42a6e02 r388aefb  
    139139 
    140140        test_text = wx.StaticText(self, -1, "WARNING: Running tests can take a few minutes!") 
     141        test_text2 = wx.StaticText(self, -1, "NOTE: No test will run if No OpenCL is checked") 
     142        test_text.SetForegroundColour(wx.RED) 
     143        self.vbox.Add(test_text2, 0, wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 10) 
    141144        self.vbox.Add(test_text, 0, wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 10) 
    142145 
  • src/sas/sasgui/perspectives/fitting/media/fitting_help.rst

    r47ace50 r9258c43c  
    180180*checked*\ . 
    181181 
    182 Also note that the 'Fit Parameters' have been split into two sections: those 
    183 which can be polydisperse (shape and orientation parameters) and those which are 
    184 not (eg, scattering length densities). 
    185  
    186182A model file generated by this option can be viewed and further modified using 
    187183the :ref:`Advanced_Plugin_Editor` . 
    188184 
    189 **SasView version 4.2** made it possible to specify whether a plugin created with 
    190 the *New Plugin Model* dialog is actually a form factor P(Q) or a structure factor 
    191 S(Q). To do this, simply add one or other of the following lines under the *import* 
    192 statements. 
     185Note that the New Plugin Model Feature currently does not allow for parameters 
     186to be polydisperse.  However they can be edited in the Advanced Editor. 
     187 
     188 
     189**SasView version 4.2** made it possible to specify whether a plugin created 
     190with the *New Plugin Model* dialog is actually a form factor P(Q) or a structure 
     191factor S(Q). To do this, simply add one or other of the following lines under 
     192the *import* statements. 
    193193 
    194194For a form factor:: 
     
    200200     structure_factor = True 
    201201 
    202 If the plugin is a structure factor it is *also* necessary to add two variables to 
    203 the parameter list:: 
     202If the plugin is a structure factor it is *also* necessary to add two variables 
     203to the parameter list:: 
    204204 
    205205     parameters = [ 
  • src/sas/sasgui/perspectives/fitting/report_dialog.py

    r69a6897 r44e8f48  
    7272        filename = basename + ext 
    7373 
    74         # save figures 
    75         pictures = [] 
    76         for num in range(self.nimages): 
    77             pic_name = basename + '_img%s.png' % num 
    78             # save the image for use with pdf writer 
    79             self.report_list[2][num].savefig(pic_name) 
    80             pictures.append(pic_name) 
     74        # save the images for use with pdf writer 
     75        pictures = [ 
     76            '_'.join((basename, url.split(':')[1])) for url in self.fig_urls] 
     77        for i, pic in enumerate(pictures): 
     78            self.report_list[2][i].savefig(pic) 
    8179 
    8280        # translate png references int html from in-memory name to on-disk name 
    83         html = self.report_html.replace("memory:img_fit", basename+'_img') 
     81        html = self.report_html.replace("memory:", basename+'_') 
    8482 
    8583        #set file extensions 
  • src/sas/sasgui/perspectives/invariant/invariant_panel.py

    r2469df7 r44e8f48  
    2424from sas.sasgui.guiframe.panel_base import PanelBase 
    2525from sas.sasgui.guiframe.documentation_window import DocumentationWindow 
     26from sas.sasgui.guiframe.report_image_handler import ReportImageHandler 
    2627 
    2728logger = logging.getLogger(__name__) 
     
    783784        report_img = self.state.image 
    784785        report_list = [report_html_str, report_text_str, report_img] 
    785         dialog = ReportDialog(report_list, None, -1, "") 
     786        ReportImageHandler.check_for_empty_instance() 
     787        imgRAM = ReportImageHandler.instance.img_holder 
     788        refs = [self.state.wximgbmp] 
     789        dialog = ReportDialog(report_list, imgRAM, refs, None, wx.ID_ANY, "") 
    786790        dialog.Show() 
    787791 
  • src/sas/sasgui/perspectives/invariant/invariant_state.py

    r2469df7 rfa412df  
    1212from lxml import etree 
    1313from sas.sascalc.dataloader.readers.cansas_reader import Reader as CansasReader 
     14from sas.sasgui.guiframe.report_image_handler import ReportImageHandler 
    1415from sas.sascalc.dataloader.readers.cansas_reader import get_content 
    1516from sas.sasgui.guiframe.utils import format_number 
     
    611612        wximgbmp = wx.BitmapFromImage(wximg) 
    612613        # store the image in wx.FileSystem Object 
    613         wx.FileSystem.AddHandler(wx.MemoryFSHandler()) 
    614         # use wx.MemoryFSHandler 
    615         self.imgRAM = wx.MemoryFSHandler() 
    616         # AddFile, image can be retrieved with 'memory:filename' 
    617         self.imgRAM.AddFile('img_inv.png', wximgbmp, wx.BITMAP_TYPE_PNG) 
    618  
    619         self.wximgbmp = 'memory:img_inv.png' 
    620         self.image = fig 
     614        imgs, refs = ReportImageHandler.set_figs([fig], [wximgbmp], 'inv') 
     615 
     616        self.wximgbmp = refs[0] 
     617        self.image = imgs[0] 
    621618 
    622619class Reader(CansasReader): 
  • src/sas/sasgui/perspectives/invariant/report_dialog.py

    r959eb01 rd0ce666f  
    4141 
    4242        # put image path in the report string 
    43         self.report_html = self.report_list[0] % "memory:img_inv.png" 
     43        self.report_html = self.report_list[0] % self.fig_urls[0] 
    4444        # layout 
    4545        self._setup_layout() 
  • src/sas/sasview/local_config.py

    rb963b20 r8ac05a5  
    3333_do_aboutbox = True 
    3434_do_acknowledge = True 
     35_do_release = True 
    3536_do_tutorial = True 
    3637_acknowledgement_preamble =\ 
     
    4849'''This work benefited from the use of the SasView application, originally developed under NSF Award DMR-0520547. SasView also contains code developed with funding from the EU Horizon 2020 programme under the SINE2020 project Grant No 654000.''' 
    4950_acknowledgement_citation = \ 
    50 '''M. Doucet et al. SasView Version 4.1.2, Zenodo, 10.5281/zenodo.825675''' 
    51  
     51'''M. Doucet et al. SasView Version 4.2, Zenodo, 10.5281/zenodo.1412041''' 
    5252_acknowledgement =  \ 
    5353'''This work was originally developed as part of the DANSE project funded by the US NSF under Award DMR-0520547,\n but is currently maintained by a collaboration between UTK, UMD, NIST, ORNL, ISIS, ESS, ILL, ANSTO, TU Delft, DLS, and the scattering community.\n\n SasView also contains code developed with funding from the EU Horizon 2020 programme under the SINE2020 project (Grant No 654000).\nA list of individual contributors can be found at: http://www.sasview.org/contact.html 
     
    9494_corner_image = os.path.join(icon_path, "angles_flat.png") 
    9595_welcome_image = os.path.join(icon_path, "SVwelcome.png") 
    96 _copyright = "(c) 2009 - 2017, UTK, UMD, NIST, ORNL, ISIS, ESS, ILL, ANSTO, TU Delft, and DLS" 
     96_copyright = "(c) 2009 - 2018, UTK, UMD, NIST, ORNL, ISIS, ESS, ILL, ANSTO, TU Delft, and DLS" 
    9797marketplace_url = "http://marketplace.sasview.org/" 
    9898 
  • src/sas/sasview/media/README.txt

    r914ba0a r356af60e  
     1The files in this folder are what get shipped in the installer \media folder. 
     2 
     3The help documentation gets shipped in the /doc folder. 
     4 
    15This Tutorial.pdf is what appears when you click on 'Tutorial' under 'Help' 
    2 in the menu bar. 
     6in the SasView menu bar. It has been manually copied over from sasview/docs/sasview. 
    37 
    4 The source files are in: /sasview/docs/sasview 
    5  
    6 The getting_started_with_sasview.pdf has been manually added here until the auto-generated LibreOffice doc build is up and running. 
     8The new tutorial pdfs here have been manually copied over from the website /downloads folder. 
  • src/sas/sasview/sasview.py

    r20fa5fe r1270e3c  
    4343        from sas.sasgui.guiframe.gui_manager import SasViewApp 
    4444        self.gui = SasViewApp(0) 
     45        if sys.platform == "darwin": 
     46            self.check_sasmodels_compiler() 
    4547        # Set the application manager for the GUI 
    4648        self.gui.set_manager(self) 
     
    130132        self.gui.MainLoop() 
    131133 
     134    def check_sasmodels_compiler(self): 
     135        """ 
     136        Checking c compiler for sasmodels and raises xcode command line 
     137        tools for installation 
     138        """ 
     139        #wx should be importable at this stage 
     140        import wx 
     141        import subprocess 
     142        #Generic message box created becuase standard MessageBox is not moveable 
     143        class GenericMessageBox(wx.Dialog): 
     144            def __init__(self, parent, text, title = ''): 
     145 
     146                wx.Dialog.__init__(self, parent, -1, title = title, 
     147                               size = (360,200), pos=(20,60), 
     148                               style = wx.STAY_ON_TOP | wx.DEFAULT_DIALOG_STYLE) 
     149                panel = wx.Panel(self, -1) 
     150                top_row_sizer = wx.BoxSizer(wx.HORIZONTAL) 
     151 
     152                error_bitmap = wx.ArtProvider.GetBitmap( 
     153                    wx.ART_ERROR, wx.ART_MESSAGE_BOX 
     154                ) 
     155                error_bitmap_ctrl = wx.StaticBitmap(panel, -1) 
     156                error_bitmap_ctrl.SetBitmap(error_bitmap) 
     157                label = wx.StaticText(panel, -1, text) 
     158                top_row_sizer.Add(error_bitmap_ctrl, flag=wx.ALL, border=10) 
     159                top_row_sizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL) 
     160 
     161                #Create the OK button in the bottom row. 
     162                ok_button = wx.Button(panel, wx.ID_OK ) 
     163                self.Bind(wx.EVT_BUTTON, self.on_ok, source=ok_button) 
     164                ok_button.SetFocus() 
     165                ok_button.SetDefault() 
     166 
     167                sizer = wx.BoxSizer(wx.VERTICAL) 
     168                sizer.Add(top_row_sizer) 
     169                sizer.Add(ok_button, flag=wx.ALIGN_CENTER | wx.ALL, border=5) 
     170                panel.SetSizer(sizer) 
     171 
     172            def on_ok(self, event): 
     173                self.Destroy() 
     174 
     175        logger = logging.getLogger(__name__) 
     176        try: 
     177            subprocess.check_output(["cc","--version"], stderr=subprocess.STDOUT) 
     178        except subprocess.CalledProcessError as exc: 
     179            dlg = GenericMessageBox(parent=None, 
     180            text='No compiler installed. Please install command line\n' 
     181                'developers tools by clicking \"Install\" in another winodw\n\n' 
     182                'Alternatively click \"Not Now\" and use OpenCL\n' 
     183                 'compiler, which can be set up from menu Fitting->OpenCL Options\n\n', 
     184            title = 'Compiler Info') 
     185            dlg.Show() 
     186            logger.error("No compiler installed. %s\n"%(exc)) 
     187            logger.error(traceback.format_exc()) 
    132188 
    133189def setup_logging(): 
  • src/sas/sascalc/fit/BumpsFitting.py

    r1386b2f r0aeba4e  
    22BumpsFitting module runs the bumps optimizer. 
    33""" 
     4from __future__ import print_function 
     5 
    46import os 
    57from datetime import timedelta, datetime 
     
    911 
    1012from bumps import fitters 
     13 
    1114try: 
    1215    from bumps.options import FIT_CONFIG 
     16    # Preserve bumps default fitter in case someone wants it later 
     17    BUMPS_DEFAULT_FITTER = FIT_CONFIG.selected_id 
    1318    # Default bumps to use the Levenberg-Marquardt optimizer 
    1419    FIT_CONFIG.selected_id = fitters.LevenbergMarquardtFit.id 
     
    1722except ImportError: 
    1823    # CRUFT: Bumps changed its handling of fit options around 0.7.5.6 
     24    # Preserve bumps default fitter in case someone wants it later 
     25    BUMPS_DEFAULT_FITTER = fitters.FIT_DEFAULT 
    1926    # Default bumps to use the Levenberg-Marquardt optimizer 
    2027    fitters.FIT_DEFAULT = 'lm' 
     
    126133        if initial_values is not None: 
    127134            self._reset_pars(fitted, initial_values) 
     135        #print("constraints", constraints) 
    128136        self.constraints = dict(constraints) 
    129137        self.set_fitted(fitted) 
     
    222230    def _setup(self): 
    223231        exprs = {} 
    224         for M in self.models: 
    225             exprs.update((".".join((M.name, k)), v) for k, v in M.constraints.items()) 
     232        for model in self.models: 
     233            exprs.update((".".join((model.name, k)), v) 
     234                         for k, v in model.constraints.items()) 
    226235        if exprs: 
    227             symtab = dict((".".join((M.name, k)), p) 
    228                           for M in self.models 
    229                           for k, p in M.parameters().items()) 
     236            symtab = dict((".".join((model.name, k)), p) 
     237                          for model in self.models 
     238                          for k, p in model.parameters().items()) 
    230239            self.update = compile_constraints(symtab, exprs) 
    231240        else: 
Note: See TracChangeset for help on using the changeset viewer.