def compare( project1, project2 ): """Compare the shifts of all equivalent atoms. """ if project1 is None or project1.molecule is None: return True if project2 is None or project2.molecule is None: return True mol1 = project1.molecule mol2 = project2.molecule nTmessage('==> comparing %s and %s\n', mol1, mol2) mapMolecule(mol1, mol2) for atm1 in mol1.allAtoms(): if atm1.has_key('delta'): del(atm1['delta']) #end for for atm1 in mol1.allAtoms(): compareAtms(atm1, atm1.map) #end for # average; taken the values of directly bonded atoms into account for atm in mol1.allAtoms(): average(atm) #end for # generate scripts mkYasaraMacro(mol1, 'delta', sprintf('yasara-%s-%s.mcr', project1.name, project2.name)) mkYasaraMacro(mol1, 'deltaAverage', sprintf('yasara-%s-%s-averaged.mcr', project1.name, project2.name))
def mkYasaraMacro(mol, attr, path): """Create a Yasara macro using attr """ nTmessage('==> Creating macro %s\n', path) yasara = open(path, 'w') fprintf(yasara, 'Console off\n') fprintf(yasara, 'ColorAtom All,Gray\n') fprintf(yasara, 'PropAtom All,-999\n') for atm in mol.allAtoms(): an = atm.translate('PDB') # tmp hack, convert to YASARA format since PDB HB3 does not work if an and an[0:1].isdigit(): an = an[1:] #end if # print atm, an if an and atm.has_key(attr): # print '>',atm[attr] a = 1.0 - atm[attr] a = max( a, 0.0 ) fprintf(yasara, 'PropAtom residue %d atom %s,%.2f\n', atm.residue.resNum, an, a) #end if #end for fprintf(yasara, 'Console off\n') fprintf(yasara, 'ColorAll Property\n') fprintf(yasara, 'Console on\n') yasara.close()
def setToSingleCoreOperation(): 'Set the cing attribute .ncpus to 1' if cing.ncpus > 1: nTmessage("Scaling back to single core operations.") cing.ncpus = 1 return nTmessage("Maintaining single core operations.")
def restoreQueeny100( project, tmp=None ): """ Restore queeny results from sml file. Return True on error """ if project is None: nTmessage("restoreQueeny100: No project defined") return True if project.molecule is None: return False # Gracefully returns queenyDefs = project.getStatusDict(constants.QUEENY_KEY) if not queenyDefs.completed: # old definition nTdebug('restoreQueeny100: no queeny completed') return False # Return gracefully path = project.validationPath( 'Queeny') if not path.exists(): ntu.nTwarning('restoreQueeny100: directory "%s" with prior queeny data not found', path) else: # delete the data and run again os.rename(path, project.path() / cdefs.directories.version1 / 'Queeny') #end if # regenerate the data project.runQueeny() nTmessage('restoreQueeny100: Re-generated Queeny results') return False
def calculatePairWiseRmsd( mol1, mol2, ranges=None ): """Calculate pairwise rmsd between mol1 and mol2 Optionally use ranges for the fitting """ #Use ranges routines to define fitAtoms ed fitResidues1 = mol1.setResiduesFromRanges(ranges) mol1.selectFitAtoms( fitResidues1, backboneOnly=True, includeProtons = False ) fitResidues2 = mol2.setResiduesFromRanges(ranges) mol2.selectFitAtoms( fitResidues2, backboneOnly=True, includeProtons = False ) # mol2.superpose( ranges ) l1 = len(mol1.ensemble) l2 = len(mol2.ensemble) if ( l1 == 0 or len(mol1.ensemble[0].fitCoordinates) == 0 or l2 == 0 or len(mol2.ensemble[0].fitCoordinates) == 0 or len(mol1.ensemble[0].fitCoordinates) != len(mol2.ensemble[0].fitCoordinates) ): nTdebug( ">calculatePairWiseRmsd> returning None, %s %s %s" , l1, l2, ranges) return None, None, None, None models = mol1.ensemble + mol2.ensemble result = NTlistOfLists(len(models), len(models), 0.0) nTmessage('==> Calculating pairwise rmsds %s %s', mol1, mol2) for i in range(len(models)): for j in range(i+1, len(models)): result[i][j] = models[i].superpose( models[j] ) result[j][i] = result[i][j] #end for #end for pairwise1 = NTlist() for i in range(l1): for j in range(i+1, l1): pairwise1.append(result[i][j]) # print '1>', i,j pairwise2 = NTlist() for i in range(l1, l1+l2): for j in range(i+1, l1+l2): pairwise2.append(result[i][j]) # print '2>', i,j pairwise12 = NTlist() for i in range(l1): for j in range(l1, l1+l2): pairwise12.append(result[i][j]) # print '12>', i,j # print len(pairwise1), len(pairwise2), len(pairwise12) return ( result, pairwise1.average2(fmt='%6.2f +- %5.2f'),pairwise2.average2(fmt='%6.2f +- %5.2f'), pairwise12.average2(fmt='%6.2f +- %5.2f'))
def upgrade100(project, restore): """ Do all things to upgrade project to current configuration All versions <= 1.00 """ nTmessage('*** upgrade100: upgrading %s from version %s ***', project, project.version) verbosity = cing.verbosity # make sure we get all if we heave debug on if cing.verbosity < cing.verbosityDebug: cing.verbosity = cing.verbosityWarning # Molecules for molName in project.moleculeNames: pathName = project.molecules.path(molName) mol = Molecule.open(pathName) if mol: mol.status = 'keep' project.appendMolecule(mol) #end if nTdebug('upgrade100: restored %s', mol) #end for # restore the lists for pl in [project.peaks, project.distances, project.dihedrals, project.rdcs, project.coplanars]: pl.restore() #end for # Now patch talos+ nTmessage('==> upgrade100: talosPlus') if restoreTalosPlus100(project): io.error('upgrade100: restoring talosPlus data failed\n') # Now patch queeny # nTmessage('==> upgrade100: queeny') # if restoreQueeny100(project): # nTerror('upgrade100: restoring queeny data failed') # project.saveQueeny() # # # Now patch shiftx # if restoreShiftx100(project): # nTerror('upgrade100: restoring shiftx data failed') # return None # project.saveShiftx() # Plugin registered functions nTdebug('upgrade100: calling plugins') project._callPluginRestores() # save to consolidate project.save() cing.verbosity = verbosity return Project.open(project.name, constants.PROJECT_OLD, restore=restore)
def parseShiftx(project, tmp=None): """ Parse the output generated by the shiftx program """ if project is None: nTmessage("parseShiftx: No project defined") return True if project.molecule is None: nTmessage("parseShiftx: No molecule defined") return True defs = project.getStatusDict(constants.SHIFTX_KEY, **shiftxStatus()) if not defs.completed: nTmessage("parseShiftx: No shiftx was run") return True path = project.validationPath(defs.directory) if not path: nTerror('parseShiftx: directory "%s" with shiftx data not found', path) return True _resetShiftx(project) # print '>>', defs, len(defs.chains) for chainId, fname in defs.chains: if _parseShiftxOutput(path / fname, project, chainId): return True # end for defs.parsed = True _calculatePseudoAtomShifts(project, len(defs.models)) _averageShiftx(project) calcQshift(project) return False
def talosPlus2restraints( project, name=constants.TALOSPLUS_LIST_STR, status='noRefine', errorFactor=2.0 ): """ Convert talos+ results to a CING dihedral restraint list """ if project == None: nTmessage("talosPlus2restraints: No project defined") return True if project.molecule == None: nTmessage("talosPlus2restraints: No project defined") return True if not project.status.has_key('talosPlus') or not project.status.talosPlus.completed: nTmessage("talosPlus2restraints: No talos+ data") return True if name in project.dihedrals.names(): project.dihedrals.delete(name) dhl = project.dihedrals.new(name=name, status=status) for res in project.molecule.allResidues(): if res.talosPlus and res.talosPlus.classification=='Good': lower = res.talosPlus.phi.value-errorFactor*res.talosPlus.phi.error upper = res.talosPlus.phi.value+errorFactor*res.talosPlus.phi.error atoms = getDeepByKeysOrAttributes( res, constants.PHI_STR, constants.ATOMS_STR ) if atoms: d = DihedralRestraint(atoms, lower, upper) dhl.append(d) lower = res.talosPlus.psi.value-errorFactor*res.talosPlus.psi.error upper = res.talosPlus.psi.value+errorFactor*res.talosPlus.psi.error atoms = getDeepByKeysOrAttributes( res, constants.PSI_STR, constants.ATOMS_STR ) if atoms: d = DihedralRestraint(atoms, lower, upper) dhl.append(d) #end if #end for nTmessage('==> Created %s', dhl)
def calcQshift(project): """Calculate per residue Q factors between assignment and shiftx results """ if project is None: nTmessage("calcQshift: no project defined") return None # end if if not project.molecule: nTmessage("calcQshift: no molecule defined") return None # end if nTdetail("==> Calculating Q-factors for chemical shift") for res in project.molecule.allResidues(): atms = res.allAtoms() bb = NTlist() heavy = NTlist() protons = NTlist() for a in atms: if a.isBackbone(): bb.append(a) if a.isProton(): protons.append(a) else: heavy.append(a) # end for result = project.validationData.getResult(res, constants.SHIFTX_KEY, QshiftxResult()) if result is None: nTmessage("calcQshift: error setting QshiftResult for residue %s", res) return None # end if result[QshiftxResult.ALL_ATOMS] = _calcQshift(project, atms) result[QshiftxResult.BACKBONE] = _calcQshift(project, bb) result[QshiftxResult.HEAVY_ATOMS] = _calcQshift(project, heavy) result[QshiftxResult.PROTONS] = _calcQshift(project, protons) # LEGACY qshiftDict = legacyQshiftDict() for k in [QshiftxResult.ALL_ATOMS, QshiftxResult.BACKBONE, QshiftxResult.HEAVY_ATOMS, QshiftxResult.PROTONS]: qshiftDict[k] = result[k] qshiftDict["residue"] = res res.Qshift = qshiftDict
def _runQueeny( project, tmp=None ): """Perform a queeny analysis and save the results. Returns True on error. Returns False when all is fine. """ nTmessage("==> Calculating restraint information by Queeny") if project is None: nTerror("runQueeny: No project defined") return True if project.molecule is None: nTerror("runQueeny: No molecule defined") return True if len(project.distances) == 0: nTmessage("==> runQueeny: No distance restraints defined.") return True queenyDefs = project.getStatusDict(constants.QUEENY_KEY, **queenyDefaults()) queenyDefs.molecule = project.molecule.asPid path = project.validationPath( queenyDefs.directory ) if not path: nTmessage("==> runQueeny: error creating '%s'", path) return True q = Queeny( project ) q.execute() queenyDefs.date = io.now() queenyDefs.completed = True queenyDefs.parsed = True queenyDefs.version = __version__ del(q) return False
def initRestraints( self ): """ Initialize restraints from restraint lists Only distances for now """ nTmessage('==> Queeny adding restraints (# elements = %d)', len(self)) for dme in self.itervalues(): dme.upperChange = 0.0 #end for nkeys = len(self) #print '>', nkeys # count = 0 for drl in self.project.distances: for dr in drl: if len(dr.atomPairs) == 1: atm1,atm2 = dr.atomPairs[0] upper = dr.upper if dr.upper is None: # sometimes happens; i.e. entry 1but upper = DmElement.upperDefault lower = dr.lower if dr.lower is None: # lower values sometimes set to None lower = DmElement.lowerDefault self.initDmElement(atm1, atm2, lower, upper) else: # ambiguous restraints rm6distances = self._calculateAverage( dr ) if rm6distances is None: nTwarning('Queeny.initRestraints: failure to analyze %s', dr) break #endif upper = dr.upper if dr.upper is None: # sometimes happens; i.e. entry 1but upper = DmElement.upperDefault lower = dr.lower if dr.lower is None: # lower values sometimes set to None lower = DmElement.lowerDefault # hr: total uncertainty change associated with this restraint # dH = hmax - hr : change in uncertainty # hi = hmax - dH*frac : relative R-6 contribution of atom pair: sum(hi) = hr hmax = DmElement.uncertaintyDefault hr = math.log(upper-lower) dH = hmax - hr pair = 0 for atm1,atm2 in dr.atomPairs: hi = hmax - rm6distances[pair]*dH self.initDmElement(atm1, atm2, lower, lower+math.exp(hi)) pair += 1 #end for #end if # count += 1 #end for #end for # nTdebug('Queeny.initRestraints: %d restraints added (# elements = %d)', count, len(self)) self.setNeighbors(nkeys) # update the neighbors for newly added
def runShiftx(project, parseOnly=False, model=None): """ Use shiftx program to predict chemical shifts Works only for protein residues. Adds ShiftxResult instance to validation container of atoms LEGACY: Adds a NTlist object with predicted values for each model as shiftx attribute to each atom for which there are predictions, or empty list otherwise. Throws warnings for non-protein residues. Returns True on error. Shiftx works on pdb files, uses only one model (first), so we have to write the files separately and analyze them one at the time. """ # LEGACY: if parseOnly: return parseShiftx(project) if cdefs.cingPaths.shiftx is None: nTmessage("runShiftx: no shiftx executable, skipping") return False # Gracefully return if project.molecule is None: nTerror("runShiftx: no molecule defined") return True if project.molecule.modelCount == 0: nTwarning('runShiftx: no models for "%s"', project.molecule) return True if model is not None and model >= project.molecule.modelCount: nTerror('runShiftx: invalid model (%d) for "%s"', model, project.molecule) return True if not project.molecule.hasAminoAcid(): nTmessage("==> Skipping runShiftx because no amino acids are present.") return False nTmessage("==> Running shiftx") skippedAtoms = [] # Keep a list of skipped atoms for later skippedResidues = [] # Only used for presenting to end user not actually used for skipping. skippedChains = [] for chain in project.molecule.allChains(): skippChain = True for res in chain.allResidues(): if not res.hasProperties("protein"): if not res.hasProperties("HOH"): # don't report waters skippedResidues.append(res) for atm in res.allAtoms(): atm.pdbSkipRecord = True skippedAtoms.append(atm) # end for else: skippChain = False # end if if skippChain: skippedChains.append(chain) # end for # end for if skippedResidues: nTmessage("==> runShiftx: %s non-protein residues will be skipped." % len(skippedResidues)) defs = project.getStatusDict(constants.SHIFTX_KEY, **shiftxStatus()) if model is not None: defs.models = NTlist(model) else: defs.models = NTlist(*range(project.molecule.modelCount)) defs.baseName = "model_%03d" defs.completed = False defs.parsed = False defs.chains = [] # initialize the shiftx attributes _resetShiftx(project) path = project.validationPath(defs.directory) if not path: return True if path.exists(): nTdebug("runShiftx: removing %s with prior data", path) path.rmdir() path.makedirs() doShiftx = ExecuteProgram(pathToProgram=cdefs.cingPaths.shiftx, rootPath=path, redirectOutput=False) startTime = io.now() for model in defs.models: # set filenames rootname = defs.baseName % model nTdebug("runShiftx: doing model %s, path %s, rootname %s", model, path, rootname) # generate a pdbfile pdbFile = project.molecule.toPDB(model=model, convention=constants.IUPAC) if not pdbFile: nTerror("runShiftx: Failed to generate a pdb file for model: %s", model) return True pdbFile.save(path / rootname + ".pdb") del pdbFile for chain in project.molecule.allChains(): if chain not in skippedChains: # nTdebug('Doing chain code [%s]' % (chain.name)) # quotes needed because by default the chain id is a space now. # chainId = "'" + chain.name + "'" # According to the readme in shiftx with the source this is the way to call it. chainId = "1" + chain.name outputFile = rootname + "_" + chain.name + ".out" defs.chains.append((chain.name, outputFile)) doShiftx(chainId, rootname + ".pdb", outputFile) # end if # end for # end for # cleanup for pdbfile in path.glob("*.pdb"): pdbfile.remove() # Restore the 'default' state for atm in skippedAtoms: atm.pdbSkipRecord = False defs.completed = True # parse the results if parseShiftx(project): return True defs.date = io.now() defs.version = __version__ defs.molecule = project.molecule.asPid defs.remark = "Shiftx on %s completed in %.1f seconds on %s; data in %s" % ( project.molecule, defs.date - startTime, defs.date, path, ) project.history(defs.remark) nTmessage("==> %s", defs.remark) return False
def runTalosPlus(project, tmp=None, parseOnly=False): """Perform a talos+ analysis; parses the results; put into new CING dihedral restraint list Returns True on error. Returns False when talos is absent or when all is fine. """ #LEGACY: if parseOnly: return parseTalosPlus(project) if project is None: nTerror("runTalosPlus: No project defined") return True # check executable if cdefs.cingPaths.talos is None: nTmessage('runTalosPlus: no talosPlus executable defined, skipping') return False # Gracefully return status, output = getOsResult('which '+ cdefs.cingPaths.talos ) if len(output) == 0: nTmessage('runTalosPlus: invalid talosPlus executable defined (%s), skipping', cdefs.cingPaths.talos) return False # Gracefully return if project.molecule is None: nTmessage("runTalosPlus: No molecule defined") return True residues = project.molecule.residuesWithProperties('protein') if not residues: nTmessage('runTalosPlus: no amino acids defined') return False if len( project.molecule.resonanceSources ) == 0: nTmessage("==> runTalosPlus: No resonances defined so no sense in running.") # JFD: This doesn't catch all cases. return False talosDefs = project.getStatusDict(constants.TALOSPLUS_KEY, **talosDefaults) talosDefs.molecule = project.molecule.asPid talosDefs.directory = constants.TALOSPLUS_KEY path = project.validationPath( talosDefs.directory ) if not path: return True if path.exists(): nTdebug('runTalosPlus: removing %s with prior data', path) path.rmdir() path.makedirs() startTime = io.now() talosDefs.completed = False talosDefs.parsed = False _resetTalosPlus(project) # Exporting the shifts fileName = path / talosDefs.tableFile if exportShifts2TalosPlus(project, fileName=fileName): nTwarning("runTalosPlus: Failed to exportShifts2TalosPlus; this is normal for empty CS list.") return False # running TalosPlus talosProgram = ExecuteProgram(cdefs.cingPaths.talos, rootPath=path, redirectOutput=True) nTmessageNoEOL('==> Running talos+ ... ') talosProgram( '-in ' + talosDefs.tableFile + ' -sum ' + talosDefs.predFile ) nTmessage('Done!') if _findTalosOutputFiles(path, talosDefs): return True talosDefs.date = io.now() talosDefs.completed=True talosDefs.version = __version__ talosDefs.molecule = project.molecule.asPid talosDefs.remark = 'TalosPlus on %s completed in %.1f seconds on %s; data in %s' % \ (project.molecule, talosDefs.date-startTime, talosDefs.date, path) # Importing the results if parseTalosPlus(project): nTerror("runTalosPlus: Failed parseTalosPlus") return True project.history(talosDefs.remark) nTmessage('==> %s', talosDefs.remark) return False
def exportShifts2TalosPlus( project, fileName=None): """Export shifts to TalosPlus format Return True on error including situation where no shifts were added to the file. --------------------------------------------------- An example of the required shift table format is shown below. Complete examples can be found in the talos/shifts and talos/test directories. Specifically: In the current version of TALOS/TALOS+, residue numbering must begin at 1. The protein sequence should be given as shown, using one or more "DATA SEQUENCE" lines. Space characters in the sequence will be ignored. Use "c" for oxidized CYS (CB ~ 42.5 ppm) and "C" for reduced CYS (CB ~ 28 ppm) in both the sequence header and the shift table. The table must include columns for residue ID, one-character residue name, atom name, and chemical shift. The table must include a "VARS" line which labels the corresponding columns of the table. The table must include a "FORMAT" line which defines the data type of the corresponding columns of the table. Atom names are always given exactly as: HA for H-alpha of all residues except glycine HA2 for the first H-alpha of glycine residues HA3 for the second H-alpha C for C' (CO) CA for C-alpha CB for C-beta N for N-amide HN for H-amide As noted, there is an exception for naming glycine assignments, which should use HA2 and HA3 instead of HA. In the case of glycine HA2/HA3 assignments, TALOS/TALOS+ will use the average value of the two, so that it is not necessary to have these assigned stereo specifically ; for use of TALOS/TALOS+, the assignment can be arbitrary. Note however that the assignment must be given exactly as either "HA2" or "HA3" rather than "HA2|HA3" etc. Other types of assignments may be present in the shift table; they will be ignored. Example shift table (excerpts): REMARK Ubiquitin input for TALOS, HA2/HA3 assignments arbitrary. DATA SEQUENCE MQIFVKTLTG KTITLEVEPS DTIENVKAKI QDKEGIPPDQ QRLIFAGKQL DATA SEQUENCE EDGRTLSDYN IQKESTLHLV LRLRGG VARS RESID RESNAME ATOMNAME SHIFT FORMAT %4d %1s %4s %8.3f 1 M HA 4.23 1 M C 170.54 1 M CA 54.45 1 M CB 33.27 2 Q N 123.22 2 Q HA 5.25 2 Q C 175.92 2 Q CA 55.08 2 Q CB 30.76 --------------------------------------------------- From talos+ randcoil.tab file: REMARK Talos Random Coil Table 2005.032.16.15 REMARK Cornilescu, Delaglio and Bax REMARK CA/CB from Spera, Bax, JACS 91. REMARK Others from Wishart et al. J. Biomol. NMR, 5(1995), 67-81 REMARK Pro N shift is the current database average (7 residues). REMARK HIS = Wishart's val - 0.5*(diff between prot./non-prot. Howarth&Lilley) DATA RESNAMES A C c D E F G H I K L M N P Q R S T V W Y DATA ATOMNAMES HA CA CB C N HN # # Values for C are CYS-reduced. # Values for c are CYS-oxidized. # Values for H are HIS-unprotonated. # Values for h are for HIS-protonated. # Values for D and E are for protonated forms. --------------------------------------------------- """ if not project: return True #end if if not project.molecule: nTerror('exportShifts2TalosPlus: no molecule defined') return True molecule = project.molecule residues = molecule.residuesWithProperties('protein') if not residues: nTerror('exportShifts2TalosPlus: no amino acid defined') return True table = NmrPipeTable() table.remarks.append( sprintf('shifts from %s', molecule.name ) ) residueOffset = residues[0].resNum-1 # residue numbering has to start from 1 table.remarks.append( sprintf('residue numbering offset %d', residueOffset ) ) # generate a one-letter sequence string; map 'all chains to one sequence' seqString = '' for res in residues: # seqString = seqString + res.db.shortName JFD mod; wrong, look at format def above! if res.translate(constants.INTERNAL_0) == 'CYSS': seqString = seqString + 'c' # oxidized else: seqString = seqString + res.db.shortName #end for # data table.data.SEQUENCE = seqString # add collun entries table.addColumn('RESID', '%-4d') table.addColumn('RESNAME', '%-4s') table.addColumn('ATOMNAME', '%-4s') table.addColumn('SHIFT', '%8.3f') # defines IUPAC to talos mapping and nuclei used talosDict = dict( N = 'N', H = 'HN', CA = 'CA', HA = 'HA', HA2= 'HA2', HA3= 'HA3', QA = 'HA2,HA3', # QA will be translsate into real atoms CB = 'CB', C = 'C' ) talosNuclei = talosDict.keys() atmCount = 0 for resId,res in enumerate(residues): for ac in res.allAtoms(): atomName = ac.translate(constants.IUPAC) if (ac.isAssigned(resonanceListIdx=constants.RESONANCE_LIST_IDX_ANY) and ( atomName in talosNuclei)): shift = ac.shift(resonanceListIdx=constants.RESONANCE_LIST_IDX_ANY) # save the shift, because Gly QA pseudo atom does get expanded for ra in ac.realAtoms(): atomName = ra.translate(constants.IUPAC) # Translate to TalosPlus if talosDict.has_key(atomName): atomName = talosDict[atomName] else: nTerror('exportShifts2TalosPlus: strange, we should not be here (ra=%s)', ra) continue #end if #print '>', seqString[resId:resId+1] table.addRow( RESID=resId+1, RESNAME=seqString[resId:resId+1], ATOMNAME=atomName, SHIFT=shift) atmCount += 1 #end for #end if #end for #end for # save the table if not fileName: fileName = molecule.name + '.tab' if not table.writeFile(fileName): nTmessage( '==> exportShifts2TalosPlus: %-4d shifts written to "%s"', atmCount, fileName ) if atmCount == 0: return True