001/* This class is based on the original FATCAT implementation by 002 * <pre> 003 * Yuzhen Ye & Adam Godzik (2003) 004 * Flexible structure alignment by chaining aligned fragment pairs allowing twists. 005 * Bioinformatics vol.19 suppl. 2. ii246-ii255. 006 * https://www.ncbi.nlm.nih.gov/pubmed/14534198 007 * </pre> 008 * 009 * Thanks to Yuzhen Ye and A. Godzik for granting permission to freely use and redistribute this code. 010 * 011 * This code may be freely distributed and modified under the 012 * terms of the GNU Lesser General Public Licence. This should 013 * be distributed with the code. If you do not have a copy, 014 * see: 015 * 016 * http://www.gnu.org/copyleft/lesser.html 017 * 018 * Copyright for this code is held jointly by the individual 019 * authors. These should be listed in @author doc comments. 020 * 021 * 022 * Created on Jun 17, 2009 023 * Created by Andreas Prlic - RCSB PDB 024 * 025 */ 026 027package org.biojava.nbio.structure.align.fatcat.calc; 028 029import org.biojava.nbio.structure.Atom; 030import org.biojava.nbio.structure.StructureException; 031import org.biojava.nbio.structure.align.model.AFP; 032import org.biojava.nbio.structure.align.model.AFPChain; 033 034import java.util.List; 035 036public class AFPOptimizer 037{ 038 039 public static final boolean debug = FatCatAligner.debug; 040 041 /** 042 * optimize the alignment by dynamic programming 043 */ 044 public static void optimizeAln(FatCatParameters params, AFPChain afpChain,Atom[] ca1, Atom[] ca2) throws StructureException 045 { 046 047 int minLen = afpChain.getMinLen(); 048 int fragLen = params.getFragLen(); 049 050 051 long optStart = System.currentTimeMillis(); 052 int i, a, k, p1, p2, bk, b1, b2, e1, e2, a1, a2; 053 int iniLen; 054 int[][] iniSet = new int[2][minLen]; 055 int maxi = 100; 056 057 int[][][] optAln = afpChain.getOptAln(); 058 int[] optLen = afpChain.getOptLen(); 059 060 int maxTra = params.getMaxTra(); 061 double[] optRmsd = afpChain.getOptRmsd(); 062 063 int blockNum = afpChain.getBlockNum(); 064 065 if(optAln == null) { 066 optAln = new int[maxTra+1][2][minLen]; 067 optLen = new int[maxTra+1]; 068 afpChain.setOptLen(optLen); 069 optRmsd = new double[maxTra+1]; 070 afpChain.setOptRmsd(optRmsd); 071 } 072 073 List<AFP> afpSet = afpChain.getAfpSet(); 074 075 int optLength = afpChain.getOptLength(); 076 int[] afpChainList = afpChain.getAfpChainList(); 077 int[] block2Afp = afpChain.getBlock2Afp(); 078 int[] blockSize = afpChain.getBlockSize(); 079 080 081 if (debug) 082 System.out.println("AFPOptimizer got blockNum: " +blockNum); 083 //optimize each alignment defined by a block 084 b1 = b2 = e1 = e2 = optLength = 0; 085 for(bk = 0; bk < blockNum; bk ++) { 086 //initial aligned position 087 iniLen = 0; 088 if(bk > 0) { 089 b1 = e1; 090 b2 = e2; 091 } 092 if(bk < blockNum - 1) { 093 a1 = afpChainList[block2Afp[bk] + blockSize[bk] - 1]; //the last AFP in current block 094 a2 = afpChainList[block2Afp[bk + 1]]; //the first AFP in next block 095 e1 = (afpSet.get(a1).getP1() + fragLen + afpSet.get(a2).getP1()) / 2; 096 e2 = (afpSet.get(a1).getP2() + fragLen + afpSet.get(a2).getP2()) / 2; 097 } //use the middle point of the current and next AFPs. old (starting point of next AFP) 098 else { 099 e1 = ca1.length; 100 e2 = ca2.length; 101 } 102 103 104 for(i = block2Afp[bk]; i < block2Afp[bk] + blockSize[bk]; i ++) { 105 a = afpChainList[i]; 106 p1 = afpSet.get(a).getP1(); 107 p2 = afpSet.get(a).getP2(); 108 for(k = 0; k < afpSet.get(a).getFragLen(); k ++) { 109 iniSet[0][iniLen] = p1 + k - b1; //note -b1 110 iniSet[1][iniLen] = p2 + k - b2; //note -b2 111 iniLen ++; 112 113 } 114 } 115 //optimize the align by dynamic programming & constraint the optimization region 116 if(debug) { 117 System.err.println(String.format("optimize block %d (%d afp), region %d-%d(len %d), %d-%d(len %d)\n", 118 bk, blockSize[bk], b1, e1, e1-b1, b2, e2, e2-b2)); 119 120 System.err.println(" initial alignment Length: " + iniLen ); 121 } 122 123 StructureAlignmentOptimizer opt = new StructureAlignmentOptimizer(b1,e1, ca1, b2,e2, ca2, iniLen, iniSet); 124 opt.runOptimization(maxi); 125 optRmsd[bk] = opt.optimizeResult(optLen,bk,optAln[bk]); 126 127 //System.out.println(optRmsd[bk]); 128 // SALNOPT *opt = new SALNOPT(e1-b1, &pro1->caCod[3 * b1], e2-b2, &pro2->caCod[3 * b2], iniLen, iniSet, maxi); 129 // optRmsd[bk] = opt->OptimizeResult(&optLen[bk], optAln[bk]); 130 131 if(debug) 132 System.out.println(String.format(" optimized len=%d, rmsd %f\n", optLen[bk], optRmsd[bk])); 133 134 for(i = 0; i < optLen[bk]; i ++) { 135 optAln[bk][0][i] += b1; //restore the position 136 optAln[bk][1][i] += b2; //restore the position 137 } 138 optLength += optLen[bk]; 139 140 141 } 142 143 long optEnd = System.currentTimeMillis(); 144 if(debug) System.out.println("complete AlignOpt " + (optEnd-optStart) +"\n"); 145 146 if(optLength < minLen) { 147 int[][][] optAln_trim = new int[maxTra + 1][2][optLength]; 148 for (i = 0; i < maxTra + 1; i ++) { 149 System.arraycopy(optAln[i][0], 0, optAln_trim[i][0], 0, optLength); 150 System.arraycopy(optAln[i][1], 0, optAln_trim[i][1], 0, optLength); 151 } 152 afpChain.setOptAln(optAln_trim); 153 } else { 154 afpChain.setOptAln(optAln); 155 } 156 157 afpChain.setBlockNum(blockNum); 158 afpChain.setOptLength(optLength); 159 afpChain.setAfpChainList(afpChainList); 160 afpChain.setBlock2Afp(block2Afp); 161 afpChain.setBlockSize(blockSize); 162 163 164 } 165 166 /** 167 * get the afp list and residue list for each block 168 */ 169 170 public static void blockInfo(AFPChain afpChain) 171 { 172 int i, j, k, a, n; 173 174 int blockNum = afpChain.getBlockNum(); 175 176 int[] blockSize =afpChain.getBlockSize(); 177 int[] afpChainList = afpChain.getAfpChainList(); 178 int[] block2Afp = afpChain.getBlock2Afp(); 179 int[][][]blockResList = afpChain.getBlockResList(); 180 181 List<AFP>afpSet = afpChain.getAfpSet(); 182 int[] blockResSize = afpChain.getBlockResSize(); 183 184 for(i = 0; i < blockNum; i ++) { 185 n = 0; 186 for(j = 0; j < blockSize[i]; j ++) { 187 //the index in afpChainList, not in the whole afp set 188 a = afpChainList[block2Afp[i] + j]; 189 for(k = 0; k < afpSet.get(a).getFragLen(); k ++) { 190 blockResList[i][0][n] = afpSet.get(a).getP1() + k; 191 blockResList[i][1][n] = afpSet.get(a).getP2() + k; 192 n ++; 193 } 194 } 195 blockResSize[i] = n; 196 } 197 198 afpChain.setBlockResSize(blockResSize); 199 afpChain.setBlockSize(blockSize); 200 afpChain.setAfpChainList(afpChainList); 201 afpChain.setBlock2Afp(block2Afp); 202 afpChain.setBlockResList(blockResList); 203 } 204 205 /** 206 * to update the chaining score after block delete and merge processed 207 * the blockScore value is important for significance evaluation 208 */ 209 public static void updateScore(FatCatParameters params, AFPChain afpChain) 210 { 211 int i, j, bknow, bkold, g1, g2; 212 213 214 afpChain.setConn(0d); 215 afpChain.setDVar(0d); 216 217 int blockNum = afpChain.getBlockNum(); 218 int alignScoreUpdate = 0; 219 double[] blockScore = afpChain.getBlockScore(); 220 int[] blockGap = afpChain.getBlockGap(); 221 int[] blockSize =afpChain.getBlockSize(); 222 int[] afpChainList = afpChain.getAfpChainList(); 223 List<AFP>afpSet = afpChain.getAfpSet(); 224 int[] block2Afp = afpChain.getBlock2Afp(); 225 226 double torsionPenalty = params.getTorsionPenalty(); 227 228 229 bkold = 0; 230 for(i = 0; i < blockNum; i ++) { 231 blockScore[i] = 0; 232 blockGap[i] = 0; 233 for(j = 0; j < blockSize[i]; j ++) { 234 bknow = afpChainList[block2Afp[i] + j]; 235 if(j == 0) { 236 blockScore[i] = afpSet.get(bknow).getScore(); 237 } 238 else { 239 AFPChainer.afpPairConn(bkold, bknow, params, afpChain); //note: j, i 240 Double conn = afpChain.getConn(); 241 blockScore[i] += afpSet.get(bknow).getScore() + conn; 242 g1 = afpSet.get(bknow).getP1() - afpSet.get(bkold).getP1() - afpSet.get(bkold).getFragLen(); 243 g2 = afpSet.get(bknow).getP2() - afpSet.get(bkold).getP2() - afpSet.get(bkold).getFragLen(); 244 blockGap[i] += (g1 > g2)?g1:g2; 245 } 246 bkold = bknow; 247 } 248 alignScoreUpdate += blockScore[i]; 249 } 250 if(blockNum >= 2) { 251 alignScoreUpdate += (blockNum - 1) * torsionPenalty; 252 } 253 254 afpChain.setBlockGap(blockGap); 255 afpChain.setAlignScoreUpdate(alignScoreUpdate); 256 afpChain.setBlockScore(blockScore); 257 afpChain.setBlockSize(blockSize); 258 afpChain.setAfpChainList(afpChainList); 259 afpChain.setBlock2Afp(block2Afp); 260 } 261 262 263 264}