Program: 17006
Project: 17006
Buggy source:
/** 
 * After the alignment changes (optAln, optLen, blockNum, at a minimum), many other properties which depend on the superposition will be invalid. 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
 * @throws StructureException
 * @see {@link CECalculator#calc_rmsd(Atom[],Atom[],int,boolean,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 {
  int optLength=afpChain.getOptLength();
  int alnPos=0;
  Atom[] aln1=new Atom[optLength];
  Atom[] aln2=new Atom[optLength];
  int[] optLen=afpChain.getOptLen();
  int[][][] optAln=afpChain.getOptAln();
  int blockNum=afpChain.getBlockNum();
  for (int blk=0; blk < blockNum; blk++) {
    for (int pos=0; pos < optLen[blk]; pos++) {
      int res1=optAln[blk][0][pos];
      int res2=optAln[blk][1][pos];
      aln1[alnPos]=ca1[res1];
      aln2[alnPos]=ca2[res2];
      alnPos++;
    }
  }
  SVDSuperimposer svd=new SVDSuperimposer(aln1,aln2);
  Matrix matrix=svd.getRotation();
  Atom shift=svd.getTranslation();
  for (  Atom a : ca2) {
    Calc.rotate(a.getGroup(),matrix);
    Calc.shift(a.getGroup(),shift);
  }
  double rmsd=svd.getRMS(ca1,ca2);
  double tm=svd.getTMScore(aln1,aln2,ca1.length,ca2.length);
  afpChain.setTotalRmsdOpt(rmsd);
  afpChain.setOptRmsd(null);
  afpChain.setBlockRmsd(null);
}

Fixed version (ground truth):
/** 
 * After the alignment changes (optAln, optLen, blockNum, at a minimum), many other properties which depend on the superposition will be invalid. 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,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 {
  int optLength=afpChain.getOptLength();
  int alnPos=0;
  Atom[] aln1=new Atom[optLength];
  Atom[] aln2=new Atom[optLength];
  int[] optLen=afpChain.getOptLen();
  int[][][] optAln=afpChain.getOptAln();
  int blockNum=afpChain.getBlockNum();
  for (int blk=0; blk < blockNum; blk++) {
    for (int pos=0; pos < optLen[blk]; pos++) {
      int res1=optAln[blk][0][pos];
      int res2=optAln[blk][1][pos];
      aln1[alnPos]=ca1[res1];
      aln2[alnPos]=ca2[res2];
      alnPos++;
    }
  }
  SVDSuperimposer svd=new SVDSuperimposer(aln1,aln2);
  Matrix matrix=svd.getRotation();
  Atom shift=svd.getTranslation();
  if (ca2.length > 0 && ca2[0].getGroup() != null && ca2[0].getGroup().getChain() != null && ca2[0].getGroup().getChain().getParent() != null) {
    Structure struct=ca2[0].getGroup().getChain().getParent();
    Calc.rotate(struct,matrix);
    Calc.shift(struct,shift);
  }
 else {
    for (    Atom a : ca2) {
      Calc.rotate(a.getGroup(),matrix);
      Calc.shift(a.getGroup(),shift);
    }
  }
  double rms=SVDSuperimposer.getRMS(ca1,ca2);
  double tm=SVDSuperimposer.getTMScore(aln1,aln2,ca1.length,ca2.length);
  afpChain.setTotalRmsdOpt(Math.sqrt(rms));
  afpChain.setTMScore(tm);
  double[] dummy=new double[blockNum];
  Arrays.fill(dummy,-1.);
  afpChain.setOptRmsd(dummy);
  afpChain.setBlockRmsd(dummy);
}