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 Apr 7, 2010
021 * Author: Andreas Prlic
022 *
023 */
024
025package org.biojava.nbio.structure.align.util;
026
027
028import javax.vecmath.Matrix4d;
029
030import org.biojava.nbio.structure.Atom;
031import org.biojava.nbio.structure.Calc;
032import org.biojava.nbio.structure.StructureException;
033import org.biojava.nbio.structure.align.model.AFPChain;
034import org.biojava.nbio.structure.geometry.SuperPositions;
035import org.slf4j.Logger;
036import org.slf4j.LoggerFactory;
037
038public class AFPChainScorer {
039
040        private static final Logger logger = LoggerFactory.getLogger(AFPChainScorer.class);
041
042
043        public  static double getTMScore(AFPChain align, Atom[] ca1, Atom[] ca2) throws StructureException
044        {
045                return getTMScore(align, ca1, ca2, true);
046        }
047
048        public  static double getTMScore(AFPChain align, Atom[] ca1, Atom[] ca2, boolean normalizeMin) throws StructureException
049        {
050                if ( align.getNrEQR() == 0)
051                        return -1;
052
053
054                // Create new arrays for the subset of atoms in the alignment.
055                Atom[] ca1aligned = new Atom[align.getOptLength()];
056                Atom[] ca2aligned = new Atom[align.getOptLength()];
057                int pos=0;
058                int[] blockLens = align.getOptLen();
059                int[][][] optAln = align.getOptAln();
060                assert(align.getBlockNum() <= optAln.length);
061
062                for(int block=0;block< align.getBlockNum();block++) {
063
064                        if ( ! ( blockLens[block] <= optAln[block][0].length)) {
065                                logger.warn("AFPChainScorer getTMScore: errors reconstructing alignment block [" + block + "]. Length is " + blockLens[block] + " but should be <=" + optAln[block][0].length);
066                        }
067
068                        for(int i=0;i<blockLens[block];i++) {
069                                int pos1 = optAln[block][0][i];
070                                int pos2 = optAln[block][1][i];
071                                Atom a1 = ca1[pos1];
072                                Atom a2 = (Atom) ca2[pos2].clone();
073
074                                ca1aligned[pos] = a1;
075                                ca2aligned[pos] = a2;
076                                pos++;
077                        }
078                }
079
080                // this can happen when we load an old XML serialization which did not support modern ChemComp representation of modified residues.
081                if ( pos != align.getOptLength()){
082                        logger.warn("AFPChainScorer getTMScore: Problems reconstructing alignment! nr of loaded atoms is " + pos + " but should be " + align.getOptLength());
083                        // we need to resize the array, because we allocated too many atoms earlier on.
084                        ca1aligned = (Atom[]) resizeArray(ca1aligned, pos);
085                        ca2aligned = (Atom[]) resizeArray(ca2aligned, pos);
086                }
087                //Superimpose
088                Matrix4d trans = SuperPositions.superpose(Calc.atomsToPoints(ca1aligned), 
089                                Calc.atomsToPoints(ca2aligned));
090
091                Calc.transform(ca2aligned, trans);
092
093                return Calc.getTMScore(ca1aligned, ca2aligned, ca1.length, ca2.length, normalizeMin);
094        }
095
096        /**
097         * Reallocates an array with a new size, and copies the contents
098         * of the old array to the new array.
099         * @param oldArray  the old array, to be reallocated.
100         * @param newSize   the new array size.
101         * @return          A new array with the same contents.
102         */
103        private static Object resizeArray (Object oldArray, int newSize) {
104                int oldSize = java.lang.reflect.Array.getLength(oldArray);
105                @SuppressWarnings("rawtypes")
106                Class elementType = oldArray.getClass().getComponentType();
107                Object newArray = java.lang.reflect.Array.newInstance(
108                                elementType,newSize);
109                int preserveLength = Math.min(oldSize,newSize);
110                if (preserveLength > 0)
111                        System.arraycopy (oldArray,0,newArray,0,preserveLength);
112                return newArray; }
113
114}