001/* 002 * BioJava development code 003 * 004 * This code may be freely distributed and modified under the 005 * terms of the GNU Lesser General Public Licence. This should 006 * be distributed with the code. If you do not have a copy, 007 * see: 008 * 009 * http://www.gnu.org/copyleft/lesser.html 010 * 011 * Copyright for this code is held jointly by the individual 012 * authors. These should be listed in @author doc comments. 013 * 014 * For more information on the BioJava project and its aims, 015 * or to join the biojava-l mailing list, visit the home page 016 * at: 017 * 018 * http://www.biojava.org/ 019 * 020 * Created on Feb 15, 2010 021 * Author: Andreas Prlic 022 * 023 */ 024 025package org.biojava.nbio.structure.align.model; 026 027import org.biojava.nbio.structure.*; 028import org.biojava.nbio.structure.align.ce.CeMain; 029import org.biojava.nbio.structure.align.ce.CeSideChainMain; 030import org.biojava.nbio.structure.align.fatcat.FatCatFlexible; 031import org.biojava.nbio.structure.align.seq.SmithWaterman3Daligner; 032import org.biojava.nbio.structure.align.util.AFPAlignmentDisplay; 033import org.biojava.nbio.structure.jama.Matrix; 034 035import java.io.StringWriter; 036import java.util.List; 037import java.util.Locale; 038 039/** 040 * A class to convert the data in an AfpChain object to various String outputs. 041 * 042 * @author Andreas Prlic 043 * 044 */ 045public class AfpChainWriter 046{ 047 048 public static final String newline = System.getProperty("line.separator"); 049 050 private static final int LINELENGTH = 70; 051 052 public static String toFatCat(AFPChain afpChain, Atom[] ca1, Atom[] ca2) 053 { 054 055 boolean printLegend = true; 056 boolean longHeader = true; 057 boolean showHTML = false; 058 boolean showAlignmentBlock = false; 059 060 return toFatCatCore(afpChain, ca1, ca2, printLegend, longHeader, showHTML, showAlignmentBlock); 061 } 062 063 public static String toScoresList(AFPChain afpChain){ 064 065 // see sippl On distance and similarity in fold space 2008 bioinformatics 066 067 StringWriter writer = new StringWriter(); 068 069 if ( afpChain.getAlgorithmName().startsWith("CE")) { 070 writer.append("Z-score " ); 071 writer.append(String.format(Locale.US, "%.2f", afpChain.getProbability())); 072 writer.append(newline); 073 } 074 075 076 writer.append("Sab (nr. equivalent residues): " ); 077 writer.append(String.valueOf(afpChain.getNrEQR())).append(""); 078 writer.append(newline); 079 080 writer.append("Dab (distance between folds a,b): "); 081 int dab = afpChain.getCa1Length()+afpChain.getCa2Length() - 2 * afpChain.getNrEQR(); 082 writer.append(String.valueOf(dab)).append(""); 083 writer.append(newline); 084 085 writer.append("sab (relative similarity): "); 086 double sab = 2 * afpChain.getNrEQR() / (double)( afpChain.getCa1Length() + afpChain.getCa2Length()); 087 writer.append(String.valueOf(sab)).append(""); 088 writer.append(newline); 089 090 writer.append("cab (coverage a): "); 091 double cab = afpChain.getNrEQR() / (double) afpChain.getCa1Length(); 092 writer.append(String.valueOf(cab)).append(""); 093 writer.append(newline); 094 095 writer.append("cba (coverage b): "); 096 double cba = afpChain.getNrEQR() / (double) afpChain.getCa2Length(); 097 writer.append(String.valueOf(cba)).append(""); 098 writer.append(newline); 099 100 writer.append("seq similarity: "); 101 writer.append(String.valueOf(afpChain.getSimilarity())).append(""); 102 writer.append(newline); 103 104 writer.append("TM-score: "); 105 writer.append(String.valueOf(afpChain.getTMScore())).append(""); 106 writer.append(newline); 107 108 return writer.toString(); 109 } 110 111 /** 112 * Output in FatCatCore format 113 * 114 * <p>Note that if a circular permutation has occured the residue numbers may 115 * be innaccurate. 116 * 117 * @param afpChain 118 * @param ca1 119 * @param ca2 120 * @param printLegend 121 * @param longHeader 122 * @param showHTML 123 * @param showAlignmentBlock 124 * @return 125 */ 126 public static String toFatCatCore( 127 AFPChain afpChain, 128 Atom[] ca1, 129 Atom[] ca2, 130 boolean printLegend, boolean longHeader, boolean showHTML, boolean showAlignmentBlock){ 131 132 //TODO The sequence numbers are inaccurate if a !afpChain.isSequential() 133 134 String name1 = afpChain.getName1(); 135 String name2 = afpChain.getName2(); 136 int ca1Length = afpChain.getCa1Length(); 137 int ca2Length = afpChain.getCa2Length(); 138 139 int blockNum = afpChain.getBlockNum(); 140 int totalLenIni = afpChain.getTotalLenIni(); 141 double totalRmsdIni = afpChain.getTotalRmsdIni(); 142 int optLength = afpChain.getOptLength(); 143 double totalRmsdOpt = afpChain.getTotalRmsdOpt(); 144 double chainRmsd = afpChain.getChainRmsd(); 145 double alignScore = afpChain.getAlignScore(); 146 int alnLength = afpChain.getAlnLength(); 147 int gapLen = afpChain.getGapLen(); 148 List<AFP> afpSet = afpChain.getAfpSet(); 149 150 double similarity = afpChain.getSimilarity(); 151 double identity = afpChain.getIdentity(); 152 153 if (similarity <0 || identity < 0){ 154 afpChain.calcSimilarity(); 155 similarity = afpChain.getSimilarity(); 156 identity = afpChain.getIdentity(); 157 } 158 159 160 161 String algorithmName = afpChain.getAlgorithmName(); 162 //String version = afpChain.getVersion(); 163 164 double probability = afpChain.getProbability(); 165 166 167 int afpNum = afpSet.size(); 168 169 int[] blockGap = afpChain.getBlockGap(); 170 171 172 double[] blockScore = afpChain.getBlockScore(); 173 double[] blockRmsd = afpChain.getBlockRmsd(); 174 int[] blockSize = afpChain.getBlockSize(); 175 176 177 int alnbeg1 = afpChain.getAlnbeg1(); 178 int alnbeg2 = afpChain.getAlnbeg2(); 179 180 char[] alnseq1 = afpChain.getAlnseq1(); 181 char[] alnseq2 = afpChain.getAlnseq2(); 182 char[] alnsymb = afpChain.getAlnsymb(); 183 184 // == end of extractation of data values from afpChain 185 //////////////////////////////// 186 187 StringBuffer txt = new StringBuffer(); 188 189 if ( longHeader) { 190 txt.append(String.format("Align %s.pdb %d with %s.pdb %d", name1, ca1Length, name2, ca2Length)); 191 } 192 else { 193 txt.append(String.format("Align %s.pdb Length1: %d with %s.pdb Length2: %d", name1, ca1Length, name2, ca2Length)); 194 } 195 txt.append(newline); 196 if ( afpChain.isShortAlign()){ 197 txt.append("Short match"); 198 return txt.toString(); 199 } 200 //txt.append(String.format(Locale.US, "raw-score: %.2f norm.-score: %.2f ", alignScore, normAlignScore)); 201 202 if ( longHeader ) { 203 txt.append(String.format(Locale.US, "Twists %d ini-len %d ini-rmsd %.2f opt-equ %d opt-rmsd %.2f chain-rmsd %.2f Score %.2f align-len %d gaps %d (%.2f%%)", 204 blockNum - 1, totalLenIni, totalRmsdIni, optLength, totalRmsdOpt, chainRmsd, alignScore, 205 alnLength, gapLen, (100.0 * gapLen/alnLength)) ); 206 txt.append(newline); 207 208 } else { 209 210 if ( ! longHeader) 211 printScore(txt,algorithmName,probability,longHeader); 212 213 printScoresInLines(afpChain, blockNum, optLength, totalRmsdOpt, alignScore, alnLength, gapLen, identity, similarity,txt); 214 } 215 216 217 //txt.append(String.format(Locale.US, "P-value %.2e Afp-num %d Identity %.2f%% Similarity %.2f%% norm.-score: %.2f"+newline, probability, afpNum, identity * 100, similarity * 100, normAlignScore)); 218 219 if ( longHeader) { 220 printScore(txt,algorithmName,probability,longHeader); 221 222 txt.append(String.format(Locale.US, "Afp-num %d Identity %.2f%% Similarity %.2f%%", afpNum, identity * 100, similarity * 100)); 223 txt.append(newline); 224 } 225 226 int i; 227 double gap; 228 229 if ( longHeader ){ 230 int fragLen = 8 ; // FatCatParameters.DEFAULT_FRAGLEN; 231 for(i = 0; i < blockNum; i ++) { 232 gap = blockGap[i] /( (double)blockGap[i] + fragLen * blockSize[i]); 233 txt.append(String.format(Locale.US, "Block %2d afp %2d score %5.2f rmsd %5.2f gap %d (%.2f%%)", 234 i, blockSize[i], blockScore[i], blockRmsd[i], blockGap[i], gap)); 235 txt.append(newline); 236 } 237 } 238 239 int linelen = 70; 240 String a; 241 String b; 242 String c; 243 244 245 int t = 0; 246 int ap = alnbeg1; 247 int bp = alnbeg2; 248 int k, len; 249 250 //System.out.println(alnseq1.length + " " + alnseq1.toString()); 251 252 while((alnLength - t) > 0) { 253 if(alnLength - t > linelen) len = linelen; 254 else len = alnLength - t; 255 256 if ( ap >= ca1.length) 257 break; 258 if ( bp >= ca2.length) 259 break; 260 261 String pdb1 = ca1[ap].getGroup().getResidueNumber().toString(); 262 String pdb2 = ca2[bp].getGroup().getResidueNumber().toString(); 263 264 265 //System.err.println("t,len:"+t+":"+len); 266 String lseq1 = new String(alnseq1).substring(t,t+len); 267 String lseq2 = new String(alnseq2).substring(t,t+len); 268 String lsymb = new String(alnsymb).substring(t,t+len); 269 270 //System.err.println("B:" + b); 271 272 273 // check conservation and color accordingly, if requested by user. 274 if ( showHTML ) { 275 a = ""; 276 b = ""; 277 c = ""; 278 279 // <span class=\"m\">|</span> ... Structurally equivalent and identical residues 280 // <span class=\"sm\">:</span> ... Structurally equivalent and similar residues 281 // <span class=\"qg\">.</span> ... Structurally equivalent, but not similar residues. 282 283 for (int pos = 0 ; pos < lseq1.length() ; pos ++){ 284 char c1 = lseq1.charAt(pos); 285 char c2 = lseq2.charAt(pos); 286 char cl = lsymb.charAt(pos); 287 int block = -1 ; 288 if ( cl != ' ') { 289 try { 290 block = Integer.parseInt(String.valueOf(cl)); 291 } catch (Exception e){ 292 // 293 } 294 } 295 if ( cl != ' ' ){ 296 297 if ( showAlignmentBlock && block > -1 ) { 298 a += "<span class=\"alignmentBlock1"+block+"\">" + c1 + "</span>"; 299 b += "<span class=\"alignmentBlock2"+block+"\">" + c2 + "</span>"; 300 c += "<span class=\"m\">" + cl + "</span>"; 301 } else { 302 a += getPrefix(c1, c2, 0, block, false).toString() + c1 + "</span>"; 303 b += getPrefix(c1, c2, 1, block, false).toString() + c2 + "</span>"; 304 c += "<span class=\"m\">" + cl + "</span>"; 305 } 306 307 } else if ( c1 != '-' && c2 != '-') { 308 309 a += "<span class=\"sm\">" + c1 + "</span>"; 310 b += "<span class=\"sm\">" + c2 + "</span>"; 311 c += "<span class=\"sm\">" + cl + "</span>"; 312 313 314 } else { 315 316 a += "<span class=\"qg\">" + c1 + "</span>"; 317 b += "<span class=\"qg\">" + c2 + "</span>"; 318 c += "<span class=\"qg\">" + cl + "</span>"; 319 320 } 321 322 if(c1 != '-') ap ++; 323 if(c2 != '-') bp ++; 324 } 325 326 327 } else { 328 329 a = lseq1; 330 b = lseq2; 331 c = lsymb; 332 } 333 334 txt.append(newline); 335 if ( longHeader ) 336 txt.append(String.format("%14s", " ")); 337 else 338 txt.append(String.format("%14s", " ")); 339 340 if ( longHeader ) { 341 for(k = 10; k <= len; k += 10) 342 txt.append(" . :"); 343 if(k <= len + 5) txt.append(" ."); 344 345 } else { 346 347 for(k = 10; k <= len; k += 10) 348 txt.append("----+----|"); 349 if(k <= len + 5) txt.append("----+"); 350 351 352 } 353 354 355 356 txt.append(newline); 357 txt.append(String.format("Chain 1:%5s %s"+newline +"%14s%s"+newline+"Chain 2:%5s %s", 358 pdb1, a, " ", c, pdb2, b)); 359 360 txt.append(newline); 361 362 if ( ! showHTML){ 363 for(k = 0; k < len; k ++) { 364 if(a.charAt(k) != '-') ap ++; 365 if(b.charAt(k) != '-') bp ++; 366 } 367 } 368 t += len; 369 370 371 372 } 373 txt.append(newline); 374 if ( printLegend ){ 375 if ( algorithmName.equalsIgnoreCase(CeMain.algorithmName) || 376 algorithmName.equalsIgnoreCase(SmithWaterman3Daligner.algorithmName)){ 377 txt.append("Note: positions are from PDB; | means alignment of identical amino acids, : of similar amino acids "); 378 379 } else { 380 txt.append("Note: positions are from PDB; the numbers between alignments are block index"); 381 } 382 txt.append(newline); 383 384 } 385 return txt.toString(); 386 387 } 388 389 public static void printScoresInLines(AFPChain afpChain, int blockNum, int optLength, double totalRmsdOpt, double alignScore, 390 int alnLength, int gapLen, double identity, double similarity, StringBuffer txt) 391 { 392 if ( blockNum - 1 > 0) { 393 txt.append(String.format(Locale.US, "Twists %d ", blockNum -1 )); 394 txt.append(newline); 395 } 396 397 txt.append(String.format(Locale.US, "Equ: %d ", optLength)); 398 txt.append(newline); 399 txt.append(String.format(Locale.US, "RMSD: %.2f ", totalRmsdOpt)); 400 txt.append(newline); 401 txt.append(String.format(Locale.US, "Score: %.2f ", alignScore)); 402 txt.append(newline); 403 txt.append(String.format(Locale.US, "Align-len: %d ", alnLength)); 404 txt.append(newline); 405 txt.append(String.format(Locale.US, "Gaps: %d (%.2f%%)", 406 gapLen, (100.0 * gapLen/alnLength)) ); 407 txt.append(newline); 408 if ( afpChain.getTMScore() >= 0) { 409 txt.append(String.format(Locale.US, "TM-score: %.2f",afpChain.getTMScore())); 410 txt.append(newline); 411 } 412 txt.append(newline); 413 txt.append(String.format(Locale.US, "Identity: %.2f%% ", identity * 100 )); 414 txt.append(newline); 415 txt.append(String.format(Locale.US, "Similarity: %.2f%%", similarity * 100)); 416 txt.append(newline); 417 } 418 419 private static void printScore(StringBuffer txt, 420 String algorithmName, 421 double probability, 422 boolean longHeader) 423 { 424 if ( algorithmName.equalsIgnoreCase(CeMain.algorithmName) || algorithmName.equalsIgnoreCase(CeSideChainMain.algorithmName) ){ 425 txt.append(String.format(Locale.US, "Z-score %.2f ", probability)); 426 if ( ! longHeader) 427 txt.append(newline); 428 } else if ( algorithmName.equalsIgnoreCase(SmithWaterman3Daligner.algorithmName)) { 429 430 } else { 431 if ( longHeader ){ 432 txt.append(String.format(Locale.US, "P-value %.2e ",probability)); 433 } else { 434 txt.append(String.format(Locale.US, "P-value: %.2e ",probability)); 435 txt.append(newline); 436 } 437 } 438 439 440 441 } 442 443 /** 444 * Prints the afpChain as a nicely formatted alignment, including alignment 445 * statistics, the aligned sequences themselves, and information about the 446 * superposition. 447 * @param afpChain 448 * @param ca1 449 * @param ca2 450 * @return a String representation as it is used on the RCSB PDB web site for display. 451 */ 452 public static String toWebSiteDisplay(AFPChain afpChain, Atom[] ca1, Atom[] ca2 ){ 453 boolean showAlignmentBlock = true; 454 return toWebSiteDisplay(afpChain, ca1, ca2, showAlignmentBlock); 455 } 456 457 /** 458 * Prints the afpChain as a nicely formatted alignment, including alignment 459 * statistics, the aligned sequences themselves, and information about the 460 * superposition. 461 * @param afpChain 462 * @param ca1 463 * @param ca2 464 * 465 * @return a String representation as it is used on the RCSB PDB web site for display. 466 */ 467 public static String toWebSiteDisplay(AFPChain afpChain, Atom[] ca1, Atom[] ca2, boolean showAlignmentBlock){ 468 469 boolean printLegend = true; 470 boolean longHeader = true; 471 boolean showHTML = true; 472 473 if ( afpChain.getAlgorithmName().equalsIgnoreCase(FatCatFlexible.algorithmName)) { 474 475 476 String msg = toFatCatCore(afpChain,ca1,ca2,printLegend,longHeader,showHTML, showAlignmentBlock); 477 478 return msg; 479 } 480 481 boolean showSeq = true; 482 483 AFPAlignmentDisplay.getAlign(afpChain, ca1, ca2, showSeq); 484 485 486 // String msg= toFatCatCore(afpChain,ca1,ca2, printLegend,longHeader); 487 // 488 489 490 String msg = toPrettyAlignment(afpChain, ca1, ca2, showHTML, showAlignmentBlock); 491 492 493 msg = msg + newline + 494 " <span class=\"m\">|</span> ... Structurally equivalent and identical residues " + newline + 495 " <span class=\"sm\">:</span> ... Structurally equivalent and similar residues " + newline + 496 " <span class=\"qg\">.</span> ... Structurally equivalent, but not similar residues. " + newline; 497 498 msg += newline; 499 msg += " To calculate the coordinates of chain 2 aligned on chain 1 apply the following transformation: "; 500 msg += newline; 501 msg += newline; 502 msg += toRotMat(afpChain); 503 return msg; 504 505 506 } 507 508 public static String toPrettyAlignment(AFPChain afpChain, Atom[] ca1, Atom[] ca2, boolean showHTML, boolean showAlignmentBlock) { 509 String name1 = afpChain.getName1(); 510 String name2 = afpChain.getName2(); 511 int ca1Length = afpChain.getCa1Length(); 512 int ca2Length = afpChain.getCa2Length(); 513 514 int blockNum = afpChain.getBlockNum(); 515 516 517 int optLength = afpChain.getOptLength(); 518 double totalRmsdOpt = afpChain.getTotalRmsdOpt(); 519 520 double alignScore = afpChain.getAlignScore(); 521 int alnLength = afpChain.getAlnLength(); 522 int gapLen = afpChain.getGapLen(); 523 524 525 double similarity = afpChain.getSimilarity(); 526 double identity = afpChain.getIdentity(); 527 528 if (similarity <0 || identity < 0){ 529 afpChain.calcSimilarity(); 530 similarity = afpChain.getSimilarity(); 531 identity = afpChain.getIdentity(); 532 } 533 534 535 String algorithmName = afpChain.getAlgorithmName(); 536 //String version = afpChain.getVersion(); 537 538 double probability = afpChain.getProbability(); 539 540 541 // == end of extractation of data values from afpChain 542 543 StringBuffer txt = new StringBuffer(); 544 545 txt.append(String.format("Align %s.pdb Length1: %d with %s.pdb Length2: %d", name1, ca1Length, name2, ca2Length)); 546 547 txt.append(newline); 548 549 if ( afpChain.isShortAlign()){ 550 txt.append("Short match"); 551 return txt.toString(); 552 } 553 554 printScore(txt, algorithmName, probability, false); 555 printScoresInLines(afpChain, blockNum, optLength, totalRmsdOpt, alignScore, alnLength, gapLen,identity, similarity, txt); 556 txt.append(newline); 557 558 int[] optLen = afpChain.getOptLen(); 559 int[][][] optAln = afpChain.getOptAln(); 560 561 562 int i, j,p1, p2; 563 564 int k; 565 int p1b = 0; 566 int p2b = 0; 567 568 int len = 0; 569 StringWriter alnseq1 = new StringWriter(); 570 StringWriter alnseq2 = new StringWriter(); 571 StringWriter alnsymb = new StringWriter(); 572 StringWriter header1 = new StringWriter(); 573 StringWriter footer1 = new StringWriter(); 574 StringWriter header2 = new StringWriter(); 575 StringWriter footer2 = new StringWriter(); 576 StringWriter block = new StringWriter(); 577 578 int aligPos = -1; 579 for(i = 0; i < blockNum; i ++) { 580 581 for(j = 0; j < optLen[i]; j ++) { 582 583 p1 = optAln[i][0][j]; 584 p2 = optAln[i][1][j]; 585 aligPos++; 586 587 // System.out.println(p1 + " " + p2 + " " + footer2.toString()); 588 589 if ( len == 0){ 590 //the first position of sequence in alignment 591 formatStartingText(p1,p2,header1,header2,footer1,footer2,ca1,ca2); 592 } else { 593 // check for gapped region 594 int lmax = (p1 - p1b - 1)>(p2 - p2b - 1)?(p1 - p1b - 1):(p2 - p2b - 1); 595 for(k = 0; k < lmax; k ++) { 596 597 598 formatGappedRegion(ca1, ca2, txt, p1, p2, k, p1b, p2b, alnseq1, alnseq2, alnsymb, header1, footer1, header2, 599 footer2, block,len, showHTML); 600 len++; 601 doLenCheck(len,txt,header1,header2,alnseq1,alnsymb,alnseq2,footer1, footer2,block, showHTML) ; 602 } 603 } 604 605 // ALIGNED REGION 606 // System.out.println(len + " >" + header1.toString() +"< "); 607 // System.out.println(len + " >" + header2.toString() +"< "); 608 // System.out.println(len + " >" + alnseq1.toString() +"< "); 609 // System.out.println(len + " >" + alnsymb.toString() +"< "); 610 // System.out.println(len + " >" + alnseq2.toString() +"< "); 611 // System.out.println(len + " >" + footer1.toString() +"< "); 612 formatAlignedRegion(afpChain, ca1, ca2, p1, p2, alnseq1, alnseq2, alnsymb, header1, footer1, header2, footer2, block,len, aligPos, showHTML, showAlignmentBlock); 613 // System.out.println(len + " >" + header1.toString() +"< "); 614 // System.out.println(len + " >" + header2.toString() +"< "); 615 // System.out.println(len + " >" + alnseq1.toString() +"< "); 616 // System.out.println(len + " >" + alnsymb.toString() +"< "); 617 // System.out.println(len + " >" + alnseq2.toString() +"< "); 618 // System.out.println(len + " >" + footer1.toString() +"< "); 619 620 len++; 621 622 doLenCheck(len,txt,header1,header2,alnseq1,alnsymb,alnseq2,footer1, footer2,block, showHTML) ; 623 624 p1b = p1; 625 p2b = p2; 626 627 //header1.append(newline); 628 //header2.append(newline); 629 630 } 631 632 } 633 634 alnLength = len; 635 636 doLenCheck(LINELENGTH,txt,header1,header2,alnseq1,alnsymb,alnseq2,footer1, footer2,block, showHTML); 637 return txt.toString(); 638 } 639 640 /** 641 * Prints the alignment in the simplest form: a list of aligned residues. 642 * Format is one line per residue pair, tab delimited: 643 * <ul><li>1. PDB number. Includes insertion code</li> 644 * <li>1. Chain.</li> 645 * <li>1. Amino Acid. Three letter code.</li> 646 * <li>2. PDB number.</li> 647 * <li>2. Chain.</li> 648 * <li>2. Amino Acid.</li> 649 * </ul> 650 * example: 651 * <code>152 A ALA 161S A VAL</code> 652 * <p>Note that this format loses information about blocks. 653 * @param afpChain 654 * @param ca1 655 * @param ca2 656 * @return a String representation of the aligned pairs. 657 */ 658 public static String toAlignedPairs(AFPChain afpChain, Atom[] ca1, Atom[] ca2) { 659 StringWriter pairs = new StringWriter(); 660 661 //Write structure names & PDB codes 662 pairs.append("#Struct1:\t"); 663 pairs.append(afpChain.getName1()); 664 pairs.append("\n"); 665 pairs.append("#Struct2:\t"); 666 pairs.append(afpChain.getName2()); 667 pairs.append("\n"); 668 669 //Write optimally aligned pairs 670 pairs.append("#Num1\tChain1\tAA1\tNum2\tChain2\tAA2\n"); 671 int[][][] optAln = afpChain.getOptAln(); 672 int[] blockLen = afpChain.getOptLen(); 673 for( int block=0;block<afpChain.getBlockNum(); block++) { 674 for(int i=0;i<blockLen[block];i++) { 675 Atom atom1 = ca1[ optAln[block][0][i] ]; 676 Atom atom2 = ca2[ optAln[block][1][i] ]; 677 678 pairs.append(atom1.getGroup().getResidueNumber().toString()); 679 pairs.append('\t'); 680 pairs.append(atom1.getGroup().getChain().getName()); 681 pairs.append('\t'); 682 pairs.append(atom1.getGroup().getPDBName()); 683 pairs.append('\t'); 684 pairs.append(atom2.getGroup().getResidueNumber().toString()); 685 pairs.append('\t'); 686 pairs.append(atom2.getGroup().getChain().getName()); 687 pairs.append('\t'); 688 pairs.append(atom2.getGroup().getPDBName()); 689 pairs.append('\n'); 690 } 691 } 692 693 return pairs.toString(); 694 } 695 696 private static void formatGappedRegion(Atom[] ca1, Atom[] ca2, StringBuffer txt, int p1, int p2, int k, int p1b, int p2b, 697 StringWriter alnseq1, StringWriter alnseq2, StringWriter alnsymb, StringWriter header1, StringWriter footer1, 698 StringWriter header2, StringWriter footer2, StringWriter block, int len, boolean formatHTML) { 699 700 // DEAL WITH GAPS 701 int tmppos = (p1 - p1b - 1); 702 block.append("g"); 703 704 int pos1=p1b+1+k ; 705 char oneletter1 = ' '; 706 try { 707 oneletter1 = getOneLetter(ca1[pos1].getGroup()); 708 } catch (Exception e){} 709 int pos2=p2b+1+k; 710 char oneletter2 = ' '; 711 try { 712 oneletter2 = getOneLetter(ca2[pos2].getGroup()); 713 } catch (Exception e){} 714 715 716 if(k >= tmppos) { 717 //alnseq1[len] = '-'; 718 if ( formatHTML){ 719 alnseq1.append("<span class=\"qg\">-</span>"); 720 header1.append(" "); 721 header2.append(" "); 722 723 724 } else { 725 alnseq1.append('-'); 726 header1.append(" "); 727 header2.append(" "); 728 } 729 730 } 731 else { 732 if ( formatHTML){ 733 alnseq1.append(getPrefix(oneletter1,oneletter2,0,-1, false)); 734 } 735 alnseq1.append(oneletter1); 736 if (formatHTML){ 737 alnseq1.append("</span>"); 738 } 739 formatPosition(pos1,ca1, len, header1, header2); 740 741 } 742 743 if(k >= (p2 - p2b - 1)) { 744 //alnseq2[len] = '-'; 745 if ( formatHTML){ 746 alnseq2.append("<span class=\"qg\">-</span>"); 747 footer1.append(" "); 748 footer2.append(" "); 749 } else { 750 alnseq2.append('-'); 751 footer1.append(" "); 752 footer2.append(" "); 753 } 754 755 } 756 else { 757 if ( formatHTML){ 758 alnseq2.append(getPrefix(oneletter1,oneletter2,1, -1, false)); 759 } 760 alnseq2.append(oneletter2); 761 if (formatHTML){ 762 alnseq2.append("</span>"); 763 } 764 formatPosition(pos2, ca2, len, footer1, footer2); 765 766 } 767 //alnsymb[len ++] = ' '; 768 alnsymb.append(' '); 769 770 } 771 772 773 774 private static CharSequence getPrefix(char oneletter1, char oneletter2, 775 int i, int blockNr, boolean showAlignmentBlock) { 776 777 if ( oneletter1 == '-' || oneletter2 == '-' ) { 778 // a gap in the alignment. 779 // label as mismatch 780 return "<span class=\"qg\">"; 781 } 782 783 // an aligned position 784 785 if ( showAlignmentBlock && blockNr > -1){ 786 return "<span class=\"alignmentBlock"+(i+1)+(blockNr+1)+"\">"; 787 } 788 789 // we return the "default" sequence alignment view... 790 791 if ( oneletter1 == oneletter2) 792 return "<span class=\"m\">"; 793 794 double score = AFPAlignmentDisplay.aaScore(oneletter1,oneletter2); 795 if ( score > 0 ) 796 return "<span class=\"sm\">"; 797 798 // not similar 799 return "<span class=\"qg\">"; 800 } 801 802 private static void formatPosition(int pos1, Atom[] ca, int len, StringWriter header1, StringWriter header2) 803 { 804 int linePos = len % LINELENGTH; 805 806 if ( header1.getBuffer().length() < linePos) { 807 // fill up the buffer, we are probably shortly after the start... 808 for ( int i = header1.getBuffer().length() ; i< linePos ; i++){ 809 header1.append(" "); 810 } 811 } 812 813 814 815 Atom a = ca[pos1]; 816 Group g = a.getGroup(); 817 818 ResidueNumber residueNumber = g.getResidueNumber(); 819 pos1 = residueNumber.getSeqNum(); 820 boolean hasInsertionCode = false; 821 if ( residueNumber.getInsCode() != null) { 822 hasInsertionCode = true; 823 } 824 825 if ( (pos1 %10 == 0) && ( ! hasInsertionCode)) { 826 CharSequence display = getPDBPos(a); 827 828 boolean ignoreH1 = false; 829 830 // make sure we don't have a problem with the left boundary... 831 if ( header1.getBuffer().length()-1 > linePos) { 832 ignoreH1 = true; 833 //System.out.println("Ignore h1: " + len + " " + header1.getBuffer().length() + " linePos: " + linePos +" >" + header1.toString() +"<"); 834 } 835 //System.out.println(len + " p1:" + tmp + " = " + pos1 + " " + " " + display + " " + ignoreH1); 836 if ( ! ignoreH1) { 837 header1.append(String.format("%-13s",display )); 838 header2.append("|"); 839 } else { 840 header2.append("|"); 841 } 842 843 } else if ( hasInsertionCode){ 844 Character insCode = g.getResidueNumber().getInsCode(); 845 if ( insCode != null) 846 header2.append(insCode); 847 else { 848 header2.append("!"); 849 } 850 } else if ( ((pos1) %5 ) == 0 && len > 5) { 851 header2.append("."); 852 } else { 853 if ( len > 0) 854 header2.append(" "); 855 } 856 857 } 858 859 860 861 private static void formatAlignedRegion(AFPChain afpChain, Atom[] ca1, Atom[] ca2, int p1, int p2, 862 StringWriter alnseq1, StringWriter alnseq2, 863 StringWriter alnsymb, StringWriter header1, StringWriter footer1, StringWriter header2, 864 StringWriter footer2, StringWriter block, int len, int aligPos, 865 boolean showHTML, boolean showAlignmentBlock) 866 { 867 char c1; 868 char c2; 869 if (( p1 < ca1.length) && (p2< ca2.length)){ 870 c1= getOneLetter(ca1[p1].getGroup()); 871 c2 = getOneLetter(ca2[p2].getGroup()); 872 } else { 873 c1 = 'X'; 874 c2 = 'X'; 875 } 876 877 int blockPos = -1; 878 if ( afpChain.getBlockNum() > 0) { 879 blockPos = AFPAlignmentDisplay.getBlockNrForAlignPos(afpChain, aligPos); 880 } 881 882 883 884 double score = AFPAlignmentDisplay.aaScore(c1,c2); 885 886 if ( showHTML) { 887 alnseq1.append(getPrefix(c1,c2, 0, blockPos, showAlignmentBlock)); 888 alnseq2.append(getPrefix(c1,c2, 1, blockPos, showAlignmentBlock)); 889 } 890 891 alnseq1.append(c1); 892 alnseq2.append(c2); 893 894 if ( showHTML){ 895 alnseq1.append("</span>"); 896 alnseq2.append("</span>"); 897 } 898 899 if ( c1 == c2){ 900 if ( showHTML){ 901 902 alnsymb.append("<span class=\"m\">|</span>"); 903 904 } else { 905 alnsymb.append('|'); 906 } 907 //alnsymb[len ++] = '|'; 908 } else { 909 910 911 if ( score > 1) { 912 if ( showHTML){ 913 alnsymb.append( "<span class=\"sm\">:</span>"); 914 } else { 915 alnsymb.append( ':'); 916 } 917 } 918 else { 919 if ( showHTML) 920 alnsymb.append( "<span class=\"qg\">.</span>"); 921 else 922 alnsymb.append( '.'); 923 } 924 } 925 926 if ( p1 < ca1.length) 927 formatPosition(p1, ca1,len, header1, header2); 928 929 if ( p2 < ca2.length) 930 formatPosition(p2,ca2,len, footer1, footer2); 931 932 } 933 934 private static void formatStartingText(int p1, int p2, StringWriter header1, StringWriter header2, StringWriter footer1, 935 StringWriter footer2, Atom[] ca1, Atom[] ca2) 936 { 937 938 header1.append(String.format("%-13s", getPDBPos(ca1[p1]))); 939 header2.append("|"); 940 footer1.append(String.format("%-13s", getPDBPos(ca2[p2]))); 941 footer2.append("|"); 942 943 944 } 945 946 private static boolean doLenCheck(int len, StringBuffer txt, StringWriter header1, StringWriter header2, StringWriter alnseq1, 947 StringWriter alnsymb, StringWriter alnseq2, StringWriter footer1, StringWriter footer2, StringWriter block, boolean formatHTML) 948 { 949 950 if ( len % LINELENGTH == 0) { 951 952 //txt.append("|"); 953 txt.append(header1); 954 //txt.append("|"); 955 txt.append(newline); 956 //txt.append("|"); 957 txt.append(header2); 958 //txt.append("|"); 959 txt.append(newline); 960 //txt.append("|"); 961 txt.append(alnseq1); 962 //txt.append("|"); 963 txt.append(newline); 964 965 //txt.append("|"); 966 txt.append(alnsymb); 967 // txt.append(newline); 968 // txt.append(block); 969 //txt.append("|"); 970 txt.append(newline); 971 //txt.append("|"); 972 txt.append(alnseq2); 973 //txt.append("|"); 974 txt.append(newline); 975 //txt.append("|"); 976 txt.append(footer2); 977 //txt.append("|"); 978 txt.append(newline); 979 //txt.append("|"); 980 txt.append(footer1); 981 //txt.append("|"); 982 txt.append(newline); 983 txt.append(newline); 984 txt.append(newline); 985 986 if (formatHTML ) { 987 988 int len1 = alnseq1.getBuffer().length(); 989 int len2 = alnseq2.getBuffer().length(); 990 int lens = alnsymb.getBuffer().length(); 991 alnseq1.getBuffer().replace(0, len1, ""); 992 alnseq2.getBuffer().replace(0, len2, ""); 993 alnsymb.getBuffer().replace(0, lens, ""); 994 995 996 997 header1.getBuffer().replace(0, LINELENGTH, ""); 998 header2.getBuffer().replace(0, LINELENGTH , ""); 999 footer1.getBuffer().replace(0, LINELENGTH, ""); 1000 footer2.getBuffer().replace(0, LINELENGTH, ""); 1001 block.getBuffer().replace(0, LINELENGTH, ""); 1002 } else { 1003 alnseq1.getBuffer().replace(0, LINELENGTH, ""); 1004 alnseq2.getBuffer().replace(0, LINELENGTH, ""); 1005 alnsymb.getBuffer().replace(0, LINELENGTH, ""); 1006 header1.getBuffer().replace(0, LINELENGTH, ""); 1007 header2.getBuffer().replace(0, LINELENGTH , ""); 1008 footer1.getBuffer().replace(0, LINELENGTH, ""); 1009 footer2.getBuffer().replace(0, LINELENGTH, ""); 1010 block.getBuffer().replace(0, LINELENGTH, ""); 1011 } 1012 StringBuffer buf = header1.getBuffer(); 1013 for ( int i=0;i<buf.length();i++){ 1014 char c = buf.charAt(i); 1015 if ( c != ' '){ 1016 buf.setCharAt(i, ' '); 1017 } 1018 } 1019 buf = footer1.getBuffer(); 1020 for ( int i=0;i<buf.length();i++){ 1021 char c = buf.charAt(i); 1022 if ( c != ' '){ 1023 buf.setCharAt(i, ' '); 1024 } 1025 } 1026 1027 return true; 1028 } 1029 1030 return false; 1031 1032 1033 } 1034 1035 private static CharSequence getPDBPos(Atom atom) 1036 { 1037 1038 Group g = atom.getGroup(); 1039 if ( g!= null){ 1040 Chain c = g.getChain(); 1041 if (c != null){ 1042 return g.getResidueNumber().toString()+":" + c.getName() ; 1043 //return g.getPDBCode()+":" + c.getName() + "." + getOneLetter(g) ; 1044 } 1045 } 1046 return "!"; 1047 } 1048 1049 private static char getOneLetter(Group g){ 1050 1051 1052 if (g==null) return StructureTools.UNKNOWN_GROUP_LABEL; 1053 1054 1055 return StructureTools.get1LetterCode(g.getPDBName()); 1056 1057 1058 } 1059 1060 1061 public static String toDBSearchResult(AFPChain afpChain) 1062 { 1063 StringBuffer str = new StringBuffer(); 1064 1065 str.append(afpChain.getName1()); 1066 str.append("\t"); 1067 str.append(afpChain.getName2()); 1068 str.append("\t"); 1069 str.append(String.format(Locale.US, "%.2f",afpChain.getAlignScore())); 1070 str.append("\t"); 1071 if ( afpChain.getAlgorithmName().equalsIgnoreCase(CeMain.algorithmName)){ 1072 str.append(String.format(Locale.US, "%.2f",afpChain.getProbability())); 1073 } else { 1074 str.append(String.format(Locale.US, "%.2e",afpChain.getProbability())); 1075 } 1076 str.append("\t"); 1077 str.append(String.format(Locale.US, "%.2f",afpChain.getTotalRmsdOpt())); 1078 str.append("\t"); 1079 str.append(afpChain.getCa1Length()); 1080 str.append("\t"); 1081 str.append(afpChain.getCa2Length()); 1082 str.append("\t"); 1083 str.append(afpChain.getCoverage1()); 1084 str.append("\t"); 1085 str.append(afpChain.getCoverage2()); 1086 str.append("\t"); 1087 str.append(String.format(Locale.US, "%.2f",afpChain.getIdentity())); 1088 str.append("\t"); 1089 str.append(afpChain.getDescription2()); 1090 str.append("\t"); 1091 str.append(newline); 1092 1093 return str.toString(); 1094 } 1095 1096 public static String toRotMat(AFPChain afpChain) 1097 { 1098 1099 Matrix[] blockRotationMatrix = afpChain.getBlockRotationMatrix(); 1100 int blockNum = afpChain.getBlockNum(); 1101 Atom[] blockShiftVector = afpChain.getBlockShiftVector(); 1102 1103 StringBuffer txt = new StringBuffer(); 1104 1105 if ( blockRotationMatrix == null || blockRotationMatrix.length < 1) 1106 return ""; 1107 1108 1109 for ( int blockNr = 0 ; blockNr < blockNum ; blockNr++){ 1110 Matrix m = blockRotationMatrix[blockNr]; 1111 Atom shift = blockShiftVector[blockNr]; 1112 if ( blockNum > 1) { 1113 txt.append("Operations for block " ); 1114 txt.append(blockNr); 1115 txt.append(newline); 1116 } 1117 1118 String origString = "orig"; 1119 if ( blockNr > 0) 1120 origString = String.valueOf(blockNr); 1121 1122 1123 txt.append(String.format(Locale.US, " X"+(blockNr+1)+" = (%9.6f)*X"+ origString +" + (%9.6f)*Y"+ origString +" + (%9.6f)*Z"+ origString +" + (%12.6f)",m.get(0,0),m.get(1,0), m.get(2,0), shift.getX())); 1124 txt.append( newline); 1125 txt.append(String.format(Locale.US, " Y"+(blockNr+1)+" = (%9.6f)*X"+ origString +" + (%9.6f)*Y"+ origString +" + (%9.6f)*Z"+ origString +" + (%12.6f)",m.get(0,1),m.get(1,1), m.get(2,1), shift.getY())); 1126 txt.append( newline); 1127 txt.append(String.format(Locale.US, " Z"+(blockNr+1)+" = (%9.6f)*X"+ origString +" + (%9.6f)*Y"+ origString +" + (%9.6f)*Z"+ origString +" + (%12.6f)",m.get(0,2),m.get(1,2), m.get(2,2), shift.getZ())); 1128 txt.append(newline); 1129 } 1130 return txt.toString(); 1131 } 1132 1133 public static String toCE(AFPChain afpChain, Atom[] ca1, Atom[] ca2) 1134 { 1135 1136 String name1 = afpChain.getName1(); 1137 String name2 = afpChain.getName2(); 1138 1139 int optLength = afpChain.getOptLength(); 1140 double totalRmsdOpt = afpChain.getTotalRmsdOpt(); 1141 1142 int alnLength = afpChain.getAlnLength(); 1143 int gapLen = afpChain.getGapLen(); 1144 1145 double similarity = afpChain.getSimilarity(); 1146 double identity = afpChain.getIdentity(); 1147 if (similarity <0 || identity <0 ){ 1148 afpChain.calcSimilarity(); 1149 similarity = afpChain.getSimilarity(); 1150 identity = afpChain.getIdentity(); 1151 } 1152 1153 double probability = afpChain.getProbability(); 1154 1155 1156 int alnbeg1 = afpChain.getAlnbeg1(); 1157 int alnbeg2 = afpChain.getAlnbeg2(); 1158 1159 char[] alnseq1 = afpChain.getAlnseq1(); 1160 char[] alnseq2 = afpChain.getAlnseq2(); 1161 1162 1163 long calculationTime = afpChain.getCalculationTime(); 1164 1165 // == end of extractation of data values from afpChain 1166 1167 StringBuffer txt = new StringBuffer(); 1168 1169 txt.append("Chain 1: "); 1170 txt.append(name1); 1171 txt.append(" (Size="); 1172 txt.append(ca1.length); 1173 txt.append(")"); 1174 txt.append(newline); 1175 txt.append("Chain 2: "); 1176 txt.append(name2); 1177 txt.append(" (Size="); 1178 txt.append(ca2.length); 1179 txt.append(")"); 1180 txt.append(newline); 1181 txt.append(newline); 1182 txt.append(String.format(Locale.US, "Alignment length = %d Rmsd = %.2fA Z-Score = %.1f",optLength,totalRmsdOpt,probability)); 1183 txt.append(String.format(Locale.US, " Gaps = %d(%.1f%%) CPU = %d ms. Sequence identities = %.1f%%",gapLen,( gapLen*100.0/optLength),calculationTime,identity*100)); 1184 1185 int linelen = 70; 1186 String a; 1187 String b; 1188 1189 int t = 0; 1190 int ap = alnbeg1; 1191 int bp = alnbeg2; 1192 int k, len; 1193 1194 while((alnLength - t) > 0) { 1195 if(alnLength - t > linelen) len = linelen; 1196 else len = alnLength - t; 1197 1198 1199 //System.err.println("t,len:"+t+":"+len); 1200 a = new String(alnseq1).substring(t,t+len); 1201 b = new String(alnseq2).substring(t,t+len); 1202 1203 //System.err.println("B:" + b); 1204 1205 /* 1206 txt.append(newline); 1207 txt.append(String.format("%14s", " ")); 1208 1209 for(k = 10; k <= len; k += 10) 1210 txt.append(" . :"); 1211 if(k <= len + 5) txt.append(" ."); 1212 */ 1213 1214 //String pdb1 = ca1[ap].getParent().getPDBCode(); 1215 //String pdb2 = ca2[bp].getParent().getPDBCode(); 1216 txt.append(newline); 1217 txt.append(String.format("Chain 1:%5s %s"+newline+"Chain 2:%5s %s", 1218 (ap+1), a, (bp+1), b)); 1219 txt.append(newline); 1220 for(k = 0; k < len; k ++) { 1221 if(a.charAt(k) != '-') ap ++; 1222 if(b.charAt(k) != '-') bp ++; 1223 } 1224 t += len; 1225 1226 } 1227 txt.append(newline); 1228 1229 txt.append(toRotMat(afpChain)); 1230 1231 return txt.toString(); 1232 } 1233 1234}