def setRawDistanceConstraintItemMembers(self): itemResonances = getResonancesFromPairwiseConstraintItem(self.item) atomSerialList = [] for i in range(2): resonance = itemResonances[i] if resonance in self.resonanceToAtomSerial.keys(): atomSerials = self.resonanceToAtomSerial[resonance] else: atomSerials = [] resonanceToAtoms = self.resonanceToAtoms[resonance] for resonanceToAtom in resonanceToAtoms: atom = resonanceToAtom.getAtom() atomSerial = self.getAtomSerial(atom) if atomSerial == None: print " Error: no atom serial for atom '{}.{}.{}, aborting this constraint.'".format( atom.residue.chain.code, atom.residue.seqCode, atom.name) atomSerials = [] break atomSerials.append(atomSerial) atomSerialList.append(atomSerials) atomSerialList[-1].sort() # # Now make all combinations... # for atomSerial1 in atomSerialList[0]: for atomSerial2 in atomSerialList[1]: atomSerialComb = (atomSerial1, atomSerial2) if atomSerialComb in self.atomSerialCombs: continue else: self.atomSerialCombs.append(atomSerialComb) self.rawConstraint.items.append(self.rawConstraintItemClass()) self.rawConstraint.items[-1].members.append( self.rawConstraintItemMemberClass(atomSerial1)) self.rawConstraint.items[-1].members.append( self.rawConstraintItemMemberClass(atomSerial2))
def setLocalSumContribs(resIndex,sideCodes,item,resAtomDict,swap,resAtomSwapDict,atomCoordDict,prochiralResonancesDict,prochiralAvgSum,avgSum): sideCode = sideCodes[resIndex] itemResonances = getResonancesFromPairwiseConstraintItem(item) resonance = itemResonances[resIndex] atomList = resAtomDict[resonance] if swap and resAtomSwapDict.has_key(resonance): atomList = resAtomSwapDict[resonance] for atom in atomList: if atomCoordDict.has_key(atom): otherResonance = itemResonances[not resIndex] otherAtomLists = [resAtomDict[otherResonance]] if resAtomSwapDict.has_key(otherResonance): otherAtomLists.append(resAtomSwapDict[otherResonance]) avgLocalSums = [0.0,0.0] for i in range(0,len(otherAtomLists)): otherAtomList = otherAtomLists[i] for otherAtom in otherAtomList: if atom != otherAtom and atomCoordDict.has_key(otherAtom) and atomCoordDict[atom] and atomCoordDict[otherAtom]: avgSumContrib = 1.0 / math.pow(getDistanceFromCoordinates(atomCoordDict[atom],atomCoordDict[otherAtom]),6) avgLocalSums[i] += avgSumContrib # # Pick the largest average local sum: is the smallest distance!! # if avgLocalSums[0] < avgLocalSums[1]: avgLocalSum = avgLocalSums[1] else: avgLocalSum = avgLocalSums[0] avgSum[sideCode] += avgLocalSum if avgLocalSum: if resonance in prochiralResonancesDict.keys(): prochiralKey = prochiralResonancesDict[resonance] if not prochiralAvgSum[sideCode].has_key(prochiralKey): prochiralAvgSum[sideCode][prochiralKey] = [0.00,[]] prochiralAvgSum[sideCode][prochiralKey][0] += avgLocalSum prochiralAvgSum[sideCode][prochiralKey][1].append(item)
def setRawRdcConstraintItemMembers(self): itemResonances = getResonancesFromPairwiseConstraintItem(self.item) for i in range(0, 2): (chainCode, seqCode, spinSystemId, seqInsertCode, atomName) = getNameInfo(self.resSetNames[i]) resLabel = self.getResonanceResLabel(itemResonances[i]) self.rawConstraintItem.members.append( self.rawConstraintItemMemberClass(chainCode, seqCode, resLabel, atomName))
def setRawDistanceConstraintItemMembers(self): itemResonances = getResonancesFromPairwiseConstraintItem(self.item) for i in range(0, 2): resonance = itemResonances[i] resLabel = self.getResonanceResLabel(resonance) (chainCode, seqCode, spinSystemId, seqInsertCode, atomName) = getNameInfo(self.resSetNames[i]) if atomName == allResidueAtoms_kw: print " Error: not handling residue level constraints for %s." % self.format continue self.rawConstraintItem.members.append( self.rawConstraintItemMemberClass(chainCode, seqCode, resLabel, atomName))
def getPseudoCorrection(self, constraint, pseudoCorrections): constraintItems = constraint.sortedItems() # # Can only really do pseudocorrection on unambiguous item, # or on multiple items that designate an atom set... # resonanceList = [] for consItem in constraintItems: resonanceList.append( getResonancesFromPairwiseConstraintItem(consItem)) atomsForPseudoCorrection = [] residueList = [] #print constraint.serial for i in range(2): chemAtomSets = [] deepChemAtomSets = [] atomNames = [] useAtomSetName = None if len(resonanceList) > 1: checkForSets = True else: checkForSets = False for resonances in resonanceList: resonance = resonances[i] if self.resObjectMapping.has_key(resonance): (residue, atomList) = self.resObjectMapping[resonance] else: useAtomSetName = checkForSets = False atomNames = [] break if len(atomList) > 1: checkForSets = True residueList.append(residue) atomNames.append(atomList[0].name) chemAtomSet = deepChemAtomSet = None chemAtom = atomList[0].chemAtom if chemAtom.chemAtomSet: chemAtomSet = chemAtom.chemAtomSet.name if chemAtom.chemAtomSet.chemAtomSet: deepChemAtomSet = chemAtom.chemAtomSet.chemAtomSet.name chemAtomSets.append(chemAtomSet) deepChemAtomSets.append(deepChemAtomSet) # First check if got multiple 'deep' chemAtomSets if not deepChemAtomSets.count(None) and checkForSets: if deepChemAtomSets.count( deepChemAtomSets[0]) == len(deepChemAtomSets): useAtomSetName = deepChemAtomSets[0] if not chemAtomSets.count(None) and checkForSets: if chemAtomSets.count(chemAtomSets[0]) == len(chemAtomSets): # Note that this will reset HG* to HG1*, for example, if this is the only # one that occurs! useAtomSetName = chemAtomSets[0] if (not checkForSets or not useAtomSetName) and atomNames and atomNames.count( atomNames[0]) == len(atomNames): useAtomSetName = atomNames[0] #print " %d" % i, chemAtomSets, deepChemAtomSets, atomNames atomsForPseudoCorrection.append(useAtomSetName) #print " ",atomsForPseudoCorrection if residueList and len(residueList) == residueList.count( residueList[0]): intraResidue = True #print " intrares, %s" % residueList[0].ccpCode else: intraResidue = False #print " interres, %s-%s" % (residueList[0].ccpCode,residueList[-1].ccpCode) # # Now check if have to apply correction... # pseudoCorrection = 0.0 if None not in atomsForPseudoCorrection and len(resonanceList) == 2: for i in range(2): resonance = resonanceList[0][i] if pseudoCorrections.has_key(resonance): if type(pseudoCorrections[resonance]) == type(0.0): pseudoCorrection += pseudoCorrections[resonance] # Now handle Wuthich exceptions... elif pseudoCorrections[resonance].has_key( atomsForPseudoCorrection[i]): corrInfo = pseudoCorrections[resonance][ atomsForPseudoCorrection[i]] if intraResidue and corrInfo[1].has_key( atomsForPseudoCorrection[not i]): pseudoCorrection += corrInfo[1][ atomsForPseudoCorrection[not i]] else: pseudoCorrection += corrInfo[0] return pseudoCorrection
def recalibrateConstraints( self, nmrConstraintStore, structures, pseudo='Wuthrich', saveResults=True, ensembleAverage='median', # Can be 'median', 'average', or 'NOE'. Last one is r-6 average classify=[], fout=sys.stdout, correlationMethod='spearman'): """ Recalibrates a set of distance constraint lists based on a set of coordinates. Input: args: nmrConstraintStore: A CCPN Nmr.NmrConstraintStore (NOTE THIS WILL BE MODIFIED IF SAVERESULTS IS TRUE!) structures: A list of CCPN MolSystem.Models keywds: pseudo: 'Wuthrich' to use Wuthrich pseudo atom corrections 'Generic' to use generic pseudo atom corrections (based on CONCOORD ones) saveResults: Boolean. Write out the results (or not) classify: Set to ['atomType'] for using bb,sc atom classifications in calibration. fout: File handle to write result information to. Output: None (except for writing outFile and possibly new data to CCPN project) """ from pdbe.analysis.Stats import getCorrelation # # Initialise some stuff # invSixth = -1.0 / 6.0 fixedResonances = nmrConstraintStore.sortedFixedResonances() # # Check if pseudo correction info OK # if pseudo == 'Wuthrich': pseudoCorrections = getPseudoCorrectionsWuthrich(fixedResonances) elif pseudo == 'Generic': pseudoCorrections = getPseudoCorrections(fixedResonances) else: print " ERROR: Unrecognized pseudo correction system '%s' - aborting." return # # Write header # if classify: classifyString = ", classification by '%s'" % str(classify) else: classifyString = "" headerLine = " # Recalibrating constraints, based on '%s', ensemble averaging '%s'%s. #\n" % ( pseudo, ensembleAverage, classifyString) headerFrameLine = " %s\n" % ("#" * (len(headerLine) - 1)) fout.write("\n") fout.write(headerFrameLine) fout.write(headerLine) fout.write(headerFrameLine) fout.write("\n") # # Set up dict for resonance->atom links # self.setAssignedAtomsAndResidues( fixedResonances) # From ResonanceCoordinateHandler class! # # Set up reference info for structure coords # self.structureList = list(structures) numStructures = len(self.structureList) if numStructures == 1: fout.write(" Warning: only one structure used in analysis!\n") self.createCoordAtomInfoDict( ) # From ResonanceCoordinateHandler class! # # Now go over the constraint lists, handle 1 by 1... # allDistanceConstraintLists = [] for constraintList in nmrConstraintStore.sortedConstraintLists(): if constraintList.className == 'DistanceConstraintList': allDistanceConstraintLists.append(constraintList) for dcl in allDistanceConstraintLists: dclConstraints = dcl.sortedConstraints() constraintKeys = [] distances = [] targetDistances = [] targetCorrected = [] upperDistances = [] upperCorrected = [] distanceClasses = [] pseudoDistances = [] pseudoTargetDistances = [] pseudoTargetCorrectedDistances = [] pseudoUpperDistances = [] pseudoUpperCorrectedDistances = [] if not classify: coordinateVolumeSum = {'all': 0.0} else: coordinateVolumeSum = {} for constraint in dclConstraints: distPerStruc = [] atomCombs = [] atomTypes = [] for strucIndex in range(numStructures): distPerStruc.append([]) hasDistance = False pseudoCorrection = self.getPseudoCorrection( constraint, pseudoCorrections) """ if dcl.serial == 9 and constraint.serial in [6,7,8,9]: print " ", constraint.serial #print " ",constraint.sortedItems() #print " ", distPerStruc #print " ", ["%s.%d.%s-%s.%d.%s" % (atomComb[0].residue.ccpCode,atomComb[0].residue.seqId,atomComb[0].name,atomComb[1].residue.ccpCode,atomComb[1].residue.seqId,atomComb[1].name) for atomComb in atomCombs] """ for item in constraint.sortedItems(): (resonance, otherResonance ) = getResonancesFromPairwiseConstraintItem(item) if self.resObjectMapping.has_key( resonance) and self.resObjectMapping.has_key( otherResonance): (residue, atomList) = self.resObjectMapping[resonance] (otherResidue, otherAtomList) = self.resObjectMapping[otherResonance] """ if dcl.serial == 9 and constraint.serial in [6,7,8,9]: print " ", residue, atomList print " ", otherResidue,otherAtomList """ # Set the atom type if 'atomType' in classify: atomContactType = [] for atomRefName in (atomList[0].name, otherAtomList[0].name): atomType = getAtomPositionType(atomRefName) atomContactType.append(atomType) atomContactType.sort() atomContactType = tuple(atomContactType) if not atomContactType in atomTypes: atomTypes.append(atomContactType) # Get distance info... for atom in atomList: if self.coordAtomInfo.has_key(atom): for otherAtom in otherAtomList: if atom == otherAtom: continue atomComb = (atom, otherAtom) # Only count each contribution once!! if atomComb in atomCombs or ( atomComb[1], atomComb[0]) in atomCombs: continue atomCombs.append(atomComb) if self.coordAtomInfo.has_key(otherAtom): hasDistance = True for strucIndex in range(numStructures): coord = self.coordAtomInfo[atom][ strucIndex] otherCoord = self.coordAtomInfo[ otherAtom][strucIndex] if coord and otherCoord: distance = getDistanceFromCoordinates( coord, otherCoord) distPerStruc[ strucIndex].append( distance) if not hasDistance: continue # # Take average based on median, straight average or NOE average (r-6) # overallDistSum = 0.0 tempDistTotal = 0.0 numDistZero = 0 tempDistanceList = [] for strucIndex in range(numStructures): distSum = 0.0 for distance in distPerStruc[strucIndex]: distSum += math.pow(distance, -6) if distSum: if ensembleAverage == 'NOE': # This is correct overallDistSum += distSum else: tempDist = math.pow(distSum, invSixth) tempDistanceList.append(tempDist) tempDistTotal += tempDist else: numDistZero += 1 # TODO: here aim 'lower' than actual target distance? Aymeric can do this himself though... # Not implemented currently numDistances = numStructures - numDistZero if not numDistances: continue if ensembleAverage == 'NOE': overallDistSum = overallDistSum / numDistances avgDist = math.pow(overallDistSum, invSixth) else: numDistances = len(tempDistanceList) # TODO ARE THERE GOOD BUILTIN PYTHON FUNCIONS FOR THIS? if ensembleAverage == 'median': tempDistanceList.sort() middleIndex = int(numDistances / 2) if numDistances % 2 == 0: avgDist = (tempDistanceList[middleIndex - 1] + tempDistanceList[middleIndex]) / 2 else: avgDist = tempDistanceList[middleIndex] elif ensembleAverage == 'average': avgDist = tempDistTotal / numDistances else: avgDist = 0.0 overallDistSum = math.pow(avgDist, -6) """ if dcl.serial == 9 and constraint.serial in [6,7,8,9]: print " ", avgDist print """ # # Now set the information # if not classify: classType = 'all' elif 'atomType' in classify: atomTypes.sort() atomTypes = tuple(atomTypes) classType = atomTypes # TODO Need to add other types if necessary, also combine info... if not coordinateVolumeSum.has_key(classType): coordinateVolumeSum[classType] = 0.0 coordinateVolumeSum[classType] += overallDistSum distances.append(avgDist) constraintKeys.append(constraint.getFullKey()) if pseudoCorrection: pseudoDistances.append(avgDist) # # Get the restraint distance info # if constraint.targetValue: targetValue = constraint.targetValue else: targetValue = 0.0 distanceClasses.append(classType) targetDistances.append(targetValue) targetCorrected.append(targetValue - pseudoCorrection) if constraint.upperLimit: upperLimit = constraint.upperLimit else: upperLimit = 0.0 upperDistances.append(upperLimit) upperCorrected.append(upperLimit - pseudoCorrection) if pseudoCorrection: pseudoTargetDistances.append(targetValue) pseudoTargetCorrectedDistances.append(targetValue - pseudoCorrection) pseudoUpperDistances.append(upperLimit) pseudoUpperCorrectedDistances.append(upperLimit - pseudoCorrection) #print residue.ccpCode, atomList[0].name, otherResidue.ccpCode, otherAtomList[0].name, avgDist, upperLimit, pseudoCorrection # # TODO: also check number of values that are available? If only a couple (out of 1000s), then don't use that one! # fout.write("Constraint list %s, with %d distances.\n" % (dcl.serial, len(distances))) if not distances: fout.write(" No distances - ignored.\n") continue fout.write(" Correlations by %s method:\n" % correlationMethod) targetCorr = getCorrelation(distances, targetDistances, correlationMethod=correlationMethod) fout.write(" All target distances, as is: %.4f.\n" % targetCorr) upperCorr = getCorrelation(distances, upperDistances, correlationMethod=correlationMethod) """ print distances[0], distances[-1], upperDistances[0], upperDistances[-1] if dcl.serial == 9: print print distances print """ fout.write(" All upper distances, as is: %.4f.\n" % upperCorr) if targetCorr > upperCorr: selectText = "Selecting target distances as best option" useDistances = targetDistances distType = 'target' elif 0 < upperCorr < 1: pseudoUpperCorr = 0.0 if pseudoDistances: pseudoUpperCorr = getCorrelation( distances, upperCorrected, correlationMethod=correlationMethod) fout.write( " All upper distances, pseudo corrected: %.4f\n" % pseudoUpperCorr) if not pseudoUpperCorr or pseudoUpperCorr < upperCorr: selectText = "Selecting upper bounds as best option" useDistances = upperDistances distType = 'upper' else: selectText = "Selecting pseudo corrected upper bounds as best option" useDistances = upperCorrected distType = 'pseudo' else: # TODO THIS IS NOT GOOD - just copy over original list as is? Or what?!?!? # Info will now go missing - check where this happens! fout.write(" Ignoring list - no valid distances.\n\n") continue fout.write("%s\n\n\n" % selectText) newConstraintList = NmrConstraint.DistanceConstraintList.getByKey( nmrConstraintStore, (dcl.serial, )) newConstraintList.details = selectText newConstraintList.addApplicationData( Implementation.AppDataString(application='ConstraintsHandler', keyword='distType', value=distType)) # # Now create a new list, with recalculated target distances # volumes = [] volumeSum = {} for classType in coordinateVolumeSum.keys(): volumeSum[classType] = 0.0 for distIndex in range(len(useDistances)): useDistance = useDistances[distIndex] classType = distanceClasses[distIndex] if useDistance: volume = math.pow(useDistance, -6) else: volume = 0.0 volumeSum[classType] += volume volumes.append((volume, classType)) correctionFactor = {} for classType in volumeSum.keys(): correctionFactor[classType] = coordinateVolumeSum[ classType] / volumeSum[classType] if type(classType) == type(""): classTypeString = classType else: classTypeString = ','.join([ "%s-%s" % classTypeItem for classTypeItem in classType ]) newConstraintList.addApplicationData( Implementation.AppDataFloat( application='ConstraintsHandler', keyword='correctionFactor_%s' % classTypeString, value=correctionFactor[classType])) for i in range(0, len(volumes)): (volume, classType) = volumes[i] if volume: newDistance = math.pow( volume * correctionFactor[classType], invSixth) else: # This is the default value newDistance = 1.8 # Consistency check if newDistance < 1.8: newDistance = 1.8 # # Change the relevant constraint... # constraintKey = constraintKeys[i][1:] newConstraint = NmrConstraint.DistanceConstraint.getByKey( nmrConstraintStore, constraintKey) newConstraint.targetValue = newDistance # Do some consistency checks... if not newConstraint.weight: newConstraint.weight = 1.0 if not newConstraint.lowerLimit or not newConstraint.upperLimit: correction = 0.125 * (newConstraint.targetValue**2) if not newConstraint.lowerLimit: lowerLimit = newConstraint.targetValue - correction if lowerLimit < 1.8: lowerLimit = 1.8 newConstraint.lowerLimit = lowerLimit if not newConstraint.upperLimit: newConstraint.upperLimit = newConstraint.targetValue + correction if saveResults: # TODO will this take care of everything? nmrConstraintStore.root.saveModified() return nmrConstraintStore
for distConstr in ccpnConstraintList.sortedConstraints(): print "Constraint %d: %.1f-%.1f" % ( distConstr.serial, distConstr.lowerLimit, distConstr.upperLimit) for constrItem in distConstr.sortedItems(): # # Now list the atoms linked to each of the two resonances associated with # this item. # atomList = [] resonanceList = getResonancesFromPairwiseConstraintItem(constrItem) for resonance in resonanceList: atomList.append([]) if resonance.resonanceSet: for atomSet in resonance.resonanceSet.atomSets: for atom in atomSet.atoms: atomList[-1].append( "%d.%s" % (atom.residue.seqCode, atom.name)) atomList[-1].sort() atomList[-1] = ','.join(atomList[-1]) print " (%s) - (%s)" % (atomList[0], atomList[1]) print
def setRawDistanceConstraintItemMembers(self): # # Expand the information... is necessary for Concoord (only handles individual atoms) # atomNameLists = [] for i in range(0, 2): atomNameLists.append([]) resonanceToAtom = self.ccpInfo[i][3] chemAtomOrigName = self.ccpInfo[i][2] if resonanceToAtom.chemAtomSet: chemAtomOrSet = resonanceToAtom.chemAtomSet else: chemAtomOrSet = resonanceToAtom.chemAtom if chemAtomOrSet: chemCompVar = resonanceToAtom.getResidue().chemCompVar namingSystem = chemCompVar.chemComp.findFirstNamingSystem( name=self.namingSystemName) if namingSystem: chemAtomSysName = findChemAtomSysName( namingSystem, {'sysName': chemAtomOrigName}) else: chemAtomSysName = None if chemAtomSysName: chemAtom = chemCompVar.findFirstChemAtom( name=chemAtomSysName.atomName, subType=chemAtomSysName.atomSubType) else: chemAtom = chemCompVar.findFirstChemAtom( name=chemAtomOrigName) if not chemAtom: chemAtomSetSysName = findChemAtomSetSysName( namingSystem, {'sysName': chemAtomOrigName}) if chemAtomSetSysName: chemAtomSet = chemCompVar.findFirstChemAtomSet( name=chemAtomSetSysName.atomName, subType=chemAtomSetSysName.atomSubType) else: chemAtomSet = chemCompVar.findFirstChemAtomSet( name=chemAtomOrigName) if chemAtomSet: (chainCode, seqCode, spinSystemId, seqInsertCode, atomName) = getNameInfo(self.resSetNames[i]) if chemAtomSet.chemAtomSets: chemAtomSets = list(chemAtomSet.chemAtomSets) else: chemAtomSets = [chemAtomSet] for chemAtomSet in chemAtomSets: chemAtomSysNames = self.getChemAtomSysNamesFromSet( chemAtomSet, chemCompVar, findIupac=1) for chemAtomSysName in chemAtomSysNames: if chemAtomSysName: atomNameLists[-1].append( getResName( chainCode, seqCode, chemAtomSysName, seqInsertCode=seqInsertCode)) else: print " Error: problems with decompressing Concoord name %s - sysNames missing for %s" % ( self.resSetNames[i], chemAtomSet.name) else: print " Error: can't decompress Concoord name %s" % self.resSetNames[ i] # # If no names use default # if not atomNameLists[-1]: atomNameLists[-1].append(self.resSetNames[i]) # # Now write them one by one... # itemResonances = getResonancesFromPairwiseConstraintItem(self.item) for resSetName0 in atomNameLists[0]: # TODO: bit risky this one! What if original names (eg GLU-) are being used?! resonance = itemResonances[0] resLabel0 = resonance.resonanceSet.findFirstAtomSet( ).findFirstAtom().residue.molResidue.chemComp.ccpCode.upper() (chainCode0, seqCode0, spinSystemId0, seqInsertCode0, atomName0) = getNameInfo(resSetName0) if atomName0 == allResidueAtoms_kw: print " Error: not handling residue level constraints for %s." % self.format continue for resSetName1 in atomNameLists[1]: # TODO: bit risky this one! What if original names (eg GLU-) are being used?! resonance = itemResonances[1] resLabel1 = resonance.resonanceSet.findFirstAtomSet( ).findFirstAtom().residue.molResidue.chemComp.ccpCode.upper() (chainCode1, seqCode1, spinSystemId1, seqInsertCode1, atomName1) = getNameInfo(resSetName1) if atomName1 == allResidueAtoms_kw: print " Error: not handling residue level constraints for %s." % self.format continue # # Now set all items and members... # self.rawConstraint.items.append(self.rawConstraintItemClass()) self.rawConstraintItem = self.rawConstraint.items[-1] self.rawConstraintItem.members.append( self.rawConstraintItemMemberClass()) self.rawConstraintItem.members[-1].setInfo( chainCode0, seqCode0, resLabel0, atomName0) self.rawConstraintItem.members.append( self.rawConstraintItemMemberClass()) self.rawConstraintItem.members[-1].setInfo( chainCode1, seqCode1, resLabel1, atomName1)
def cleanDistanceConstraintList(self, constraintList): print "Cleaning distance constraint list '%s'." % constraintList.name constraints = [] constraintRefs = [] # # Set up some reference data and do initial checking # for constraint in constraintList.constraints: constraints.append([]) constraintRefs.append(constraint) for item in constraint.sortedItems(): resonances = getResonancesFromPairwiseConstraintItem(item) # # Check for items between the same resonance (or resonanceSet) # Remove if present. # if resonances[0] == resonances[1]: print " Deleting constraint item (between same resonance)" item.delete() continue elif resonances[0].resonanceSet and resonances[ 0].resonanceSet == resonances[1].resonanceSet: print " Deleting constraint item (between same resonanceSets)" # This item can be deleted because ambiguity present on resonanceSet level - # need not be repeated on constraint level! item.delete() continue # # Check if restraint between directly covalently linked atoms # if resonances[0].resonanceSet and len( resonances[0].resonanceSet.atomSets) == 1: if resonances[1].resonanceSet and len( resonances[1].resonanceSet.atomSets) == 1: # # Need direct link to atomSet for both resonances... # nmrAtoms0 = list(resonances[0].resonanceSet. findFirstAtomSet().atoms) refChemAtom0 = self.getRefChemAtom(nmrAtoms0) if refChemAtom0: nmrAtoms1 = list(resonances[1].resonanceSet. findFirstAtomSet().atoms) refChemAtom1 = self.getRefChemAtom(nmrAtoms1) if refChemAtom1 and nmrAtoms0[ 0].residue == nmrAtoms1[0].residue: itemDeleted = 0 if refChemAtom1 == refChemAtom0: print " Deleting constraint item (connected via atom %s)" % ( refChemAtom0.name) item.delete() itemDeleted = 1 #else: # for chemBond in refChemAtom0.chemBonds: # if refChemAtom1 == getOtherAtom(refChemAtom0,chemBond): # print " Deleting constraint item (between atoms %s, %s directly connected via two covalent bonds)" % (refChemAtom0.name,refChemAtom1.name) # item.delete() # itemDeleted = 1 # break if itemDeleted: continue # # Keep track of valid items # constraints[-1].append(resonances) # # Check if there are any items left # if not constraint.items: print " Deleting constraint %d (no items left)" % constraint.serial constraint.delete() constraints.pop(-1) constraintRefs.pop(-1) else: constraints[-1].sort() # # Now check whether there are any duplicates # i = 0 while (i < len(constraints)): refConstraint = constraints[i] j = i + 1 while (j < len(constraints)): if refConstraint == constraints[j]: items = "" for (res1, res2) in constraints[j]: items += "[%s,%s]," % (res1.name, res2.name) items = items[:-1] # # Always keep tightest value if available # for attribute in [ 'upperLimit', 'targetValue', 'lowerLimit' ]: if getattr(constraintRefs[i], attribute) and getattr( constraintRefs[j], attribute): setattr( constraintRefs[i], attribute, min(getattr(constraintRefs[i], attribute), getattr(constraintRefs[j], attribute))) print " Constraint %s (items %s) is duplicate of %s - deleted" % ( constraintRefs[j].serial, items, constraintRefs[i].serial) constraintRefs[j].delete() constraints.pop(j) constraintRefs.pop(j) else: j += 1 i += 1
def checkSwapsAndClean(self,method = 'SUM_AVERAGING', violationCodes = None, swapFraction = 0.75): if not self.distanceConstraintLists or not self.structureEnsemble or not self.structureEnsemble.models: print "Error: no constraint lists or no structures available! Aborting..." return print print "Checking swap status and cleaning prochiral groups in constraint lists..." print # # Initialize... see parameters above for swapFraction # # Set a dictionary with violationCodes (what is a large violation?) # if violationCodes: self.violationCodes = violationCodes else: self.violationCodes = {} self.violationCodes['xl'] = {'violation': 2.0, 'fraction': 0.00001} self.violationCodes['l'] = {'violation': 1.0, 'fraction': 0.5} # # Set up a dict of resonances # TODO: Should this be done in cleanStereoAssignments?!? # Should I make this a 'violationHandler' class??!?! # (self.resAtomDict,self.resAtomSetDict) = createResonanceAtomAndAtomSetDict(self.distanceConstraintLists[0].parent.fixedResonances) if self.verbose: print "Made resAtomDict, resAtomSetDict" (self.resAtomSwapDict,self.prochiralResonancesDict) = createResAtomSwapDict(self.resAtomSetDict) if self.verbose: print "Made resAtomSwapDict,prochiralResonancesDict" structureViolations = [] """ infoStrings = [] for resonance in resAtomSwapDict.keys(): atoms = resAtomDict[resonance] infoString = "%3d.%s" % (atoms[0].residue.seqId, atoms[0].atomSet.name) atoms = resAtomSwapDict[resonance] infoString += "-> swap is %3d.%s" % (atoms[0].residue.seqId, atoms[0].name) infoStrings.append(infoString) infoStrings.sort() for infoString in infoStrings: print infoString """ # # Set the factor for calculating violations # if method == 'SUM_AVERAGING': factor = 1.0/6.0 # # Loop over the structures # self.models = self.structureEnsemble.sortedModels() #self.models = self.models[:3] for model in self.models: self.prochiralViolationDict = self.createProchiralViolationDict() #violationList = Nmr.ViolationList(distanceConstraintLists[0].structureGeneration,molStructures = [model]) totalViols = 0 # # Set up dict for coordinates # self.atomCoordDict = {} # No need for sorting here... for cChain in self.structureEnsemble.coordChains: for cRes in cChain.residues: for cAtom in cRes.atoms: if cAtom.atom: # # TODO: cannot handle multiple coords for one atom!! # self.atomCoordDict[cAtom.atom] = model.findFirstCoord(atom = cAtom) if self.verbose: print "Made atomCoordDict for model %d" % model.serial # # Go over the distance constraints # for distanceConstraintList in self.distanceConstraintLists: for distConstr in distanceConstraintList.sortedConstraints(): # TODO: extend to other methods? if method == 'SUM_AVERAGING': # # Calculate sum averaged distance (Nilges et al., Proteins 17, 297-309, 1993) # (avgDist,prochiralContribs) = getDistConstrSumAvg(distConstr,self.resAtomDict,self.atomCoordDict,factor,self.resAtomSwapDict,self.prochiralResonancesDict) totalViols += self.setViolationDict(avgDist,prochiralContribs,distConstr,'orig') # # Now do the same but for the swap... # if prochiralContribs: (avgDist,prochiralContribs) = getDistConstrSumAvg(distConstr,self.resAtomDict,self.atomCoordDict,factor,self.resAtomSwapDict,self.prochiralResonancesDict,swap = True) self.setViolationDict(avgDist,prochiralContribs,distConstr,'swap') structureViolations.append(self.prochiralViolationDict) if self.verbose: print "Total violations %d" % totalViols # # Check if whether original or swap state was the best... # prochiralSwaps = {} for i in range(0,len(structureViolations)): prochiralViolationDict = structureViolations[i] for prochiralKey in prochiralViolationDict['orig']['total']: # # Calculate total violation over all structures for swapping... # if prochiralViolationDict['orig']['total'][prochiralKey] > prochiralViolationDict['swap']['total'][prochiralKey]: if not prochiralSwaps.has_key(prochiralKey): prochiralSwaps[prochiralKey] = 0 prochiralSwaps[prochiralKey] += 1 # # Finally make the changes in the data model where appropriate # cutoff = swapFraction * len(structureViolations) infoText = [] totalStructures = len(self.models) for prochiralKey in prochiralViolationDict['orig']['total']: # # Set the swapstatus # if prochiralSwaps.has_key(prochiralKey) and prochiralSwaps[prochiralKey] > cutoff: swapStatus = 'swap' percent = prochiralSwaps[prochiralKey] * 100 / len(structureViolations) infoText.append("Swapping stereo assignment status chain %s, residue %3d group %s: %.3f%%" % (prochiralKey[0],prochiralKey[1],prochiralKey[2].name,percent)) else: swapStatus = 'orig' # # Check for constraints with large violations based on the swap state... # constraintItemsReset = [] for violationCode in self.violationCodes.keys(): constraintsViolated = {} cutoffFraction = self.violationCodes[violationCode]['fraction'] # # Again look over all structures # for prochiralViolationDict in structureViolations: for distConstr in prochiralViolationDict[swapStatus][violationCode][prochiralKey].keys(): if not constraintsViolated.has_key(distConstr): constraintsViolated[distConstr] = [0.0,[]] constraintsViolated[distConstr][0] += 1.0 for constrItem in prochiralViolationDict[swapStatus][violationCode][prochiralKey][distConstr][1]: if constrItem not in constraintsViolated[distConstr][1]: constraintsViolated[distConstr][1].append(constrItem) # # Then recalculate and add a constraint item if necessary # distConstraints = constraintsViolated.keys() distConstraints.sort() for distConstr in distConstraints: fractionViolated = constraintsViolated[distConstr][0] / totalStructures #print prochiralKey, violationCode, fractionViolated if fractionViolated >= cutoffFraction: prochiralResonances = [] for resonance in self.prochiralResonancesDict.keys(): if self.prochiralResonancesDict[resonance] == prochiralKey: prochiralResonances.append(resonance) # # Have to make a new prochiral resonance if there's only one!! # if len(prochiralResonances) == 1: otherProchiralResonance = NmrConstraint.FixedResonance(self.nmrConstraintStore, isotopeCode = prochiralResonances[0].isotopeCode) otherAtoms = self.resAtomSwapDict[prochiralResonances[0]] if otherAtoms[0].atomSet: otherAtomSet = otherAtoms[0].atomSet else: otherAtomSet = NmrConstraint.FixedAtomSet(self.nmrConstraintStore,atoms = otherAtoms) otherProchiralResonanceSet = NmrConstraint.FixedResonanceSet(self.nmrConstraintStore, resonances = [otherProchiralResonance], atomSets = [otherAtomSet]) prochiralResonances.append(otherProchiralResonance) self.prochiralResonancesDict[otherProchiralResonance] = prochiralKey violatedItems = constraintsViolated[distConstr][1] for violatedItem in violatedItems: # # Don't redo the item if it was already reset.. # if (prochiralKey,violatedItem) in constraintItemsReset: continue violatedResonances = getResonancesFromPairwiseConstraintItem(violatedItem) for resonance in prochiralResonances: if resonance in violatedResonances: otherResonanceIndex = not violatedResonances.index(resonance) otherResonance = violatedResonances[otherResonanceIndex] otherProchiralResonance = prochiralResonances[not prochiralResonances.index(resonance)] # Put these the wrong way around on purpose! if otherResonanceIndex == 1: newResonances = [otherResonance,otherProchiralResonance] else: newResonances = [otherProchiralResonance,otherResonance] break constraintExists = distConstr.findFirstItem(resonances = tuple(newResonances)) if not constraintExists: newResonances.reverse() constraintExists = distConstr.findFirstItem(resonances = tuple(newResonances)) if not constraintExists and newResonances[0] != newResonances[1]: NmrConstraint.DistanceConstraintItem(distConstr,resonances = newResonances) prochiralText = "%s.%d.%s" % (prochiralKey[0],prochiralKey[1],prochiralKey[2].name) infoLine = "Deassigned constraint %d to prochiral %s: violation > %.1f in %.1f%% of structures.\n" % (distConstr.serial,prochiralText,self.violationCodes[violationCode]['violation'],fractionViolated * 100) infoLine += " --> added new item for '%s' to '%s'" % (getResNameText(newResonances[0]),getResNameText(newResonances[1])) infoText.append(infoLine) constraintItemsReset.append((prochiralKey,violatedItem)) # # Reset based on swapStatus # if swapStatus == 'swap': # # Switch the assignments... # prochiralResonances = [] for resonance in self.prochiralResonancesDict.keys(): if self.prochiralResonancesDict[resonance] == prochiralKey: prochiralResonances.append(resonance) if len(prochiralResonances) == 2: resSet1 = prochiralResonances[0].resonanceSet atomSet1 = resSet1.sortedAtomSets()[0] resSet2 = prochiralResonances[1].resonanceSet atomSet2 = resSet2.sortedAtomSets()[0] resSet1.addAtomSet(atomSet2) resSet1.removeAtomSet(atomSet1) resSet2.addAtomSet(atomSet1) resSet2.removeAtomSet(atomSet2) else: resSet = prochiralResonances[0].resonanceSet atomSet1 = resSet.sortedAtomSets()[0] otherAtoms = self.resAtomSwapDict[prochiralResonances[0]] if otherAtoms[0].atomSet: otherAtomSet = otherAtoms[0].atomSet else: otherAtomSet = NmrConstraint.FixedAtomSet(self.nmrConstraintStore,atoms = otherAtoms) resSet.addAtomSet(otherAtomSet) resSet.removeAtomSet(atomSet1) infoText.sort() for line in infoText: print line
# for distConstr in ccpnConstraintList.sortedConstraints(): print "Constraint %d: %.1f-%.1f" % (distConstr.serial, distConstr.lowerLimit, distConstr.upperLimit) for constrItem in distConstr.sortedItems(): # # Now list the atoms linked to each of the two resonances associated with # this item. # atomList = [] resonanceList = getResonancesFromPairwiseConstraintItem(constrItem) for resonance in resonanceList: atomList.append([]) if resonance.resonanceSet: for atomSet in resonance.resonanceSet.atomSets: for atom in atomSet.atoms: atomList[-1].append("%d.%s" % (atom.residue.seqCode,atom.name)) atomList[-1].sort() atomList[-1] = ','.join(atomList[-1]) print " (%s) - (%s)" % (atomList[0],atomList[1]) print