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(String.valueOf(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        public 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        public static String toPrettyAlignment(AFPChain afpChain, Atom[] ca1, Atom[] ca2, boolean showHTML, boolean showAlignmentBlock) {
507                String name1 = afpChain.getName1();
508                String name2 = afpChain.getName2();
509                int ca1Length = afpChain.getCa1Length();
510                int ca2Length = afpChain.getCa2Length();
511
512                int blockNum = afpChain.getBlockNum();
513
514
515                int optLength = afpChain.getOptLength();
516                double totalRmsdOpt = afpChain.getTotalRmsdOpt();
517
518                double alignScore = afpChain.getAlignScore();
519                int alnLength = afpChain.getAlnLength();
520                int gapLen = afpChain.getGapLen();
521
522
523                double similarity = afpChain.getSimilarity();
524                double identity = afpChain.getIdentity();
525
526                if (similarity <0  || identity < 0){
527                        afpChain.calcSimilarity();
528                        similarity = afpChain.getSimilarity();
529                        identity = afpChain.getIdentity();
530                }
531
532
533                String algorithmName = afpChain.getAlgorithmName();
534                //String version = afpChain.getVersion();
535
536                double probability = afpChain.getProbability();
537
538
539                // == end of extractation of data values from afpChain
540
541                StringBuffer txt = new StringBuffer();
542
543                txt.append(String.format("Align %s.pdb Length1: %d with %s.pdb Length2: %d", name1, ca1Length, name2, ca2Length));
544
545                txt.append(newline);
546
547                if ( afpChain.isShortAlign()){
548                        txt.append("Short match");
549                        return txt.toString();
550                }
551
552                printScore(txt, algorithmName, probability, false);
553                printScoresInLines(afpChain, blockNum, optLength, totalRmsdOpt, alignScore, alnLength, gapLen,identity, similarity, txt);
554                txt.append(newline);
555
556                int[] optLen = afpChain.getOptLen();
557                int[][][] optAln = afpChain.getOptAln();
558
559
560                int i, j,p1, p2;
561
562                int k;
563                int p1b = 0;
564                int p2b = 0;
565
566                int     len = 0;
567                StringWriter alnseq1 = new StringWriter();
568                StringWriter alnseq2 = new StringWriter();
569                StringWriter alnsymb = new StringWriter();
570                StringWriter header1  = new StringWriter();
571                StringWriter footer1  = new StringWriter();
572                StringWriter header2  = new StringWriter();
573                StringWriter footer2  = new StringWriter();
574                StringWriter block    = new StringWriter();
575
576                int aligPos = -1;
577                for(i = 0; i < blockNum; i ++)  {
578
579                        for(j = 0; j < optLen[i]; j ++) {
580
581                                p1 = optAln[i][0][j];
582                                p2 = optAln[i][1][j];
583                                aligPos++;
584
585                                //               System.out.println(p1 + " " + p2 + " " +  footer2.toString());
586
587                                if ( len == 0){
588                                        //the first position of sequence in alignment
589                                        formatStartingText(p1,p2,header1,header2,footer1,footer2,ca1,ca2);
590                                } else {
591                                        // check for gapped region
592                                        int lmax = (p1 - p1b - 1)>(p2 - p2b - 1)?(p1 - p1b - 1):(p2 - p2b - 1);
593                                        for(k = 0; k < lmax; k ++)      {
594
595
596                                                formatGappedRegion(ca1, ca2, txt, p1, p2, k, p1b, p2b, alnseq1, alnseq2, alnsymb, header1, footer1, header2,
597                                                                footer2, block,len, showHTML);
598                                                len++;
599                                                doLenCheck(len,txt,header1,header2,alnseq1,alnsymb,alnseq2,footer1, footer2,block, showHTML)  ;
600                                        }
601                                }
602
603                                // ALIGNED REGION
604                                //           System.out.println(len + " >" + header1.toString() +"< ");
605                                //           System.out.println(len + " >" + header2.toString() +"< ");
606                                //           System.out.println(len + " >" + alnseq1.toString() +"< ");
607                                //           System.out.println(len + " >" + alnsymb.toString() +"< ");
608                                //           System.out.println(len + " >" + alnseq2.toString() +"< ");
609                                //           System.out.println(len + " >" + footer1.toString() +"< ");
610                                formatAlignedRegion(afpChain, ca1, ca2, p1, p2, alnseq1, alnseq2, alnsymb, header1, footer1, header2, footer2, block,len, aligPos, showHTML, showAlignmentBlock);
611                                //            System.out.println(len + " >" + header1.toString() +"< ");
612                                //            System.out.println(len + " >" + header2.toString() +"< ");
613                                //            System.out.println(len + " >" + alnseq1.toString() +"< ");
614                                //            System.out.println(len + " >" + alnsymb.toString() +"< ");
615                                //            System.out.println(len + " >" + alnseq2.toString() +"< ");
616                                //            System.out.println(len + " >" + footer1.toString() +"< ");
617
618                                len++;
619
620                                doLenCheck(len,txt,header1,header2,alnseq1,alnsymb,alnseq2,footer1, footer2,block, showHTML)  ;
621
622                                p1b = p1;
623                                p2b = p2;
624
625                                //header1.append(newline);
626                                //header2.append(newline);
627
628                        }
629
630                }
631
632                alnLength = len;
633
634                doLenCheck(LINELENGTH,txt,header1,header2,alnseq1,alnsymb,alnseq2,footer1, footer2,block, showHTML);
635                return txt.toString();
636        }
637
638        /**
639         * Prints the alignment in the simplest form: a list of aligned residues.
640         * Format is one line per residue pair, tab delimited:
641         * <ul><li>1. PDB number. Includes insertion code</li>
642         * <li>1. Chain.</li>
643         * <li>1. Amino Acid. Three letter code.</li>
644         * <li>2. PDB number.</li>
645         * <li>2. Chain.</li>
646         * <li>2. Amino Acid.</li>
647         * </ul>
648         * example:
649         * <code>152    A       ALA     161S    A       VAL</code>
650         * <p>Note that this format loses information about blocks.
651         * @param afpChain
652         * @param ca1
653         * @param ca2
654         * @return a String representation of the aligned pairs.
655         */
656        public static String toAlignedPairs(AFPChain afpChain, Atom[] ca1, Atom[] ca2) {
657                StringWriter pairs = new StringWriter();
658
659                //Write structure names & PDB codes
660                pairs.append("#Struct1:\t");
661                pairs.append(afpChain.getName1());
662                pairs.append("\n");
663                pairs.append("#Struct2:\t");
664                pairs.append(afpChain.getName2());
665                pairs.append("\n");
666
667                //Write optimally aligned pairs
668                pairs.append("#Num1\tChain1\tAA1\tNum2\tChain2\tAA2\n");
669                int[][][] optAln = afpChain.getOptAln();
670                int[] blockLen = afpChain.getOptLen();
671                for( int block=0;block<afpChain.getBlockNum(); block++) {
672                        for(int i=0;i<blockLen[block];i++) {
673                                Atom atom1 = ca1[ optAln[block][0][i] ];
674                                Atom atom2 = ca2[ optAln[block][1][i] ];
675
676                                pairs.append(atom1.getGroup().getResidueNumber().toString());
677                                pairs.append('\t');
678                                pairs.append(atom1.getGroup().getChain().getName());
679                                pairs.append('\t');
680                                pairs.append(atom1.getGroup().getPDBName());
681                                pairs.append('\t');
682                                pairs.append(atom2.getGroup().getResidueNumber().toString());
683                                pairs.append('\t');
684                                pairs.append(atom2.getGroup().getChain().getName());
685                                pairs.append('\t');
686                                pairs.append(atom2.getGroup().getPDBName());
687                                pairs.append('\n');
688                        }
689                }
690
691                return pairs.toString();
692        }
693
694        private static void formatGappedRegion(Atom[] ca1, Atom[] ca2, StringBuffer txt, int p1, int p2, int k, int p1b, int p2b,
695                        StringWriter alnseq1, StringWriter alnseq2, StringWriter alnsymb, StringWriter header1, StringWriter footer1,
696                        StringWriter header2, StringWriter footer2, StringWriter block, int len, boolean formatHTML)    {
697
698                // DEAL WITH GAPS
699                int tmppos = (p1 - p1b - 1);
700                block.append("g");
701
702                int  pos1=p1b+1+k ;
703                char oneletter1 = ' ';
704                try {
705                        oneletter1 = getOneLetter(ca1[pos1].getGroup());
706                } catch (Exception e){}
707                int pos2=p2b+1+k;
708                char oneletter2 = ' ';
709                try {
710                        oneletter2 = getOneLetter(ca2[pos2].getGroup());
711                } catch (Exception e){}
712
713
714                if(k >= tmppos) {
715                        //alnseq1[len] = '-';
716                        if (  formatHTML){
717                                alnseq1.append("<span class=\"qg\">-</span>");
718                                header1.append(" ");
719                                header2.append(" ");
720
721
722                        } else {
723                                alnseq1.append('-');
724                                header1.append(" ");
725                                header2.append(" ");
726                        }
727
728                }
729                else {
730                        if ( formatHTML){
731                                alnseq1.append(getPrefix(oneletter1,oneletter2,0,-1, false));
732                        }
733                        alnseq1.append(oneletter1);
734                        if (formatHTML){
735                                alnseq1.append("</span>");
736                        }
737                        formatPosition(pos1,ca1, len, header1, header2);
738
739                }
740
741                if(k >= (p2 - p2b - 1)) {
742                        //alnseq2[len] = '-';
743                        if ( formatHTML){
744                                alnseq2.append("<span class=\"qg\">-</span>");
745                                footer1.append(" ");
746                                footer2.append(" ");
747                        } else {
748                                alnseq2.append('-');
749                                footer1.append(" ");
750                                footer2.append(" ");
751                        }
752
753                }
754                else  {
755                        if ( formatHTML){
756                                alnseq2.append(getPrefix(oneletter1,oneletter2,1, -1, false));
757                        }
758                        alnseq2.append(oneletter2);
759                        if (formatHTML){
760                                alnseq2.append("</span>");
761                        }
762                        formatPosition(pos2, ca2, len, footer1, footer2);
763
764                }
765                //alnsymb[len ++] = ' ';
766                alnsymb.append(' ');
767
768        }
769
770
771
772        private static CharSequence getPrefix(char oneletter1, char oneletter2,
773                        int i, int blockNr, boolean showAlignmentBlock) {
774
775                if ( oneletter1 == '-' || oneletter2 == '-' ) {
776                        // a gap in the alignment.
777                        // label as mismatch
778                        return "<span class=\"qg\">";
779                }
780
781                // an aligned position
782
783                if ( showAlignmentBlock && blockNr > -1){
784                        return "<span class=\"alignmentBlock"+(i+1)+(blockNr+1)+"\">";
785                }
786
787                // we return the "default" sequence alignment view...
788
789                if ( oneletter1 == oneletter2)
790                        return "<span class=\"m\">";
791
792                double score = AFPAlignmentDisplay.aaScore(oneletter1,oneletter2);
793                if ( score > 0 )
794                        return "<span class=\"sm\">";
795
796                // not similar
797                return "<span class=\"qg\">";
798        }
799
800        private static void formatPosition(int pos1, Atom[] ca, int len, StringWriter header1, StringWriter header2)
801        {
802                int linePos = len % LINELENGTH;
803
804                if ( header1.getBuffer().length() < linePos) {
805                        // fill up the buffer, we are probably shortly after the start...
806                        for ( int i = header1.getBuffer().length() ; i< linePos ; i++){
807                                header1.append(" ");
808                        }
809                }
810
811
812
813                Atom a = ca[pos1];
814                Group g = a.getGroup();
815
816                ResidueNumber residueNumber = g.getResidueNumber();
817                pos1 = residueNumber.getSeqNum();
818                boolean hasInsertionCode = false;
819                if ( residueNumber.getInsCode() != null) {
820                        hasInsertionCode = true;
821                }
822
823                if ( (pos1 %10  == 0) && ( ! hasInsertionCode)) {
824                        CharSequence display = getPDBPos(a);
825
826                        boolean ignoreH1 = false;
827
828                        // make sure we don't have a problem with the left boundary...
829                        if ( header1.getBuffer().length()-1 > linePos) {
830                                ignoreH1 = true;
831                                //System.out.println("Ignore h1: " + len + " " + header1.getBuffer().length() + " linePos: " + linePos +"  >" + header1.toString() +"<");
832                        }
833                        //System.out.println(len + " p1:" + tmp + " = " + pos1 + " " + " " + display + " " + ignoreH1);
834                        if ( ! ignoreH1) {
835                                header1.append(String.format("%-13s",display ));
836                                header2.append("|");
837                        } else {
838                                header2.append("|");
839                        }
840
841                } else if ( hasInsertionCode){
842                        Character insCode = g.getResidueNumber().getInsCode();
843                        if ( insCode != null)
844                                header2.append(insCode);
845                        else {
846                                header2.append("!");
847                        }
848                } else if ( ((pos1) %5 ) == 0 && len > 5) {
849                        header2.append(".");
850                } else {
851                        if ( len > 0)
852                                header2.append(" ");
853                }
854
855        }
856
857
858
859        private static void formatAlignedRegion(AFPChain afpChain, Atom[] ca1, Atom[] ca2, int p1, int p2,
860                        StringWriter alnseq1, StringWriter alnseq2,
861                        StringWriter alnsymb, StringWriter header1, StringWriter footer1, StringWriter header2,
862                        StringWriter footer2, StringWriter block, int len, int aligPos,
863                        boolean showHTML, boolean showAlignmentBlock)
864        {
865                char c1;
866                char c2;
867                if (( p1 < ca1.length) && (p2< ca2.length)){
868                        c1=  getOneLetter(ca1[p1].getGroup());
869                        c2 =  getOneLetter(ca2[p2].getGroup());
870                } else {
871                        c1 = 'X';
872                        c2 = 'X';
873                }
874
875                int blockPos = -1;
876                if ( afpChain.getBlockNum() > 0) {
877                        blockPos = AFPAlignmentDisplay.getBlockNrForAlignPos(afpChain, aligPos);
878                }
879
880
881
882                double score = AFPAlignmentDisplay.aaScore(c1,c2);
883
884                if ( showHTML) {
885                        alnseq1.append(getPrefix(c1,c2,  0, blockPos, showAlignmentBlock));
886                        alnseq2.append(getPrefix(c1,c2,  1, blockPos, showAlignmentBlock));
887                }
888
889                alnseq1.append(c1);
890                alnseq2.append(c2);
891
892                if ( showHTML){
893                        alnseq1.append("</span>");
894                        alnseq2.append("</span>");
895                }
896
897                if ( c1 == c2){
898                        if ( showHTML){
899
900                                alnsymb.append("<span class=\"m\">|</span>");
901
902                        } else {
903                                alnsymb.append('|');
904                        }
905                        //alnsymb[len ++] = '|';
906                } else {
907
908
909                        if ( score > 1) {
910                                if ( showHTML){
911                                        alnsymb.append( "<span class=\"sm\">:</span>");
912                                } else {
913                                        alnsymb.append( ':');
914                                }
915                        }
916                        else {
917                                if ( showHTML)
918                                        alnsymb.append( "<span class=\"qg\">.</span>");
919                                else
920                                        alnsymb.append( '.');
921                        }
922                }
923
924                if ( p1 < ca1.length)
925                        formatPosition(p1, ca1,len, header1, header2);
926
927                if ( p2 < ca2.length)
928                        formatPosition(p2,ca2,len, footer1, footer2);
929
930        }
931
932        private static void formatStartingText(int p1, int p2, StringWriter header1, StringWriter header2, StringWriter footer1,
933                        StringWriter footer2, Atom[] ca1, Atom[] ca2)
934        {
935
936                header1.append(String.format("%-13s", getPDBPos(ca1[p1])));
937                header2.append("|");
938                footer1.append(String.format("%-13s", getPDBPos(ca2[p2])));
939                footer2.append("|");
940
941
942        }
943
944        private static boolean doLenCheck(int len, StringBuffer txt, StringWriter header1, StringWriter header2, StringWriter alnseq1,
945                        StringWriter alnsymb, StringWriter alnseq2, StringWriter footer1, StringWriter footer2, StringWriter block, boolean formatHTML)
946        {
947
948                if ( len % LINELENGTH  == 0) {
949
950                        //txt.append("|");
951                        txt.append(header1);
952                        //txt.append("|");
953                        txt.append(newline);
954                        //txt.append("|");
955                        txt.append(header2);
956                        //txt.append("|");
957                        txt.append(newline);
958                        //txt.append("|");
959                        txt.append(alnseq1);
960                        //txt.append("|");
961                        txt.append(newline);
962
963                        //txt.append("|");
964                        txt.append(alnsymb);
965                        //         txt.append(newline);
966                        //         txt.append(block);
967                        //txt.append("|");
968                        txt.append(newline);
969                        //txt.append("|");
970                        txt.append(alnseq2);
971                        //txt.append("|");
972                        txt.append(newline);
973                        //txt.append("|");
974                        txt.append(footer2);
975                        //txt.append("|");
976                        txt.append(newline);
977                        //txt.append("|");
978                        txt.append(footer1);
979                        //txt.append("|");
980                        txt.append(newline);
981                        txt.append(newline);
982                        txt.append(newline);
983
984                        if (formatHTML ) {
985
986                                int len1 = alnseq1.getBuffer().length();
987                                int len2 = alnseq2.getBuffer().length();
988                                int lens = alnsymb.getBuffer().length();
989                                alnseq1.getBuffer().replace(0, len1, "");
990                                alnseq2.getBuffer().replace(0, len2, "");
991                                alnsymb.getBuffer().replace(0, lens, "");
992
993
994
995                                header1.getBuffer().replace(0, LINELENGTH, "");
996                                header2.getBuffer().replace(0, LINELENGTH , "");
997                                footer1.getBuffer().replace(0, LINELENGTH, "");
998                                footer2.getBuffer().replace(0, LINELENGTH, "");
999                                block.getBuffer().replace(0, LINELENGTH, "");
1000                        } else {
1001                                alnseq1.getBuffer().replace(0, LINELENGTH, "");
1002                                alnseq2.getBuffer().replace(0, LINELENGTH, "");
1003                                alnsymb.getBuffer().replace(0, LINELENGTH, "");
1004                                header1.getBuffer().replace(0, LINELENGTH, "");
1005                                header2.getBuffer().replace(0, LINELENGTH , "");
1006                                footer1.getBuffer().replace(0, LINELENGTH, "");
1007                                footer2.getBuffer().replace(0, LINELENGTH, "");
1008                                block.getBuffer().replace(0, LINELENGTH, "");
1009                        }
1010                        StringBuffer buf = header1.getBuffer();
1011                        for ( int i=0;i<buf.length();i++){
1012                                char c = buf.charAt(i);
1013                                if ( c != ' '){
1014                                        buf.setCharAt(i, ' ');
1015                                }
1016                        }
1017                        buf = footer1.getBuffer();
1018                        for ( int i=0;i<buf.length();i++){
1019                                char c = buf.charAt(i);
1020                                if ( c != ' '){
1021                                        buf.setCharAt(i, ' ');
1022                                }
1023                        }
1024
1025                        return true;
1026                }
1027
1028                return false;
1029
1030
1031        }
1032
1033        private static CharSequence getPDBPos(Atom atom)
1034        {
1035
1036                Group g = atom.getGroup();
1037                if ( g!= null){
1038                        Chain c = g.getChain();
1039                        if (c != null){
1040                                return g.getResidueNumber().toString()+":" + c.getName() ;
1041                                //return g.getPDBCode()+":" + c.getName() + "." + getOneLetter(g) ;
1042                        }
1043                }
1044                return "!";
1045        }
1046
1047        private static char getOneLetter(Group g){
1048
1049
1050                if (g==null) return StructureTools.UNKNOWN_GROUP_LABEL;
1051
1052
1053                return StructureTools.get1LetterCode(g.getPDBName());
1054
1055
1056        }
1057
1058
1059        public static String toDBSearchResult(AFPChain afpChain)
1060        {
1061                StringBuffer str = new StringBuffer();
1062
1063                str.append(afpChain.getName1());
1064                str.append("\t");
1065                str.append(afpChain.getName2());
1066                str.append("\t");
1067                str.append(String.format("%.2f",afpChain.getAlignScore()));
1068                str.append("\t");
1069                if ( afpChain.getAlgorithmName().equalsIgnoreCase(CeMain.algorithmName)){
1070                        str.append(String.format("%.2f",afpChain.getProbability()));
1071                } else {
1072                        str.append(String.format("%.2e",afpChain.getProbability()));
1073                }
1074                str.append("\t");
1075                str.append(String.format("%.2f",afpChain.getTotalRmsdOpt()));
1076                str.append("\t");
1077                str.append(afpChain.getCa1Length());
1078                str.append("\t");
1079                str.append(afpChain.getCa2Length());
1080                str.append("\t");
1081                str.append(afpChain.getCoverage1());
1082                str.append("\t");
1083                str.append(afpChain.getCoverage2());
1084                str.append("\t");
1085                str.append(String.format("%.2f",afpChain.getIdentity()));
1086                str.append("\t");
1087                str.append(afpChain.getDescription2());
1088                str.append("\t");
1089                str.append(newline);
1090
1091                return str.toString();
1092        }
1093
1094        public static String toRotMat(AFPChain afpChain)
1095        {
1096
1097                Matrix[] blockRotationMatrix = afpChain.getBlockRotationMatrix();
1098                int blockNum = afpChain.getBlockNum();
1099                Atom[] blockShiftVector = afpChain.getBlockShiftVector();
1100
1101                StringBuffer txt = new StringBuffer();
1102
1103                if ( blockRotationMatrix == null || blockRotationMatrix.length < 1)
1104                        return "";
1105
1106
1107                for ( int blockNr = 0 ; blockNr < blockNum  ; blockNr++){
1108                        Matrix m = blockRotationMatrix[blockNr];
1109                        Atom shift   = blockShiftVector[blockNr];
1110                        if ( blockNum > 1) {
1111                                txt.append("Operations for block " );
1112                                txt.append(blockNr);
1113                                txt.append(newline);
1114                        }
1115
1116                        String origString = "orig";
1117                        if ( blockNr > 0)
1118                                origString = String.valueOf(blockNr);
1119
1120
1121                        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()));
1122                        txt.append( newline);
1123                        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()));
1124                        txt.append( newline);
1125                        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()));
1126                        txt.append(newline);
1127                }
1128                return txt.toString();
1129        }
1130
1131        public static String toCE(AFPChain afpChain, Atom[] ca1, Atom[] ca2)
1132        {
1133
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
1146                double similarity = afpChain.getSimilarity();
1147                double identity = afpChain.getIdentity();
1148                if (similarity <0 || identity <0  ){
1149                        afpChain.calcSimilarity();
1150                        similarity = afpChain.getSimilarity();
1151                        identity = afpChain.getIdentity();
1152                }
1153
1154
1155
1156                double probability = afpChain.getProbability();
1157
1158
1159                int alnbeg1 = afpChain.getAlnbeg1();
1160                int alnbeg2 = afpChain.getAlnbeg2();
1161
1162                char[] alnseq1 = afpChain.getAlnseq1();
1163                char[] alnseq2 = afpChain.getAlnseq2();
1164
1165
1166                long calculationTime = afpChain.getCalculationTime();
1167
1168                // == end of extractation of data values from afpChain
1169
1170
1171
1172                StringBuffer txt = new StringBuffer();
1173
1174                txt.append("Chain 1: ");
1175                txt.append(name1);
1176                txt.append(" (Size=");
1177                txt.append(ca1.length);
1178                txt.append(")");
1179                txt.append(newline);
1180                txt.append("Chain 2: ");
1181                txt.append(name2);
1182                txt.append(" (Size=");
1183                txt.append(ca2.length);
1184                txt.append(")");
1185                txt.append(newline);
1186                txt.append(newline);
1187                txt.append(String.format("Alignment length = %d Rmsd = %.2fA Z-Score = %.1f",optLength,totalRmsdOpt,probability));
1188                txt.append(String.format(" Gaps = %d(%.1f%%) CPU = %d ms. Sequence identities = %.1f%%",gapLen,( gapLen*100.0/optLength),calculationTime,identity*100));
1189
1190                int     linelen = 70;
1191                String a;
1192                String b;
1193
1194
1195
1196                int     t = 0;
1197                int     ap = alnbeg1;
1198                int     bp = alnbeg2;
1199                int     k, len;
1200
1201                while((alnLength - t) > 0)      {
1202                        if(alnLength - t > linelen)     len = linelen;
1203                        else    len = alnLength - t;
1204
1205
1206                        //System.err.println("t,len:"+t+":"+len);
1207                        a = new String(alnseq1).substring(t,t+len);
1208                        b = new String(alnseq2).substring(t,t+len);
1209
1210                        //System.err.println("B:" + b);
1211
1212                        /*
1213                        txt.append(newline);
1214                        txt.append(String.format("%14s", " "));
1215
1216                        for(k = 10; k <= len; k += 10)
1217                                txt.append("    .    :");
1218                        if(k <= len + 5) txt.append("    .");
1219                         */
1220
1221                        //String pdb1 = ca1[ap].getParent().getPDBCode();
1222                        //String pdb2 = ca2[bp].getParent().getPDBCode();
1223                        txt.append(newline);
1224                        txt.append(String.format("Chain 1:%5s %s"+newline+"Chain 2:%5s %s",
1225                                        (ap+1), a, (bp+1), b));
1226                        txt.append(newline);
1227                        for(k = 0; k < len; k ++)       {
1228                                if(a.charAt(k) != '-') ap ++;
1229                                if(b.charAt(k) != '-') bp ++;
1230                        }
1231                        t += len;
1232
1233                }
1234                txt.append(newline);
1235
1236                txt.append(toRotMat(afpChain));
1237
1238                return txt.toString();
1239
1240
1241        }
1242
1243
1244
1245
1246
1247
1248}