UNPKG

pdbe-molstar

Version:
181 lines (180 loc) 7.17 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.superposeBySequenceAlignment = superposeBySequenceAlignment; const int_1 = require("molstar/lib/mol-data/int"); const minimize_rmsd_1 = require("molstar/lib/mol-math/linear-algebra/3d/minimize-rmsd"); const alignment_1 = require("molstar/lib/mol-model/sequence/alignment/alignment"); const structure_1 = require("molstar/lib/mol-model/structure"); const superposition_1 = require("molstar/lib/mol-model/structure/structure/util/superposition"); const helpers_1 = require("../../helpers"); /** Superpose structures based on the largest common component (measured the by number of residues), components being defined by `mappingsA` and `mappingsB`. * Residue-residue correspondence is determined by sequence alignment. */ function superposeBySequenceAlignment(structA, structB, mappingsA, mappingsB) { const sortedA = sortAccessionsAndUnits(structA, mappingsA); const sortedB = sortAccessionsAndUnits(structB, mappingsB); const bestMatch = bestMappingMatch(sortedA, sortedB); if (!bestMatch) { return undefined; } const accession = bestMatch.accession; const lociA = helpers_1.QueryHelper.getInteractivityLoci(mappingsA[accession], structA); const lociB = helpers_1.QueryHelper.getInteractivityLoci(mappingsB[accession], structB); const superposition = alignAndSuperpose(lociA, lociB); if (!isNaN(superposition.rmsd)) { return Object.assign(Object.assign({}, superposition), { method: 'sequence-alignment', accession: bestMatch.accession }); } else { return undefined; } } /** Sort units for each accession by decreasing size and sort accessions by decreasing biggest unit size. */ function sortAccessionsAndUnits(struct, mappings) { const unitsByAccession = {}; for (const accession in mappings) { const loci = helpers_1.QueryHelper.getInteractivityLoci(mappings[accession], struct); const units = []; for (const u of loci.elements) { const unitId = u.unit.id.toString(); const elements = []; int_1.OrderedSet.forEach(u.indices, elementUnitIndex => { const elementIndex = u.unit.elements[elementUnitIndex]; if (int_1.SortedArray.has(u.unit.polymerElements, elementIndex)) elements.push(elementIndex); }); units.push({ unitId, size: elements.length, elements: int_1.SortedArray.ofSortedArray(elements) }); } units.sort((a, b) => b.size - a.size); unitsByAccession[accession] = units; } return { /** Accessions sorted by decreasing biggest unit size */ accessions: Object.keys(unitsByAccession).sort((a, b) => unitsByAccession[b][0].size - unitsByAccession[a][0].size), /** Units per accession, sorted by decreasing unit size */ units: unitsByAccession, }; } function bestMappingMatch(sortedA, sortedB) { let bestMatch = undefined; let bestScore = 0; for (const accession of sortedA.accessions) { const unitsA = sortedA.units[accession]; const unitsB = sortedB.units[accession]; if (!unitsB) continue; for (const ua of unitsA) { if (ua.size <= bestScore) break; for (const ub of unitsB) { if (ub.size <= bestScore || ua.size <= bestScore) break; const score = Math.min(ua.size, ub.size); if (score > bestScore) { bestScore = score; bestMatch = { accession, unitA: ua.unitId, unitB: ub.unitId, elementsA: ua.elements, elementsB: ub.elements, nMatchedElements: score }; } } } } return bestMatch; } const reProtein = /(polypeptide|cyclic-pseudo-peptide)/i; function alignAndSuperpose(lociA, lociB) { const location = structure_1.StructureElement.Loci.getFirstLocation(lociA); const subtype = structure_1.StructureProperties.entity.subtype(location); const substMatrix = subtype.match(reProtein) ? 'blosum62' : 'default'; const { matchedA, matchedB } = computeAlignment(lociA.elements[0], lociB.elements[0], { substMatrix }); const n = int_1.OrderedSet.size(matchedA.indices); const coordsA = (0, superposition_1.getPositionTable)(structure_1.StructureElement.Loci(lociA.structure, [matchedA]), n); const coordsB = (0, superposition_1.getPositionTable)(structure_1.StructureElement.Loci(lociB.structure, [matchedB]), n); const superposition = minimize_rmsd_1.MinimizeRmsd.compute({ a: coordsA, b: coordsB }); return superposition; } function computeAlignment(a, b, options = {}) { const seqA = getSequenceFromLoci(a); const seqB = getSequenceFromLoci(b); const { aliA, aliB, score } = (0, alignment_1.align)(seqA.sequence.map(getOneLetterCode), seqB.sequence.map(getOneLetterCode), options); const indicesA = []; const indicesB = []; let seqIdxA = 0, seqIdxB = 0; for (let i = 0, n = aliA.length; i < n; ++i) { if (aliA[i] !== '-' && aliB[i] !== '-') { indicesA.push(seqA.unitElements[seqIdxA]); indicesB.push(seqB.unitElements[seqIdxB]); } if (aliA[i] !== '-') seqIdxA += 1; if (aliB[i] !== '-') seqIdxB += 1; } return { matchedA: { unit: a.unit, indices: int_1.OrderedSet.ofSortedArray(indicesA) }, matchedB: { unit: b.unit, indices: int_1.OrderedSet.ofSortedArray(indicesB) }, score, }; } /** Extract sequence and array of corresponding trace atoms. */ function getSequenceFromLoci(loci) { const { unit, indices } = loci; const unitElements = []; const sequence = []; int_1.OrderedSet.forEach(indices, elementUnitIndex => { const elementIndex = unit.elements[elementUnitIndex]; if (int_1.OrderedSet.has(unit.polymerElements, elementIndex)) { unitElements.push(elementUnitIndex); const compId = unit.model.atomicHierarchy.atoms.label_comp_id.value(elementIndex); sequence.push(compId); } }); return { sequence, unitElements }; } function getOneLetterCode(compId) { var _a; return (_a = OneLetterCodes[compId]) !== null && _a !== void 0 ? _a : 'X'; } // Copied from Molstar const OneLetterCodes = { 'HIS': 'H', 'ARG': 'R', 'LYS': 'K', 'ILE': 'I', 'PHE': 'F', 'LEU': 'L', 'TRP': 'W', 'ALA': 'A', 'MET': 'M', 'PRO': 'P', 'CYS': 'C', 'ASN': 'N', 'VAL': 'V', 'GLY': 'G', 'SER': 'S', 'GLN': 'Q', 'TYR': 'Y', 'ASP': 'D', 'GLU': 'E', 'THR': 'T', 'SEC': 'U', // as per IUPAC definition 'PYL': 'O', // as per IUPAC definition // charmm ff 'HSD': 'H', 'HSE': 'H', 'HSP': 'H', 'LSN': 'K', 'ASPP': 'D', 'GLUP': 'E', // amber ff 'HID': 'H', 'HIE': 'H', 'HIP': 'H', 'LYN': 'K', 'ASH': 'D', 'GLH': 'E', // DNA 'DA': 'A', 'DC': 'C', 'DG': 'G', 'DT': 'T', 'DU': 'U', // RNA 'A': 'A', 'C': 'C', 'G': 'G', 'T': 'T', 'U': 'U', };