UNPKG

molstar

Version:

A comprehensive macromolecular library.

106 lines (105 loc) 3.88 kB
/** * Copyright (c) 2024 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ import { SecondaryStructure } from '../../../mol-model/structure/model/properties/secondary-structure'; import { SortedArray } from '../../../mol-data/int'; import { Vec3 } from '../../../mol-math/linear-algebra/3d/vec3'; const HelixDistances = [5.45, 5.18, 6.37]; const HelixDelta = 2.1; const SheetDistances = [6.1, 10.4, 13.0]; const SheetDelta = 1.42; const posA = Vec3(); const posB = Vec3(); function zhangSkolnickAtomicSS(unit, residueIndices, i, distances, delta) { const c = unit.conformation; const { traceElementIndex } = unit.model.atomicHierarchy.derived.residue; for (let j = Math.max(0, i - 2); j <= i; ++j) { for (let k = 2; k < 5; ++k) { if (j + k >= residueIndices.length) return false; const rA = residueIndices[j]; const rB = residueIndices[j + k]; const aA = traceElementIndex[rA]; const aB = traceElementIndex[rB]; if (aA === -1 || aB === -1) return false; c.invariantPosition(aA, posA); c.invariantPosition(aB, posB); const d = Vec3.distance(posA, posB); if (Math.abs(d - distances[k - 2]) >= delta) return false; } } return true; } /** * Secondary-structure assignment based on Zhang and Skolnick's TM-align paper. * TM-align: a protein structure alignment algorithm based on the Tm-score (2005) NAR, 33(7) 2302-2309. * * While not as accurate as DSSP, it is faster and works for coarse-grained/backbone-only models. */ export async function computeUnitZhangSkolnik(unit) { const count = unit.proteinElements.length; const type = new Uint32Array(count); const keys = []; const elements = []; const { proteinElements, residueIndex } = unit; const residueCount = proteinElements.length; const unitProteinResidues = new Uint32Array(residueCount); for (let i = 0; i < residueCount; ++i) { const rI = residueIndex[proteinElements[i]]; unitProteinResidues[i] = rI; } const residueIndices = SortedArray.ofSortedArray(unitProteinResidues); const getIndex = (rI) => SortedArray.indexOf(residueIndices, rI); for (let i = 0, il = residueIndices.length; i < il; ++i) { let flag = 0 /* SecondaryStructureType.Flag.None */; if (zhangSkolnickAtomicSS(unit, residueIndices, i, HelixDistances, HelixDelta)) { flag = 2 /* SecondaryStructureType.Flag.Helix */; } else if (zhangSkolnickAtomicSS(unit, residueIndices, i, SheetDistances, SheetDelta)) { flag = 4 /* SecondaryStructureType.Flag.Beta */; } type[i] = flag; if (elements.length === 0 || flag !== getFlag(elements[elements.length - 1])) { elements[elements.length] = createElement(mapToKind(flag), flag); } keys[i] = elements.length - 1; } return SecondaryStructure(type, keys, elements, getIndex); } function createElement(kind, flag) { if (kind === 'helix') { return { kind: 'helix', flags: flag }; } else if (kind === 'sheet') { return { kind: 'sheet', flags: flag }; } else { return { kind: 'none' }; } } function mapToKind(flag) { if (flag === 2 /* SecondaryStructureType.Flag.Helix */) { return 'helix'; } else if (flag === 4 /* SecondaryStructureType.Flag.Beta */) { return 'sheet'; } else { return 'none'; } } function getFlag(element) { if (element.kind === 'helix') { return element.flags; } else if (element.kind === 'sheet') { return element.flags; } else { return 0 /* SecondaryStructureType.Flag.None */; } }