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 */
021
022package org.biojava.nbio.structure.symmetry.core;
023
024import java.util.ArrayList;
025import java.util.List;
026
027/**
028 *
029 * @author Peter
030 */
031public class HelixLayers {
032        private List<Helix> helices = new ArrayList<Helix>();
033        private double symmetryDeviation = 0;
034
035        public int size() {
036                return helices.size();
037        }
038
039        public void addHelix(Helix helix) {
040                helices.add(helix);
041        }
042
043        public Helix getHelix(int index) {
044                return helices.get(index);
045        }
046
047        /*
048         * Returns Helix with lowest twist angle
049         */
050        public Helix getByLowestAngle() {
051                double angle = Double.MAX_VALUE;
052                Helix lowest = null;
053                for (Helix helix: helices) {
054                        if (helix.getAngle() < angle) {
055                                angle = helix.getAngle();
056                                lowest = helix;
057                        }
058                }
059                return lowest;
060        }
061
062        /*
063         * Returns Helix with largest number of intermolecular contacts
064         * between repeat units
065         */
066        public Helix getByLargestContacts() {
067                double contacts = 0;
068                Helix largest = null;
069                for (Helix helix: helices) {
070                        if (helix.getContacts() > contacts) {
071                                contacts = helix.getContacts();
072                                largest = helix;
073                        }
074                }
075                return largest;
076        }
077
078        /*
079         * Returns Helix that has the largest number of contacts, besides
080         * the Helix with the lowest twist angle
081         */
082        public Helix getByLargestContactsNotLowestAngle() {
083                double contacts = 0;
084                Helix lowest = getByLowestAngle();
085                // TODO why are there helices with almost identical helix parameters??
086                double angle = lowest.getAngle() + 0.05;
087                Helix largest = null;
088                for (Helix helix: helices) {
089                        if (helix == lowest) {
090                                continue;
091                        }
092                        if (helix.getContacts() > contacts && helix.getAngle() > angle) {
093                                contacts = helix.getContacts();
094                                largest = helix;
095                        }
096                }
097                if (largest == null) {
098                        return lowest;
099                }
100                return largest;
101        }
102
103        /**
104         * Returns QuatSymmetryScores averaged over all rotations
105         * (except the first rotation, which is the unit operation E)
106         * @return mean scores average over rotations
107         */
108        public QuatSymmetryScores getScores() {
109                QuatSymmetryScores scores = new QuatSymmetryScores();
110
111                double[] values = new double[helices.size()];
112
113                // minRmsd
114                for (int i = 0; i < helices.size(); i++) {
115                        values[i] = helices.get(i).getScores().getMinRmsd();
116                }
117                scores.setMinRmsd(minScores(values));
118
119                // maxRmsd
120                for (int i = 0; i < helices.size(); i++) {
121                        values[i] = helices.get(i).getScores().getMaxRmsd();
122                }
123                scores.setMaxRmsd(maxScores(values));
124
125                // Rmsd
126                for (int i = 0; i < helices.size(); i++) {
127                        values[i] = helices.get(i).getScores().getRmsd();
128                }
129                scores.setRmsd(averageScores(values));
130
131                // minTm
132                for (int i = 0; i < helices.size(); i++) {
133                        values[i] = helices.get(i).getScores().getMinTm();
134                }
135                scores.setMinTm(minScores(values));
136
137                // maxTm
138                for (int i = 0; i < helices.size(); i++) {
139                        values[i] = helices.get(i).getScores().getMaxTm();
140                }
141                scores.setMaxTm(maxScores(values));
142
143                // Tm
144                for (int i = 0; i < helices.size(); i++) {
145                        values[i] = helices.get(i).getScores().getTm();
146                }
147                scores.setTm(averageScores(values));
148
149                // Rmsd subunit centers
150                for (int i = 0; i < helices.size(); i++) {
151                        values[i] = helices.get(i).getScores().getRmsdCenters();
152                }
153                scores.setRmsdCenters(averageScores(values));
154
155                // TmIntra
156                for (int i = 0; i < helices.size(); i++) {
157                        values[i] = helices.get(i).getScores().getTmIntra();
158                }
159                scores.setTmIntra(averageScores(values));
160
161                // RmsdIntra
162                for (int i = 0; i < helices.size(); i++) {
163                        values[i] = helices.get(i).getScores().getRmsdIntra();
164                }
165                scores.setRmsdIntra(averageScores(values));
166
167                // SymDeviation
168                scores.setSymDeviation(symmetryDeviation);
169
170                return scores;
171        }
172
173        /**
174         * @param symmetryDeviation the symmetryDeviation to set
175         */
176        public void setSymmetryDeviation(double symmetryDeviation) {
177                this.symmetryDeviation = symmetryDeviation;
178        }
179
180        private double averageScores(double[] scores) {
181                double sum = 0;
182                for (double s: scores) {
183                        sum += s;
184                }
185                return sum/scores.length;
186        }
187
188        private double minScores(double[] scores) {
189                double score = Double.MAX_VALUE;
190                for (double s: scores) {
191                        score = Math.min(score, s);
192                }
193                return score;
194        }
195
196        private double maxScores(double[] scores) {
197                double score = Double.MIN_VALUE;
198                for (double s: scores) {
199                        score = Math.max(score, s);
200                }
201                return score;
202        }
203
204        public void clear() {
205                helices.clear();
206        }
207
208        @Override
209        public String toString() {
210                StringBuilder sb = new StringBuilder();
211                sb.append("Helices: " + size() + "\n");
212                for (Helix s: helices) {
213                        sb.append(s.toString() + "\n");
214                }
215                return sb.toString();
216        }
217
218
219
220}