in progress
[jalview.git] / forester / ruby / evoruby / lib / evo / tool / phylogenies_decorator.rb
1 #!/usr/local/bin/ruby -w
2 #
3 # = lib/evo/apps/phylogenies_decorator
4 #
5 # Copyright::  Copyright (C) 2006-2008 Christian M. Zmasek
6 # License::    GNU Lesser General Public License (LGPL)
7 #
8 # decoration of phylogenies with sequence/species names and domain architectures
9 #
10 # $Id: phylogenies_decorator.rb,v 1.34 2010/12/13 19:00:11 cmzmasek Exp $
11 #
12 # Environment variable FORESTER_HOME needs to point to the appropriate
13 # directory (e.g. setenv FORESTER_HOME $HOME/SOFTWARE_DEV/ECLIPSE_WORKSPACE/forester/)
14
15 require 'lib/evo/util/constants'
16 require 'lib/evo/util/util'
17 require 'lib/evo/util/command_line_arguments'
18
19 require 'date'
20
21 module Evoruby
22
23   class PhylogeniesDecorator
24
25     #DECORATOR_OPTIONS_SEQ_NAMES = '-r=1 -mdn'
26     #DECORATOR_OPTIONS_SEQ_NAMES = '-p -t -sn'
27     DECORATOR_OPTIONS_SEQ_NAMES = '-p -t -tc -mp -or'
28     # -mdn is a hidden expert option to rename e.g. "6_ORYLA3" to "6_[3]_ORYLA"
29     #DECORATOR_OPTIONS_SEQ_NAMES = '-sn -r=1'
30     #DECORATOR_OPTIONS_DOMAINS = '-r=1'
31     DECORATOR_OPTIONS_DOMAINS = '-p -t'
32     IDS_MAPFILE_SUFFIX        = '.nim'
33     DOMAINS_MAPFILE_SUFFIX    = '_hmmscan_10.dff'
34     SLEEP_TIME                = 0.05
35     REMOVE_NI                 = true
36     TMP_FILE_1                  = '___PD1___'
37     TMP_FILE_2                  = '___PD2___'
38     LOG_FILE                  = '00_phylogenies_decorator.log'
39     FORESTER_HOME             = ENV[Constants::FORESTER_HOME_ENV_VARIABLE]
40     JAVA_HOME                 = ENV[Constants::JAVA_HOME_ENV_VARIABLE]
41
42     PRG_NAME       = "phylogenies_decorator"
43     PRG_DATE       = "2013.11.15"
44     PRG_DESC       = "decoration of phylogenies with sequence/species names and domain architectures"
45     PRG_VERSION    = "1.02"
46     COPYRIGHT      = "2013 Christian M Zmasek"
47     CONTACT        = "phylosoft@gmail.com"
48     WWW            = "https://sites.google.com/site/cmzmasek/home/software/forester"
49
50
51     HELP_OPTION_1       = "help"
52     HELP_OPTION_2       = "h"
53
54     NL = Constants::LINE_DELIMITER
55
56     def run
57
58       Util.print_program_information( PRG_NAME,
59         PRG_VERSION,
60         PRG_DESC,
61         PRG_DATE,
62         COPYRIGHT,
63         CONTACT,
64         WWW,
65         STDOUT )
66
67       if ( ARGV == nil || ARGV.length > 3 || ARGV.length < 2  )
68         print_help
69         exit( -1 )
70       end
71
72       if FORESTER_HOME == nil || FORESTER_HOME.length < 1
73         Util.fatal_error( PRG_NAME, "apparently environment variable #{Constants::FORESTER_HOME_ENV_VARIABLE} has not been set" )
74       end
75       if JAVA_HOME == nil ||  JAVA_HOME.length < 1
76         Util.fatal_error( PRG_NAME, "apparently environment variable #{Constants::JAVA_HOME_ENV_VARIABLE} has not been set" )
77       end
78
79       if !File.exist?( FORESTER_HOME )
80         Util.fatal_error( PRG_NAME, '[' + FORESTER_HOME + '] does not exist' )
81       end
82       if !File.exist?( JAVA_HOME )
83         Util.fatal_error( PRG_NAME, '[' + JAVA_HOME + '] does not exist' )
84       end
85
86       decorator = JAVA_HOME + '/bin/java -cp ' + FORESTER_HOME + '/java/forester.jar org.forester.application.decorator'
87
88       begin
89         cla = CommandLineArguments.new( ARGV )
90       rescue ArgumentError => e
91         Util.fatal_error( PRG_NAME, "error: " + e.to_s )
92       end
93
94       if ( cla.is_option_set?( HELP_OPTION_1 ) ||
95            cla.is_option_set?( HELP_OPTION_2 ) )
96         print_help
97         exit( 0 )
98       end
99
100       if File.exist?( LOG_FILE )
101         Util.fatal_error( PRG_NAME, 'logfile [' + LOG_FILE + '] already exists' )
102       end
103
104       in_suffix = cla.get_file_name( 0 )
105       out_suffix = cla.get_file_name( 1 )
106
107       log = String.new
108
109       now = DateTime.now
110       log << "Program              : " + PRG_NAME + NL
111       log << "Version              : " + PRG_VERSION + NL
112       log << "Program date         : " + PRG_DATE + NL
113       log << "Options for seq names: " + DECORATOR_OPTIONS_SEQ_NAMES + NL
114       log << "Options for domains  : " + DECORATOR_OPTIONS_DOMAINS + NL
115       log << "FORESTER_HOME        : " + FORESTER_HOME + NL
116       log << "JAVA_HOME            : " + JAVA_HOME + NL + NL
117       log << "Date/time: " + now.to_s + NL
118       log << "Directory: " + Dir.getwd  + NL + NL
119
120       Util.print_message( PRG_NAME, 'input suffix     : ' + in_suffix )
121       Util.print_message( PRG_NAME, 'output suffix    : ' + out_suffix )
122
123       log << 'input suffix     : ' + in_suffix + NL
124       log << 'output suffix    : ' + out_suffix + NL
125
126       if ( File.exists?( TMP_FILE_1 ) )
127         File.delete( TMP_FILE_1 )
128       end
129       if ( File.exists?( TMP_FILE_2 ) )
130         File.delete( TMP_FILE_2 )
131       end
132
133       files = Dir.entries( "." )
134
135       counter = 0
136
137       files.each { | phylogeny_file |
138         if ( !File.directory?( phylogeny_file ) &&
139              phylogeny_file !~ /^\./ &&
140              phylogeny_file !~ /^00/ &&
141              phylogeny_file !~ /#{out_suffix}$/ &&
142              phylogeny_file =~ /#{in_suffix}$/ )
143           begin
144             Util.check_file_for_readability( phylogeny_file )
145           rescue ArgumentError
146             Util.fatal_error( PRG_NAME, 'can not read from: ' + phylogeny_file + ': '+ $! )
147           end
148
149           counter += 1
150
151           outfile = phylogeny_file.sub( /#{in_suffix}$/, out_suffix )
152
153           if REMOVE_NI
154             outfile = outfile.sub( /_ni_/, '_' )
155           end
156
157           if File.exists?( outfile )
158             msg = counter.to_s + ': ' + phylogeny_file + ' -> ' +  outfile +
159              ' : already exists, skipping'
160             Util.print_message( PRG_NAME, msg  )
161             log << msg + NL
162             next
163           end
164
165           Util.print_message( PRG_NAME, counter.to_s + ': ' + phylogeny_file + ' -> ' +  outfile )
166           log << counter.to_s + ': ' + phylogeny_file + ' -> ' +  outfile + NL
167
168           phylogeny_id = get_id( phylogeny_file )
169           if  phylogeny_id == nil || phylogeny_id.size < 1
170             Util.fatal_error( PRG_NAME, 'could not get id from ' + phylogeny_file.to_s )
171           end
172           puts
173           Util.print_message( PRG_NAME, "id: " + phylogeny_id )
174           log << "id: " + phylogeny_id + NL
175
176           ids_mapfile_name = nil
177           domains_mapfile_name = nil
178           seqs_file_name = nil
179
180           ids_mapfile_name = get_file( files, phylogeny_id, IDS_MAPFILE_SUFFIX )
181           domains_mapfile_name = get_file( files, phylogeny_id, DOMAINS_MAPFILE_SUFFIX )
182           seqs_file_name = get_seq_file( files, phylogeny_id )
183
184           begin
185             Util.check_file_for_readability( domains_mapfile_name )
186           rescue ArgumentError
187             Util.fatal_error( PRG_NAME, 'failed to read from [#{domains_mapfile_name}]: ' + $! )
188           end
189
190           begin
191             Util.check_file_for_readability( ids_mapfile_name )
192           rescue ArgumentError
193             Util.fatal_error( PRG_NAME, 'failed to read from [#{ids_mapfile_name}]: ' + $! )
194           end
195
196           begin
197             Util.check_file_for_readability( seqs_file_name  )
198           rescue ArgumentError
199             Util.fatal_error( PRG_NAME, 'failed to read from [#{seqs_file_name }]: ' + $! )
200           end
201
202 #          cmd = decorator +
203 #           ' -t -p -f=m ' + phylogeny_file + ' ' +
204 #           seqs_file_name  + ' ' + TMP_FILE_1
205 #          puts cmd
206 #          begin
207 #            execute_cmd( cmd, log )
208 #          rescue Error
209 #            Util.fatal_error( PRG_NAME, 'error: ' + $! )
210 #          end
211 #
212 #          cmd = decorator + ' ' + DECORATOR_OPTIONS_DOMAINS + ' ' +
213 #           '-f=d ' + TMP_FILE_1 + ' ' +
214 #           domains_mapfile_name + ' ' +TMP_FILE_2
215 #          puts cmd
216 #          begin
217 #            execute_cmd( cmd, log )
218 #          rescue Error
219 #            Util.fatal_error( PRG_NAME, 'error: ' + $! )
220 #          end
221
222           cmd = decorator + ' ' +  DECORATOR_OPTIONS_SEQ_NAMES + ' ' +
223            '-f=n ' + TMP_FILE_2 + ' ' +
224            ids_mapfile_name + ' ' + outfile
225           puts cmd
226           begin
227             execute_cmd( cmd, log )
228           rescue Error
229             Util.fatal_error( PRG_NAME, 'error: ' + $! )
230           end
231
232           File.delete( TMP_FILE_1 )
233           File.delete( TMP_FILE_2 )
234
235         end
236       }
237       open( LOG_FILE, 'w' ) do | f |
238         f.write( log )
239       end
240       puts
241       Util.print_message( PRG_NAME, 'OK' )
242       puts
243     end # def run
244
245     def execute_cmd( cmd, log )
246       log << 'executing ' + cmd + NL
247       IO.popen( cmd , 'r+' ) do | pipe |
248         pipe.close_write
249         log << pipe.read + NL + NL
250       end
251       sleep( SLEEP_TIME )
252     end
253
254
255     def get_id( phylogeny_file_name )
256       if phylogeny_file_name =~ /^(.+?_.+?)_/
257         return $1
258       elsif phylogeny_file_name =~ /^(.+?)__/
259         return $1
260       elsif phylogeny_file_name =~ /^(.+?)_/
261         return $1
262       end
263       nil
264     end
265
266     def get_file( files_in_dir, phylogeny_id, suffix_pattern )
267       matching_files = Array.new
268
269       files_in_dir.each { | file |
270
271         if ( !File.directory?( file ) &&
272              file !~ /^\./ &&
273              file !~ /^00/ &&
274              file =~ /^#{phylogeny_id}.*#{suffix_pattern}$/ )
275           matching_files << file
276         end
277       }
278       if matching_files.length < 1
279         Util.fatal_error( PRG_NAME, 'no file matching [' + phylogeny_id +
280            '...' + suffix_pattern + '] present in current directory' )
281       end
282       if matching_files.length > 1
283         Util.fatal_error( PRG_NAME, 'more than one file matching [' +
284            phylogeny_id  + '...' + suffix_pattern + '] present in current directory' )
285       end
286       matching_files[ 0 ]
287     end
288
289     def get_seq_file( files_in_dir, phylogeny_id )
290       matching_files = Array.new
291
292       files_in_dir.each { | file |
293
294         if ( !File.directory?( file ) &&
295              file !~ /^\./ &&
296              file !~ /^00/ &&
297              ( file =~ /^#{phylogeny_id}__.+\d$/ || file =~ /^#{phylogeny_id}_.*\.fasta$/ ) )
298           matching_files << file
299         end
300       }
301
302       if matching_files.length < 1
303         Util.fatal_error( PRG_NAME, 'no seq file matching [' +
304            phylogeny_id + '_] present in current directory' )
305       end
306       if matching_files.length > 1
307         Util.fatal_error( PRG_NAME, 'more than one seq file matching [' +
308            phylogeny_id + '_] present in current directory' )
309       end
310       matching_files[ 0 ]
311     end
312
313
314     def print_help()
315       puts( "Usage:" )
316       puts()
317       puts( "  " + PRG_NAME + ".rb <suffix of intrees to be decorated> <suffix for decorated outtrees> " )
318       puts()
319       puts()
320     end
321   end # class PhylogenyiesDecorator
322
323 end # module Evoruby