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 Jan 28, 2006
021 *
022 */
023package org.biojava.nbio.structure.align.pairwise;
024
025
026import org.biojava.nbio.structure.*;
027import org.biojava.nbio.structure.align.StrucAligParameters;
028import org.biojava.nbio.structure.align.helper.AligMatEl;
029import org.biojava.nbio.structure.align.helper.IndexPair;
030import org.biojava.nbio.structure.align.helper.JointFragments;
031import org.biojava.nbio.structure.geometry.Matrices;
032import org.biojava.nbio.structure.geometry.SuperPositions;
033import org.biojava.nbio.structure.jama.Matrix;
034
035import java.io.Serializable;
036import java.text.DecimalFormat;
037import java.util.List;
038import java.util.logging.Logger;
039
040import javax.vecmath.Matrix4d;
041
042/**
043 * Implements a class which handles one possible (alternative) solution.
044 *
045 * Alternative alignments arise from different seed
046 * alignments or seed FPairs. The AltAlg class contains methods
047 * for refinement (Dynamic Programming based) and filtering
048 * (i.e. removing probably wrongly matched APairs). In the refinement
049 * phase, different seed alignments can converge to the same solution.
050 *
051 * @author Andreas Prlic,
052 * @author Peter Lackner (original Python and C code)
053 * @since 3:04:26 PM
054 * @version %I% %G%
055 */
056public class AlternativeAlignment implements Serializable{
057
058
059        /**
060         *
061         */
062        private static final long serialVersionUID = -6226717654562221241L;
063
064        int[] idx1;
065        int[] idx2;
066        String[] pdbresnum1;
067        String[] pdbresnum2;
068        //short[] alig1;
069        //short[] alig2;
070
071        int nfrags;
072        Atom center;
073        Matrix rot;
074        Atom tr;
075
076
077        // the scores...
078        int gaps0;
079        int eqr0;
080        int rms0;
081        int joined;
082        int percId;
083        int cluster;
084        float score;
085        IndexPair[] aligpath;
086        int fromia;
087        Matrix currentRotMatrix;
088        Atom currentTranMatrix;
089
090        double rms;
091
092        Matrix distanceMatrix;
093
094        public static Logger logger =  Logger.getLogger("org.biojava.nbio.structure.align");
095
096
097        public AlternativeAlignment() {
098                super();
099
100                nfrags = 0;
101                aligpath = new IndexPair[0];
102                //alig1 = new short[0];
103                //alig2 = new short[0];
104                idx1 = new int[0];
105                idx2 = new int[0];
106
107                center = new AtomImpl();
108                rot = null;
109                tr = new AtomImpl();
110                eqr0 = -99;
111                rms0 = 99;
112                joined = 0;
113                gaps0 = -99;
114                fromia = 0;
115
116                currentRotMatrix = new Matrix(0,0);
117                currentTranMatrix = new AtomImpl();
118
119                distanceMatrix = new Matrix(0,0);
120        }
121
122
123
124
125        /** print the idx positions of this alignment
126         *
127         * @return a String representation
128         */
129        @Override
130        public String toString(){
131                DecimalFormat d2 = new DecimalFormat();
132                // the result can be localized. To change this and enforce UK local do...
133                //(DecimalFormat)NumberFormat.getInstance(java.util.Locale.UK);
134                d2.setMaximumIntegerDigits(3);
135                d2.setMinimumFractionDigits(2);
136                d2.setMaximumFractionDigits(2);
137                StringBuffer s = new StringBuffer();
138                s.append("#" + getAltAligNumber() +
139                                " cluster:" + cluster +
140                                " eqr:" + getEqr() +
141                                " rmsd:" + d2.format(getRmsd()) +
142                                " %id:" + getPercId() +
143                                " gaps:" + getGaps() +
144                                " score:" + d2.format(score)    );
145
146                return s.toString();
147        }
148
149
150        /** get the number of the cluster this alignment belongs to
151         *
152         * @return an int giving the number of the cluster
153         */
154        public int getCluster() {
155                return cluster;
156        }
157
158
159
160        /** set the number of the cluster this alignment belongs to.
161         * All alignments in a cluster are quite similar.
162         *
163         * @param cluster the number of the cluster
164         */
165        public void setCluster(int cluster) {
166                this.cluster = cluster;
167        }
168
169
170
171
172        public double getRmsd() {
173                return rms;
174        }
175
176        /** the rms in the structurally equivalent regions
177         *
178         * @param rms
179         */
180        public void setRms(double rms) {
181                this.rms = rms;
182        }
183
184        /** the alignment score
185         *
186         * @return the score of this alignment
187         */
188        public float getScore() {
189                return score;
190        }
191
192        public void setScore(float score) {
193                this.score = score;
194        }
195
196
197        /** return the number of gaps in this alignment
198         *
199         * @return the number of Gaps
200         */
201        public int getGaps(){
202                return gaps0;
203        }
204
205        /** returns the number of euqivalent residues in this alignment
206         *
207         * @return the number of equivalent residues
208         */
209        public int getEqr(){
210                return eqr0 ;
211        }
212
213        /** the positions of the structure equivalent positions in atom set 1
214         *
215         * @return the array of the positions
216         */
217        public int[] getIdx1(){
218                return idx1;
219        }
220
221        /** the positions of the structure equivalent atoms in atom set 2
222         *
223         * @return the array of the positions
224         */
225        public int[] getIdx2(){
226                return idx2;
227        }
228
229        public int getPercId() {
230                return percId;
231        }
232
233        public void setPercId(int percId) {
234                this.percId = percId;
235        }
236
237        /** Set apairs according to a seed position.
238         *
239         * @param l
240         * @param i
241         * @param j
242         */
243        public void  apairs_from_seed(int l,int i, int j){
244                aligpath = new IndexPair[l];
245                idx1 = new int[l];
246                idx2 = new int[l];
247                for (int x = 0 ; x < l ; x++) {
248                        idx1[x]=i+x;
249                        idx2[x]=j+x;
250                        aligpath[x] = new IndexPair((short)(i+x),(short)(j+x));
251                }
252        }
253
254        /** Set apairs according to a list of (i,j) tuples.
255         *
256         * @param jf a JoingFragment
257         */
258        public void apairs_from_idxlst(JointFragments jf) {
259                List<int[]> il = jf.getIdxlist();
260                //System.out.println("Alt Alig apairs_from_idxlst");
261
262                aligpath = new IndexPair[il.size()];
263                idx1 = new int[il.size()];
264                idx2 = new int[il.size()];
265                for (int i =0 ; i < il.size();i++) {
266                        int[] p = il.get(i);
267                        //System.out.print(" idx1 " + p[0] + " idx2 " + p[1]);
268                        idx1[i] = p[0];
269                        idx2[i] = p[1];
270                        aligpath[i] = new IndexPair((short)p[0],(short)p[1]);
271
272                }
273                eqr0  = idx1.length;
274                //System.out.println("eqr " + eqr0);
275                gaps0 = count_gaps(idx1,idx2);
276
277        }
278
279
280        /** returns the sequential number of this alternative alignment
281         *
282         * @return the sequential number of this alternative alignment
283         */
284        public int getAltAligNumber() {
285                return fromia;
286        }
287
288        public void setAltAligNumber(int fromia) {
289                this.fromia = fromia;
290        }
291
292        /** rotate and shift atoms with currentRotMatrix and current Tranmatrix
293         *
294         * @param ca
295         */
296        private void rotateShiftAtoms(Atom[] ca){
297
298                for (int i  = 0 ; i < ca.length; i++){
299                        Atom c = ca[i];
300
301                        Calc.rotate(c,currentRotMatrix);
302                        Calc.shift(c,currentTranMatrix);
303                        //System.out.println("after " + c);
304                        ca[i] = c;
305                }
306                //System.out.println("after " + ca[0]);
307        }
308
309        public void finish(StrucAligParameters params,Atom[]ca1,Atom[]ca2) throws StructureException{
310
311                Atom[] ca3 = new Atom[ca2.length];
312                for ( int i = 0 ; i < ca2.length;i++){
313                        ca3[i] = (Atom) ca2[i].clone();
314
315                }
316                // do the inital superpos...
317
318                super_pos_alig(ca1,ca3,idx1,idx2,true);
319                rotateShiftAtoms(ca3);
320
321                calcScores(ca1,ca2);
322                logger.fine("eqr " + eqr0 + " " + gaps0 + " "  +idx1[0] + " " +idx1[1]);
323
324                getPdbRegions(ca1,ca2);
325
326        }
327
328        public static Matrix getDistanceMatrix(Atom[] ca1, Atom[]ca2){
329
330                int r = ca1.length;
331                int c = ca2.length;
332
333                Matrix out = new Matrix(r,c);
334
335                for (int i=0; i<r; i++) {
336                        Atom a1 = ca1[i];
337                        for (int j=0;j<c;j++){
338                                Atom b1 = ca2[j];
339
340
341                                double d = Calc.getDistance(a1,b1);
342                                out.set(i,j,d);
343
344                        }
345                }
346                return out;
347        }
348
349        private Alignable getInitalStrCompAlignment(
350                        Atom[] ca1,
351                        Atom[]ca2,
352                        StrucAligParameters params
353                        ){
354
355                int rows = ca1.length;
356                int cols = ca2.length;
357
358                float gapOpen = params.getGapOpen();
359                float gapExtension = params.getGapExtension();
360                float co = params.getCreate_co();
361
362                Alignable al = new StrCompAlignment(rows,cols);
363                al.setGapExtCol(gapExtension);
364                al.setGapExtRow(gapExtension);
365                al.setGapOpenCol(gapOpen);
366                al.setGapOpenRow(gapOpen);
367
368                AligMatEl[][] aligmat = al.getAligMat();
369
370                //System.out.println(rows + " " + cols );
371
372                aligmat[0][cols]    = new AligMatEl();
373                aligmat[rows][0]    = new AligMatEl();
374                aligmat[rows][cols] = new AligMatEl();
375
376                for (int i = 0; i < rows; i++) {
377                        Atom a1 = ca1[i];
378
379                        aligmat[i][0]    = new AligMatEl();
380                        //aligmat[i][cols] = new AligMatEl();
381
382                        for (int j = 0; j < cols; j++) {
383                                //System.out.println("index " + i + " " + j);
384                                aligmat[0][j] = new AligMatEl();
385
386                                Atom b1 = ca2[j];
387                                double d = 999;
388
389                                d = Calc.getDistance(a1,b1);
390
391
392                                AligMatEl e = new AligMatEl();
393                                if (d > co) {
394                                        e.setValue(0);
395                                } else {
396                                        double s =  2 * co / ( 1 + ( d/co) * (d/co)) - co;
397                                        e.setValue((int) Math.round(Gotoh.ALIGFACTOR * s));
398                                }
399                                aligmat[i+1][j+1] = e;
400                        }
401                }
402
403                return al;
404        }
405
406        /*private Alignable getAlignableFromSimMatrix (Matrix sim,StrucAligParameters params){
407                //System.out.println("align_NPE");
408
409                float gapOpen = params.getGapOpen();
410                float gapExtension = params.getGapExtension();
411
412                int rows = sim.getRowDimension();
413                int cols = sim.getColumnDimension();
414
415                Alignable al = new StrCompAlignment(rows,cols);
416                al.setGapExtCol(gapExtension);
417                al.setGapExtRow(gapExtension);
418                al.setGapOpenCol(gapOpen);
419                al.setGapOpenRow(gapOpen);
420                //System.out.println("size of aligmat: " + rows+1 + " " + cols+1);
421                //AligMatEl[][] aligmat = new AligMatEl[rows+1][cols+1];
422                AligMatEl[][] aligmat = al.getAligMat();
423
424                for (int i = 0; i < rows; i++) {
425                        for (int j = 0; j < cols; j++) {
426
427                                int e=0;
428                                //if ( ( i < rows) &&
429                                //        ( j < cols)) {
430                                //TODO: the ALIGFACTOR calc should be hidden in Gotoh!!
431
432                                e = (int)Math.round(Gotoh.ALIGFACTOR * sim.get(i,j));
433                                //}
434                                //System.out.println(e);
435                                //AligMatEl am = new AligMatEl();
436                                aligmat[i+1][j+1].setValue(e);
437                                //.setValue(e);
438                                //am.setTrack(new IndexPair((short)-99,(short)-99));
439                                //igmat[i+1][j+1] = am;
440
441                        }
442                }
443                //al.setAligMat(aligmat);
444
445
446                return al;
447        }*/
448        /** Refinement procedure based on superposition and dynamic programming.
449         * Performs an iterative refinement. Several methods apply such a procedure,
450         * e.g. CE or ProSup. Here we additionally test for circular permutation,
451         * which are in the same frame of superposition as the optimal alignment.
452         * This feature may be switched off by setting permsize to -1.
453         *
454         * @param params the parameters
455         * @param ca1 atoms of structure 1
456         * @param ca2 atoms of structure 2
457         * @throws StructureException
458         */
459
460        public void refine(StrucAligParameters params,Atom[]ca1,Atom[]ca2) throws StructureException{
461                // System.out.println("refine Alternative Alignment #"+ getAltAligNumber()+" l1:" + ca1.length + " l2:" + ca2.length);
462                //              for ( int i= 0 ; i < idx1.length;i++){
463                //              System.out.println(idx1[i] + " " + idx2[i]);
464                //              }
465
466                // avoid any operations on the original Atoms ...
467                Atom[] ca3 = new Atom[ca2.length];
468                for ( int i = 0 ; i < ca2.length;i++){
469                        ca3[i] = (Atom) ca2[i].clone();
470
471                }
472                //Atom[] ca3 = (Atom[]) ca2.clone();
473
474                // do the inital superpos...
475
476                super_pos_alig(ca1,ca3,idx1,idx2,false);
477
478                //JmolDisplay jmol1 = new JmolDisplay(ca1,ca2,"after first alig " );
479                //jmol1.selectEquiv(idx1,idx2);
480                //int[] jmoltmp1 = idx1;
481                //int[] jmoltmp2 = idx2;
482
483                int lenalt =idx1.length;
484                int lenneu = aligpath.length;
485                //Matrix rmsalt = currentRotMatrix;
486
487
488
489                int ml = Math.max(ca1.length, ca3.length);
490                idx1 = new int[ml];
491                idx2 = new int[ml];
492
493                //int m1l = ca1.length;
494                //int m2l = ca3.length;
495
496                //Matrix sim = new Matrix(ca1.length,ca3.length,0);
497
498                int maxiter = params.getMaxIter();
499                for (int iter = 0 ; iter< maxiter; iter++){
500
501                        float  subscore = 0.0f;
502
503                        rotateShiftAtoms(ca3);
504
505                        // do the dynamic alignment...
506                        Alignable ali = getInitalStrCompAlignment(ca1,ca3, params);
507
508                        new Gotoh(ali);
509
510                        this.score = ali.getScore();
511                        //System.out.println("score " + score);
512                        IndexPair[] path = ali.getPath();
513
514                        int pathsize = ali.getPathSize();
515
516
517                        // now for a superimposable permutation. First we need to check the size and
518                        // position of the quadrant left out by the optimal path
519                        int firsta = path[0].getRow();
520                        int firstb = path[0].getCol();
521                        int lasta  = path[pathsize-1].getRow();
522                        int lastb  = path[pathsize-1].getCol();
523
524                        int quada_beg, quada_end, quadb_beg,quadb_end;
525
526                        if ( firsta == 0){
527                                quada_beg = lasta +1;
528                                quada_end = ca1.length -1;
529                                quadb_beg = 0;
530                                quadb_end = firstb-1;
531                        } else {
532                                quada_beg = 0;
533                                quada_end = firsta-1;
534                                quadb_beg = lastb+1;
535                                quadb_end = ca3.length -1;
536                        }
537
538                        // if the unaligned quadrant is larger than permsize
539                        int permsize = params.getPermutationSize();
540
541                        if ( permsize > 0 &&
542                                        (quada_end - quada_beg >= permsize) &&
543                                        ( quadb_end - quadb_beg >= permsize)) {
544                                AligMatEl[][] aligmat = ali.getAligMat();
545                                Matrix submat = new Matrix(quada_end-quada_beg, quadb_end - quadb_beg) ;
546                                //then we copy the score values of the quadrant into a new matrix
547
548                                //System.out.println(quada_beg + " " + quada_end + " " +quadb_beg+" " + quadb_end);
549                                //System.out.println(sim.getRowDimension() + " " + sim.getColumnDimension());
550                                Atom[] tmp1 = new Atom[quada_end - quada_beg ];
551                                Atom[] tmp2 = new Atom[quadb_end - quadb_beg ];
552
553                                for ( int s = quada_beg; s < quada_end; s++){
554                                        //System.out.println(s + " " +( quada_end-s));
555                                        tmp1[quada_end - s -1] = ca1[s];
556                                        for ( int t = quadb_beg; t < quadb_end; t++){
557                                                if ( s == quada_beg )
558                                                        tmp2[quadb_end - t -1 ] = ca3[t];
559
560                                                //System.out.println(s+" " +t);
561                                                //double val = sim.get(s,t);
562                                                double val = aligmat[s][t].getValue();
563                                                submat.set(s-quada_beg,t-quadb_beg,val);
564                                        }
565                                }
566                                // and perform a dp alignment again. (Note, that we fix the superposition).
567
568                                //Alignable subali = getAlignableFromSimMatrix(submat,params);
569                                Alignable subali = getInitalStrCompAlignment(tmp1, tmp2, params);
570                                subscore = subali.getScore();
571                                //System.out.println("join score" + score + " " + subscore);
572                                this.score = score+subscore;
573
574                                IndexPair[] subpath = subali.getPath();
575                                int subpathsize = subali.getPathSize();
576                                for ( int p=0;p<subpath.length;p++){
577                                        IndexPair sp = subpath[p];
578                                        sp.setRow((short)(sp.getRow()+quada_beg));
579                                        sp.setCol((short)(sp.getCol()+quadb_beg));
580                                }
581
582                                // now we join the two solutions
583                                if ( subpathsize > permsize){
584                                        IndexPair[] wholepath = new IndexPair[pathsize+subpathsize];
585                                        for ( int t=0; t < pathsize; t++){
586                                                wholepath[t] = path[t];
587                                        }
588                                        for ( int t=0 ; t < subpathsize; t++){
589                                                wholepath[t+pathsize] = subpath[t];
590                                        }
591                                        pathsize += subpathsize;
592                                        path = wholepath;
593                                        ali.setPath(path);
594                                        ali.setPathSize(pathsize);
595                                }
596
597                        }
598
599
600                        int j =0 ;
601                        //System.out.println("pathsize,path " + pathsize + " " + path.length);
602
603                        for (int i=0; i < pathsize; i++){
604                                int x = path[i].getRow();
605                                int y = path[i].getCol();
606                                //System.out.println(x+ " " + y);
607                                double d = Calc.getDistance(ca1[x], ca3[y]);
608                                //double d = dismat.get(x,y);
609                                // now we apply the evaluation distance cutoff
610                                if ( d < params.getEvalCutoff()){
611                                        //System.out.println("j:"+j+ " " + x+" " + y + " " + d );
612
613                                        idx1[j] = x;
614                                        idx2[j] = y;
615                                        j+=1;
616                                }
617                        }
618
619                        lenneu = j;
620                        //System.out.println("lenalt,neu:" + lenalt + " " + lenneu);
621
622
623                        int[] tmpidx1 = new int[j];
624                        int[] tmpidx2 = new int[j];
625                        //String idx1str ="idx1: ";
626                        //String idx2str ="idx2: ";
627                        for (int i = 0 ; i<j;i++){
628                                //idx1str += idx1[i]+ " ";
629                                //idx2str += idx2[i]+ " ";
630                                tmpidx1[i] = idx1[i];
631                                tmpidx2[i] = idx2[i];
632                        }
633                        //System.out.println(idx1str);
634                        //System.out.println(idx2str);
635                        //jmol.selectEquiv(idx1,idx2);
636
637                        //if ( j > 0)
638                        //  System.out.println("do new superimpos " + idx1.length + " " + idx2.length + " " + idx1[0] + " " + idx2[0]);
639                        super_pos_alig(ca1,ca3,tmpidx1,tmpidx2,false);
640
641                        this.aligpath = path;
642
643                        if (lenneu == lenalt)
644                                break;
645
646                }
647
648
649
650                idx1 = (int[]) FragmentJoiner.resizeArray(idx1,lenneu);
651                idx2 = (int[]) FragmentJoiner.resizeArray(idx2,lenneu);
652                //              new ... get rms...
653                // now use the original atoms to get the rotmat relative to the original structure...
654                super_pos_alig(ca1,ca2,idx1,idx2,true);
655                eqr0 = idx1.length;
656                gaps0 = count_gaps(idx1,idx2);
657
658                getPdbRegions(ca1,ca2);
659                //System.out.println("eqr " + eqr0 + " aligpath len:"+aligpath.length+ " gaps:" + gaps0 + " score " + score);
660        }
661
662        private void getPdbRegions(Atom[] ca1, Atom[] ca2){
663                pdbresnum1 = new String[idx1.length];
664                pdbresnum2 = new String[idx2.length];
665
666                for (int i =0 ; i < idx1.length;i++){
667                        Atom a1 = ca1[idx1[i]];
668                        Atom a2 = ca2[idx2[i]];
669                        Group p1 = a1.getGroup();
670                        Group p2 = a2.getGroup();
671                        Chain c1 = p1.getChain();
672                        Chain c2 = p2.getChain();
673
674                        String cid1 = c1.getId();
675                        String cid2 = c2.getId();
676
677                        String pdb1 = p1.getResidueNumber().toString();
678                        String pdb2 = p2.getResidueNumber().toString();
679
680
681                        if ( ! cid1.equals(" "))
682                                pdb1 += ":" + cid1;
683
684
685                        if ( ! cid2.equals(" "))
686                                pdb2 += ":" + cid2;
687
688
689                        pdbresnum1[i] = pdb1;
690                        pdbresnum2[i] = pdb2;
691                }
692        }
693
694
695        public String[] getPDBresnum1() {
696                return pdbresnum1;
697        }
698
699
700
701
702        public void setPDBresnum1(String[] pdbresnum1) {
703                this.pdbresnum1 = pdbresnum1;
704        }
705
706
707
708
709        public String[] getPDBresnum2() {
710                return pdbresnum2;
711        }
712
713
714
715
716        public void setPDBresnum2(String[] pdbresnum2) {
717                this.pdbresnum2 = pdbresnum2;
718        }
719
720
721
722
723        /** Count the number of gaps in an alignment represented by idx1,idx2.
724         *
725         * @param idx1
726         * @param idx2
727         * @return the number of gaps in this alignment
728         */
729        private int count_gaps(int[] i1, int[] i2){
730
731                int i0 = i1[0];
732                int j0 = i2[0];
733                int gaps = 0;
734                for (int i =1 ; i<i1.length;i++ ){
735                        if ( Math.abs(i1[i]-i0) != 1 ||
736                                        ( Math.abs(i2[i]-j0) != 1)){
737                                gaps +=1;
738                        }
739                        i0 = i1[i];
740                        j0 = i2[i];
741                }
742
743                return gaps;
744        }
745
746
747
748        public void calculateSuperpositionByIdx(Atom[] ca1, Atom[] ca2)throws StructureException {
749
750                super_pos_alig(ca1,ca2,idx1,idx2,false);
751
752        }
753
754        /** Superimposes two molecules according to residue index list idx1 and idx2.
755         *  Does not change the original coordinates.
756         *  as an internal result the rotation matrix and shift vectors for are set
757         *
758         * @param ca1 Atom set 1
759         * @param ca2 Atom set 2
760         * @param idx1 idx positions in set1
761         * @param idx2 idx positions in set2
762         * @param getRMS a flag if the RMS should be calculated
763         * @throws StructureException
764         */
765
766
767
768        private void super_pos_alig(Atom[]ca1,Atom[]ca2,int[] idx1, int[] idx2, boolean getRMS) throws StructureException{
769
770                //System.out.println("superpos alig ");
771                Atom[] ca1subset = new Atom[idx1.length];
772                Atom[] ca2subset = new Atom[idx2.length];
773
774                for (int i = 0 ; i < idx1.length;i++){
775                        //System.out.println("idx1 "+ idx1[i] + " " + idx2[i]);
776                        int pos1 =  idx1[i];
777                        int pos2 =  idx2[i];
778
779                        ca1subset[i] =  ca1[pos1];
780                        ca2subset[i] = (Atom) ca2[pos2].clone();
781                }
782
783                Matrix4d trans = SuperPositions.superpose(Calc.atomsToPoints(ca1subset), 
784                                Calc.atomsToPoints(ca2subset));
785                this.currentRotMatrix  = Matrices.getRotationJAMA(trans);
786                this.currentTranMatrix = Calc.getTranslationVector(trans);
787                //currentRotMatrix.print(3,3);
788                if ( getRMS) {
789                        rotateShiftAtoms(ca2subset);
790                        this.rms = Calc.rmsd(ca1subset,ca2subset);
791                }
792
793
794        }
795
796
797        /** returns the rotation matrix that needs to be applied to structure 2 to rotate on structure 1
798         *
799         * @return the rotation Matrix
800         */
801        public Matrix getRotationMatrix(){
802                return currentRotMatrix;
803        }
804
805        /** returns the shift vector that has to be applied on structure to to shift on structure one
806         *
807         * @return the shift vector
808         */
809        public Atom getShift(){
810                return currentTranMatrix;
811        }
812
813
814
815        /** calculates  scores for this alignment ( %id )
816         * @param ca1 set of Atoms for molecule 1
817         * @param ca2 set of Atoms for molecule 2
818
819         */
820        public void calcScores(Atom[] ca1, Atom[] ca2){
821                eqr0 = idx1.length;
822                gaps0 = count_gaps(idx1,idx2);
823
824                percId = 0;
825                // calc the % id
826                for (int i=0 ; i< idx1.length; i++){
827                        Atom a1 = ca1[idx1[i]];
828                        Atom a2 = ca2[idx2[i]];
829
830                        Group g1 = a1.getGroup();
831                        Group g2 = a2.getGroup();
832                        if ( g1.getPDBName().equals(g2.getPDBName())){
833                                percId++;
834                        }
835
836                }
837        }
838
839
840
841        /** create an artifical Structure object that contains the two
842         * structures superimposed onto each other. Each structure is in a separate model.
843         * Model 1 is structure 1 and Model 2 is structure 2.
844         *
845         * @param s1 the first structure. its coordinates will not be changed
846         * @param s2 the second structure, it will be cloned and the cloned coordinates will be rotated according to the alignment results.
847         * @return composite structure containing the 2 aligned structures as a models 1 and 2
848         */
849        public Structure getAlignedStructure(Structure s1, Structure s2){
850                // do not change the original coords ..
851                Structure s3 = s2.clone();
852
853                currentRotMatrix.print(3,3);
854
855                Calc.rotate(s3, currentRotMatrix);
856                Calc.shift( s3, currentTranMatrix);
857
858                Structure newpdb = new StructureImpl();
859                newpdb.setPDBCode("Java");
860                newpdb.setName("Aligned with BioJava");
861
862
863                newpdb.addModel(s1.getChains(0));
864                newpdb.addModel(s3.getChains(0));
865
866                return newpdb;
867
868        }
869
870        /** converts the alignment to a PDB file
871         * each of the structures will be represented as a model.
872         *
873         *
874         * @param s1
875         * @param s2
876         * @return a PDB file as a String
877         */
878        public String toPDB(Structure s1, Structure s2){
879
880
881                Structure newpdb = getAlignedStructure(s1, s2);
882
883                return newpdb.toPDB();
884        }
885
886
887
888        /** The distance matrix this alignment is based on
889         *
890         * @return a Matrix object.
891         */
892        public Matrix getDistanceMatrix() {
893                return distanceMatrix;
894        }
895
896
897
898        /** The distance matrix this alignment is based on
899         *
900         * @param distanceMatrix
901         */
902        public void setDistanceMatrix(Matrix distanceMatrix) {
903                this.distanceMatrix = distanceMatrix;
904        }
905
906
907
908
909        public IndexPair[] getPath() {
910                return aligpath;
911        }
912
913
914
915}
916