Changeset 2d06beb in sasview for pr_inversion


Ignore:
Timestamp:
May 5, 2008 2:03:39 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:
b43a009
Parents:
150c04a
Message:

Use simple least-square fit

Location:
pr_inversion
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • pr_inversion/c_extensions/Cinvertor.c

    reca05c8 r2d06beb  
    8080        Py_ssize_t ndata; 
    8181        double *data; 
     82        int i; 
    8283   
    8384        if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL; 
    8485        OUTVECTOR(data_obj,data,ndata); 
    85         self->params.x = data; 
     86         
     87        free(self->params.x); 
     88        self->params.x = (double*) malloc(ndata*sizeof(double)); 
     89         
     90        if(self->params.x==NULL) { 
     91            PyErr_SetString(CinvertorError,  
     92                "Cinvertor.set_x: problem allocating memory."); 
     93                return NULL;             
     94        } 
     95         
     96        for (i=0; i<ndata; i++) { 
     97                self->params.x[i] = data[i]; 
     98        } 
     99         
     100        //self->params.x = data; 
    86101        self->params.npoints = ndata; 
    87102        return Py_BuildValue("i", self->params.npoints);         
     
    95110     
    96111        if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL; 
    97         INVECTOR(data_obj, data, ndata); 
     112        OUTVECTOR(data_obj, data, ndata); 
    98113         
    99114        // Check that the input array is large enough 
     
    120135        Py_ssize_t ndata; 
    121136        double *data; 
     137        int i; 
    122138   
    123139        if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL; 
    124140        OUTVECTOR(data_obj,data,ndata); 
    125         self->params.y = data; 
     141         
     142        free(self->params.y); 
     143        self->params.y = (double*) malloc(ndata*sizeof(double)); 
     144         
     145        if(self->params.y==NULL) { 
     146            PyErr_SetString(CinvertorError,  
     147                "Cinvertor.set_y: problem allocating memory."); 
     148                return NULL;             
     149        } 
     150         
     151        for (i=0; i<ndata; i++) { 
     152                self->params.y[i] = data[i]; 
     153        }        
     154         
     155        //self->params.y = data; 
    126156        self->params.ny = ndata; 
    127157        return Py_BuildValue("i", self->params.ny);      
     
    135165     
    136166        if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL; 
    137         INVECTOR(data_obj, data, ndata); 
     167        OUTVECTOR(data_obj, data, ndata); 
    138168         
    139169        // Check that the input array is large enough 
     
    160190        Py_ssize_t ndata; 
    161191        double *data; 
     192        int i; 
    162193   
    163194        if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL; 
    164195        OUTVECTOR(data_obj,data,ndata); 
    165         self->params.err = data; 
     196         
     197        free(self->params.err); 
     198        self->params.err = (double*) malloc(ndata*sizeof(double)); 
     199         
     200        if(self->params.err==NULL) { 
     201            PyErr_SetString(CinvertorError,  
     202                "Cinvertor.set_err: problem allocating memory."); 
     203                return NULL;             
     204        } 
     205         
     206        for (i=0; i<ndata; i++) { 
     207                self->params.err[i] = data[i]; 
     208        } 
     209         
     210        //self->params.err = data; 
    166211        self->params.nerr = ndata; 
    167212        return Py_BuildValue("i", self->params.nerr);    
     
    175220     
    176221        if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL; 
    177         INVECTOR(data_obj, data, ndata); 
     222        OUTVECTOR(data_obj, data, ndata); 
    178223         
    179224        // Check that the input array is large enough 
     
    414459} 
    415460 
     461static PyObject * basefunc_ft(Cinvertor *self, PyObject *args) { 
     462        double d_max, q; 
     463        int n; 
     464         
     465        if (!PyArg_ParseTuple(args, "did", &d_max, &n, &q)) return NULL; 
     466        return Py_BuildValue("f", ortho_transformed(d_max, n, q));       
     467         
     468} 
    416469 
    417470static PyMethodDef Cinvertor_methods[] = { 
     
    435488                   {"get_pr_err", (PyCFunction)get_pr_err, METH_VARARGS, ""}, 
    436489                   {"is_valid", (PyCFunction)is_valid, METH_VARARGS, ""}, 
     490                   {"basefunc_ft", (PyCFunction)basefunc_ft, METH_VARARGS, ""}, 
    437491    
    438492   {NULL} 
  • pr_inversion/c_extensions/invertor.c

    reca05c8 r2d06beb  
    88 */ 
    99void invertor_dealloc(Invertor_params *pars) { 
    10         //free(pars->x); 
    11         //free(pars->y); 
    12         //free(pars->err); 
     10        free(pars->x); 
     11        free(pars->y); 
     12        free(pars->err); 
    1313} 
    1414 
     
    133133} 
    134134 
    135  
  • pr_inversion/c_extensions/invertor.h

    reca05c8 r2d06beb  
    2929void pr_err(double *pars, double *err, double d_max, int n_c,  
    3030                double r, double *pr_value, double *pr_value_err); 
    31  
    3231#endif 
  • pr_inversion/invertor.py

    reca05c8 r2d06beb  
    55     
    66    ## Chisqr of the last computation 
    7     chisqr = 0 
     7    chi2  = 0 
     8    ## Time elapsed for last computation 
     9    elapsed = 0 
    810     
    911    def __init__(self): 
     
    5860        return None 
    5961     
     62    def clone(self): 
     63        """ 
     64            Return a clone of this instance 
     65        """ 
     66        invertor = Invertor() 
     67        invertor.chi2    = self.chi2  
     68        invertor.elapsed = self.elapsed  
     69        invertor.alpha   = self.alpha 
     70        invertor.d_max   = self.d_max 
     71         
     72        invertor.x = self.x 
     73        invertor.y = self.y 
     74        invertor.err = self.err 
     75         
     76        return invertor 
     77     
    6078    def invert(self, nfunc=5): 
    6179        """ 
     
    6381        """ 
    6482        from scipy import optimize 
     83        import time 
    6584         
    6685        # First, check that the current data is valid 
     
    6988         
    7089        p = numpy.ones(nfunc) 
     90        t_0 = time.time() 
    7191        out, cov_x, info, mesg, success = optimize.leastsq(self.residuals, p, full_output=1, warning=True) 
    7292         
     
    7898         
    7999        self.chi2 = chisqr 
     100 
     101        # Store computation time 
     102        self.elapsed = time.time() - t_0 
    80103         
    81104        return out, cov_x 
     
    92115         
    93116        p = numpy.ones(nfunc) 
     117        t_0 = time.time() 
    94118        out, cov_x, info, mesg, success = optimize.leastsq(self.pr_residuals, p, full_output=1, warning=True) 
    95119         
     
    102126        self.chisqr = chisqr 
    103127         
     128        # Store computation time 
     129        self.elapsed = time.time() - t_0 
     130 
    104131        return out, cov_x 
    105132     
     
    117144 
    118145        return self.get_pr_err(c, c_err, r) 
     146        
     147    def lstsq(self, nfunc=5): 
     148        import math 
     149        from scipy.linalg.basic import lstsq 
     150         
     151        # a -- An M x N matrix. 
     152        # b -- An M x nrhs matrix or M vector. 
     153        npts = len(self.x) 
     154        nq   = 20 
     155        sqrt_alpha = math.sqrt(self.alpha) 
     156         
     157        a = numpy.zeros([npts+nq, nfunc]) 
     158        b = numpy.zeros(npts+nq) 
     159        err = numpy.zeros(nfunc) 
     160         
     161        for j in range(nfunc): 
     162            for i in range(npts): 
     163                a[i][j] = self.basefunc_ft(self.d_max, j+1, self.x[i])/self.err[i] 
     164            for i_q in range(nq): 
     165                r = self.d_max/nq*i_q 
     166                #a[i_q+npts][j] = sqrt_alpha * 1.0/nq*self.d_max*2.0*math.fabs(math.sin(math.pi*(j+1)*r/self.d_max) + math.pi*(j+1)*r/self.d_max * math.cos(math.pi*(j+1)*r/self.d_max))      
     167                a[i_q+npts][j] = sqrt_alpha * 1.0/nq*self.d_max*2.0*(2.0*math.pi*(j+1)/self.d_max*math.cos(math.pi*(j+1)*r/self.d_max) + math.pi**2*(j+1)**2*r/self.d_max**2 * math.sin(math.pi*(j+1)*r/self.d_max))      
     168         
     169        for i in range(npts): 
     170            b[i] = self.y[i]/self.err[i] 
     171             
     172        c, chi2, rank, n = lstsq(a, b) 
     173        self.chi2 = chi2 
     174                 
     175        at = numpy.transpose(a) 
     176        inv_cov = numpy.zeros([nfunc,nfunc]) 
     177        for i in range(nfunc): 
     178            for j in range(nfunc): 
     179                inv_cov[i][j] = 0.0 
     180                for k in range(npts): 
     181                    inv_cov[i][j] = at[i][k]*a[k][j] 
     182                     
     183        # Compute the reg term size for the output 
     184        sum_sig = 0.0 
     185        sum_reg = 0.0 
     186        for j in range(nfunc): 
     187            for i in range(npts): 
     188                sum_sig += (a[i][j])**2 
     189            for i in range(nq): 
     190                sum_reg += (a[i_q+npts][j])**2 
     191                     
     192        new_alpha = sum_sig/(sum_reg/self.alpha) 
     193        print "Suggested alpha =", 0.1*new_alpha 
     194         
     195        try: 
     196            err = math.fabs(chi2/(npts-nfunc))* inv_cov 
     197        except: 
     198            print "Error estimating uncertainties" 
     199             
     200         
     201        return c, err 
     202         
     203    def svd(self, nfunc=5): 
     204        import math, time 
     205        # Ac - b = 0 
     206         
     207        A = numpy.zeros([nfunc, nfunc]) 
     208        y = numpy.zeros(nfunc) 
     209         
     210        t_0 = time.time() 
     211        for i in range(nfunc): 
     212            # A 
     213            for j in range(nfunc): 
     214                A[i][j] = 0.0 
     215                for k in range(len(self.x)): 
     216                    err = self.err[k] 
     217                    A[i][j] += 1.0/err/err*self.basefunc_ft(self.d_max, j+1, self.x[k]) \ 
     218                            *self.basefunc_ft(self.d_max, i+1, self.x[k]); 
     219                #print A[i][j] 
     220                #A[i][j] -= self.alpha*(math.cos(math.pi*(i+j)) - math.cos(math.pi*(i-j))); 
     221                if i==j: 
     222                    A[i][j] += -1.0*self.alpha 
     223                elif i-j==1 or i-j==-1: 
     224                    A[i][j] += 1.0*self.alpha 
     225                #print "   ",A[i][j] 
     226            # y 
     227            y[i] = 0.0 
     228            for k in range(len(self.x)): 
     229                y[i] = self.y[k]/self.err[k]/self.err[k]*self.basefunc_ft(self.d_max, i+1, self.x[k]) 
     230             
     231        print time.time()-t_0, 'secs' 
     232         
     233        # use numpy.pinv(A) 
     234        #inv_A = numpy.linalg.inv(A) 
     235        #c = y*inv_A 
     236        print y 
     237        c = numpy.linalg.solve(A, y) 
     238         
     239         
     240        print c 
     241         
     242        err = numpy.zeros(len(c)) 
     243        return c, err 
     244         
     245         
     246         
    119247         
    120248     
  • pr_inversion/test/utest_invertor.py

    reca05c8 r2d06beb  
    174174            print "chi2 =", chi2/51.0 
    175175            raise 
     176         
     177    def test_lstsq(self): 
     178        """ 
     179            Test an inversion for which we know the answer 
     180        """ 
     181        x, y, err = load("sphere_80.txt") 
     182 
     183        # Choose the right d_max... 
     184        self.invertor.d_max = 160.0 
     185        # Set a small alpha 
     186        self.invertor.alpha = .0007 
     187        # Set data 
     188        self.invertor.x   = x 
     189        self.invertor.y   = y 
     190        self.invertor.err = err 
     191        # Perform inversion 
     192        #out, cov = self.invertor.invert(10) 
     193         
     194        out, cov = self.invertor.lstsq(10) 
     195          
     196         
     197        # This is a very specific case 
     198        # We should make sure it always passes 
     199        try: 
     200            self.assertTrue(self.invertor.chi2/len(x)<200.00) 
     201        except: 
     202            print "Chi2(I(q)) =", self.invertor.chi2/len(x) 
     203            raise 
     204         
     205        # Check the computed P(r) with the theory 
     206        # for shpere of radius 80 
     207        x = pylab.arange(0.01, self.invertor.d_max, self.invertor.d_max/51.0) 
     208        y = numpy.zeros(len(x)) 
     209        dy = numpy.zeros(len(x)) 
     210        y_true = numpy.zeros(len(x)) 
     211 
     212        sum = 0.0 
     213        sum_true = 0.0 
     214        for i in range(len(x)): 
     215            #y[i] = self.invertor.pr(out, x[i]) 
     216            (y[i], dy[i]) = self.invertor.pr_err(out, cov, x[i]) 
     217            sum += y[i] 
     218            if x[i]<80.0: 
     219                y_true[i] = pr_theory(x[i], 80.0) 
     220            else: 
     221                y_true[i] = 0 
     222            sum_true += y_true[i] 
     223             
     224        y = y/sum*self.invertor.d_max/len(x) 
     225        dy = dy/sum*self.invertor.d_max/len(x) 
     226        y_true = y_true/sum_true*self.invertor.d_max/len(x) 
     227         
     228        chi2 = 0.0 
     229        for i in range(len(x)): 
     230            res = (y[i]-y_true[i])/dy[i] 
     231            chi2 += res*res 
     232             
     233        try: 
     234            self.assertTrue(chi2/51.0<50.0) 
     235        except: 
     236            print "chi2(P(r)) =", chi2/51.0 
     237            raise 
    176238             
    177239    def test_q_zero(self): 
     
    239301            print "Chi2 =", self.invertor.chi2 
    240302            raise 
     303         
     304    def no_test_time(self): 
     305        x, y, err = load("sphere_80.txt") 
     306 
     307        # Choose the right d_max... 
     308        self.invertor.d_max = 160.0 
     309        # Set a small alpha 
     310        self.invertor.alpha = 1e-7 
     311        # Set data 
     312        self.invertor.x   = x 
     313        self.invertor.y   = y 
     314        self.invertor.err = err 
     315     
     316        # time scales like nfunc**2 
     317        # on a Lenovo Intel Core 2 CPU T7400 @ 2.16GHz,  
     318        # I get time/(nfunc)**2 = 0.022 sec 
    241319                             
    242          
    243  
     320        out, cov = self.invertor.invert(15) 
     321        t16 = self.invertor.elapsed 
     322         
     323        out, cov = self.invertor.invert(30) 
     324        t30 = self.invertor.elapsed 
     325         
     326        t30s = t30/30.0**2 
     327        self.assertTrue( (t30s-t16/16.0**2)/t30s <1.2 ) 
     328         
     329    def test_clone(self): 
     330        self.invertor.x = self.x_in 
     331        clone = self.invertor.clone() 
     332         
     333        for i in range(len(self.x_in)): 
     334            self.assertEqual(self.x_in[i], clone.x[i]) 
     335         
    244336def pr_theory(r, R): 
    245337    """ 
Note: See TracChangeset for help on using the changeset viewer.