520c87454d3acf7e8e526fa35d5a41b5fe8638dc
[jalview.git] / src / jalview / util / HMMProbabilityDistributionAnalyser.java
1 package jalview.util;
2
3 import jalview.datamodel.HiddenMarkovModel;
4 import jalview.datamodel.SequenceI;
5 import jalview.io.DataSourceType;
6 import jalview.io.FileParse;
7 import jalview.io.HMMFile;
8 import jalview.io.StockholmFile;
9 import jalview.schemes.ResidueProperties;
10
11 import java.io.BufferedReader;
12 import java.io.File;
13 import java.io.FileNotFoundException;
14 import java.io.FileOutputStream;
15 import java.io.FileReader;
16 import java.io.IOException;
17 import java.io.InputStreamReader;
18 import java.io.PrintWriter;
19 import java.util.ArrayList;
20 import java.util.HashMap;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Random;
24 import java.util.Scanner;
25 import java.util.Vector;
26
27 /**
28  * Processes probability data. The file indexes used in this program represent
29  * the index of the location of a family or hmm in their respective files,
30  * starting from 0.
31  * 
32  * @author TZVanaalten
33  *
34  */
35 public class HMMProbabilityDistributionAnalyser
36 {
37
38   Vector<SequenceI> sequences;
39
40   HiddenMarkovModel hmm;
41
42   // contains the raw data produced
43   List<ArrayList<Double>> raw = new ArrayList<>();
44
45   // contains binned data
46   Map<String, Double> binned = new HashMap<>();
47
48   // location of the family file
49   String families = "H:/Desktop/PFAM/Family/SeedFamilies.seed";
50
51   // location of the file containing the family-clan links
52   final static String FAMILIESTOCLAN = "H:/Desktop/PFAM/Family/Clanlinks.dat";
53
54   // location of the HMM file
55   String hmms = "H:/Desktop/PFAM/HMMs/Pfam-A.hmm";
56
57   // suffix for raw file
58   final static String RAW = "/Raw.csv";
59
60   // suffix for binned file
61   final static String BINNED = "/Binned.csv";
62
63   // normalisation scale
64   final static double SCALE = 1;
65
66   // current position in file
67   int currentFilePosition = 0;
68
69   final static String NL = "\n";
70
71   Random generator = new Random();
72
73   // current directory
74   String currentFolder;
75
76   boolean keepRaw = false;
77
78   /**
79    * Sets the working directory.
80    * 
81    * @param path
82    */
83   public void setFolder(String path)
84   {
85     currentFolder = path;
86   }
87
88   /**
89    * Moves a buffered reader forward in the file by a certain amount of entries.
90    * Each entry in the file is delimited by '//'.
91    * 
92    * @param index
93    *          The index of the location in the file.
94    * @param br
95    * @throws IOException
96    */
97   public void moveLocationBy(int index, BufferedReader br)
98           throws IOException
99   {
100     for (int i = 0; i < index; i++)
101     {
102       String line = br.readLine();
103       while (!"//".equals(line))
104       {
105         line = br.readLine();
106       }
107     }
108
109   }
110   
111   /**
112    * Analyses a specified number of families and then saves the data. Before
113    * analysing the data, the previous saved data will be imported and after
114    * analysing this, the data is exported back into the file.
115    * 
116    * @param increments
117    *          The number of families to read before saving.
118    * @throws IOException
119    */
120   public void run(int increments, boolean keepRawData) throws IOException
121   {
122     keepRaw = keepRawData;
123     try
124     {
125       readPreviousData(currentFolder);
126       BufferedReader posReader = new BufferedReader(
127               new FileReader(currentFolder + "/CurrentPosition.txt"));
128
129       String line = posReader.readLine();
130       posReader.close();
131       currentFilePosition = Integer.parseInt(line);
132     } catch (Exception e)
133     {
134       System.out.println("No previous data found");
135     }
136
137
138
139     BufferedReader inputSTO = new BufferedReader(new FileReader(families));
140     BufferedReader inputHMM = new BufferedReader(new FileReader(hmms));
141
142
143
144     moveLocationBy(currentFilePosition, inputHMM);
145     moveLocationBy(currentFilePosition, inputSTO);
146
147     int filesRead = 0;
148     int i = 0;
149     while (filesRead < increments)
150     {
151
152       readStockholm(inputSTO);
153
154       readHMM(inputHMM);
155
156         int count = countValidResidues();
157         processData(count);
158         filesRead++;
159
160       currentFilePosition++;
161       System.out.println(i);
162       i++;
163     }
164
165     PrintWriter p = new PrintWriter(
166             new File(currentFolder + "/CurrentPosition.txt"));
167     p.print(currentFilePosition);
168     p.close();
169     exportData(currentFolder);
170     raw.clear();
171     binned.clear();
172
173   }
174
175   /**
176    * Analyses all families and then saves the data. Before analysing the data,
177    * the previous saved data will be imported and after analysing this, the data
178    * is exported back into the file.
179    * 
180    * @param increments
181    *          The number of families to read before saving.
182    * @throws IOException
183    */
184   public void runToEnd(boolean keepRawData) throws IOException
185   {
186     keepRaw = keepRawData;
187     BufferedReader inputSTO = null;
188     BufferedReader inputHMM = null;
189     int size = 0;
190     try
191     {
192       readPreviousData(currentFolder);
193       BufferedReader posReader = new BufferedReader(
194               new FileReader(currentFolder + "/CurrentPosition.txt"));
195
196       String line = posReader.readLine();
197       posReader.close();
198       currentFilePosition = Integer.parseInt(line);
199       readPreviousData(currentFolder);
200       
201       inputSTO = new BufferedReader(new FileReader(families));
202       inputHMM = new BufferedReader(new FileReader(hmms));
203     } catch (Exception e)
204     {
205       System.out.println("No or incomplete previous data found");
206     }
207
208     
209
210     moveLocationBy(currentFilePosition, inputHMM);
211     moveLocationBy(currentFilePosition, inputSTO);
212
213     int filesRead = 0;
214     int i = 0;
215     boolean endReached = atEnd(inputSTO);
216     while (!endReached)
217       {
218       readStockholm(inputSTO);
219       readHMM(inputHMM);
220
221         int count = countValidResidues();
222         processData(count);
223         filesRead++;
224
225         currentFilePosition++;
226         System.out.println(i);
227         i++;
228       endReached = atEnd(inputSTO);
229       }
230
231
232     PrintWriter p = new PrintWriter(
233             new File(currentFolder + "/CurrentPosition.txt"));
234     p.print(currentFilePosition);
235     p.close();
236     exportData(currentFolder);
237     raw.clear();
238     binned.clear();
239
240   }
241
242   /**
243    * Reads the previous data from both files
244    * 
245    * @param source
246    * @throws IOException
247    */
248   public void readPreviousData(String source) throws IOException
249   {
250     readBinned(source);
251     if (keepRaw)
252     {
253       readRaw(source);
254     }
255   }
256
257   /**
258    * Reads the previous data from the binned file.
259    * 
260    * @param source
261    * @throws IOException
262    */
263   public void readBinned(String source) throws IOException
264   {
265     BufferedReader input = new BufferedReader(
266             new FileReader(source + BINNED));
267     String line = input.readLine();
268     binned = new HashMap<>();
269     while (!("".equals(line) || line == null))
270     {
271       Scanner scanner = new Scanner(line);
272       scanner.useDelimiter(",");
273       String key = scanner.next();
274       String value = scanner.next();
275       binned.put(key, Double.valueOf(value));
276       scanner.close();
277       line = input.readLine();
278     }
279
280     input.close();
281   }
282
283   /**
284    * Reads the previous data from the raw file.
285    * 
286    * @param source
287    * @throws IOException
288    */
289   public void readRaw(String source) throws IOException
290   {
291     BufferedReader input = new BufferedReader(new FileReader(source + RAW));
292     String line = input.readLine();
293     if (line == null)
294     {
295       input.close();
296       return;
297     }
298     Scanner numberScanner = new Scanner(line);
299     numberScanner.useDelimiter(",");
300     raw = new ArrayList<>();
301     while (numberScanner.hasNext())
302     {
303       numberScanner.next();
304       raw.add(new ArrayList<Double>());
305     }
306     numberScanner.close();
307
308     line = input.readLine();
309     while (!("".equals(line) || line == null))
310     {
311       Scanner scanner = new Scanner(line);
312       scanner.useDelimiter(",");
313
314       int i = 0;
315       while (scanner.hasNext())
316       {
317         String value;
318         value = scanner.next();
319         if (!value.equals("EMPTY"))
320         {
321           raw.get(i).add(Double.parseDouble(value));
322         }
323         else
324         {
325           raw.get(i).add(null);
326         }
327
328         i++;
329       }
330       scanner.close();
331       line = input.readLine();
332     }
333
334     input.close();
335   }
336
337   /**
338    * Counts the number of valid residues in the sequence.
339    * 
340    * @return
341    */
342   public int countValidResidues()
343   {
344     int count = 0;
345
346     for (int width = 0; width < sequences.size(); width++)
347     {
348       for (int length = 1; length < hmm.getLength() + 1; length++)
349       {
350         char symbol;
351         int alignPos;
352         alignPos = hmm.getNodeAlignmentColumn(length);
353
354         symbol = sequences.get(width).getCharAt(alignPos);
355         if (ResidueProperties.aminoBackgroundFrequencies
356                 .containsKey(symbol))
357         {
358           count++;
359         }
360       }
361     }
362
363     return count;
364   }
365
366   /**
367    * Processes data, and stores it in both a raw and binned format.
368    * 
369    * @param count
370    */
371   public void processData(int count)
372   {
373     int rawPos = 0;
374     if (keepRaw)
375     {
376       raw.add(new ArrayList<Double>());
377       rawPos = raw.size() - 1;
378     }
379
380     for (int width = 0; width < sequences.size(); width++)
381     {
382       for (int length = 1; length < hmm.getLength() + 1; length++)
383       {
384         char symbol;
385         int alignPos;
386         alignPos = hmm.getNodeAlignmentColumn(length);
387         
388         symbol = sequences.get(width).getCharAt(alignPos);
389         if (ResidueProperties.aminoBackgroundFrequencies
390                 .containsKey(symbol))
391         {
392           Double prob;
393           Float bfreq;
394           Double llr;
395           prob = hmm.getMatchEmissionProbability(alignPos, symbol);
396           bfreq = ResidueProperties.aminoBackgroundFrequencies.get(symbol);
397           llr = Math.log(prob / bfreq);
398           if (keepRaw)
399           {
400             raw.get(rawPos).add(llr);
401           }
402
403           String output;
404           output = String.format("%.1f", llr);
405           if ("-0.0".equals(output))
406           {
407             output = "0.0";
408           }
409           if (binned.containsKey(output))
410           {
411             double prev = binned.get(output);
412             prev += (SCALE / count);
413             binned.put(output, prev);
414
415           }
416           else
417           {
418             binned.put(output, SCALE / count);
419           }
420         }
421       }
422     }
423   }
424
425
426   /**
427    * Reads in the sequence data from a Stockholm file.
428    * 
429    * @param source
430    * @throws IOException
431    */
432   public void readStockholm(BufferedReader inputSTO) throws IOException
433   {
434     FileParse parserSTO = new FileParse(inputSTO, "", DataSourceType.FILE);
435     StockholmFile file = new StockholmFile(parserSTO);
436     sequences = file.getSeqs();
437   }
438
439   /**
440    * Reads in the HMM data from a HMMer file.
441    * 
442    * @param source
443    * @throws IOException
444    */
445   public void readHMM(BufferedReader inputHMM) throws IOException
446   {
447     FileParse parserHMM = new FileParse(inputHMM, "", DataSourceType.FILE);
448     HMMFile file = new HMMFile(parserHMM);
449     file.parse();
450     hmm = file.getHMM();
451
452   }
453
454   /**
455    * Exports both the binned and raw data into separate files.
456    * 
457    * @param location
458    * @throws FileNotFoundException
459    */
460   public void exportData(String location) throws FileNotFoundException
461   {
462     PrintWriter writerBin = new PrintWriter(new File(location + BINNED));
463     for (Map.Entry<String, Double> entry : binned.entrySet())
464     {
465       writerBin.println(entry.getKey() + "," + entry.getValue());
466     }
467     writerBin.close();
468     if (keepRaw)
469     {
470
471     PrintWriter writerRaw = new PrintWriter(new File(location + RAW));
472     
473     StringBuilder identifier = new StringBuilder();
474     
475     for (int i = 1; i < raw.size() + 1; i++)
476     {
477       identifier.append("Fam " + i + ",");
478     }
479     
480     writerRaw.println(identifier);
481     
482     boolean rowIsEmpty = false;
483     int row = 0;
484     while (!rowIsEmpty)
485     {
486       rowIsEmpty = true;
487       StringBuilder string = new StringBuilder();
488       for (int column = 0; column < raw.size(); column++)
489       {
490         if (raw.get(column).size() <= row)
491         {
492           string.append("EMPTY,");
493         }
494         else
495         {
496           string.append(raw.get(column).get(row) + ",");
497           rowIsEmpty = false;
498         }
499       }
500       row++;
501       writerRaw.println(string);
502     }
503     writerRaw.close();
504
505     }
506
507   }
508
509   /**
510    * Prints the specified family on the console.
511    * 
512    * @param index
513    * @throws IOException
514    */
515   public void printFam(int index) throws IOException
516   {
517     BufferedReader br = new BufferedReader(new FileReader(families));
518
519     moveLocationBy(index, br);
520
521     String line = br.readLine();
522
523     while (!"//".equals(line))
524     {
525       System.out.println(line);
526       line = br.readLine();
527     }
528     System.out.println(line);
529     br.close();
530
531   }
532
533   /**
534    * Prints the specified HMM on the console.
535    * 
536    * @param index
537    * @throws IOException
538    */
539   public void printHMM(int index) throws IOException
540   {
541     BufferedReader br = new BufferedReader(new FileReader(hmms));
542
543     moveLocationBy(index, br);
544
545     String line = br.readLine();
546
547     while (!"//".equals(line))
548     {
549       System.out.println(line);
550       line = br.readLine();
551     }
552     System.out.println(line);
553     br.close();
554
555   }
556
557   /**
558    * Prints the specified family to a .sto file.
559    * 
560    * @param index
561    * @throws IOException
562    */
563   public void exportFam(int index, String location) throws IOException
564   {
565     BufferedReader br = new BufferedReader(new FileReader(families));
566
567     moveLocationBy(index, br);
568
569     String line = br.readLine();
570     PrintWriter writer = new PrintWriter(
571             new FileOutputStream(new File(location), true));
572     while (!"//".equals(line))
573     {
574       writer.println(line);
575       line = br.readLine();
576     }
577     writer.println(line);
578     writer.close();
579     br.close();
580
581   }
582
583   public void exportFile(BufferedReader br, String location, boolean append)
584           throws IOException
585   {
586     String line = br.readLine();
587     PrintWriter writer = new PrintWriter(
588             new FileOutputStream(location, append));
589     while (!"//".equals(line))
590     {
591       writer.println(line);
592       line = br.readLine();
593     }
594     writer.println(line);
595     writer.close();
596
597
598   }
599
600   public String getHMMName(int index) throws IOException
601   {
602     String name;
603
604     BufferedReader nameFinder = new BufferedReader(new FileReader(hmms));
605
606     moveLocationBy(index, nameFinder);
607
608     nameFinder.readLine();
609
610     Scanner scanner = new Scanner(nameFinder.readLine());
611     name = scanner.next();
612     name = scanner.next();
613     scanner.close();
614     return name;
615   }
616
617   public String getFamilyName(int index) throws IOException
618   {
619     String name;
620
621     BufferedReader nameFinder = new BufferedReader(
622             new FileReader(families));
623
624     moveLocationBy(index, nameFinder);
625
626     nameFinder.readLine();
627
628     Scanner scanner = new Scanner(nameFinder.readLine());
629     name = scanner.next();
630     name = scanner.next();
631     name = scanner.next();
632     scanner.close();
633     return name;
634   }
635
636   /**
637    * Prints the specified family to a .hmm file in the current directory.
638    * 
639    * @param index
640    * @throws IOException
641    */
642   public void exportHMM(int index, String location) throws IOException
643   {
644
645
646     BufferedReader br = new BufferedReader(new FileReader(hmms));
647
648     moveLocationBy(index, br);
649
650     String line = br.readLine();
651
652     PrintWriter writer = new PrintWriter(
653             new FileOutputStream(new File(location), true));
654     while (!"//".equals(line))
655     {
656       writer.println(line);
657       line = br.readLine();
658     }
659     writer.println(line);
660     writer.close();
661     br.close();
662
663   }
664   
665   /**
666    * Clears all raw, binned and current position data in the current directory.
667    * 
668    * @throws FileNotFoundException
669    */
670   public void clear() throws FileNotFoundException
671   {
672     PrintWriter pos = new PrintWriter(
673             currentFolder + "/CurrentPosition.txt");
674     pos.println("0");
675     
676     PrintWriter raw = new PrintWriter(currentFolder + RAW);
677     
678     PrintWriter bin = new PrintWriter(currentFolder + BINNED);
679     
680     pos.close();
681     bin.close();
682     raw.close();
683   }
684
685   public void sortIntoClans(String directory) throws IOException
686   {
687     BufferedReader clanFinder = new BufferedReader(new FileReader(FAMILIESTOCLAN));
688     BufferedReader familyReader = new BufferedReader(
689             new FileReader(families));
690     BufferedReader hmmReader = new BufferedReader(new FileReader(hmms));
691     HashMap<String, Integer> clanIndexes = new HashMap<>();
692     ArrayList<Integer> familyCounts = new ArrayList<>();
693     int filePos = 0; 
694     int clanCount = 0;
695     String line;
696     line = clanFinder.readLine();
697     
698     while (!"".equals(line) && !" ".equals(line) && line != null)
699     {
700      String clanName;
701       boolean inClan = false;
702      while (!(line.indexOf("//") > -1))
703      {
704        
705       if (line.indexOf("#=GF CL") > -1)
706       {
707           inClan = true;
708         Scanner scanner = new Scanner(line);
709         scanner.next();
710         scanner.next();
711         clanName = scanner.next();
712           scanner.close();
713         
714         if (!clanIndexes.containsKey(clanName))
715         {
716           clanIndexes.put(clanName, clanCount);
717             clanCount++;
718             familyCounts.add(0);
719         }
720
721
722           Integer clanI = clanIndexes.get(clanName);
723           String clanPath = directory + "/Clan" + clanI.toString();
724           createFolders(clanPath);
725
726           int index = clanIndexes.get(clanName);
727           exportFile(familyReader,
728                   clanPath + "/Families/Fam" + familyCounts.get(index)
729                           + ".sto",
730                   false);
731           exportFile(hmmReader,
732                   clanPath + "/HMMs/HMM" + familyCounts.get(index) + ".hmm",
733                   false);
734
735           int count = familyCounts.get(index);
736           count++;
737           familyCounts.set(index, count);
738       }
739         line = clanFinder.readLine();
740
741       }
742       if (!inClan)
743       {
744         moveLocationBy(1, familyReader);
745         moveLocationBy(1, hmmReader);
746       }
747       filePos++;
748       System.out.println(filePos + " files read.");
749       line = clanFinder.readLine();
750
751      }
752     clanFinder.close();
753
754     for (int clan = 0; clan < clanCount; clan++)
755     {
756       PrintWriter writer = new PrintWriter(
757               directory + "/Clan" + clan + "/NumberOfFamilies.txt");
758       int count = familyCounts.get(clan);
759       writer.print(count);
760       writer.close();
761     }
762       
763     }
764
765   public String getFamilies()
766   {
767     return families;
768   }
769
770   public void setFamilies(String families)
771   {
772     this.families = currentFolder + families;
773   }
774
775   public String getHmms()
776   {
777     return hmms;
778   }
779
780   public void setHmms(String hmms)
781   {
782     this.hmms = currentFolder + hmms;
783   }
784     
785   public void alignWithinClan(String exportLocation, String clansLocation)
786           throws IOException, InterruptedException
787   {
788     int alignmentsExported = 0;
789     for (int clan = 0; clan < 604; clan++)
790     {
791       int famCount = 0;
792       String clanPath = clansLocation + "/Clan" + clan;
793       int numberOfFamilies;
794       BufferedReader br = new BufferedReader(
795               new FileReader(clanPath + "/NumberOfFamilies.txt"));
796       String line = br.readLine();
797       numberOfFamilies = Integer.parseInt(line);
798       br.close();
799       String commandExportLocation = exportLocation + "/Clan" + clan;
800       createFolders(commandExportLocation);
801       for (int family = 0; family < numberOfFamilies; family++)
802       {
803         famCount++;
804         ArrayList<Integer> indexes = new ArrayList<>();
805         for (int i = 0; i < numberOfFamilies; i++)
806         {
807           if (i != family)
808           {
809             indexes.add(i);
810           }
811         }
812         int hmmIndex = getRandom(indexes);
813         String famPath = clanPath + "/Families/Fam" + family + ".sto";
814         String hmmPath = clanPath + "/HMMs/HMM" + hmmIndex + ".hmm";
815         String command = "H:/Documents/hmmalign -o " + commandExportLocation
816                 + "/Fam" + family + ".sto ";
817         command += hmmPath + " ";
818         command += famPath;
819
820         final Process p = Runtime.getRuntime().exec(command);
821
822         new Thread(new Runnable()
823         {
824           @Override
825           public void run()
826           {
827             BufferedReader input = new BufferedReader(
828                     new InputStreamReader(p.getInputStream()));
829             String line = null;
830
831             try
832             {
833               while ((line = input.readLine()) != null)
834               {
835                 System.out.println(line);
836               }
837             } catch (IOException e)
838             {
839               e.printStackTrace();
840             }
841           }
842         }).start();
843
844         p.waitFor();
845
846         exportHMM(hmmIndex,
847                 commandExportLocation + "/HMMs/HMM" + family + ".hmm");
848
849         alignmentsExported++;
850
851         System.out.println(alignmentsExported + " alignments exported");
852
853       }
854       PrintWriter writer = new PrintWriter(
855               commandExportLocation + "/NumberOfFamilies.txt");
856       writer.print(famCount);
857       writer.close();
858     }
859
860   }
861
862   public boolean atEnd(BufferedReader br) throws IOException
863   {
864     boolean end = false;
865     br.mark(80);
866     String line = br.readLine();
867     if ("".equals(line) || line == null)
868     {
869       end = true;
870     }
871     br.reset();
872     return end;
873   }
874
875   public int getRandom(ArrayList<Integer> list)
876   {
877     int index = generator.nextInt(list.size());
878     int value = list.get(index);
879     list.remove(index);
880     return value;
881   }
882
883   public void createFolders(String clanPath)
884   {
885     File clanFolder = new File(clanPath);
886     if (!clanFolder.exists())
887     {
888       clanFolder.mkdir();
889     }
890
891     File famFolder = new File(clanPath + "/Families");
892     File hmmFolder = new File(clanPath + "/HMMs");
893     if (!famFolder.exists())
894     {
895       famFolder.mkdir();
896       hmmFolder.mkdir();
897     }
898   }
899 }
900
901
902
903