import chimera import os from chimera.baseDialog import ModelessDialog from chimera import UserError class MolsStack: """ class that created a stack using deep copy mols into the stack to save time to display them """ def __init__(self, initialMols, message = None): self.message = message # optional message function object, see class MultiFit_Dialog self.molsCopy = [] # this contains a deep copy of initialMols, so the class instance will not depends # on initialMols after initialization self.molsPool = [] # this is list of mols(list) for m in initialMols: from Molecule import copy_molecule self.molsCopy.append(copy_molecule(m)) def size(self): return len(self.molsPool) def elementSize(self): return len(self.molsCopy) def increase(self): mtmp = [] for m in self.molsCopy: from Molecule import copy_molecule mtmp.append(copy_molecule(m)) if self.message != None: self.message('Copying model %s ...' % m.name) self.molsPool.append(mtmp) if self.message != None: self.message('' ) def decrease(self): if self.size() == 0: return mtmp = self.molsPool.pop() for m in mtmp: m.destroy() def adjust(self, nset): while self.size() < nset: self.increase() while self.size() > nset and nset >= 0: self.decrease() def popMols(self): if self.size() == 0: self.increase() return self.molsPool.pop() def pushMols(self, mols): if len(mols) != self.elementSize(): print len(mols), "\t", self.elementSize() raise RuntimeError('the mols set in MolsStack has different lenth of the mols you push.') return self.molsPool.append(mols) class MultiFitResult(object): def __init__(self, volumeMap, index, tm, cc, color, message, molStack, transInvariant, AsbName): self.volumeMap = volumeMap self.index = index # int self.tm = tm self.cc = cc # float self._color = color self.message = message self.molStack = molStack self.transInvariant = transInvariant self.AsbName = "%s_%d" % (AsbName, self.index) self.molList = [] self.shown = False def getcolor(self): return self._color def setcolor(self, rgba): self._color = rgba for m in self.molList: m.color = self._color color = property(getcolor, setcolor) def show(self): """ show the result """ from Matrix import xform_matrix, chimera_xform, multiply_matrices from chimera import openModels self.molList = self.molStack.popMols() chimera.openModels.add(self.molList) for i, tf in enumerate(self.tm): subname = self.AsbName + ('_%d' %(i+1)) self.molList[i].name = subname if self.volumeMap and not self.volumeMap.__destroyed__: mv = xform_matrix(self.volumeMap.openState.xform) self.molList[i].openState.xform = chimera_xform( multiply_matrices( mv, tf, self.transInvariant[i] ) ) else: self.molList[i].openState.xform = chimera_xform( multiply_matrices( tf, self.transInvariant[i] ) ) for i, m in enumerate(self.molList): m.color = self.color for a in m.atoms: a.display = False for r in m.residues: r.ribbonDisplay = True self.shown = True def hide(self): """ hide the result """ if len(self.molList) == 0: return self.molStack.pushMols(self.molList) for m in self.molList: from chimera import openModels chimera.openModels.remove([m]) self.shown = False self.molList = [] class RunMultiFit: # This is actually an abstract base class. # Derived class needs to run MultiFit and call _fillResultTable def __init__(self, jobName, message, symmetry, molStack, transInvariant, resultTable, volumeMap): self.jobName = jobName self.message = message self.symmetry = symmetry self.molStack = molStack self.transInvariant = transInvariant self.resultTable = resultTable self.volumeMap = volumeMap def _fillResultTable(self, lines): """ converting lines to matrics, and fill the results table """ self.molStack.adjust(2) for line in lines: if self.symmetry: [ind,dock_rot_s,dock_trans_s,fit_rot_s,fit_trans_s,cc_s]=line.split("|") s=dock_rot_s.split(" ") s1=dock_trans_s.split(" ") dock_t = ( (float(s[0]),float(s[1]),float(s[2]),float(s1[0])), (float(s[3]),float(s[4]),float(s[5]),float(s1[1])), (float(s[6]),float(s[7]),float(s[8]),float(s1[2])) ) s=fit_rot_s.split(" ") s1=fit_trans_s.split(" ") fit_t = ( (float(s[0]),float(s[1]),float(s[2]),float(s1[0])), (float(s[3]),float(s[4]),float(s[5]),float(s1[1])), (float(s[6]),float(s[7]),float(s[8]),float(s1[2])) ) from Matrix import multiply_matrices tf = [] curr_t = dock_t for i in range(self.molStack.elementSize()): tf.append(curr_t) curr_t = multiply_matrices(dock_t, curr_t) transfMatrices = [multiply_matrices(fit_t, t) for t in tf] else: s = line.split("\t") ind = s[0] #cc_s = s[1] cc_s = "%f" % (1.0 - float(s[1])) # TODO use above line, if Keren using correlation instead of 1-cc tm = s[2].rstrip(' | ').split('|') transfMatrices = [] for i in range(len(tm)): fm = [float(m) for m in tm[i].strip().split(' ')] transfMatrices.append( ( (fm[0], fm[1], fm[2], fm[9] ), (fm[3], fm[4], fm[5], fm[10]), (fm[6], fm[7], fm[8], fm[11]) ) ) AsbName = '%s_fit_in_%s' % ( self.jobName[0].replace('.pdb','').replace('.PDB',''), self.jobName[1].replace('.mrc','').replace('.MRC','') ) import random col = chimera.MaterialColor(random.random(), random.random(), random.random(), 1.0) self.resultTable.data.append( MultiFitResult(self.volumeMap, int(ind), transfMatrices, float(cc_s), col, self.message, self.molStack, self.transInvariant, AsbName) ) self.resultTable.refresh() self.message('Click line(s) in the above results table to show the fitted model(s).') class RunMultiFitWS(RunMultiFit): def __init__(self, jobName, # Tuple (fitMols name, volume name) message, # message function to display message inputFileMap, # input file map symmetry, # bool, wheather symmetry or not molStack, # deep copy fitMols stacks transInvariant, # transformation invariant so user can freely move mol after # submiting the fitting job resultTable, # results table to be filled after running volumeMap = None, # volume map to be fitted, optional command = 'MultiFitConfig.xml', # Opal command parameters, the xml file name sessionData = None # for restore function, optional ): RunMultiFit.__init__(self, jobName, message, symmetry, molStack, transInvariant, resultTable, volumeMap) self.tempPath = os.path.dirname(inputFileMap["chem.lib"]) title = "MultiFit: %s to %s" %jobName from WebServices import appWebService serviceName = "MultiFitWebService" kw = dict() kw["finishTest"] = "multifit.chimera.output" kw["progressCB"] = self._progressCBWeb if sessionData: kw["sessionData"] = sessionData else: kw["params"] = (serviceName, title, inputFileMap, command) # TODO testing TESTING = False if TESTING: pkgdir = os.path.dirname(__file__) outputPath = os.path.join(pkgdir, 'test/output') if self.symmetry: outputFile = open(os.path.join(outputPath, "cn.multifit.chimera.output"), "r") else: outputFile = open(os.path.join(outputPath, "asym.multifit.chimera.output"), "r") lines = outputFile.read().strip().split('\n') self._fillResultTable(lines) else: self.ws = appWebService.AppWebService(self._wsFinish, **kw) def _wsFinish(self, opal, fileMap): data = opal.getURLContent(fileMap["multifit.chimera.output"]) foutput = open(os.path.join(self.tempPath, "multifit.chimera.output"), 'w') foutput.write(data) foutput.close() lines = data.strip().split('\n') if len(lines) > 1: self.message('Running MultiFit on web service completed, check the Results table...') self._fillResultTable(lines) def sessionData(self): return self.ws.sessionData() def _progressCBWeb(self, stdout): if stdout: fstdout = open(os.path.join(self.tempPath, 'stdout.txt'), 'w') fstdout.write(stdout) fstdout.close() count = 1.0 prog = 0.0 if self.symmetry: # for cn_multifit: counting the number of '*' under the progress bar # which allways start with '*'. if not, contact Keren for line in stdout.split('\n'): if line.startswith('*'): count += len(line) if count < 52.0: prog = 0.3 * count/53.0 else: prog = 0.3 + 0.68*(count - 51.0)/53.0 else: # for asym_multifit: just counting the number of '*' allstars = 51.0 * (self.molStack.elementSize() + 3) + 10.0 for line in stdout.split('\n'): # convert the each surface generating as 51/n '*'s if line.startswith('Surface Points number:'): count += 51.0 / self.molStack.elementSize() for c in stdout: if c == '*': count+=1 prog = count/allstars if prog > 1.0: prog = 0.99 self.message("Running MultiFit on web service: %d%% completed." %(prog*100)) return prog else: return 0.0 class RunMultiFitLocal(RunMultiFit): def __init__(self, message=None, msdotsPath=None, impPath=None, volumePath=None, volumeMap=None, resolution=None, pdbPath=None, fitMols=None, symmetry=True, resultTable=None): RunMultiFit.__init__(self, message, fitMols, symmetry, resultTable) self.msdotsPath = msdotsPath self.impPath = impPath self.volumePath = volumePath self.volumeMap = volumeMap self.resolution = resolution self.pdbPath = pdbPath # self.tempPath = os.path.dirname(self.pdbPath) self.pdbFileName = os.path.basename(self.pdbPath) self.volumeFileName = os.path.basename(self.volumePath) self.jobName = (self.pdbFileName[:-4], self.volumeFileName[:-4]) # #TODO --- remove the following lines after testing #self._fillResultTable(self._outputToLinesTest()) #return #TODO --- if self.genSurf_local(): self.modeling_local(self.genParms_local()) def genSurf_local(self): """ generate the surface using msdots, return the surface file location """ self.message('Generating the surface using msdots...') oldDir = os.getcwd() os.chdir(self.tempPath) cmd = '%s %s vdw.lib out 10.0 1.8' %(self.msdotsPath, self.pdbFileName) print 'now executing: \n %s' %cmd """ cmd = [] cmd.append(self.msdotsPath.get()) cmd.append('%s.pdb'%self.pdbFileName) cmd.append('vdw.lib') cmd.append('out') cmd.append('10.0') cmd.append('1.8') print 'now executing: ', cmd from chimera import SubprocessMonitor as SM from chimera.tasks import Task self.task = Task("Generate the surface using msdots for %s.pdb" %self.pdbFileName, None) self.task.updateStatus("Running msdots") try: subproc = SM.Popen(cmd, stdin=None, stdout=None, stderr=SM.PIPE, daemon=True) except OSError, e: raise UserError("Unable run msdots: %s" %e) finally: os.chdir(oldDir) subprog = SM.monitor('running msdots ...', subproc, title="MultiFit: surface generating", task=self.task, afterCB=self._msdotsCB) """ try: status = os.system(cmd) print 'status: %s' %status self.message('Done with generating the surface using msdots.') except OSError, e: raise UserError("Unable run msdots, got error %s\n when executing:\n %s" %(e, cmd)) finally: os.chdir(oldDir) if os.path.exists(os.path.join(self.tempPath, 'CONTACT')) and\ os.path.exists(os.path.join(self.tempPath, 'REENTRANT')): self.message('Merging the surface files ... ') print 'Surface Points number %d' %self._mergeSurfFile(self.tempPath, self.pdbFileName) if os.path.exists(os.path.join(self.tempPath, self.pdbFileName+'.ms')): return os.path.exists(os.path.join(self.tempPath, self.pdbFileName+'.ms')) def _msdotsCB(self, aborted): """ Call back funcion of SM.monitor in running msdots """ if aborted: self.task.finished() raise UserError('User abort the surface generating process.') self.message('User abort the surface generating process.') else: self.message('Done running msdots.') self.task.finished() return def _mergeSurfFile(self, path, fname): """ rewritten according to the runMSPoints.pl peal codes, merge the output files from msdots """ number = 0 fms = open(os.path.join(path, fname+'.ms'), 'w') for name in ['CONTACT', 'REENTRANT']: file = open(os.path.join(path, name), 'r') for line in file.readlines(): atom1 = int(line[0:5]) atom2 = int(line[5:10]) atom3 = int(line[10:15]) num = int(line[15:17]) px = float(line[17:26]) py = float(line[26:35]) pz = float(line[35:44]) sarea = float(line[44:51]) nx = float(line[51:58]) ny = float(line[58:65]) nz = float(line[65:72]) curv = int(line[72:74]) fms.write('%5d%5d%5d' %(atom1, atom2, atom3)) fms.write('%8.3f%8.3f%8.3f' %(px, py, pz)) fms.write('%8.3f' %sarea) fms.write('%7.3f%7.3f%7.3f' %(nx, ny, nz)) fms.write('%7.3f\n' %0.5) number += 1 file.close() fms.close() self.message('Done with merging the surface files ... ') return number def genParms_local(self): """ generate the parameters file using build_cn_multifit_params.py """ cmd = 'python build_cn_multifit_params.py ' cmd += '-o %s ' % os.path.join(self.tempPath, 'multifit.output') cmd += '-p %s ' % os.path.join(self.tempPath, 'multifit.param') cmd += '-l %s ' % os.path.join(self.tempPath, 'chem.lib') cmd += '-m %s ' % self.pdbFileName[:-4] cmd += '-- %s ' % len(self.fitMols) cmd += '%s ' % self.pdbPath cmd += '%s ' % self.volumePath cmd += '%s ' % self.resolution cmd += '%f ' % (sum(self.volumeMap.data.step)/len(self.volumeMap.data.step)) cmd += '%f ' % self.volumeMap.surface_levels[0] cmd += '%f %f %f' % self.volumeMap.data.origin print "Now executing: %s\n" %cmd # self.message('Copying the chem.lib into the temp folder ...') oldDir = os.getcwd() pkgdir = os.path.dirname(__file__) os.chdir(pkgdir) self.message('Generating the parameters file ...') try: status = os.system(cmd) except OSError, e: raise UserError("Unable run build_cn_multifit_params.py, got error %s\n" \ + "when executing:\n %s" %(e, cmd)) finally: os.chdir(oldDir) if os.path.exists(os.path.join(self.tempPath, 'multifit.param')): self.message('Done with generating the parameters file.') return os.path.join(self.tempPath, 'multifit.param') else: raise UserError("Error in running build_cn_multifit_params.py") def modeling_local(self, paramPath): """ Run the modeling procedure $IMP/tools/imppy.sh $IMP/modules/cn_multifit/bin/symmetric_multifit multifit.param """ imppyPath = os.path.join(self.impPath, 'tools/imppy.sh') cnMultiFitPath = os.path.join(self.impPath, 'modules/cn_multifit/bin/symmetric_multifit') stdoutPath = os.path.join(self.tempPath, 'stdout.txt') oldDir = os.getcwd() os.chdir(self.tempPath) """ cmd = '%s ' %imppyPath cmd += '%s ' %cnMultiFitPath cmd += '%s' %paramPath print "Now executing: %s\n" %cmd # self.message('Running the MultiFit modeling procedure ...') try: status = os.system(cmd) except OSError, e: raise UserError("Unable run msdots, got error %s\n when executing:\n %s" %(e, cmd)) return -1 finally: os.chdir(oldDir) # """ cmd = [] cmd.append(imppyPath) cmd.append(cnMultiFitPath) cmd.append(paramPath) cmd.append('--chimera') cmd.append('multifit.chimera.output') print "Now executing: ", " ".join(cmd) self.message('Now running MultiFit, check the task manager for status.') from chimera import SubprocessMonitor as SM from chimera.tasks import Task self.task = Task("MultiFit: %s to %s" %self.jobName, None) self.task.updateStatus("Running MultiFit locally") try: subproc = SM.Popen(cmd, stdin=None, stdout=None, stderr=SM.PIPE, daemon=True, progressCB = self._progressCB) except OSError, e: raise UserError("Unable run MultiFit: %s" %e) finally: os.chdir(oldDir) subprog = SM.monitor('Running MultiFit locally', subproc, title="MultiFit: %s to %s" %self.jobName, task=self.task, afterCB=self._collectResultsCB ) def _progressCB(self, inProgress): """ Based on the output files, estimate the progress of the modeling. """ if inProgress: if os.path.exists(os.path.join(self.tempPath, 'multifit.chimera.output')): return 0.99 fileList = os.listdir(self.tempPath) count = 1.0 # TODO make the measurment more accurate for f in fileList: if f.startswith(self.pdbFileName[-4]) and f.endswith('.pdb'): count+=1.0 fileTotal = 11.0 return count / fileTotal else: return 0.0 def _collectResultsCB(self, aborted): """ Call back funcion of SM.monitor """ if aborted: self.task.finished() raise UserError("User abort the MultiFit modeling.") self.message("User abort the MultiFit modeling.") else: outputFile = os.path.join(self.tempPath, 'multifit.chimera.output') if os.path.exists(outputFile): self.message('Done with running MultiFit; showing results ...') foutputFile = open(outputFile, 'r') lines = foutputFile.readlines() foutputFile.close() self._fillResultTable(lines) else: self.message('Error in running MultiFit locally!') self.task.finished() return def _outputToLinesTest(self): #TODO remove this function outputFile = open("/Users/proteinyang/Documents/research/project/MultiFitProject/examples/temp_folder/multifit.chimera.output", "r") return outputFile.readlines() def restoreRunMultiFitWS(title, sesData): RunMultiFitWS(title, sessionData=sesData)