Changeset f71287f4 in sasview
- Timestamp:
- May 9, 2008 6:09:10 PM (17 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:
- 634f1cf
- Parents:
- 32dffae4
- Location:
- pr_inversion
- Files:
-
- 1 added
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
pr_inversion/c_extensions/Cinvertor.c
r4f63160 rf71287f4 266 266 return Py_BuildValue("d", self->params.d_max); 267 267 } 268 269 /** 270 * Sets the minimum q 271 */ 272 static PyObject * set_qmin(Cinvertor *self, PyObject *args) { 273 double q_min; 274 275 if (!PyArg_ParseTuple(args, "d", &q_min)) return NULL; 276 self->params.q_min = q_min; 277 return Py_BuildValue("d", self->params.q_min); 278 } 279 280 /** 281 * Gets the minimum q 282 */ 283 static PyObject * get_qmin(Cinvertor *self, PyObject *args) { 284 return Py_BuildValue("d", self->params.q_min); 285 } 286 287 288 /** 289 * Sets the maximum q 290 */ 291 static PyObject * set_qmax(Cinvertor *self, PyObject *args) { 292 double q_max; 293 294 if (!PyArg_ParseTuple(args, "d", &q_max)) return NULL; 295 self->params.q_max = q_max; 296 return Py_BuildValue("d", self->params.q_max); 297 } 298 299 /** 300 * Gets the maximum q 301 */ 302 static PyObject * get_qmax(Cinvertor *self, PyObject *args) { 303 return Py_BuildValue("d", self->params.q_max); 304 } 305 268 306 269 307 static PyObject * set_alpha(Cinvertor *self, PyObject *args) { … … 513 551 {"set_dmax", (PyCFunction)set_dmax, METH_VARARGS, ""}, 514 552 {"get_dmax", (PyCFunction)get_dmax, METH_VARARGS, ""}, 553 {"set_qmin", (PyCFunction)set_qmin, METH_VARARGS, ""}, 554 {"get_qmin", (PyCFunction)get_qmin, METH_VARARGS, ""}, 555 {"set_qmax", (PyCFunction)set_qmax, METH_VARARGS, ""}, 556 {"get_qmax", (PyCFunction)get_qmax, METH_VARARGS, ""}, 515 557 {"set_alpha", (PyCFunction)set_alpha, METH_VARARGS, ""}, 516 558 {"get_alpha", (PyCFunction)get_alpha, METH_VARARGS, ""}, -
pr_inversion/c_extensions/invertor.c
r4f63160 rf71287f4 18 18 void invertor_init(Invertor_params *pars) { 19 19 pars->d_max = 180; 20 pars->q_min = -1.0; 21 pars->q_max = -1.0; 20 22 } 21 23 -
pr_inversion/c_extensions/invertor.h
r4f63160 rf71287f4 12 12 int nerr; 13 13 double alpha; 14 double q_min; 15 double q_max; 14 16 } Invertor_params; 15 17 -
pr_inversion/invertor.py
r4241e48 rf71287f4 1 1 from sans.pr.core.pr_inversion import Cinvertor 2 2 import numpy 3 import sys 3 4 4 5 class Invertor(Cinvertor): … … 10 11 ## Alpha to get the reg term the same size as the signal 11 12 suggested_alpha = 0 13 ## Last number of base functions used 14 nfunc = 0 15 ## Last output values 16 out = None 17 ## Last errors on output values 18 cov = None 12 19 13 20 def __init__(self): … … 30 37 elif name=='d_max': 31 38 return self.set_dmax(value) 39 elif name=='q_min': 40 if value==None: 41 return self.set_qmin(-1.0) 42 return self.set_qmin(value) 43 elif name=='q_max': 44 if value==None: 45 return self.set_qmax(-1.0) 46 return self.set_qmax(value) 32 47 elif name=='alpha': 33 48 return self.set_alpha(value) … … 56 71 elif name=='d_max': 57 72 return self.get_dmax() 73 elif name=='q_min': 74 qmin = self.get_qmin() 75 if qmin<0: 76 return None 77 return qmin 78 elif name=='q_max': 79 qmax = self.get_qmax() 80 if qmax<0: 81 return None 82 return qmax 58 83 elif name=='alpha': 59 84 return self.get_alpha() … … 71 96 invertor.alpha = self.alpha 72 97 invertor.d_max = self.d_max 98 invertor.q_min = self.q_min 99 invertor.q_max = self.q_max 73 100 74 101 invertor.x = self.x … … 85 112 import time 86 113 114 self.nfunc = nfunc 87 115 # First, check that the current data is valid 88 116 if self.is_valid()<=0: … … 147 175 return self.get_pr_err(c, c_err, r) 148 176 177 def _accept_q(self, q): 178 """ 179 Check q-value against user-defined range 180 """ 181 if not self.q_min==None and q<self.q_min: 182 return False 183 if not self.q_max==None and q>self.q_max: 184 return False 185 return True 186 149 187 def lstsq(self, nfunc=5): 188 #TODO: do this on the C side 189 # 190 # To make sure an array is contiguous: 191 # blah = numpy.ascontiguousarray(blah_original) 192 # ... before passing it to C 193 150 194 import math 151 195 from scipy.linalg.basic import lstsq 152 196 197 self.nfunc = nfunc 153 198 # a -- An M x N matrix. 154 199 # b -- An M x nrhs matrix or M vector. … … 163 208 for j in range(nfunc): 164 209 for i in range(npts): 165 a[i][j] = self.basefunc_ft(self.d_max, j+1, self.x[i])/self.err[i] 210 if self._accept_q(self.x[i]): 211 a[i][j] = self.basefunc_ft(self.d_max, j+1, self.x[i])/self.err[i] 166 212 for i_q in range(nq): 167 213 r = self.d_max/nq*i_q … … 170 216 171 217 for i in range(npts): 172 b[i] = self.y[i]/self.err[i] 218 if self._accept_q(self.x[i]): 219 b[i] = self.y[i]/self.err[i] 173 220 174 221 c, chi2, rank, n = lstsq(a, b) … … 181 228 inv_cov[i][j] = 0.0 182 229 for k in range(npts): 183 inv_cov[i][j] = at[i][k]*a[k][j] 230 if self._accept_q(self.x[i]): 231 inv_cov[i][j] = at[i][k]*a[k][j] 184 232 185 233 # Compute the reg term size for the output … … 188 236 for j in range(nfunc): 189 237 for i in range(npts): 190 sum_sig += (a[i][j])**2 238 if self._accept_q(self.x[i]): 239 sum_sig += (a[i][j])**2 191 240 for i in range(nq): 192 sum_reg += (a[i _q+npts][j])**2241 sum_reg += (a[i+npts][j])**2 193 242 194 243 if math.fabs(self.alpha)>0: … … 203 252 print "Error estimating uncertainties" 204 253 254 # Keep a copy of the last output 255 self.out = c 256 self.cov = err 205 257 206 258 return c, err … … 248 300 return c, err 249 301 250 251 252 302 def estimate_alpha(self, nfunc): 303 """ 304 Returns a reasonable guess for the 305 regularization constant alpha 306 307 @return: alpha, message, elapsed 308 309 where alpha is the estimate for alpha, 310 message is a message for the user, 311 elapsed is the computation time 312 """ 313 import time 314 try: 315 pr = self.clone() 316 317 # T_0 for computation time 318 starttime = time.time() 319 320 # If the current alpha is zero, try 321 # another value 322 if pr.alpha<=0: 323 pr.alpha = 0.0001 324 325 # Perform inversion to find the largest alpha 326 out, cov = pr.lstsq(nfunc) 327 elapsed = time.time()-starttime 328 initial_alpha = pr.alpha 329 initial_peaks = pr.get_peaks(out) 330 331 # Try the inversion with the estimated alpha 332 pr.alpha = pr.suggested_alpha 333 out, cov = pr.lstsq(nfunc) 334 335 npeaks = pr.get_peaks(out) 336 # if more than one peak to start with 337 # just return the estimate 338 if npeaks>1: 339 message = "Your P(r) is not smooth, please check your inversion parameters" 340 return pr.suggested_alpha, message, elapsed 341 else: 342 343 # Look at smaller values 344 # We assume that for the suggested alpha, we have 1 peak 345 # if not, send a message to change parameters 346 alpha = pr.suggested_alpha 347 best_alpha = pr.suggested_alpha 348 found = False 349 for i in range(10): 350 pr.alpha = (0.33)**(i+1)*alpha 351 out, cov = pr.lstsq(nfunc) 352 353 peaks = pr.get_peaks(out) 354 print pr.alpha, peaks 355 if peaks>1: 356 found = True 357 break 358 best_alpha = pr.alpha 359 360 # If we didn't find a turning point for alpha and 361 # the initial alpha already had only one peak, 362 # just return that 363 if not found and initial_peaks==1 and initial_alpha<best_alpha: 364 best_alpha = initial_alpha 365 366 # Check whether the size makes sense 367 message='' 368 369 if not found: 370 message = "None" 371 elif best_alpha>=0.5*pr.suggested_alpha: 372 # best alpha is too big, return a 373 # reasonable value 374 message = "The estimated alpha for your system is too large. " 375 message += "Try increasing your maximum distance." 376 377 return best_alpha, message, elapsed 378 379 except: 380 message = "Invertor.estimate_alpha: %s" % sys.exc_value 381 return 0, message, elapsed 382 383 384 def to_file(self, path, npts=100): 385 """ 386 Save the state to a file that will be readable 387 by SliceView. 388 @param path: path of the file to write 389 @param npts: number of P(r) points to be written 390 """ 391 import pylab 392 393 file = open(path, 'w') 394 file.write("#d_max=%g\n" % self.d_max) 395 file.write("#nfunc=%g\n" % self.nfunc) 396 file.write("#alpha=%g\n" % self.alpha) 397 file.write("#chi2=%g\n" % self.chi2) 398 file.write("#elapsed=%g\n" % self.elapsed) 399 file.write("#alpha_estimate=%g\n" % self.suggested_alpha) 400 if not self.out==None: 401 if len(self.out)==len(self.cov): 402 for i in range(len(self.out)): 403 file.write("#C_%i=%s+-%s\n" % (i, str(self.out[i]), str(self.cov[i][i]))) 404 file.write("<r> <Pr> <dPr>\n") 405 r = pylab.arange(0.0, self.d_max, self.d_max/npts) 406 407 for r_i in r: 408 (value, err) = self.pr_err(self.out, self.cov, r_i) 409 file.write("%g %g %g\n" % (r_i, value, err)) 410 411 file.close() 412 413 def from_file(self, path): 414 """ 415 Load the state of the Invertor from a file, 416 to be able to generate P(r) from a set of 417 parameters. 418 @param path: path of the file to load 419 """ 420 import os 421 import re 422 if os.path.isfile(path): 423 try: 424 fd = open(path, 'r') 425 426 buff = fd.read() 427 lines = buff.split('\n') 428 for line in lines: 429 if line.startswith('#d_max='): 430 toks = line.split('=') 431 self.d_max = float(toks[1]) 432 elif line.startswith('#nfunc='): 433 toks = line.split('=') 434 self.nfunc = int(toks[1]) 435 self.out = numpy.zeros(self.nfunc) 436 self.cov = numpy.zeros([self.nfunc, self.nfunc]) 437 elif line.startswith('#alpha='): 438 toks = line.split('=') 439 self.alpha = float(toks[1]) 440 elif line.startswith('#chi2='): 441 toks = line.split('=') 442 self.chi2 = float(toks[1]) 443 elif line.startswith('#elapsed='): 444 toks = line.split('=') 445 self.elapsed = float(toks[1]) 446 elif line.startswith('#alpha_estimate='): 447 toks = line.split('=') 448 self.suggested_alpha = float(toks[1]) 449 450 # Now read in the parameters 451 elif line.startswith('#C_'): 452 toks = line.split('=') 453 p = re.compile('#C_([0-9]+)') 454 m = p.search(toks[0]) 455 toks2 = toks[1].split('+-') 456 i = int(m.group(1)) 457 self.out[i] = float(toks2[0]) 458 459 self.cov[i][i] = float(toks2[1]) 460 461 except: 462 raise RuntimeError, "Invertor.from_file: corrupted file\n%s" % sys.exc_value 463 else: 464 raise RuntimeError, "Invertor.from_file: '%s' is not a file" % str(path) 465 466 467 253 468 254 469 if __name__ == "__main__": -
pr_inversion/test/utest_invertor.py
r2d06beb rf71287f4 333 333 for i in range(len(self.x_in)): 334 334 self.assertEqual(self.x_in[i], clone.x[i]) 335 336 def test_save(self): 337 x, y, err = load("sphere_80.txt") 338 339 # Choose the right d_max... 340 self.invertor.d_max = 160.0 341 # Set a small alpha 342 self.invertor.alpha = .0007 343 # Set data 344 self.invertor.x = x 345 self.invertor.y = y 346 self.invertor.err = err 347 # Perform inversion 348 349 out, cov = self.invertor.lstsq(10) 350 351 # Save 352 self.invertor.to_file("test_output.txt") 353 354 def test_load(self): 355 self.invertor.from_file("test_output.txt") 356 self.assertEqual(self.invertor.d_max, 160.0) 357 self.assertEqual(self.invertor.alpha, 0.0007) 358 self.assertEqual(self.invertor.chi2, 16654.1) 359 self.assertAlmostEqual(self.invertor.pr(self.invertor.out, 10.0), 8948.22689927, 4) 360 361 def test_qmin(self): 362 self.invertor.q_min = 1.0 363 print self.invertor.q_min 364 self.assertEqual(self.invertor.q_min, 1.0) 365 366 self.invertor.q_min = None 367 self.assertEqual(self.invertor.q_min, None) 368 369 370 def test_qmax(self): 371 self.invertor.q_max = 1.0 372 self.assertEqual(self.invertor.q_max, 1.0) 373 374 self.invertor.q_max = None 375 self.assertEqual(self.invertor.q_max, None) 376 335 377 336 378 def pr_theory(r, R):
Note: See TracChangeset
for help on using the changeset viewer.