Changeset d3b0c77 in sasview for src/sas/sascalc
- Timestamp:
- Sep 23, 2017 4:24:27 PM (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:
- b963b20, fca1f50
- Parents:
- 9706d88 (diff), dba8557 (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/sascalc
- Files:
-
- 6 edited
- 2 moved
Legend:
- Unmodified
- Added
- Removed
-
src/sas/sascalc/dataloader/readers/__init__.py
r7a5d066 r488f3a5 1 1 # Method to associate extensions to default readers 2 2 from associations import read_associations 3 4 5 # Method to return the location of the XML settings file6 def get_data_path():7 """8 Return the location of the settings file for the data readers.9 """10 import os11 return os.path.dirname(__file__) -
src/sas/sascalc/fit/models.py
r9706d88 rd3b0c77 4 4 from __future__ import print_function 5 5 6 import traceback7 6 import os 8 7 import sys 9 import os.path10 # Time is needed by the log method11 8 import time 12 9 import datetime 13 10 import logging 11 import traceback 14 12 import py_compile 15 13 import shutil 16 #?? from copy import copy17 14 18 15 from sasmodels.sasview_model import load_custom_model, load_standard_models 19 from sasmodels.sasview_model import MultiplicationModel 20 #?? from sas.sasgui.perspectives.fitting.fitpage import CUSTOM_MODEL 16 17 from sas.sasgui import get_user_dir 21 18 22 19 # Explicitly import from the pluginmodel module so that py2exe … … 29 26 30 27 PLUGIN_DIR = 'plugin_models' 31 PLUGIN_LOG = os.path.join(os.path.expanduser("~"), '.sasview', PLUGIN_DIR, 32 "plugins.log") 28 PLUGIN_LOG = os.path.join(get_user_dir(), PLUGIN_DIR, "plugins.log") 33 29 PLUGIN_NAME_BASE = '[plug-in] ' 34 30 -
src/sas/sascalc/fit/AbstractFitEngine.py
ra1b8fee r50fcb09 137 137 that will smear the theory data (slit smearing or resolution 138 138 smearing) when set. 139 139 140 140 The proper way to set the smearing object would be to 141 141 do the following: :: 142 143 from sas.sascalc. data_util.qsmearing import smear_selection142 143 from sas.sascalc.fit.qsmearing import smear_selection 144 144 smearer = smear_selection(some_data) 145 145 fitdata1d = FitData1D( x= [1,3,..,], … … 147 147 dx=None, 148 148 dy=[1,2...], smearer= smearer) 149 149 150 150 :Note: that some_data _HAS_ to be of 151 151 class DataLoader.data_info.Data1D 152 152 Setting it back to None will turn smearing off. 153 153 154 154 """ 155 155 Data1D.__init__(self, x=x, y=y, dx=dx, dy=dy, lam=lam, dlam=dlam) … … 176 176 ## Max Q-value 177 177 self.qmax = max(self.x) 178 178 179 179 # Range used for input to smearing 180 180 self._qmin_unsmeared = self.qmin … … 184 184 self.idx_unsmeared = (self.x >= self._qmin_unsmeared) \ 185 185 & (self.x <= self._qmax_unsmeared) 186 186 187 187 def set_fit_range(self, qmin=None, qmax=None): 188 188 """ to set the fit range""" … … 199 199 self._qmin_unsmeared = self.qmin 200 200 self._qmax_unsmeared = self.qmax 201 201 202 202 self._first_unsmeared_bin = 0 203 203 self._last_unsmeared_bin = len(self.x) - 1 204 204 205 205 if self.smearer is not None: 206 206 self._first_unsmeared_bin, self._last_unsmeared_bin = \ … … 208 208 self._qmin_unsmeared = self.x[self._first_unsmeared_bin] 209 209 self._qmax_unsmeared = self.x[self._last_unsmeared_bin] 210 210 211 211 # Identify the bin range for the unsmeared and smeared spaces 212 212 self.idx = (self.x >= self.qmin) & (self.x <= self.qmax) … … 231 231 """ 232 232 Compute residuals. 233 233 234 234 If self.smearer has been set, use if to smear 235 235 the data before computing chi squared. 236 236 237 237 :param fn: function that return model value 238 238 239 239 :return: residuals 240 240 """ … … 242 242 fx = np.zeros(len(self.x)) 243 243 fx[self.idx_unsmeared] = fn(self.x[self.idx_unsmeared]) 244 244 245 245 ## Smear theory data 246 246 if self.smearer is not None: … … 253 253 raise RuntimeError, msg 254 254 return (self.y[self.idx] - fx[self.idx]) / self.dy[self.idx], fx[self.idx] 255 255 256 256 def residuals_deriv(self, model, pars=[]): 257 257 """ 258 258 :return: residuals derivatives . 259 260 :note: in this case just return empty array 259 260 :note: in this case just return empty array 261 261 """ 262 262 return [] … … 293 293 x_max = max(math.fabs(sas_data2d.xmin), math.fabs(sas_data2d.xmax)) 294 294 y_max = max(math.fabs(sas_data2d.ymin), math.fabs(sas_data2d.ymax)) 295 295 296 296 ## fitting range 297 297 if qmin is None: … … 305 305 self.res_err_data = copy.deepcopy(self.err_data) 306 306 #self.res_err_data[self.res_err_data==0]=1 307 307 308 308 self.radius = np.sqrt(self.qx_data**2 + self.qy_data**2) 309 309 310 310 # Note: mask = True: for MASK while mask = False for NOT to mask 311 311 self.idx = ((self.qmin <= self.radius) &\ … … 368 368 369 369 return res, gn 370 370 371 371 def residuals_deriv(self, model, pars=[]): 372 372 """ 373 373 :return: residuals derivatives . 374 374 375 375 :note: in this case just return empty array 376 376 377 377 """ 378 378 return [] 379 380 379 380 381 381 class FitAbort(Exception): 382 382 """ … … 396 396 self.fit_arrange_dict = {} 397 397 self.fitter_id = None 398 398 399 399 def set_model(self, model, id, pars=[], constraints=[], data=None): 400 400 """ 401 401 set a model on a given in the fit engine. 402 403 :param model: sas.models type 402 403 :param model: sas.models type 404 404 :param id: is the key of the fitArrange dictionary where model is saved as a value 405 :param pars: the list of parameters to fit 406 :param constraints: list of 405 :param pars: the list of parameters to fit 406 :param constraints: list of 407 407 tuple (name of parameter, value of parameters) 408 408 the value of parameter must be a string to constraint 2 different 409 409 parameters. 410 Example: 410 Example: 411 411 we want to fit 2 model M1 and M2 both have parameters A and B. 412 412 constraints can be ``constraints = [(M1.A, M2.B+2), (M1.B= M2.A *5),...,]`` 413 414 413 414 415 415 :note: pars must contains only name of existing model's parameters 416 416 417 417 """ 418 418 if not pars: … … 445 445 in a FitArrange object and adds that object in a dictionary 446 446 with key id. 447 447 448 448 :param data: data added 449 449 :param id: unique key corresponding to a fitArrange object with data … … 456 456 dx=data.dx, dy=data.dy, smearer=smearer) 457 457 fitdata.sas_data = data 458 458 459 459 fitdata.set_fit_range(qmin=qmin, qmax=qmax) 460 460 #A fitArrange is already created but contains model only at id … … 466 466 fitproblem.add_data(fitdata) 467 467 self.fit_arrange_dict[id] = fitproblem 468 468 469 469 def get_model(self, id): 470 470 """ 471 471 :param id: id is key in the dictionary containing the model to return 472 472 473 473 :return: a model at this id or None if no FitArrange element was 474 474 created with this id … … 478 478 else: 479 479 return None 480 480 481 481 def remove_fit_problem(self, id): 482 482 """remove fitarrange in id""" 483 483 if id in self.fit_arrange_dict: 484 484 del self.fit_arrange_dict[id] 485 485 486 486 def select_problem_for_fit(self, id, value): 487 487 """ 488 488 select a couple of model and data at the id position in dictionary 489 489 and set in self.selected value to value 490 490 491 491 :param value: the value to allow fitting. 492 492 can only have the value one or zero … … 494 494 if id in self.fit_arrange_dict: 495 495 self.fit_arrange_dict[id].set_to_fit(value) 496 496 497 497 def get_problem_to_fit(self, id): 498 498 """ 499 499 return the self.selected value of the fit problem of id 500 500 501 501 :param id: the id of the problem 502 502 """ 503 503 if id in self.fit_arrange_dict: 504 504 self.fit_arrange_dict[id].get_to_fit() 505 506 505 506 507 507 class FitArrange: 508 508 def __init__(self): … … 511 511 to perform the Fit.FitArrange must contain exactly one model 512 512 and at least one data for the fit to be performed. 513 513 514 514 model: the model selected by the user 515 515 Ldata: a list of data what the user wants to fit 516 516 517 517 """ 518 518 self.model = None … … 525 525 """ 526 526 set_model save a copy of the model 527 527 528 528 :param model: the model being set 529 529 """ 530 530 self.model = model 531 531 532 532 def add_data(self, data): 533 533 """ 534 534 add_data fill a self.data_list with data to fit 535 535 536 536 :param data: Data to add in the list 537 537 """ 538 538 if not data in self.data_list: 539 539 self.data_list.append(data) 540 540 541 541 def get_model(self): 542 542 """ … … 544 544 """ 545 545 return self.model 546 546 547 547 def get_data(self): 548 548 """ … … 550 550 """ 551 551 return self.data_list[0] 552 552 553 553 def remove_data(self, data): 554 554 """ 555 555 Remove one element from the list 556 556 557 557 :param data: Data to remove from data_list 558 558 """ 559 559 if data in self.data_list: 560 560 self.data_list.remove(data) 561 561 562 562 def set_to_fit(self, value=0): 563 563 """ 564 564 set self.selected to 0 or 1 for other values raise an exception 565 565 566 566 :param value: integer between 0 or 1 567 567 """ 568 568 self.selected = value 569 569 570 570 def get_to_fit(self): 571 571 """ … … 599 599 if self.model is not None and self.data is not None: 600 600 self.inputs = [(self.model, self.data)] 601 601 602 602 def set_model(self, model): 603 603 """ 604 604 """ 605 605 self.model = model 606 606 607 607 def set_fitness(self, fitness): 608 608 """ 609 609 """ 610 610 self.fitness = fitness 611 611 612 612 def __str__(self): 613 613 """ … … 624 624 msg = [msg1, msg3] + msg2 625 625 return "\n".join(msg) 626 626 627 627 def print_summary(self): 628 628 """ -
src/sas/sascalc/fit/BumpsFitting.py
r9a5097c r1386b2f 15 15 def get_fitter(): 16 16 return FIT_CONFIG.selected_fitter, FIT_CONFIG.selected_values 17 except :17 except ImportError: 18 18 # CRUFT: Bumps changed its handling of fit options around 0.7.5.6 19 19 # Default bumps to use the Levenberg-Marquardt optimizer … … 56 56 header = "=== Steps: %s chisq: %s ETA: %s\n"%(step, chisq, time) 57 57 parameters = ["%15s: %-10.3g%s"%(k,v,("\n" if i%3==2 else " | ")) 58 for i, (k,v) in enumerate(zip(pars,history.point[0]))]58 for i, (k, v) in enumerate(zip(pars, history.point[0]))] 59 59 self.msg = "".join([header]+parameters) 60 60 … … 77 77 self.handler.set_result(Progress(history, self.max_step, self.pars, self.dof)) 78 78 self.handler.progress(history.step[0], self.max_step) 79 if len(history.step) >1 and history.step[1] > history.step[0]:79 if len(history.step) > 1 and history.step[1] > history.step[0]: 80 80 self.handler.improvement() 81 81 self.handler.update_fit() … … 97 97 try: 98 98 p = history.population_values[0] 99 n, p = len(p), np.sort(p)100 QI, Qmid, = int(0.2*n),int(0.5*n)101 self.convergence.append((best, p[0], p[QI],p[Qmid],p[-1-QI],p[-1]))102 except :103 self.convergence.append((best, best, best,best,best,best))99 n, p = len(p), np.sort(p) 100 QI, Qmid = int(0.2*n), int(0.5*n) 101 self.convergence.append((best, p[0], p[QI], p[Qmid], p[-1-QI], p[-1])) 102 except Exception: 103 self.convergence.append((best, best, best, best, best, best)) 104 104 105 105 … … 131 131 132 132 def _reset_pars(self, names, values): 133 for k, v in zip(names, values):133 for k, v in zip(names, values): 134 134 self._pars[k].value = v 135 135 … … 137 137 self._pars = {} 138 138 for k in self.model.getParamList(): 139 name = ".".join((self.name, k))139 name = ".".join((self.name, k)) 140 140 value = self.model.getParam(k) 141 bounds = self.model.details.get(k, ["",None,None])[1:3]141 bounds = self.model.details.get(k, ["", None, None])[1:3] 142 142 self._pars[k] = parameter.Parameter(value=value, bounds=bounds, 143 143 fixed=True, name=name) … … 145 145 146 146 def _init_pars(self, kw): 147 for k, v in kw.items():147 for k, v in kw.items(): 148 148 # dispersion parameters initialized with _field instead of .field 149 if k.endswith('_width'): k = k[:-6]+'.width' 150 elif k.endswith('_npts'): k = k[:-5]+'.npts' 151 elif k.endswith('_nsigmas'): k = k[:-7]+'.nsigmas' 152 elif k.endswith('_type'): k = k[:-5]+'.type' 149 if k.endswith('_width'): 150 k = k[:-6]+'.width' 151 elif k.endswith('_npts'): 152 k = k[:-5]+'.npts' 153 elif k.endswith('_nsigmas'): 154 k = k[:-7]+'.nsigmas' 155 elif k.endswith('_type'): 156 k = k[:-5]+'.type' 153 157 if k not in self._pars: 154 158 formatted_pars = ", ".join(sorted(self._pars.keys())) … … 159 163 elif isinstance(v, parameter.BaseParameter): 160 164 self._pars[k] = v 161 elif isinstance(v, (tuple, list)):165 elif isinstance(v, (tuple, list)): 162 166 low, high = v 163 167 self._pars[k].value = (low+high)/2 164 self._pars[k].range(low, high)168 self._pars[k].range(low, high) 165 169 else: 166 170 self._pars[k].value = v … … 170 174 Flag a set of parameters as fitted parameters. 171 175 """ 172 for k, p in self._pars.items():176 for k, p in self._pars.items(): 173 177 p.fixed = (k not in param_list or k in self.constraints) 174 178 self.fitted_par_names = [k for k in param_list if k not in self.constraints] … … 182 186 183 187 def update(self): 184 for k, v in self._pars.items():188 for k, v in self._pars.items(): 185 189 #print "updating",k,v,v.value 186 self.model.setParam(k, v.value)190 self.model.setParam(k, v.value) 187 191 self._dirty = True 188 192 … … 223 227 symtab = dict((".".join((M.name, k)), p) 224 228 for M in self.models 225 for k, p in M.parameters().items())229 for k, p in M.parameters().items()) 226 230 self.update = compile_constraints(symtab, exprs) 227 231 else: … … 300 304 np.NaN*np.ones(len(fitness.computed_pars)))) 301 305 R.pvec = np.hstack((result['value'][fitted_index], 302 306 [p.value for p in fitness.computed_pars])) 303 307 R.fitness = np.sum(R.residuals**2)/(fitness.numpoints() - len(fitted_index)) 304 308 else: 305 309 R.stderr = np.NaN*np.ones(len(param_list)) 306 R.pvec = np.asarray( 310 R.pvec = np.asarray([p.value for p in fitness.fitted_pars+fitness.computed_pars]) 307 311 R.fitness = np.NaN 308 312 R.convergence = result['convergence'] … … 331 335 steps = options.get('steps', 0) 332 336 if steps == 0: 333 pop = options.get('pop', 0)*len(problem._parameters)337 pop = options.get('pop', 0)*len(problem._parameters) 334 338 samples = options.get('samples', 0) 335 339 steps = (samples+pop-1)/pop if pop != 0 else samples … … 343 347 fitdriver = fitters.FitDriver(fitclass, problem=problem, 344 348 abort_test=abort_test, **options) 345 omp_threads = int(os.environ.get('OMP_NUM_THREADS', '0'))349 omp_threads = int(os.environ.get('OMP_NUM_THREADS', '0')) 346 350 mapper = MPMapper if omp_threads == 1 else SerialMapper 347 351 fitdriver.mapper = mapper.start_mapper(problem, None) … … 359 363 convergence_list = options['monitors'][-1].convergence 360 364 convergence = (2*np.asarray(convergence_list)/problem.dof 361 if convergence_list else np.empty((0, 1),'d'))365 if convergence_list else np.empty((0, 1), 'd')) 362 366 363 367 success = best is not None … … 376 380 'errors': '\n'.join(errors), 377 381 } 378 -
src/sas/sascalc/fit/pagestate.py
rda9b239 r277257f 1 1 """ 2 2 Class that holds a fit page state 3 3 """ 4 4 # TODO: Refactor code so we don't need to use getattr/setattr … … 15 15 import os 16 16 import sys 17 import wx18 17 import copy 19 18 import logging … … 23 22 import xml.dom.minidom 24 23 from xml.dom.minidom import parseString 24 from xml.dom.minidom import getDOMImplementation 25 25 from lxml import etree 26 26 27 27 from sasmodels import convert 28 28 import sasmodels.weights 29 30 from sas.sasview import __version__ as SASVIEW_VERSION 29 31 30 32 import sas.sascalc.dataloader … … 38 40 # Information to read/write state as xml 39 41 FITTING_NODE_NAME = 'fitting_plug_in' 40 CANSAS_NS = "cansas1d/1.0"42 CANSAS_NS = {"ns": "cansas1d/1.0"} 41 43 42 44 CUSTOM_MODEL = 'Plugin Models' … … 72 74 ["cb1", "cb1", "bool"], 73 75 ["tcChi", "tcChi", "float"], 74 ["smearer", "smearer", "float"],75 ["smear_type", "smear_type", "string"],76 76 ["dq_l", "dq_l", "float"], 77 77 ["dq_r", "dq_r", "float"], … … 83 83 ["weights", "weights"]] 84 84 85 DISPERSION_LIST = [["disp_obj_dict", " _disp_obj_dict", "string"]]85 DISPERSION_LIST = [["disp_obj_dict", "disp_obj_dict", "string"]] 86 86 87 87 LIST_OF_STATE_PARAMETERS = [["parameters", "parameters"], … … 142 142 Contains information to reconstruct a page of the fitpanel. 143 143 """ 144 def __init__(self, parent=None,model=None, data=None):144 def __init__(self, model=None, data=None): 145 145 """ 146 146 Initialize the current state … … 154 154 self.timestamp = time.time() 155 155 # Data member to store the dispersion object created 156 self. _disp_obj_dict = {}156 self.disp_obj_dict = {} 157 157 # ------------------------ 158 158 # Data used for fitting … … 190 190 # fit page manager 191 191 self.manager = None 192 # Store the parent of this panel parent193 # For this application fitpanel is the parent194 self.parent = parent195 192 # Event_owner is the owner of model event 196 193 self.event_owner = None … … 211 208 # orientation parameters for gaussian dispersity 212 209 self.orientation_params_disp = [] 213 # smearer info214 self.smearer = None215 self.smear_type = None216 210 self.dq_l = None 217 211 self.dq_r = None … … 231 225 # contains link between a model and selected parameters to fit 232 226 self.param_toFit = [] 233 # dictionary of model type and model class234 self.model_list_box = None235 227 # save the state of the context menu 236 228 self.saved_states = {} … … 277 269 # store value of chisqr 278 270 self.tcChi = None 279 self.version = (1, 0,0)271 self.version = (1, 0, 0) 280 272 281 273 def clone(self): … … 287 279 model = self.model.clone() 288 280 model.name = self.model.name 289 obj = PageState( self.parent,model=model)281 obj = PageState(model=model) 290 282 obj.file = copy.deepcopy(self.file) 291 283 obj.data = copy.deepcopy(self.data) … … 294 286 obj.data_name = self.data_name 295 287 obj.is_data = self.is_data 296 obj.model_list_box = copy.deepcopy(self.model_list_box)297 288 298 289 obj.categorycombobox = self.categorycombobox … … 321 312 obj.tcChi = self.tcChi 322 313 323 if len(self. _disp_obj_dict) > 0:324 for k, v in self. _disp_obj_dict.iteritems():325 obj. _disp_obj_dict[k] = v314 if len(self.disp_obj_dict) > 0: 315 for k, v in self.disp_obj_dict.iteritems(): 316 obj.disp_obj_dict[k] = v 326 317 if len(self.disp_cb_dict) > 0: 327 318 for k, v in self.disp_cb_dict.iteritems(): … … 337 328 obj.pinhole_smearer = copy.deepcopy(self.pinhole_smearer) 338 329 obj.slit_smearer = copy.deepcopy(self.slit_smearer) 339 obj.smear_type = copy.deepcopy(self.smear_type)340 330 obj.dI_noweight = copy.deepcopy(self.dI_noweight) 341 331 obj.dI_didata = copy.deepcopy(self.dI_didata) … … 355 345 obj.npts = copy.deepcopy(self.npts) 356 346 obj.cb1 = copy.deepcopy(self.cb1) 357 obj.smearer = copy.deepcopy(self.smearer)358 347 obj.version = copy.deepcopy(self.version) 359 348 … … 519 508 rep = "\nState name: %s\n" % self.file 520 509 t = time.localtime(self.timestamp) 521 time_str = time.strftime("%b %d %Y %H ;%M;%S ", t)510 time_str = time.strftime("%b %d %Y %H:%M:%S ", t) 522 511 523 512 rep += "State created: %s\n" % time_str … … 559 548 rep += "All parameters checkbox selected: %s\n" % self.cb1 560 549 rep += "Value of Chisqr : %s\n" % str(self.tcChi) 561 rep += "Smear object : %s\n" % self.smearer562 rep += "Smear type : %s\n" % self.smear_type563 550 rep += "dq_l : %s\n" % self.dq_l 564 551 rep += "dq_r : %s\n" % self.dq_r … … 596 583 return rep 597 584 598 def set_report_string(self):585 def _get_report_string(self): 599 586 """ 600 587 Get the values (strings) from __str__ for report … … 611 598 q_range = "" 612 599 strings = self.__repr__() 600 fixed_parameter = False 613 601 lines = strings.split('\n') 614 615 602 # get all string values from __str__() 616 603 for line in lines: 617 value = "" 618 content = line.split(":") 619 if line == '' or len(content) == 1: 604 # Skip lines which are not key: value pairs, which includes 605 # blank lines and freeform notes in SASNotes fields. 606 if not ':' in line: 607 #msg = "Report string expected 'name: value' but got %r" % line 608 #logger.error(msg) 620 609 continue 621 name = content[0] 622 try: 623 value = content[1] 624 except Exception: 625 msg = "Report string expected 'name: value' but got %r" % line 626 logger.error(msg) 627 if name.count("State created"): 628 repo_time = "" + value 629 if name.count("parameter name"): 610 611 name, value = [s.strip() for s in line.split(":", 1)] 612 if name == "State created": 613 repo_time = value 614 elif name == "parameter name": 630 615 val_name = value.split(".") 631 616 if len(val_name) > 1: … … 636 621 else: 637 622 param_string += value + ',' 638 if name == "value":623 elif name == "value": 639 624 param_string += value + ',' 640 fixed_parameter = False 641 if name == "selected": 642 if value == u' False': 643 fixed_parameter = True 644 if name == "error value": 625 elif name == "selected": 626 # remember if it is fixed when reporting error value 627 fixed_parameter = (value == u'False') 628 elif name == "error value": 645 629 if fixed_parameter: 646 630 param_string += '(fixed),' 647 631 else: 648 632 param_string += value + ',' 649 if name == "parameter unit":633 elif name == "parameter unit": 650 634 param_string += value + ':' 651 if name == "Value of Chisqr":635 elif name == "Value of Chisqr": 652 636 chi2 = ("Chi2/Npts = " + value) 653 637 chi2_string = CENTRE % chi2 654 if name == "Title":638 elif name == "Title": 655 639 if len(value.strip()) == 0: 656 640 continue 657 641 title = value + " [" + repo_time + "]" 658 642 title_name = HEADER % title 659 if name == "data":643 elif name == "data": 660 644 try: 661 file_value = ("File name:" + content[2]) 645 # parsing "data : File: filename [mmm dd hh:mm]" 646 name = value.split(':', 1)[1].strip() 647 file_value = "File name:" + name 662 648 file_name = CENTRE % file_value 663 649 if len(title) == 0: 664 title = content[2]+ " [" + repo_time + "]"650 title = name + " [" + repo_time + "]" 665 651 title_name = HEADER % title 666 652 except Exception: 667 653 msg = "While parsing 'data: ...'\n" 668 654 logger.error(msg + traceback.format_exc()) 669 if name == "model name":655 elif name == "model name": 670 656 try: 671 modelname = "Model name:" + content[1]672 except :657 modelname = "Model name:" + value 658 except Exception: 673 659 modelname = "Model name:" + " NAN" 674 660 model_name = CENTRE % modelname 675 661 676 if name == "Plotting Range":662 elif name == "Plotting Range": 677 663 try: 678 q_range = content[1] + " = " + content[2] \ 679 + " = " + content[3].split(",")[0] 664 parts = value.split(':') 665 q_range = parts[0] + " = " + parts[1] \ 666 + " = " + parts[2].split(",")[0] 680 667 q_name = ("Q Range: " + q_range) 681 668 q_range = CENTRE % q_name … … 683 670 msg = "While parsing 'Plotting Range: ...'\n" 684 671 logger.error(msg + traceback.format_exc()) 672 685 673 paramval = "" 686 674 for lines in param_string.split(":"): … … 711 699 "\n" + paramval_string + \ 712 700 "\n" + ELINE + \ 713 "\n" + FEET_1 % title + \ 714 "\n" + FEET_2 701 "\n" + FEET_1 % title 715 702 716 703 return html_string, text_string, title … … 725 712 return name 726 713 727 def report(self, fig s=None, canvases=None):714 def report(self, fig_urls): 728 715 """ 729 716 Invoke report dialog panel … … 731 718 : param figs: list of pylab figures [list] 732 719 """ 733 from sas.sasgui.perspectives.fitting.report_dialog import ReportDialog734 720 # get the strings for report 735 html_str, text_str, title = self. set_report_string()721 html_str, text_str, title = self._get_report_string() 736 722 # Allow 2 figures to append 737 if len(figs) == 1: 738 add_str = FEET_3 739 elif len(figs) == 2: 740 add_str = ELINE 741 add_str += FEET_2 % ("%s") 742 add_str += ELINE 743 add_str += FEET_3 744 elif len(figs) > 2: 745 add_str = ELINE 746 add_str += FEET_2 % ("%s") 747 add_str += ELINE 748 add_str += FEET_2 % ("%s") 749 add_str += ELINE 750 add_str += FEET_3 751 else: 752 add_str = "" 723 image_links = [FEET_2%fig for fig in fig_urls] 753 724 754 725 # final report html strings 755 report_str = html_str % ("%s") + add_str 756 757 # make plot image 758 images = self.set_plot_state(figs, canvases) 759 report_list = [report_str, text_str, images] 760 dialog = ReportDialog(report_list, None, wx.ID_ANY, "") 761 dialog.Show() 726 report_str = html_str + ELINE.join(image_links) 727 728 return report_str, text_str 762 729 763 730 def _to_xml_helper(self, thelist, element, newdoc): … … 794 761 :param batch_fit_state: simultaneous fit state 795 762 """ 796 from xml.dom.minidom import getDOMImplementation797 798 763 # Check whether we have to write a standalone XML file 799 764 if doc is None: … … 807 772 try: 808 773 top_element = newdoc.createElement(FITTING_NODE_NAME) 809 except :774 except Exception: 810 775 string = etree.tostring(doc, pretty_print=True) 811 776 newdoc = parseString(string) … … 816 781 try: 817 782 entry_node.appendChild(top_element) 818 except :783 except Exception: 819 784 node_name = entry_node.tag 820 785 node_list = newdoc.getElementsByTagName(node_name) … … 823 788 824 789 attr = newdoc.createAttribute("version") 825 from sas import sasview 826 attr.nodeValue = sasview.__version__ 790 attr.nodeValue = SASVIEW_VERSION 827 791 # attr.nodeValue = '1.0' 828 792 top_element.setAttributeNode(attr) … … 880 844 inputs.appendChild(element) 881 845 882 # Create doc for the dictionary of self. _disp_obj_dic846 # Create doc for the dictionary of self.disp_obj_dic 883 847 for tagname, varname, tagtype in DISPERSION_LIST: 884 848 element = newdoc.createElement(tagname) … … 961 925 """ 962 926 for item in node: 963 try: 964 name = item.get('name') 965 except: 966 name = None 967 try: 968 value = item.get('value') 969 except: 970 value = None 971 try: 972 selected_to_fit = (item.get('selected_to_fit') == "True") 973 except: 974 selected_to_fit = None 975 try: 976 error_displayed = (item.get('error_displayed') == "True") 977 except: 978 error_displayed = None 979 try: 980 error_value = item.get('error_value') 981 except: 982 error_value = None 983 try: 984 minimum_displayed = (item.get('minimum_displayed') == "True") 985 except: 986 minimum_displayed = None 987 try: 988 minimum_value = item.get('minimum_value') 989 except: 990 minimum_value = None 991 try: 992 maximum_displayed = (item.get('maximum_displayed') == "True") 993 except: 994 maximum_displayed = None 995 try: 996 maximum_value = item.get('maximum_value') 997 except: 998 maximum_value = None 999 try: 1000 unit = item.get('unit') 1001 except: 1002 unit = None 927 name = item.get('name') 928 value = item.get('value') 929 selected_to_fit = (item.get('selected_to_fit') == "True") 930 error_displayed = (item.get('error_displayed') == "True") 931 error_value = item.get('error_value') 932 minimum_displayed = (item.get('minimum_displayed') == "True") 933 minimum_value = item.get('minimum_value') 934 maximum_displayed = (item.get('maximum_displayed') == "True") 935 maximum_value = item.get('maximum_value') 936 unit = item.get('unit') 1003 937 list.append([selected_to_fit, name, value, "+/-", 1004 938 [error_displayed, error_value], … … 1030 964 # Get file name 1031 965 entry = get_content('ns:filename', node) 1032 if entry is not None :966 if entry is not None and entry.text: 1033 967 self.file = entry.text.strip() 968 else: 969 self.file = '' 1034 970 1035 971 # Get time stamp … … 1038 974 try: 1039 975 self.timestamp = float(entry.get('epoch')) 1040 except :976 except Exception: 1041 977 msg = "PageState.fromXML: Could not" 1042 978 msg += " read timestamp\n %s" % sys.exc_value … … 1066 1002 list=getattr(self, item[1])) 1067 1003 1068 # Recover _disp_obj_dict from xml file1069 self. _disp_obj_dict = {}1004 # Recover disp_obj_dict from xml file 1005 self.disp_obj_dict = {} 1070 1006 for tagname, varname, tagtype in DISPERSION_LIST: 1071 1007 node = get_content("ns:%s" % tagname, entry) … … 1081 1017 except Exception: 1082 1018 base = "unable to load distribution %r for %s" 1083 logger.error(base % (value, parameter))1019 logger.error(base, value, parameter) 1084 1020 continue 1085 _disp_obj_dict = getattr(self, varname)1086 _disp_obj_dict[parameter] = value1021 disp_obj_dict = getattr(self, varname) 1022 disp_obj_dict[parameter] = value 1087 1023 1088 1024 # get self.values and self.weights dic. if exists … … 1107 1043 setattr(self, varname, dic) 1108 1044 1109 def set_plot_state(self, figs, canvases): 1110 """ 1111 Build image state that wx.html understand 1112 by plotting, putting it into wx.FileSystem image object 1113 1114 """ 1115 images = [] 1116 1117 # Reset memory 1118 self.imgRAM = None 1119 wx.MemoryFSHandler() 1120 1121 # For no figures in the list, prepare empty plot 1122 if figs is None or len(figs) == 0: 1123 figs = [None] 1124 1125 # Loop over the list of figures 1126 # use wx.MemoryFSHandler 1127 self.imgRAM = wx.MemoryFSHandler() 1128 for fig in figs: 1129 if fig is not None: 1130 ind = figs.index(fig) 1131 canvas = canvases[ind] 1132 1133 # store the image in wx.FileSystem Object 1134 wx.FileSystem.AddHandler(wx.MemoryFSHandler()) 1135 1136 # index of the fig 1137 ind = figs.index(fig) 1138 1139 # AddFile, image can be retrieved with 'memory:filename' 1140 self.imgRAM.AddFile('img_fit%s.png' % ind, 1141 canvas.bitmap, wx.BITMAP_TYPE_PNG) 1142 1143 # append figs 1144 images.append(fig) 1145 1146 return images 1147 1045 class SimFitPageState(object): 1046 """ 1047 State of the simultaneous fit page for saving purposes 1048 """ 1049 1050 def __init__(self): 1051 # Sim Fit Page Number 1052 self.fit_page_no = None 1053 # Select all data 1054 self.select_all = False 1055 # Data sets sent to fit page 1056 self.model_list = [] 1057 # Data sets to be fit 1058 self.model_to_fit = [] 1059 # Number of constraints 1060 self.no_constraint = 0 1061 # Dictionary of constraints 1062 self.constraint_dict = {} 1063 # List of constraints 1064 self.constraints_list = [] 1065 1066 def __repr__(self): 1067 # TODO: should use __str__, not __repr__ (similarly for PageState) 1068 # TODO: could use a nicer representation 1069 repr = """\ 1070 fit page number : %(fit_page_no)s 1071 select all : %(select_all)s 1072 model_list : %(model_list)s 1073 model to fit : %(model_to_fit)s 1074 number of construsts : %(no_constraint)s 1075 constraint dict : %(constraint_dict)s 1076 constraints list : %(constraints_list)s 1077 """%self.__dict__ 1078 return repr 1148 1079 1149 1080 class Reader(CansasReader): … … 1204 1135 try: 1205 1136 nodes = entry.xpath('ns:%s' % FITTING_NODE_NAME, 1206 namespaces= {'ns': CANSAS_NS})1137 namespaces=CANSAS_NS) 1207 1138 if nodes: 1208 1139 # Create an empty state … … 1210 1141 state.from_xml(node=nodes[0]) 1211 1142 1212 except :1143 except Exception: 1213 1144 logger.info("XML document does not contain fitting information.\n" 1214 1145 + traceback.format_exc()) 1215 1146 1216 1147 return state … … 1223 1154 """ 1224 1155 nodes = entry.xpath('ns:%s' % FITTING_NODE_NAME, 1225 namespaces= {'ns': CANSAS_NS})1156 namespaces=CANSAS_NS) 1226 1157 if nodes: 1227 1158 simfitstate = nodes[0].xpath('ns:simultaneous_fit', 1228 namespaces= {'ns': CANSAS_NS})1159 namespaces=CANSAS_NS) 1229 1160 if simfitstate: 1230 from simfitpage import SimFitPageState1231 1161 sim_fit_state = SimFitPageState() 1232 1162 simfitstate_0 = simfitstate[0] 1233 1163 all = simfitstate_0.xpath('ns:select_all', 1234 namespaces= {'ns': CANSAS_NS})1164 namespaces=CANSAS_NS) 1235 1165 atts = all[0].attrib 1236 1166 checked = atts.get('checked') 1237 1167 sim_fit_state.select_all = bool(checked) 1238 1168 model_list = simfitstate_0.xpath('ns:model_list', 1239 namespaces= {'ns': CANSAS_NS})1169 namespaces=CANSAS_NS) 1240 1170 model_list_items = model_list[0].xpath('ns:model_list_item', 1241 namespaces={'ns': 1242 CANSAS_NS}) 1171 namespaces=CANSAS_NS) 1243 1172 for model in model_list_items: 1244 1173 attrs = model.attrib … … 1246 1175 1247 1176 constraints = simfitstate_0.xpath('ns:constraints', 1248 namespaces={'ns': CANSAS_NS})1177 namespaces=CANSAS_NS) 1249 1178 constraint_list = constraints[0].xpath('ns:constraint', 1250 namespaces={'ns': CANSAS_NS})1179 namespaces=CANSAS_NS) 1251 1180 for constraint in constraint_list: 1252 1181 attrs = constraint.attrib … … 1266 1195 1267 1196 """ 1268 node = dom.xpath('ns:data_class', namespaces= {'ns': CANSAS_NS})1197 node = dom.xpath('ns:data_class', namespaces=CANSAS_NS) 1269 1198 return_value, _ = self._parse_entry(dom) 1270 1199 return return_value, _ … … 1295 1224 root = tree.getroot() 1296 1225 entry_list = root.xpath('ns:SASentry', 1297 namespaces= {'ns': CANSAS_NS})1226 namespaces=CANSAS_NS) 1298 1227 for entry in entry_list: 1299 1228 try: … … 1319 1248 return None 1320 1249 else: 1321 for ind in range(len(output)):1250 for data in output: 1322 1251 # Call back to post the new state 1323 state = output[ind].meta_data['fitstate']1252 state = data.meta_data['fitstate'] 1324 1253 t = time.localtime(state.timestamp) 1325 1254 time_str = time.strftime("%b %d %H:%M", t) … … 1332 1261 1333 1262 if state is not None and state.is_data is not None: 1334 output[ind].is_data = state.is_data1335 1336 output[ind].filename = state.file1337 state.data = output[ind]1338 state.data.name = output[ind].filename # state.data_name1263 data.is_data = state.is_data 1264 1265 data.filename = state.file 1266 state.data = data 1267 state.data.name = data.filename # state.data_name 1339 1268 state.data.id = state.data_id 1340 1269 if state.is_data is not None: 1341 1270 state.data.is_data = state.is_data 1342 if output[ind].run_name is not None\1343 and len(output[ind].run_name) != 0:1344 if isinstance(output[ind].run_name, dict):1345 name = output[ind].run_name.keys()[0]1271 if data.run_name is not None and len(data.run_name) != 0: 1272 if isinstance(data.run_name, dict): 1273 # Note: key order in dict is not guaranteed, so sort 1274 name = data.run_name.keys()[0] 1346 1275 else: 1347 name = output[ind].run_name1276 name = data.run_name 1348 1277 else: 1349 1278 name = original_fname … … 1351 1280 state.version = fitstate.version 1352 1281 # store state in fitting 1353 self.call_back(state=state, 1354 datainfo=output[ind], format=ext) 1282 self.call_back(state=state, datainfo=data, format=ext) 1355 1283 self.state = state 1356 1284 simfitstate = self._parse_simfit_state(entry) … … 1412 1340 return doc 1413 1341 1414 # Simple html report templ et1342 # Simple html report template 1415 1343 HEADER = "<html>\n" 1416 1344 HEADER += "<head>\n" … … 1440 1368 """ 1441 1369 FEET_2 = \ 1442 """ 1443 <img src="%s" > 1444 </img> 1370 """<img src="%s" ></img> 1445 1371 """ 1446 1372 FEET_3 = \ 1447 """ 1448 </center> 1373 """</center> 1449 1374 </div> 1450 1375 </body> 1451 1376 </html> 1452 1377 """ 1453 ELINE = "<p class=MsoNormal> </p>" 1378 ELINE = """<p class=MsoNormal> </p> 1379 """ -
src/sas/sascalc/fit/qsmearing.py
r8938502 r50fcb09 5 5 #This software was developed by the University of Tennessee as part of the 6 6 #Distributed Data Analysis of Neutron Scattering Experiments (DANSE) 7 #project funded by the US National Science Foundation. 7 #project funded by the US National Science Foundation. 8 8 #See the license text in license.txt 9 9 #copyright 2008, University of Tennessee … … 19 19 from sasmodels.sesans import SesansTransform 20 20 from sasmodels.resolution2d import Pinhole2D 21 from .nxsunit import Converter 21 22 from sas.sascalc.data_util.nxsunit import Converter 22 23 23 24 def smear_selection(data, model = None): -
src/sas/sascalc/pr/fit/AbstractFitEngine.py
ra1b8fee r50fcb09 137 137 that will smear the theory data (slit smearing or resolution 138 138 smearing) when set. 139 139 140 140 The proper way to set the smearing object would be to 141 141 do the following: :: 142 143 from sas.sascalc. data_util.qsmearing import smear_selection142 143 from sas.sascalc.fit.qsmearing import smear_selection 144 144 smearer = smear_selection(some_data) 145 145 fitdata1d = FitData1D( x= [1,3,..,], … … 147 147 dx=None, 148 148 dy=[1,2...], smearer= smearer) 149 149 150 150 :Note: that some_data _HAS_ to be of 151 151 class DataLoader.data_info.Data1D 152 152 Setting it back to None will turn smearing off. 153 153 154 154 """ 155 155 Data1D.__init__(self, x=x, y=y, dx=dx, dy=dy) … … 176 176 ## Max Q-value 177 177 self.qmax = max(self.x) 178 178 179 179 # Range used for input to smearing 180 180 self._qmin_unsmeared = self.qmin … … 184 184 self.idx_unsmeared = (self.x >= self._qmin_unsmeared) \ 185 185 & (self.x <= self._qmax_unsmeared) 186 186 187 187 def set_fit_range(self, qmin=None, qmax=None): 188 188 """ to set the fit range""" … … 199 199 self._qmin_unsmeared = self.qmin 200 200 self._qmax_unsmeared = self.qmax 201 201 202 202 self._first_unsmeared_bin = 0 203 203 self._last_unsmeared_bin = len(self.x) - 1 204 204 205 205 if self.smearer is not None: 206 206 self._first_unsmeared_bin, self._last_unsmeared_bin = \ … … 208 208 self._qmin_unsmeared = self.x[self._first_unsmeared_bin] 209 209 self._qmax_unsmeared = self.x[self._last_unsmeared_bin] 210 210 211 211 # Identify the bin range for the unsmeared and smeared spaces 212 212 self.idx = (self.x >= self.qmin) & (self.x <= self.qmax) … … 231 231 """ 232 232 Compute residuals. 233 233 234 234 If self.smearer has been set, use if to smear 235 235 the data before computing chi squared. 236 236 237 237 :param fn: function that return model value 238 238 239 239 :return: residuals 240 240 """ … … 242 242 fx = np.zeros(len(self.x)) 243 243 fx[self.idx_unsmeared] = fn(self.x[self.idx_unsmeared]) 244 244 245 245 ## Smear theory data 246 246 if self.smearer is not None: … … 253 253 raise RuntimeError, msg 254 254 return (self.y[self.idx] - fx[self.idx]) / self.dy[self.idx], fx[self.idx] 255 255 256 256 def residuals_deriv(self, model, pars=[]): 257 257 """ 258 258 :return: residuals derivatives . 259 260 :note: in this case just return empty array 259 260 :note: in this case just return empty array 261 261 """ 262 262 return [] … … 293 293 x_max = max(math.fabs(sas_data2d.xmin), math.fabs(sas_data2d.xmax)) 294 294 y_max = max(math.fabs(sas_data2d.ymin), math.fabs(sas_data2d.ymax)) 295 295 296 296 ## fitting range 297 297 if qmin is None: … … 305 305 self.res_err_data = copy.deepcopy(self.err_data) 306 306 #self.res_err_data[self.res_err_data==0]=1 307 307 308 308 self.radius = np.sqrt(self.qx_data**2 + self.qy_data**2) 309 309 310 310 # Note: mask = True: for MASK while mask = False for NOT to mask 311 311 self.idx = ((self.qmin <= self.radius) &\ … … 371 371 372 372 return res, gn 373 373 374 374 def residuals_deriv(self, model, pars=[]): 375 375 """ 376 376 :return: residuals derivatives . 377 377 378 378 :note: in this case just return empty array 379 379 380 380 """ 381 381 return [] 382 383 382 383 384 384 class FitAbort(Exception): 385 385 """ … … 399 399 self.fit_arrange_dict = {} 400 400 self.fitter_id = None 401 401 402 402 def set_model(self, model, id, pars=[], constraints=[], data=None): 403 403 """ 404 404 set a model on a given in the fit engine. 405 406 :param model: sas.models type 405 406 :param model: sas.models type 407 407 :param id: is the key of the fitArrange dictionary where model is saved as a value 408 :param pars: the list of parameters to fit 409 :param constraints: list of 408 :param pars: the list of parameters to fit 409 :param constraints: list of 410 410 tuple (name of parameter, value of parameters) 411 411 the value of parameter must be a string to constraint 2 different 412 412 parameters. 413 Example: 413 Example: 414 414 we want to fit 2 model M1 and M2 both have parameters A and B. 415 415 constraints can be ``constraints = [(M1.A, M2.B+2), (M1.B= M2.A *5),...,]`` 416 417 416 417 418 418 :note: pars must contains only name of existing model's parameters 419 419 420 420 """ 421 421 if not pars: … … 448 448 in a FitArrange object and adds that object in a dictionary 449 449 with key id. 450 450 451 451 :param data: data added 452 452 :param id: unique key corresponding to a fitArrange object with data … … 459 459 dx=data.dx, dy=data.dy, smearer=smearer) 460 460 fitdata.sas_data = data 461 461 462 462 fitdata.set_fit_range(qmin=qmin, qmax=qmax) 463 463 #A fitArrange is already created but contains model only at id … … 469 469 fitproblem.add_data(fitdata) 470 470 self.fit_arrange_dict[id] = fitproblem 471 471 472 472 def get_model(self, id): 473 473 """ 474 474 :param id: id is key in the dictionary containing the model to return 475 475 476 476 :return: a model at this id or None if no FitArrange element was 477 477 created with this id … … 481 481 else: 482 482 return None 483 483 484 484 def remove_fit_problem(self, id): 485 485 """remove fitarrange in id""" 486 486 if id in self.fit_arrange_dict: 487 487 del self.fit_arrange_dict[id] 488 488 489 489 def select_problem_for_fit(self, id, value): 490 490 """ 491 491 select a couple of model and data at the id position in dictionary 492 492 and set in self.selected value to value 493 493 494 494 :param value: the value to allow fitting. 495 495 can only have the value one or zero … … 497 497 if id in self.fit_arrange_dict: 498 498 self.fit_arrange_dict[id].set_to_fit(value) 499 499 500 500 def get_problem_to_fit(self, id): 501 501 """ 502 502 return the self.selected value of the fit problem of id 503 503 504 504 :param id: the id of the problem 505 505 """ 506 506 if id in self.fit_arrange_dict: 507 507 self.fit_arrange_dict[id].get_to_fit() 508 509 508 509 510 510 class FitArrange: 511 511 def __init__(self): … … 514 514 to perform the Fit.FitArrange must contain exactly one model 515 515 and at least one data for the fit to be performed. 516 516 517 517 model: the model selected by the user 518 518 Ldata: a list of data what the user wants to fit 519 519 520 520 """ 521 521 self.model = None … … 528 528 """ 529 529 set_model save a copy of the model 530 530 531 531 :param model: the model being set 532 532 """ 533 533 self.model = model 534 534 535 535 def add_data(self, data): 536 536 """ 537 537 add_data fill a self.data_list with data to fit 538 538 539 539 :param data: Data to add in the list 540 540 """ 541 541 if not data in self.data_list: 542 542 self.data_list.append(data) 543 543 544 544 def get_model(self): 545 545 """ … … 547 547 """ 548 548 return self.model 549 549 550 550 def get_data(self): 551 551 """ … … 553 553 """ 554 554 return self.data_list[0] 555 555 556 556 def remove_data(self, data): 557 557 """ 558 558 Remove one element from the list 559 559 560 560 :param data: Data to remove from data_list 561 561 """ 562 562 if data in self.data_list: 563 563 self.data_list.remove(data) 564 564 565 565 def set_to_fit(self, value=0): 566 566 """ 567 567 set self.selected to 0 or 1 for other values raise an exception 568 568 569 569 :param value: integer between 0 or 1 570 570 """ 571 571 self.selected = value 572 572 573 573 def get_to_fit(self): 574 574 """ … … 602 602 if self.model is not None and self.data is not None: 603 603 self.inputs = [(self.model, self.data)] 604 604 605 605 def set_model(self, model): 606 606 """ 607 607 """ 608 608 self.model = model 609 609 610 610 def set_fitness(self, fitness): 611 611 """ 612 612 """ 613 613 self.fitness = fitness 614 614 615 615 def __str__(self): 616 616 """ … … 627 627 msg = [msg1, msg3] + msg2 628 628 return "\n".join(msg) 629 629 630 630 def print_summary(self): 631 631 """ -
src/sas/sascalc/realspace/VolumeCanvas.py
r235f514 r98e3f24 4 4 Simulation canvas for real-space simulation of SAS scattering intensity. 5 5 The user can create an arrangement of basic shapes and estimate I(q) and 6 I(q_x, q_y). Error estimates on the simulation are also available. 7 6 I(q_x, q_y). Error estimates on the simulation are also available. 7 8 8 Example: 9 9 10 10 import sas.sascalc.realspace.VolumeCanvas as VolumeCanvas 11 11 canvas = VolumeCanvas.VolumeCanvas() 12 12 canvas.setParam('lores_density', 0.01) 13 13 14 14 sphere = SphereDescriptor() 15 15 handle = canvas.addObject(sphere) … … 17 17 output, error = canvas.getIqError(q=0.1) 18 18 output, error = canvas.getIq2DError(0.1, 0.1) 19 19 20 20 or alternatively: 21 21 iq = canvas.run(0.1) 22 22 i2_2D = canvas.run([0.1, 1.57]) 23 23 24 24 """ 25 25 26 from sas. models.BaseComponent import BaseComponent26 from sas.sascalc.calculator.BaseComponent import BaseComponent 27 27 from sas.sascalc.simulation.pointsmodelpy import pointsmodelpy 28 28 from sas.sascalc.simulation.geoshapespy import geoshapespy … … 31 31 import os.path, math 32 32 33 class ShapeDescriptor :33 class ShapeDescriptor(object): 34 34 """ 35 35 Class to hold the information about a shape 36 36 The descriptor holds a dictionary of parameters. 37 37 38 38 Note: if shape parameters are accessed directly 39 39 from outside VolumeCanvas. The getPr method 40 40 should be called before evaluating I(q). 41 41 42 42 """ 43 43 def __init__(self): … … 55 55 self.params['is_lores'] = True 56 56 self.params['order'] = 0 57 57 58 58 def create(self): 59 59 """ … … 65 65 z0 = self.params["center"][2] 66 66 geoshapespy.set_center(self.shapeObject, x0, y0, z0) 67 67 68 68 # Set orientation 69 69 x0 = self.params["orientation"][0] … … 71 71 z0 = self.params["orientation"][2] 72 72 geoshapespy.set_orientation(self.shapeObject, x0, y0, z0) 73 73 74 74 class SphereDescriptor(ShapeDescriptor): 75 75 """ 76 76 Descriptor for a sphere 77 77 78 78 The parameters are: 79 79 - radius [Angstroem] [default = 20 A] 80 80 - Contrast [A-2] [default = 1 A-2] 81 81 82 82 """ 83 83 def __init__(self): 84 84 """ 85 85 Initialization 86 """ 86 """ 87 87 ShapeDescriptor.__init__(self) 88 88 # Default parameters 89 self.params["type"] 89 self.params["type"] = "sphere" 90 90 # Radius of the sphere 91 91 self.params["radius"] = 20.0 … … 100 100 self.shapeObject = geoshapespy.new_sphere(\ 101 101 self.params["radius"]) 102 103 ShapeDescriptor.create(self) 102 103 ShapeDescriptor.create(self) 104 104 return self.shapeObject 105 105 106 106 class CylinderDescriptor(ShapeDescriptor): 107 107 """ 108 108 Descriptor for a cylinder 109 109 Orientation: Default cylinder is along Y 110 110 111 111 Parameters: 112 112 - Length [default = 40 A] … … 117 117 """ 118 118 Initialization 119 """ 119 """ 120 120 ShapeDescriptor.__init__(self) 121 121 # Default parameters 122 self.params["type"] 122 self.params["type"] = "cylinder" 123 123 # Length of the cylinder 124 124 self.params["length"] = 40.0 … … 127 127 # Constrast parameter 128 128 self.params["contrast"] = 1.0 129 129 130 130 def create(self): 131 131 """ … … 138 138 ShapeDescriptor.create(self) 139 139 return self.shapeObject 140 140 141 141 142 142 class EllipsoidDescriptor(ShapeDescriptor): 143 143 """ 144 144 Descriptor for an ellipsoid 145 145 146 146 Parameters: 147 147 - Radius_x along the x-axis [default = 30 A] … … 153 153 """ 154 154 Initialization 155 """ 155 """ 156 156 ShapeDescriptor.__init__(self) 157 157 # Default parameters 158 self.params["type"] 158 self.params["type"] = "ellipsoid" 159 159 self.params["radius_x"] = 30.0 160 160 self.params["radius_y"] = 20.0 161 161 self.params["radius_z"] = 10.0 162 162 self.params["contrast"] = 1.0 163 163 164 164 def create(self): 165 165 """ … … 168 168 """ 169 169 self.shapeObject = geoshapespy.new_ellipsoid(\ 170 self.params["radius_x"], self.params["radius_y"], 170 self.params["radius_x"], self.params["radius_y"], 171 171 self.params["radius_z"]) 172 173 ShapeDescriptor.create(self) 172 173 ShapeDescriptor.create(self) 174 174 return self.shapeObject 175 175 176 176 class HelixDescriptor(ShapeDescriptor): 177 177 """ 178 178 Descriptor for an helix 179 179 180 180 Parameters: 181 181 -radius_helix: the radius of the helix [default = 10 A] … … 188 188 """ 189 189 Initialization 190 """ 190 """ 191 191 ShapeDescriptor.__init__(self) 192 192 # Default parameters 193 self.params["type"] 193 self.params["type"] = "singlehelix" 194 194 self.params["radius_helix"] = 10.0 195 195 self.params["radius_tube"] = 3.0 … … 204 204 """ 205 205 self.shapeObject = geoshapespy.new_singlehelix(\ 206 self.params["radius_helix"], self.params["radius_tube"], 206 self.params["radius_helix"], self.params["radius_tube"], 207 207 self.params["pitch"], self.params["turns"]) 208 209 ShapeDescriptor.create(self) 208 209 ShapeDescriptor.create(self) 210 210 return self.shapeObject 211 211 212 212 class PDBDescriptor(ShapeDescriptor): 213 213 """ 214 214 Descriptor for a PDB set of points 215 215 216 216 Parameter: 217 217 - file = name of the PDB file … … 221 221 Initialization 222 222 @param filename: name of the PDB file to load 223 """ 223 """ 224 224 ShapeDescriptor.__init__(self) 225 225 # Default parameters 226 self.params["type"] 226 self.params["type"] = "pdb" 227 227 self.params["file"] = filename 228 228 self.params['is_lores'] = False … … 234 234 """ 235 235 self.shapeObject = pointsmodelpy.new_pdbmodel() 236 pointsmodelpy.pdbmodel_add(self.shapeObject, self.params['file']) 237 238 #ShapeDescriptor.create(self) 236 pointsmodelpy.pdbmodel_add(self.shapeObject, self.params['file']) 237 238 #ShapeDescriptor.create(self) 239 239 return self.shapeObject 240 240 241 241 # Define a dictionary for the shape until we find 242 242 # a better way to create them … … 245 245 'ellipsoid':EllipsoidDescriptor, 246 246 'singlehelix':HelixDescriptor} 247 247 248 248 class VolumeCanvas(BaseComponent): 249 249 """ 250 Class representing an empty space volume to add 250 Class representing an empty space volume to add 251 251 geometrical object to. 252 252 253 253 For 1D I(q) simulation, getPr() is called internally for the 254 254 first call to getIq(). 255 256 """ 257 255 256 """ 257 258 258 def __init__(self): 259 259 """ … … 261 261 """ 262 262 BaseComponent.__init__(self) 263 263 264 264 ## Maximum value of q reachable 265 265 self.params['q_max'] = 0.1 … … 267 267 self.params['scale'] = 1.0 268 268 self.params['background'] = 0.0 269 269 270 270 self.lores_model = pointsmodelpy.new_loresmodel(self.params['lores_density']) 271 271 self.complex_model = pointsmodelpy.new_complexmodel() 272 272 self.shapes = {} 273 self.shapecount = 0 273 self.shapecount = 0 274 274 self.points = None 275 275 self.npts = 0 276 self.hasPr = False 277 276 self.hasPr = False 277 278 278 def _model_changed(self): 279 279 """ 280 Reset internal data members to reflect the fact that the 280 Reset internal data members to reflect the fact that the 281 281 real-space model has changed 282 282 """ 283 self.hasPr 283 self.hasPr = False 284 284 self.points = None 285 286 def addObject(self, shapeDesc, id =None):285 286 def addObject(self, shapeDesc, id=None): 287 287 """ 288 288 Adds a real-space object to the canvas. 289 289 290 290 @param shapeDesc: object to add to the canvas [ShapeDescriptor] 291 291 @param id: string handle for the object [string] [optional] … … 295 295 if id is None: 296 296 id = shapeDesc.params["type"]+str(self.shapecount) 297 297 298 298 # Self the order number 299 299 shapeDesc.params['order'] = self.shapecount … … 307 307 308 308 return id 309 310 311 def add(self, shape, id =None):309 310 311 def add(self, shape, id=None): 312 312 """ 313 313 The intend of this method is to eventually be able to use it … … 315 315 analytical solutions. For instance, if one adds a cylinder and 316 316 it is the only shape on the canvas, the analytical solution 317 could be called. If multiple shapes are involved, then 317 could be called. If multiple shapes are involved, then 318 318 simulation has to be performed. 319 319 320 320 This function is deprecated, use addObject(). 321 321 322 322 @param shape: name of the object to add to the canvas [string] 323 323 @param id: string handle for the object [string] [optional] … … 327 327 if id is None: 328 328 id = "shape"+str(self.shapecount) 329 329 330 330 # shapeDesc = ShapeDescriptor(shape.lower()) 331 331 if shape.lower() in shape_dict: … … 336 336 else: 337 337 raise ValueError("VolumeCanvas.add: Unknown shape %s" % shape) 338 338 339 339 return self.addObject(shapeDesc, id) 340 340 … … 354 354 355 355 356 def setParam(self, name, value): 357 """ 358 Function to set the value of a parameter. 356 def setParam(self, name, value): 357 """ 358 Function to set the value of a parameter. 359 359 Both VolumeCanvas parameters and shape parameters 360 are accessible. 361 360 are accessible. 361 362 362 Note: if shape parameters are accessed directly 363 363 from outside VolumeCanvas. The getPr method 364 364 should be called before evaluating I(q). 365 365 366 366 TODO: implemented a check method to protect 367 367 against that. 368 368 369 369 @param name: name of the parameter to change 370 370 @param value: value to give the parameter 371 371 """ 372 372 373 373 # Lowercase for case insensitivity 374 374 name = name.lower() 375 375 376 376 # Look for shape access 377 377 toks = name.split('.') 378 378 379 379 # If a shape identifier was given, look the shape up 380 380 # in the dictionary … … 390 390 else: 391 391 raise ValueError("Could not find shape %s" % toks[0]) 392 392 393 393 else: 394 # If we are not accessing the parameters of a 394 # If we are not accessing the parameters of a 395 395 # shape, see if the parameter is part of this object 396 396 BaseComponent.setParam(self, name, value) 397 397 self._model_changed() 398 398 399 def getParam(self, name): 399 def getParam(self, name): 400 400 """ 401 401 @param name: name of the parameter to change 402 402 """ 403 403 #TODO: clean this up 404 404 405 405 # Lowercase for case insensitivity 406 406 name = name.lower() 407 407 408 408 # Look for sub-model access 409 409 toks = name.split('.') … … 435 435 else: 436 436 raise ValueError("VolumeCanvas.getParam: Could not find %s" % name) 437 437 438 438 def getParamList(self, shapeid=None): 439 439 """ 440 return a full list of all available parameters from 440 return a full list of all available parameters from 441 441 self.params.keys(). If a key in self.params is a instance 442 of ShapeDescriptor, extend the return list to: 442 of ShapeDescriptor, extend the return list to: 443 443 [param1,param2,shapeid.param1,shapeid.param2.......] 444 444 … … 456 456 header = key2 + '.' 457 457 for key3 in value2.params: 458 fullname = header + key3 458 fullname = header + key3 459 459 param_list.append(fullname) 460 460 461 461 else: 462 462 if not shapeid in self.shapes: … … 470 470 def getShapeList(self): 471 471 """ 472 Return a list of the shapes 472 Return a list of the shapes 473 473 """ 474 474 return self.shapes.keys() … … 481 481 # Create the object model 482 482 shapeDesc.create() 483 483 484 484 if shapeDesc.params['is_lores']: 485 485 # Add the shape to the lores_model 486 pointsmodelpy.lores_add(self.lores_model, 487 shapeDesc.shapeObject, shapeDesc.params['contrast']) 486 pointsmodelpy.lores_add(self.lores_model, 487 shapeDesc.shapeObject, 488 shapeDesc.params['contrast']) 488 489 489 490 def _createVolumeFromList(self): … … 492 493 Whenever we change a parameter of a shape, we have to re-create 493 494 the whole thing. 494 495 495 496 Items with higher 'order' number take precedence for regions 496 of space that are shared with other objects. Points in the 497 of space that are shared with other objects. Points in the 497 498 overlapping region belonging to objects with lower 'order' 498 499 will be ignored. 499 500 500 501 Items are added in decreasing 'order' number. 501 502 The item with the highest 'order' will be added *first*. 502 503 [That conventions is prescribed by the realSpaceModeling module] 503 504 """ 504 505 505 506 # Create empty model 506 507 self.lores_model = \ … … 509 510 # Create empty complex model 510 511 self.complex_model = pointsmodelpy.new_complexmodel() 511 512 512 513 # Order the object first 513 514 obj_list = [] 514 515 515 516 for shape in self.shapes: 516 517 order = self.shapes[shape].params['order'] 517 518 # find where to place it in the list 518 519 stored = False 519 520 520 521 for i in range(len(obj_list)): 521 522 if obj_list[i][0] > order: … … 523 524 stored = True 524 525 break 525 526 526 527 if not stored: 527 528 obj_list.append([order, shape]) 528 529 529 530 # Add each shape 530 531 len_list = len(obj_list) … … 533 534 self._addSingleShape(shapedesc) 534 535 535 return 0 536 536 return 0 537 537 538 def getPr(self): 538 539 """ … … 540 541 This method should always be called after the shapes 541 542 on the VolumeCanvas have changed. 542 543 @return: calculation output flag 543 544 @return: calculation output flag 544 545 """ 545 546 # To find a complete example of the correct call order: 546 547 # In LORES2, in actionclass.py, method CalculateAction._get_iq() 547 548 548 549 # If there are not shapes, do nothing 549 550 if len(self.shapes) == 0: 550 551 self._model_changed() 551 552 return 0 552 553 553 554 # generate space filling points from shape list 554 555 self._createVolumeFromList() … … 556 557 self.points = pointsmodelpy.new_point3dvec() 557 558 558 pointsmodelpy.complexmodel_add(self.complex_model, 559 559 pointsmodelpy.complexmodel_add(self.complex_model, 560 self.lores_model, "LORES") 560 561 for shape in self.shapes: 561 if self.shapes[shape].params['is_lores'] == False:562 pointsmodelpy.complexmodel_add(self.complex_model, 562 if not self.shapes[shape].params['is_lores']: 563 pointsmodelpy.complexmodel_add(self.complex_model, 563 564 self.shapes[shape].shapeObject, "PDB") 564 565 565 566 #pointsmodelpy.get_lorespoints(self.lores_model, self.points) 566 567 self.npts = pointsmodelpy.get_complexpoints(self.complex_model, self.points) 567 568 568 569 # expecting the rmax is a positive float or 0. The maximum distance. 569 #rmax = pointsmodelpy.get_lores_pr(self.lores_model, self.points) 570 571 rmax = pointsmodelpy.get_complex_pr(self.complex_model, self.points) 572 self.hasPr = True 570 #rmax = pointsmodelpy.get_lores_pr(self.lores_model, self.points) 571 572 rmax = pointsmodelpy.get_complex_pr(self.complex_model, self.points) 573 self.hasPr = True 573 574 574 575 return rmax 575 576 def run(self, q =0):576 577 def run(self, q=0): 577 578 """ 578 579 Returns the value of I(q) for a given q-value … … 595 596 else: 596 597 raise ValueError("run(q): bad type for q") 597 598 def runXY(self, q =0):598 599 def runXY(self, q=0): 599 600 """ 600 601 Standard run command for the canvas. 601 Redirects to the correct method 602 Redirects to the correct method 602 603 according to the input type. 603 604 @param q: q-value [float] or [list] [A-1] … … 615 616 else: 616 617 raise ValueError("runXY(q): bad type for q") 617 618 618 619 def _create_modelObject(self): 619 620 """ 620 621 Create the simulation model obejct from the list 621 622 of shapes. 622 623 623 624 This method needs to be called each time a parameter 624 625 changes because of the way the underlying library 625 was (badly) written. It is impossible to change a 626 parameter, or remove a shape without having to 626 was (badly) written. It is impossible to change a 627 parameter, or remove a shape without having to 627 628 refill the space points. 628 629 629 630 TODO: improve that. 630 631 """ 631 632 # To find a complete example of the correct call order: 632 633 # In LORES2, in actionclass.py, method CalculateAction._get_iq() 633 634 634 635 # If there are not shapes, do nothing 635 636 if len(self.shapes) == 0: 636 637 self._model_changed() 637 638 return 0 638 639 639 640 # generate space filling points from shape list 640 641 self._createVolumeFromList() … … 642 643 self.points = pointsmodelpy.new_point3dvec() 643 644 644 pointsmodelpy.complexmodel_add(self.complex_model, 645 645 pointsmodelpy.complexmodel_add(self.complex_model, 646 self.lores_model, "LORES") 646 647 for shape in self.shapes: 647 if self.shapes[shape].params['is_lores'] == False:648 pointsmodelpy.complexmodel_add(self.complex_model, 648 if not self.shapes[shape].params['is_lores']: 649 pointsmodelpy.complexmodel_add(self.complex_model, 649 650 self.shapes[shape].shapeObject, "PDB") 650 651 651 652 #pointsmodelpy.get_lorespoints(self.lores_model, self.points) 652 653 self.npts = pointsmodelpy.get_complexpoints(self.complex_model, self.points) 653 654 654 655 655 656 def getIq2D(self, qx, qy): 656 657 """ … … 660 661 @return: I(q) [cm-1] 661 662 """ 662 663 663 664 # If this is the first simulation call, we need to generate the 664 665 # space points 665 666 if self.points is None: 666 667 self._create_modelObject() 667 668 668 669 # Protect against empty model 669 670 if self.points is None: 670 671 return 0 671 672 # Evalute I(q) 673 norm = 672 673 # Evalute I(q) 674 norm = 1.0e8/self.params['lores_density']*self.params['scale'] 674 675 return norm*pointsmodelpy.get_complex_iq_2D(self.complex_model, self.points, qx, qy)\ 675 676 + self.params['background'] 676 677 677 678 def write_pr(self, filename): 678 679 """ 679 680 Write P(r) to an output file 680 681 @param filename: file name for P(r) output 681 """ 682 if self.hasPr == False:682 """ 683 if not self.hasPr: 683 684 self.getPr() 684 685 685 686 pointsmodelpy.outputPR(self.complex_model, filename) 686 687 687 688 def getPrData(self): 688 689 """ 689 690 Write P(r) to an output file 690 691 @param filename: file name for P(r) output 691 """ 692 if self.hasPr == False:692 """ 693 if not self.hasPr: 693 694 self.getPr() 694 695 695 696 return pointsmodelpy.get_pr(self.complex_model) 696 697 697 698 def getIq(self, q): 698 699 """ 699 700 Returns the value of I(q) for a given q-value 700 701 701 702 This method should remain internal to the class 702 703 and the run() method should be used instead. 703 704 704 705 @param q: q-value [float] 705 706 @return: I(q) [float] 706 707 """ 707 708 if self.hasPr == False:708 709 if not self.hasPr: 709 710 self.getPr() 710 711 711 # By dividing by the density instead of the actuall V/N, 712 # we have an uncertainty of +-1 on N because the number 712 # By dividing by the density instead of the actuall V/N, 713 # we have an uncertainty of +-1 on N because the number 713 714 # of points chosen for the simulation is int(density*volume). 714 715 # Propagation of error gives: … … 716 717 # where N is stored in self.npts 717 718 718 norm = 719 norm = 1.0e8/self.params['lores_density']*self.params['scale'] 719 720 #return norm*pointsmodelpy.get_lores_i(self.lores_model, q) 720 721 return norm*pointsmodelpy.get_complex_i(self.complex_model, q)\ 721 722 + self.params['background'] 722 723 723 724 def getError(self, q): 724 725 """ … … 727 728 @return: I(q) [float] 728 729 """ 729 730 if self.hasPr == False:730 731 if not self.hasPr: 731 732 self.getPr() 732 733 733 # By dividing by the density instead of the actual V/N, 734 # we have an uncertainty of +-1 on N because the number 734 # By dividing by the density instead of the actual V/N, 735 # we have an uncertainty of +-1 on N because the number 735 736 # of points chosen for the simulation is int(density*volume). 736 737 # Propagation of error gives: … … 738 739 # where N is stored in self.npts 739 740 740 norm = 741 norm = 1.0e8/self.params['lores_density']*self.params['scale'] 741 742 #return norm*pointsmodelpy.get_lores_i(self.lores_model, q) 742 743 return norm*pointsmodelpy.get_complex_i_error(self.complex_model, q)\ 743 744 + self.params['background'] 744 745 745 746 def getIqError(self, q): 746 747 """ 747 748 Return the simulated value along with its estimated 748 749 error for a given q-value 749 750 750 751 Propagation of errors is used to evaluate the 751 752 uncertainty. 752 753 753 754 @param q: q-value [float] 754 755 @return: mean, error [float, float] … … 765 766 Return the simulated value along with its estimated 766 767 error for a given q-value 767 768 768 769 Propagation of errors is used to evaluate the 769 770 uncertainty. 770 771 771 772 @param qx: qx-value [float] 772 773 @param qy: qy-value [float] … … 774 775 """ 775 776 self._create_modelObject() 776 777 norm = 777 778 norm = 1.0e8/self.params['lores_density']*self.params['scale'] 778 779 val = norm*pointsmodelpy.get_complex_iq_2D(self.complex_model, self.points, qx, qy)\ 779 780 + self.params['background'] 780 781 781 782 # Simulation error (statistical) 782 norm = 783 783 norm = 1.0e8/self.params['lores_density']*self.params['scale'] \ 784 * math.pow(self.npts/self.params['lores_density'], 1.0/3.0)/self.npts 784 785 err = norm*pointsmodelpy.get_complex_iq_2D_err(self.complex_model, self.points, qx, qy) 785 786 # Error on V/N 786 787 simerr = 2*val/self.npts 787 788 788 789 # The error used for the position is over-simplified. 789 790 # The actual error was empirically found to be about 790 791 # an order of magnitude larger. 791 792 return val, 10.0*err+simerr 792
Note: See TracChangeset
for help on using the changeset viewer.