_buildBetaSheets()

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;
        }
      }
    }
  }