def avgRmsd(self, cluster, aMask=None, threshold=0.): """ Claculate the average pairwise rmsd (in Angstrom) for members of a cluter. @param cluster: cluster number @type cluster: int @param aMask: atom mask applied before calculation @type aMask: [1|0] @param threshold: float 0-1, minimal cluster membership, see L{memberTraj()} @type threshold: float @return: average rmsd and the standard deviation @rtype: float, float """ try: rms = self.memberTraj(cluster, threshold).pairwiseRmsd(aMask) rms = aboveDiagonal(rms) except: rms = [] if len(N0.ravel(rms)) == 1: ## was: return N0.average(rms)[0], 0.0 return N0.average(rms), 0.0 if len(N0.ravel(rms)) == 0: return 0.0, 0.0 return N0.average(rms), SD(rms)
def calcReducedContacts( self, soln, c ): """ Get contact matrices and/or fnarc from reduced-atom models. @param soln: solution number @type soln: int @param c: Complex @type c: Complex """ if not (self.reduced_recs and self.reduced_ligs): return if not self.requested(c,'c_ratom_10','fnarc_10'): return try: ## create Complex with same orientation but reduced coordinates red_rec = self.reduced_recs[ c.rec_model.source ] red_lig = self.reduced_ligs[ c.lig_model.source ] red_com = Complex( red_rec, red_lig, c.ligandMatrix ) contacts = red_com.atomContacts( 10.0, cache=1 ) if self.requested(c, 'c_ratom_10'): c['c_ratom_10'] = MU.packBinaryMatrix(contacts) if self.c_ref_ratom_10 is not None: ref = N0.ravel( self.c_ref_ratom_10 ) c['fnarc_10'] = N0.sum( N0.ravel(contacts) * ref )\ / float( N0.sum(ref)) except: self.reportError('reduced contacts error', soln)
def __unmaskedMatrix(self, contacts, rec_mask, lig_mask): """ Map contacts between selected rec and lig atoms back to all atoms matrix. @param contacts: contact matrix, array sum_rec_mask x sum_lig_mask @type contacts: array @param rec_mask: atom mask @type rec_mask: [1|0] @param lig_mask: atom mask @type lig_mask: [1|0] @return: atom contact matrix, array N_atoms_rec x N_atoms_lig @rtype: array """ l_rec = len(self.rec_model) l_lig = len(self.lig_model) ## map contacts back to all atoms matrix r = N0.zeros(l_rec * l_lig) rMask = N0.ravel(N0.outerproduct(rec_mask, lig_mask)) ## (Optimization: nonzero is time consuming step) N0.put(r, N0.nonzero(rMask), N0.ravel(contacts)) return N0.resize(r, (l_rec, l_lig))
def calcReducedContacts(self, soln, c): """ Get contact matrices and/or fnarc from reduced-atom models. @param soln: solution number @type soln: int @param c: Complex @type c: Complex """ if not (self.reduced_recs and self.reduced_ligs): return if not self.requested(c, 'c_ratom_10', 'fnarc_10'): return try: ## create Complex with same orientation but reduced coordinates red_rec = self.reduced_recs[c.rec_model.source] red_lig = self.reduced_ligs[c.lig_model.source] red_com = Complex(red_rec, red_lig, c.ligandMatrix) contacts = red_com.atomContacts(10.0, cache=1) if self.requested(c, 'c_ratom_10'): c['c_ratom_10'] = MU.packBinaryMatrix(contacts) if self.c_ref_ratom_10 is not None: ref = N0.ravel(self.c_ref_ratom_10) c['fnarc_10'] = N0.sum( N0.ravel(contacts) * ref )\ / float( N0.sum(ref)) except: self.reportError('reduced contacts error', soln)
def takeMembers(self, mIndices): """ Take all frames belonging to the members in mIndices:: takeMembers( mIndices ) -> EnsembleTraj with frames of given members @param mIndices: list of member indices @type mIndices: [int] OR array('i') @return: EnsembleTraj with specified members @rtype: EnsembleTraj @todo: return self.__class__ instead of EnsembleTraj """ try: ## assumes that each member traj has same number of frames fi = N0.array([self.memberIndices(i) for i in mIndices]) fi = N0.ravel(N0.transpose(fi)) n_members = len(mIndices) ## has wrong n_members and member order t = self.takeFrames(fi) result = EnsembleTraj(n_members=n_members) result.__dict__.update(t.__dict__) result.n_members = n_members result.resetFrameNames() return result except TypeError: raise EnsembleTrajError, 'takeMembers TypeError '+\ str(mIndices)+\ "\nlenFrames: %i; n_members: %i" %(len(self), self.n_members)
def test_rmsFit(self): """rmsFit test""" import Biskit.tools as T self.traj = T.load(T.testRoot() + '/lig_pcr_00/traj.dat') rt, rmsdLst = match(self.traj.ref.xyz, self.traj[-1].xyz) if self.local: print 'RMSD: %.2f' % rmsdLst[0][1] # return rotation matrix r = abs(N0.sum(N0.ravel(rt[0]))) e = abs(N0.sum(N0.ravel(self.EXPECT))) self.assertAlmostEqual(r, e, 6)
def test_molTools(self): """molTools test""" from Biskit import PDBModel ## Loading PDB... self.m = PDBModel( T.testRoot() + '/lig/1A19.pdb' ) self.m = self.m.compress( self.m.maskProtein() ) hb = hbonds( self.m ) xyz = xyzOfNearestCovalentNeighbour( 40, self.m ) if self.local: print '\nThe nearest covalently attached atom to the' print ' atom with index 40 has the coordinates:' print xyz print 'Potential h-bonds in model:' print '(donor index, acceptor index, distance and angle)' for h in hb: print h globals().update( locals() ) self.r = N0.sum(N0.ravel(hb[3:5])) + N0.sum(xyz) self.assertAlmostEqual( self.r, self.EXPECT, 3 )
def test_ComplexTraj(self): """Dock.ComplexTraj test""" import Biskit.tools as T ## there is no complex trajectory in the test folder so will have ## to create a fake trajectory with a complex f = [T.testRoot() + '/com/1BGS.pdb'] * 5 t = Trajectory(f, verbose=self.local) t = ComplexTraj(t, recChains=[0]) #if self.local: #print 'plotting contact density...' #t.plotContactDensity( step=2 ) ## create a fake second chain in the ligand for i in range(1093 + 98, 1968): t.ref.atoms['chain_id'][i] = 'B' t.ref.chainIndex(force=1, cache=1) t.cl = [1, 2] r = N0.concatenate((range(1093, 1191), range(0, 1093), range(1191, 1968))) tt = t.takeAtoms(r) contactMat = tt.atomContacts(1) if self.local: print 'Receptor chains: %s Ligand chains: %s' % (t.cr, t.cl) self.assertEqual(N0.sum(N0.ravel(contactMat)), 308)
def test_molTools(self): """molTools test""" from Biskit import PDBModel ## Loading PDB... self.m = PDBModel(T.testRoot() + '/lig/1A19.pdb') self.m = self.m.compress(self.m.maskProtein()) hb = hbonds(self.m) xyz = xyzOfNearestCovalentNeighbour(40, self.m) if self.local: print '\nThe nearest covalently attached atom to the' print ' atom with index 40 has the coordinates:' print xyz print 'Potential h-bonds in model:' print '(donor index, acceptor index, distance and angle)' for h in hb: print h globals().update(locals()) self.r = N0.sum(N0.ravel(hb[3:5])) + N0.sum(xyz) self.assertAlmostEqual(self.r, self.EXPECT, 3)
def random_contacts( self, contMat, n, maskRec=None, maskLig=None ): """ Create randomized surface contact matrix with same number of contacts and same shape as given contact matrix. @param contMat: template contact matrix @type contMat: matrix @param n: number of matrices to generate @type n: int @param maskRec: surface masks (or something similar) @type maskRec: [1|0] @param maskLig: surface masks (or something similar) @type maskLig: [1|0] @return: list of [n] random contact matricies @rtype: [matrix] """ a,b = N0.shape( contMat ) nContacts = N0.sum( N0.sum( contMat )) if not maskLig: r_size, l_size = N0.shape( contMat ) maskLig = N0.ones( l_size ) maskRec = N0.ones( r_size ) c_mask = N0.ravel( N0.outerproduct( maskRec, maskLig ) ) c_pos = N0.nonzero( c_mask ) # get array with surface positions from complex cont = N0.take( N0.ravel(contMat), c_pos ) length = len( cont ) result = [] for i in range( n ): # create random array ranCont = mathUtils.randomMask( nContacts,length ) # blow up to size of original matrix r = N0.zeros(a*b) N0.put( r, c_pos, ranCont) result += [ N0.reshape( r, (a,b) ) ] return result
def plotContactDensity(self, step=1, cutoff=4.5): """ Example. plot histogramm of contact density. Somehing wrong?? @raise ComplexTrajError: if gnuplot program is not installed """ if not gnuplot.installed: raise ComplexTrajError, 'gnuplot program is not installed' r = self.averageContacts(step, cutoff) r = N0.ravel(r) r = N0.compress(r, r) gnuplot.plot(hist.density(r, 10))
def calcContacts( self, soln, c ): """ Calculate contact matrices and fraction of native contacts, residue- and atom-based, with different distance cutoffs. @param soln: solution number @type soln: int @param c: Complex @type c: Complex """ try: if self.requested(c, 'fnac_4.5') and self.c_ref_atom_4_5 is not None: ## cache pairwise atom distances for following calculations contacts = c.atomContacts( 4.5, self.mask_rec, self.mask_lig, cache=1, map_back=0 ) ref = N0.ravel( self.c_ref_atom_4_5 ) c['fnac_4.5'] = N0.sum( N0.ravel(contacts) * ref )\ / float( N0.sum(ref)) if self.requested(c, 'fnac_10') and self.c_ref_atom_10 is not None: contacts = c.atomContacts( 10., self.mask_rec, self.mask_lig, cache=1, map_back=0 ) ref = N0.ravel( self.c_ref_atom_10 ) c['fnac_10'] = N0.sum( N0.ravel(contacts) * ref ) \ / float( N0.sum(ref)) if self.requested(c, 'c_res_4.5') \ or ( self.c_ref_res_4_5 is not None \ and (self.requested(c,'fnrc_4.5','fnSurf_rec'))): res_cont = c.resContacts( 4.5, cache=self.requested(c, 'c_res_4.5')) if self.c_ref_res_4_5 is not None \ and self.requested(c, 'fnrc_4.5' ): ref = N0.ravel( self.c_ref_res_4_5 ) c['fnrc_4.5'] = N0.sum(N0.ravel(res_cont)*ref) \ /float(N0.sum(ref)) if self.c_ref_res_4_5 is not None \ and self.requested(c, 'fnSurf_rec'): r, l = c.fractionNativeSurface(res_cont, self.c_ref_res_4_5 ) c['fnSurf_rec'] = r c['fnSurf_lig'] = l except: m1 = m2 = s = 0 try: m1, m2, s = c.get('model1',0), c.get('model2',0),\ c.get('soln',0) except: pass self.reportError('contact error (r %i : l %i, #%i)'%\ (m1,m2,s), soln)
def __init__(self, models, name=None, profileName='relAS', verbose=1): """ @param models: List of models display a Ramachandran plot for @type models: [ PDBModel ] OR PDBModel @param name: model name, will show up in plot @type name: str @param profileName: name of profile to use for coloring (default: 'relAS') @type profileName: str @param verbose: verbosity level (default: 1) @type verbose: 1|0 """ if not biggles: raise ImportError, 'biggles module could not be imported.' if type(models) != type([]): models = [models] self.psi = [] self.phi = [] self.gly = [] self.pro = [] self.prof = [] self.profileName = profileName self.name = name self.verbose = verbose # calculate angles, profiles ... self.calc(models) self.prof = N0.ravel(self.prof) self.gly = N0.ravel(self.gly) self.pro = N0.ravel(self.pro)
def getFirstCrdLine(self): """ Return the first line of Amber crd. @return: first line of Amber crd formatted coordinate block @rtype: str """ if not self.xyz: self.getXyz() result = "" for x in N0.ravel(self.xyz)[:10]: result += "%8.3f" % x return result + "\n"
def changeModel(inFile, prefix, sourceModel): print '\nget ' + os.path.basename(inFile) + '..', model = PDBModel(inFile) model.update() model = model.sort() eq = model.equals(sourceModel) if not eq[0] and eq[1]: raise ConvertError('source and other models are not equal: ' + str(eq)) # model.validSource() model.setSource(sourceModel.validSource()) #model.atomsChanged = 0 for k in model.atoms: model.atoms[k, 'changed'] = N0.all(model[k] == sourceModel[k]) model.xyzChanged = (0 != N0.sum(N0.ravel(model.xyz - sourceModel.xyz))) model.update(updateMissing=1) if model.xyzChanged: doper = PDBDope(model) if 'MS' in sourceModel.atoms.keys(): doper.addSurfaceRacer(probe=1.4) if 'density' in sourceModel.atoms.keys(): doper.addDensity() if 'foldX' in sourceModel.info.keys(): doper.addFoldX() if 'delphi' in sourceModel.info.keys(): doper.addDelphi() outFile = os.path.dirname( inFile ) + '/' + prefix +\ T.stripFilename( inFile ) + '.model' T.dump(model, outFile) print '-> ' + os.path.basename(outFile)
def changeModel( inFile, prefix, sourceModel ): print '\nget ' + os.path.basename( inFile ) + '..', model = PDBModel( inFile ) model.update() model = model.sort() eq = model.equals( sourceModel ) if not eq[0] and eq[1]: raise ConvertError('source and other models are not equal: ' + str(eq)) # model.validSource() model.setSource( sourceModel.validSource() ) #model.atomsChanged = 0 for k in model.atoms: model.atoms[k,'changed'] = N0.all( model[k] == sourceModel[k] ) model.xyzChanged = ( 0 != N0.sum( N0.ravel( model.xyz - sourceModel.xyz)) ) model.update( updateMissing=1 ) if model.xyzChanged: doper = PDBDope( model ) if 'MS' in sourceModel.atoms.keys(): doper.addSurfaceRacer( probe=1.4 ) if 'density' in sourceModel.atoms.keys(): doper.addDensity() ## if 'foldX' in sourceModel.info.keys(): ## doper.addFoldX() if 'delphi' in sourceModel.info.keys(): doper.addDelphi() outFile = os.path.dirname( inFile ) + '/' + prefix +\ T.stripFilename( inFile ) + '.model' T.dump( model, outFile ) print '-> ' + os.path.basename( outFile )
def writeCrd(self, fcrd, append=1, lastAtom=None): """ Write/Append Amber-formatted block of coordinates to a file. If a file handle is given, the file will not be closed. @param fcrd: file to write to @type fcrd: str or file object @param append: append to existing file (default: 1) @type append: 0|1 @param lastAtom: skip all atoms beyond this one (default: None) @type lastAtom: int """ if not self.xyz: self.getXyz() if type(fcrd) == file: ## take file handle f = fcrd else: ## create new file handle mode = 'w' if append: mode = 'a' f = open(T.absfile(fcrd), mode) newf = (mode == 'w' or not os.path.exists(T.absfile(fcrd))) if newf: f.write("\n") i = 0 for x in N0.ravel(self.xyz): i = i + 1 f.write("%8.3f" % x) if (i % 10) == 0: f.write("\n") if lastAtom and i / 3.0 == lastAtom: break if ((i % 10) != 0): f.write("\n") if type(fcrd) != file: ## don't close file that was already given f.close()
def color_array( self, a, resetLimits=1 ): """ @param a: array of float @type a: array of float @param resetLimits: re-define color range on max and min of values (default: 1) @type resetLimits: 1|0 @return: matrix of color codes with same dimensions as a @rtype: array of float """ s = N0.shape( a ) v = N0.ravel( a ) r = self.colors( v, resetLimits=resetLimits ) r = N0.reshape( r, s ) return r
def slim(self): """ Remove coordinates and atoms of ligand and receptor from memory, if they can be restored from file, compress contact matrix. @note: CALLED BEFORE PICKLING """ self.lig_transformed = None self.pw_dist = None ## self.ligandMatrix = self.ligandMatrix.tolist() if 'matrix' in self.info: del self.info['matrix'] ## compress contact matrix array if self.contacts is not None and \ len(N0.shape( self.contacts['result'] ) )==2: m = self.contacts['result'] self.contacts['shape'] = N0.shape(m) self.contacts['result'] = N0.nonzero(N0.ravel(m)).astype(N0.Int32)
def calcRmsd(self, window, f1, f2): """ Calulate the rmsd between two frame chunks. @param window: start and end of two frame chunks within the whole trajectory @type window: ((int, int),(int,int)) @param f1: frame chunk @type f1: array @param f2: frame chunk @type f2: array @return: the rms between the frames @rtype: [float] """ try: i_start, i_stop = window[0] j_start, j_stop = window[1] a = N0.zeros((i_stop - i_start, j_stop - j_start), N0.Float) i = j = -1 ## block on the diagonal, only calculate one half of it S = (self.only_off_diagonal and window[0] == window[1]) for i in range(i_start, i_stop): for j in range(S * i - S * j_start + j_start, j_stop): if self.requested(i, j): rt, rmsdLst = rmsFit.match(f1[i - i_start], f2[j - j_start], 1) a[i - i_start, j - j_start] = rmsdLst[0][1] return N0.ravel(a).tolist() except Exception, why: self.reportError('ERROR ' + str(why), (i, j)) return
def calcRmsd( self, window, f1, f2 ): """ Calulate the rmsd between two frame chunks. @param window: start and end of two frame chunks within the whole trajectory @type window: ((int, int),(int,int)) @param f1: frame chunk @type f1: array @param f2: frame chunk @type f2: array @return: the rms between the frames @rtype: [float] """ try: i_start, i_stop = window[0] j_start, j_stop = window[1] a = N0.zeros( (i_stop-i_start, j_stop-j_start), N0.Float ) i = j = -1 ## block on the diagonal, only calculate one half of it S = (self.only_off_diagonal and window[0] == window[1]) for i in range( i_start, i_stop ): for j in range( S * i - S * j_start + j_start, j_stop ): if self.requested( i, j ): rt, rmsdLst = rmsFit.match( f1[i-i_start], f2[j-j_start], 1 ) a[i-i_start,j-j_start] = rmsdLst[0][1] return N0.ravel(a).tolist() except Exception, why: self.reportError( 'ERROR '+str(why), (i,j) ) return
def writeCrd( self, fname, frames=None ): """ Write frames to Amber crd file (w/o box info). @param fname: output file name @type fname: str @param frames: frame indices (default: all) @type frames: [int] """ if frames is None: frames = range( self.lenFrames() ) template = " %7.3f" * 10 + '\n' ## open new file out = open( T.absfile(fname), 'w') __write = out.write ## cache function address for speed __write('\n') n_lines = None for fi in frames: f = N0.ravel( self.frames[ fi ] ) if n_lines is None: n_lines = n_lines or len( f ) / 10 overhang= ( 0 != len( f ) % 10 ) i_lines = range( n_lines ) for i in i_lines: __write( template % tuple( f[10*i:10*i+10] ) ) if overhang: for x in f[i*10+10:]: __write(" %7.3f" % x ) __write('\n') out.close()
def thin(self, step=1): """ Keep only each step'th frame from trajectory with 10 ensemble members. @param step: 1..keep all frames, 2..skip first and every second, .. (default: 1) @type step: int @return: reduced EnsembleTraj @rtype: EnsembleTraj """ T.ensure(step, int, forbidden=[0]) ## 10 x lenFrames/10, frame indices of each member mI = [self.memberIndices(i) for i in range(self.n_members)] mI = N0.array(mI) mI = N0.take(mI, range(-1, N0.shape(mI)[1], step)[1:], 1) mI = N0.transpose(mI) return self.takeFrames(N0.ravel(mI))
def pcMovie( self, ev, steps, factor=1., ref=0, morph=1 ): """ Morph between the two extreme values of a single principal component. @param ev: EigenVector to visualize @type ev: int @param steps: number of intermediate frames @type steps: int @param factor: exageration factor (default: 1 = No exageration) @type factor: float @param ref: take other eigenvecors from this frame (default: 1) @type ref: int @param morph: morph between min and max (1) or take real values (0) (default: 1) @type morph: 1|0 @return: Trajectory with frames visualizing the morphing. @rtype: Trajectory """ fit = 1 if self.pc is not None: fit = self.pc['fit'] pc = self.getPca( fit=fit ) ## eigenvectors (rows) U = pc['u'] ## raveled and centered frames x_avg = N0.average(self.frames, 0) X = N0.array( [N0.ravel(x) for x in self.frames - x_avg] ) ## ev'th eigenvector of reference frame alpha_0 = N0.dot( X[ref], U[ev] ) ## list of deviations of ev'th eigenvector of each frame from ref alpha_range = N0.dot(X, U[ev]) - alpha_0 ## get some representative alphas... if morph: a_min = factor * min(alpha_range) a_max = factor * max(alpha_range) delta = (a_max - a_min) / steps alpha_range = [ a_min + i*(delta) for i in range(0, steps) ] else: alpha_range = N0.sort( alpha_range ) delta = len(alpha_range) / (steps * 1.0) alpha_range = [ alpha_range[ int(round( i*delta )) ] for i in range(0,steps) ] ## scale ev'th eigenvector of ref with different alphas Y = N0.array( [ X[ref] + alpha * U[ev] for alpha in alpha_range] ) ## back convert to N x 3 coordinates Y = N0.reshape(Y, (Y.shape[0], -1, 3)) Y = x_avg + Y result = self.__class__() result.ref = self.ref result.frames = Y return result
def calcContacts(self, soln, c): """ Calculate contact matrices and fraction of native contacts, residue- and atom-based, with different distance cutoffs. @param soln: solution number @type soln: int @param c: Complex @type c: Complex """ try: if self.requested(c, 'fnac_4.5') and self.c_ref_atom_4_5 is not None: ## cache pairwise atom distances for following calculations contacts = c.atomContacts(4.5, self.mask_rec, self.mask_lig, cache=1, map_back=0) ref = N0.ravel(self.c_ref_atom_4_5) c['fnac_4.5'] = N0.sum( N0.ravel(contacts) * ref )\ / float( N0.sum(ref)) if self.requested(c, 'fnac_10') and self.c_ref_atom_10 is not None: contacts = c.atomContacts(10., self.mask_rec, self.mask_lig, cache=1, map_back=0) ref = N0.ravel(self.c_ref_atom_10) c['fnac_10'] = N0.sum( N0.ravel(contacts) * ref ) \ / float( N0.sum(ref)) if self.requested(c, 'c_res_4.5') \ or ( self.c_ref_res_4_5 is not None \ and (self.requested(c,'fnrc_4.5','fnSurf_rec'))): res_cont = c.resContacts(4.5, cache=self.requested(c, 'c_res_4.5')) if self.c_ref_res_4_5 is not None \ and self.requested(c, 'fnrc_4.5' ): ref = N0.ravel(self.c_ref_res_4_5) c['fnrc_4.5'] = N0.sum(N0.ravel(res_cont)*ref) \ /float(N0.sum(ref)) if self.c_ref_res_4_5 is not None \ and self.requested(c, 'fnSurf_rec'): r, l = c.fractionNativeSurface(res_cont, self.c_ref_res_4_5) c['fnSurf_rec'] = r c['fnSurf_lig'] = l except: m1 = m2 = s = 0 try: m1, m2, s = c.get('model1',0), c.get('model2',0),\ c.get('soln',0) except: pass self.reportError('contact error (r %i : l %i, #%i)'%\ (m1,m2,s), soln)
def conservationScore(self, cons_type='cons_ent', ranNr=150, log=StdLog(), verbose=1): """ Score of conserved residue pairs in the interaction surface. Optionally, normalized by radom surface contacts. @param cons_type: precalculated conservation profile name, see L{Biskit.PDBDope}. @type cons_type: str @param ranNr: number of random matricies to use (default: 150) @type ranNr: int @param log: log file [STDOUT] @type log: Biskit.LogFile @param verbose: give progress report [1] @type verbose: bool | int @return: conservation score @rtype: float """ try: recCons = self.rec().profile(cons_type, updateMissing=1) except: if verbose: log.add('\n'+'*'*30+'\nNO HHM PROFILE FOR RECEPTOR\n'+\ '*'*30+'\n') recCons = N0.ones(self.rec().lenResidues()) try: ligCons = self.lig().profile(cons_type, updateMissing=1) except: if verbose: log.add(\ '\n'+'*'*30+'\nNO HHM PROFILE FOR LIGAND\n'+'*'*30+'\n') ligCons = N0.ones(self.lig().lenResidues()) if self.rec().profile('surfMask'): recSurf = self.rec().profile('surfMask') else: d = PDBDope(self.rec()) d.addSurfaceMask() if self.lig().profile('surfMask'): ligSurf = self.lig().profile('surfMask') else: d = PDBDope(self.lig()) d.addSurfaceMask() surfMask = N0.ravel(N0.outerproduct(recSurf, ligSurf)) missing = N0.outerproduct(N0.equal(recCons, 0), N0.equal(ligCons, 0)) cont = self.resContacts() * N0.logical_not(missing) consMat = N0.outerproduct(recCons, ligCons) score = cont * consMat # get a random score if ranNr != 0: if self.verbose: self.log.write('.') ranMat = mathUtils.random2DArray(cont, ranNr, mask=surfMask) random_score = N0.sum(N0.sum(ranMat * consMat)) / (ranNr * 1.0) return N0.sum(N0.sum(score)) / random_score else: return N0.sum(N0.sum(score)) / N0.sum(N0.sum(cont))