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 2013-05-23
021 *
022 */
023package org.biojava.nbio.structure.symmetry.core;
024
025import org.biojava.nbio.structure.Structure;
026import org.biojava.nbio.structure.cluster.Subunit;
027import org.biojava.nbio.structure.cluster.SubunitCluster;
028
029import java.util.ArrayList;
030import java.util.Collections;
031import java.util.List;
032
033/**
034 * Holds the results of quaternary symmetry perception obtained with
035 * {@link QuatSymmetryDetector}.
036 *
037 * @author Peter Rose
038 * @author Aleix Lafita
039 *
040 */
041public class QuatSymmetryResults {
042
043        // Optional: the query Structure, if any
044        private Structure structure;
045
046        // Information about the clustering process
047        private Stoichiometry stoichiometry;
048        private boolean local = false;
049
050        // Cached properties
051        private List<SubunitCluster> clusters;
052        private List<Subunit> subunits;
053
054        // Information about the symmetry
055        private SymmetryPerceptionMethod method;
056        private HelixLayers helixLayers;
057        private RotationGroup rotationGroup = new RotationGroup();
058
059        // TODO we should unify rotational and roto-translational results
060
061        /**
062         * Constructor for rotational symmetries.
063         *
064         * @param stoichiometry
065         *            Stoichiometry used to calculate symmetry
066         * @param rotationGroup
067         * @param method
068         */
069        public QuatSymmetryResults(Stoichiometry stoichiometry,
070                        RotationGroup rotationGroup, SymmetryPerceptionMethod method) {
071
072                this.stoichiometry = stoichiometry;
073                this.clusters = stoichiometry.getClusters();
074
075                subunits = new ArrayList<Subunit>();
076                for (SubunitCluster c : clusters) {
077                        subunits.addAll(c.getSubunits());
078                }
079
080                this.rotationGroup = rotationGroup;
081                this.method = method;
082        }
083
084        /**
085         * Constructor for roto-translational symmetries.
086         *
087         * @param stoichiometry
088         *            Stoichiometry used to calculate symmetry
089         * @param helixLayers
090         * @param method
091         */
092        public QuatSymmetryResults(Stoichiometry stoichiometry,
093                        HelixLayers helixLayers, SymmetryPerceptionMethod method) {
094
095                this.stoichiometry = stoichiometry;
096                this.clusters = stoichiometry.getClusters();
097
098                subunits = new ArrayList<Subunit>();
099                for (SubunitCluster c : clusters) {
100                        subunits.addAll(c.getSubunits());
101                }
102
103                this.helixLayers = helixLayers;
104                this.method = method;
105        }
106
107        /**
108         * Determine if this symmetry result is a subset of the other Symmetry result.
109         * Checks the following conditions:
110         * - 'Other' includes all subunits of 'this'.
111         * - 'Other' has the same or higher order than 'this'.
112         *
113         * Special treatment for the helical symmetry:
114         * - 'Other' includes all subunits of 'this'.
115         * - 'this' may be Cn, as well as H
116         *
117         *  Note that isSupersededBy establishes a partial order, i.e. for some
118         *  symmetries A and B, neither A.isSupersededBy(B) nor B.isSupersededBy(A)
119         *  may be true.
120         *
121         * @param other
122         *            QuatSymmetryResults
123         *
124         * @return true if other supersedes this, false otherwise
125         */
126
127        public boolean isSupersededBy(QuatSymmetryResults other) {
128                if(other.getSymmetry().startsWith("H")) {
129                        if(this.getSymmetry().startsWith("C") || this.getSymmetry().startsWith("H")) {
130                                if (other.subunits.containsAll(this.subunits)) {
131                                        return true;
132                                }
133                        }
134                        return false;
135                }
136
137                if (this.getSymmetry().startsWith("H")) {
138                        return false;
139                }
140
141                if (this.rotationGroup.getOrder() <= other.rotationGroup.getOrder() &&
142                                other.subunits.containsAll(this.subunits)) {
143                        return true;
144                }
145                return false;
146        }
147
148        /**
149         * Returns the List of SubunitCluster used to calculate symmetry.
150         *
151         * @return an unmodifiable view of the original List
152         */
153        public List<SubunitCluster> getSubunitClusters() {
154                return Collections.unmodifiableList(clusters);
155        }
156
157        /**
158         * Returns the List of Subunits used to calculate symmetry.
159         *
160         * @return an unmodifiable view of the List
161         */
162        public List<Subunit> getSubunits() {
163                return Collections.unmodifiableList(subunits);
164        }
165
166        /**
167         * Return the number of Subunits involved in the symmetry.
168         *
169         * @return the number of Subunits
170         */
171        public int getSubunitCount() {
172                return subunits.size();
173        }
174
175        /**
176         * @return rotation group (point group) information representing rotational
177         *         quaternary symmetry.
178         */
179        public RotationGroup getRotationGroup() {
180                return rotationGroup;
181        }
182
183        /**
184         * @return helix layers (layer lines) as a list of helices that describe a
185         *         helical structure.
186         */
187        public HelixLayers getHelixLayers() {
188                return helixLayers;
189        }
190
191        /**
192         * @return the method used for symmetry perception.
193         */
194        public SymmetryPerceptionMethod getMethod() {
195                return method;
196        }
197
198        /**
199         * @return the symmetry group symbol. For point groups returns the point
200         *         group symbol and for helical symmetry returns "H".
201         */
202        public String getSymmetry() {
203                if (helixLayers != null && helixLayers.size() > 0) {
204                        return "H";
205                } else if (rotationGroup != null && rotationGroup.getOrder() > 0) {
206                        return rotationGroup.getPointGroup();
207                }
208                return "";
209        }
210
211        /**
212         * @return the quaternary scores as an object
213         */
214        public QuatSymmetryScores getScores() {
215                if (helixLayers != null && helixLayers.size() > 0) {
216                        return helixLayers.getScores();
217                } else if (rotationGroup != null && rotationGroup.getOrder() > 0) {
218                        return rotationGroup.getScores();
219                }
220                return new QuatSymmetryScores();
221        }
222
223        public Stoichiometry getStoichiometry() {
224                return stoichiometry;
225        }
226
227        public boolean isPseudoStoichiometric() {
228                return stoichiometry.isPseudoStoichiometric();
229        }
230
231        /**
232         * A local result means that only a subset of the original Subunits was used
233         * for symmetry determination.
234         *
235         * @return true if local result, false otherwise
236         */
237        public boolean isLocal() {
238                return local;
239        }
240
241        /**
242         * A local result means that only a subset of the original Subunits was used
243         * for symmetry determination.
244         *
245         * @param local
246         *            true if local result, false otherwise
247         */
248        void setLocal(boolean local) {
249                this.local = local;
250        }
251
252        public Structure getStructure() {
253                return structure;
254        }
255
256        public void setStructure(Structure structure) {
257                this.structure = structure;
258        }
259
260        @Override
261        public String toString() {
262                return "QuatSymmetryResults [stoichiometry: " + getStoichiometry()
263                                + ", symmetry: " + getSymmetry() + ", pseudo-stoichiometric: "
264                                + isPseudoStoichiometric() + ", local: " + local + ", method: "
265                                + method + "]";
266        }
267
268}