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.basepairs;
023
024import org.biojava.nbio.structure.Atom;
025import org.biojava.nbio.structure.Chain;
026import org.biojava.nbio.structure.Group;
027import org.biojava.nbio.structure.Structure;
028import org.biojava.nbio.structure.contact.Pair;
029
030import javax.vecmath.Matrix4d;
031import java.util.ArrayList;
032import java.util.List;
033
034/**
035 * This class also finds the base pairing and base-pair step parameters but has a broader definition
036 * of a base pair so that non-canonical-WC base pairs will be detected and reported.  This is useful
037 * for RNA that has folded into different regions, and for higher-order DNA structures.  Intra-strand
038 * pairings are considered in this class (but in not the base class or MismatchedBasePairParameters class)
039 * @author Luke Czapla
040 * @since 5.0.0
041 *
042 */
043public class TertiaryBasePairParameters extends BasePairParameters {
044
045        private static final long serialVersionUID = 2556427111533466577L;
046
047        public static final double DEFAULT_MAX_STAGGER = 2.0;
048        public static final double DEFAULT_MAX_PROPELLER = 60.0;
049        // These are the criteria used to select proper base pairs.
050        private double maxStagger = DEFAULT_MAX_STAGGER,
051                        maxPropeller = DEFAULT_MAX_PROPELLER;
052
053        public TertiaryBasePairParameters(Structure structure, boolean RNA, boolean removeDups) {
054                super(structure, RNA, removeDups);
055        }
056
057        /**
058         * This is an alternative implementation of findPair() that looks for anything that would fit the
059         * criteria for a base-pair, useful for the context of tertiary structure of RNA.  Intra-strand base pairs
060         * are found with this algorithm.
061         * @param chains The list of chains already found to be nucleic acids
062         * @return A list of the Pair of groups that match the base pair criteria, including intra-strand groups.
063         */
064        @Override
065        public List<Pair<Group>> findPairs(List<Chain> chains) {
066                List<Pair<Group>> result = new ArrayList<>();
067                boolean lastFoundPair = false;
068                for (int i = 0; i < chains.size(); i++) {
069                        Chain c = chains.get(i);
070                        String sequence = c.getAtomSequence();
071                        Integer type1, type2;
072                        for (int j = 0; j < sequence.length(); j++) {
073                                boolean foundPair = false;
074                                for (int k = sequence.length()-1; k >= j + 3 && !foundPair; k--) {
075                                        Group g1 = c.getAtomGroup(j);
076                                        Group g2 = c.getAtomGroup(k);
077                                        type1 = BASE_MAP.get(g1.getPDBName());
078                                        type2 = BASE_MAP.get(g2.getPDBName());
079                                        if (type1 == null || type2 == null) continue;
080                                        Atom a1 = g1.getAtom("C1'");
081                                        Atom a2 = g2.getAtom("C1'");
082                                        if (a1 == null || a2 == null) continue;
083                                        // C1'-C1' distance is one useful criteria
084                                        if (Math.abs(a1.getCoordsAsPoint3d().distance(a2.getCoordsAsPoint3d())-10.0) > 4.0) continue;
085                                        Pair<Group> ga = new Pair<>(g1, g2);
086                                        // TODO is this call needed?? JD 2018-03-07
087                                        @SuppressWarnings("unused")
088                                        Matrix4d data = basePairReferenceFrame(ga);
089                                        // if the stagger is greater than 2 Å, it's not really paired.
090                                        if (Math.abs(pairParameters[5]) > maxStagger) continue;
091                                        // if the propeller is ridiculous it's also not that good of a pair.
092                                        if (Math.abs(pairParameters[1]) > maxPropeller) {
093                                                continue;
094                                        }
095                                        result.add(ga);
096                                        pairingNames.add(useRNA ? BASE_LIST_RNA[type1]+ BASE_LIST_RNA[type2]: BASE_LIST_DNA[type1]+ BASE_LIST_DNA[type2]);
097                                        foundPair = true;
098                                }
099                                if (!foundPair && lastFoundPair) {
100                                        if (pairSequence.length() > 0 && pairSequence.charAt(pairSequence.length()-1) != ' ')
101                                                pairSequence += ' ';
102                                }
103                                if (foundPair) pairSequence += (c.getAtomSequence().charAt(j));
104                                lastFoundPair = foundPair;
105                        }
106                }
107                result.addAll(super.findPairs(chains));
108                return result;
109        }
110
111        /**
112         * This method returns the maximum stagger between bases used as criteria for the characterization of two bases as being paired.
113         * @return the maximum stagger (in Å) allowed.
114         */
115        public double getMaxStagger() {
116                return maxStagger;
117        }
118
119        /**
120         * This method sets the maximum stagger allowed for a base pair, prior to analyze() call
121         * @param maxStagger The maximum stagger (in Å) allowed to consider two bases paired
122         */
123        public void setMaxStagger(double maxStagger) {
124                this.maxStagger = maxStagger;
125        }
126
127        /**
128         * This method returns the maximum propeller twist between bases used as criteria for the characterization of two bases as being paired.
129         * @return the maximum propeller ("propeller-twist", in degrees) allowed.
130         */
131        public double getMaxPropeller() {
132                return maxPropeller;
133        }
134
135        /**
136         * This method sets the maximum propeller allowed for a base pair, prior to analyze() call
137         * @param maxPropeller The maximum propeller ("propeller-twist", in degrees) allowed to consider two bases paired
138         */
139        public void setMaxPropeller(double maxPropeller) {
140                this.maxPropeller = maxPropeller;
141        }
142}