Ignore:
Timestamp:
Feb 10, 2019 4:40:06 PM (4 years ago)
Author:
toby
Message:

refactor to move some IO-only routines; add initial image support to scriptable

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/GSASIIscriptable.py

    r3811 r3814  
    571571import GSASIIpwd as G2pwd
    572572import GSASIIstrMain as G2strMain
     573#import GSASIIIO as G2IO
    573574import GSASIIstrIO as G2strIO
    574575import GSASIIspc as G2spc
    575576import GSASIIElem as G2elem
    576 
    577 
    578 # Delay imports to not slow down small scripts
    579 G2fil = None
    580 PwdrDataReaders = []
    581 PhaseReaders = []
     577import GSASIIfiles as G2fil
     578
     579# Delay imports to not slow down small scripts that don't need them
     580Readers = {'Pwdr':[], 'Phase':[], 'Image':[]}
     581'''Readers by reader type'''
    582582exportersByExtension = {}
    583583'''Specifies the list of extensions that are supported for Powder data export'''
     
    585585def LoadG2fil():
    586586    """Delay importing this module, it is slow"""
    587     global G2fil
    588     if G2fil is None:
    589         import GSASIIfiles
    590         G2fil = GSASIIfiles
    591         global PwdrDataReaders
    592         global PhaseReaders
    593         PwdrDataReaders = G2fil.LoadImportRoutines("pwd", "Powder_Data")
    594         PhaseReaders = G2fil.LoadImportRoutines("phase", "Phase")
    595         AllExporters = G2fil.LoadExportRoutines(None)
    596         global exportersByExtension
    597         exportersByExtension = {}
    598         for obj in AllExporters:
    599             try:
    600                 obj.Writer
    601             except AttributeError:
    602                 continue
    603             for typ in obj.exporttype:
    604                 if typ not in exportersByExtension:
    605                     exportersByExtension[typ] = {obj.extension:obj}
    606                 else:
    607                     exportersByExtension[typ][obj.extension] = obj
     587    if len(Readers['Pwdr']) > 0: return
     588    # initialize imports
     589    Readers['Pwdr'] = G2fil.LoadImportRoutines("pwd", "Powder_Data")
     590    Readers['Phase'] = G2fil.LoadImportRoutines("phase", "Phase")
     591    Readers['Image'] = G2fil.LoadImportRoutines("img", "Image")
     592
     593    # initialize exports
     594    for obj in exportersByExtension:
     595        try:
     596            obj.Writer
     597        except AttributeError:
     598            continue
     599        for typ in obj.exporttype:
     600            if typ not in exportersByExtension:
     601                exportersByExtension[typ] = {obj.extension:obj}
     602            else:
     603                exportersByExtension[typ][obj.extension] = obj
    608604
    609605def LoadDictFromProjFile(ProjFile):
     
    11981194
    11991195
    1200 class G2Project(G2ObjectWrapper):
    1201     """
    1202     Represents an entire GSAS-II project.
     1196class G2Project(G2ObjectWrapper):   
     1197    """Represents an entire GSAS-II project.
    12031198
    12041199    :param str gpxfile: Existing .gpx file to be loaded. If nonexistent,
     
    13351330        datafile = os.path.abspath(os.path.expanduser(datafile))
    13361331        iparams = os.path.abspath(os.path.expanduser(iparams))
    1337         pwdrreaders = import_generic(datafile, PwdrDataReaders,fmthint=fmthint,bank=databank)
     1332        pwdrreaders = import_generic(datafile, Readers['Pwdr'],fmthint=fmthint,bank=databank)
    13381333        histname, new_names, pwdrdata = load_pwd_from_reader(
    13391334                                          pwdrreaders[0], iparams,
     
    14451440        :param str phasename: The name of the new phase, or None for the default
    14461441        :param list histograms: The names of the histograms to associate with
    1447             this phase. Use proj.Histograms() to add to all histograms.
     1442            this phase. Use proj.histograms() to add to all histograms.
    14481443        :param str fmthint: If specified, only importers where the format name
    14491444          (reader.formatName, as shown in Import menu) contains the
     
    14601455
    14611456        # TODO handle multiple phases in a file
    1462         phasereaders = import_generic(phasefile, PhaseReaders, fmthint=fmthint)
     1457        phasereaders = import_generic(phasefile, Readers['Phase'], fmthint=fmthint)
    14631458        phasereader = phasereaders[0]
    14641459       
     
    15771572            :meth:`G2Project.phase`
    15781573            :meth:`G2Project.phases`
    1579             """
     1574        """
    15801575        if isinstance(histname, G2PwdrData):
    15811576            if histname.proj == self:
     
    15931588                return histogram
    15941589
    1595     def histograms(self):
    1596         """Return a list of all histograms, as
    1597         :class:`G2PwdrData` objects
     1590    def histograms(self, typ=None):
     1591        """Return a list of all histograms, as :class:`G2PwdrData` objects
     1592
     1593        For now this only finds Powder/Single Xtal histograms, since that is all that is
     1594        currently implemented in this module.
     1595
     1596        :param ste typ: The prefix (type) the histogram such as 'PWDR '. If None
     1597          (the default) all known histograms types are found.
     1598        :returns: a list of objects
    15981599
    15991600        .. seealso::
    1600             :meth:`G2Project.histograms`
     1601            :meth:`G2Project.histogram`
    16011602            :meth:`G2Project.phase`
    16021603            :meth:`G2Project.phases`
    1603             """
     1604        """
    16041605        output = []
    16051606        # loop through each tree entry. If it is more than one level (more than one item in the
    1606         # list of names) then it must be a histogram, unless labeled Phases or Restraints
    1607         for obj in self.names:
    1608             if len(obj) > 1 and obj[0] != u'Phases' and obj[0] != u'Restraints':
    1609                 output.append(self.histogram(obj[0]))
     1607        # list of names). then it must be a histogram, unless labeled Phases or Restraints
     1608        if typ is None:
     1609            for obj in self.names:
     1610                if obj[0].startswith('PWDR ') or obj[0].startswith('HKLF '):
     1611                    output.append(self.histogram(obj[0]))
     1612        else:
     1613            for obj in self.names:
     1614                if len(obj) > 1 and obj[0].startswith(typ):
     1615                    output.append(self.histogram(obj[0]))
    16101616        return output
    16111617
     
    16581664        return []
    16591665
     1666    def _images(self):
     1667        """Returns a list of all the phases in the project.
     1668        """
     1669        return [i[0] for i in self.names if i[0].startswith('IMG ')]
     1670   
     1671    def image(self, imageRef):
     1672        """
     1673        Gives an object representing the specified image in this project.
     1674
     1675        :param str imageRef: A reference to the desired image. Either the Image
     1676          tree name (str), the image's index (int) or
     1677          a image object (:class:`G2Image`)
     1678        :returns: A :class:`G2Image` object
     1679        :raises: KeyError
     1680
     1681        .. seealso::
     1682            :meth:`G2Project.images`
     1683            """
     1684        if isinstance(imageRef, G2Image):
     1685            if imageRef.proj == self:
     1686                return imageRef
     1687            else:
     1688                raise Exception("Image {} not in current selected project".format(imageRef.name))
     1689        if imageRef in self._images():
     1690            return G2Image(self.data[imageRef], imageRef, self)
     1691
     1692        try:
     1693            # imageRef should be an index
     1694            num = int(imageRef)
     1695            imageRef = self._images()[num]
     1696            return G2Image(self.data[imageRef], imageRef, self)
     1697        except ValueError:
     1698            raise Exception("imageRef {} not an object, name or image index in current selected project"
     1699                                .format(imageRef))
     1700        except IndexError:
     1701            raise Exception("imageRef {} out of range (max={}) in current selected project"
     1702                                .format(imageRef,len(self._images())-1))
     1703           
     1704    def images(self):
     1705        """
     1706        Returns a list of all the images in the project.
     1707
     1708        :returns: A list of :class:`G2Image` objects
     1709        """
     1710        return [G2Image(self.data[i],i,self) for i in self._images()]
     1711   
    16601712    def update_ids(self):
    16611713        """Makes sure all phases and histograms have proper hId and pId"""
     
    19522004        return G2obj.G2VarObj(phase, hist, varname, atomId)
    19532005
     2006    def add_image(self, imagefile, fmthint=None, defaultImage=None):
     2007        """Load an image into a project
     2008
     2009        :param str imagefile: The image file to read, a filename.
     2010        :param str fmthint: If specified, only importers where the format name
     2011          (reader.formatName, as shown in Import menu) contains the
     2012          supplied string will be tried as importers. If not specified, all
     2013          importers consistent with the file extension will be tried
     2014          (equivalent to "guess format" in menu).
     2015        :param str defaultImage: The name of an image to use as a default for
     2016          setting parameters for the image file to read.
     2017
     2018        :returns: a list of G2Image object for the added image(s) [this routine
     2019          has not yet been tested with files with multiple images...]
     2020        """
     2021        LoadG2fil()
     2022        imagefile = os.path.abspath(os.path.expanduser(imagefile))
     2023        readers = import_generic(imagefile, Readers['Image'], fmthint=fmthint)
     2024        objlist = []
     2025        for rd in readers:
     2026            if rd.SciPy:        #was default read by scipy; needs 1 time fixes
     2027                print('TODO: Image {} read by SciPy. Parameters likely need editing'.format(imagefile))
     2028                #see this: G2IO.EditImageParms(self,rd.Data,rd.Comments,rd.Image,imagefile)
     2029                rd.SciPy = False
     2030            rd.readfilename = imagefile
     2031            if rd.repeatcount == 1 and not rd.repeat: # skip image number if only one in set
     2032                rd.Data['ImageTag'] = None
     2033            else:
     2034                rd.Data['ImageTag'] = rd.repeatcount
     2035            rd.Data['formatName'] = rd.formatName
     2036            if rd.sumfile:
     2037                rd.readfilename = rd.sumfile
     2038            # Load generic metadata, as configured
     2039            G2fil.GetColumnMetadata(rd)
     2040            # Code from G2IO.LoadImage2Tree(rd.readfilename,self,rd.Comments,rd.Data,rd.Npix,rd.Image)
     2041            Imax = np.amax(rd.Image)
     2042            ImgNames = [i[0] for i in self.names if i[0].startswith('IMG ')]
     2043            TreeLbl = 'IMG '+os.path.basename(imagefile)
     2044            ImageTag = rd.Data.get('ImageTag')
     2045            if ImageTag:
     2046                TreeLbl += ' #'+'%04d'%(ImageTag)
     2047                imageInfo = (imagefile,ImageTag)
     2048            else:
     2049                imageInfo = imagefile
     2050            TreeName = G2obj.MakeUniqueLabel(TreeLbl,ImgNames)
     2051            # MT dict to contain image info
     2052            ImgDict = {}
     2053            ImgDict['data'] = [rd.Npix,imageInfo]
     2054            ImgDict['Comments'] = rd.Comments
     2055            if defaultImage:
     2056                if isinstance(defaultImage, G2Image):
     2057                    if defaultImage.proj == self:
     2058                        defaultImage = self.data[defaultImage.name]['data']
     2059                    else:
     2060                        raise Exception("Image {} not in current selected project".format(defaultImage.name))
     2061                elif defaultImage in self._images():
     2062                    defaultImage = self.data[defaultImage]['data']
     2063                else:
     2064                    defaultImage = None
     2065            Data = rd.Data
     2066            if defaultImage:
     2067                Data = copy.copy(defaultImage)
     2068                Data['showLines'] = True
     2069                Data['ring'] = []
     2070                Data['rings'] = []
     2071                Data['cutoff'] = 10.
     2072                Data['pixLimit'] = 20
     2073                Data['edgemin'] = 100000000
     2074                Data['calibdmin'] = 0.5
     2075                Data['calibskip'] = 0
     2076                Data['ellipses'] = []
     2077                Data['calibrant'] = ''
     2078                Data['GonioAngles'] = [0.,0.,0.]
     2079                Data['DetDepthRef'] = False
     2080            else:
     2081                Data['type'] = 'PWDR'
     2082                Data['color'] = GSASIIpath.GetConfigValue('Contour_color','Paired')
     2083                if 'tilt' not in Data:          #defaults if not preset in e.g. Bruker importer
     2084                    Data['tilt'] = 0.0
     2085                    Data['rotation'] = 0.0
     2086                    Data['pixLimit'] = 20
     2087                    Data['calibdmin'] = 0.5
     2088                    Data['cutoff'] = 10.
     2089                Data['showLines'] = False
     2090                Data['calibskip'] = 0
     2091                Data['ring'] = []
     2092                Data['rings'] = []
     2093                Data['edgemin'] = 100000000
     2094                Data['ellipses'] = []
     2095                Data['GonioAngles'] = [0.,0.,0.]
     2096                Data['DetDepth'] = 0.
     2097                Data['DetDepthRef'] = False
     2098                Data['calibrant'] = ''
     2099                Data['IOtth'] = [5.0,50.0]
     2100                Data['LRazimuth'] = [0.,180.]
     2101                Data['azmthOff'] = 0.0
     2102                Data['outChannels'] = 2250
     2103                Data['outAzimuths'] = 1
     2104                Data['centerAzm'] = False
     2105                Data['fullIntegrate'] = GSASIIpath.GetConfigValue('fullIntegrate',True)
     2106                Data['setRings'] = False
     2107                Data['background image'] = ['',-1.0]                           
     2108                Data['dark image'] = ['',-1.0]
     2109                Data['Flat Bkg'] = 0.0
     2110                Data['Oblique'] = [0.5,False]
     2111            Data['setDefault'] = False
     2112            Data['range'] = [(0,Imax),[0,Imax]]
     2113            ImgDict['Image Controls'] = Data
     2114            ImgDict['Masks'] = {'Points':[],'Rings':[],'Arcs':[],'Polygons':[],
     2115                                'Frames':[],'Thresholds':[(0,Imax),[0,Imax]]}
     2116            ImgDict['Stress/Strain']  = {'Type':'True','d-zero':[],'Sample phi':0.0,
     2117                                             'Sample z':0.0,'Sample load':0.0}
     2118            self.names.append([TreeName]+['Comments','Image Controls','Masks','Stress/Strain'])
     2119            self.data[TreeName] = ImgDict
     2120            del rd.Image
     2121            objlist.append(G2Image(self.data[TreeName], TreeName, self))
     2122        return objlist
    19542123
    19552124class G2AtomRecord(G2ObjectWrapper):
     
    29413110                    print(u'Unknown HAP key: '+key)
    29423111
     3112class G2Image(G2ObjectWrapper):
     3113    """Wrapper for an IMG tree entry, containing an image and various metadata.
     3114    """
     3115    # parameters in
     3116    ControlList = {
     3117        'int': ['calibskip', 'pixLimit', 'edgemin', 'outChannels',
     3118                    'outAzimuths'],
     3119        'float': ['cutoff', 'setdist', 'wavelength', 'Flat Bkg',
     3120                      'azmthOff', 'tilt', 'calibdmin', 'rotation',
     3121                      'distance', 'DetDepth'],
     3122        'bool': ['setRings', 'setDefault', 'centerAzm', 'fullIntegrate',
     3123                     'DetDepthRef', 'showLines'],
     3124        'str': ['SampleShape', 'binType', 'formatName', 'color',
     3125                    'type', 'calibrant'],
     3126        'list': ['GonioAngles', 'IOtth', 'LRazimuth', 'Oblique', 'PolaVal',
     3127                   'SampleAbs', 'center', 'ellipses', 'linescan',
     3128                    'pixelSize', 'range', 'ring', 'rings', 'size', ],
     3129        'dict': ['varylist'],
     3130#        'image': ['background image', 'dark image', 'Gain map'],
     3131        }
     3132    '''Defines the items known to exist in the Image Controls tree section
     3133    and their data types.
     3134    '''
     3135
     3136    def __init__(self, data, name, proj):
     3137        self.data = data
     3138        self.name = name
     3139        self.proj = proj
     3140
     3141    def setControl(self,arg,value):
     3142        '''Set an Image Controls parameter in the current image.
     3143        If the parameter is not found an exception is raised.
     3144
     3145        :param str arg: the name of a parameter (dict entry) in the
     3146          image. The parameter must be found in :data:`ControlList`
     3147          or an exception is raised.
     3148        :param value: the value to set the parameter. The value is
     3149          cast as the appropriate type from :data:`ControlList`.
     3150        '''
     3151        for typ in self.ControlList:
     3152            if arg in self.ControlList[typ]: break
     3153        else:
     3154            raise Exception('arg {} not defined in G2Image.setControl'
     3155                                .format(arg))
     3156        try:
     3157            if typ == 'int':
     3158                self.data['Image Controls'][arg] = int(value)
     3159            elif typ == 'float':
     3160                self.data['Image Controls'][arg] = float(value)
     3161            elif typ == 'bool':
     3162                self.data['Image Controls'][arg] = bool(value)
     3163            elif typ == 'str':
     3164                self.data['Image Controls'][arg] = str(value)
     3165            elif typ == 'list':
     3166                self.data['Image Controls'][arg] = list(value)
     3167            elif typ == 'dict':
     3168                self.data['Image Controls'][arg] = dict(value)
     3169            else:
     3170                raise Exception('Unknown type {} for arg {} in  G2Image.setControl'
     3171                                    .format(typ,arg))
     3172        except:
     3173            raise Exception('Error formatting value {} as type {} for arg {} in  G2Image.setControl'
     3174                                    .format(value,typ,arg))
     3175
     3176    def getControl(self,arg):
     3177        '''Return an Image Controls parameter in the current image.
     3178        If the parameter is not found an exception is raised.
     3179
     3180        :param str arg: the name of a parameter (dict entry) in the
     3181          image.
     3182        :returns: the value as a int, float, list,...
     3183        '''
     3184        if arg in self.data['Image Controls']:
     3185            return self.data['Image Controls'][arg]
     3186        raise Exception('arg {} not defined in G2Image.getControl'.format(arg))
     3187
     3188    def findControl(self,arg):
     3189        '''Finds the Image Controls parameter(s) in the current image
     3190        that match the string in arg.
     3191
     3192          Example: findControl('calib') will return
     3193          [['calibskip', 'int'], ['calibdmin', 'float'], ['calibrant', 'str']]
     3194
     3195        :param str arg: a string containing part of the name of a
     3196          parameter (dict entry) in the image's Image Controls.
     3197        :returns: a list of matching entries in form
     3198          [['item','type'], ['item','type'],...] where each 'item' string
     3199          contains the sting in arg.
     3200        '''
     3201        matchList = []
     3202        for typ in self.ControlList:
     3203            for item in self.ControlList[typ]:
     3204                if arg in item:
     3205                    matchList.append([item,typ])
     3206        return matchList
     3207
     3208    def setControlFile(self,typ,imageRef,mult=None):
     3209        '''Set a image to be used as a background/dark/gain map image
     3210
     3211        :param str typ: specifies image type, which must be one of:
     3212           'background image', 'dark image', 'gain map'; N.B. only the first
     3213           four characters must be specified and case is ignored.
     3214        :param imageRef:
     3215        :param float mult:
     3216        '''
     3217#        'image': ['background image', 'dark image', 'Gain map'],
     3218        if 'back' in typ.lower():
     3219            key = 'background image'
     3220            mult = float(mult)
     3221        elif 'dark' in typ.lower():
     3222            key = 'dark image'
     3223            mult = float(mult)
     3224        elif 'gain' in typ.lower():
     3225            #key = 'Gain map'
     3226            if mult is not None:
     3227                print('Ignoring multiplier for Gain map')
     3228            mult = None
     3229        else:
     3230            raise Exception("Invalid typ {} for setControlFile".format(typ))
     3231        imgNam = self.proj.image(imageRef).name
     3232        if mult is None:
     3233            self.data['Image Controls']['Gain map'] = imgNam
     3234        else:
     3235            self.data['Image Controls'][key] = [imgNam,mult]
     3236
     3237    def loadControls(self,filename):
     3238        '''load controls from a .imctrl file
     3239        :param str filename: specifies a file to be read, which should end
     3240          with .imctrl
     3241        '''
     3242        File = open(filename,'r')
     3243        Slines = File.readlines()
     3244        File.close()
     3245        G2fil.LoadControls(Slines,self.data['Image Controls'])
     3246        print('file {} read into {}'.format(filename,self.name))
     3247
     3248    def saveControls(self,filename):
     3249        '''write current controls values to a .imctrl file
     3250        :param str filename: specifies a file to write, which should end
     3251          with .imctrl
     3252        '''
     3253        G2fil.WriteControls(filename,self.data['Image Controls'])
     3254        print('file {} written from {}'.format(filename,self.name))
    29433255
    29443256##########################
Note: See TracChangeset for help on using the changeset viewer.