Changeset f71287f4 in sasview


Ignore:
Timestamp:
May 9, 2008 6:09:10 PM (17 years ago)
Author:
Mathieu Doucet <doucetm@…>
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
Message:

Allow user to set q_min/q_max

Location:
pr_inversion
Files:
1 added
5 edited

Legend:

Unmodified
Added
Removed
  • pr_inversion/c_extensions/Cinvertor.c

    r4f63160 rf71287f4  
    266266        return Py_BuildValue("d", self->params.d_max);   
    267267} 
     268 
     269/** 
     270 * Sets the minimum q 
     271 */ 
     272static 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 */ 
     283static 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 */ 
     291static 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 */ 
     302static PyObject * get_qmax(Cinvertor *self, PyObject *args) { 
     303        return Py_BuildValue("d", self->params.q_max);   
     304} 
     305 
    268306 
    269307static PyObject * set_alpha(Cinvertor *self, PyObject *args) { 
     
    513551                   {"set_dmax", (PyCFunction)set_dmax, METH_VARARGS, ""}, 
    514552                   {"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, ""}, 
    515557                   {"set_alpha", (PyCFunction)set_alpha, METH_VARARGS, ""}, 
    516558                   {"get_alpha", (PyCFunction)get_alpha, METH_VARARGS, ""}, 
  • pr_inversion/c_extensions/invertor.c

    r4f63160 rf71287f4  
    1818void invertor_init(Invertor_params *pars) { 
    1919        pars->d_max = 180; 
     20        pars->q_min = -1.0; 
     21        pars->q_max = -1.0; 
    2022} 
    2123 
  • pr_inversion/c_extensions/invertor.h

    r4f63160 rf71287f4  
    1212    int nerr;   
    1313    double alpha; 
     14    double q_min; 
     15    double q_max; 
    1416} Invertor_params;  
    1517 
  • pr_inversion/invertor.py

    r4241e48 rf71287f4  
    11from sans.pr.core.pr_inversion import Cinvertor 
    22import numpy 
     3import sys 
    34 
    45class Invertor(Cinvertor): 
     
    1011    ## Alpha to get the reg term the same size as the signal 
    1112    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 
    1219     
    1320    def __init__(self): 
     
    3037        elif name=='d_max': 
    3138            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) 
    3247        elif name=='alpha': 
    3348            return self.set_alpha(value) 
     
    5671        elif name=='d_max': 
    5772            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 
    5883        elif name=='alpha': 
    5984            return self.get_alpha() 
     
    7196        invertor.alpha   = self.alpha 
    7297        invertor.d_max   = self.d_max 
     98        invertor.q_min   = self.q_min 
     99        invertor.q_max   = self.q_max 
    73100         
    74101        invertor.x = self.x 
     
    85112        import time 
    86113         
     114        self.nfunc = nfunc 
    87115        # First, check that the current data is valid 
    88116        if self.is_valid()<=0: 
     
    147175        return self.get_pr_err(c, c_err, r) 
    148176        
     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        
    149187    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         
    150194        import math 
    151195        from scipy.linalg.basic import lstsq 
    152196         
     197        self.nfunc = nfunc 
    153198        # a -- An M x N matrix. 
    154199        # b -- An M x nrhs matrix or M vector. 
     
    163208        for j in range(nfunc): 
    164209            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] 
    166212            for i_q in range(nq): 
    167213                r = self.d_max/nq*i_q 
     
    170216         
    171217        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] 
    173220             
    174221        c, chi2, rank, n = lstsq(a, b) 
     
    181228                inv_cov[i][j] = 0.0 
    182229                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] 
    184232                     
    185233        # Compute the reg term size for the output 
     
    188236        for j in range(nfunc): 
    189237            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 
    191240            for i in range(nq): 
    192                 sum_reg += (a[i_q+npts][j])**2 
     241                sum_reg += (a[i+npts][j])**2 
    193242                     
    194243        if math.fabs(self.alpha)>0: 
     
    203252            print "Error estimating uncertainties" 
    204253             
     254        # Keep a copy of the last output 
     255        self.out = c 
     256        self.cov = err 
    205257         
    206258        return c, err 
     
    248300        return c, err 
    249301         
    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     
    253468     
    254469if __name__ == "__main__": 
  • pr_inversion/test/utest_invertor.py

    r2d06beb rf71287f4  
    333333        for i in range(len(self.x_in)): 
    334334            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 
    335377         
    336378def pr_theory(r, R): 
Note: See TracChangeset for help on using the changeset viewer.