/** * Checks that the alignment given by afpChain is sequential. This means that the residue indices * of both proteins increase monotonically as a function of the alignment position (ie both * proteins are sorted). * * <p>This will return false for circularly permuted alignments or other non-topological * alignments. It will also return false for cases where the alignment itself is sequential but it * is not stored in the afpChain in a sorted manner. * * <p>Since algorithms which create non-sequential alignments split the alignment into multiple * blocks, some computational time can be saved by only checking block boundaries for * sequentiality. Setting <tt>checkWithinBlocks</tt> to <tt>true</tt> makes this function slower, * but detects AFPChains with non-sequential blocks. * * <p>Note that this method should give the same results as {@link * AFPChain#isSequentialAlignment()}. However, the AFPChain version relies on the * StructureAlignment algorithm correctly setting this parameter, which is sadly not always the * case. * * @param afpChain An alignment * @param checkWithinBlocks Indicates whether individual blocks should be checked for * sequentiality * @return True if the alignment is sequential. */ public static boolean isSequentialAlignment(AFPChain afpChain, boolean checkWithinBlocks) { int[][][] optAln = afpChain.getOptAln(); int[] alnLen = afpChain.getOptLen(); int blocks = afpChain.getBlockNum(); if (blocks < 1) return true; // trivial case if (alnLen[0] < 1) return true; // Check that blocks are sequential if (checkWithinBlocks) { for (int block = 0; block < blocks; block++) { if (alnLen[block] < 1) continue; // skip empty blocks int prevRes1 = optAln[block][0][0]; int prevRes2 = optAln[block][1][0]; for (int pos = 1; pos < alnLen[block]; pos++) { int currRes1 = optAln[block][0][pos]; int currRes2 = optAln[block][1][pos]; if (currRes1 < prevRes1) { return false; } if (currRes2 < prevRes2) { return false; } prevRes1 = currRes1; prevRes2 = currRes2; } } } // Check that blocks are sequential int prevRes1 = optAln[0][0][alnLen[0] - 1]; int prevRes2 = optAln[0][1][alnLen[0] - 1]; for (int block = 1; block < blocks; block++) { if (alnLen[block] < 1) continue; // skip empty blocks if (optAln[block][0][0] < prevRes1) { return false; } if (optAln[block][1][0] < prevRes2) { return false; } prevRes1 = optAln[block][0][alnLen[block] - 1]; prevRes2 = optAln[block][1][alnLen[block] - 1]; } return true; }
/** * Builds an {@link AFPChain} from already-matched arrays of atoms and residues. * * @param ca1 An array of atoms in the first structure * @param ca2 An array of atoms in the second structure * @param residues1 An array of {@link ResidueNumber ResidueNumbers} in the first structure that * are aligned. Only null ResidueNumbers are considered to be unaligned * @param residues2 An array of {@link ResidueNumber ResidueNumbers} in the second structure that * are aligned. Only null ResidueNumbers are considered to be unaligned * @throws StructureException */ private static AFPChain buildAlignment( Atom[] ca1, Atom[] ca2, ResidueNumber[] residues1, ResidueNumber[] residues2) throws StructureException { // remove any gap // this includes the ones introduced by the nullifying above List<ResidueNumber> alignedResiduesList1 = new ArrayList<ResidueNumber>(); List<ResidueNumber> alignedResiduesList2 = new ArrayList<ResidueNumber>(); for (int i = 0; i < residues1.length; i++) { if (residues1[i] != null && residues2[i] != null) { alignedResiduesList1.add(residues1[i]); alignedResiduesList2.add(residues2[i]); } } ResidueNumber[] alignedResidues1 = alignedResiduesList1.toArray(new ResidueNumber[alignedResiduesList1.size()]); ResidueNumber[] alignedResidues2 = alignedResiduesList2.toArray(new ResidueNumber[alignedResiduesList2.size()]); AFPChain afpChain = AlignmentTools.createAFPChain(ca1, ca2, alignedResidues1, alignedResidues2); afpChain.setAlgorithmName("unknown"); AlignmentTools.updateSuperposition(afpChain, ca1, ca2); afpChain.setBlockSize(new int[] {afpChain.getNrEQR()}); afpChain.setBlockRmsd(new double[] {afpChain.getTotalRmsdOpt()}); afpChain.setBlockGap(new int[] {afpChain.getGapLen()}); return afpChain; }
/** * Creates a Map specifying the alignment as a mapping between residue indices of protein 1 and * residue indices of protein 2. * * <p>For example, * * <pre> * 1234 * 5678</pre> * * becomes * * <pre> * 1->5 * 2->6 * 3->7 * 4->8</pre> * * @param afpChain An alignment * @return A mapping from aligned residues of protein 1 to their partners in protein 2. * @throws StructureException If afpChain is not one-to-one */ public static Map<Integer, Integer> alignmentAsMap(AFPChain afpChain) throws StructureException { Map<Integer, Integer> map = new HashMap<Integer, Integer>(); if (afpChain.getAlnLength() < 1) { return map; } int[][][] optAln = afpChain.getOptAln(); int[] optLen = afpChain.getOptLen(); for (int block = 0; block < afpChain.getBlockNum(); block++) { for (int pos = 0; pos < optLen[block]; pos++) { int res1 = optAln[block][0][pos]; int res2 = optAln[block][1][pos]; if (map.containsKey(res1)) { throw new StructureException( String.format("Residue %d aligned to both %d and %d.", res1, map.get(res1), res2)); } map.put(res1, res2); } } return map; }
/** * Retrieves the optimum alignment from an AFPChain and returns it as a java collection. The * result is indexed in the same way as {@link AFPChain#getOptAln()}, but has the correct size(). * * <pre> * List<List<List<Integer>>> aln = getOptAlnAsList(AFPChain afpChain); * aln.get(blockNum).get(structureNum={0,1}).get(pos)</pre> * * @param afpChain * @return */ public static List<List<List<Integer>>> getOptAlnAsList(AFPChain afpChain) { int[][][] optAln = afpChain.getOptAln(); int[] optLen = afpChain.getOptLen(); List<List<List<Integer>>> blocks = new ArrayList<List<List<Integer>>>(afpChain.getBlockNum()); for (int blockNum = 0; blockNum < afpChain.getBlockNum(); blockNum++) { // TODO could improve speed an memory by wrapping the arrays with // an unmodifiable list, similar to Arrays.asList(...) but with the // correct size parameter. List<Integer> align1 = new ArrayList<Integer>(optLen[blockNum]); List<Integer> align2 = new ArrayList<Integer>(optLen[blockNum]); for (int pos = 0; pos < optLen[blockNum]; pos++) { align1.add(optAln[blockNum][0][pos]); align2.add(optAln[blockNum][1][pos]); } List<List<Integer>> block = new ArrayList<List<Integer>>(2); block.add(align1); block.add(align2); blocks.add(block); } return blocks; }
/** * Conditions checked are: score above the threshold, order higher than 1 and refinement * succeeded. * * @return true if significant, false otherwise */ public boolean isSignificant() { // In any case if the order is 1 it is asymmetric if (symmOrder < 2) return false; // If the TM-Score is below the threshold if (selfAlignment.getTMScore() < params.getScoreThreshold()) return false; // If the refinement was attempted if (params.getRefineMethod() != RefineMethod.NOT_REFINED) { // Check for minimum length if (multipleAlignment.getCoreLength() < params.getMinCoreLength()) return false; // Allow 90% of original TM-Score theshold if (multipleAlignment.getScore(MultipleAlignmentScorer.AVGTM_SCORE) < params.getScoreThreshold() * 0.9) return false; return true; } return true; }
/** * @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; }
/** * 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); }
/** * 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 a * @param ca1 * @param ca2 * @return * @throws StructureException if an error occurred during superposition */ public static AFPChain splitBlocksByTopology(AFPChain a, Atom[] ca1, Atom[] ca2) throws StructureException { int[][][] optAln = a.getOptAln(); int blockNum = a.getBlockNum(); int[] optLen = a.getOptLen(); // Determine block lengths // Split blocks if residue indices don't increase monotonically List<Integer> newBlkLen = new ArrayList<Integer>(); boolean blockChanged = false; for (int blk = 0; blk < blockNum; blk++) { int currLen = 1; for (int pos = 1; pos < optLen[blk]; pos++) { if (optAln[blk][0][pos] <= optAln[blk][0][pos - 1] || optAln[blk][1][pos] <= optAln[blk][1][pos - 1]) { // start a new block newBlkLen.add(currLen); currLen = 0; blockChanged = true; } currLen++; } if (optLen[blk] < 2) { newBlkLen.add(optLen[blk]); } else { newBlkLen.add(currLen); } } // Check if anything needs to be split if (!blockChanged) { return a; } // Split blocks List<int[][]> blocks = new ArrayList<int[][]>(newBlkLen.size()); int oldBlk = 0; int pos = 0; for (int blkLen : newBlkLen) { if (blkLen == optLen[oldBlk]) { assert (pos == 0); // should be the whole block // Use the old block blocks.add(optAln[oldBlk]); } else { int[][] newBlock = new int[2][blkLen]; assert (pos + blkLen <= optLen[oldBlk]); // don't overrun block for (int i = 0; i < blkLen; i++) { newBlock[0][i] = optAln[oldBlk][0][pos + i]; newBlock[1][i] = optAln[oldBlk][1][pos + i]; } pos += blkLen; blocks.add(newBlock); if (pos == optLen[oldBlk]) { // Finished this oldBlk, start the next oldBlk++; pos = 0; } } } // Store new blocks int[][][] newOptAln = blocks.toArray(new int[0][][]); int[] newBlockLens = new int[newBlkLen.size()]; for (int i = 0; i < newBlkLen.size(); i++) { newBlockLens[i] = newBlkLen.get(i); } return replaceOptAln(a, ca1, ca2, blocks.size(), newBlockLens, newOptAln); }
/** * Fundamentally, an alignment is just a list of aligned residues in each protein. This method * converts two lists of ResidueNumbers into an AFPChain. * * <p>Parameters are filled with defaults (often null) or sometimes calculated. * * <p>For a way to modify the alignment of an existing AFPChain, see {@link * AlignmentTools#replaceOptAln(AFPChain, Atom[], Atom[], Map)} * * @param ca1 CA atoms of the first protein * @param ca2 CA atoms of the second protein * @param aligned1 A list of aligned residues from the first protein * @param aligned2 A list of aligned residues from the second protein. Must be the same length as * aligned1. * @return An AFPChain representing the alignment. Many properties may be null or another default. * @throws StructureException if an error occured during superposition * @throws IllegalArgumentException if aligned1 and aligned2 have different lengths * @see AlignmentTools#replaceOptAln(AFPChain, Atom[], Atom[], Map) */ public static AFPChain createAFPChain( Atom[] ca1, Atom[] ca2, ResidueNumber[] aligned1, ResidueNumber[] aligned2) throws StructureException { // input validation int alnLen = aligned1.length; if (alnLen != aligned2.length) { throw new IllegalArgumentException("Alignment lengths are not equal"); } AFPChain a = new AFPChain(AFPChain.UNKNOWN_ALGORITHM); try { a.setName1(ca1[0].getGroup().getChain().getStructure().getName()); if (ca2[0].getGroup().getChain().getStructure() != null) { // common case for cloned ca2 a.setName2(ca2[0].getGroup().getChain().getStructure().getName()); } } catch (Exception e) { // One of the structures wasn't fully created. Ignore } a.setBlockNum(1); a.setCa1Length(ca1.length); a.setCa2Length(ca2.length); a.setOptLength(alnLen); a.setOptLen(new int[] {alnLen}); Matrix[] ms = new Matrix[a.getBlockNum()]; a.setBlockRotationMatrix(ms); Atom[] blockShiftVector = new Atom[a.getBlockNum()]; a.setBlockShiftVector(blockShiftVector); String[][][] pdbAln = new String[1][2][alnLen]; for (int i = 0; i < alnLen; i++) { pdbAln[0][0][i] = aligned1[i].getChainId() + ":" + aligned1[i]; pdbAln[0][1][i] = aligned2[i].getChainId() + ":" + aligned2[i]; } a.setPdbAln(pdbAln); // convert pdbAln to optAln, and fill in some other basic parameters AFPChainXMLParser.rebuildAFPChain(a, ca1, ca2); return a; // Currently a single block. Split into several blocks by sequence if needed // return AlignmentTools.splitBlocksByTopology(a,ca1,ca2); }
/** * Creates a simple interaction format (SIF) file for an alignment. * * <p>The SIF file can be read by network software (eg Cytoscape) to analyze alignments as graphs. * * <p>This function creates a graph with residues as nodes and two types of edges: 1. backbone * edges, which connect adjacent residues in the aligned protein 2. alignment edges, which connect * aligned residues * * @param out Stream to write to * @param afpChain alignment to write * @param ca1 First protein, used to generate node names * @param ca2 Second protein, used to generate node names * @param backboneInteraction Two-letter string used to identify backbone edges * @param alignmentInteraction Two-letter string used to identify alignment edges * @throws IOException */ public static void alignmentToSIF( Writer out, AFPChain afpChain, Atom[] ca1, Atom[] ca2, String backboneInteraction, String alignmentInteraction) throws IOException { // out.write("Res1\tInteraction\tRes2\n"); String name1 = afpChain.getName1(); String name2 = afpChain.getName2(); if (name1 == null) name1 = ""; else name1 += ":"; if (name2 == null) name2 = ""; else name2 += ":"; // Print alignment edges int nblocks = afpChain.getBlockNum(); int[] blockLen = afpChain.getOptLen(); int[][][] optAlign = afpChain.getOptAln(); for (int b = 0; b < nblocks; b++) { for (int r = 0; r < blockLen[b]; r++) { int res1 = optAlign[b][0][r]; int res2 = optAlign[b][1][r]; ResidueNumber rn1 = ca1[res1].getGroup().getResidueNumber(); ResidueNumber rn2 = ca2[res2].getGroup().getResidueNumber(); String node1 = name1 + rn1.getChainId() + rn1.toString(); String node2 = name2 + rn2.getChainId() + rn2.toString(); out.write(String.format("%s\t%s\t%s\n", node1, alignmentInteraction, node2)); } } // Print first backbone edges ResidueNumber rn = ca1[0].getGroup().getResidueNumber(); String last = name1 + rn.getChainId() + rn.toString(); for (int i = 1; i < ca1.length; i++) { rn = ca1[i].getGroup().getResidueNumber(); String curr = name1 + rn.getChainId() + rn.toString(); out.write(String.format("%s\t%s\t%s\n", last, backboneInteraction, curr)); last = curr; } // Print second backbone edges, if the proteins differ // Do some quick checks for whether the proteins differ // (Not perfect, but should detect major differences and CPs.) if (!name1.equals(name2) || ca1.length != ca2.length || (ca1.length > 0 && ca1[0].getGroup() != null && ca2[0].getGroup() != null && !ca1[0] .getGroup() .getResidueNumber() .equals(ca2[0].getGroup().getResidueNumber()))) { rn = ca2[0].getGroup().getResidueNumber(); last = name2 + rn.getChainId() + rn.toString(); for (int i = 1; i < ca2.length; i++) { rn = ca2[i].getGroup().getResidueNumber(); String curr = name2 + rn.getChainId() + rn.toString(); out.write(String.format("%s\t%s\t%s\n", last, backboneInteraction, curr)); last = curr; } } }
public void testOldSecOutput() throws Exception { String fileName = "/ce_1fdo.A_2iv2.X.out"; InputStream inStream = this.getClass().getResourceAsStream(fileName); assertNotNull("Could not find file " + fileName + " in resource path. Config error?", inStream); String xml = StringManipulationHelper.convertStreamToString(inStream); AtomCache cache = new AtomCache(); String name1 = "1FDO.A"; String name2 = "2IV2.X"; Atom[] ca1 = cache.getAtoms(name1); Atom[] ca2 = cache.getAtoms(name2); assertEquals(715, ca1.length); assertEquals(697, ca2.length); AFPChain afpChainOrig = AFPChainXMLParser.fromXML(xml, ca1, ca2); assertNotNull("Could not get AfpChain object from flat file!", afpChainOrig); assertEquals( "Could not find alignment string for prot 1", "MKKVVTVCPYCASGCKINLVVDNGKIVRAEAAQGKTNQGTLCLKGYYGWDFINDTQILTPRLKTPMIRRQRGGKLEPVSWDEALNYVAERLSAIKEKYGPDAIQTTGSSRGTGNETNYVMQKFARAVIGTNNVDCCARVUHGPSVA-----GLHQSVGNGAMSNAINEIDNTDLVFVFGYNPADSHPIVANHVINAKRNGAKIIVCDPRKIETARIADMHIALKNGSNIALLNAMGHVIIEENLYDKAFVASRTEGFEEYRKIVEGYTPESVEDITGVSASEIRQAARMYAQAKSAAILWGMGVTQFYQGVETVRSLTSLAMLTGNLGKPHAGVNPVRGQNNVQGACDMGALPDTYPGYQYVKDPANREKFAKAWGVESLPAHTGYRISELPHRAAHGEVRAAYIMGEDPLQTDAELSAVRKAFEDLELVIVQDIFMTKTASAADVILPSTSWGEHEGVFTAADRGFQRFFKAVEPKWDLKTDWQIISEIATRMGYPMHYNNTQEIWDELRHLCPDFYGATYEKMGELGFIQWPCRDTSDADQGTSYLFKEKFDTPNGLAQFFTCDWVAPIDKLTDEYPMVLSTVREVGHYSCRSMTGNCAALAALADEPGYAQINTEDAKRLGIEDEALVWVHSRKGKIITRAQVSDRPNKGAIYMTYQWWIGACNELVTENLSPITKTPEYKYCAVRVEPIADQRAAEQYVIDEYNKLKTRLREAALA", new String(afpChainOrig.getAlnseq1(), 0, afpChainOrig.getAlnLength())); assertEquals( "Could not find alignment string for prot 2", "MKKVVTVCPYCASGCKINLVVDNGKIVRAEAAQGKTNQGTLCLKGYYGWDFINDTQILTPRLKTPMIRRQRGGKLEPVSWDEALNYVAERLSAIKEKYGPDAIQTTGSSRGTGNETNYVMQKFARAVIGTNNVDCCAR-----VUHGPSVAGLHQSVGNGAMSNAINEIDNTDLVFVFGYNPADSHPIVANHVINAKRNGAKIIVCDPRKIETARIADMHIALKNGSNIALLNAMGHVIIEENLYDKAFVASRTEGFEEYRKIVEGYTPESVEDITGVSASEIRQAARMYAQAKSAAILWGMGVTQFYQGVETVRSLTSLAMLTGNLGKPHAGVNPVRGQNNVQGACDMGALPDTYPGYQYVKDPANREKFAKAWGVESLPAHTGYRISELPHRAAHGEVRAAYIMGEDPLQTDAELSAVRKAFEDLELVIVQDIFMTKTASAADVILPSTSWGEHEGVFTAADRGFQRFFKAVEPKWDLKTDWQIISEIATRMGYPMHYNNTQEIWDELRHLCPDFYGATYEKMGELGFIQWPCRDTSDADQGTSYLFKEKFDTPNGLAQFFTCDWVAPIDKLTDEYPMVLSTVREVGHYSCRSMTGNCAALAALADEPGYAQINTEDAKRLGIEDEALVWVHSRKGKIITRAQVSDRPNKGAIYMTYQWW------------------PEYKYCAVRVEPIADQRAAEQYVIDEYNKLKTRLREAALA", new String(afpChainOrig.getAlnseq2(), 0, afpChainOrig.getAlnLength())); // calc time is hardware dependent.... overwrite... afpChainOrig.setCalculationTime(-1); assertEquals( "alnLength is wrong! (" + afpChainOrig.getAfpChainLen() + ")", 720, afpChainOrig.getAlnLength()); assertEquals( "gapLength is wrong! (" + afpChainOrig.getGapLen() + ")", 28, afpChainOrig.getGapLen()); // identity should be 0.9569 assertTrue( "alinment ID is < 0.95 ! (" + afpChainOrig.getIdentity() + ")", afpChainOrig.getIdentity() > 0.95); assertTrue( "alignment ID is > 0.96 ! (" + afpChainOrig.getIdentity() + ")", afpChainOrig.getIdentity() < 0.96); String xmlComp = AFPChainXMLConverter.toXML(afpChainOrig, ca1, ca2); FlipAFPChainTest t = new FlipAFPChainTest(); t.printFirstMismatch(xml, xmlComp); StringManipulationTestsHelper.assertEqualsIgnoreEndline(xml, xmlComp); StructureAlignment ce = StructureAlignmentFactory.getAlgorithm(CeMain.algorithmName); AFPChain afpChainNew = ce.align(ca1, ca2); afpChainNew.setCalculationTime(-1); afpChainNew.setName1(name1); afpChainNew.setName2(name2); String xmlNew = AFPChainXMLConverter.toXML(afpChainNew, ca1, ca2); StringManipulationTestsHelper.assertEqualsIgnoreEndline(xml, xmlNew); }