JAL-1517 source formatting
[jalview.git] / src / jalview / analysis / Rna.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
3  * Copyright (C) 2014 The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 /* Author: Lauren Michelle Lui 
22  * Methods are based on RALEE methods http://personalpages.manchester.ac.uk/staff/sam.griffiths-jones/software/ralee/
23  * Additional Author: Jan Engelhart (2011) - Structure consensus and bug fixing
24  * Additional Author: Anne Menard (2012) - Pseudoknot support and secondary structure consensus
25  * */
26
27 package jalview.analysis;
28
29 import java.util.ArrayList;
30 import java.util.Arrays;
31 import java.util.HashSet;
32 import java.util.Hashtable;
33 import java.util.Stack;
34 import java.util.Vector;
35
36 import jalview.analysis.SecStrConsensus.SimpleBP;
37 import jalview.datamodel.SequenceFeature;
38
39 public class Rna
40 {
41
42   static Hashtable<Integer, Integer> pairHash = new Hashtable();
43
44   private static final Character[] openingPars =
45   { '(', '[', '{', '<', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
46       'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
47       'Y', 'Z' };
48
49   private static final Character[] closingPars =
50   { ')', ']', '}', '>', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
51       'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
52       'y', 'z' };
53
54   private static HashSet<Character> openingParsSet = new HashSet<Character>(
55           Arrays.asList(openingPars));
56
57   private static HashSet<Character> closingParsSet = new HashSet<Character>(
58           Arrays.asList(closingPars));
59
60   private static Hashtable<Character, Character> closingToOpening = new Hashtable<Character, Character>()
61   // Initializing final data structure
62   {
63     private static final long serialVersionUID = 1L;
64     {
65       for (int i = 0; i < openingPars.length; i++)
66       {
67         System.out.println(closingPars[i] + "->" + openingPars[i]);
68         put(closingPars[i], openingPars[i]);
69       }
70     }
71   };
72
73   private static boolean isOpeningParenthesis(char c)
74   {
75     return openingParsSet.contains(c);
76   }
77
78   private static boolean isClosingParenthesis(char c)
79   {
80     return closingParsSet.contains(c);
81   }
82
83   private static char matchingOpeningParenthesis(char closingParenthesis)
84           throws WUSSParseException
85   {
86     if (!isClosingParenthesis(closingParenthesis))
87     {
88       throw new WUSSParseException(
89               "Querying matching opening parenthesis for non-closing parenthesis character "
90                       + closingParenthesis, -1);
91     }
92
93     return closingToOpening.get(closingParenthesis);
94   }
95
96   /**
97    * Based off of RALEE code ralee-get-base-pairs. Keeps track of open bracket
98    * positions in "stack" vector. When a close bracket is reached, pair this
99    * with the last element in the "stack" vector and store in "pairs" vector.
100    * Remove last element in the "stack" vector. Continue in this manner until
101    * the whole string is processed.
102    * 
103    * @param line
104    *          Secondary structure line of an RNA Stockholm file
105    * @return Array of SequenceFeature; type = RNA helix, begin is open base
106    *         pair, end is close base pair
107    */
108   public static Vector<SimpleBP> GetSimpleBPs(CharSequence line)
109           throws WUSSParseException
110   {
111     System.out.println(line);
112     Hashtable<Character, Stack<Integer>> stacks = new Hashtable<Character, Stack<Integer>>();
113     Vector<SimpleBP> pairs = new Vector<SimpleBP>();
114     int i = 0;
115     while (i < line.length())
116     {
117       char base = line.charAt(i);
118
119       if (isOpeningParenthesis(base))
120       {
121         if (!stacks.containsKey(base))
122         {
123           stacks.put(base, new Stack<Integer>());
124         }
125         stacks.get(base).push(i);
126
127       }
128       else if (isClosingParenthesis(base))
129       {
130
131         char opening = matchingOpeningParenthesis(base);
132
133         if (!stacks.containsKey(opening))
134         {
135           throw new WUSSParseException(
136                   "Mismatched (unseen) closing character " + base, i);
137         }
138
139         Stack<Integer> stack = stacks.get(opening);
140         if (stack.isEmpty())
141         {
142           // error whilst parsing i'th position. pass back
143           throw new WUSSParseException("Mismatched closing character "
144                   + base, i);
145         }
146         int temp = stack.pop();
147
148         pairs.add(new SimpleBP(temp, i));
149       }
150       i++;
151     }
152     for (char opening : stacks.keySet())
153     {
154       Stack<Integer> stack = stacks.get(opening);
155       if (!stack.empty())
156       {
157         throw new WUSSParseException("Mismatched opening character "
158                 + opening + " at " + stack.pop(), i);
159       }
160     }
161     return pairs;
162   }
163
164   public static SequenceFeature[] GetBasePairs(CharSequence line)
165           throws WUSSParseException
166   {
167     Vector<SimpleBP> bps = GetSimpleBPs(line);
168     SequenceFeature[] outPairs = new SequenceFeature[bps.size()];
169     for (int p = 0; p < bps.size(); p++)
170     {
171       SimpleBP bp = bps.elementAt(p);
172       outPairs[p] = new SequenceFeature("RNA helix", "", "", bp.getBP5(),
173               bp.getBP3(), "");
174     }
175     return outPairs;
176   }
177
178   public static ArrayList<SimpleBP> GetModeleBP(CharSequence line)
179           throws WUSSParseException
180   {
181     Vector<SimpleBP> bps = GetSimpleBPs(line);
182     return new ArrayList<SimpleBP>(bps);
183   }
184
185   /**
186    * Function to get the end position corresponding to a given start position
187    * 
188    * @param indice
189    *          - start position of a base pair
190    * @return - end position of a base pair
191    */
192   /*
193    * makes no sense at the moment :( public int findEnd(int indice){ //TODO:
194    * Probably extend this to find the start to a given end? //could be done by
195    * putting everything twice to the hash ArrayList<Integer> pair = new
196    * ArrayList<Integer>(); return pairHash.get(indice); }
197    */
198
199   /**
200    * Figures out which helix each position belongs to and stores the helix
201    * number in the 'featureGroup' member of a SequenceFeature Based off of RALEE
202    * code ralee-helix-map.
203    * 
204    * @param pairs
205    *          Array of SequenceFeature (output from Rna.GetBasePairs)
206    */
207   public static void HelixMap(SequenceFeature[] pairs)
208   {
209
210     int helix = 0; // Number of helices/current helix
211     int lastopen = 0; // Position of last open bracket reviewed
212     int lastclose = 9999999; // Position of last close bracket reviewed
213     int i = pairs.length; // Number of pairs
214
215     int open; // Position of an open bracket under review
216     int close; // Position of a close bracket under review
217     int j; // Counter
218
219     Hashtable helices = new Hashtable(); // Keep track of helix number for each
220                                          // position
221
222     // Go through each base pair and assign positions a helix
223     for (i = 0; i < pairs.length; i++)
224     {
225
226       open = pairs[i].getBegin();
227       close = pairs[i].getEnd();
228
229       // System.out.println("open " + open + " close " + close);
230       // System.out.println("lastclose " + lastclose + " lastopen " + lastopen);
231
232       // we're moving from right to left based on closing pair
233       /*
234        * catch things like <<..>>..<<..>> |
235        */
236       if (open > lastclose)
237       {
238         helix++;
239       }
240
241       /*
242        * catch things like <<..<<..>>..<<..>>>> |
243        */
244       j = pairs.length - 1;
245       while (j >= 0)
246       {
247         int popen = pairs[j].getBegin();
248
249         // System.out.println("j " + j + " popen " + popen + " lastopen "
250         // +lastopen + " open " + open);
251         if ((popen < lastopen) && (popen > open))
252         {
253           if (helices.containsValue(popen)
254                   && (((Integer) helices.get(popen)) == helix))
255           {
256             continue;
257           }
258           else
259           {
260             helix++;
261             break;
262           }
263         }
264
265         j -= 1;
266       }
267
268       // Put positions and helix information into the hashtable
269       helices.put(open, helix);
270       helices.put(close, helix);
271
272       // Record helix as featuregroup
273       pairs[i].setFeatureGroup(Integer.toString(helix));
274
275       lastopen = open;
276       lastclose = close;
277
278     }
279   }
280 }