- Timestamp:
- Sep 20, 2017 7:55:53 AM (7 years ago)
- Branches:
- master, 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, magnetic_scatt, release-4.2.2, ticket-1009, ticket-1094-headless, ticket-1242-2d-resolution, ticket-1243, ticket-1249, ticket885, unittest-saveload
- Children:
- fca1f50
- Parents:
- 6d62b7f (diff), 2a399ca (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. - Location:
- src/sas
- Files:
-
- 3 added
- 3 deleted
- 22 edited
Legend:
- Unmodified
- Added
- Removed
-
src/sas/sascalc/corfunc/corfunc_calculator.py
rff11b21 ra859f99 34 34 35 35 def __call__(self, x): 36 if self._lastx == [] or x.tolist() != self._lastx.tolist(): 36 # If input is a single number, evaluate the function at that number 37 # and return a single number 38 if type(x) == float or type(x) == int: 39 return self._smoothed_function(np.array([x]))[0] 40 # If input is a list, and is different to the last input, evaluate 41 # the function at each point. If the input is the same as last time 42 # the function was called, return the result that was calculated 43 # last time instead of explicity evaluating the function again. 44 elif self._lastx == [] or x.tolist() != self._lastx.tolist(): 37 45 self._lasty = self._smoothed_function(x) 38 46 self._lastx = x … … 121 129 extrapolation = Data1D(qs, iqs) 122 130 123 return params, extrapolation 131 return params, extrapolation, s2 124 132 125 133 def compute_transform(self, extrapolation, trans_type, background=None, … … 131 139 :param background: The background value (if not provided, previously 132 140 calculated value will be used) 141 :param extrap_fn: A callable function representing the extraoplated data 133 142 :param completefn: The function to call when the transform calculation 134 is complete `143 is complete 135 144 :param updatefn: The function to call to update the GUI with the status 136 145 of the transform calculation … … 144 153 if trans_type == 'fourier': 145 154 self._transform_thread = FourierThread(self._data, extrapolation, 146 background, completefn=completefn, updatefn=updatefn) 155 background, completefn=completefn, 156 updatefn=updatefn) 147 157 elif trans_type == 'hilbert': 148 158 self._transform_thread = HilbertThread(self._data, extrapolation, -
src/sas/sascalc/corfunc/transform_thread.py
rd03228e ra859f99 2 2 from sas.sascalc.dataloader.data_info import Data1D 3 3 from scipy.fftpack import dct 4 from scipy.integrate import trapz, cumtrapz 4 5 import numpy as np 5 6 from time import sleep … … 13 14 self.extrapolation = extrapolated_data 14 15 16 def check_if_cancelled(self): 17 if self.isquit(): 18 self.update("Fourier transform cancelled.") 19 self.complete(transforms=None) 20 return True 21 return False 22 15 23 def compute(self): 16 24 qs = self.extrapolation.x … … 19 27 background = self.background 20 28 29 xs = np.pi*np.arange(len(qs),dtype=np.float32)/(q[1]-q[0])/len(qs) 30 21 31 self.ready(delay=0.0) 22 self.update(msg=" Starting Fourier transform.")32 self.update(msg="Fourier transform in progress.") 23 33 self.ready(delay=0.0) 24 if self.isquit(): 25 34 35 if self.check_if_cancelled(): return 26 36 try: 27 gamma = dct((iqs-background)*qs**2) 28 gamma = gamma / gamma.max() 29 except: 37 # ----- 1D Correlation Function ----- 38 gamma1 = dct((iqs-background)*qs**2) 39 Q = gamma1.max() 40 gamma1 /= Q 41 42 if self.check_if_cancelled(): return 43 44 # ----- 3D Correlation Function ----- 45 # gamma3(R) = 1/R int_{0}^{R} gamma1(x) dx 46 # trapz uses the trapezium rule to calculate the integral 47 mask = xs <= 200.0 # Only calculate gamma3 up to x=200 (as this is all that's plotted) 48 # gamma3 = [trapz(gamma1[:n], xs[:n])/xs[n-1] for n in range(2, len(xs[mask]) + 1)]j 49 # gamma3.insert(0, 1.0) # Gamma_3(0) is defined as 1 50 n = len(xs[mask]) 51 gamma3 = cumtrapz(gamma1[:n], xs[:n])/xs[1:n] 52 gamma3 = np.hstack((1.0, gamma3)) # Gamma_3(0) is defined as 1 53 54 if self.check_if_cancelled(): return 55 56 # ----- Interface Distribution function ----- 57 idf = dct(-qs**4 * (iqs-background)) 58 59 if self.check_if_cancelled(): return 60 61 # Manually calculate IDF(0.0), since scipy DCT tends to give us a 62 # very large negative value. 63 # IDF(x) = int_0^inf q^4 * I(q) * cos(q*x) * dq 64 # => IDF(0) = int_0^inf q^4 * I(q) * dq 65 idf[0] = trapz(-qs**4 * (iqs-background), qs) 66 idf /= Q # Normalise using scattering invariant 67 68 except Exception as e: 69 import logging 70 logger = logging.getLogger(__name__) 71 logger.error(e) 72 30 73 self.update(msg="Fourier transform failed.") 31 self.complete(transform =None)74 self.complete(transforms=None) 32 75 return 33 76 if self.isquit(): … … 35 78 self.update(msg="Fourier transform completed.") 36 79 37 xs = np.pi*np.arange(len(qs),dtype=np.float32)/(q[1]-q[0])/len(qs) 38 transform = Data1D(xs, gamma) 80 transform1 = Data1D(xs, gamma1) 81 transform3 = Data1D(xs[xs <= 200], gamma3) 82 idf = Data1D(xs, idf) 39 83 40 self.complete(transform=transform) 84 transforms = (transform1, transform3, idf) 85 86 self.complete(transforms=transforms) 41 87 42 88 class HilbertThread(CalcThread): … … 64 110 self.update(msg="Hilbert transform completed.") 65 111 66 self.complete(transform =None)112 self.complete(transforms=None) -
src/sas/sasgui/perspectives/calculator/image_viewer.py
ra1b8fee r412e9e8b 59 59 _, extension = os.path.splitext(basename) 60 60 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. 61 67 img = mpimg.imread(file_path) 62 68 is_png = extension.lower() == '.png' … … 89 95 if location is None: 90 96 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) 93 109 if dlg.ShowModal() == wx.ID_OK: 94 110 path = dlg.GetPaths() -
src/sas/sasgui/perspectives/calculator/media/image_viewer_help.rst
rda456fb r412e9e8b 34 34 will be displayed. 35 35 36 .. image:: load_image. bmp36 .. image:: load_image.png 37 37 38 38 3) To save, print, or copy the image, or to apply a grid overlay, right-click 39 39 anywhere in the plot. 40 40 41 .. image:: pic_plot. bmp41 .. image:: pic_plot.png 42 42 43 43 4. If the image is taken from a 2D detector, SasView can attempt to convert … … 51 51 then click the OK. 52 52 53 .. image:: pic_convert. bmp53 .. image:: pic_convert.png 54 54 55 55 .. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ -
src/sas/sasgui/perspectives/corfunc/corfunc.py
r463e7ffc r9b90bf8 189 189 # Show the transformation as a curve instead of points 190 190 new_plot.symbol = GUIFRAME_ID.CURVE_SYMBOL_NUM 191 elif label == IDF_LABEL: 192 new_plot.xaxis("{x}", 'A') 193 new_plot.yaxis("{g_1}", '') 194 # Linear scale 195 new_plot.xtransform = 'x' 196 new_plot.ytransform = 'y' 197 group_id = GROUP_ID_IDF 198 # Show IDF as a curve instead of points 199 new_plot.symbol = GUIFRAME_ID.CURVE_SYMBOL_NUM 191 200 new_plot.id = label 192 201 new_plot.name = label -
src/sas/sasgui/perspectives/corfunc/corfunc_panel.py
r7432acb r2a399ca 20 20 21 21 OUTPUT_STRINGS = { 22 'max': "Long Period (A): ",22 'max': "Long Period / 2 (A): ", 23 23 'Lc': "Average Hard Block Thickness (A): ", 24 24 'dtr': "Average Interface Thickness (A): ", … … 55 55 self._data = data # The data to be analysed (corrected fr background) 56 56 self._extrapolated_data = None # The extrapolated data set 57 # Callable object of class CorfuncCalculator._Interpolator representing 58 # the extrapolated and interpolated data 59 self._extrapolated_fn = None 57 60 self._transformed_data = None # Fourier trans. of the extrapolated data 58 61 self._calculator = CorfuncCalculator() … … 218 221 219 222 try: 220 params, self._extrapolated_data = self._calculator.compute_extrapolation() 223 params, self._extrapolated_data, self._extrapolated_fn = \ 224 self._calculator.compute_extrapolation() 221 225 except Exception as e: 222 226 msg = "Error extrapolating data:\n" … … 257 261 StatusEvent(status=msg)) 258 262 259 def transform_complete(self, transform =None):263 def transform_complete(self, transforms=None): 260 264 """ 261 265 Called from FourierThread when calculation has completed 262 266 """ 263 267 self._transform_btn.SetLabel("Transform") 264 if transform is None:268 if transforms is None: 265 269 msg = "Error calculating Transform." 266 270 if self.transform_type == 'hilbert': … … 270 274 self._extract_btn.Disable() 271 275 return 272 self._transformed_data = transform 273 import numpy as np 274 plot_x = transform.x[np.where(transform.x <= 200)] 275 plot_y = transform.y[np.where(transform.x <= 200)] 276 277 self._transformed_data = transforms 278 (transform1, transform3, idf) = transforms 279 plot_x = transform1.x[transform1.x <= 200] 280 plot_y = transform1.y[transform1.x <= 200] 276 281 self._manager.show_data(Data1D(plot_x, plot_y), TRANSFORM_LABEL1) 282 # No need to shorten gamma3 as it's only calculated up to x=200 283 self._manager.show_data(transform3, TRANSFORM_LABEL3) 284 285 plot_x = idf.x[idf.x <= 200] 286 plot_y = idf.y[idf.x <= 200] 287 self._manager.show_data(Data1D(plot_x, plot_y), IDF_LABEL) 288 277 289 # Only enable extract params button if a fourier trans. has been done 278 290 if self.transform_type == 'fourier': … … 286 298 """ 287 299 try: 288 params = self._calculator.extract_parameters(self._transformed_data )300 params = self._calculator.extract_parameters(self._transformed_data[0]) 289 301 except: 290 302 params = None -
src/sas/sasgui/perspectives/corfunc/corfunc_state.py
r7432acb r2a399ca 28 28 # List of output parameters, used by __str__ 29 29 output_list = [ 30 ['max', "Long Period (A): "],30 ['max', "Long Period / 2 (A): "], 31 31 ['Lc', "Average Hard Block Thickness (A): "], 32 32 ['dtr', "Average Interface Thickness (A): "], … … 59 59 self.q = None 60 60 self.iq = None 61 # TODO: Add extrapolated data and transformed data (when implemented)62 61 63 62 def __str__(self): -
src/sas/sasgui/perspectives/corfunc/media/corfunc_help.rst
r1404cce rd78b5cb 10 10 11 11 This performs a correlation function analysis of one-dimensional 12 SAXS/SANS data, or generates a model-independent volume fraction 12 SAXS/SANS data, or generates a model-independent volume fraction 13 13 profile from the SANS from an adsorbed polymer/surfactant layer. 14 14 15 A correlation function may be interpreted in terms of an imaginary rod moving 16 through the structure of the material. Î\ :sub:`1D`\ (R) is the probability that 17 a rod of length R moving through the material has equal electron/neutron scattering 18 length density at either end. Hence a frequently occurring spacing within a structure 15 A correlation function may be interpreted in terms of an imaginary rod moving 16 through the structure of the material. Î\ :sub:`1D`\ (R) is the probability that 17 a rod of length R moving through the material has equal electron/neutron scattering 18 length density at either end. Hence a frequently occurring spacing within a structure 19 19 manifests itself as a peak. 20 20 … … 30 30 * Fourier / Hilbert Transform of the smoothed data to give the correlation 31 31 function / volume fraction profile, respectively 32 * (Optional) Interpretation of the 1D correlation function based on an ideal 32 * (Optional) Interpretation of the 1D correlation function based on an ideal 33 33 lamellar morphology 34 34 … … 74 74 :align: center 75 75 76 76 77 77 Smoothing 78 78 --------- 79 79 80 The extrapolated data set consists of the Guinier back-extrapolation from Q~0 80 The extrapolated data set consists of the Guinier back-extrapolation from Q~0 81 81 up to the lowest Q value in the original data, then the original scattering data, and the Porod tail-fit beyond this. The joins between the original data and the Guinier/Porod fits are smoothed using the algorithm below to avoid the formation of ripples in the transformed data. 82 82 … … 93 93 h_i = \frac{1}{1 + \frac{(x_i-b)^2}{(x_i-a)^2}} 94 94 95 95 96 96 Transform 97 97 --------- … … 102 102 If "Fourier" is selected for the transform type, the analysis will perform a 103 103 discrete cosine transform on the extrapolated data in order to calculate the 104 correlation function 104 1D correlation function: 105 105 106 106 .. math:: … … 115 115 \left(n + \frac{1}{2} \right) k \right] } \text{ for } k = 0, 1, \ldots, 116 116 N-1, N 117 118 The 3D correlation function is also calculated: 119 120 .. math:: 121 \Gamma _{3D}(R) = \frac{1}{Q^{*}} \int_{0}^{\infty}I(q) q^{2} 122 \frac{sin(qR)}{qR} dq 117 123 118 124 Hilbert … … 165 171 .. figure:: profile1.png 166 172 :align: center 167 173 168 174 .. figure:: profile2.png 169 175 :align: center 170 176 171 177 172 178 References … … 191 197 ----- 192 198 Upon sending data for correlation function analysis, it will be plotted (minus 193 the background value), along with a *red* bar indicating the *upper end of the 199 the background value), along with a *red* bar indicating the *upper end of the 194 200 low-Q range* (used for back-extrapolation), and 2 *purple* bars indicating the range to be used for forward-extrapolation. These bars may be moved my clicking and 195 201 dragging, or by entering appropriate values in the Q range input boxes. … … 221 227 :align: center 222 228 223 229 224 230 .. note:: 225 231 This help document was last changed by Steve King, 08Oct2016 -
src/sas/sasgui/perspectives/corfunc/plot_labels.py
r1dc8ec9 r7dda833 4 4 5 5 GROUP_ID_TRANSFORM = r"$\Gamma(x)$" 6 TRANSFORM_LABEL1 = r"$\Gamma1(x)$" 7 TRANSFORM_LABEL3 = r"$\Gamma3(x)$" 6 TRANSFORM_LABEL1 = r"$\Gamma_1(x)$" 7 TRANSFORM_LABEL3 = r"$\Gamma_3(x)$" 8 9 GROUP_ID_IDF = r"$g_1(x)$" 10 IDF_LABEL = r"$g_1(x)$" -
src/sas/sasgui/perspectives/fitting/basepage.py
r914c49d5 r66acafe 1841 1841 if models.name != "NoStructure": 1842 1842 mlist.append((models.name, models)) 1843 1844 1843 # Sort the models 1845 1844 mlist_sorted = sorted(mlist) … … 2929 2928 return False 2930 2929 2930 2931 def _get_copy_params_details(self): 2932 """ 2933 Combines polydisperse parameters with self.parameters so that they can 2934 be written to the clipboard (for Excel or LaTeX). Also returns a list of 2935 the names of parameters that have been fitted 2936 2937 :returns: all_params - A list of all parameters, in the format of 2938 self.parameters 2939 :returns: fitted_par_names - A list of the names of parameters that have 2940 been fitted 2941 """ 2942 # Names of params that are being fitted 2943 fitted_par_names = [param[1] for param in self.param_toFit] 2944 # Names of params with associated polydispersity 2945 disp_params = [param[1].split('.')[0] for param in self.fittable_param] 2946 2947 # Create array of all parameters 2948 all_params = copy.copy(self.parameters) 2949 for param in self.parameters: 2950 if param[1] in disp_params: 2951 # Polydisperse params aren't in self.parameters, so need adding 2952 # to all_params 2953 name = param[1] + ".width" 2954 index = all_params.index(param) + 1 2955 to_insert = [] 2956 if name in fitted_par_names: 2957 # Param is fitted, so already has a param list in self.param_toFit 2958 to_insert = self.param_toFit[fitted_par_names.index(name)] 2959 else: 2960 # Param isn't fitted, so mockup a param list 2961 to_insert = [None, name, self.model.getParam(name), None, None] 2962 all_params.insert(index, to_insert) 2963 return all_params, fitted_par_names 2964 2931 2965 def get_copy_excel(self): 2932 2966 """ … … 2942 2976 Get the string copies of the param names and values in the tap 2943 2977 """ 2978 if not self.parameters: 2979 # Do nothing if parameters doesn't exist 2980 return False 2981 2944 2982 content = '' 2945 2946 2983 crlf = chr(13) + chr(10) 2947 2984 tab = chr(9) 2948 2985 2949 # Do it if params exist 2950 if self.parameters: 2951 2952 for param in self.parameters: 2953 content += param[1] # parameter name 2986 all_params, fitted_param_names = self._get_copy_params_details() 2987 2988 # Construct row of parameter names 2989 for param in all_params: 2990 name = param[1] # Parameter name 2991 content += name 2992 content += tab 2993 if name in fitted_param_names: 2994 # Only print errors for fitted parameters 2995 content += name + "_err" 2954 2996 content += tab 2955 content += param[1] + "_err" 2956 content += tab 2957 2958 content += crlf 2959 2960 # row of values and errors... 2961 for param in self.parameters: 2962 content += param[2].GetValue() # value 2963 content += tab 2964 content += param[4].GetValue() # error 2965 content += tab 2966 2967 return content 2968 else: 2969 return False 2997 2998 content += crlf 2999 3000 # Construct row of parameter values and errors 3001 for param in all_params: 3002 value = param[2] 3003 if hasattr(value, 'GetValue'): 3004 # param[2] is a text box 3005 value = value.GetValue() 3006 else: 3007 # param[2] is a float (from our self._get_copy_params_details) 3008 value = str(value) 3009 content += value 3010 content += tab 3011 if param[1] in fitted_param_names: 3012 # Only print errors for fitted parameters 3013 content += param[4].GetValue() 3014 content += tab 3015 3016 return content 2970 3017 2971 3018 def get_copy_latex(self): … … 2982 3029 Get the string copies of the param names and values in the tap 2983 3030 """ 3031 if not self.parameters: 3032 # Do nothing if self.parameters doesn't exist 3033 return False 3034 2984 3035 content = '\\begin{table}' 2985 3036 content += '\\begin{tabular}[h]' … … 2988 3039 tab = chr(9) 2989 3040 2990 # Do it if params exist 2991 if self.parameters: 2992 2993 content += '{|' 2994 for param in self.parameters: 2995 content += 'l|l|' 2996 content += '}\hline' 2997 content += crlf 2998 2999 for index, param in enumerate(self.parameters): 3000 content += param[1].replace('_', '\_') # parameter name 3041 all_params, fitted_param_names = self._get_copy_params_details() 3042 3043 content += '{|' 3044 for param in all_params: 3045 content += 'l|l|' 3046 content += '}\hline' 3047 content += crlf 3048 3049 # Construct row of parameter names 3050 for index, param in enumerate(all_params): 3051 name = param[1] # Parameter name 3052 content += name.replace('_', '\_') # Escape underscores 3053 if name in fitted_param_names: 3054 # Only print errors for fitted parameters 3001 3055 content += ' & ' 3002 content += param[1].replace('_', '\_') + "\_err" 3003 if index < len(self.parameters) - 1: 3004 content += ' & ' 3005 content += '\\\\ \\hline' 3006 content += crlf 3007 3008 # row of values and errors... 3009 for index, param in enumerate(self.parameters): 3010 content += param[2].GetValue() # parameter value 3056 content += name.replace('_', '\_') + "\_err" 3057 if index < len(all_params) - 1: 3011 3058 content += ' & ' 3012 content += param[4].GetValue() # parameter error 3013 if index < len(self.parameters) - 1: 3014 content += ' & ' 3015 content += '\\\\ \\hline' 3016 content += crlf 3017 3018 content += '\\end{tabular}' 3019 content += '\\end{table}' 3020 return content 3021 else: 3022 return False 3059 3060 content += '\\\\ \\hline' 3061 content += crlf 3062 3063 # Construct row of values and errors 3064 for index, param in enumerate(all_params): 3065 value = param[2] 3066 if hasattr(value, "GetValue"): 3067 # value is a text box 3068 value = value.GetValue() 3069 else: 3070 # value is a float (from self._get_copy_params_details) 3071 value = str(value) 3072 content += value 3073 if param[1] in fitted_param_names: 3074 # Only print errors for fitted params 3075 content += ' & ' 3076 content += param[4].GetValue() 3077 if index < len(all_params) - 1: 3078 content += ' & ' 3079 3080 content += '\\\\ \\hline' 3081 content += crlf 3082 content += '\\end{tabular}' 3083 content += '\\end{table}' 3084 3085 return content 3023 3086 3024 3087 def set_clipboard(self, content=None): -
src/sas/sasgui/perspectives/fitting/fitpage.py
r6a455cd3 r13374be 289 289 self.btFitHelp.SetToolTipString("General fitting help.") 290 290 self.btFitHelp.Bind(wx.EVT_BUTTON, self._onFitHelp) 291 291 292 292 # Resolution Smearing Help button (for now use same technique as 293 293 # used for dI help to get tiniest possible button that works … … 303 303 self.btSmearHelp.SetToolTipString("Resolution smearing help.") 304 304 self.btSmearHelp.Bind(wx.EVT_BUTTON, self._onSmearHelp) 305 305 306 306 # textcntrl for custom resolution 307 307 self.smear_pinhole_percent = ModelTextCtrl(self, wx.ID_ANY, … … 564 564 sizer.Add(self.draw_button, 0, 0) 565 565 sizer.Add((-1, 5)) 566 566 567 567 sizer.Add(self.tcChi, 0, 0) 568 568 sizer.Add(self.Npts_fit, 0, 0) … … 570 570 sizer.Add(self.btFit, 0, 0) 571 571 sizer.Add(self.btFitHelp, 0, 0) 572 572 573 573 boxsizer_range.Add(sizer_chi2) 574 574 boxsizer_range.Add(sizer) … … 1156 1156 copy_flag = self.get_copy_params() 1157 1157 is_poly_enabled = self.enable_disp.GetValue() 1158 1159 self._on_select_model_helper() 1158 try: 1159 self._on_select_model_helper() 1160 except Exception as e: 1161 evt = StatusEvent(status=e.message, info="error") 1162 wx.PostEvent(self._manager.parent, evt) 1163 # Set S(Q) to None 1164 self.structurebox.SetSelection(0) 1165 self._on_select_model() 1166 return 1160 1167 self.set_model_param_sizer(self.model) 1161 1168 if self.model is None: … … 2185 2192 self.save_current_state() 2186 2193 2194 if not self.is_mac: 2195 self.Layout() 2196 self.Refresh() 2187 2197 # plot model ( when drawing, do not update chisqr value again) 2188 2198 self._draw_model(update_chisqr=False, source='fit') … … 2779 2789 else: 2780 2790 return cmp(a.lower(), b.lower()) 2781 2791 2782 2792 # keys obtained now from ordered dict, so commenting alphabetical 2783 2793 # ordering keys.sort(custom_compare) -
src/sas/sasgui/perspectives/fitting/fitpanel.py
rc9ecd1b r13374be 503 503 if data is None: 504 504 return None 505 focused_page = self.GetPage(self.GetSelection()) 505 506 for page in self.opened_pages.values(): 506 507 # check if the selected data existing in the fitpanel 507 508 pos = self.GetPageIndex(page) 508 509 if not check_data_validity(page.get_data()) and not page.batch_on: 510 if page.model is not None and page != focused_page: 511 # Page has an active theory and is in background - don't 512 # send data here. 513 continue 509 514 # make sure data get placed in 1D empty tab if data is 1D 510 515 # else data get place on 2D tab empty tab -
src/sas/sasgui/perspectives/fitting/fitting.py
r2d9526d r66acafe 357 357 else: 358 358 page.formfactorbox.SetLabel(current_val) 359 if hasattr(page, 'structurebox'): 360 selected_name = page.structurebox.GetStringSelection() 361 362 page.structurebox.Clear() 363 page.initialize_combox() 364 365 index = page.structurebox.FindString(selected_name) 366 if index == -1: 367 index = 0 368 page.structurebox.SetSelection(index) 369 page._on_select_model() 359 370 except: 360 371 logger.error("update_custom_combo: %s", sys.exc_value) … … 1326 1337 1327 1338 is_data2d = issubclass(data.__class__, Data2D) 1328 # check consistency of arrays1339 # Check consistency of arrays 1329 1340 if not is_data2d: 1330 1341 if len(res.theory) == len(res.index[res.index]) and \ … … 1337 1348 new_theory[res.index == False] = np.nan 1338 1349 correct_result = True 1339 # get all fittable parameters of the current model1350 # Get all fittable parameters of the current model 1340 1351 param_list = model.getParamList() 1341 1352 for param in model.getDispParamList(): 1342 if not model.is_fittable(param) and \ 1353 if '.' in param and param in param_list: 1354 # Ensure polydispersity results are displayed 1355 p1, p2 = param.split('.') 1356 if not model.is_fittable(p1) and not (p2 == 'width' and param in res.param_list)\ 1357 and param in param_list: 1358 param_list.remove(param) 1359 elif not model.is_fittable(param) and \ 1343 1360 param in param_list: 1344 1361 param_list.remove(param) … … 1361 1378 batch_outputs["Chi2"].append(ERROR) 1362 1379 for param in param_list: 1363 # save value of fixed parameters1380 # Save value of fixed parameters 1364 1381 if param not in res.param_list: 1365 1382 batch_outputs[str(param)].append(ERROR) 1366 1383 else: 1367 # save only fitted values1384 # Save only fitted values 1368 1385 batch_outputs[param].append(ERROR) 1369 1386 batch_inputs["error on %s" % str(param)].append(ERROR) -
src/sas/sasgui/perspectives/fitting/models.py
rb682c6a r13374be 14 14 import py_compile 15 15 import shutil 16 from copy import copy 16 17 # Explicitly import from the pluginmodel module so that py2exe 17 18 # places it in the distribution. The Model1DPlugin class is used … … 281 282 """ 282 283 283 # regular model names only284 # Regular model names only 284 285 self.model_name_list = [] 285 286 286 # Build list automagically from sasmodels package287 # Build list automagically from sasmodels package 287 288 for model in load_standard_models(): 288 289 self.model_dictionary[model.name] = model … … 296 297 self.model_name_list.append(model.name) 297 298 298 # Looking for plugins299 # Looking for plugins 299 300 self.stored_plugins = self.findModels() 300 301 self.plugins = self.stored_plugins.values() 301 302 for name, plug in self.stored_plugins.iteritems(): 302 303 self.model_dictionary[name] = plug 304 # TODO: Remove 'hasattr' statements when old style plugin models 305 # are no longer supported. All sasmodels models will have 306 # the required attributes. 307 if hasattr(plug, 'is_structure_factor') and plug.is_structure_factor: 308 self.struct_list.append(plug) 309 self.plugins.remove(plug) 310 elif hasattr(plug, 'is_form_factor') and plug.is_form_factor: 311 self.multiplication_factor.append(plug) 312 if hasattr(plug, 'is_multiplicity_model') and plug.is_multiplicity_model: 313 self.multi_func_list.append(plug) 303 314 304 315 self._get_multifunc_models() … … 343 354 """ 344 355 self.plugins = [] 345 new_plugins = _find_models() 346 for name, plug in new_plugins.iteritems(): 347 for stored_name, stored_plug in self.stored_plugins.iteritems(): 348 if name == stored_name: 349 del self.stored_plugins[name] 350 del self.model_dictionary[name] 351 break 356 self.stored_plugins = _find_models() 357 structure_names = [model.name for model in self.struct_list] 358 form_names = [model.name for model in self.multiplication_factor] 359 360 # Remove all plugin structure factors and form factors 361 for name in copy(structure_names): 362 if '[plug-in]' in name: 363 i = structure_names.index(name) 364 del self.struct_list[i] 365 structure_names.remove(name) 366 for name in copy(form_names): 367 if '[plug-in]' in name: 368 i = form_names.index(name) 369 del self.multiplication_factor[i] 370 form_names.remove(name) 371 372 # Add new plugin structure factors and form factors 373 for name, plug in self.stored_plugins.iteritems(): 374 if plug.is_structure_factor: 375 if name in structure_names: 376 # Delete the old model from self.struct list 377 i = structure_names.index(name) 378 del self.struct_list[i] 379 # Add the new model to self.struct_list 380 self.struct_list.append(plug) 381 elif plug.is_form_factor: 382 if name in form_names: 383 # Delete the old model from self.multiplication_factor 384 i = form_names.index(name) 385 del self.multiplication_factor[i] 386 # Add the new model to self.multiplication_factor 387 self.multiplication_factor.append(plug) 388 389 # Add references to the updated model 352 390 self.stored_plugins[name] = plug 353 self.plugins.append(plug) 391 if not plug.is_structure_factor: 392 # Don't show S(Q) models in the 'Plugin Models' dropdown 393 self.plugins.append(plug) 354 394 self.model_dictionary[name] = plug 355 395 356 396 self.model_combobox.reset_list("Plugin Models", self.plugins) 397 self.model_combobox.reset_list("Structure Factors", self.struct_list) 398 self.model_combobox.reset_list("P(Q)*S(Q)", self.multiplication_factor) 399 357 400 return self.model_combobox.get_list() 358 401 -
src/sas/sascalc/dataloader/file_reader_base_class.py
ra78a02f rae69c690 115 115 data.y = np.asarray([data.y[i] for i in ind]).astype(np.float64) 116 116 if data.dx is not None: 117 if len(data.dx) == 0: 118 data.dx = None 119 continue 117 120 data.dx = np.asarray([data.dx[i] for i in ind]).astype(np.float64) 118 121 if data.dxl is not None: … … 121 124 data.dxw = np.asarray([data.dxw[i] for i in ind]).astype(np.float64) 122 125 if data.dy is not None: 126 if len(data.dy) == 0: 127 data.dy = None 128 continue 123 129 data.dy = np.asarray([data.dy[i] for i in ind]).astype(np.float64) 124 130 if data.lam is not None: … … 185 191 self.output = [] 186 192 187 def remove_empty_q_values(self, has_error_dx=False, has_error_dy=False): 193 def remove_empty_q_values(self, has_error_dx=False, has_error_dy=False, 194 has_error_dxl=False, has_error_dxw=False): 188 195 """ 189 196 Remove any point where Q == 0 … … 192 199 self.current_dataset.x = self.current_dataset.x[x != 0] 193 200 self.current_dataset.y = self.current_dataset.y[x != 0] 194 self.current_dataset.dy = self.current_dataset.dy[x != 0] if \ 195 has_error_dy else np.zeros(len(self.current_dataset.y)) 196 self.current_dataset.dx = self.current_dataset.dx[x != 0] if \ 197 has_error_dx else np.zeros(len(self.current_dataset.x)) 201 if has_error_dy: 202 self.current_dataset.dy = self.current_dataset.dy[x != 0] 203 if has_error_dx: 204 self.current_dataset.dx = self.current_dataset.dx[x != 0] 205 if has_error_dxl: 206 self.current_dataset.dxl = self.current_dataset.dxl[x != 0] 207 if has_error_dxw: 208 self.current_dataset.dxw = self.current_dataset.dxw[x != 0] 198 209 199 210 def reset_data_list(self, no_lines=0): … … 204 215 x = np.zeros(no_lines) 205 216 y = np.zeros(no_lines) 217 dx = np.zeros(no_lines) 206 218 dy = np.zeros(no_lines) 207 dx = np.zeros(no_lines)208 219 self.current_dataset = plottable_1D(x, y, dx, dy) 209 220 -
src/sas/sascalc/dataloader/readers/cansas_reader.py
ra78a02f rae69c690 130 130 self.current_datainfo.meta_data[PREPROCESS] = self.processing_instructions 131 131 self._parse_entry(entry) 132 has_error_dx = self.current_dataset.dx is not None 133 has_error_dy = self.current_dataset.dy is not None 134 self.remove_empty_q_values(has_error_dx=has_error_dx, 135 has_error_dy=has_error_dy) 136 self.send_to_output() # Combine datasets with DataInfo 137 self.current_datainfo = DataInfo() # Reset DataInfo 132 self.data_cleanup() 138 133 except FileContentsException as fc_exc: 139 134 # File doesn't meet schema - try loading with a less strict schema … … 154 149 self.load_file_and_schema(xml_file) # Reload strict schema so we can find where error are in file 155 150 invalid_xml = self.find_invalid_xml() 156 invalid_xml = INVALID_XML.format(basename + self.extension) + invalid_xml 157 raise DataReaderException(invalid_xml) # Handled by base class 151 if invalid_xml != "": 152 invalid_xml = INVALID_XML.format(basename + self.extension) + invalid_xml 153 raise DataReaderException(invalid_xml) # Handled by base class 158 154 except FileContentsException as fc_exc: 159 155 msg = "CanSAS Reader could not load the file {}".format(xml_file) … … 279 275 # I and Q points 280 276 elif tagname == 'I' and isinstance(self.current_dataset, plottable_1D): 281 unit_list = unit.split("|") 282 if len(unit_list) > 1: 283 self.current_dataset.yaxis(unit_list[0].strip(), 284 unit_list[1].strip()) 285 else: 286 self.current_dataset.yaxis("Intensity", unit) 277 self.current_dataset.yaxis("Intensity", unit) 287 278 self.current_dataset.y = np.append(self.current_dataset.y, data_point) 288 279 elif tagname == 'Idev' and isinstance(self.current_dataset, plottable_1D): 289 280 self.current_dataset.dy = np.append(self.current_dataset.dy, data_point) 290 281 elif tagname == 'Q': 291 unit_list = unit.split("|") 292 if len(unit_list) > 1: 293 self.current_dataset.xaxis(unit_list[0].strip(), 294 unit_list[1].strip()) 295 else: 296 self.current_dataset.xaxis("Q", unit) 282 self.current_dataset.xaxis("Q", unit) 297 283 self.current_dataset.x = np.append(self.current_dataset.x, data_point) 298 284 elif tagname == 'Qdev': 299 285 self.current_dataset.dx = np.append(self.current_dataset.dx, data_point) 300 286 elif tagname == 'dQw': 301 if self.current_dataset.dxw is None: 302 self.current_dataset.dxw = np.empty(0) 303 self.current_dataset.dxw = np.append(self.current_dataset.dxw, data_point) 287 self.current_dataset.dxw = np.append(self.current_dataset.dxw, data_point) 304 288 elif tagname == 'dQl': 305 if self.current_dataset.dxl is None:306 self.current_dataset.dxl = np.empty(0)307 289 self.current_dataset.dxl = np.append(self.current_dataset.dxl, data_point) 308 290 elif tagname == 'Qmean': … … 312 294 elif tagname == 'Sesans': 313 295 self.current_datainfo.isSesans = bool(data_point) 296 self.current_dataset.xaxis(attr.get('x_axis'), 297 attr.get('x_unit')) 298 self.current_dataset.yaxis(attr.get('y_axis'), 299 attr.get('y_unit')) 314 300 elif tagname == 'yacceptance': 315 301 self.current_datainfo.sample.yacceptance = (data_point, unit) … … 512 498 for error in self.errors: 513 499 self.current_datainfo.errors.add(error) 514 self.errors.clear() 515 self.send_to_output() 500 self.data_cleanup() 501 self.sort_one_d_data() 502 self.sort_two_d_data() 503 self.reset_data_list() 516 504 empty = None 517 505 return self.output[0], empty 506 507 def data_cleanup(self): 508 """ 509 Clean up the data sets and refresh everything 510 :return: None 511 """ 512 has_error_dx = self.current_dataset.dx is not None 513 has_error_dxl = self.current_dataset.dxl is not None 514 has_error_dxw = self.current_dataset.dxw is not None 515 has_error_dy = self.current_dataset.dy is not None 516 self.remove_empty_q_values(has_error_dx=has_error_dx, 517 has_error_dxl=has_error_dxl, 518 has_error_dxw=has_error_dxw, 519 has_error_dy=has_error_dy) 520 self.send_to_output() # Combine datasets with DataInfo 521 self.current_datainfo = DataInfo() # Reset DataInfo 518 522 519 523 def _is_call_local(self): … … 642 646 value_unit = local_unit 643 647 except KeyError: 644 err_msg = "CanSAS reader: unexpected " 645 err_msg += "\"{0}\" unit [{1}]; " 646 err_msg = err_msg.format(tagname, local_unit) 647 err_msg += "expecting [{0}]".format(default_unit) 648 # Do not throw an error for loading Sesans data in cansas xml 649 # This is a temporary fix. 650 if local_unit != "A" and local_unit != 'pol': 651 err_msg = "CanSAS reader: unexpected " 652 err_msg += "\"{0}\" unit [{1}]; " 653 err_msg = err_msg.format(tagname, local_unit) 654 err_msg += "expecting [{0}]".format(default_unit) 648 655 value_unit = local_unit 649 656 except: … … 675 682 di_exists = True 676 683 if dqw_exists and not dql_exists: 677 array_size = self.current_dataset.dxw.size - 1 678 self.current_dataset.dxl = np.append(self.current_dataset.dxl, 679 np.zeros([array_size])) 684 array_size = self.current_dataset.dxw.size 685 self.current_dataset.dxl = np.zeros(array_size) 680 686 elif dql_exists and not dqw_exists: 681 array_size = self.current_dataset.dxl.size - 1 682 self.current_dataset.dxw = np.append(self.current_dataset.dxw, 683 np.zeros([array_size])) 687 array_size = self.current_dataset.dxl.size 688 self.current_dataset.dxw = np.zeros(array_size) 684 689 elif not dql_exists and not dqw_exists and not dq_exists: 685 array_size = self.current_dataset.x.size - 1690 array_size = self.current_dataset.x.size 686 691 self.current_dataset.dx = np.append(self.current_dataset.dx, 687 692 np.zeros([array_size])) 688 693 if not di_exists: 689 array_size = self.current_dataset.y.size - 1694 array_size = self.current_dataset.y.size 690 695 self.current_dataset.dy = np.append(self.current_dataset.dy, 691 696 np.zeros([array_size])) … … 857 862 node.append(point) 858 863 self.write_node(point, "Q", datainfo.x[i], 859 {'unit': datainfo. _xaxis + " | " + datainfo._xunit})864 {'unit': datainfo.x_unit}) 860 865 if len(datainfo.y) >= i: 861 866 self.write_node(point, "I", datainfo.y[i], 862 {'unit': datainfo. _yaxis + " | " + datainfo._yunit})867 {'unit': datainfo.y_unit}) 863 868 if datainfo.dy is not None and len(datainfo.dy) > i: 864 869 self.write_node(point, "Idev", datainfo.dy[i], 865 {'unit': datainfo. _yaxis + " | " + datainfo._yunit})870 {'unit': datainfo.y_unit}) 866 871 if datainfo.dx is not None and len(datainfo.dx) > i: 867 872 self.write_node(point, "Qdev", datainfo.dx[i], 868 {'unit': datainfo. _xaxis + " | " + datainfo._xunit})873 {'unit': datainfo.x_unit}) 869 874 if datainfo.dxw is not None and len(datainfo.dxw) > i: 870 875 self.write_node(point, "dQw", datainfo.dxw[i], 871 {'unit': datainfo. _xaxis + " | " + datainfo._xunit})876 {'unit': datainfo.x_unit}) 872 877 if datainfo.dxl is not None and len(datainfo.dxl) > i: 873 878 self.write_node(point, "dQl", datainfo.dxl[i], 874 {'unit': datainfo. _xaxis + " | " + datainfo._xunit})879 {'unit': datainfo.x_unit}) 875 880 if datainfo.isSesans: 876 sesans = self.create_element("Sesans") 881 sesans_attrib = {'x_axis': datainfo._xaxis, 882 'y_axis': datainfo._yaxis, 883 'x_unit': datainfo.x_unit, 884 'y_unit': datainfo.y_unit} 885 sesans = self.create_element("Sesans", attrib=sesans_attrib) 877 886 sesans.text = str(datainfo.isSesans) 878 node.append(sesans)879 self.write_node( node, "yacceptance", datainfo.sample.yacceptance[0],887 entry_node.append(sesans) 888 self.write_node(entry_node, "yacceptance", datainfo.sample.yacceptance[0], 880 889 {'unit': datainfo.sample.yacceptance[1]}) 881 self.write_node( node, "zacceptance", datainfo.sample.zacceptance[0],890 self.write_node(entry_node, "zacceptance", datainfo.sample.zacceptance[0], 882 891 {'unit': datainfo.sample.zacceptance[1]}) 883 892 -
src/sas/sascalc/dataloader/readers/cansas_reader_HDF5.py
rdcb91cf rcd57c7d4 140 140 141 141 if isinstance(value, h5py.Group): 142 # Set parent class before recursion 142 143 self.parent_class = class_name 143 144 parent_list.append(key) … … 150 151 # Recursion step to access data within the group 151 152 self.read_children(value, parent_list) 153 # Reset parent class when returning from recursive method 154 self.parent_class = class_name 152 155 self.add_intermediate() 153 156 parent_list.remove(key) -
src/sas/sascalc/dataloader/readers/xml_reader.py
rfafe52a rcd57c7d4 134 134 first_error = schema.assertValid(self.xmldoc) 135 135 except etree.DocumentInvalid as err: 136 # Suppress errors for <'any'> elements 137 if "##other" in str(err): 138 return first_error 136 139 first_error = str(err) 137 140 return first_error -
src/sas/sascalc/invariant/invariant.py
r7432acb rb1f20d1 610 610 # Data boundaries for fitting 611 611 qmin = self._data.x[0] 612 qmax = self._data.x[ self._low_extrapolation_npts - 1]612 qmax = self._data.x[int(self._low_extrapolation_npts - 1)] 613 613 614 614 # Extrapolate the low-Q data … … 649 649 # Data boundaries for fitting 650 650 x_len = len(self._data.x) - 1 651 qmin = self._data.x[ x_len - (self._high_extrapolation_npts - 1)]652 qmax = self._data.x[ x_len]651 qmin = self._data.x[int(x_len - (self._high_extrapolation_npts - 1))] 652 qmax = self._data.x[int(x_len)] 653 653 654 654 # fit the data with a model to get the appropriate parameters … … 688 688 if npts_in is None: 689 689 npts_in = self._low_extrapolation_npts 690 q_end = self._data.x[max(0, npts_in - 1)]690 q_end = self._data.x[max(0, int(npts_in - 1))] 691 691 692 692 if q_start >= q_end: … … 714 714 # Get extrapolation range 715 715 if npts_in is None: 716 npts_in = self._high_extrapolation_npts716 npts_in = int(self._high_extrapolation_npts) 717 717 _npts = len(self._data.x) 718 q_start = self._data.x[min(_npts, _npts - npts_in)]718 q_start = self._data.x[min(_npts, int(_npts - npts_in))] 719 719 720 720 if q_start >= q_end: -
src/sas/sasgui/guiframe/config.py
ra1b8fee rce2819b 48 48 '''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.''' 49 49 _acknowledgement_citation = \ 50 '''M. Doucet et al. SasView Version 4.1 , Zenodo, 10.5281/zenodo.438138'''50 '''M. Doucet et al. SasView Version 4.1.2, Zenodo, 10.5281/zenodo.825675''' 51 51 52 52 _acknowledgement = \ -
src/sas/sasgui/guiframe/documentation_window.py
r959eb01 r6a455cd3 75 75 logger.error("Could not find Sphinx documentation at %s \ 76 76 -- has it been built?", file_path) 77 elif WX_SUPPORTS_HTML2: 78 # Complete HTML/CSS support! 79 self.view = html.WebView.New(self) 80 self.view.LoadURL(url) 81 self.Show() 77 #Commenting following 5 lines, so default browser is forced 78 #This is due to CDN mathjax discontinuation of service, intenal help 79 #browser should be back with qt version 80 #Note added by Wojtek Potrzebowski, July 4th 2017 81 # elif WX_SUPPORTS_HTML2: 82 # # Complete HTML/CSS support! 83 # self.view = html.WebView.New(self) 84 # self.view.LoadURL(url) 85 # self.Show() 82 86 else: 83 87 logger.error("No html2 support, popping up a web browser") -
src/sas/sasgui/perspectives/fitting/pagestate.py
r959eb01 rda9b239 617 617 value = "" 618 618 content = line.split(":") 619 if line == '' or len(content) == 1: 620 continue 619 621 name = content[0] 620 622 try:
Note: See TracChangeset
for help on using the changeset viewer.