Esempio n. 1
0
  /**
   * After the alignment changes (optAln, optLen, blockNum, at a minimum), many other properties
   * which depend on the superposition will be invalid.
   *
   * <p>This method re-runs a rigid superposition over the whole alignment and repopulates the
   * required properties, including RMSD (TotalRMSD) and TM-Score.
   *
   * @param afpChain
   * @param ca1
   * @param ca2 Second set of ca atoms. Will be modified based on the superposition
   * @throws StructureException
   * @see {@link CECalculator#calc_rmsd(Atom[], Atom[], int, boolean)} contains much of the same
   *     code, but stores results in a CECalculator instance rather than an AFPChain
   */
  public static void updateSuperposition(AFPChain afpChain, Atom[] ca1, Atom[] ca2)
      throws StructureException {

    // Update ca information, because the atom array might also be changed
    afpChain.setCa1Length(ca1.length);
    afpChain.setCa2Length(ca2.length);

    // We need this to get the correct superposition
    int[] focusRes1 = afpChain.getFocusRes1();
    int[] focusRes2 = afpChain.getFocusRes2();
    if (focusRes1 == null) {
      focusRes1 = new int[afpChain.getCa1Length()];
      afpChain.setFocusRes1(focusRes1);
    }
    if (focusRes2 == null) {
      focusRes2 = new int[afpChain.getCa2Length()];
      afpChain.setFocusRes2(focusRes2);
    }

    if (afpChain.getNrEQR() == 0) return;

    // create new arrays for the subset of atoms in the alignment.
    Atom[] ca1aligned = new Atom[afpChain.getOptLength()];
    Atom[] ca2aligned = new Atom[afpChain.getOptLength()];
    int pos = 0;
    int[] blockLens = afpChain.getOptLen();
    int[][][] optAln = afpChain.getOptAln();
    assert (afpChain.getBlockNum() <= optAln.length);

    for (int block = 0; block < afpChain.getBlockNum(); block++) {
      for (int i = 0; i < blockLens[block]; i++) {
        int pos1 = optAln[block][0][i];
        int pos2 = optAln[block][1][i];
        Atom a1 = ca1[pos1];
        Atom a2 = (Atom) ca2[pos2].clone();
        ca1aligned[pos] = a1;
        ca2aligned[pos] = a2;
        pos++;
      }
    }

    // this can happen when we load an old XML serialization which did not support modern ChemComp
    // representation of modified residues.
    if (pos != afpChain.getOptLength()) {
      logger.warn(
          "AFPChainScorer getTMScore: Problems reconstructing alignment! nr of loaded atoms is "
              + pos
              + " but should be "
              + afpChain.getOptLength());
      // we need to resize the array, because we allocated too many atoms earlier on.
      ca1aligned = (Atom[]) resizeArray(ca1aligned, pos);
      ca2aligned = (Atom[]) resizeArray(ca2aligned, pos);
    }

    // Superimpose the two structures in correspondance to the new alignment
    SVDSuperimposer svd = new SVDSuperimposer(ca1aligned, ca2aligned);
    Matrix matrix = svd.getRotation();
    Atom shift = svd.getTranslation();
    Matrix[] blockMxs = new Matrix[afpChain.getBlockNum()];
    Arrays.fill(blockMxs, matrix);
    afpChain.setBlockRotationMatrix(blockMxs);
    Atom[] blockShifts = new Atom[afpChain.getBlockNum()];
    Arrays.fill(blockShifts, shift);
    afpChain.setBlockShiftVector(blockShifts);

    for (Atom a : ca2aligned) {
      Calc.rotate(a, matrix);
      Calc.shift(a, shift);
    }

    // Calculate the RMSD and TM score for the new alignment
    double rmsd = SVDSuperimposer.getRMS(ca1aligned, ca2aligned);
    double tmScore = SVDSuperimposer.getTMScore(ca1aligned, ca2aligned, ca1.length, ca2.length);
    afpChain.setTotalRmsdOpt(rmsd);
    afpChain.setTMScore(tmScore);

    // Calculate the RMSD and TM score for every block of the new alignment
    double[] blockRMSD = new double[afpChain.getBlockNum()];
    double[] blockScore = new double[afpChain.getBlockNum()];
    for (int k = 0; k < afpChain.getBlockNum(); k++) {
      // Create the atom arrays corresponding to the aligned residues in the block
      Atom[] ca1block = new Atom[afpChain.getOptLen()[k]];
      Atom[] ca2block = new Atom[afpChain.getOptLen()[k]];
      int position = 0;
      for (int i = 0; i < blockLens[k]; i++) {
        int pos1 = optAln[k][0][i];
        int pos2 = optAln[k][1][i];
        Atom a1 = ca1[pos1];
        Atom a2 = (Atom) ca2[pos2].clone();
        ca1block[position] = a1;
        ca2block[position] = a2;
        position++;
      }
      if (position != afpChain.getOptLen()[k]) {
        logger.warn(
            "AFPChainScorer getTMScore: Problems reconstructing block alignment! nr of loaded atoms is "
                + pos
                + " but should be "
                + afpChain.getOptLen()[k]);
        // we need to resize the array, because we allocated too many atoms earlier on.
        ca1block = (Atom[]) resizeArray(ca1block, position);
        ca2block = (Atom[]) resizeArray(ca2block, position);
      }
      // Superimpose the two block structures
      SVDSuperimposer svdb = new SVDSuperimposer(ca1block, ca2block);
      Matrix matrixb = svdb.getRotation();
      Atom shiftb = svdb.getTranslation();
      for (Atom a : ca2block) {
        Calc.rotate(a, matrixb);
        Calc.shift(a, shiftb);
      }
      // Calculate the RMSD and TM score for the block
      double rmsdb = SVDSuperimposer.getRMS(ca1block, ca2block);
      double tmScoreb = SVDSuperimposer.getTMScore(ca1block, ca2block, ca1.length, ca2.length);
      blockRMSD[k] = rmsdb;
      blockScore[k] = tmScoreb;
    }
    afpChain.setOptRmsd(blockRMSD);
    afpChain.setBlockRmsd(blockRMSD);
    afpChain.setBlockScore(blockScore);
  }