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 */
021package org.biojava.nbio.structure.cluster;
022
023import java.util.ArrayList;
024import java.util.List;
025
026import org.biojava.nbio.core.exceptions.CompoundNotFoundException;
027import org.biojava.nbio.structure.Structure;
028import org.biojava.nbio.structure.StructureException;
029import org.biojava.nbio.structure.symmetry.core.Stoichiometry;
030import org.slf4j.Logger;
031import org.slf4j.LoggerFactory;
032
033/**
034 * The SubunitClusterer takes as input a collection of {@link Subunit} and
035 * returns a collection of {@link SubunitCluster}.
036 * 
037 * @author Aleix Lafita
038 * @since 5.0.0
039 * 
040 */
041public class SubunitClusterer {
042
043        private static final Logger logger = LoggerFactory
044                        .getLogger(SubunitClusterer.class);
045
046        /** Prevent instantiation **/
047        private SubunitClusterer() {
048        }
049
050        public static Stoichiometry cluster(Structure structure,
051                        SubunitClustererParameters params) {
052                List<Subunit> subunits = SubunitExtractor.extractSubunits(structure,
053                                params.getAbsoluteMinimumSequenceLength(),
054                                params.getMinimumSequenceLengthFraction(),
055                                params.getMinimumSequenceLength());
056                return cluster(subunits, params);
057        }
058
059        public static Stoichiometry cluster(List<Subunit> subunits,
060                        SubunitClustererParameters params) {
061
062                // The collection of clusters to return
063                List<SubunitCluster> clusters = new ArrayList<SubunitCluster>();
064
065                if (subunits.size() == 0)
066                        return new Stoichiometry(clusters);
067
068                // First generate a new cluster for each Subunit
069                for (Subunit s : subunits)
070                        clusters.add(new SubunitCluster(s));
071
072                if (params.getClustererMethod() == SubunitClustererMethod.SEQUENCE ||
073                                params.getClustererMethod() == SubunitClustererMethod.SEQUENCE_STRUCTURE) {
074                        // Now merge clusters by SEQUENCE
075                        for (int c1 = 0; c1 < clusters.size(); c1++) {
076                                for (int c2 = clusters.size() - 1; c2 > c1; c2--) {
077                                        try {
078                                                if (clusters.get(c1).mergeSequence(clusters.get(c2), params)) {
079                                                        clusters.remove(c2);
080                                                }
081
082                                        } catch (CompoundNotFoundException e) {
083                                                logger.warn("Could not merge by Sequence. {}",
084                                                                e.getMessage());
085                                        }
086                                }
087                        }
088                }
089
090                if (params.getClustererMethod() == SubunitClustererMethod.STRUCTURE ||
091                                params.getClustererMethod() == SubunitClustererMethod.SEQUENCE_STRUCTURE) {
092                        // Now merge clusters by STRUCTURE
093                        for (int c1 = 0; c1 < clusters.size(); c1++) {
094                                for (int c2 = clusters.size() - 1; c2 > c1; c2--) {
095                                        try {
096                                                if (clusters.get(c1).mergeStructure(clusters.get(c2), params)) {
097                                                        clusters.remove(c2);
098                                                }
099                                        } catch (StructureException e) {
100                                                logger.warn("Could not merge by Structure. {}", e.getMessage());
101                                        }
102                                }
103                        }
104                }
105
106                if (params.isInternalSymmetry()) {
107                        // Now divide clusters by their INTERNAL SYMMETRY
108                        for (int c = 0; c < clusters.size(); c++) {
109                                try {
110                                        clusters.get(c).divideInternally(params);
111                                } catch (StructureException e) {
112                                        logger.warn("Error analyzing internal symmetry. {}",
113                                                        e.getMessage());
114                                }
115                        }
116
117                        // After internal symmetry merge again by structural similarity
118                        // Use case: C8 propeller with 3 chains with 3+3+2 repeats each
119                        for (int c1 = 0; c1 < clusters.size(); c1++) {
120                                for (int c2 = clusters.size() - 1; c2 > c1; c2--) {
121                                        try {
122                                                if (clusters.get(c1).mergeStructure(clusters.get(c2), params))
123                                                        clusters.remove(c2);
124                                        } catch (StructureException e) {
125                                                logger.warn("Could not merge by Structure. {}",
126                                                                e.getMessage());
127                                        }
128                                }
129                        }
130                }
131
132                return new Stoichiometry(clusters);
133        }
134}