UNPKG

molstar

Version:

A comprehensive macromolecular library.

113 lines (112 loc) 6.18 kB
/** * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ import { Segmentation, Interval } from '../../../../../mol-data/int'; import { SortedRanges } from '../../../../../mol-data/int/sorted-ranges'; import { isPolymer } from '../../types'; import { getAtomIdForAtomRole } from '../../../util'; import { Vec3 } from '../../../../../mol-math/linear-algebra'; function areBackboneConnected(riStart, riEnd, conformation, index, derived) { var _a = derived.residue, polymerType = _a.polymerType, traceElementIndex = _a.traceElementIndex, directionFromElementIndex = _a.directionFromElementIndex, directionToElementIndex = _a.directionToElementIndex; var ptStart = polymerType[riStart]; var ptEnd = polymerType[riEnd]; if (ptStart === 0 /* PolymerType.NA */ || ptEnd === 0 /* PolymerType.NA */) return false; if (traceElementIndex[riStart] === -1 || traceElementIndex[riEnd] === -1) return false; var eiStart = index.findAtomsOnResidue(riStart, getAtomIdForAtomRole(ptStart, 'backboneStart')); var eiEnd = index.findAtomsOnResidue(riEnd, getAtomIdForAtomRole(ptEnd, 'backboneEnd')); if (eiStart === -1 || eiEnd === -1) { eiStart = index.findAtomsOnResidue(riStart, getAtomIdForAtomRole(ptStart, 'coarseBackbone')); eiEnd = index.findAtomsOnResidue(riEnd, getAtomIdForAtomRole(ptEnd, 'coarseBackbone')); } var x = conformation.x, y = conformation.y, z = conformation.z; var pStart = Vec3.create(x[eiStart], y[eiStart], z[eiStart]); var pEnd = Vec3.create(x[eiEnd], y[eiEnd], z[eiEnd]); var isCoarse = directionFromElementIndex[riStart] === -1 || directionToElementIndex[riStart] === -1 || directionFromElementIndex[riEnd] === -1 || directionToElementIndex[riEnd] === -1; return Vec3.distance(pStart, pEnd) < (isCoarse ? 10 : 3); } export function getAtomicRanges(hierarchy, entities, conformation, sequence) { var polymerRanges = []; var gapRanges = []; var cyclicPolymerMap = new Map(); var chainIt = Segmentation.transientSegments(hierarchy.chainAtomSegments, Interval.ofBounds(0, hierarchy.atoms._rowCount)); var residueIt = Segmentation.transientSegments(hierarchy.residueAtomSegments, Interval.ofBounds(0, hierarchy.atoms._rowCount)); var index = hierarchy.index, derived = hierarchy.derived; var label_seq_id = hierarchy.residues.label_seq_id; var label_entity_id = hierarchy.chains.label_entity_id; var _a = derived.residue, moleculeType = _a.moleculeType, traceElementIndex = _a.traceElementIndex; var prevSeqId; var prevStart; var prevEnd; var startIndex; while (chainIt.hasNext) { var chainSegment = chainIt.move(); residueIt.setSegment(chainSegment); prevSeqId = -1; prevStart = -1; prevEnd = -1; startIndex = -1; var eI = entities.getEntityIndex(label_entity_id.value(chainSegment.index)); var seq = sequence.byEntityKey[eI]; var maxSeqId = seq ? seq.sequence.seqId.value(seq.sequence.seqId.rowCount - 1) : -1; // check cyclic peptides, seqIds and distance must be compatible var riStart = hierarchy.residueAtomSegments.index[chainSegment.start]; var riEnd = hierarchy.residueAtomSegments.index[chainSegment.end - 1]; var seqIdStart = label_seq_id.value(riStart); var seqIdEnd = label_seq_id.value(riEnd); if (seqIdStart === 1 && seqIdEnd === maxSeqId && conformation.xyzDefined && areBackboneConnected(riStart, riEnd, conformation, index, derived)) { cyclicPolymerMap.set(riStart, riEnd); cyclicPolymerMap.set(riEnd, riStart); } while (residueIt.hasNext) { var residueSegment = residueIt.move(); var residueIndex = residueSegment.index; var seqId = label_seq_id.value(residueIndex); // treat polymers residues that don't have a trace element resolved as gaps if (isPolymer(moleculeType[residueIndex]) && traceElementIndex[residueIndex] !== -1) { if (startIndex !== -1) { if (seqId !== prevSeqId + 1) { polymerRanges.push(startIndex, prevEnd - 1); gapRanges.push(prevStart, residueSegment.end - 1); startIndex = residueSegment.start; } else if (!residueIt.hasNext) { polymerRanges.push(startIndex, residueSegment.end - 1); // TODO store terminal gaps } else { var riStart_1 = hierarchy.residueAtomSegments.index[residueSegment.start]; var riEnd_1 = hierarchy.residueAtomSegments.index[prevEnd - 1]; if (conformation.xyzDefined && !areBackboneConnected(riStart_1, riEnd_1, conformation, hierarchy.index, derived)) { polymerRanges.push(startIndex, prevEnd - 1); // add gap even for consecutive residues if they are not connected gapRanges.push(prevStart, residueSegment.end - 1); startIndex = residueSegment.start; } } } else { startIndex = residueSegment.start; // start polymer // TODO store terminal gaps } } else { if (startIndex !== -1) { polymerRanges.push(startIndex, prevEnd - 1); startIndex = -1; } } prevStart = residueSegment.start; prevEnd = residueSegment.end; prevSeqId = seqId; } } return { polymerRanges: SortedRanges.ofSortedRanges(polymerRanges), gapRanges: SortedRanges.ofSortedRanges(gapRanges), cyclicPolymerMap: cyclicPolymerMap }; }