in packages/miew/src/chem/SecondaryStructureMap.js [203:442]
_buildBetaSheets() {
// find bridges
// check each chain against each other chain, and against itself
const bridges = [];
for (let a = 0; a < this._complex._chains.length; ++a) {
const lenA = this._chainLengths[a];
if (lenA <= 4) {
continue;
}
const chainA = this._complex._chains[a].getResidues();
for (let b = a; b < this._complex._chains.length; ++b) {
const lenB = this._chainLengths[b];
if (lenB <= 4) {
continue;
}
const chainB = this._complex._chains[b].getResidues();
for (let i = 1; i + 1 < lenA; ++i) {
const ri = chainA[i];
let j = 1;
if (b === a) {
j = i + 3; // check for self-bridges forward down the chain
}
for (; j + 1 < lenB; ++j) {
const rj = chainB[j];
const type = this._testBridge(chainA, i, chainB, j);
if (type === BridgeType.NO_BRIDGE) {
continue;
}
// there is a bridge, try to attach it to previously found sequence
let found = false;
for (const bridge of bridges) {
if (type !== bridge.type || ri._index !== bridge.i[bridge.i.length - 1] + 1) {
continue;
}
if (type === BridgeType.PARALLEL && bridge.j[bridge.j.length - 1] + 1 === rj._index) {
bridge.i.push(ri._index);
bridge.j.push(rj._index);
found = true;
break;
}
if (type === BridgeType.ANTI_PARALLEL && bridge.j[0] - 1 === rj._index) {
bridge.i.push(ri._index);
bridge.j.unshift(rj._index);
found = true;
break;
}
}
// this bridge cannot be attached anywhere, start a new sequence
if (!found) {
bridges.push({
type,
i: [ri._index],
chainI: ri.getChain()._index,
j: [rj._index],
chainJ: rj.getChain()._index,
});
}
}
}
}
}
// extend ladders
bridges.sort((a, b) => {
if (a.chainI < b.chainI || (a.chainI === b.chainI && a.i[0] < b.i[0])) {
return -1;
}
return 1;
});
for (let i = 0; i < bridges.length; ++i) {
for (let j = i + 1; j < bridges.length; ++j) {
const ibi = bridges[i].i[0];
const iei = bridges[i].i[bridges[i].i.length - 1];
const jbi = bridges[i].j[0];
const jei = bridges[i].j[bridges[i].j.length - 1];
const ibj = bridges[j].i[0];
const iej = bridges[j].i[bridges[j].i.length - 1];
const jbj = bridges[j].j[0];
const jej = bridges[j].j[bridges[j].j.length - 1];
if (bridges[i].type !== bridges[j].type
|| this._hasChainBreak(Math.min(ibi, ibj), Math.max(iei, iej))
|| this._hasChainBreak(Math.min(jbi, jbj), Math.max(jei, jej))
|| ibj - iei >= 6 || (iei >= ibj && ibi <= iej)) {
continue;
}
let bulge = false;
if (bridges[i].type === BridgeType.PARALLEL) {
bulge = ((jbj - jei < 6 && ibj - iei < 3) || (jbj - jei < 3));
} else {
bulge = ((jbi - jej < 6 && ibj - iei < 3) || (jbi - jej < 3));
}
if (bulge) {
bridges[i].i = bridges[i].i.concat(bridges[j].i);
if (bridges[i].type === BridgeType.PARALLEL) {
bridges[i].j = bridges[i].j.concat(bridges[j].j);
} else {
bridges[i].j = bridges[j].j.concat(bridges[i].j);
}
bridges.splice(j--, 1);
}
}
}
// Sheet
const ladderset = new Set();
for (let i = 0; i < bridges.length; ++i) {
ladderset.add(bridges[i]);
}
let sheet = 1;
let ladder = 0;
while (ladderset.size > 0) {
let bridge = ladderset.values().next().value;
ladderset.delete(bridge);
const sheetset = new Set();
sheetset.add(bridge);
let toMove;
do {
toMove = new Set();
for (const a of sheetset.values()) {
for (const b of ladderset.values()) {
if (this._areBridgesLinked(a, b)) {
toMove.add(b);
}
}
}
for (bridge of toMove.values()) {
sheetset.add(bridge);
ladderset.delete(bridge);
}
} while (toMove.size > 0);
for (bridge of sheetset.values()) {
bridge.ladder = ladder;
bridge.sheet = sheet;
bridge.link = sheetset;
++ladder;
}
++sheet;
}
for (let i = 0; i < bridges.length; ++i) {
const bridge = bridges[i];
// find out if any of the i and j set members already have
// a bridge assigned, if so, we're assigning bridge 2
let betai = 0;
let betaj = 0;
for (let l = 0; l < bridge.i.length; ++l) {
if (this._betaPartners[bridge.i[l]][0]) {
betai = 1;
break;
}
}
for (let l = 0; l < bridge.j.length; ++l) {
if (this._betaPartners[bridge.j[l]][0]) {
betaj = 1;
break;
}
}
let ss = StructureType.BRIDGE;
if (bridge.i.length > 1) {
ss = StructureType.STRAND;
}
if (bridge.type === BridgeType.PARALLEL) {
let j = 0;
for (let k = 0; k < bridge.i.length; ++k) {
this._betaPartners[bridge.i[k]][betai] = {
residue: bridge.j[j++],
ladder: bridge.ladder,
parallel: true,
};
}
j = 0;
for (let k = 0; k < bridge.j.length; ++k) {
this._betaPartners[bridge.j[k]][betaj] = {
residue: bridge.i[j++],
ladder: bridge.ladder,
parallel: true,
};
}
} else {
let j = bridge.j.length - 1;
for (let k = 0; k < bridge.i.length; ++k) {
this._betaPartners[bridge.i[k]][betai] = {
residue: bridge.j[j--],
ladder: bridge.ladder,
parallel: false,
};
}
j = bridge.i.length - 1;
for (let k = 0; k < bridge.j.length; ++k) {
this._betaPartners[bridge.j[k]][betaj] = {
residue: bridge.i[j--],
ladder: bridge.ladder,
parallel: false,
};
}
}
for (let k = bridge.i[0]; k <= bridge.i[bridge.i.length - 1]; ++k) {
if (this._ss[k] !== StructureType.STRAND) {
this._ss[k] = ss;
this._sheet[k] = bridge.sheet;
}
}
for (let k = bridge.j[0]; k <= bridge.j[bridge.j.length - 1]; ++k) {
if (this._ss[k] !== StructureType.STRAND) {
this._ss[k] = ss;
this._sheet[k] = bridge.sheet;
}
}
}
}