<commit_before>import ResidueType from './ResidueType';

/**
 * Created by anton.zherzdev on 25.12.2017.
 */

const kMinimalDistance = 0.5,
  kMinHBondEnergy = -9.9,
  kMaxHBondEnergy = -0.5,
  kCouplingConstant = -27.888; // = -332 * 0.42 * 0.2

export default class HBondInfo {
  constructor(complex) {
    this._complex = complex;
    this._hbonds = []; // array of bond info for each residue
    this._build();
  }

  isBond(from, to) {
    if (this._hbonds[from]) {
      let acc = this._hbonds[from].acceptor[0];
      if (acc && acc.residue === to && acc.energy < kMaxHBondEnergy) {
        return true;
      }
      acc = this._hbonds[from].acceptor[1];
      if (acc && acc.residue === to && acc.energy < kMaxHBondEnergy) {
        return true;
      }
    }
    return false;
  }

  _build() {
    const self = this;

    // TODO Replace quadratic algorithm with something better (use voxel grid?)
    for (let i = 0; i < this._complex._residues.length - 1; ++i) {
      let ri = this._complex._residues[i];
      if ((ri.getType().flags & ResidueType.Flags.PROTEIN) === 0) {
        continue;
      }

      // get predecessor in chain
      let preri = null;
      if (i > 0 && (this._complex._residues[i - 1].getType().flags & ResidueType.Flags.PROTEIN) &&
        ri._sequence === this._complex._residues[i - 1]._sequence + 1) {
        preri = this._complex._residues[i - 1];
      }

      for (let j = i + 1; j < this._complex._residues.length; ++j) {
        let rj = this._complex._residues[j];
        if ((rj.getType().flags & ResidueType.Flags.PROTEIN) === 0) {
          continue;
        }

        // get predecessor in chain
        let prerj = null;
        if ((this._complex._residues[j - 1].getType().flags & ResidueType.Flags.PROTEIN) &&
          rj._sequence === this._complex._residues[j - 1]._sequence + 1) {
          prerj = this._complex._residues[j - 1];
        }

        self._calcHBondEnergy(preri, ri, rj);
        if (j !== i + 1) {
          self._calcHBondEnergy(prerj, rj, ri);
        }
      }
    }
  }

  _residueGetCO(res) {
    let c = null, o = null;<commit_msg>Add optimized H-bond calculation algorithm for large molecules<commit_after>import ResidueType from './ResidueType';
import PairCollection from './AtomPairs';

/**
 * Created by anton.zherzdev on 25.12.2017.
 */

const kMinimalDistance = 0.5,
  kMinHBondEnergy = -9.9,
  kMaxHBondEnergy = -0.5,
  kCouplingConstant = -27.888, // = -332 * 0.42 * 0.2
  kMaxCouplingDistance = 5.0; // how far is the closest atom of a potential partner residue from CA atom

export default class HBondInfo {
  constructor(complex) {
    this._complex = complex;
    this._hbonds = []; // array of bond info for each residue
    if (this._complex._residues.length > 1000) {
      this._buildVW(); // optimized version using voxel grid
    } else {
      this._build(); // test all pairs of residues
    }
  }

  isBond(from, to) {
    if (this._hbonds[from]) {
      let acc = this._hbonds[from].acceptor[0];
      if (acc && acc.residue === to && acc.energy < kMaxHBondEnergy) {
        return true;
      }
      acc = this._hbonds[from].acceptor[1];
      if (acc && acc.residue === to && acc.energy < kMaxHBondEnergy) {
        return true;
      }
    }
    return false;
  }

  _build() {
    const self = this;

    // TODO Replace quadratic algorithm with something better (use voxel grid?)
    for (let i = 0; i < this._complex._residues.length - 1; ++i) {
      let ri = this._complex._residues[i];
      if ((ri.getType().flags & ResidueType.Flags.PROTEIN) === 0) {
        continue;
      }

      // get predecessor in chain
      let preri = null;
      if (i > 0 && (this._complex._residues[i - 1].getType().flags & ResidueType.Flags.PROTEIN) &&
        ri._sequence === this._complex._residues[i - 1]._sequence + 1) {
        preri = this._complex._residues[i - 1];
      }

      for (let j = i + 1; j < this._complex._residues.length; ++j) {
        let rj = this._complex._residues[j];
        if ((rj.getType().flags & ResidueType.Flags.PROTEIN) === 0) {
          continue;
        }

        // get predecessor in chain
        let prerj = null;
        if ((this._complex._residues[j - 1].getType().flags & ResidueType.Flags.PROTEIN) &&
          rj._sequence === this._complex._residues[j - 1]._sequence + 1) {
          prerj = this._complex._residues[j - 1];
        }

        self._calcHBondEnergy(preri, ri, rj);
        if (j !== i + 1) {
          self._calcHBondEnergy(prerj, rj, ri);
        }
      }
    }
  }

  _buildVW() {
    const self = this;
    let residues = this._complex._residues;
    let ri, preri;

    let vw = this._complex.getVoxelWorld();
    if (vw === null) {
      return;
    }

    let pairs = new PairCollection(this._complex._residues.length * this._complex._residues.length / 2);

    function processAtom(atom) {
      let rj = atom._residue;

      if (rj._index === ri._index) {
        return;
      }

      if ((rj.getType().flags & ResidueType.Flags.PROTEIN) === 0) {
        return;
      }

      if (!pairs.addPair(ri._index, rj._index)) {
        // we've seen this pair
        return;
      }

      // get predecessor in chain
      let prerj = rj._index > 0 ? residues[rj._index - 1] : null;
      if (prerj &&
        ((prerj.getType().flags & ResidueType.Flags.PROTEIN) === 0 || rj._sequence !== prerj._sequence + 1)) {
        prerj = null;
      }

      self._calcHBondEnergy(preri, ri, rj);
      if (rj._index !== ri._index + 1) {
        self._calcHBondEnergy(prerj, rj, ri);
      }
    }

    for (let i = 0; i < residues.length - 1; ++i) {
      ri = residues[i];
      if ((ri.getType().flags & ResidueType.Flags.PROTEIN) === 0) {
        continue;
      }

      // get predecessor in chain
      preri = i > 0 ? residues[i - 1] : null;
      if (preri &&
        ((preri.getType().flags & ResidueType.Flags.PROTEIN) === 0 || ri._sequence !== preri._sequence + 1)) {
        preri = null;
      }

      vw.forEachAtomWithinRadius(this._residueGetCAlpha(ri), kMaxCouplingDistance, processAtom);
    }
  }

  _residueGetCAlpha(res) {
    for (let i = 0; i < res._atoms.length; ++i) {
      let name = res._atoms[i].getName().getString();
      if (name === 'CA' ||
        name === 'C1') {
        return res._atoms[i].getPosition();
      }
    }

    return null;
  }

  _residueGetCO(res) {
    let c = null, o = null;
{'fraction_non_alphanumeric': 0.14814236653137683, 'fraction_numerical': 0.017171401810802372, 'mean_word_length': 2.1376101860920667, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 8, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1420374', 'n_tokens_mistral': 2383, 'n_tokens_neox': 2187, 'n_words': 503}