Changeset ef9ed58 in sasview
- Timestamp:
- Nov 30, 2009 7:10:39 PM (15 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, costrafo411, magnetic_scatt, release-4.1.1, release-4.1.2, release-4.2.2, release_4.0.1, ticket-1009, ticket-1094-headless, ticket-1242-2d-resolution, ticket-1243, ticket-1249, ticket885, unittest-saveload
- Children:
- c5607fa
- Parents:
- 2733188
- Location:
- Invariant
- Files:
-
- 2 added
- 1 deleted
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
Invariant/invariant.py
r2cce133 ref9ed58 5 5 6 6 import math 7 import numpy .linalg.lstsq7 import numpy 8 8 9 9 from DataLoader.data_info import Data1D as LoaderData1D 10 #from DataLoader.data_info import Data1D as LoaderData1D 10 11 from DataLoader.qsmearing import smear_selection 11 12 … … 20 21 INTEGRATION_NSTEPS = 1000 21 22 22 class FitFunctor:23 """24 compute f(x)25 """26 def __init__(self,data , function):27 """28 @param function :the function used for computing residuals29 @param Data: data used for computing residuals30 """31 self.function = function32 self.data = data33 x_len = len(self.data.x) -134 #fitting range35 self.qmin = self.data[0]36 if self.qmin == 0:37 self.qmin = Q_MINIMUM38 39 self.qmax = self.data[x_len]40 #Unsmeared q range41 self._qmin_unsmeared = 042 self._qmax_unsmeared = self.data[x_len]43 44 #bin for smear data45 self._first_unsmeared_bin = 046 self._last_unsmeared_bin = x_len47 48 # Identify the bin range for the unsmeared and smeared spaces49 self.idx = (self.x>=self.qmin) & (self.x <= self.qmax)50 self.idx_unsmeared = (self.x>=self._qmin_unsmeared) & (self.x <= self._qmax_unsmeared)51 52 #get the smear object of data53 self.smearer = smear_selection( self.data )54 self.func_name = "Residuals"55 56 def setFitRange(self):57 """ to set the fit range"""58 self.qmin = self.data[0]59 if self.qmin== 0:60 self.qmin= MINIMUM61 62 x_len= len(self.data.x) -163 self.qmax= self.data[x_len]64 65 # Determine the range needed in unsmeared-Q to cover66 # the smeared Q range67 self._qmin_unsmeared = self.qmin68 self._qmax_unsmeared = self.qmax69 70 self._first_unsmeared_bin = 071 self._last_unsmeared_bin = len(self.data.x)-172 73 if self.smearer!=None:74 self._first_unsmeared_bin, self._last_unsmeared_bin = self.smearer.get_bin_range(self.qmin, self.qmax)75 self._qmin_unsmeared = self.data.x[self._first_unsmeared_bin]76 self._qmax_unsmeared = self.data.x[self._last_unsmeared_bin]77 78 # Identify the bin range for the unsmeared and smeared spaces79 self.idx = (self.data.x>=self.qmin) & (self.data.x <= self.qmax)80 self.idx_unsmeared = (self.data.x>=self._qmin_unsmeared) & (self.data.x <= self._qmax_unsmeared)81 82 83 def _get_residuals(self, params):84 """85 Compute residuals86 @return res: numpy array of float of size.self.data.x87 """88 # Compute theory data f(x)89 fx = numpy.zeros(len(self.data.x))90 fx[self.idx_unsmeared] = self.funtion(self.data.x[self.idx_unsmeared])91 92 ## Smear theory data93 if self.smearer is not None:94 fx = self.smearer(fx, self._first_unsmeared_bin, self._last_unsmeared_bin)95 96 ## Sanity check97 if numpy.size(self.data.dy)!= numpy.size(fx):98 raise RuntimeError, "Residuals: invalid error array %d <> %d" % (numpy.shape(self.data.dy),99 numpy.size(fx))100 101 return (self.data.y[self.idx]-fx[self.idx])/self.data.dy[self.idx]102 103 104 def __call__(self,params):105 """106 Compute residuals107 @param params: value of parameters to fit108 """109 return self._get_residuals(params)110 111 112 23 def guinier(x, scale=1, radius=0.1): 113 24 """ 114 25 Compute a F(x) = scale* e-((radius*x)**2/3). 115 @param x: a vector of q values or one q value26 @param x: a vector of q values 116 27 @param scale: the scale value 117 28 @param radius: the guinier radius value 118 29 @return F(x) 119 """ 120 30 """ 31 value = numpy.array([math.exp(-((radius * i)**2/3)) for i in x ]) 32 return scale * value 33 121 34 def power_law(x, scale=1, power=4): 122 35 """ … … 125 38 else power_law 126 39 The model has three parameters: 40 @param x: a vector of q values 127 41 @param power: power of the function 128 42 @param scale : scale factor value 129 43 @param F(x) 130 """ 131 132 44 """ 45 value = numpy.array([ math.pow(i, -power) for i in x ]) 46 return scale * value 47 48 class FitFunctor: 49 """ 50 compute f(x) 51 """ 52 def __init__(self,data , function): 53 """ 54 @param function :the function used for computing residuals 55 @param Data: data used for computing residuals 56 """ 57 self.function = function 58 self.data = data 59 x_len = len(self.data.x) -1 60 #fitting range 61 self.qmin = self.data.x[0] 62 if self.qmin == 0: 63 self.qmin = Q_MINIMUM 64 65 self.qmax = self.data.x[x_len] 66 #Unsmeared q range 67 self._qmin_unsmeared = 0 68 self._qmax_unsmeared = self.data.x[x_len] 69 70 #bin for smear data 71 self._first_unsmeared_bin = 0 72 self._last_unsmeared_bin = x_len 73 74 # Identify the bin range for the unsmeared and smeared spaces 75 self.idx = (self.data.x >= self.qmin) & (self.data.x <= self.qmax) 76 self.idx_unsmeared = (self.data.x >= self._qmin_unsmeared) \ 77 & (self.data.x <= self._qmax_unsmeared) 78 79 #get the smear object of data 80 self.smearer = smear_selection( self.data ) 81 82 83 def set_fit_range(self ,qmin=None, qmax=None): 84 """ to set the fit range""" 85 if qmin is not None: 86 self.qmin = qmin 87 if qmax is not None: 88 self.qmax = qmax 89 90 # Determine the range needed in unsmeared-Q to cover 91 # the smeared Q range 92 self._qmin_unsmeared = self.qmin 93 self._qmax_unsmeared = self.qmax 94 95 self._first_unsmeared_bin = 0 96 self._last_unsmeared_bin = len(self.data.x)-1 97 98 if self.smearer!=None: 99 self._first_unsmeared_bin, self._last_unsmeared_bin = self.smearer.get_bin_range(self.qmin, self.qmax) 100 self._qmin_unsmeared = self.data.x[self._first_unsmeared_bin] 101 self._qmax_unsmeared = self.data.x[self._last_unsmeared_bin] 102 103 # Identify the bin range for the unsmeared and smeared spaces 104 self.idx = (self.data.x >= self.qmin) & (self.data.x <= self.qmax) 105 self.idx_unsmeared = (self.data.x >= self._qmin_unsmeared) \ 106 & (self.data.x <= self._qmax_unsmeared) 107 108 def fit(self): 109 """ 110 Fit data for y = ax + b return a and b 111 112 """ 113 fx = self.data.y 114 ## Smear theory data 115 if self.smearer is not None: 116 fx = self.smearer(fx, self._first_unsmeared_bin, 117 self._last_unsmeared_bin) 118 A = numpy.vstack([ self.data.x, numpy.ones(len(self.data.x))]).T 119 120 a, b = numpy.linalg.lstsq(A, fx)[0] 121 return a, b 122 133 123 class InvariantCalculator(object): 134 124 """ … … 141 131 @note: Some computations depends on each others. 142 132 """ 133 134 143 135 def __init__(self, data, background=0, scale=1 ): 144 136 """ … … 168 160 self._low_extrapolation_function = guinier 169 161 self._low_extrapolation_power = 4 170 162 171 163 self._high_extrapolation_npts = 4 172 164 self._high_extrapolation_function = power_law 173 165 self._high_extrapolation_power = 4 174 166 167 175 168 def set_extrapolation(self, range, npts=4, function=None, power=4): 176 169 """ 177 170 Set the extrapolation parameters for the high or low Q-range. 178 171 Note that this does not turn extrapolation on or off. 172 @param range: a keyword set the type of extrapolation . type string 173 @param npts: the numbers of q points of data to consider for extrapolation 174 @param function: a keyword to select the function to use for extrapolation. 175 of type string. 176 @param power: an power to apply power_low function 177 179 178 """ 180 179 range = range.lower() … … 185 184 raise ValueError, "Extrapolation function should be 'guinier' or 'power_law'" 186 185 187 if range =='high':186 if range == 'high': 188 187 if function != 'power_law': 189 188 raise ValueError, "Extrapolation only allows a power law at high Q" … … 207 206 #Process only data that inherited from DataLoader.Data_info.Data1D 208 207 raise ValueError,"Data must be of type DataLoader.Data1D" 209 210 211 def _fit(self, function, params=[]):208 return self._scale * data - self._background 209 210 def _fit(self, function, qmin=Q_MINIMUM, qmax=Q_MAXIMUM): 212 211 """ 213 212 fit data with function using … … 216 215 y = data.y 217 216 out, cov_x = linalg.lstsq(y,fx) 218 219 217 @param qmin: data first q value to consider during the fit 218 @param qmax: data last q value to consider during the fit 220 219 @param function: the function to use during the fit 221 @param params: the list of parameters values to use during the fit 222 223 """ 224 220 @return a: the scale of the function 221 @return b: the other parameter of the function for guinier will be radius 222 for power_law will be the power value 223 """ 224 if function.__name__ == "guinier": 225 fit_x = self._data.x * self._data.x 226 qmin = qmin**2 227 qmax = qmax**2 228 fit_y = [math.log(y) for y in self._data.y] 229 elif function.__name__ == "power_law": 230 fit_x = [math.log(x) for x in self._data.x] 231 qmin = math.log(qmin) 232 qmax = math.log(qmax) 233 fit_y = [math.log(y) for y in self._data.y] 234 else: 235 raise ValueError("Unknown function used to fit %s"%function.__name__) 236 237 fit_data = LoaderData1D(x=fit_x, y=fit_y) 238 fit_data.dxl = self._data.dxl 239 fit_data.dxw = self._data.dxw 240 241 functor = FitFunctor(data=fit_data, function= function) 242 functor.set_fit_range(qmin=qmin, qmax=qmax) 243 a, b = functor.fit() 244 245 if function.__name__ == "guinier": 246 # b is the radius value of the guinier function 247 print "b",b 248 b = math.sqrt(-3 * b) 249 250 # a is the scale of the guinier function 251 a = math.exp(a) 252 return a, math.fabs(b) 253 254 def _get_qstar(self, data): 255 """ 256 Compute invariant for data 257 @param data: data to use to compute invariant. 258 259 """ 260 if data is None: 261 return 0 262 if data.is_slit_smeared(): 263 return self._get_qstar_smear(data) 264 else: 265 return self._get_qstar_unsmear(data) 266 267 225 268 def get_qstar(self, extrapolation=None): 226 269 """ … … 231 274 else: 232 275 qstar_0 = self._get_qstar_unsmear() 233 276 if extrapolation is None: 277 return qstar_0 234 278 if extrapolation==low: 235 279 return qstar_0 + self._get_qstar_low() … … 238 282 elif extrapolation==both: 239 283 return qstar_0 + self._get_qstar_low() + self._get_qstar_high() 240 284 285 @param extrapolation: string to apply optional extrapolation 241 286 @return q_star: invariant of the data within data's q range 242 """ 243 244 245 def _get_qstar_unsmear(self): 287 288 @warning: When using setting data to Data1D , the user is responsible of 289 checking that the scale and the background are properly apply to the data 290 291 @warning: if error occur self._get_qstar_low() or self._get_qstar_low() 292 their returned value will be ignored 293 """ 294 qstar_0 = self._get_qstar(data=self._data) 295 296 if extrapolation is None: 297 self._qstar = qstar_0 298 return self._qstar 299 # Compute invariant plus invaraint of extrapolated data 300 extrapolation = extrapolation.lower() 301 if extrapolation == "low": 302 self._qstar = qstar_0 + self._get_qstar_low() 303 return self._qstar 304 elif extrapolation == "high": 305 self._qstar = qstar_0 + self._get_qstar_high() 306 return self._qstar 307 elif extrapolation == "both": 308 self._qstar = qstar_0 + self._get_qstar_low() + self._get_qstar_high() 309 return self._qstar 310 311 def _get_qstar_unsmear(self, data): 246 312 """ 247 313 Compute invariant for pinhole data. … … 255 321 dx0 = (x1 - x0)/2 256 322 dxn = xn - xn-1 257 258 @return q_star: invariant value for pinhole data. 259 """ 260 261 def _get_qstar_smear(self): 323 @param data: the data to use to compute invariant. 324 @return q_star: invariant value for pinhole data. q_star > 0 325 """ 326 if len(data.x) <= 1 or len(data.y) <= 1 or len(data.x)!= len(data.y): 327 msg = "Length x and y must be equal" 328 msg += " and greater than 1; got x=%s, y=%s"%(len(data.x), len(data.y)) 329 raise ValueError, msg 330 else: 331 n = len(data.x)- 1 332 #compute the first delta q 333 dx0 = (data.x[1] - data.x[0])/2 334 #compute the last delta q 335 dxn = data.x[n] - data.x[n-1] 336 sum = 0 337 sum += data.x[0] * data.x[0] * data.y[0] * dx0 338 sum += data.x[n] * data.x[n] * data.y[n] * dxn 339 340 if len(data.x) == 2: 341 return sum 342 else: 343 #iterate between for element different from the first and the last 344 for i in xrange(1, n-1): 345 dxi = (data.x[i+1] - data.x[i-1])/2 346 sum += data.x[i] * data.x[i] * data.y[i] * dxi 347 return sum 348 349 def _get_qstar_smear(self, data): 262 350 """ 263 351 Compute invariant for slit-smeared data. … … 273 361 @return q_star: invariant value for slit smeared data. 274 362 """ 275 276 def _get_qstar_unsmear_uncertainty(self): 363 if not data.is_slit_smeared(): 364 msg = "_get_qstar_smear need slit smear data " 365 msg += "Hint :dxl= %s , dxw= %s"%(str(data.dxl), str(data.dxw)) 366 raise ValueError, msg 367 368 if len(data.x) <= 1 or len(data.y) <= 1 or len(data.x) != len(data.y)\ 369 or len(data.x)!= len(data.dxl): 370 msg = "x, dxl, and y must be have the same length and greater than 1" 371 raise ValueError, msg 372 else: 373 n = len(data.x)-1 374 #compute the first delta 375 dx0 = (data.x[1] + data.x[0])/2 376 #compute the last delta 377 dxn = data.x[n] - data.x[n-1] 378 sum = 0 379 sum += data.x[0] * data.dxl[0] * data.y[0] * dx0 380 sum += data.x[n] * data.dxl[n] * data.y[n] * dxn 381 382 if len(data.x)==2: 383 return sum 384 else: 385 #iterate between for element different from the first and the last 386 for i in xrange(1, n-1): 387 dxi = (data.x[i+1] - data.x[i-1])/2 388 sum += data.x[i] * data.dxl[i] * data.y[i] * dxi 389 return sum 390 391 def _get_qstar_uncertainty(self, data=None): 392 """ 393 Compute uncertainty of invariant value 394 Implementation: 395 if data is None: 396 data = self.data 397 398 if data.slit smear: 399 return self._get_qstar_smear_uncertainty(data) 400 else: 401 return self._get_qstar_unsmear_uncertainty(data) 402 403 @param: data use to compute the invariant which allow uncertainty 404 computation. 405 @return: uncertainty 406 """ 407 if data is None: 408 data = self.data 409 410 if data.is_slit_smeared(): 411 return self._get_qstar_smear_uncertainty(data) 412 else: 413 return self._get_qstar_unsmear_uncertainty(data) 414 415 def _get_qstar_unsmear_uncertainty(self, data=None): 277 416 """ 278 417 Compute invariant uncertainty with with pinhole data. … … 285 424 dxn = xn - xn-1 286 425 dyn: error on dy 287 @param data: data of type Data1D where the scale is applied288 and the background is subtracted.426 427 @param data: 289 428 note: if data doesn't contain dy assume dy= math.sqrt(data.y) 290 429 """ 430 if data is None: 431 data = self.data 432 433 if len(data.x) <= 1 or len(data.y) <= 1 or \ 434 len(self.data.x) != len(self.data.y): 435 msg = "Length of data.x and data.y must be equal" 436 msg += " and greater than 1; got x=%s, y=%s"%(len(data.x), 437 len(data.y)) 438 raise ValueError, msg 439 else: 440 #Create error for data without dy error 441 if (data.dy is None) or (not data.dy): 442 dy = math.sqrt(y) 443 else: 444 dy = data.dy 445 446 n = len(data.x) - 1 447 #compute the first delta 448 dx0 = (data.x[1] - data.x[0])/2 449 #compute the last delta 450 dxn= data.x[n] - data.x[n-1] 451 sum = 0 452 sum += (data.x[0] * data.x[0] * dy[0] * dx0)**2 453 sum += (data.x[n] * data.x[n] * dy[n] * dxn)**2 454 if len(data.x) == 2: 455 return math.sqrt(sum) 456 else: 457 #iterate between for element different from the first and the last 458 for i in xrange(1, n-1): 459 dxi = (data.x[i+1] - data.x[i-1])/2 460 sum += (data.x[i] * data.x[i] * dy[i] * dxi)**2 461 return math.sqrt(sum) 291 462 292 463 def _get_qstar_smear_uncertainty(self): … … 307 478 note: if data doesn't contain dy assume dy= math.sqrt(data.y) 308 479 """ 480 if data is None: 481 data = self._data 482 483 if not data.is_slit_smeared(): 484 msg = "_get_qstar_smear_uncertainty need slit smear data " 485 msg += "Hint :dxl= %s , dxw= %s"%(str(data.dxl), str(data.dxw)) 486 raise ValueError, msg 487 488 if len(data.x) <= 1 or len(data.y) <= 1 or len(data.x) != len(data.y)\ 489 or len(data.x) != len(data.dxl): 490 msg = "x, dxl, and y must be have the same length and greater than 1" 491 raise ValueError, msg 492 else: 493 #Create error for data without dy error 494 if (data.dy is None) or (not data.dy): 495 dy = math.sqrt(y) 496 else: 497 dy = data.dy 498 499 n = len(data.x) - 1 500 #compute the first delta 501 dx0 = (data.x[1] - data.x[0])/2 502 #compute the last delta 503 dxn = data.x[n] - data.x[n-1] 504 sum = 0 505 sum += (data.x[0] * data.dxl[0] * dy[0] * dx0)**2 506 sum += (data.x[n] * data.dxl[n] * dy[n] * dxn)**2 507 508 if len(data.x) == 2: 509 return math.sqrt(sum) 510 else: 511 #iterate between for element different from the first and the last 512 for i in xrange(1, n-1): 513 dxi = (data.x[i+1] - data.x[i-1])/2 514 sum += (data.x[i] * data.dxl[i] * dy[i] * dxi)**2 515 return math.sqrt(sum) 309 516 310 517 def get_surface(self,contrast, porod_const): … … 322 529 @return: specific surface 323 530 """ 324 531 #Check whether we have Q star 532 if self._qstar is None: 533 self._qstar = self.get_star() 534 if self._qstar == 0: 535 raise RuntimeError("Cannot compute surface, invariant value is zero") 536 # Compute the volume 537 volume = self.get_volume_fraction(contrast) 538 return 2 * math.pi * volume *(1 - volume) * float(porod_const)/self._qstar 539 540 325 541 def get_volume_fraction(self, contrast): 326 542 """ … … 328 544 329 545 q_star = 2*(pi*contrast)**2* volume( 1- volume) 330 for k = 10^( 8)*q_star/(2*(pi*|contrast|)**2)546 for k = 10^(-8)*q_star/(2*(pi*|contrast|)**2) 331 547 we get 2 values of volume: 548 with 1 - 4 * k >= 0 332 549 volume1 = (1- sqrt(1- 4*k))/2 333 550 volume2 = (1+ sqrt(1- 4*k))/2 … … 335 552 q_star: the invariant value included extrapolation is applied 336 553 unit 1/A^(3)*1/cm 337 q_star = self. _qstar554 q_star = self.get_qstar() 338 555 339 556 the result returned will be 0<= volume <= 1 … … 344 561 @note: volume fraction must have no unit 345 562 """ 346 563 if contrast < 0: 564 raise ValueError, "contrast must be greater than zero" 565 566 if self._qstar is None: 567 self._qstar = self.get_qstar() 568 569 if self._qstar < 0: 570 raise RuntimeError, "invariant must be greater than zero" 571 572 print "self._qstar",self._qstar 573 # Compute intermediate constant 574 k = 1.e-8 * self._qstar/(2 * (math.pi * math.fabs(float(contrast)))**2) 575 #Check discriminant value 576 discrim = 1 - 4 * k 577 print "discrim",k,discrim 578 # Compute volume fraction 579 if discrim < 0: 580 raise RuntimeError, "could not compute the volume fraction: negative discriminant" 581 elif discrim ==0: 582 return 1/2 583 else: 584 volume1 = 0.5 *(1 - math.sqrt(discrim)) 585 volume2 = 0.5 *(1 + math.sqrt(discrim)) 586 587 if 0 <= volume1 and volume1 <= 1: 588 return volume1 589 elif 0 <= volume2 and volume2 <= 1: 590 return volume2 591 raise RuntimeError, "could not compute the volume fraction: inconsistent results" 592 347 593 def _get_qstar_low(self): 348 594 """ … … 355 601 @return q_star: the invariant for data extrapolated at low q. 356 602 """ 603 data = self._get_extra_data_low() 604 return self._get_qstar(data=data) 357 605 358 606 def _get_qstar_high(self): … … 366 614 @return q_star: the invariant for data extrapolated at high q. 367 615 """ 616 data = self._get_extra_data_high() 617 return self._get_qstar( data=data) 368 618 369 619 def _get_extra_data_low(self): … … 388 638 @return: a new data of type Data1D 389 639 """ 390 640 # Data boundaries for fiiting 641 qmin = self._data.x[0] 642 qmax = self._data.x[self._low_extrapolation_npts] 643 644 try: 645 # fit the data with a model to get the appropriate parameters 646 a, b = self._fit(function=self._low_extrapolation_function, 647 qmin=qmin, qmax=qmax) 648 except: 649 raise 650 return None 651 652 #create new Data1D to compute the invariant 653 new_x = numpy.linspace(start=Q_MINIMUM, 654 stop=qmin, 655 num=INTEGRATION_NSTEPS, 656 endpoint=True) 657 new_y = self._low_extrapolation_function(x=new_x, 658 scale=a, 659 radius=b) 660 dxl = None 661 dxw = None 662 if self._data.dxl is not None: 663 dxl = numpy.ones(1, INTEGRATION_NSTEPS) 664 dxl = dxl * self._data.dxl[0] 665 if self._data.dxw is not None: 666 dwl = numpy.ones(1, INTEGRATION_NSTEPS) 667 dwl = dwl * self._data.dwl[0] 668 669 data_min = LoaderData1D(x=new_x, y=new_y) 670 data_min.dxl = dxl 671 data_min.dxw = dxw 672 self._data.clone_without_data( clone= data_min) 673 674 return data_min 675 391 676 def _get_extra_data_high(self): 392 677 """ … … 403 688 @return: a new data of type Data1D 404 689 """ 405 406 def get_qstar_with_error(self): 690 # Data boundaries for fiiting 691 x_len = len(self._data.x) - 1 692 qmin = self._data.x[x_len - self._high_extrapolation_npts] 693 qmax = self._data.x[x_len] 694 695 try: 696 # fit the data with a model to get the appropriate parameters 697 a, b = self._fit(function=self._high_extrapolation_function, 698 qmin=qmin, qmax=qmax) 699 except: 700 raise 701 return None 702 703 #create new Data1D to compute the invariant 704 new_x = numpy.linspace(start=qmax, 705 stop=Q_MAXIMUM, 706 num=INTEGRATION_NSTEPS, 707 endpoint=True) 708 new_y = self._high_extrapolation_function(x=new_x, 709 scale=a, 710 power=b) 711 dxl = None 712 dxw = None 713 if self._data.dxl is not None: 714 dxl = numpy.ones(1, INTEGRATION_NSTEPS) 715 dxl = dxl * self._data.dxl[0] 716 if self._data.dxw is not None: 717 dwl = numpy.ones(1, INTEGRATION_NSTEPS) 718 dwl = dwl * self._data.dwl[0] 719 720 data_max = LoaderData1D(x=new_x, y=new_y) 721 data_max.dxl = dxl 722 data_max.dxw = dxw 723 self._data.clone_without_data( clone=data_max) 724 725 return data_max 726 727 def get_qstar_with_error(self, extrapolation=None): 407 728 """ 408 729 Compute the invariant uncertainty. 409 730 This uncertainty computation depends on whether or not the data is 410 731 smeared. 411 @return dq_star: 412 if slit smear: 413 return self._get_qstar(), self._get_qstar_smear_uncertainty() 414 else: 415 return self._get_qstar(), self._get_qstar_unsmear_uncertainty() 416 """ 417 732 @return: invariant, the invariant uncertainty 733 return self._get_qstar(), self._get_qstar_smear_uncertainty() 734 """ 735 if self._qstar is None: 736 self._qstar = self.get_qstar(extrapolation=extrapolation) 737 if self._qstar_err is None: 738 self._qstar_err = self._get_qstar_smear_uncertainty() 739 740 return self._qstar, self._qstar_err 741 418 742 def get_volume_fraction_with_error(self, contrast): 419 743 """ … … 430 754 @return: V, dV = self.get_volume_fraction_with_error(contrast), dV 431 755 """ 432 756 self._qstar, self._qstar_err = self.get_qstar_with_error() 757 758 volume = self.get_volume_fraction(contrast) 759 if self._qstar < 0: 760 raise ValueError, "invariant must be greater than zero" 761 762 k = 1.e-8 * self._qstar /(2*(math.pi* math.fabs(float(contrast)))**2) 763 #check value inside the sqrt function 764 value = 1 - k * self._qstar 765 if (1 - k * self._qstar) <= 0: 766 raise ValueError, "Cannot compute incertainty on volume" 767 # Compute uncertainty 768 uncertainty = (0.5 * 4 * k * self._qstar_err)/(2 * math.sqrt(1- k * self._qstar)) 769 770 return volume, math.fabs(uncertainty) 771 433 772 def get_surface_with_error(self, contrast, porod_const): 434 773 """ … … 448 787 @return S, dS: the surface, with its uncertainty 449 788 """ 450 451 789 v, dv = self.get_volume_fraction_with_error(contrast) 790 self._qstar, self._qstar_err = self.get_qstar_with_error() 791 if self._qstar <= 0: 792 raise ValueError, "invariant must be greater than zero" 793 ds = porod_const * 2 * math.pi * (( dv - 2 * v * dv)/ self._qstar\ 794 + self._qstar_err * ( v - v**2)) 795 s = self.get_surface(contrast=contrast, porod_const=porod_const) 796 return s, ds -
Invariant/test/utest_use_cases.py
rb6666d4 ref9ed58 4 4 """ 5 5 import unittest 6 import numpy 6 7 from DataLoader.loader import Loader 7 8 from sans.invariant import invariant 8 9 9 10 class Data1D: 11 print "I am not of type Dataloader.Data1D" 12 10 13 class TestInvPolySphere(unittest.TestCase): 11 14 """ … … 14 17 def setUp(self): 15 18 self.data = Loader().load("PolySpheres.txt") 19 20 def test_wrong_data(self): 21 """ test receiving Data1D not of type loader""" 22 23 wrong_data= Data1D() 24 try: 25 self.assertRaises(ValueError,invariant.InvariantCalculator(wrong_data)) 26 except ValueError, msg: 27 print "test pass "+ str(msg) 28 else: raise ValueError, "fail to raise exception when expected" 29 16 30 17 31 def test_use_case_1(self): … … 33 47 # methods should check that Q* has been computed. If not, it should 34 48 # compute it by calling get_qstare(), leaving the parameters as default. 35 volume_fraction = inv.get_volume_fraction(contrast=1.0) 36 surface = inv.get_surface(contrast=1.0, porod_const=1.0) 49 v, dv = inv.get_volume_fraction_with_error(contrast=2.6e-6) 50 s, ds = inv.get_surface_with_error(contrast=2.6e-6, porod_const=2) 51 52 # Test results 53 self.assertAlmostEquals(qstar, 7.48959e-5,2) 54 self.assertAlmostEquals(v, 0.005644689) 55 self.assertAlmostEquals(s, 9.42e+2,2) 37 56 38 57 def test_use_case_2(self): … … 46 65 # Get the invariant with errors 47 66 qstar, qstar_err = inv.get_qstar_with_error() 48 v, dv = inv.get_volume_fraction_with_error(contrast=1.0) 49 s, ds = inv.get_surface_with_error(contrast=1.0, porod_const=1.0) 67 68 # The volume fraction and surface use Q*. That means that the following 69 # methods should check that Q* has been computed. If not, it should 70 # compute it by calling get_qstare(), leaving the parameters as default. 71 v, dv = inv.get_volume_fraction_with_error(contrast=2.6e-6) 72 s, ds = inv.get_surface_with_error(contrast=2.6e-6, porod_const=2) 73 # Test results 74 self.assertAlmostEquals(qstar, 7.48959e-5,2) 75 self.assertAlmostEquals(v, 0.005644689) 76 self.assertAlmostEquals(s, 9.42e+2,2) 77 50 78 51 79 def test_use_case_3(self): … … 62 90 # The function parameter should default to None. If it is None, 63 91 # the method should pick a good default (Guinier at low-Q and 1/q^4 at high-Q). 64 # The method should also check for consistency of the extrapolat eand function92 # The method should also check for consistency of the extrapolation and function 65 93 # parameters. For instance, you might not want to allow 'high' and 'guinier'. 66 94 # The power parameter (not shown below) should default to 4. 67 inv.set_extrap lotation(range='low', npts=5, function='guinier')95 inv.set_extrapolation(range='low', npts=20, function='guinier') 68 96 69 97 # The version of the call without error 70 98 # At this point, we could still compute Q* without extrapolation by calling 71 # get_qstar with arguments, or with extrapolate=None. 72 qstar = inv.get_qstar(extrapolate='low') 73 74 # The version of the call with error 75 qstar, qstar_err = inv.get_qstar_with_error(extrapolate='low') 76 77 # Get the volume fraction and surface 78 v, dv = inv.get_volume_fraction_with_error(contrast=1.0) 79 s, ds = inv.get_surface_with_error(contrast=1.0, porod_const=1.0) 80 99 # get_qstar with arguments, or with extrapolation=None. 100 qstar = inv.get_qstar(extrapolation='low') 101 102 # The version of the call with error 103 qstar, qstar_err = inv.get_qstar_with_error(extrapolation='low') 104 105 # Get the volume fraction and surface 106 v, dv = inv.get_volume_fraction_with_error(contrast=2.6e-6) 107 s, ds = inv.get_surface_with_error(contrast=2.6e-6, porod_const=2) 108 109 # Test results 110 self.assertAlmostEquals(qstar, 7.49e-5,2) 111 self.assertAlmostEquals(v, 0.005648401) 112 self.assertAlmostEquals(s, 9.42e+2,2) 113 81 114 def test_use_case_4(self): 82 115 """ … … 86 119 inv = invariant.InvariantCalculator(data=self.data) 87 120 88 89 121 # Set the extrapolation parameters for the high-Q range 90 91 # The npts parameter should have a good default. 92 # The range parameter should be 'high' or 'low'. Those should be stored separately. 93 # The function parameter should default to None. If it is None, 94 # the method should pick a good default (Guinier at low-Q and 1/q^4 at high-Q). 95 # The method should also check for consistency of the extrapolate and function 96 # parameters. For instance, you might not want to allow 'high' and 'guinier'. 97 # The power parameter should default to 4. 98 inv.set_extraplotation(range='high', npts=5, function='power_law', power=4) 99 100 101 # The version of the call without error 102 # The function parameter defaults to None, then is picked to be 'power_law' for extrapolate='high' 103 qstar = inv.get_qstar(extrapolate='high') 104 105 # The version of the call with error 106 qstar, qstar_err = inv.get_qstar_with_error(extrapolate='high') 107 108 # Get the volume fraction and surface 109 v, dv = inv.get_volume_fraction_with_error(contrast=1.0) 110 s, ds = inv.get_surface_with_error(contrast=1.0, porod_const=1.0) 122 inv.set_extrapolation(range='high', npts=20, function='power_law', power=4) 123 124 # The version of the call without error 125 # The function parameter defaults to None, then is picked to be 'power_law' for extrapolation='high' 126 qstar = inv.get_qstar(extrapolation='high') 127 128 # The version of the call with error 129 qstar, qstar_err = inv.get_qstar_with_error(extrapolation='high') 130 131 # Get the volume fraction and surface 132 v, dv = inv.get_volume_fraction_with_error(contrast=2.6e-6) 133 s, ds = inv.get_surface_with_error(contrast=2.6e-6, porod_const=2) 134 135 # Test results 136 self.assertAlmostEquals(qstar, 7.49e-5,2) 137 self.assertAlmostEquals(v, 0.005952674) 138 self.assertAlmostEquals(s, 9.42e+2,2) 111 139 112 140 def test_use_case_5(self): … … 118 146 119 147 # Set the extrapolation parameters for the low- and high-Q ranges 120 inv.set_extraplotation(range='low', npts=5, function='guinier') 121 inv.set_extraplotation(range='high', npts=5, function='power_law', power=4) 122 123 # The version of the call without error 124 # The function parameter defaults to None, then is picked to be 'power_law' for extrapolate='high' 125 qstar = inv.get_qstar(extrapolate='both') 126 127 # The version of the call with error 128 qstar, qstar_err = inv.get_qstar_with_error(extrapolate='both') 129 130 # Get the volume fraction and surface 131 v, dv = inv.get_volume_fraction_with_error(contrast=1.0) 132 s, ds = inv.get_surface_with_error(contrast=1.0, porod_const=1.0) 133 134 148 inv.set_extrapolation(range='low', npts=5, function='guinier') 149 inv.set_extrapolation(range='high', npts=5, function='power_law', power=4) 150 151 # The version of the call without error 152 # The function parameter defaults to None, then is picked to be 'power_law' for extrapolation='high' 153 qstar = inv.get_qstar(extrapolation='both') 154 155 # The version of the call with error 156 qstar, qstar_err = inv.get_qstar_with_error(extrapolation='both') 157 158 # Get the volume fraction and surface 159 v, dv = inv.get_volume_fraction_with_error(contrast=2.6e-6) 160 s, ds = inv.get_surface_with_error(contrast=2.6e-6, porod_const=2) 161 162 # Test results 163 self.assertAlmostEquals(qstar, 7.90069e-5,2) 164 self.assertAlmostEquals(v, 0.005952674) 165 self.assertAlmostEquals(s, 9.42e+2,2) 166 167 class TestInvSlitSmear(unittest.TestCase): 168 """ 169 Test slit smeared data for invariant computation 170 """ 171 def setUp(self): 172 # Data with slit smear 173 list = Loader().load("latex_smeared.xml") 174 self.data_slit_smear = list[1] 175 176 def test_use_case_1(self): 177 """ 178 Invariant without extrapolation 179 """ 180 inv = invariant.InvariantCalculator(data=self.data_slit_smear) 181 # get invariant 182 qstar = inv.get_qstar() 183 # Get the volume fraction and surface 184 v, dv = inv.get_volume_fraction_with_error(contrast=2.6e-6) 185 s, ds = inv.get_surface_with_error(contrast=2.6e-6, porod_const=2) 186 # Test results 187 self.assertAlmostEquals(qstar, 4.1539e-4) 188 self.assertAlmostEquals(v, 0.032164596) 189 self.assertAlmostEquals(s, 9.42e+2,2) 190 191 def test_use_case_2(self): 192 """ 193 Invariant without extrapolation. Invariant, volume fraction and surface 194 are given with errors. 195 """ 196 # Create invariant object. Background and scale left as defaults. 197 inv = invariant.InvariantCalculator(data=self.data_slit_smear) 198 # Get the invariant with errors 199 qstar, qstar_err = inv.get_qstar_with_error() 200 # Get the volume fraction and surface 201 v, dv = inv.get_volume_fraction_with_error(contrast=2.6e-6) 202 s, ds = inv.get_surface_with_error(contrast=2.6e-6, porod_const=2) 203 # Test results 204 self.assertAlmostEquals(qstar, 4.1539e-4) 205 self.assertAlmostEquals(v, 0.032164596) 206 self.assertAlmostEquals(s, 9.42e+2,2) 207 208 def test_use_case_3(self): 209 """ 210 Invariant with low-Q extrapolation 211 """ 212 # Create invariant object. Background and scale left as defaults. 213 inv = invariant.InvariantCalculator(data=self.data_slit_smear) 214 # Set the extrapolation parameters for the low-Q range 215 inv.set_extrapolation(range='low', npts=20, function='guinier') 216 # The version of the call without error 217 # At this point, we could still compute Q* without extrapolation by calling 218 # get_qstar with arguments, or with extrapolation=None. 219 qstar = inv.get_qstar(extrapolation='low') 220 # The version of the call with error 221 qstar, qstar_err = inv.get_qstar_with_error(extrapolation='low') 222 # Get the volume fraction and surface 223 v, dv = inv.get_volume_fraction_with_error(contrast=2.6e-6) 224 s, ds = inv.get_surface_with_error(contrast=2.6e-6, porod_const=2) 225 226 # Test results 227 self.assertAlmostEquals(qstar,4.1534e-4,3) 228 self.assertAlmostEquals(v, 0.032164596) 229 self.assertAlmostEquals(s, 9.42e+2,2) 230 231 def test_use_case_4(self): 232 """ 233 Invariant with high-Q extrapolation 234 """ 235 # Create invariant object. Background and scale left as defaults. 236 inv = invariant.InvariantCalculator(data=self.data_slit_smear) 237 238 # Set the extrapolation parameters for the high-Q range 239 inv.set_extrapolation(range='high', npts=20, function='power_law', power=4) 240 241 # The version of the call without error 242 # The function parameter defaults to None, then is picked to be 'power_law' for extrapolation='high' 243 qstar = inv.get_qstar(extrapolation='high') 244 245 # The version of the call with error 246 qstar, qstar_err = inv.get_qstar_with_error(extrapolation='high') 247 248 # Get the volume fraction and surface 249 v, dv = inv.get_volume_fraction_with_error(contrast=2.6e-6) 250 s, ds = inv.get_surface_with_error(contrast=2.6e-6, porod_const=2) 251 252 # Test results 253 self.assertAlmostEquals(qstar, 4.1539e-4) 254 self.assertAlmostEquals(v, 0.032164596) 255 self.assertAlmostEquals(s, 9.42e+2,2) 256 257 def test_use_case_5(self): 258 """ 259 Invariant with both high- and low-Q extrapolation 260 """ 261 # Create invariant object. Background and scale left as defaults. 262 inv = invariant.InvariantCalculator(data=self.data_slit_smear) 263 264 # Set the extrapolation parameters for the low- and high-Q ranges 265 inv.set_extrapolation(range='low', npts=20, function='guinier') 266 inv.set_extrapolation(range='high', npts=20, function='power_law', power=4) 267 268 # The version of the call without error 269 # The function parameter defaults to None, then is picked to be 'power_law' for extrapolation='high' 270 qstar = inv.get_qstar(extrapolation='both') 271 272 # The version of the call with error 273 qstar, qstar_err = inv.get_qstar_with_error(extrapolation='both') 274 275 # Get the volume fraction and surface 276 v, dv = inv.get_volume_fraction_with_error(contrast=2.6e-6) 277 s, ds = inv.get_surface_with_error(contrast=2.6e-6, porod_const=2) 278 279 # Test results 280 self.assertAlmostEquals(qstar, 4.1534e-4,3) 281 self.assertAlmostEquals(v, 0.032164596) 282 self.assertAlmostEquals(s, 9.42e+2,2) 283 284 class TestInvPinholeSmear(unittest.TestCase): 285 """ 286 Test pinhole smeared data for invariant computation 287 """ 288 def setUp(self): 289 # data with smear info 290 list = Loader().load("latex_smeared.xml") 291 self.data_q_smear = list[0] 292 293 def test_use_case_1(self): 294 """ 295 Invariant without extrapolation 296 """ 297 inv = invariant.InvariantCalculator(data=self.data_q_smear) 298 qstar = inv.get_qstar() 299 300 volume_fraction = inv.get_volume_fraction(contrast=2.6e-6) 301 surface = inv.get_surface(contrast=2.6e-6, porod_const=2) 302 # Test results 303 self.assertAlmostEquals(qstar, 1.361677e-3) 304 self.assertAlmostEquals(v, 0.115352622) 305 self.assertAlmostEquals(s, 9.42e+2,2) 306 307 def test_use_case_2(self): 308 """ 309 Invariant without extrapolation. Invariant, volume fraction and surface 310 are given with errors. 311 """ 312 # Create invariant object. Background and scale left as defaults. 313 inv = invariant.InvariantCalculator(data=self.data_q_smear) 314 315 # Get the invariant with errors 316 qstar, qstar_err = inv.get_qstar_with_error() 317 # Get the volume fraction and surface 318 v, dv = inv.get_volume_fraction_with_error(contrast=2.6e-6) 319 s, ds = inv.get_surface_with_error(contrast=2.6e-6, porod_const=2) 320 # Test results 321 self.assertAlmostEquals(qstar, 1.361677e-3) 322 self.assertAlmostEquals(v, 0.115352622) 323 self.assertAlmostEquals(s, 9.42e+2,2) 324 325 def test_use_case_3(self): 326 """ 327 Invariant with low-Q extrapolation 328 """ 329 # Create invariant object. Background and scale left as defaults. 330 inv = invariant.InvariantCalculator(data=self.data_q_smear) 331 # Set the extrapolation parameters for the low-Q range 332 inv.set_extrapolation(range='low', npts=20, function='guinier') 333 # The version of the call without error 334 qstar = inv.get_qstar(extrapolation='low') 335 # The version of the call with error 336 qstar, qstar_err = inv.get_qstar_with_error(extrapolation='low') 337 # Get the volume fraction and surface 338 v, dv = inv.get_volume_fraction_with_error(contrast=2.6e-6) 339 s, ds = inv.get_surface_with_error(contrast=1.0, porod_const=0.08) 340 341 # Test results 342 self.assertAlmostEquals(qstar, 0.002037677) 343 self.assertAlmostEquals(v, 0.115352622) 344 self.assertAlmostEquals(s, 9.42e+2,2) 345 346 def test_use_case_4(self): 347 """ 348 Invariant with high-Q extrapolation 349 """ 350 # Create invariant object. Background and scale left as defaults. 351 inv = invariant.InvariantCalculator(data=self.data_q_smear) 352 # Set the extrapolation parameters for the high-Q range 353 inv.set_extrapolation(range='high', npts=20, function='power_law', power=4) 354 # The version of the call without error 355 qstar = inv.get_qstar(extrapolation='high') 356 # The version of the call with error 357 qstar, qstar_err = inv.get_qstar_with_error(extrapolation='high') 358 # Get the volume fraction and surface 359 v, dv = inv.get_volume_fraction_with_error(contrast=2.6e-6) 360 s, ds = inv.get_surface_with_error(contrast=2.6e-6, porod_const=2) 361 362 # Test results 363 self.assertAlmostEquals(qstar, 1.481677e-3) 364 self.assertAlmostEquals(v, 0.127225804) 365 self.assertAlmostEquals(s, 9.42e+2,2) 366 367 def test_use_case_5(self): 368 """ 369 Invariant with both high- and low-Q extrapolation 370 """ 371 # Create invariant object. Background and scale left as defaults. 372 inv = invariant.InvariantCalculator(data=self.data_q_smear) 373 # Set the extrapolation parameters for the low- and high-Q ranges 374 inv.set_extrapolation(range='low', npts=20, function='guinier') 375 inv.set_extrapolation(range='high', npts=20, function='power_law', power=4) 376 # The version of the call without error 377 # The function parameter defaults to None, then is picked to be 'power_law' for extrapolation='high' 378 qstar = inv.get_qstar(extrapolation='both') 379 # The version of the call with error 380 qstar, qstar_err = inv.get_qstar_with_error(extrapolation='both') 381 # Get the volume fraction and surface 382 v, dv = inv.get_volume_fraction_with_error(contrast=2.6e-6) 383 s, ds = inv.get_surface_with_error(contrast=2.6e-6, porod_const=2) 384 385 # Test results 386 self.assertAlmostEquals(qstar, 0.002157677) 387 self.assertAlmostEquals(v, 0.202846825) 388 self.assertAlmostEquals(s, 9.42e+2,2)
Note: See TracChangeset
for help on using the changeset viewer.