@rcsb/rcsb-saguaro-3d
Version:
RCSB Molstar/Saguaro Web App
230 lines • 9.17 kB
JavaScript
import { __awaiter } from "tslib";
import { cloneDeep } from "lodash";
import { TagDelimiter } from "@rcsb/rcsb-api-tools/lib/RcsbUtils/TagDelimiter";
import { RcsbRequestContextManager } from "@rcsb/rcsb-saguaro-app/lib/app";
export class AlignmentReference {
constructor() {
this.alignmentRefGaps = {};
this.memberRefList = [];
this.alignmentMap = new Map();
}
init(result) {
return __awaiter(this, void 0, void 0, function* () {
this.alignmentMap.clear();
this.refId = this.addUniqueAlignmentId(result, 0, 0);
const length = (yield this.getSequences())[0].sequence.length;
this.alignmentRefMap = Array(length).fill(0).map((v, n) => n + 1);
});
}
addAlignment(id, alignment, target) {
const gaps = findGaps(alignment);
for (const gapBeg in gaps) {
if (this.alignmentRefGaps[gapBeg])
this.extendGap(parseInt(gapBeg), gaps[gapBeg]);
else
this.addGap(parseInt(gapBeg), gaps[gapBeg]);
}
const beg = alignment.filter(a => (a && this.alignmentRefMap[0] && a < this.alignmentRefMap[0]));
if (beg.length > 0)
this.addBeg(beg);
const n = this.alignmentRefMap[this.alignmentRefMap.length - 1];
const end = alignment.filter(a => (a && n && a > n));
if (end.length > 0)
this.addEnd(end);
this.addRef(id, alignment, target);
}
buildAlignments() {
return buildAlignments(this.refId, this.alignmentRefMap, this.memberRefList);
}
addUniqueAlignmentId(result, alignmentIndex, pairIndex = 1) {
var _a, _b, _c, _d;
const res = result.structures[pairIndex];
if (!res.selection)
throw new Error("Missing entry_id and name from result");
let entryId = undefined;
const asymId = 'asym_id' in res.selection ? res.selection.asym_id : undefined;
if ("entry_id" in res && res.entry_id && res.selection && "asym_id" in res.selection)
entryId = res.entry_id;
else if ("name" in res && res.selection && "asym_id" in res.selection)
entryId = res.name;
if (!entryId || !asymId)
throw new Error("Missing entry_id and name from result");
if (!this.alignmentMap.has(`${entryId}${TagDelimiter.instance}${asymId}`)) {
this.alignmentMap.set(`${entryId}${TagDelimiter.instance}${asymId}`, {
entryId,
instanceId: asymId,
sequence: (_b = (_a = result.sequence_alignment) === null || _a === void 0 ? void 0 : _a[pairIndex].sequence) !== null && _b !== void 0 ? _b : "",
alignmentIndex: alignmentIndex,
pairIndex: pairIndex,
alignmentId: `${entryId}${TagDelimiter.instance}${asymId}`
});
return `${entryId}${TagDelimiter.instance}${asymId}`;
}
else {
let tag = 1;
while (this.alignmentMap.has(`${entryId}[${tag}]${TagDelimiter.instance}${asymId}`)) {
tag++;
}
this.alignmentMap.set(`${entryId}[${tag}]${TagDelimiter.instance}${asymId}`, {
entryId,
instanceId: asymId,
sequence: (_d = (_c = result.sequence_alignment) === null || _c === void 0 ? void 0 : _c[pairIndex].sequence) !== null && _d !== void 0 ? _d : "",
alignmentIndex: alignmentIndex,
pairIndex: pairIndex,
alignmentId: `${entryId}[${tag}]${TagDelimiter.instance}${asymId}`
});
return `${entryId}[${tag}]${TagDelimiter.instance}${asymId}`;
}
}
getAlignmentEntry(alignmentId) {
const pdb = this.alignmentMap.get(alignmentId);
if (pdb)
return pdb;
throw new Error("Alignment Id not found");
}
getSequences() {
return __awaiter(this, void 0, void 0, function* () {
const out = Array.from(this.alignmentMap.values()).filter(v => v.sequence.length > 0).map(v => ({
rcsbId: v.alignmentId,
sequence: v.sequence
}));
const missingSeq = yield RcsbRequestContextManager.getInstanceSequences(Array.from(this.alignmentMap.values()).filter(v => v.sequence.length == 0).map(v => `${v.entryId}${TagDelimiter.instance}${v.instanceId}`).filter((value, index, list) => list.indexOf(value) === index));
return out.concat(Array.from(this.alignmentMap.values()).filter(v => v.sequence.length == 0).map(v => {
var _a, _b;
return ({
rcsbId: v.alignmentId,
sequence: (_b = (_a = missingSeq.find(s => s.rcsbId === `${v.entryId}${TagDelimiter.instance}${v.instanceId}`)) === null || _a === void 0 ? void 0 : _a.sequence) !== null && _b !== void 0 ? _b : ""
});
}));
});
}
addRef(id, alignment, target) {
const map = Array(this.alignmentRefMap.length).fill(undefined);
alignment.forEach((v, n) => {
if (typeof v === "undefined")
return;
const index = this.alignmentRefMap.findIndex(e => e === v);
if (index >= 0)
map[index] = n;
});
const gaps = findGaps(alignment);
for (const gapBeg in gaps) {
const index = this.alignmentRefMap.findIndex(v => v === parseInt(gapBeg));
for (let i = 1; i <= gaps[gapBeg]; i++) {
map[index + i] = map[index] + i;
}
}
this.memberRefList.push({
id,
map,
ref: cloneDeep(alignment),
target: cloneDeep(target)
});
}
addEnd(indexList) {
const last = this.alignmentRefMap.length;
this.alignmentRefMap.splice(last, 0, ...indexList);
this.memberRefList.forEach(mr => {
mr.map.splice(last, 0, ...Array(indexList.length).fill(undefined));
});
}
addBeg(indexList) {
this.alignmentRefMap.splice(0, 0, ...indexList);
this.memberRefList.forEach(mr => {
mr.map.splice(0, 0, ...Array(indexList.length).fill(undefined));
});
}
addGap(gapBeg, gapLength) {
this.alignmentRefGaps[gapBeg] = gapLength;
const i = this.alignmentRefMap.findIndex((v) => v === gapBeg) + 1;
this.alignmentRefMap.splice(i, 0, ...Array(gapLength).fill(undefined));
this.memberRefList.forEach(mr => {
mr.map.splice(i, 0, ...Array(gapLength).fill(undefined));
});
}
extendGap(gapBeg, gapLength) {
if (!this.alignmentRefGaps[gapBeg] || this.alignmentRefGaps[gapBeg] >= gapLength)
return;
const delta = gapLength - this.alignmentRefGaps[gapBeg];
this.alignmentRefGaps[gapBeg] += delta;
const i = this.alignmentRefMap.findIndex((v) => v === gapBeg) + 1;
this.alignmentRefMap.splice(i, 0, ...Array(delta).fill(undefined));
this.memberRefList.forEach(mr => {
mr.map.splice(i, 0, ...Array(delta).fill(undefined));
});
}
}
function buildAlignments(refId, alignmentRefMap, alignmentMembers) {
const out = {};
out.target_alignments = [];
out.target_alignments.push({
aligned_regions: buildRegions(alignmentRefMap),
target_id: refId
});
alignmentMembers.forEach(am => {
var _a;
(_a = out.target_alignments) === null || _a === void 0 ? void 0 : _a.push({
target_id: am.id,
aligned_regions: buildRegions(am.map.map((v, n) => typeof v === "number" ? am.target[v] : undefined))
});
});
return out;
}
function buildRegions(alignment) {
const out = [];
let begIndex = 0;
let begPos = 0;
alignment.forEach((v, n) => {
if (!v) {
if (begIndex > 0) {
out.push({
query_begin: begIndex,
target_begin: begPos,
query_end: n,
target_end: begPos + (n - begIndex)
});
begIndex = 0;
begPos = 0;
}
}
else {
if (begIndex == 0) {
begIndex = n + 1;
begPos = v;
}
}
});
if (begPos > 0) {
const n = alignment.length;
out.push({
query_begin: begIndex,
target_begin: begPos,
query_end: n,
target_end: alignment[n - 1]
});
}
return out;
}
function findGaps(alignment) {
const out = {};
let gapBeg = 0;
let gapLength = 0;
alignment.forEach((v, n) => {
if (!v) {
if (gapBeg == 0)
gapBeg = alignment[n - 1];
gapLength++;
}
else {
if (gapLength > 0) {
out[gapBeg] = gapLength;
gapBeg = 0;
gapLength = 0;
}
}
});
if (gapLength > 0)
out[gapBeg] = gapLength;
return out;
}
//# sourceMappingURL=AlignmentReference.js.map