Exemple #1
0
def readMap(dirIn='./', dirOut='./', mapName='untitled.map',
            mapType='atom_map', atomInds=[], log='',
            standardise=False, fixMaxMapVal=''):

    # a function to read in a .map file of either density or atom-tagged type

    # define 'rho' electron map object
    rho = MapInfo()

    mapName = dirIn + mapName
    filesize = os.path.getsize(mapName)
    log.writeToLog(str='Map file of size {} bytes to be read'.format(filesize))

    # open electron density .map file here (bmf for binary map file)
    if os.name != 'nt':
        with open(mapName) as f:
            bmf = mmap.mmap(
                f.fileno(), 0, prot=mmap.PROT_READ, flags=mmap.MAP_PRIVATE)
    else:
        with open(mapName, "r+b") as f:
            bmf = mmap.mmap(f.fileno(), 0)

    # start adding header information into MapInfo class format.
    # Note the unpacking of a struct for each byte, read as a long 'l'
    for n in ('nx', 'ny', 'nz'):
        rho.nxyz[n] = unpack('=l', bmf.read(4))[0]

    rho.type = unpack('=l', bmf.read(4))[0]

    for s in ('fast', 'med', 'slow'):
        rho.start[s] = unpack('=l', bmf.read(4))[0]

    for g in ('1', '2', '3'):
        rho.gridsamp[g] = unpack('=l', bmf.read(4))[0]

    for d in ('a', 'b', 'c', 'alpha', 'beta', 'gamma'):
        # cell dims stored as float not long int
        rho.celldims[d] = unpack('f', bmf.read(4))[0]

    for a in ('fast', 'med', 'slow'):
        rho.axis[a] = unpack('=l', bmf.read(4))[0]

    for d in ('min', 'max', 'mean'):
        rho.density[d] = unpack('f', bmf.read(4))[0]

    s = rho.getHeaderInfo(tab=True)

    # write to log file if specified
    if log != '':
        if os.path.exists(log.logFile):
            for l in s.split('\n'):
                log.writeToLog(l, priority='minor')
    else:
        print(s)

    # calculate the last nx*ny*nz bytes of file (corresponding to
    # the position of the 3D electron density array). Note factor
    # of 4 is included since 4-byte floats used for electron
    # density array values.

    densitystart = filesize - 4*(reduce(lambda x, y: x*y, list(rho.nxyz.values())))

    # if sys.version_info[0] >= 3:
    #     import functools
    #     densitystart = filesize - 4*(functools.reduce(lambda x, y: x*y, list(rho.nxyz.values())))
    # else:
    #     densitystart = filesize - 4*(reduce(lambda x, y: x*y, list(rho.nxyz.values())))

    # get symmetry operations from map header
    for j in range(23, 58):
        if j != 53 and j < 57:

            if j != 55:
                val = unpack('=l', bmf.read(4))[0]
            else:
                val = unpack('=f', bmf.read(4))[0]

            if j == 24:
                numSymBytes = val

            if j == 55:
                mapStdev = round(val, 5)

        elif j < 57:
            for i in range(4):
                val = unpack('c', bmf.read(1))[0]
        else:
            for i in range(10):
                for k in range(80):
                    char = unpack('c', bmf.read(1))[0]
    symOps = []

    for j in range(numSymBytes // 80):
        line = ''
        for k in range(80):
            char = unpack('=c', bmf.read(1))[0].decode("utf-8")
            line += char
        symOps.append(line)
    rho.curateSymOps(symOps)

    # next seek start of electron density data
    bmf.seek(densitystart, 0)

    # if electron density written in shorts this is not
    # currently expected, so program will halt
    if rho.type == 1:
        error(text='Untested .map type --> 1 (type 2 expected). ' +
                   'Values read as int16 ("i2?") - consult .map header in ' +
                   'MAPDUMP(CCP4) to check', log=log, type='error')

    # if electron density written in floats (which is to be expected
    # from FFT-CCP4 outputted .map file of electron density)
    if rho.type == 2:

        # the length of the each data chunk to read map voxels below
        struct_fmt = '=f'
        struct_len = calcsize(struct_fmt)
        # should get struct_len = 4
        if struct_len != 4:
            error(text='Bad data chunk length assigned when reading map',
                  log=log, type='error')

        density = []
        appenddens = density.append

        if mapType in ('atom_map'):
            atomInds = []
            appendindex = atomInds.append
            counter = -1
            while True:
                data = bmf.read(struct_len)
                if not data:
                    break
                s = unpack(struct_fmt, data)[0]
                counter += 1
                if int(s) == 0:
                    continue
                else:
                    appenddens(s)
                    appendindex(counter)
            log.writeToLog(str='# voxels in total : {}'.format(counter + 1))

        # efficient way to read through density map file
        # using indices of atoms from atom map file above
        elif mapType in ('density_map'):

            for i in range(0, len(atomInds)):
                if i != 0:
                    bmf.read(struct_len*(atomInds[i]-atomInds[i-1] - 1))
                else:
                    bmf.read(struct_len*(atomInds[0]))

                data = bmf.read(struct_len)
                s = unpack(struct_fmt, data)[0]
                appenddens(s)

            # check that resulting list of same length as atomInds
            if len(density) != len(atomInds):
                error(text='Failure to process the density map ' +
                           'using atom-tagged map', log=log, type='error')

            # UNCOMMENT TO INSTEAD READ IN ALL VOXELS
            # while True:
            #     data = bmf.read(struct_len)
            #     if not data: break
            #     s = unpack(struct_fmt,data)[0]
            #     appenddens(s)

        else:
            error(text='Unknown map type!', log=log, type='error')
    bmf.close()

    # as a check that file has been read correctly, check that the min
    # and max electron density stated in .map file header correspond to
    # calculated min and max here.
    # NOTE for the case of atom map, the min voxel val will be 0 (no
    # atom present)--> since these voxels are removed during the filtering
    # of the map, only the map value is tested.
    # For density map, cannot currently perform a check, since there is no
    # guarantee that the max and min voxel values may be non atom voxels and
    # thus removed
    if mapType in ('atom_map'):
        if max(density) == rho.density['max']:
            log.writeToLog(
                str='calculated max voxel value match value ' +
                    'stated in file header')
        else:
            error(
                text='Calculated max voxel value:{} does NOT '.format(
                    max(density)) +
                'match value stated in file header:{}'.format(
                    rho.density['max']),
                log=log, type='error')

    # if each voxel value is an atom number, then want to convert to integer
    if mapType in ('atom_map'):
        density_final = [int(dens // 100) for dens in density]
    elif mapType in ('density_map'):
        density_final = density
    else:
        error(text='Unknown map type!', log=log, type='error')

    # provide option to standardise density to map mean and standard deviation
    if standardise and mapType in ('density_map'):
        density_final = (np.array(density_final)-rho.density['mean'])/mapStdev

        if fixMaxMapVal != '':
            density_final /= np.max(np.absolute(density_final))
            if fixMaxMapVal == 'rand':
                fixMaxMapVal = np.random.uniform(6, 10)
                log.writeToLog(
                    str='Random max map value chosen to be {}'.format(
                        fixMaxMapVal))
            density_final *= fixMaxMapVal

        density_final = density_final.tolist()

    rho.vxls_val = density_final

    if mapType in ('atom_map'):
        return rho, atomInds
    else:
        return rho
def readMap(where,pdbname,mapfilename,maptype,atom_indices):

    # append to log file for this eTrack run 
    logfileName = '{}output/{}_log.txt'.format(where,pdbname)
    logfile = open(logfileName,'a')
    
    # define 'rho' electron map object
    rho = MapInfo()

    # open electron density .map file here (bmf for binary map file)
    bmf = open(where+mapfilename,'rb')
    
    # start adding header information into MapInfo class format. 
    # Note the unpacking of a struct for each byte, read as a long 'l'
    for n in ('nx','ny','nz'):
        rho.nxyz[n]   = struct.unpack('=l',bmf.read(4))[0]

    print 'Num. Col, Row, Sec: '
    print '{} {} {}'.format(*rho.nxyz.values())
    logfile.write('Num. Col, Row, Sec: {} {} {}\n'.format(*rho.nxyz.values()))
    
    rho.type = struct.unpack('=l',bmf.read(4))[0]

    for s in ('1','2','3'):
        rho.start[s] = struct.unpack('=l',bmf.read(4))[0] 

    print 'Start positions: '
    print '{} {} {}'.format(*rho.start.values())
    logfile.write('Start positions: {} {} {}\n'.format(*rho.start.values()))

    for g in ('1','2','3'):
        rho.gridsamp[g] = struct.unpack('=l',bmf.read(4))[0] 

    print 'Grid sampling:'
    print '{} {} {}'.format(*rho.gridsamp.values())
    logfile.write('Grid sampling: {} {} {}\n'.format(*rho.gridsamp.values()))

    # for cell dimensions, stored in header file as float not long 
    # integer so must account for this
    for d in ('a','b','c','alpha','beta','gamma'):
        rho.celldims[d]       = struct.unpack('f',bmf.read(4))[0]

    print 'Cell dimensions:'
    print '{} {} {}'.format(*rho.gridsamp.values()[0:3])
    print '{} {} {}'.format(*rho.gridsamp.values()[3:6])
    logfile.write('Cell dimensions: {} {} {} {} {} {}\n'.format(*rho.gridsamp.values()))

    for a in ('fast','med','slow'):
        rho.axis[a]   = struct.unpack('=l',bmf.read(4))[0] 

    print 'Fast,med,slow axes: '
    print '{} {} {}'.format(*rho.axis.values())
    logfile.write('Fast,med,slow axes: {} {} {}\n'.format(*rho.axis.values()))

    for d in ('min','max','mean'):
        rho.density[d]  = struct.unpack('f',bmf.read(4))[0] 

    print 'Density values: '
    print '{} {} {}'.format(*rho.density.values())
    logfile.write('Density values: {} {} {}\n'.format(*rho.density.values()))

    # next find .map file size, to calculate the last nx*ny*nz bytes of 
    # file (corresponding to the position of the 3D electron density 
    # array). Note factor of 4 is included since 4-byte floats used for 
    # electron density array values.
    filesize = os.path.getsize(where+mapfilename)
    densitystart = filesize - 4*(rho.nx*rho.ny*rho.nz)
    
    # next seek start of electron density data
    bmf.seek(densitystart,0)
    
    # if electron density written in shorts (I don't think it will be 
    # but best to have this case)
    if rho.type is 1:  
        print 'Untested .map type --> 1 (type 2 expected). Values read' 
        + 'as int16 ("i2?") - consult .map header in MAPDUMP(CCP4) to check'
  
        struct_fmt = '=i2'
        struct_len = struct.calcsize(struct_fmt)
        density = []
       
        while True:
            data = bmf.read(struct_len)
            if not data: break
            s = struct.unpack(struct_fmt,data)[0]
            density.append(s)    
    
    # if electron density written in floats (which is to be expected 
    # from FFT-CCP4 outputted .map file of electron density)
    if rho.type is 2:  
        struct_fmt = '=f4'
        struct_len = struct.calcsize(struct_fmt)
        density = []
        appenddens = density.append
        
        if maptype in ('atom_map'):
            atom_indices = []
            appendindex = atom_indices.append
            counter = -1
            while True:
                data = bmf.read(struct_len)
                if not data: break
                s = struct.unpack(struct_fmt,data)[0]
                counter += 1
                if int(s) == 0:
                    continue
                else:    
                    appenddens(s)
                    appendindex(counter)
        
        # efficient way to read through density map file using indices of atoms
        # from atom map file above
        elif maptype in ('density_map'):
            for i in range(0,len(atom_indices)):
                if i != 0:
                    bmf.read(struct_len*(atom_indices[i]-atom_indices[i-1] - 1))
                else:
                    bmf.read(struct_len*(atom_indices[0]))
                    
                data = bmf.read(struct_len)
                s = struct.unpack(struct_fmt,data)[0]
                appenddens(s)
                
        else:
            print 'Unknown map type --> terminating script'
            sys.exit()
         
    logfile.close()           
    bmf.close()
    
    # as a check that file has been read correctly, check that the min 
    # and max electron density stated in .map file header correspond to 
    # calculated min and max here
    # Note for the case of atom map, the min voxel val will be 0 (no atom present)
    # --> since these voxels are removed during the filtering of the map, only 
    # the map value is tested.
    # For density map, cannot currently perform a check, since there is no 
    # guarantee that the max and min voxel values may be non atom voxels and
    # thus removed
    if maptype in ('atom_map'):        
        if max(density) == rho.maxdensity:
            print 'calculated max voxel value match value stated in file header'
        else:
            print 'calculated max voxel value does NOT match value stated in file header'
            print 'have now calculated max voxel value to be: %s'\
            %str(max(density))
            sys.exit()
    
    # if each voxel value is an atom number, then want to convert to integer
    if maptype in ('atom_map'):
        density_final = [int(dens)/100 for dens in density]
    elif maptype in ('density_map'):
        density_final = density
    else:
        print 'Unknown map type --> terminating script'
        sys.exit()

    rho.vxls_val = density_final
    
    if maptype in ('atom_map'):
        return rho,atom_indices
    else:
        return rho
def readMap(dirIn    = './',
            dirOut   = './',
            mapName  = 'untitled.map',
            mapType  = 'atom_map',
            atomInds = [],
            log      = ''):

    # define 'rho' electron map object
    rho = MapInfo()

    mapName = dirIn + mapName
    filesize = os.path.getsize(mapName)
    ln = 'Map file of size {} bytes to be read'.format(filesize)
    log.writeToLog(str = ln)

    # open electron density .map file here (bmf for binary map file)
    if os.name != 'nt': # if not windows 
        with open( mapName ) as f:
            bmf = mmap.mmap( f.fileno(), 0, prot = mmap.PROT_READ, flags = mmap.MAP_PRIVATE )
    else:
        with open( mapName ,"r+b") as f:
            bmf = mmap.mmap( f.fileno(), 0)

    # start adding header information into MapInfo class format. 
    # Note the unpacking of a struct for each byte, read as a long 'l'
    for n in ('nx','ny','nz'):
        rho.nxyz[n] = unpack('=l',bmf.read(4))[0]

    rho.type = unpack('=l',bmf.read(4))[0]

    for s in ('fast','med','slow'):
        rho.start[s] = unpack('=l',bmf.read(4))[0] 

    for g in ('1','2','3'):
        rho.gridsamp[g] = unpack('=l',bmf.read(4))[0] 

    for d in ('a','b','c','alpha','beta','gamma'):
        rho.celldims[d] = unpack('f',bmf.read(4))[0] # cell dims stored as float not long int

    for a in ('fast','med','slow'): 
        rho.axis[a] = unpack('=l',bmf.read(4))[0] 
        
    for d in ('min','max','mean'): 
        rho.density[d] = unpack('f',bmf.read(4))[0]

    s = rho.getHeaderInfo(tab = True)

    # write to log file if specified 
    if log != '':
        if os.path.exists(log.logFile):
            for l in s.split('\n'): log.writeToLog(l)
    else: 
        print s

    # calculate the last nx*ny*nz bytes of file (corresponding to 
    # the position of the 3D electron density array). Note factor 
    # of 4 is included since 4-byte floats used for electron 
    # density array values.
    densitystart = filesize - 4*(reduce(lambda x, y: x*y, rho.nxyz.values()))
    
    # get symmetry operations from map header
    for j in range(23,58):
        if j != 53 and j < 57:
            val = unpack('=l',bmf.read(4))[0]
            if j == 24:
                numSymBytes = val
        elif j < 57:
            for i in range(4):
                val = unpack('c',bmf.read(1))[0]
        else:
            for i in range(10):
                for  k in range(80):
                    char = unpack('c',bmf.read(1))[0]
    symOps = []
    for j in range(numSymBytes/80):
        line = ''
        for k in range(80):
            char = unpack('c',bmf.read(1))[0]
            line += char
        symOps.append(line)
    rho.curateSymOps(symOps)

    # next seek start of electron density data
    bmf.seek(densitystart,0)
    
    # if electron density written in shorts (I don't think it will be 
    # but best to have this case)
    if rho.type is 1:  
        err = 'Untested .map type --> 1 (type 2 expected). Values read'+\
              'as int16 ("i2?") - consult .map header in MAPDUMP(CCP4) to check'
        log.writeToLog(str = err)
  
        struct_fmt = '=i2'
        struct_len = calcsize(struct_fmt)
        density = []
       
        while True:
            data = bmf.read(struct_len)
            if not data: break
            s = unpack(struct_fmt,data)[0]
            density.append(s)    

    # if electron density written in floats (which is to be expected 
    # from FFT-CCP4 outputted .map file of electron density)
    if rho.type is 2:  
        struct_fmt = '=f4'
        struct_len = calcsize(struct_fmt)
        density = []
        appenddens = density.append
        
        if mapType in ('atom_map'):
            atomInds = []
            appendindex = atomInds.append
            counter = -1
            while True:
                data = bmf.read(struct_len)
                if not data: break
                s = unpack(struct_fmt,data)[0]
                counter += 1
                if int(s) == 0:
                    continue
                else:    
                    appenddens(s)
                    appendindex(counter)
            ln = '# voxels in total : {}'.format(counter + 1)
            log.writeToLog(str = ln)

        # efficient way to read through density map file using indices of atoms
        # from atom map file above
        elif mapType in ('density_map'):
            for i in range(0,len(atomInds)):
                if i != 0:
                    bmf.read(struct_len*(atomInds[i]-atomInds[i-1] - 1))
                else:
                    bmf.read(struct_len*(atomInds[0]))
                    
                data = bmf.read(struct_len)
                s = unpack(struct_fmt,data)[0]
                appenddens(s)

            # check that resulting list of same length as atomInds
            if len(density) != len(atomInds):
                err = 'Error in processing of density map using atom-tagged map'
                log.writeToLog(str = err)

                sys.exit()           
        else:
            err = 'Unknown map type --> terminating script'
            log.writeToLog(str = err)

            sys.exit()
    bmf.close()
    
    # as a check that file has been read correctly, check that the min 
    # and max electron density stated in .map file header correspond to 
    # calculated min and max here.
    # Note for the case of atom map, the min voxel val will be 0 (no atom present)
    # --> since these voxels are removed during the filtering of the map, only 
    # the map value is tested.
    # For density map, cannot currently perform a check, since there is no 
    # guarantee that the max and min voxel values may be non atom voxels and
    # thus removed
    if mapType in ('atom_map'):      
        if max(density) == rho.density['max']:
            ln = 'calculated max voxel value match value stated in file header'
            log.writeToLog(str = ln)
        else:
            err = 'calculated max voxel value:{} does NOT '.format(max(density))+\
                  'match value stated in file header:{}'.format(rho.density['max'])
            log.writeToLog(str = err)
            sys.exit()
    
    # if each voxel value is an atom number, then want to convert to integer
    if mapType in ('atom_map'):
        density_final = [int(dens)/100 for dens in density]
    elif mapType in ('density_map'):
        density_final = density
    else:
        err = 'Unknown map type --> terminating script'
        log.writeToLog(str = err)
        sys.exit()

    rho.vxls_val = density_final

    if mapType in ('atom_map'):
        return rho,atomInds
    else:
        return rho
def readMap(dirIn,dirOut,pdbname,mapfilename,maptype,atom_indices):
    # append to log file for this eTrack run 
    logfileName = '{}{}_log.txt'.format(dirOut,pdbname)
    logfile = open(logfileName,'a')
    
    # define 'rho' electron map object
    rho = MapInfo()

    # open electron density .map file here (bmf for binary map file)
    # bmf = open(where+mapfilename,'rb')
    mapName = dirIn+mapfilename
    with open( mapName ) as f:
        bmf = mmap.mmap( f.fileno(), 0, prot = mmap.PROT_READ, flags = mmap.MAP_PRIVATE )
    
    # start adding header information into MapInfo class format. 
    # Note the unpacking of a struct for each byte, read as a long 'l'
    for n in ('nx','ny','nz'):
        rho.nxyz[n] = unpack('=l',bmf.read(4))[0]

    rho.type = unpack('=l',bmf.read(4))[0]

    for s in ('1','2','3'):
        rho.start[s] = unpack('=l',bmf.read(4))[0] 

    for g in ('1','2','3'):
        rho.gridsamp[g] = unpack('=l',bmf.read(4))[0] 

    for d in ('a','b','c','alpha','beta','gamma'):
        rho.celldims[d] = unpack('f',bmf.read(4))[0] # cell dims stored as float not long int

    for a in ('fast','med','slow'): 
        rho.axis[a] = unpack('=l',bmf.read(4))[0] 
        
    for d in ('min','max','mean'): 
        rho.density[d] = unpack('f',bmf.read(4))[0] 

    s = rho.getHeaderInfo()
    logfile.write(s)

    # next find .map file size, to calculate the last nx*ny*nz bytes of 
    # file (corresponding to the position of the 3D electron density 
    # array). Note factor of 4 is included since 4-byte floats used for 
    # electron density array values.
    filesize = os.path.getsize(dirIn+mapfilename)
    densitystart = filesize - 4*(reduce(lambda x, y: x*y, rho.nxyz.values()))
    
    # next seek start of electron density data
    bmf.seek(densitystart,0)
    
    # if electron density written in shorts (I don't think it will be 
    # but best to have this case)
    if rho.type is 1:  
        print 'Untested .map type --> 1 (type 2 expected). Values read' 
        + 'as int16 ("i2?") - consult .map header in MAPDUMP(CCP4) to check'
  
        struct_fmt = '=i2'
        struct_len = calcsize(struct_fmt)
        density = []
       
        while True:
            data = bmf.read(struct_len)
            if not data: break
            s = unpack(struct_fmt,data)[0]
            density.append(s)    

    # if electron density written in floats (which is to be expected 
    # from FFT-CCP4 outputted .map file of electron density)
    if rho.type is 2:  
        struct_fmt = '=f4'
        struct_len = calcsize(struct_fmt)
        density = []
        appenddens = density.append
        
        if maptype in ('atom_map'):
            atom_indices = []
            appendindex = atom_indices.append
            counter = -1
            while True:
                data = bmf.read(struct_len)
                if not data: break
                s = unpack(struct_fmt,data)[0]
                counter += 1
                if int(s) == 0:
                    continue
                else:    
                    appenddens(s)
                    appendindex(counter)
            print '# voxels in total : {}'.format(counter+1)

        # efficient way to read through density map file using indices of atoms
        # from atom map file above
        elif maptype in ('density_map'):
            for i in range(0,len(atom_indices)):
                if i != 0:
                    bmf.read(struct_len*(atom_indices[i]-atom_indices[i-1] - 1))
                else:
                    bmf.read(struct_len*(atom_indices[0]))
                    
                data = bmf.read(struct_len)
                s = unpack(struct_fmt,data)[0]
                appenddens(s)

            # check that resulting list of same length as atom_indices
            if len(density) != len(atom_indices):
                print 'Error in processing of density map using atom-tagged map'
                sys.exit()           
        else:
            print 'Unknown map type --> terminating script'
            sys.exit()

    logfile.close()           
    bmf.close()
    
    # as a check that file has been read correctly, check that the min 
    # and max electron density stated in .map file header correspond to 
    # calculated min and max here
    # Note for the case of atom map, the min voxel val will be 0 (no atom present)
    # --> since these voxels are removed during the filtering of the map, only 
    # the map value is tested.
    # For density map, cannot currently perform a check, since there is no 
    # guarantee that the max and min voxel values may be non atom voxels and
    # thus removed
    if maptype in ('atom_map'):      
        if max(density) == rho.density['max']:
            print 'calculated max voxel value match value stated in file header'
        else:
            print 'calculated max voxel value:{} does NOT match value stated in file header:{}'.format(max(density),rho.density['max'])
            sys.exit()
    
    # if each voxel value is an atom number, then want to convert to integer
    if maptype in ('atom_map'):
        density_final = [int(dens)/100 for dens in density]
    elif maptype in ('density_map'):
        density_final = density
    else:
        print 'Unknown map type --> terminating script'
        sys.exit()

    rho.vxls_val = density_final

    if maptype in ('atom_map'):
        return rho,atom_indices
    else:
        return rho