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;
037
038/** A class to convert the data in an AfpChain object to various String outputs.
039 *
040 * @author Andreas Prlic
041 *
042 */
043public class AfpChainWriter
044{
045
046        public static final String newline = System.getProperty("line.separator");
047
048        private static int LINELENGTH = 70;
049
050        public static String toFatCat(AFPChain afpChain, Atom[] ca1, Atom[] ca2)
051        {
052
053                boolean printLegend = true;
054                boolean longHeader  = true;
055                boolean showHTML = false;
056                boolean showAlignmentBlock = false;
057
058                return toFatCatCore(afpChain, ca1, ca2, printLegend, longHeader, showHTML, showAlignmentBlock);
059        }
060
061        public static String toScoresList(AFPChain afpChain){
062
063                // see sippl On distance and similarity in fold space 2008 bioinformatics
064
065                StringWriter writer = new StringWriter();
066
067                if ( afpChain.getAlgorithmName().startsWith("CE")) {
068                        writer.append("Z-score " );
069                        writer.append(String.format("%.2f", afpChain.getProbability()));
070                        writer.append(newline);
071                }
072
073
074                writer.append("Sab (nr. equivalent residues): " );
075                writer.append(String.valueOf(afpChain.getNrEQR())).append("");
076                writer.append(newline);
077
078                writer.append("Dab (distance between folds a,b): ");
079                int dab = afpChain.getCa1Length()+afpChain.getCa2Length() - 2 * afpChain.getNrEQR();
080                writer.append(String.valueOf(dab)).append("");
081                writer.append(newline);
082
083                writer.append("sab (relative similarity): ");
084                double sab = 2 * afpChain.getNrEQR() / (double)( afpChain.getCa1Length() + afpChain.getCa2Length());
085                writer.append(String.valueOf(sab)).append("");
086                writer.append(newline);
087
088                writer.append("cab (coverage a): ");
089                double cab = afpChain.getNrEQR() / (double) afpChain.getCa1Length();
090                writer.append(String.valueOf(cab)).append("");
091                writer.append(newline);
092
093                writer.append("cba (coverage b): ");
094                double cba = afpChain.getNrEQR() / (double) afpChain.getCa2Length();
095                writer.append(String.valueOf(cba)).append("");
096                writer.append(newline);
097
098                writer.append("seq similarity: ");
099                writer.append(String.valueOf(afpChain.getSimilarity())).append("");
100                writer.append(newline);
101
102                writer.append("TM-score: ");
103                writer.append(String.valueOf(afpChain.getTMScore())).append("");
104                writer.append(newline);
105
106                return writer.toString();
107        }
108
109        /**
110         * Output in FatCatCore format
111         *
112         * <p>Note that if a circular permutation has occured the residue numbers may
113         * be innaccurate.
114         *
115         * @param afpChain
116         * @param ca1
117         * @param ca2
118         * @param printLegend
119         * @param longHeader
120         * @param showHTML
121         * @param showAlignmentBlock
122         * @return
123         */
124        public static String toFatCatCore(
125                        AFPChain afpChain,
126                        Atom[] ca1,
127                        Atom[] ca2,
128                        boolean printLegend, boolean longHeader, boolean showHTML, boolean showAlignmentBlock){
129
130                //TODO The sequence numbers are inaccurate if a !afpChain.isSequential()
131
132                String name1 = afpChain.getName1();
133                String name2 = afpChain.getName2();
134                int ca1Length = afpChain.getCa1Length();
135                int ca2Length = afpChain.getCa2Length();
136
137                int blockNum = afpChain.getBlockNum();
138                int totalLenIni = afpChain.getTotalLenIni();
139                double totalRmsdIni = afpChain.getTotalRmsdIni();
140                int optLength = afpChain.getOptLength();
141                double totalRmsdOpt = afpChain.getTotalRmsdOpt();
142                double chainRmsd = afpChain.getChainRmsd();
143                double alignScore = afpChain.getAlignScore();
144                int alnLength = afpChain.getAlnLength();
145                int gapLen = afpChain.getGapLen();
146                List<AFP> afpSet = afpChain.getAfpSet();
147
148                double similarity = afpChain.getSimilarity();
149                double identity = afpChain.getIdentity();
150
151                if (similarity <0  || identity < 0){
152                        afpChain.calcSimilarity();
153                        similarity = afpChain.getSimilarity();
154                        identity = afpChain.getIdentity();
155                }
156
157
158
159                String algorithmName = afpChain.getAlgorithmName();
160                //String version = afpChain.getVersion();
161
162                double probability = afpChain.getProbability();
163
164
165                int afpNum = afpSet.size();
166
167                int[] blockGap = afpChain.getBlockGap();
168
169
170                double[] blockScore = afpChain.getBlockScore();
171                double[] blockRmsd = afpChain.getBlockRmsd();
172                int[] blockSize = afpChain.getBlockSize();
173
174
175                int alnbeg1 = afpChain.getAlnbeg1();
176                int alnbeg2 = afpChain.getAlnbeg2();
177
178                char[] alnseq1 = afpChain.getAlnseq1();
179                char[] alnseq2 = afpChain.getAlnseq2();
180                char[] alnsymb = afpChain.getAlnsymb();
181
182                // == end of extractation of data values from afpChain
183                ////////////////////////////////
184
185                StringBuffer txt = new StringBuffer();
186
187                if ( longHeader) {
188                        txt.append(String.format("Align %s.pdb %d with %s.pdb %d", name1, ca1Length, name2, ca2Length));
189                }
190                else {
191                        txt.append(String.format("Align %s.pdb Length1: %d with %s.pdb Length2: %d", name1, ca1Length, name2, ca2Length));
192                }
193                txt.append(newline);
194                if ( afpChain.isShortAlign()){
195                        txt.append("Short match");
196                        return txt.toString();
197                }
198                //txt.append(String.format("raw-score: %.2f norm.-score: %.2f ", alignScore, normAlignScore));
199
200                if ( longHeader ) {
201                        txt.append(String.format( "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%%)",
202                                        blockNum - 1, totalLenIni, totalRmsdIni, optLength, totalRmsdOpt, chainRmsd, alignScore,
203                                        alnLength, gapLen, (100.0 * gapLen/alnLength)) );
204                        txt.append(newline);
205
206                }  else {
207
208                        if ( ! longHeader)
209                                printScore(txt,algorithmName,probability,longHeader);
210
211                        printScoresInLines(afpChain, blockNum, optLength, totalRmsdOpt, alignScore, alnLength, gapLen, identity, similarity,txt);
212                }
213
214
215                //txt.append(String.format("P-value %.2e Afp-num %d Identity %.2f%% Similarity %.2f%% norm.-score: %.2f"+newline, probability, afpNum, identity * 100, similarity * 100, normAlignScore));
216
217                if ( longHeader) {
218                        printScore(txt,algorithmName,probability,longHeader);
219
220                        txt.append(String.format("Afp-num %d Identity %.2f%% Similarity %.2f%%", afpNum, identity * 100, similarity * 100));
221                        txt.append(newline);
222                }
223
224                int i;
225                double gap;
226
227                if ( longHeader ){
228                        int fragLen = 8 ; // FatCatParameters.DEFAULT_FRAGLEN;
229                        for(i = 0; i < blockNum; i ++)  {
230                                gap = blockGap[i] /( (double)blockGap[i] + fragLen * blockSize[i]);
231                                txt.append(String.format( "Block %2d afp %2d score %5.2f rmsd %5.2f gap %d (%.2f%%)",
232                                                i, blockSize[i], blockScore[i], blockRmsd[i], blockGap[i], gap));
233                                txt.append(newline);
234                        }
235                }
236
237                int     linelen = 70;
238                String a;
239                String b;
240                String c;
241
242
243                int     t = 0;
244                int     ap = alnbeg1;
245                int     bp = alnbeg2;
246                int     k, len;
247
248                //System.out.println(alnseq1.length + " " + alnseq1.toString());
249
250                while((alnLength - t) > 0)      {
251                        if(alnLength - t > linelen)     len = linelen;
252                        else    len = alnLength - t;
253
254                        if ( ap >= ca1.length)
255                                break;
256                        if ( bp >= ca2.length)
257                                break;
258
259                        String pdb1 = ca1[ap].getGroup().getResidueNumber().toString();
260                        String pdb2 = ca2[bp].getGroup().getResidueNumber().toString();
261
262
263                        //System.err.println("t,len:"+t+":"+len);
264                        String lseq1 = new String(alnseq1).substring(t,t+len);
265                        String lseq2 = new String(alnseq2).substring(t,t+len);
266                        String lsymb = new String(alnsymb).substring(t,t+len);
267
268                        //System.err.println("B:" + b);
269
270
271                        // check conservation and color accordingly, if requested by user.
272                        if ( showHTML ) {
273                                a = "";
274                                b = "";
275                                c = "";
276
277                                //      <span class=\"m\">|</span> ... Structurally equivalent and identical residues
278                                //  <span class=\"sm\">:</span> ... Structurally equivalent and similar residues
279                                //  <span class=\"qg\">.</span> ... Structurally equivalent, but not similar residues.
280
281                                for (int pos = 0 ; pos < lseq1.length() ; pos ++){
282                                        char c1 = lseq1.charAt(pos);
283                                        char c2 = lseq2.charAt(pos);
284                                        char cl = lsymb.charAt(pos);
285                                        int block = -1 ;
286                                        if ( cl != ' ') {
287                                                try {
288                                                        block = Integer.parseInt(cl+"");
289                                                } catch (Exception e){
290                                                        //
291                                                }
292                                        }
293                                        if ( cl != ' ' ){
294
295                                                if ( showAlignmentBlock && block > -1 ) {
296                                                        a += "<span class=\"alignmentBlock1"+block+"\">" + c1 + "</span>";
297                                                        b += "<span class=\"alignmentBlock2"+block+"\">" + c2 + "</span>";
298                                                        c += "<span class=\"m\">" + cl + "</span>";
299                                                } else {
300                                                        a += getPrefix(c1, c2, 0, block, false).toString() + c1 + "</span>";
301                                                        b += getPrefix(c1, c2, 1, block, false).toString() + c2 + "</span>";
302                                                        c += "<span class=\"m\">" + cl + "</span>";
303                                                }
304
305                                        } else if ( c1 != '-' && c2 != '-') {
306
307                                                a += "<span class=\"sm\">" + c1 + "</span>";
308                                                b += "<span class=\"sm\">" + c2 + "</span>";
309                                                c += "<span class=\"sm\">" + cl + "</span>";
310
311
312                                        } else {
313
314                                                a += "<span class=\"qg\">" + c1 + "</span>";
315                                                b += "<span class=\"qg\">" + c2 + "</span>";
316                                                c += "<span class=\"qg\">" + cl + "</span>";
317
318                                        }
319
320                                        if(c1 != '-') ap ++;
321                                        if(c2 != '-') bp ++;
322                                }
323
324
325                        } else {
326
327                                a = lseq1;
328                                b = lseq2;
329                                c = lsymb;
330                        }
331
332                        txt.append(newline);
333                        if ( longHeader )
334                                txt.append(String.format("%14s", " "));
335                        else
336                                txt.append(String.format("%14s", " "));
337
338                        if (  longHeader ) {
339                                for(k = 10; k <= len; k += 10)
340                                        txt.append("    .    :");
341                                if(k <= len + 5) txt.append("    .");
342
343                        } else {
344
345                                for(k = 10; k <= len; k += 10)
346                                        txt.append("----+----|");
347                                if(k <= len + 5) txt.append("----+");
348
349
350                        }
351
352
353
354                        txt.append(newline);
355                        txt.append(String.format("Chain 1:%5s %s"+newline +"%14s%s"+newline+"Chain 2:%5s %s",
356                                        pdb1, a, " ", c, pdb2, b));
357
358                        txt.append(newline);
359
360                        if ( ! showHTML){
361                                for(k = 0; k < len; k ++)       {
362                                        if(a.charAt(k) != '-') ap ++;
363                                        if(b.charAt(k) != '-') bp ++;
364                                }
365                        }
366                        t += len;
367
368
369
370                }
371                txt.append(newline);
372                if ( printLegend ){
373                        if ( algorithmName.equalsIgnoreCase(CeMain.algorithmName) ||
374                                        algorithmName.equalsIgnoreCase(SmithWaterman3Daligner.algorithmName)){
375                                txt.append("Note: positions are from PDB; | means alignment of identical amino acids, : of similar amino acids ");
376
377                        } else {
378                                txt.append("Note: positions are from PDB; the numbers between alignments are block index");
379                        }
380                        txt.append(newline);
381
382                }
383                return txt.toString();
384
385        }
386
387        private static void printScoresInLines(AFPChain afpChain, int blockNum, int optLength, double totalRmsdOpt, double alignScore,
388                        int alnLength, int gapLen, double identity, double similarity, StringBuffer txt)
389        {
390                if ( blockNum - 1 > 0) {
391                        txt.append(String.format( "Twists %d ", blockNum -1 ));
392                        txt.append(newline);
393                }
394
395                txt.append(String.format("Equ: %d ", optLength));
396                txt.append(newline);
397                txt.append(String.format("RMSD: %.2f ", totalRmsdOpt));
398                txt.append(newline);
399                txt.append(String.format("Score: %.2f ", alignScore));
400                txt.append(newline);
401                txt.append(String.format("Align-len: %d ", alnLength));
402                txt.append(newline);
403                txt.append(String.format("Gaps: %d (%.2f%%)",
404                                gapLen, (100.0 * gapLen/alnLength)) );
405                txt.append(newline);
406                if ( afpChain.getTMScore() >= 0) {
407                        txt.append(String.format("TM-score: %.2f",afpChain.getTMScore()));
408                        txt.append(newline);
409                }
410                txt.append(newline);
411                txt.append(String.format("Identity: %.2f%% ", identity * 100 ));
412                txt.append(newline);
413                txt.append(String.format("Similarity: %.2f%%", similarity * 100));
414                txt.append(newline);
415        }
416
417        private static void printScore(StringBuffer txt,
418                        String algorithmName,
419                        double probability,
420                        boolean longHeader)
421        {
422                if ( algorithmName.equalsIgnoreCase(CeMain.algorithmName) || algorithmName.equalsIgnoreCase(CeSideChainMain.algorithmName) ){
423                        txt.append(String.format("Z-score %.2f ", probability));
424                        if ( ! longHeader)
425                                txt.append(newline);
426                } else if ( algorithmName.equalsIgnoreCase(SmithWaterman3Daligner.algorithmName)) {
427
428                } else {
429                        if ( longHeader ){
430                                txt.append(String.format("P-value %.2e ",probability));
431                        }  else {
432                                txt.append(String.format("P-value: %.2e ",probability));
433                                txt.append(newline);
434                        }
435                }
436
437
438
439        }
440
441        /**
442         * Prints the afpChain as a nicely formatted alignment, including alignment
443         * statistics, the aligned sequences themselves, and information about the
444         * superposition.
445         * @param afpChain
446         * @param ca1
447         * @param ca2
448         * @return a String representation as it is used on the RCSB PDB web site for display.
449         */
450        public static String toWebSiteDisplay(AFPChain afpChain, Atom[] ca1, Atom[] ca2 ){
451                boolean showAlignmentBlock   = true;
452                return toWebSiteDisplay(afpChain, ca1, ca2, showAlignmentBlock);
453        }
454
455        /**
456         * Prints the afpChain as a nicely formatted alignment, including alignment
457         * statistics, the aligned sequences themselves, and information about the
458         * superposition.
459         * @param afpChain
460         * @param ca1
461         * @param ca2
462         *
463         * @return a String representation as it is used on the RCSB PDB web site for display.
464         */
465        public static String toWebSiteDisplay(AFPChain afpChain, Atom[] ca1, Atom[] ca2, boolean showAlignmentBlock){
466
467                boolean printLegend = true;
468                boolean longHeader  = true;
469                boolean showHTML = true;
470
471                if ( afpChain.getAlgorithmName().equalsIgnoreCase(FatCatFlexible.algorithmName)) {
472
473
474                        String msg =  toFatCatCore(afpChain,ca1,ca2,printLegend,longHeader,showHTML, showAlignmentBlock);
475
476                        return msg;
477                }
478
479                boolean showSeq = true;
480
481                AFPAlignmentDisplay.getAlign(afpChain, ca1, ca2, showSeq);
482
483
484                //      String msg= toFatCatCore(afpChain,ca1,ca2, printLegend,longHeader);
485                //
486
487
488                String msg = toPrettyAlignment(afpChain, ca1, ca2, showHTML, showAlignmentBlock);
489
490
491                msg = msg + newline +
492                "     <span class=\"m\">|</span> ... Structurally equivalent and identical residues " + newline +
493                "     <span class=\"sm\">:</span> ... Structurally equivalent and similar residues " + newline +
494                "     <span class=\"qg\">.</span> ... Structurally equivalent, but not similar residues. " + newline;
495
496                msg += newline;
497                msg += "     To calculate the coordinates of chain 2 aligned on chain 1 apply the following transformation: ";
498                msg += newline;
499                msg += newline;
500                msg += toRotMat(afpChain);
501                return msg;
502
503
504        }
505
506
507
508        private 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().getChainID());
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().getChainID());
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.getChainID() ;
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("%.2f",afpChain.getAlignScore()));
1070                str.append("\t");
1071                if ( afpChain.getAlgorithmName().equalsIgnoreCase(CeMain.algorithmName)){
1072                        str.append(String.format("%.2f",afpChain.getProbability()));
1073                } else {
1074                        str.append(String.format("%.2e",afpChain.getProbability()));
1075                }
1076                str.append("\t");
1077                str.append(String.format("%.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("%.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 = (blockNr)+"";
1121
1122
1123                        txt.append(String.format("     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("     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("     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
1137
1138                String name1 = afpChain.getName1();
1139                String name2 = afpChain.getName2();
1140
1141                int optLength = afpChain.getOptLength();
1142                double totalRmsdOpt = afpChain.getTotalRmsdOpt();
1143
1144                int alnLength = afpChain.getAlnLength();
1145                int gapLen = afpChain.getGapLen();
1146
1147
1148                double similarity = afpChain.getSimilarity();
1149                double identity = afpChain.getIdentity();
1150                if (similarity <0 || identity <0  ){
1151                        afpChain.calcSimilarity();
1152                        similarity = afpChain.getSimilarity();
1153                        identity = afpChain.getIdentity();
1154                }
1155
1156
1157
1158                double probability = afpChain.getProbability();
1159
1160
1161                int alnbeg1 = afpChain.getAlnbeg1();
1162                int alnbeg2 = afpChain.getAlnbeg2();
1163
1164                char[] alnseq1 = afpChain.getAlnseq1();
1165                char[] alnseq2 = afpChain.getAlnseq2();
1166
1167
1168                long calculationTime = afpChain.getCalculationTime();
1169
1170                // == end of extractation of data values from afpChain
1171
1172
1173
1174                StringBuffer txt = new StringBuffer();
1175
1176                txt.append("Chain 1: ");
1177                txt.append(name1);
1178                txt.append(" (Size=");
1179                txt.append(ca1.length);
1180                txt.append(")");
1181                txt.append(newline);
1182                txt.append("Chain 2: ");
1183                txt.append(name2);
1184                txt.append(" (Size=");
1185                txt.append(ca2.length);
1186                txt.append(")");
1187                txt.append(newline);
1188                txt.append(newline);
1189                txt.append(String.format("Alignment length = %d Rmsd = %.2fA Z-Score = %.1f",optLength,totalRmsdOpt,probability));
1190                txt.append(String.format(" Gaps = %d(%.1f%%) CPU = %d ms. Sequence identities = %.1f%%",gapLen,( gapLen*100.0/optLength),calculationTime,identity*100));
1191
1192                int     linelen = 70;
1193                String a;
1194                String b;
1195
1196
1197
1198                int     t = 0;
1199                int     ap = alnbeg1;
1200                int     bp = alnbeg2;
1201                int     k, len;
1202
1203                while((alnLength - t) > 0)      {
1204                        if(alnLength - t > linelen)     len = linelen;
1205                        else    len = alnLength - t;
1206
1207
1208                        //System.err.println("t,len:"+t+":"+len);
1209                        a = new String(alnseq1).substring(t,t+len);
1210                        b = new String(alnseq2).substring(t,t+len);
1211
1212                        //System.err.println("B:" + b);
1213
1214                        /*
1215                        txt.append(newline);
1216                        txt.append(String.format("%14s", " "));
1217
1218                        for(k = 10; k <= len; k += 10)
1219                                txt.append("    .    :");
1220                        if(k <= len + 5) txt.append("    .");
1221                         */
1222
1223                        //String pdb1 = ca1[ap].getParent().getPDBCode();
1224                        //String pdb2 = ca2[bp].getParent().getPDBCode();
1225                        txt.append(newline);
1226                        txt.append(String.format("Chain 1:%5s %s"+newline+"Chain 2:%5s %s",
1227                                        (ap+1), a, (bp+1), b));
1228                        txt.append(newline);
1229                        for(k = 0; k < len; k ++)       {
1230                                if(a.charAt(k) != '-') ap ++;
1231                                if(b.charAt(k) != '-') bp ++;
1232                        }
1233                        t += len;
1234
1235                }
1236                txt.append(newline);
1237
1238                txt.append(toRotMat(afpChain));
1239
1240                return txt.toString();
1241
1242
1243        }
1244
1245
1246
1247
1248
1249
1250}