def updateSpinSystems(self): textMatrix = [] objectList = [] colorMatrix = [] headingList = self.getHeadings() for spinSystem in self.getTentativeSpinSystems(): residueText = None residue, probability = self.getProbableResidue(spinSystem) if residue: residueText = '%d%s' % (residue.seqCode, getResidueCode(residue)) links = [] color = '#D04040' if findConnectedSpinSystem(spinSystem, delta=-1): links.append('-1') if findConnectedSpinSystem(spinSystem, delta=1): links.append('+1') if len(links) == 2: color = '#40B040' elif len(links) == 1: color = '#B0B040' datum = [] datum.append(spinSystem.serial) datum.append(residueText) datum.append(probability) datum.append(' '.join(links)) self.addShiftData(spinSystem, datum) colors = [None] * len(headingList) colors[3] = color objectList.append(spinSystem) textMatrix.append(datum) colorMatrix.append(colors) if self.spinSystem not in objectList: self.spinSystem = None self.spinSystemMatrix.update(headingList=headingList, objectList=objectList, textMatrix=textMatrix, colorMatrix=colorMatrix) self.updateButtons() self.waiting = False
def getConnectedSpinSystems(self, spinSystem): if self.link == '-1': prevSS = findConnectedSpinSystem(spinSystem, delta=-1) nextSS = None elif self.link == '+1': prevSS = None nextSS = findConnectedSpinSystem(spinSystem, delta=1) else: prevSS = findConnectedSpinSystem(spinSystem, delta=-1) nextSS = findConnectedSpinSystem(spinSystem, delta=1) return prevSS, nextSS
def makeInterConstraints(self, resonances, constraintSet): from ccpnmr.analysis.core.ConstraintBasic import getFixedResonance from ccpnmr.analysis.core.AssignmentBasic import findConnectedSpinSystem project = constraintSet.root constraintList = constraintSet.newDistanceConstraintList() constraintList.name = 'Seq connections' resDict = {} spinSystemDict = {} for resonance in resonances: resDict[resonance] = True spinSystem = resonance.resonanceGroup if spinSystem: spinSystemDict[spinSystem] = None spinSystems = spinSystemDict.keys() for spinSystem in spinSystems: nextSpinSystem = findConnectedSpinSystem(spinSystem, delta=1) if nextSpinSystem: ca = spinSystem.newAtoms.get('CA') c = spinSystem.newAtoms.get('C') n = nextSpinSystem.newAtoms.get('N') if ca and c and n: if resDict.get(ca) is None: resonances.append(ca) if resDict.get(c) is None: resonances.append(c) if resDict.get(n) is None: resonances.append(n) c_n = constraintList.newDistanceConstraint( weight=1.0, origData=1.0, targetValue=1.32, upperLimit=1.35, lowerLimit=1.29, error=0.06) # below based on angle constraints ca_n = constraintList.newDistanceConstraint( weight=1.0, origData=1.0, targetValue=2.415, upperLimit=2.513, lowerLimit=2.316, error=0.197) frCa = getFixedResonance(constraintSet, ca) frC = getFixedResonance(constraintSet, c) frN = getFixedResonance(constraintSet, n) item = ca_n.newDistanceConstraintItem( resonances=[frCa, frN]) item = c_n.newDistanceConstraintItem(resonances=[frC, frN]) return resonances, constraintList
def linkSpinSystems(self, spinSystems): data = [] for spinSystem in spinSystems: residue, p = self.getProbableResidue(spinSystem) key = '%s%s%4.4d' % (residue.chain.molSystem.code, residue.chain.code, residue.seqCode) data.append([key, residue.seqCode, residue, spinSystem]) data.sort() seqCodes = [x[1] for x in data] residues = [x[2] for x in data] spinSystems = [x[3] for x in data] N = len(data) for i in range(N): if i > 0: delta = seqCodes[i] - seqCodes[i - 1] if delta == 1 and (residues[i].chain is residues[i - 1].chain): ss = findConnectedSpinSystem(spinSystems[i], delta=-1) if ss: mergeSpinSystems( ss, spinSystems[i - 1]) # copy resonances across & delete makeSeqSpinSystemLink(spinSystems[i - 1], spinSystems[i], delta=1) if i < N - 1: delta = seqCodes[i + 1] - seqCodes[i] if delta == 1 and (residues[i].chain is residues[i + 1].chain): ss = findConnectedSpinSystem(spinSystems[i], delta=1) if ss: mergeSpinSystems( ss, spinSystems[i + 1]) # copy resonances across & delete makeSeqSpinSystemLink(spinSystems[i], spinSystems[i + 1], delta=1) self.updateSpinSystemsAfter()
def networkAnchorAssign(peakLists, intensityType='height', strictness=2, threshold=1.0, isotopeTolerances=None, assignPeakList=True, constraintSet=None, labelling=None, minLabelFraction=0.1, scale=None, distParams=None, structure=None, progressBar=None, nexus=None): if not peakLists: return if isotopeTolerances: TOLERANCE_DICT = isotopeTolerances distanceFunction = None if distParams: distanceFunction = lambda val: getNoeDistance(val, distParams) project = peakLists[0].root nmrProject = peakLists[0].topObject molSystem = project.findFirstMolSystem() shiftList = peakLists[0].dataSource.experiment.shiftList isotopes = set([]) # Get known network of connectivities inc covalent and NOE network = {} covalent = {} # Assign some peaks with uniquely matching shifts for peakList in peakLists: if labelling is True: expLabelling = peakList.dataSource.experiment else: expLabelling = labelling network, covalent = getCloseSingleShiftMatches( peakList, network, covalent, labelling=expLabelling, minLabelFraction=minLabelFraction, intensityType=intensityType, progressBar=progressBar) # Get existing assigned NOE network totalPeaks = 0 for peakList in peakLists: if not peakList.peaks: continue meanIntensity = getMeanPeakIntensity(peakList.peaks, intensityType=intensityType) if scale: meanIntensity = scale spectrum = peakList.dataSource distDims = getThroughSpaceDataDims(spectrum) for dataDim in distDims: isotopes.update(getDataDimIsotopes(dataDim)) hDims = [dd.dim - 1 for dd in distDims] numPeaks = len(peakList.peaks) totalPeaks += numPeaks info = (spectrum.experiment.name, spectrum.name, peakList.serial, numPeaks) if progressBar: progressBar.setText( 'Get existing NOE network\nfor %s:%s:%d - %d peaks' % info) progressBar.set(0) progressBar.total = numPeaks progressBar.open() progressBar.update_idletasks() else: print 'Get existing NOE network for %s:%s:%d - %d peaks' % info if len(hDims) != 2: continue for peak in peakList.peaks: if progressBar: progressBar.increment() peakDims = peak.sortedPeakDims() peakDim1 = peakDims[hDims[0]] contribs1 = peakDim1.peakDimContribs if contribs1: peakDim2 = peakDims[hDims[1]] contribs2 = peakDim2.peakDimContribs if contribs2: peakIntensity = peak.findFirstPeakIntensity( intensityType=intensityType) if peakIntensity: intensity = peakIntensity.value intensity /= float(len(contribs1)) intensity /= float(len(contribs2)) #intensity /= meanIntensity for contrib1 in contribs1: resonance1 = contrib1.resonance if network.get(resonance1) is None: covalent[resonance1] = {} network[resonance1] = {} intensity2 = intensity if resonance1.resonanceSet: intensity2 /= float( len(resonance1.resonanceSet. findFirstAtomSet().atoms)) for contrib2 in contribs2: resonance2 = contrib2.resonance if network.get(resonance2) is None: network[resonance2] = {} covalent[resonance2] = {} if resonance2.resonanceSet: intensity2 /= float( len(resonance2.resonanceSet. findFirstAtomSet().atoms)) if not contrib2.peakContribs: if not contrib1.peakContribs: network[resonance1][resonance2] = [ intensity2, peak ] network[resonance2][resonance1] = [ intensity2, peak ] else: for peakContrib in contrib2.peakContribs: if peakContrib in contrib1.peakContribs: network[resonance1][resonance2] = [ intensity2, peak ] network[resonance2][resonance1] = [ intensity2, peak ] break else: pass # Should warn covalentIntensity = 5.0 # Need to optimise this # Get covalent network if progressBar: progressBar.setText('Getting covalent network') progressBar.set(0) progressBar.total = len(nmrProject.resonances) progressBar.open() progressBar.update_idletasks() else: print 'Getting covalent network - %d resonances' % len( nmrProject.resonances) neighbours = {} chemAtomToAtom = {} c = 0 for resonance in nmrProject.resonances: if progressBar: progressBar.increment() if resonance.isotopeCode not in isotopes: continue resonanceSet = resonance.resonanceSet if not resonanceSet: continue if network.get(resonance) is None: network[resonance] = {} covalent[resonance] = {} for atomSet in resonanceSet.atomSets: for atom in atomSet.atoms: residue = atom.residue if chemAtomToAtom.get(residue) is None: chemAtomToAtom[residue] = {} for atom2 in residue.atoms: chemAtomToAtom[residue][atom2.chemAtom] = atom2 chemAtom = atom.chemAtom if chemAtom.waterExchangeable: continue chemAtoms = neighbours.get(chemAtom) if chemAtoms is None: chemAtoms = [] for atom2 in residue.atoms: if atom2 is atom: continue chemAtom2 = atom2.chemAtom if DEFAULT_ISOTOPES.get( chemAtom2.elementSymbol) not in isotopes: continue numBonds = getNumConnectingBonds(atom, atom2, limit=6) if numBonds < 5: chemAtoms.append(chemAtom2) neighbours[chemAtom] = chemAtoms atoms = [] for chemAtomB in chemAtoms: atom2 = chemAtomToAtom[residue].get(chemAtomB) if atom2 is not None: atoms.append(atom2) residue2 = getLinkedResidue(residue, 'prev') if residue2: for atom2 in residue2.atoms: chemAtom2 = atom2.chemAtom if DEFAULT_ISOTOPES.get( chemAtom2.elementSymbol) not in isotopes: continue numBonds = getNumConnectingBonds(atom, atom2, limit=6) if numBonds < 5: atoms.append(atom2) residue2 = getLinkedResidue(residue, 'next') if residue2: for atom2 in residue2.atoms: chemAtom2 = atom2.chemAtom if DEFAULT_ISOTOPES.get( chemAtom2.elementSymbol) not in isotopes: continue numBonds = getNumConnectingBonds(atom, atom2, limit=6) if numBonds < 5: atoms.append(atom2) for atom2 in atoms: atomSet2 = atom2.atomSet if atomSet2 and (atomSet2 is not atomSet): for resonanceSet2 in atomSet2.resonanceSets: for resonance2 in resonanceSet2.resonances: if network.get(resonance2) is None: network[resonance2] = {} covalent[resonance2] = {} if network[resonance].get( resonance2 ) is None: # Not already in network network[resonance][resonance2] = [ covalentIntensity, None ] network[resonance2][resonance] = [ covalentIntensity, None ] covalent[resonance][resonance2] = True covalent[resonance2][resonance] = True c += 1 #print 'Atom pair network connections %d' % c c = 0 for ss in nmrProject.resonanceGroups: ss2 = findConnectedSpinSystem(ss, delta=-1) if ss2: for r1 in ss.resonances: if r1.isotopeCode not in isotopes: continue for r2 in ss.resonances: if r2.isotopeCode not in isotopes: continue if network.get(r1) is None: network[r1] = {} covalent[r1] = {} if network.get(r2) is None: network[r2] = {} covalent[r2] = {} if network[r1].get(r2) is None: network[r1][r2] = [covalentIntensity, None] network[r2][r1] = [covalentIntensity, None] covalent[r1][r2] = True covalent[r2][r1] = True c += 1 #print 'Anonymous intra residue connections %d' % c done = {} iter = 0 nAssign = 1 k = 0 dataSets = [] while nAssign > 0: #while iter < 1: data = [] nAssign = 0 iter += 1 if progressBar: progressBar.setText('Anchoring iteration %d' % iter) progressBar.set(0) progressBar.total = totalPeaks progressBar.open() progressBar.update_idletasks() else: print 'Anchoring iteration %d' % iter closeResonancesDict = {} for peakList in peakLists: if not peakList.peaks: continue spectrum = peakList.dataSource distDims = getThroughSpaceDataDims(spectrum) hDims = [dd.dim - 1 for dd in distDims] tolerances = getDimTolerances(spectrum) bondedDims = getBondedDimsDict(spectrum) #meanIntensity = getMeanPeakIntensity(peakList.peaks, intensityType=intensityType) info = (spectrum.experiment.name, spectrum.name, peakList.serial, len(peakList.peaks)) #print ' Using %s:%s:%d - %d peaks' % info if len(hDims) != 2: continue for peak in peakList.peaks: if progressBar: progressBar.increment() if done.get(peak): continue peakDims = peak.sortedPeakDims() if peakDims[hDims[0]].peakDimContribs: if peakDims[hDims[1]].peakDimContribs: continue boundResonances = {} if closeResonancesDict.get(peak) is None: possibles = [] for dim in hDims: peakDim = peakDims[dim] if peakDim.peakDimContribs: possibles.append([ contrib.resonance for contrib in peakDim.peakDimContribs ]) continue resonances = [] shifts = findMatchingPeakDimShifts( peakDim, shiftRanges=None, tolerance=tolerances[dim], aliasing=True, findAssigned=False) dim2 = bondedDims.get(dim) peakDim2 = None if dim2 is not None: peakDim2 = peakDims[dim2] shifts2 = findMatchingPeakDimShifts( peakDim2, shiftRanges=None, tolerance=tolerances[dim2], aliasing=True, findAssigned=False) for shift in shifts: resonance1 = shift.resonance for shift2 in shifts2: resonance2 = shift2.resonance if areResonancesBound( resonance1, resonance2): if labelling: fraction = getResonancePairLabellingFraction( resonance1, resonance2, expLabelling) if fraction < minLabelFraction: continue resonances.append(resonance1) boundResonances[ resonance1] = resonance2 break else: for shift in shifts: resonance = shift.resonance if labelling: fraction = getResonanceLabellingFraction( resonance, expLabelling) if fraction < minLabelFraction: continue resonances.append(resonance) possibles.append(resonances) closeResonancesDict[peak] = possibles else: possibles = closeResonancesDict[peak] if not possibles[0]: continue # warn if not possibles[1]: continue # warn peakIntensity = peak.findFirstPeakIntensity( intensityType=intensityType) if not peakIntensity: print 'Peak missing intensity', peak continue else: intensity = peakIntensity.value #/meanIntensity scores = {} numbers = {} bestScore = None bestPair = None for resonance1 in possibles[0]: if not resonance1.resonanceGroup: continue if network.get(resonance1) is None: continue anchors1 = network[resonance1].keys() spinSystem1 = resonance1.resonanceGroup for resonance2 in possibles[1]: if not resonance2.resonanceGroup: continue if network.get(resonance2) is None: continue anchors2 = network[resonance2].keys() pair = (resonance1, resonance2) spinSystem2 = resonance2.resonanceGroup for resonance3 in anchors1: spinSystem3 = resonance3.resonanceGroup if (strictness > 0) and spinSystem3: check = False if (spinSystem3 is spinSystem1) or ( spinSystem3 is spinSystem2): check = True if (strictness > 1) and spinSystem3.residue: if spinSystem1.residue: if abs(spinSystem1.residue.seqCode - spinSystem3.residue.seqCode ) < 2: check = True if spinSystem2.residue: if abs(spinSystem2.residue.seqCode - spinSystem3.residue.seqCode ) < 2: check = True else: check = True if check and (resonance3 in anchors2): intensityA, peakA = network[resonance1][ resonance3] intensityB, peakB = network[resonance2][ resonance3] if scores.get(pair) is None: scores[pair] = 0.0 numbers[pair] = 0.0 shift1 = resonance1.findFirstShift( parentList=shiftList) shift2 = resonance2.findFirstShift( parentList=shiftList) if shift1 and shift2: delta1 = abs(peakDims[hDims[0]].realValue - shift1.value) delta2 = abs(peakDims[hDims[1]].realValue - shift2.value) tol1 = TOLERANCE_DICT[ resonance1.isotopeCode] tol2 = TOLERANCE_DICT[ resonance2.isotopeCode] match1 = (tol1 - delta1) / tol1 match2 = (tol2 - delta2) / tol2 scores[ pair] += intensityA * intensityB * match1 * match2 numbers[pair] += 1 nGood = 0 for pair in scores.keys(): resonance1, resonance2 = pair score = scores[pair] if score > threshold: nGood += 1 if (bestScore is None) or (score > bestScore): bestScore = score bestPair = pair #if bestScore and (nGood < 2): for pair in scores.keys(): resonance1, resonance2 = pair if scores[pair] < threshold: #if len(scores.keys()) > 1: continue else: intensity2 = intensity / nGood bestPair = pair bestScore = scores[pair] for i in (0, 1): resonance = bestPair[i] if assignPeakList: assignResToDim(peakDims[hDims[i]], resonance, doWarning=False) bound = boundResonances.get(resonance) if bound: dim2 = bondedDims.get(hDims[i]) if dim2 is not None: assignResToDim(peakDims[dim2], bound, doWarning=False) if network.get(resonance) is None: network[resonance] = {} #name1 = makeResonanceGuiName(bestPair[0]) #name2 = makeResonanceGuiName(bestPair[1]) if resonance1.resonanceSet: intensity2 /= float( len(resonance1.resonanceSet.findFirstAtomSet(). atoms)) if resonance2.resonanceSet: intensity2 /= float( len(resonance2.resonanceSet.findFirstAtomSet(). atoms)) if labelling: intensity2 /= getResonanceLabellingFraction( resonance1, expLabelling) intensity2 /= getResonanceLabellingFraction( resonance2, expLabelling) nAssign += 1 covalent[bestPair[0]][bestPair[1]] = None covalent[bestPair[1]][bestPair[0]] = None network[bestPair[0]][bestPair[1]] = [intensity2, peak] network[bestPair[1]][bestPair[0]] = [intensity2, peak] done[peak] = True #print ' Assigned:', nAssign dataSets.append(data) from ccpnmr.analysis.core.ConstraintBasic import getDistancesFromIntensity, getIntensityDistanceTable from ccpnmr.analysis.core.ConstraintBasic import makeNmrConstraintStore, getFixedResonance if constraintSet is None: constraintSet = makeNmrConstraintStore(nmrProject) if not constraintSet: return constraintList = constraintSet.newDistanceConstraintList() peakConstraints = {} doneResonances = {} for resonance1 in network.keys(): fixedResonance1 = getFixedResonance(constraintSet, resonance1) for resonance2 in network[resonance1].keys(): if resonance1 is resonance2: continue key = [resonance1.serial, resonance2.serial] key.sort() key = tuple(key) if doneResonances.get(key): continue else: doneResonances[key] = True if covalent.get(resonance1): if covalent[resonance1].get(resonance2): # J connected are close so what do we do...? #print "Skip", makeResonanceGuiName(resonance1), makeResonanceGuiName(resonance2) continue fixedResonance2 = getFixedResonance(constraintSet, resonance2) intensity, peak = network[resonance1][resonance2] if peak: peakList = peak.peakList spectrum = peakList.dataSource experiment = spectrum.experiment if not distanceFunction: noeDistClasses = getIntensityDistanceTable(spectrum) distanceFunction = lambda val: getDistancesFromIntensity( noeDistClasses, val) constraint = peakConstraints.get(peak) if not constraint: constraint = constraintList.newDistanceConstraint( weight=1.0, origData=intensity) peakContrib = constraint.newConstraintPeakContrib( experimentSerial=experiment.serial, dataSourceSerial=spectrum.serial, peakListSerial=peakList.serial, peakSerial=peak.serial) peakConstraints[peak] = constraint else: intensity += constraint.origData dist, minDist, maxDist = distanceFunction(intensity / meanIntensity) error = abs(maxDist - minDist) constraint.origData = intensity constraint.targetValue = dist constraint.upperLimit = maxDist constraint.lowerLimit = minDist constraint.error = error item = constraint.newDistanceConstraintItem( resonances=[fixedResonance1, fixedResonance2]) return constraintList
def getInitialAssignMatrix(chain, spinSystems, peakLists, shiftList, keepExisting=False, progressBar=None): if progressBar: progressBar.setText('Preparing Spin System Typing') progressBar.total = len(spinSystems) progressBar.set(0) progressBar.open() progressBar.parent.update_idletasks() peakListDict = {} for peakList in peakLists: peakListDict[peakList] = True allResidues = chain.sortedResidues() nResidues = len(allResidues) prolyl = [] residues = [] prevResidueDict = {} rMatrix = [] for i, residue in enumerate(allResidues): row = [0.0] * nResidues if i + 1 < nResidues: row[i + 1] = 1.0 rMatrix.append(row) prevResidueDict[residue] = getLinkedResidue(residue, 'prev') if residue.ccpCode in PROLYL: prolyl.append(i) else: residues.append(residue) prolyl.reverse() for row in rMatrix: for i in prolyl: del row[i] for i in prolyl: del rMatrix[i] nResidues = len(residues) nSpinSystems = len(spinSystems) #t0 = time.time() aMatrix = [[0] * nResidues for x in range(nSpinSystems)] for i, spinSystem in enumerate(spinSystems): #if hasattr(spinSystem, 'codeScoreDict'): # del spinSystem.codeScoreDict if keepExisting: residueA = spinSystem.residue ccpCodeA = spinSystem.ccpCode if residueA and (residueA.chain is chain): for j, residue in enumerate(residues): if residue is residueA: score = 1.0 else: score = 0.0 aMatrix[i][j] = score continue elif ccpCodeA: for j, residue in enumerate(residues): if residue.ccpCode == ccpCodeA: score = 1.0 else: score = 0.0 aMatrix[i][j] = score continue shifts = [] for resonance in spinSystem.resonances: for contrib in resonance.peakDimContribs: peak = contrib.peakDim.peak if peakListDict.get(peak.peakList): shift = resonance.findFirstShift(parentList=shiftList) if shift: shifts.append(shift) break scores = getShiftsChainProbabilities(shifts, chain) prevSpinSystem = findConnectedSpinSystem(spinSystem, delta=-1) if spinSystem.residue and not prevSpinSystem: residueB = getLinkedResidue(spinSystem.residue, linkCode='prev') nmrProject = spinSystem.topObject prevSpinSystem = nmrProject.findFirstResonanceGroup( residue=residueB) prevScores = None if prevSpinSystem: prevShifts = [] for resonance in prevSpinSystem.resonances: for contrib in resonance.peakDimContribs: peak = contrib.peakDim.peak if peakListDict.get(peak.peakList): shift = resonance.findFirstShift(parentList=shiftList) if shift: prevShifts.append(shift) break prevSpinSystem.shifts = prevShifts prevScores = getShiftsChainProbabilities(prevShifts, chain) for j, residue in enumerate(residues): aMatrix[i][j] = scores[residue.ccpCode] or 1e-150 prevResidue = prevResidueDict.get(residue) if prevResidue and prevScores: aMatrix[i][j] *= prevScores[prevResidue.ccpCode] or 1e-150 else: aMatrix[i][j] *= aMatrix[i][j] if progressBar: progressBar.increment() #print "Time", time.time() - t0 A = matrix(aMatrix) R = matrix(rMatrix) # Normalise per Spin System for s in xrange(A.shape[0]): A[s] /= A[s].max() # Normalise per Residue A = A.T for s in xrange(A.shape[0]): A[s] /= A[s].max() A = A.T A /= A.max() if progressBar: progressBar.close() return A, R, spinSystems, residues
def assignSpecNonRootResonances(rootPeaks, targetPeakList, tolerances=None, diagTolerance=0.5, waterMinPpm=4.88, waterMaxPpm=4.92, progressBar=None, assignType=False, refExpsCO=None): """Descrn: Inputs: Output: """ peaks, dimMapping = pickAssignSpecFromRoot(rootPeaks, targetPeakList, tolerances=tolerances, progressBar=progressBar, pickNew=False) spectrum = targetPeakList.dataSource targetDataDim = None rootDataDims = set() for dataDim in spectrum.dataDims: if dataDim.dim in dimMapping.values(): rootDataDims.add(dataDim.dim) else: targetDataDim = dataDim if targetDataDim is None: msg = 'No non-root dimension found for %s:%s' showWarning('Failure', msg % (spectrum.experiment.name, spectrum.name)) resonances = assignDimNewResonances(peaks, targetDataDim.dim, diagTolerance=diagTolerance, waterMinPpm=waterMinPpm, waterMaxPpm=waterMaxPpm, assignType=assignType) if not refExpsCO: refExps, refExpsCO = ExperimentBasic.getSeqAssignRefExperiments( targetPeakList.root) refExperiment = targetPeakList.dataSource.experiment.refExperiment if refExperiment in refExpsCO: resonances2 = set([r for r in resonances if not r.resonanceGroup]) rootSpinSystems = set() for peak in peaks: for peakDim in peak.peakDims: if peakDim.dim in rootDataDims: for contrib in peakDim.peakDimContribs: spinSystem = contrib.resonance.resonanceGroup if spinSystem: rootSpinSystems.add(spinSystem) if len(rootSpinSystems) == 1: rootSpinSystem = rootSpinSystems.pop() prevSpinSystem = findConnectedSpinSystem(rootSpinSystem, delta=-1) if not prevSpinSystem: prevSpinSystem = rootSpinSystem.nmrProject.newResonanceGroup() makeSeqSpinSystemLink(prevSpinSystem, rootSpinSystem, delta=1) resonances2.update(prevSpinSystem.resonances) prevSpinSystem.setResonances(resonances2)
def assignSpinSystemstoResidues(spinSystems, residues, strategy=None, guiParent=None): ''' This method is somewhat different than multiple calls to assignmentBasic.assignSpinSystemResidue does. If you want to assign more spin systems in one go, you should prevent merging 2 spin systems A and B if B possibly needs to be assigned in a next iteration to another residue. Also multiple calls to assignmentBasic.assignSpinSystem would cause unnescesarry breaking of sequential links, because they don't fit the assignment temporarely. In this funtion, non-valid sequential links are only corrected after all assignments have been made. Also, present sequential links are ignored in this function, in the sense that linked spin systems are not automatically assigned to neighboring residues because they might conflict with the answer the annealing presented. Also no new sequential links are made. args: spinSystems: list of spin systems residues: list of corrsponding residues kwargs: strategy: what to do when if a spin systems should be assigned to a residue that already has a spin system assignment. five possibilities: 1) None, in this case the user is asked every single time this happens. 2) 'skip', leave the old spin system assignment. 3) 'noMerge', assign but do not merge. 4) 'remove', remove old spin system assignment 4) 'merge', assign and merge. guiParent: nescesarry to raise a popup to ask for a merging strategy, only important when strategy=None output: None ''' #proposedSRdict = {} proposedRSdict = {} visitedSpinSystems = set() visitedResidues = set() deAssignedSpinSystems = set() # Determine the proposed mapping between spin systems and residues and # the other way around. Only a unique mapping between residues and # spin systems is used, because it is impossible to assign one spin # system to different residues. # Although it is technically possible to assign two spin systems # to one residue that is not what I want to do (unless there is already a # spin system assigned to the residue, in which case I'll ask what to do # with it.). for spinSystem, residue in set(zip(spinSystems, residues)): if not spinSystem or not residue: continue if spinSystem in visitedSpinSystems or residue in visitedResidues: proposedRSdict.pop(residue, None) continue proposedRSdict[residue] = spinSystem visitedSpinSystems.add(spinSystem) visitedResidues.add(residue) # Figuring out which of the spin systems assigned to the targetted #residues are not going to be shuffled around, they potentially have to get # merged or correct assignment might already be present assignSpinSystems = set(proposedRSdict.values()) for residue, spinSystem in proposedRSdict.items(): nonMovingSpinSystems = [] placeHolderSpinSystems = [] oldSpinSystems = residue.getResonanceGroups() for oldSpinSystem in oldSpinSystems: if oldSpinSystem is spinSystem or oldSpinSystem not in assignSpinSystems: if oldSpinSystem.resonances: nonMovingSpinSystems.append(oldSpinSystem) else: placeHolderSpinSystems.append(oldSpinSystem) if nonMovingSpinSystems: # The spin system is already assigned to the residue if spinSystem in nonMovingSpinSystems: continue else: tempStrategy = strategy or askToMergeSpinSystems( residue, spinSystem, nonMovingSpinSystems + placeHolderSpinSystems, guiParent=guiParent) # options are: 'merge','remove','noMerge','skip' if tempStrategy == 'skip': continue elif tempStrategy == 'noMerge': assignSpinSystemResidueMinimal(spinSystem, residue) elif tempStrategy == 'remove': for oldSpinSystem in nonMovingSpinSystems: assignSpinSystemResidueMinimal(oldSpinSystem, None) deAssignedSpinSystems.add(oldSpinSystem) assignSpinSystemResidueMinimal(spinSystem, residue) for placeHolderSpinSystem in placeHolderSpinSystems: mergeSpinSystems(placeHolderSpinSystem, spinSystem) elif tempStrategy == 'merge': assignSpinSystemResidueMinimal(spinSystem, residue) for oldSpinSystem in placeHolderSpinSystems + nonMovingSpinSystems: mergeSpinSystems(oldSpinSystem, spinSystem) else: assignSpinSystemResidueMinimal(spinSystem, residue) for placeHolderSpinSystem in placeHolderSpinSystems: mergeSpinSystems(placeHolderSpinSystem, spinSystem) # Removing sequentials links that do not make sense any longer for spinSystem in assignSpinSystems.union(deAssignedSpinSystems): connectedSpinSystems = [ findConnectedSpinSystem(spinSystem, delta=i) for i in (-1, 1) ] residue = spinSystem.getResidue() if residue: connectedResidues = [ residue.chain.findFirstResidue(seqId=residue.seqId + i) for i in (-1, 1) ] for connectedResidue, connectedSpinSystem, i in zip( connectedResidues, connectedSpinSystems, [-1, 1]): if connectedResidue: assignedSpinSystems = connectedResidue.getResonanceGroups() if connectedSpinSystem not in assignedSpinSystems: clearSeqSpinSystemLinks(spinSystem, delta=i) else: for connectedSpinSystem, i in zip(connectedSpinSystems, [-1, 1]): if connectedSpinSystem: connectedResidue = connectedSpinSystem.getResidue() if connectedResidue: residue = connectedResidue.chain.findFirstResidue( seqId=residue.seqId + (i * -1)) if residue and residue.getResonanceGroups(): clearSeqSpinSystemLinks(spinSystem, delta=i)
def linkSpinSystemInterIntraResonances(spinSystem, activeLists, tolerances=None): nmrProject = spinSystem.topObject prevSpinSystem = findConnectedSpinSystem(spinSystem) allowedRefExps, coRefExps = getSeqAssignRefExperiments(nmrProject.root) if not prevSpinSystem: if spinSystem.residue: residueB = getLinkedResidue(spinSystem.residue, linkCode='prev') prevSpinSystem = nmrProject.findFirstResonanceGroup( residue=residueB) if not prevSpinSystem: prevSpinSystem = nmrProject.newResonanceGroup() makeSeqSpinSystemLink(prevSpinSystem, spinSystem) peaks = [] found = {} expTypes = {} linkDims = {} # go though the peaks associated with this spin system # within the selected peak lists # find the indirect, linking dimension for resonance in spinSystem.resonances: if resonance.isotopeCode != '15N': continue if not isResonanceAmide(resonance): continue for contrib in resonance.peakDimContribs: peakDim = contrib.peakDim peak = peakDim.peak if found.get(peak): continue peakList = peak.peakList if peakList not in activeLists: continue setupPeakHeight(peak) intensity = peak.findFirstPeakIntensity(intensityType='height') if not intensity: continue spectrum = peakList.dataSource expType = expTypes.get(peakList, spectrum.experiment.refExperiment) expTypes[peakList] = expType linkDim = linkDims.get(peakList) if linkDim is None: boundDict = {} for dataDimA, dataDimB in getOnebondDataDims(spectrum): boundDict[dataDimA] = dataDimB boundDict[dataDimB] = dataDimA dims = [] for dataDim in spectrum.dataDims: dataDimRef = getPrimaryDataDimRef(dataDim) if not dataDimRef: continue isotopes = '/'.join(dataDimRef.expDimRef.isotopeCodes) dims.append((isotopes, dataDim)) dims.sort() for isotopes, dataDim in dims: if '13C' == isotopes: linkDim = (dataDim.dim, isotopes) break elif '1H' == isotopes: dataDimB = boundDict.get(dataDim) if dataDimB: dataDimRefB = getPrimaryDataDimRef(dataDimB) if '15N' in dataDimRefB.expDimRef.isotopeCodes: continue linkDim = (dataDim.dim, isotopes) break linkDims[peakList] = linkDim if linkDim is None: continue if peakDim.dim is linkDim[0]: continue found[peak] = True peakDimL = peak.findFirstPeakDim(dim=linkDim[0]) isotope = linkDim[1] peaks.append((peak, expType, peakDimL, isotope, intensity.value)) peakTypes = [] interResonances = {} intraResonances = {} for peak, expType, peakDim, isotope, height in peaks: ppm = peakDim.value atomType = None if expType in coRefExps: isInter = True elif 'N[coca]' in expType.name: isInter = False elif 'N_' in expType.name: isInter = False else: isInter = None resonance = None contrib = peakDim.findFirstPeakDimContrib() if contrib: resonance = contrib.resonance if isInter and resonance.assignNames: atomType = resonance.assignNames[0] interResonances[atomType] = (resonance, ppm, prevSpinSystem) if (isInter is False) and resonance.assignNames: atomType = resonance.assignNames[0] intraResonances[atomType] = (resonance, ppm, spinSystem) if not atomType: atomType = guessAtomType(expType, ppm, height) peakTypes.append((peakDim, atomType, contrib, isotope, isInter, ppm)) # Get known inter/intra resonance assignments # for each atom type for peakDim, atomType, contrib, isotope, isInter, ppm in peakTypes: if isInter is None: continue elif isInter: resDict = interResonances uniqSpinSystem = prevSpinSystem else: resDict = intraResonances uniqSpinSystem = spinSystem if atomType: resonance, ppm2, ss = resDict.get(atomType, (None, None, None)) if (resonance is None) and contrib: resDict[atomType] = (contrib.resonance, ppm, uniqSpinSystem) # Make any new assignments for the unambig peaks untypedIntra = [] untypedInter = [] for i, data in enumerate(peakTypes): (peakDim, atomType, contrib, isotope, isInter, ppm) = data if isInter is None: continue elif isInter: untyped = untypedInter resDict = interResonances uniqSpinSystem = prevSpinSystem else: resDict = intraResonances untyped = untypedIntra uniqSpinSystem = spinSystem if atomType: # Get any previously used resonances for this atom type resonance, ppm2, ss = resDict.get(atomType, (None, None, None)) # If no prev resonance, look at the peak assignment if (not resonance) and contrib: resonance = contrib.resonance # Check to ensure that any existing resonance # is from the correct, this/prev spin system if resonance: spinSystem2 = resonance.resonanceGroup if spinSystem2 and (spinSystem2 is not uniqSpinSystem): resonance = None # If no valid reasonance yet, check named ones # in the required spin system if not resonance: for resonance2 in uniqSpinSystem.resonances: if atomType in resonance2.assignNames: resonance = resonance2 break # If no valid resonance yet, make a new one if not resonance: resonance = nmrProject.newResonance(isotopeCode=isotope) # If peak dim is assigned to the wrong resonance # clear the assignment if contrib and contrib.resonance is not resonance: clearPeakDim(peakDim) contrib = None # Ensure the peak dim is assigned correctly if not contrib: assignResToDim(peakDim, resonance) # Check type of resonance set correctly if not resonance.assignNames: assignResonanceType(resonance, assignNames=(atomType, )) # Check spin system set correctly if resonance.resonanceGroup is not uniqSpinSystem: addSpinSystemResonance(uniqSpinSystem, resonance) # Store resonance by atom type, so that it can # be picked up later resDict[atomType] = (resonance, ppm, uniqSpinSystem) else: untyped.append((peakDim, contrib, isotope, isInter, ppm, i)) uniqResonances = interResonances.values() + intraResonances.values() # Cluster untyped peaks interCluster = {} intraCluster = () interData = (untypedInter, interCluster, prevSpinSystem) intraData = (untypedIntra, intraCluster, spinSystem) for untyped, clusters, uniqSpinSystem in (interData, intraData): for peakDim, contrib, isotope, isInter, ppm, i in untyped: if peakDim in clusters: continue if tolerances: tolerance = tolerances[isotope] else: tolerance = getAnalysisDataDim(peakDim.dataDim).assignTolerance if contrib: resonance = contrib.resonance else: resonance = None cluster = [peakDim] interCluster[peakDim] = True for peakDimB, contribB, isotopeB, isInterB, ppmB, i in untyped: if isotope != isotopeB: continue if abs(ppmB - ppm) > tolerance: continue if peakDim.peak.peakList == peakDimB.peak.peakList: continue if contribB: if not resonance: resonance = contribB.resonance if resonance is not contribB.resonance: clearPeakDim(peakDimB) assignResToDim(peakDimB, resonance, tolerance=tolerance) cluster.append(peakDimB) clusters[peakDimB] = True if not resonance: # Try to macth to any typed peaks for peakDimB, atomType, contribB, isotopeB, isInterB, ppmB in peakTypes: if not contribB: continue if not atomType: continue if isotope != isotopeB: continue if abs(ppmB - ppm) > tolerance: continue if peakDim.peak.peakList == peakDimB.peak.peakList: continue resonance = contribB.resonance # Set type for this peak peakTypes[i] = (peakDim, atomType, contrib, isotope, isInter, ppm) break if not resonance: resonance = nmrProject.newResonance(isotopeCode=isotope) for peakDimC in cluster: clearPeakDim(peakDimC) assignResToDim(peakDimC, resonance, tolerance=tolerance) uniqResonances.append((resonance, ppm, uniqSpinSystem)) if resonance.resonanceGroup is not uniqSpinSystem: addSpinSystemResonance(uniqSpinSystem, resonance) # E.g. Find the HNCA peaks which best match the HNcoCA/iHNCA resonances matchDict = {} closestDict = {} for peakDim, atomType, contrib, isotope, isInter, ppm in peakTypes: if isInter is not None: # Not through HNcoCA or iHNCA continue if tolerances: tolerance = tolerances[isotope] else: tolerance = getAnalysisDataDim(peakDim.dataDim).assignTolerance matches = [] shiftList = peakDim.peak.peakList.dataSource.experiment.shiftList for resonanceB, ppm2, uniqSpinSystem in uniqResonances: if resonanceB.isotopeCode != isotope: continue assignNames = resonanceB.assignNames if assignNames and (atomType not in assignNames): continue if not ppm2: shift = resonanceB.findFirstShift(parentList=shiftList) if not shift: continue ppm2 = shift.value delta = abs(ppm - ppm2) prevDelta = closestDict.get(peakDim) if (prevDelta is None) or (delta < prevDelta): closestDict[peakDim] = delta if delta > tolerance: continue matches.append((delta, resonanceB, uniqSpinSystem)) # Best match has smallest delta if matches: matches.sort() delta, resonance, uniqSpinSystem = matches[0] prevDelta, peakDimB, ss = matchDict.get(resonance, (None, None, None)) if not peakDimB or (delta < prevDelta): matchDict[resonance] = (delta, peakDim, uniqSpinSystem) uniqResonanceDict = {} for resonance in matchDict.keys(): delta, peakDim, uniqSpinSystem = matchDict[resonance] uniqResonanceDict[peakDim] = resonance, uniqSpinSystem # E.g. go through HNCA peaks and assign to # HNcoCA or iHNCA resonances if required nonMatched = {} for peakDim, atomType, contrib, isotope, isInter, ppm in peakTypes: if isInter is not None: continue if closestDict.get(peakDim) is None: # No inter residue peaks at all intensity = peak.findFirstPeakIntensity(intensityType='height') if intensity: if not nonMatched.has_key(atomType): nonMatched[atomType] = [] nonMatched[atomType].append( (-abs(intensity.value), peakDim, contrib, isotope)) continue match = uniqResonanceDict.get(peakDim) if match: resonance, uniqSpinSystem = match if tolerances: tolerance = tolerances[isotope] else: tolerance = getAnalysisDataDim(peakDim.dataDim).assignTolerance # untyped through-carbonyl resonance can interit type # by matching typed peaks if atomType and not resonance.assignNames: resonance.addAssignName(atomType) # e.g. the HNcoCA resonance is the one to put on this HNCA peak if contrib: if contrib.resonance is not resonance: clearPeakDim(peakDim) assignResToDim(peakDim, resonance, tolerance=tolerance) else: assignResToDim(peakDim, resonance, tolerance=tolerance) else: # No match to an unambig peak # store to work out which is best for each atom type # e.g. just in case we have two intra residue CA possibilites if not nonMatched.has_key(atomType): nonMatched[atomType] = [] nonMatched[atomType].append( (closestDict[peakDim], peakDim, contrib, isotope)) for atomType in nonMatched.keys(): if (atomType in intraResonances) and (atomType in interResonances): # Both resonances already found, peak is spurious continue if (atomType in intraResonances) and (atomType not in interResonances): # E.g. there was iHNCA but no HNcoCA otherSpinSystem = prevSpinSystem elif (atomType not in intraResonances) and (atomType in interResonances): # E.g. there was HNcoCA but no iHNCA otherSpinSystem = spinSystem else: # No info continue peakDimList = nonMatched[atomType] peakDimList.sort() # Assume that if we have two possible ambiguous peaks # for any given atom type, then the one furthest from an # unambigous peak is the best to take deltaPpm, peakDim, contrib, isotope = peakDimList[-1] if tolerances: tolerance = tolerances[isotope] else: tolerance = getAnalysisDataDim(peakDim.dataDim).assignTolerance # E.g. this HNCA peak matches no HNcoCA/iHNCA resonances resonance = None if contrib: resonance = contrib.resonance if resonance: # Already have an assignment spinSystem2 = resonance.resonanceGroup if spinSystem2 is None: addSpinSystemResonance(otherSpinSystem, resonance) elif spinSystem2 is not otherSpinSystem: resonance = nmrProject.newResonance(isotopeCode=isotope) addSpinSystemResonance(otherSpinSystem, resonance) clearPeakDim(peakDim) contrib = assignResToDim(peakDim, resonance, tolerance=tolerance) else: # Needs a new assignment for resonance2 in otherSpinSystem.resonances: if atomType in resonance2.assignNames: resonance = resonance2 break if not resonance: resonance = nmrProject.newResonance(isotopeCode=isotope) contrib = assignResToDim(peakDim, resonance, tolerance=tolerance) addSpinSystemResonance(otherSpinSystem, resonance) if not contrib: # Resonance has come from the spin system due to its atomTypes contrib = assignResToDim(peakDim, resonance, tolerance=2 * tolerance) if not contrib: # Existing resonance on spin system was too far away resonance = nmrProject.newResonance(isotopeCode=isotope) contrib = assignResToDim(peakDim, resonance, tolerance=tolerance) addSpinSystemResonance(otherSpinSystem, resonance) if atomType: assignNames = (atomType, ) else: assignNames = [] if not resonance.assignNames: assignResonanceType(resonance, assignNames=assignNames)
def getSpinSystemInterIntraResonances(spinSystem, peakLists): nmrProject = spinSystem.nmrProject shiftLists = [] for peakList in peakLists: spectrum = peakList.dataSource experiment = spectrum.experiment shiftLists.append(experiment.shiftList) interResonances = [] intraResonances = [] interPpms = [] intraPpms = [] interTypes = [] intraTypes = [] for resonance in spinSystem.resonances: if isResonanceAmide(resonance): continue if resonance.shifts: for contrib in resonance.peakDimContribs: peakList2 = contrib.peakDim.peak.peakList if peakList2 in peakLists: assignName = '/'.join(resonance.assignNames) intraResonances.append(resonance) intraTypes.append(assignName) break prevSpinSystem = findConnectedSpinSystem(spinSystem) if not prevSpinSystem: if spinSystem.residue: residueB = getLinkedResidue(spinSystem.residue, linkCode='prev') prevSpinSystem = nmrProject.findFirstResonanceGroup( residue=residueB) if prevSpinSystem: for resonance in prevSpinSystem.resonances: if isResonanceAmide(resonance): continue if resonance.shifts: for contrib in resonance.peakDimContribs: peakList2 = contrib.peakDim.peak.peakList if peakList2 in peakLists: assignName = '/'.join(resonance.assignNames) interResonances.append(resonance) interTypes.append(assignName) break inter = [interResonances, interPpms] intra = [intraResonances, intraPpms] for resonances, ppms in (inter, intra): for resonance in resonances: ppmSum = {} counts = {} for shiftList in shiftLists: ppmSum[shiftList] = 0.0 counts[shiftList] = 0.0 for shiftList in shiftLists: shift = resonance.findFirstShift(parentList=shiftList) if shift: ppmSum[shiftList] += shift.value counts[shiftList] += 1.0 ppm = None if shiftLists: ppm = 0.0 for shiftList in shiftLists: n = counts[shiftList] if n: ppm += ppmSum[shiftList] / n ppm /= len(shiftLists) ppms.append(ppm) return interResonances, intraResonances, interPpms, intraPpms, interTypes, intraTypes
def assignSpinSystemstoResidues(spinSystems, residues, strategy=None, guiParent=None): ''' This method is somewhat different than multiple calls to assignmentBasic.assignSpinSystemResidue does. If you want to assign more spin systems in one go, you should prevent merging 2 spin systems A and B if B possibly needs to be assigned in a next iteration to another residue. Also multiple calls to assignmentBasic.assignSpinSystem would cause unnescesarry breaking of sequential links, because they don't fit the assignment temporarely. In this funtion, non-valid sequential links are only corrected after all assignments have been made. Also, present sequential links are ignored in this function, in the sense that linked spin systems are not automatically assigned to neighboring residues because they might conflict with the answer the annealing presented. Also no new sequential links are made. args: spinSystems: list of spin systems residues: list of corrsponding residues kwargs: strategy: what to do when if a spin systems should be assigned to a residue that already has a spin system assignment. five possibilities: 1) None, in this case the user is asked every single time this happens. 2) 'skip', leave the old spin system assignment. 3) 'noMerge', assign but do not merge. 4) 'remove', remove old spin system assignment 4) 'merge', assign and merge. guiParent: nescesarry to raise a popup to ask for a merging strategy, only important when strategy=None output: None ''' #proposedSRdict = {} proposedRSdict = {} visitedSpinSystems = set() visitedResidues = set() deAssignedSpinSystems = set() # Determine the proposed mapping between spin systems and residues and # the other way around. Only a unique mapping between residues and # spin systems is used, because it is impossible to assign one spin # system to different residues. # Although it is technically possible to assign two spin systems # to one residue that is not what I want to do (unless there is already a # spin system assigned to the residue, in which case I'll ask what to do # with it.). for spinSystem, residue in set(zip(spinSystems, residues)): if not spinSystem or not residue: continue if spinSystem in visitedSpinSystems or residue in visitedResidues: proposedRSdict.pop(residue, None) continue proposedRSdict[residue] = spinSystem visitedSpinSystems.add(spinSystem) visitedResidues.add(residue) # Figuring out which of the spin systems assigned to the targetted #residues are not going to be shuffled around, they potentially have to get # merged or correct assignment might already be present assignSpinSystems = set(proposedRSdict.values()) for residue, spinSystem in proposedRSdict.items(): nonMovingSpinSystems = [] placeHolderSpinSystems = [] oldSpinSystems = residue.getResonanceGroups() for oldSpinSystem in oldSpinSystems: if oldSpinSystem is spinSystem or oldSpinSystem not in assignSpinSystems: if oldSpinSystem.resonances: nonMovingSpinSystems.append(oldSpinSystem) else: placeHolderSpinSystems.append(oldSpinSystem) if nonMovingSpinSystems: # The spin system is already assigned to the residue if spinSystem in nonMovingSpinSystems: continue else: tempStrategy = strategy or askToMergeSpinSystems(residue, spinSystem, nonMovingSpinSystems + placeHolderSpinSystems, guiParent=guiParent) # options are: 'merge','remove','noMerge','skip' if tempStrategy == 'skip': continue elif tempStrategy == 'noMerge': assignSpinSystemResidueMinimal(spinSystem, residue) elif tempStrategy == 'remove': for oldSpinSystem in nonMovingSpinSystems: assignSpinSystemResidueMinimal(oldSpinSystem, None) deAssignedSpinSystems.add(oldSpinSystem) assignSpinSystemResidueMinimal(spinSystem, residue) for placeHolderSpinSystem in placeHolderSpinSystems: mergeSpinSystems(placeHolderSpinSystem, spinSystem) elif tempStrategy == 'merge': assignSpinSystemResidueMinimal(spinSystem, residue) for oldSpinSystem in placeHolderSpinSystems + nonMovingSpinSystems: mergeSpinSystems(oldSpinSystem, spinSystem) else: assignSpinSystemResidueMinimal(spinSystem, residue) for placeHolderSpinSystem in placeHolderSpinSystems: mergeSpinSystems(placeHolderSpinSystem, spinSystem) # Removing sequentials links that do not make sense any longer for spinSystem in assignSpinSystems.union(deAssignedSpinSystems): connectedSpinSystems = [ findConnectedSpinSystem(spinSystem, delta=i) for i in (-1, 1)] residue = spinSystem.getResidue() if residue: connectedResidues = [ residue.chain.findFirstResidue(seqId=residue.seqId + i) for i in (-1, 1)] for connectedResidue, connectedSpinSystem, i in zip(connectedResidues, connectedSpinSystems, [-1, 1]): if connectedResidue: assignedSpinSystems = connectedResidue.getResonanceGroups() if connectedSpinSystem not in assignedSpinSystems: clearSeqSpinSystemLinks(spinSystem, delta=i) else: for connectedSpinSystem, i in zip(connectedSpinSystems, [-1, 1]): if connectedSpinSystem: connectedResidue = connectedSpinSystem.getResidue() if connectedResidue: residue = connectedResidue.chain.findFirstResidue( seqId=residue.seqId + (i * -1)) if residue and residue.getResonanceGroups(): clearSeqSpinSystemLinks(spinSystem, delta=i)