Changeset 3350ad6 in sasview for src/sas


Ignore:
Timestamp:
Mar 4, 2015 11:56:03 AM (10 years ago)
Author:
Doucet, Mathieu <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:
5f8fc78
Parents:
091e71a2
Message:

pylint fixes

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/sas/pr/invertor.py

    r79492222 r3350ad6  
     1# pylint: disable=invalid-name 
    12""" 
    23Module to perform P(r) inversion. 
     
    1112import os 
    1213import re 
     14import logging 
    1315from numpy.linalg import lstsq 
    1416from scipy import optimize 
     
    2022    Future work: extend this function to allow topic selection 
    2123    """ 
    22     info_txt  = "The inversion approach is based on Moore, J. Appl. Cryst. " 
     24    info_txt = "The inversion approach is based on Moore, J. Appl. Cryst. " 
    2325    info_txt += "(1980) 13, 168-175.\n\n" 
    2426    info_txt += "P(r) is set to be equal to an expansion of base functions " 
     
    4749    info_txt += "   - Maximum distance: the maximum distance between any " 
    4850    info_txt += "two points in the system.\n" 
    49       
     51 
    5052    return info_txt 
    51      
     53 
    5254 
    5355class Invertor(Cinvertor): 
    5456    """ 
    5557    Invertor class to perform P(r) inversion 
    56      
     58 
    5759    The problem is solved by posing the problem as  Ax = b, 
    5860    where x is the set of coefficients we are looking for. 
    59      
     61 
    6062    Npts is the number of points. 
    61      
     63 
    6264    In the following i refers to the ith base function coefficient. 
    6365    The matrix has its entries j in its first Npts rows set to :: 
    6466 
    6567        A[j][i] = (Fourier transformed base function for point j) 
    66          
     68 
    6769    We them choose a number of r-points, n_r, to evaluate the second 
    6870    derivative of P(r) at. This is used as our regularization term. 
     
    7173        A[j+Npts][i] = (2nd derivative of P(r), d**2(P(r))/d(r)**2, 
    7274        evaluated at r[j]) 
    73          
     75 
    7476    The vector b has its first Npts entries set to :: 
    7577 
    7678        b[j] = (I(q) observed for point j) 
    77          
     79 
    7880    The following n_r entries are set to zero. 
    79      
     81 
    8082    The result is found by using scipy.linalg.basic.lstsq to invert 
    8183    the matrix and find the coefficients x. 
    82      
     84 
    8385    Methods inherited from Cinvertor: 
    8486 
     
    8991    """ 
    9092    ## Chisqr of the last computation 
    91     chi2  = 0 
     93    chi2 = 0 
    9294    ## Time elapsed for last computation 
    9395    elapsed = 0 
    9496    ## Alpha to get the reg term the same size as the signal 
    9597    suggested_alpha = 0 
     98    alpha = 0 
    9699    ## Last number of base functions used 
    97100    nfunc = 10 
     
    104107    ## Information dictionary for application use 
    105108    info = {} 
    106      
     109 
    107110    def __init__(self): 
    108111        Cinvertor.__init__(self) 
    109          
     112        self.slit_height = None 
     113        self.slit_width = None 
     114        self.err = None 
     115        self.d_max = None 
     116        self.q_min = self.set_qmin(-1.0) 
     117        self.q_max = self.set_qmax(-1.0) 
     118        self.x = None 
     119        self.y = None 
     120        self.has_bck = False 
     121 
    110122    def __setstate__(self, state): 
    111123        """ 
     
    117129         self.err, self.has_bck, 
    118130         self.slit_height, self.slit_width) = state 
    119     
     131 
    120132    def __reduce_ex__(self, proto): 
    121133        """ 
     
    129141                 self.err, self.has_bck, 
    130142                 self.slit_height, self.slit_width, 
    131                  ) 
     143                ) 
    132144        return (Invertor, tuple(), state, None, None) 
    133      
     145 
    134146    def __setattr__(self, name, value): 
    135147        """ 
     
    172184            else: 
    173185                raise ValueError, "Invertor: has_bck can only be True or False" 
    174              
     186 
    175187        return Cinvertor.__setattr__(self, name, value) 
    176      
     188 
    177189    def __getattr__(self, name): 
    178190        """ 
     
    219231            return self.__dict__[name] 
    220232        return None 
    221      
     233 
    222234    def clone(self): 
    223235        """ 
     
    225237        """ 
    226238        #import copy 
    227          
     239 
    228240        invertor = Invertor() 
    229         invertor.chi2    = self.chi2 
     241        invertor.chi2 = self.chi2 
    230242        invertor.elapsed = self.elapsed 
    231         invertor.nfunc   = self.nfunc 
    232         invertor.alpha   = self.alpha 
    233         invertor.d_max   = self.d_max 
    234         invertor.q_min   = self.q_min 
    235         invertor.q_max   = self.q_max 
    236          
     243        invertor.nfunc = self.nfunc 
     244        invertor.alpha = self.alpha 
     245        invertor.d_max = self.d_max 
     246        invertor.q_min = self.q_min 
     247        invertor.q_max = self.q_max 
     248 
    237249        invertor.x = self.x 
    238250        invertor.y = self.y 
     
    241253        invertor.slit_height = self.slit_height 
    242254        invertor.slit_width = self.slit_width 
    243          
     255 
    244256        invertor.info = copy.deepcopy(self.info) 
    245          
     257 
    246258        return invertor 
    247      
     259 
    248260    def invert(self, nfunc=10, nr=20): 
    249261        """ 
    250262        Perform inversion to P(r) 
    251          
     263 
    252264        The problem is solved by posing the problem as  Ax = b, 
    253265        where x is the set of coefficients we are looking for. 
    254          
     266 
    255267        Npts is the number of points. 
    256          
     268 
    257269        In the following i refers to the ith base function coefficient. 
    258270        The matrix has its entries j in its first Npts rows set to :: 
    259271 
    260272            A[i][j] = (Fourier transformed base function for point j) 
    261              
     273 
    262274        We them choose a number of r-points, n_r, to evaluate the second 
    263275        derivative of P(r) at. This is used as our regularization term. 
     
    265277 
    266278            A[i+Npts][j] = (2nd derivative of P(r), d**2(P(r))/d(r)**2, evaluated at r[j]) 
    267              
     279 
    268280        The vector b has its first Npts entries set to :: 
    269281 
    270282            b[j] = (I(q) observed for point j) 
    271              
     283 
    272284        The following n_r entries are set to zero. 
    273          
     285 
    274286        The result is found by using scipy.linalg.basic.lstsq to invert 
    275287        the matrix and find the coefficients x. 
    276          
     288 
    277289        :param nfunc: number of base functions to use. 
    278290        :param nr: number of r points to evaluate the 2nd derivative at for the reg. term. 
     
    282294        self.background = 0.0 
    283295        return self.lstsq(nfunc, nr=nr) 
    284      
     296 
    285297    def iq(self, out, q): 
    286298        """ 
    287299        Function to call to evaluate the scattering intensity 
    288          
     300 
    289301        :param args: c-parameters, and q 
    290302        :return: I(q) 
    291          
     303 
    292304        """ 
    293305        return Cinvertor.iq(self, out, q) + self.background 
    294      
     306 
    295307    def invert_optimize(self, nfunc=10, nr=20): 
    296308        """ 
    297309        Slower version of the P(r) inversion that uses scipy.optimize.leastsq. 
    298          
     310 
    299311        This probably produce more reliable results, but is much slower. 
    300312        The minimization function is set to 
     
    303315        the square of the first derivative 
    304316        of P(r), d(P(r))/dr, integrated over the full range of r. 
    305          
     317 
    306318        :param nfunc: number of base functions to use. 
    307319        :param nr: number of r points to evaluate the 2nd derivative at 
    308320            for the reg. term. 
    309          
     321 
    310322        :return: c_out, c_cov - the coefficients with covariance matrix 
    311          
     323 
    312324        """ 
    313325        self.nfunc = nfunc 
     
    316328            msg = "Invertor.invert: Data array are of different length" 
    317329            raise RuntimeError, msg 
    318          
     330 
    319331        p = numpy.ones(nfunc) 
    320332        t_0 = time.time() 
    321         out, cov_x, _, _, _ = optimize.leastsq(self.residuals, 
    322                                                             p, full_output=1) 
    323          
     333        out, cov_x, _, _, _ = optimize.leastsq(self.residuals, p, full_output=1) 
     334 
    324335        # Compute chi^2 
    325336        res = self.residuals(out) 
     
    327338        for i in range(len(res)): 
    328339            chisqr += res[i] 
    329          
     340 
    330341        self.chi2 = chisqr 
    331342 
    332343        # Store computation time 
    333344        self.elapsed = time.time() - t_0 
    334          
     345 
    335346        if cov_x is None: 
    336347            cov_x = numpy.ones([nfunc, nfunc]) 
    337348            cov_x *= math.fabs(chisqr) 
    338349        return out, cov_x 
    339      
     350 
    340351    def pr_fit(self, nfunc=5): 
    341352        """ 
     
    343354        is set to some P(r) distribution that we are trying to reproduce 
    344355        with a set of base functions. 
    345          
     356 
    346357        This method is provided as a test. 
    347358        """ 
     
    350361            msg = "Invertor.invert: Data arrays are of different length" 
    351362            raise RuntimeError, msg 
    352          
     363 
    353364        p = numpy.ones(nfunc) 
    354365        t_0 = time.time() 
    355         out, cov_x, _, _, _ = optimize.leastsq(self.pr_residuals, p, 
    356                                                             full_output=1) 
    357          
     366        out, cov_x, _, _, _ = optimize.leastsq(self.pr_residuals, p, full_output=1) 
     367 
    358368        # Compute chi^2 
    359369        res = self.pr_residuals(out) 
     
    361371        for i in range(len(res)): 
    362372            chisqr += res[i] 
    363          
     373 
    364374        self.chisqr = chisqr 
    365          
     375 
    366376        # Store computation time 
    367377        self.elapsed = time.time() - t_0 
    368378 
    369379        return out, cov_x 
    370      
     380 
    371381    def pr_err(self, c, c_cov, r): 
    372382        """ 
    373383        Returns the value of P(r) for a given r, and base function 
    374384        coefficients, with error. 
    375          
     385 
    376386        :param c: base function coefficients 
    377387        :param c_cov: covariance matrice of the base function coefficients 
    378388        :param r: r-value to evaluate P(r) at 
    379          
     389 
    380390        :return: P(r) 
    381          
     391 
    382392        """ 
    383393        return self.get_pr_err(c, c_cov, r) 
    384         
     394 
    385395    def _accept_q(self, q): 
    386396        """ 
     
    392402            return False 
    393403        return True 
    394         
     404 
    395405    def lstsq(self, nfunc=5, nr=20): 
    396406        """ 
    397407        The problem is solved by posing the problem as  Ax = b, 
    398408        where x is the set of coefficients we are looking for. 
    399          
     409 
    400410        Npts is the number of points. 
    401          
     411 
    402412        In the following i refers to the ith base function coefficient. 
    403413        The matrix has its entries j in its first Npts rows set to :: 
    404414 
    405415            A[i][j] = (Fourier transformed base function for point j) 
    406              
     416 
    407417        We them choose a number of r-points, n_r, to evaluate the second 
    408418        derivative of P(r) at. This is used as our regularization term. 
     
    411421            A[i+Npts][j] = (2nd derivative of P(r), d**2(P(r))/d(r)**2, 
    412422            evaluated at r[j]) 
    413              
     423 
    414424        The vector b has its first Npts entries set to :: 
    415425 
    416426            b[j] = (I(q) observed for point j) 
    417              
     427 
    418428        The following n_r entries are set to zero. 
    419          
     429 
    420430        The result is found by using scipy.linalg.basic.lstsq to invert 
    421431        the matrix and find the coefficients x. 
    422          
     432 
    423433        :param nfunc: number of base functions to use. 
    424434        :param nr: number of r points to evaluate the 2nd derivative at for the reg. term. 
     
    431441        # blah = numpy.ascontiguousarray(blah_original) 
    432442        # ... before passing it to C 
    433          
     443 
    434444        if self.is_valid() < 0: 
    435445            msg = "Invertor: invalid data; incompatible data lengths." 
    436446            raise RuntimeError, msg 
    437          
     447 
    438448        self.nfunc = nfunc 
    439449        # a -- An M x N matrix. 
    440450        # b -- An M x nrhs matrix or M vector. 
    441451        npts = len(self.x) 
    442         nq   = nr 
     452        nq = nr 
    443453        sqrt_alpha = math.sqrt(math.fabs(self.alpha)) 
    444454        if sqrt_alpha < 0.0: 
     
    453463        b = numpy.zeros(npts + nq) 
    454464        err = numpy.zeros([nfunc, nfunc]) 
    455          
     465 
    456466        # Construct the a matrix and b vector that represent the problem 
    457467        t_0 = time.time() 
     
    460470        except: 
    461471            raise RuntimeError, "Invertor: could not invert I(Q)\n  %s" % sys.exc_value 
    462               
     472 
    463473        # Perform the inversion (least square fit) 
    464474        c, chi2, _, _ = lstsq(a, b) 
     
    469479            chi2 = -1.0 
    470480        self.chi2 = chi2 
    471                  
     481 
    472482        inv_cov = numpy.zeros([nfunc, nfunc]) 
    473483        # Get the covariance matrix, defined as inv_cov = a_transposed * a 
    474484        self._get_invcov_matrix(nfunc, nr, a, inv_cov) 
    475                      
     485 
    476486        # Compute the reg term size for the output 
    477487        sum_sig, sum_reg = self._get_reg_size(nfunc, nr, a) 
    478                      
     488 
    479489        if math.fabs(self.alpha) > 0: 
    480490            new_alpha = sum_sig / (sum_reg / self.alpha) 
     
    482492            new_alpha = 0.0 
    483493        self.suggested_alpha = new_alpha 
    484          
     494 
    485495        try: 
    486496            cov = numpy.linalg.pinv(inv_cov) 
     
    489499            # We were not able to estimate the errors 
    490500            # Return an empty error matrix 
    491             pass 
    492              
     501            logging.error(sys.exc_value) 
     502 
    493503        # Keep a copy of the last output 
    494504        if self.has_bck == False: 
     
    498508        else: 
    499509            self.background = c[0] 
    500              
     510 
    501511            err_0 = numpy.zeros([nfunc, nfunc]) 
    502512            c_0 = numpy.zeros(nfunc) 
    503              
     513 
    504514            for i in range(nfunc_0): 
    505                 c_0[i] = c[i+1] 
     515                c_0[i] = c[i + 1] 
    506516                for j in range(nfunc_0): 
    507                     err_0[i][j] = err[i+1][j+1] 
    508                      
     517                    err_0[i][j] = err[i + 1][j + 1] 
     518 
    509519            self.out = c_0 
    510520            self.cov = err_0 
    511              
     521 
    512522        # Store computation time 
    513523        self.elapsed = time.time() - t_0 
    514          
     524 
    515525        return self.out, self.cov 
    516          
     526 
    517527    def estimate_numterms(self, isquit_func=None): 
    518528        """ 
    519529        Returns a reasonable guess for the 
    520530        number of terms 
    521          
     531 
    522532        :param isquit_func: 
    523533          reference to thread function to call to check whether the computation needs to 
    524534          be stopped. 
    525          
     535 
    526536        :return: number of terms, alpha, message 
    527          
     537 
    528538        """ 
    529539        from num_term import Num_terms 
     
    536546            best_alpha, _, _ = self.estimate_alpha(self.nfunc) 
    537547            return self.nfunc, best_alpha, "Could not estimate number of terms" 
    538                      
     548 
    539549    def estimate_alpha(self, nfunc): 
    540550        """ 
    541551        Returns a reasonable guess for the 
    542552        regularization constant alpha 
    543          
     553 
    544554        :param nfunc: number of terms to use in the expansion. 
    545          
     555 
    546556        :return: alpha, message, elapsed 
    547          
     557 
    548558        where alpha is the estimate for alpha, 
    549559        message is a message for the user, 
     
    553563        try: 
    554564            pr = self.clone() 
    555              
     565 
    556566            # T_0 for computation time 
    557567            starttime = time.time() 
    558568            elapsed = 0 
    559              
     569 
    560570            # If the current alpha is zero, try 
    561571            # another value 
    562572            if pr.alpha <= 0: 
    563573                pr.alpha = 0.0001 
    564                   
     574 
    565575            # Perform inversion to find the largest alpha 
    566576            out, _ = pr.invert(nfunc) 
     
    568578            initial_alpha = pr.alpha 
    569579            initial_peaks = pr.get_peaks(out) 
    570      
     580 
    571581            # Try the inversion with the estimated alpha 
    572582            pr.alpha = pr.suggested_alpha 
    573583            out, _ = pr.invert(nfunc) 
    574      
     584 
    575585            npeaks = pr.get_peaks(out) 
    576586            # if more than one peak to start with 
     
    582592                return pr.suggested_alpha, message, elapsed 
    583593            else: 
    584                  
     594 
    585595                # Look at smaller values 
    586596                # We assume that for the suggested alpha, we have 1 peak 
     
    590600                found = False 
    591601                for i in range(10): 
    592                     pr.alpha = (0.33)**(i+1) * alpha 
     602                    pr.alpha = (0.33) ** (i + 1) * alpha 
    593603                    out, _ = pr.invert(nfunc) 
    594                      
     604 
    595605                    peaks = pr.get_peaks(out) 
    596606                    if peaks > 1: 
     
    598608                        break 
    599609                    best_alpha = pr.alpha 
    600                      
     610 
    601611                # If we didn't find a turning point for alpha and 
    602612                # the initial alpha already had only one peak, 
     
    605615                    initial_alpha < best_alpha: 
    606616                    best_alpha = initial_alpha 
    607                      
     617 
    608618                # Check whether the size makes sense 
    609619                message = '' 
    610                  
     620 
    611621                if not found: 
    612622                    message = None 
     
    614624                    # best alpha is too big, return a 
    615625                    # reasonable value 
    616                     message  = "The estimated alpha for your system is too " 
     626                    message = "The estimated alpha for your system is too " 
    617627                    message += "large. " 
    618628                    message += "Try increasing your maximum distance." 
    619                  
     629 
    620630                return best_alpha, message, elapsed 
    621      
     631 
    622632        except: 
    623633            message = "Invertor.estimate_alpha: %s" % sys.exc_value 
    624634            return 0, message, elapsed 
    625      
     635 
    626636    def to_file(self, path, npts=100): 
    627637        """ 
    628638        Save the state to a file that will be readable 
    629639        by SliceView. 
    630          
     640 
    631641        :param path: path of the file to write 
    632642        :param npts: number of P(r) points to be written 
    633          
     643 
    634644        """ 
    635645        file = open(path, 'w') 
     
    653663                for i in range(len(self.out)): 
    654664                    file.write("#C_%i=%s+-%s\n" % (i, str(self.out[i]), 
    655                                                     str(self.cov[i][i]))) 
     665                                                   str(self.cov[i][i]))) 
    656666        file.write("<r>  <Pr>  <dPr>\n") 
    657         r = numpy.arange(0.0, self.d_max, self.d_max/npts) 
    658          
     667        r = numpy.arange(0.0, self.d_max, self.d_max / npts) 
     668 
    659669        for r_i in r: 
    660670            (value, err) = self.pr_err(self.out, self.cov, r_i) 
    661671            file.write("%g  %g  %g\n" % (r_i, value, err)) 
    662      
     672 
    663673        file.close() 
    664       
     674 
    665675    def from_file(self, path): 
    666676        """ 
     
    668678        to be able to generate P(r) from a set of 
    669679        parameters. 
    670          
     680 
    671681        :param path: path of the file to load 
    672          
     682 
    673683        """ 
    674684        #import os 
     
    677687            try: 
    678688                fd = open(path, 'r') 
    679                  
     689 
    680690                buff = fd.read() 
    681691                lines = buff.split('\n') 
     
    728738                        else: 
    729739                            self.has_bck = False 
    730              
     740 
    731741                    # Now read in the parameters 
    732742                    elif line.startswith('#C_'): 
     
    737747                        i = int(m.group(1)) 
    738748                        self.out[i] = float(toks2[0]) 
    739                          
     749 
    740750                        self.cov[i][i] = float(toks2[1]) 
    741              
     751 
    742752            except: 
    743753                msg = "Invertor.from_file: corrupted file\n%s" % sys.exc_value 
Note: See TracChangeset for help on using the changeset viewer.