/**
   * It replaces an optimal alignment of an AFPChain and calculates all the new alignment scores and
   * variables.
   */
  public static AFPChain replaceOptAln(int[][][] newAlgn, AFPChain afpChain, Atom[] ca1, Atom[] ca2)
      throws StructureException {

    // The order is the number of groups in the newAlgn
    int order = newAlgn.length;

    // Calculate the alignment length from all the subunits lengths
    int[] optLens = new int[order];
    for (int s = 0; s < order; s++) {
      optLens[s] = newAlgn[s][0].length;
    }
    int optLength = 0;
    for (int s = 0; s < order; s++) {
      optLength += optLens[s];
    }

    // Create a copy of the original AFPChain and set everything needed for the structure update
    AFPChain copyAFP = (AFPChain) afpChain.clone();

    // Set the new parameters of the optimal alignment
    copyAFP.setOptLength(optLength);
    copyAFP.setOptLen(optLens);
    copyAFP.setOptAln(newAlgn);

    // Set the block information of the new alignment
    copyAFP.setBlockNum(order);
    copyAFP.setBlockSize(optLens);
    copyAFP.setBlockResList(newAlgn);
    copyAFP.setBlockResSize(optLens);
    copyAFP.setBlockGap(calculateBlockGap(newAlgn));

    // Recalculate properties: superposition, tm-score, etc
    Atom[] ca2clone = StructureTools.cloneAtomArray(ca2); // don't modify ca2 positions
    AlignmentTools.updateSuperposition(copyAFP, ca1, ca2clone);

    // It re-does the sequence alignment strings from the OptAlgn information only
    copyAFP.setAlnsymb(null);
    AFPAlignmentDisplay.getAlign(copyAFP, ca1, ca2clone);

    return copyAFP;
  }
  /**
   * @param afpChain Input afpchain. UNMODIFIED
   * @param ca1
   * @param ca2
   * @param optLens
   * @param optAln
   * @return A NEW AfpChain based off the input but with the optAln modified
   * @throws StructureException if an error occured during superposition
   */
  public static AFPChain replaceOptAln(
      AFPChain afpChain, Atom[] ca1, Atom[] ca2, int blockNum, int[] optLens, int[][][] optAln)
      throws StructureException {
    int optLength = 0;
    for (int blk = 0; blk < blockNum; blk++) {
      optLength += optLens[blk];
    }

    // set everything
    AFPChain refinedAFP = (AFPChain) afpChain.clone();
    refinedAFP.setOptLength(optLength);
    refinedAFP.setBlockSize(optLens);
    refinedAFP.setOptLen(optLens);
    refinedAFP.setOptAln(optAln);
    refinedAFP.setBlockNum(blockNum);

    // TODO recalculate properties: superposition, tm-score, etc
    Atom[] ca2clone = StructureTools.cloneAtomArray(ca2); // don't modify ca2 positions
    AlignmentTools.updateSuperposition(refinedAFP, ca1, ca2clone);

    AFPAlignmentDisplay.getAlign(refinedAFP, ca1, ca2clone);
    return refinedAFP;
  }