pdb
[jalview.git] / forester / ruby / evoruby / lib / evo / tool / msa_processor.rb
1 #
2 # = lib/evo/apps/msa_processor.rb - MsaProcessor class
3 #
4 # Copyright::  Copyright (C) 2006-2007 Christian M. Zmasek
5 # License::    GNU Lesser General Public License (LGPL)
6 #
7 # $Id: msa_processor.rb,v 1.33 2010/12/13 19:00:10 cmzmasek Exp $
8 #
9
10 require 'date'
11 require 'set'
12
13 require 'lib/evo/util/constants'
14 require 'lib/evo/util/util'
15 require 'lib/evo/util/command_line_arguments'
16 require 'lib/evo/msa/msa_factory'
17 require 'lib/evo/io/msa_io'
18 require 'lib/evo/io/writer/phylip_sequential_writer'
19 require 'lib/evo/io/writer/nexus_writer'
20 require 'lib/evo/io/writer/fasta_writer'
21 require 'lib/evo/io/parser/fasta_parser'
22 require 'lib/evo/io/parser/general_msa_parser'
23 require 'lib/evo/io/writer/msa_writer'
24
25 module Evoruby
26
27   class MsaProcessor
28
29     PRG_NAME       = "msa_pro"
30     PRG_DATE       = "2012.05.11"
31     PRG_DESC       = "processing of multiple sequence alignments"
32     PRG_VERSION    = "1.06"
33     COPYRIGHT      = "2008-2010 Christian M Zmasek"
34     CONTACT        = "phylosoft@gmail.com"
35     WWW            = "www.phylosoft.org"
36
37
38     NAME_LENGTH_DEFAULT                = 10
39     WIDTH_DEFAULT_FASTA                = 60
40     INPUT_TYPE_OPTION                  = "i"
41     OUTPUT_TYPE_OPTION                 = "o"
42     MAXIMAL_NAME_LENGTH_OPTION         = "n"
43     WIDTH_OPTION                       = "w"
44     CLEAN_UP_SEQ_OPTION                = "c"
45     REM_RED_OPTION                     = "rem_red"
46     REMOVE_GAP_COLUMNS_OPTION          = "rgc"
47     REMOVE_GAP_ONLY_COLUMNS            = "rgoc"
48     REMOVE_COLUMNS_GAP_RATIO_OPTION    = "rr"
49     REMOVE_ALL_GAP_CHARACTERS_OPTION   = "rg"
50     REMOVE_ALL_SEQUENCES_LISTED_OPTION = "r"
51     KEEP_ONLY_SEQUENCES_LISTED_OPTION  = "k"
52
53     KEEP_MATCHING_SEQUENCES_OPTION     = "mk"
54     REMOVE_MATCHING_SEQUENCES_OPTION   = "mr"
55
56     TRIM_OPTION                        = "t"
57     REMOVE_SEQS_GAP_RATIO_OPTION       = "rsgr"
58     REMOVE_SEQS_NON_GAP_LENGTH_OPTION  = "rsl"
59     SPLIT                              = "split"
60     LOG_SUFFIX                         = "_msa_pro.log"
61     HELP_OPTION_1                      = "help"
62     HELP_OPTION_2                      = "h"
63
64
65     def initialize()
66       @input_format_set = false
67       @output_format_set = false
68       @fasta_input      = false
69       @phylip_input     = true
70       @name_length      = NAME_LENGTH_DEFAULT
71       @name_length_set  = false
72       @width            = WIDTH_DEFAULT_FASTA     # fasta only
73       @pi_output        = true
74       @fasta_output     = false
75       @nexus_output     = false
76       @clean            = false  # phylip only
77       @rgc              = false
78       @rgoc             = false
79       @rg               = false  # fasta only
80       @rem_red          = false
81       @rgr              = -1
82       @rsgr             = -1
83       @rsl              = -1
84       @remove_matching  = nil
85       @keep_matching    = nil
86
87       @seqs_name_file   = nil
88       @remove_seqs      = false
89       @keep_seqs        = false
90       @trim             = false
91       @split            = -1
92       @first            = -1
93       @last             = -1
94     end
95
96
97     def run()
98
99       Util.print_program_information( PRG_NAME,
100         PRG_VERSION,
101         PRG_DESC,
102         PRG_DATE,
103         COPYRIGHT,
104         CONTACT,
105         WWW,
106         STDOUT )
107
108       if ( ARGV == nil || ARGV.length < 1 )
109         Util.print_message( PRG_NAME, "Illegal number of arguments" )
110         print_help
111         exit( -1 )
112       end
113
114       begin
115         cla = CommandLineArguments.new( ARGV )
116       rescue ArgumentError => e
117         Util.fatal_error( PRG_NAME, "Error: " + e.to_s, STDOUT )
118       end
119
120       if ( cla.is_option_set?( HELP_OPTION_1 ) ||
121            cla.is_option_set?( HELP_OPTION_2 ) )
122         print_help
123         exit( 0 )
124       end
125
126       if ( cla.get_number_of_files != 2 || ARGV.length < 2 )
127         Util.print_message( PRG_NAME, "Illegal number of arguments" )
128         print_help
129         exit( -1 )
130       end
131
132       allowed_opts = Array.new
133       allowed_opts.push( INPUT_TYPE_OPTION )
134       allowed_opts.push( OUTPUT_TYPE_OPTION )
135       allowed_opts.push( MAXIMAL_NAME_LENGTH_OPTION )
136       allowed_opts.push( WIDTH_OPTION )
137       allowed_opts.push( CLEAN_UP_SEQ_OPTION )
138       allowed_opts.push( REMOVE_GAP_COLUMNS_OPTION )
139       allowed_opts.push( REMOVE_GAP_ONLY_COLUMNS )
140       allowed_opts.push( REMOVE_COLUMNS_GAP_RATIO_OPTION )
141       allowed_opts.push( REMOVE_ALL_GAP_CHARACTERS_OPTION )
142       allowed_opts.push( REMOVE_ALL_SEQUENCES_LISTED_OPTION )
143       allowed_opts.push( KEEP_ONLY_SEQUENCES_LISTED_OPTION )
144       allowed_opts.push( TRIM_OPTION )
145       allowed_opts.push( REMOVE_SEQS_GAP_RATIO_OPTION )
146       allowed_opts.push( REMOVE_SEQS_NON_GAP_LENGTH_OPTION )
147       allowed_opts.push( SPLIT )
148       allowed_opts.push( REM_RED_OPTION )
149       allowed_opts.push( KEEP_MATCHING_SEQUENCES_OPTION )
150       allowed_opts.push( REMOVE_MATCHING_SEQUENCES_OPTION )
151
152       disallowed = cla.validate_allowed_options_as_str( allowed_opts )
153       if ( disallowed.length > 0 )
154         Util.fatal_error( PRG_NAME,
155           "unknown option(s): " + disallowed )
156       end
157
158       input = cla.get_file_name( 0 )
159       output = cla.get_file_name( 1 )
160
161       analyze_command_line( cla )
162
163       begin
164         Util.check_file_for_readability( input )
165       rescue ArgumentError => e
166         Util.fatal_error( PRG_NAME, "error: " + e.to_s )
167       end
168
169       begin
170         Util.check_file_for_writability( output )
171       rescue ArgumentError => e
172         Util.fatal_error( PRG_NAME, "error: " + e.to_s )
173       end
174
175       if ( @rg )
176         set_pi_output( false )
177         set_fasta_output( true )
178         set_nexus_output( false )
179       end
180
181       if ( !@input_format_set )
182         fasta_like = false
183         begin
184           fasta_like = Util.looks_like_fasta?( input )
185         rescue ArgumentError => e
186           Util.fatal_error( PRG_NAME, "error: " + e.to_s )
187         end
188         @fasta_input = fasta_like
189         @phylip_input = !fasta_like
190         if ( !@output_format_set )
191           @fasta_output = fasta_like
192           @pi_output = !fasta_like
193           @nexus_output = false
194         end
195       end
196
197       ld = Constants::LINE_DELIMITER
198       log = PRG_NAME + " " + PRG_VERSION + " [" + PRG_DATE + "]" + " LOG" + ld
199       now = DateTime.now
200       log << "Date/time: " + now.to_s + ld
201
202       puts()
203       puts( "Input alignment  : " + input )
204       log << "Input alignment  : " + input + ld
205       puts( "Output alignment : " + output )
206       log << "Output alignment : " + output + ld
207       if ( @phylip_input )
208         puts( "Input is         : Phylip, or something like it" )
209         log << "Input is         : Phylip, or something like it" + ld
210       elsif ( @fasta_input )
211         puts( "Input is         : Fasta" )
212         log << "Input is         : Fasta" + ld
213       end
214       if( @rgr >= 0 )
215         puts( "Max col gap ratio: " + @rgr.to_s )
216         log << "Max col gap ratio: " + @rgr.to_s + ld
217       elsif ( @rgc )
218         puts( "Remove gap colums" )
219         log << "Remove gap colums" + ld
220       elsif( @rgoc )
221         puts( "Remove gap only colums" )
222         log << "Remove gap only colums" + ld
223       end
224       if ( @clean )
225         puts( "Clean up         : true" )
226         log << "Clean up         : true" + ld
227       end
228
229       if ( @pi_output )
230         puts( "Output is        : Phylip interleaved" )
231         log << "Output is        : Phylip interleaved" + ld
232       elsif ( @fasta_output )
233         puts( "Output is        : Fasta" )
234         log << "Output is        : Fasta" + ld
235         if ( @width )
236           puts( "Width            : " + @width.to_s )
237           log << "Width            : " + @width.to_s + ld
238         end
239         if ( @rg )
240           puts( "Remove all gap characters (alignment is destroyed)" )
241           log << "Remove all gap characters (alignment is destroyed)" + ld
242         end
243       elsif ( @nexus_output )
244         puts( "Output is        : Nexus" )
245         log << "Output is        : Nexus" + ld
246       end
247       if ( @name_length_set || !@fasta_output )
248         puts( "Max name length  : " + @name_length.to_s )
249         log << "Max name length  : " + @name_length.to_s + ld
250       end
251       if( @rsgr >= 0 )
252         puts( "Remove sequences for which the gap ratio > " + @rsgr.to_s )
253         log << "Remove sequences for which the gap ratio > " + @rsgr.to_s + ld
254       end
255       if( @rsl >= 0 )
256         puts( "Remove sequences with less than "  + @rsl.to_s + " non-gap characters" )
257         log << "Remove sequences with less than "  + @rsl.to_s + " non-gap characters" + ld
258       end
259       if ( @remove_seqs )
260         puts( "Remove sequences listed in: " + @seqs_name_file )
261         log << "Remove sequences listed in: " + @seqs_name_file + ld
262       elsif ( @keep_seqs )
263         puts( "Keep only sequences listed in: " + @seqs_name_file )
264         log << "Keep only sequences listed in: " + @seqs_name_file + ld
265       end
266       if ( @trim )
267         puts( "Keep only columns from: "+ @first.to_s + " to " + @last.to_s )
268         log << "Keep only columns from: "+ @first.to_s + " to " + @last.to_s + ld
269       end
270       if ( @rem_red )
271         puts( "Remove redundant sequences: true" )
272         log << "Remove redundant sequences: true" + ld
273       end
274       if ( @split > 0 )
275         puts( "Split            : " + @split.to_s )
276         log << "Split            : " + @split.to_s + ld
277       end
278       puts()
279
280       f = MsaFactory.new()
281
282       msa = nil
283
284       begin
285         if ( @phylip_input )
286           msa = f.create_msa_from_file( input, GeneralMsaParser.new() )
287         elsif ( @fasta_input )
288           msa = f.create_msa_from_file( input, FastaParser.new() )
289         end
290       rescue Exception => e
291         Util.fatal_error( PRG_NAME, "error: " + e.to_s, STDOUT )
292       end
293
294       if ( msa.is_aligned() )
295         Util.print_message( PRG_NAME, "Length of original alignment         : " + msa.get_length.to_s )
296         log << "Length of original alignment         : " + msa.get_length.to_s + ld
297         gp = msa.calculate_gap_proportion
298         Util.print_message( PRG_NAME, "Gap-proportion of original alignment : " + gp.to_s )
299         log << "Gap-proportion of original alignment : " +  gp.to_s + ld
300       else
301         Util.print_message( PRG_NAME, "the input is not aligned" )
302         log << "The input is not aligned" + ld
303       end
304
305       all_names = Set.new()
306       for i in 0 ... msa.get_number_of_seqs()
307         current_name = msa.get_sequence( i ).get_name
308         if all_names.include?( current_name )
309           Util.print_warning_message( PRG_NAME, "sequence name [" + current_name + "] is not unique" )
310         else
311           all_names.add( current_name )
312         end
313       end
314
315       begin
316
317         if ( @remove_seqs || @keep_seqs )
318           names = Util.file2array( @seqs_name_file, true )
319           if ( names == nil ||  names.length() < 1 )
320             error_msg = "file \"" + @seqs_name_file.to_s + "\" appears empty"
321             Util.fatal_error( PRG_NAME, error_msg )
322           end
323
324           if ( @remove_seqs )
325             c = 0
326             for i in 0 ... names.length()
327               to_delete = msa.find_by_name( names[ i ], true, false )
328               if ( to_delete.length() < 1 )
329                 error_msg = "sequence name \"" + names[ i ] + "\" not found"
330                 Util.fatal_error( PRG_NAME, error_msg )
331               elsif ( to_delete.length() > 1 )
332                 error_msg = "sequence name \"" + names[ i ] + "\" is not unique"
333                 Util.fatal_error( PRG_NAME, error_msg )
334               else
335                 msa.remove_sequence!( to_delete[ 0 ] )
336                 c += 1
337               end
338             end
339             Util.print_message( PRG_NAME, "Removed " + c.to_s + " sequences" )
340             log <<  "Removed " + c.to_s + " sequences" + ld
341           elsif ( @keep_seqs )
342             msa_new = Msa.new()
343             r = 0
344             k = 0
345             for j in 0 ... msa.get_number_of_seqs()
346               if ( names.include?( msa.get_sequence( j ).get_name() ) )
347                 msa_new.add_sequence( msa.get_sequence( j ) )
348                 k += 1
349               else
350                 r += 1
351               end
352             end
353             msa = msa_new
354             Util.print_message( PRG_NAME, "Kept    " + k.to_s + " sequences" )
355             log << "Kept    " + k.to_s + " sequences" + ld
356             Util.print_message( PRG_NAME, "Removed " + r.to_s + " sequences" )
357             log << "removed " + r.to_s + " sequences" + ld
358           end
359         end
360
361         if ( @trim )
362           msa.trim!( @first, @last )
363         end
364         if( @rgr >= 0 )
365           msa.remove_gap_columns_w_gap_ratio!( @rgr )
366         elsif ( @rgc )
367           msa.remove_gap_columns!()
368         elsif( @rgoc )
369           msa.remove_gap_only_columns!()
370         end
371         if( @rsgr >= 0 )
372           n = msa.get_number_of_seqs()
373           removed = msa.remove_sequences_by_gap_ratio!( @rsgr )
374           k = msa.get_number_of_seqs()
375           r = n - k
376           Util.print_message( PRG_NAME, "Kept    " + k.to_s + " sequences" )
377           log << "Kept    " + k.to_s + " sequences" + ld
378           Util.print_message( PRG_NAME, "Removed " + r.to_s + " sequences"  )
379           log << "Removed " + r.to_s + " sequences:" + ld
380           removed.each { | seq_name |
381             log << "         " + seq_name  + ld
382           }
383         end
384         if( @rsl >= 0 )
385           n = msa.get_number_of_seqs()
386           removed = msa.remove_sequences_by_non_gap_length!( @rsl )
387           k = msa.get_number_of_seqs()
388           r = n - k
389           Util.print_message( PRG_NAME, "Kept    " + k.to_s + " sequences" )
390           log << "Kept    " + k.to_s + " sequences" + ld
391           Util.print_message( PRG_NAME, "Removed " + r.to_s + " sequences" )
392           log << "Removed " + r.to_s + " sequences:" + ld
393           removed.each { | seq_name |
394             log << "         " + seq_name  + ld
395           }
396         end
397         if ( @keep_matching )
398           n = msa.get_number_of_seqs
399           to_be_removed = Set.new
400           for ii in 0 ...  n
401             seq = msa.get_sequence( ii )
402             if !seq.get_name.downcase.index( @keep_matching.downcase )
403               to_be_removed.add( ii )
404             end
405           end
406           to_be_removed_ary = to_be_removed.to_a.sort.reverse
407           to_be_removed_ary.each { | index |
408             msa.remove_sequence!( index )
409           }
410           # msa = sort( msa )
411         end
412         if ( @remove_matching )
413           n = msa.get_number_of_seqs
414           to_be_removed = Set.new
415           for iii in 0 ... n
416
417             seq = msa.get_sequence( iii )
418
419             if seq.get_name.downcase.index( @remove_matching.downcase )
420               to_be_removed.add( iii )
421             end
422           end
423           to_be_removed_ary = to_be_removed.to_a.sort.reverse
424           to_be_removed_ary.each { | index |
425             msa.remove_sequence!( index )
426           }
427           msa = sort( msa )
428         end
429
430
431
432         if ( @split > 0 )
433           begin
434             msas = msa.split( @split, true )
435             io = MsaIO.new()
436             w = MsaWriter
437             if ( @pi_output )
438               w = PhylipSequentialWriter.new()
439               w.clean( @clean )
440               w.set_max_name_length( @name_length )
441             elsif( @fasta_output )
442               w = FastaWriter.new()
443               w.set_line_width( @width )
444               if ( @rg )
445                 w.remove_gap_chars( true )
446                 Util.print_warning_message( PRG_NAME, "removing gap character, the output is likely to become unaligned" )
447                 log << "removing gap character, the output is likely to become unaligned" + ld
448               end
449               w.clean( @clean )
450               if ( @name_length_set )
451                 w.set_max_name_length( @name_length )
452               end
453             elsif( @nexus_output )
454               w = NexusWriter.new()
455               w.clean( @clean )
456               w.set_max_name_length( @name_length )
457             end
458             i = 0
459             for m in msas
460               i = i + 1
461               io.write_to_file( m, output + "_" + i.to_s, w )
462             end
463             Util.print_message( PRG_NAME, "wrote " + msas.length.to_s + " files"  )
464             log << "wrote " + msas.length.to_s + " files" + ld
465           rescue Exception => e
466             Util.fatal_error( PRG_NAME, "error: " + e.to_s, STDOUT )
467           end
468
469         end
470       rescue Exception => e
471         Util.fatal_error( PRG_NAME, "error: " + e.to_s, STDOUT )
472       end
473
474       if ( @split <= 0 )
475
476         unless ( @rg )
477           if ( msa.is_aligned() )
478             Util.print_message( PRG_NAME, "Length of processed alignment        : " + msa.get_length.to_s )
479             log <<  "Length of processed alignment        : " + msa.get_length.to_s + ld
480             gp = msa.calculate_gap_proportion
481             Util.print_message( PRG_NAME, "Gap-proportion of processed alignment: " + gp.to_s )
482             log << "Gap-proportion of processed alignment: " +  gp.to_s + ld
483           else
484             Util.print_warning_message( PRG_NAME, "output is not aligned" )
485             log << "output is not aligned" + ld
486           end
487         end
488
489         if @rem_red
490           removed = msa.remove_redundant_sequences!( true, false )
491           if removed.size > 0
492             identicals = msa.get_identical_seqs_detected
493             log << "the following " + identicals.size.to_s + " sequences are identical:" + ld
494             identicals.each { | s |
495               log << s + ld
496             }
497             log << "ignoring the following " + removed.size.to_s + " redundant sequences:" + ld
498             removed.each { | seq_name |
499               log << seq_name + ld
500             }
501             Util.print_message( PRG_NAME, "will store " + msa.get_number_of_seqs.to_s + " non-redundant sequences" )
502             log << "will store " + msa.get_number_of_seqs.to_s + " non-redundant sequences" + ld
503           end
504         end
505
506         io = MsaIO.new()
507
508         w = MsaWriter
509
510         if ( @pi_output )
511           w = PhylipSequentialWriter.new()
512           w.clean( @clean )
513           w.set_max_name_length( @name_length )
514         elsif( @fasta_output )
515           w = FastaWriter.new()
516           w.set_line_width( @width )
517           if ( @rg )
518             w.remove_gap_chars( true )
519             Util.print_warning_message( PRG_NAME, "removing gap characters, the output is likely to become unaligned"  )
520             log << "removing gap character, the output is likely to become unaligned" + ld
521           end
522           w.clean( @clean )
523           if ( @name_length_set )
524             w.set_max_name_length( @name_length )
525           end
526         elsif( @nexus_output )
527           w = NexusWriter.new()
528           w.clean( @clean )
529           w.set_max_name_length( @name_length )
530         end
531
532
533         begin
534           io.write_to_file( msa, output, w )
535         rescue Exception => e
536           Util.fatal_error( PRG_NAME, "error: " + e.to_s )
537         end
538
539         begin
540           f = File.open( output + LOG_SUFFIX, 'a' )
541           f.print( log )
542           f.close
543         rescue Exception => e
544           Util.fatal_error( PRG_NAME, "error: " + e.to_s )
545         end
546
547
548       end
549       Util.print_message( PRG_NAME, "OK" )
550       puts
551     end
552
553
554     private
555
556     def sort( msa )
557       names = Set.new
558       for i in 0 ... msa.get_number_of_seqs
559         name = msa.get_sequence( i ).get_name
560         names.add( name )
561       end
562       sorted_ary = names.to_a.sort
563       new_msa = Msa.new
564       sorted_ary.each { | seq_name |
565         seq = msa.get_sequence( msa.find_by_name( seq_name, true, false )[ 0 ] )
566         new_msa.add_sequence( seq )
567       }
568       new_msa
569     end
570
571     def set_fasta_input( fi = true )
572       @fasta_input = fi
573       @input_format_set = true
574     end
575     def set_phylip_input( pi = true )
576       @phylip_input = pi
577       @input_format_set = true
578     end
579     def set_name_length( i )
580       @name_length = i
581       @name_length_set = true
582     end
583     def set_width( i )
584       @width = i
585     end
586     def set_fasta_output( fo = true )
587       @fasta_output = fo
588       @output_format_set = true
589     end
590     def set_pi_output( pso = true )
591       @pi_output = pso
592       @output_format_set = true
593     end
594     def set_nexus_output( nexus = true )
595       @nexus_output = nexus
596       @output_format_set = true
597     end
598     def set_clean( c = true )
599       @clean = c
600     end
601     def set_remove_gap_columns( rgc = true )
602       @rgc = rgc
603     end
604     def set_remove_gap_only_columns( rgoc = true )
605       @rgoc = rgoc
606     end
607     def set_remove_gaps( rg = true )
608       @rg = rg
609     end
610     def set_remove_gap_ratio( rgr )
611       @rgr = rgr
612     end
613     def set_remove_seqs_gap_ratio( rsgr )
614       @rsgr = rsgr
615     end
616     def set_remove_seqs_min_non_gap_length( rsl )
617       @rsl = rsl
618     end
619     def set_remove_seqs( file )
620       @seqs_name_file = file
621       @remove_seqs    = true
622       @keep_seqs      = false
623     end
624     def set_keep_seqs( file )
625       @seqs_name_file = file
626       @keep_seqs      = true
627       @remove_seqs    = false
628     end
629     def set_trim( first, last )
630       @trim            = true
631       @first           = first
632       @last            = last
633     end
634     def set_remove_matching( remove )
635       @remove_matching  = remove
636     end
637     def set_keep_matching( keep )
638       @keep_matching = keep
639     end
640     def set_rem_red( rr )
641       @rem_red = rr
642     end
643
644
645
646     def set_split( s )
647       if ( s > 0 )
648         @split            = s
649         @clean            = false  # phylip only
650         @rgc              = false
651         @rgoc             = false
652         @rg               = false  # fasta only
653         @rgr              = -1
654         @rsgr             = -1
655         @rsl              = -1
656         @seqs_name_file   = nil
657         @remove_seqs      = false
658         @keep_seqs        = false
659         @trim             = false
660         @first            = -1
661         @last             = -1
662       end
663     end
664     def analyze_command_line( cla )
665       if ( cla.is_option_set?( INPUT_TYPE_OPTION ) )
666         begin
667           type = cla.get_option_value( INPUT_TYPE_OPTION )
668           if ( type == "p" )
669             set_phylip_input( true )
670             set_fasta_input( false )
671           elsif ( type == "f" )
672             set_fasta_input( true )
673             set_phylip_input( false )
674           end
675         rescue ArgumentError => e
676           Util.fatal_error( PRG_NAME, "error: " + e.to_s, STDOUT )
677         end
678       end
679       if ( cla.is_option_set?( OUTPUT_TYPE_OPTION ) )
680         begin
681           type = cla.get_option_value( OUTPUT_TYPE_OPTION )
682           if ( type == "p" )
683             set_pi_output( true )
684             set_fasta_output( false )
685             set_nexus_output( false )
686           elsif ( type == "f" )
687             set_pi_output( false )
688             set_fasta_output( true )
689             set_nexus_output( false )
690           elsif ( type == "n" )
691             set_pi_output( false )
692             set_fasta_output( false )
693             set_nexus_output( true )
694           end
695         rescue ArgumentError => e
696           Util.fatal_error( PRG_NAME, "error: " + e.to_s, STDOUT )
697         end
698       end
699       if ( cla.is_option_set?( MAXIMAL_NAME_LENGTH_OPTION ) )
700         begin
701           l = cla.get_option_value_as_int( MAXIMAL_NAME_LENGTH_OPTION )
702           set_name_length( l )
703         rescue ArgumentError => e
704           Util.fatal_error( PRG_NAME, "error: " + e.to_s, STDOUT )
705         end
706       end
707       if ( cla.is_option_set?( WIDTH_OPTION ) )
708         begin
709           w = cla.get_option_value_as_int( WIDTH_OPTION )
710           set_width( w )
711         rescue ArgumentError => e
712           Util.fatal_error( PRG_NAME, "error: " + e.to_s, STDOUT )
713         end
714       end
715       if ( cla.is_option_set?( CLEAN_UP_SEQ_OPTION ) )
716         set_clean( true )
717       end
718       if ( cla.is_option_set?( REMOVE_GAP_COLUMNS_OPTION ) )
719         set_remove_gap_columns( true )
720       end
721       if ( cla.is_option_set?( REM_RED_OPTION ) )
722         set_rem_red( true )
723       end
724       if ( cla.is_option_set?( REMOVE_GAP_ONLY_COLUMNS ) )
725         set_remove_gap_only_columns( true )
726       end
727       if ( cla.is_option_set?( REMOVE_ALL_GAP_CHARACTERS_OPTION ) )
728         set_remove_gaps( true )
729       end
730       if ( cla.is_option_set?( REMOVE_COLUMNS_GAP_RATIO_OPTION ) )
731         begin
732           f = cla.get_option_value_as_float( REMOVE_COLUMNS_GAP_RATIO_OPTION )
733           set_remove_gap_ratio( f )
734         rescue ArgumentError => e
735           Util.fatal_error( PRG_NAME, "error: " + e.to_s, STDOUT )
736         end
737       end
738       if ( cla.is_option_set?( REMOVE_ALL_SEQUENCES_LISTED_OPTION ) )
739         begin
740           s = cla.get_option_value( REMOVE_ALL_SEQUENCES_LISTED_OPTION )
741           set_remove_seqs( s )
742         rescue ArgumentError => e
743           Util.fatal_error( PRG_NAME, "error: " + e.to_s, STDOUT )
744         end
745       end
746       if ( cla.is_option_set?( KEEP_ONLY_SEQUENCES_LISTED_OPTION ) )
747         begin
748           s = cla.get_option_value( KEEP_ONLY_SEQUENCES_LISTED_OPTION )
749           set_keep_seqs( s )
750         rescue ArgumentError => e
751           Util.fatal_error( PRG_NAME, "error: " + e.to_s, STDOUT )
752         end
753       end
754       if ( cla.is_option_set?( TRIM_OPTION ) )
755         begin
756           s = cla.get_option_value( TRIM_OPTION )
757           if ( s =~ /(\d+)-(\d+)/ )
758             set_trim( $1.to_i(), $2.to_i() )
759           else
760             puts( "illegal argument" )
761             print_help
762             exit( -1 )
763           end
764         rescue ArgumentError => e
765           Util.fatal_error( PRG_NAME, "error: " + e.to_s, STDOUT )
766         end
767       end
768       if ( cla.is_option_set?( REMOVE_SEQS_GAP_RATIO_OPTION ) )
769         begin
770           f = cla.get_option_value_as_float( REMOVE_SEQS_GAP_RATIO_OPTION )
771           set_remove_seqs_gap_ratio( f )
772         rescue ArgumentError => e
773           Util.fatal_error( PRG_NAME, "error: " + e.to_s, STDOUT )
774         end
775       end
776       if ( cla.is_option_set?( REMOVE_SEQS_NON_GAP_LENGTH_OPTION ) )
777         begin
778           f = cla.get_option_value_as_int( REMOVE_SEQS_NON_GAP_LENGTH_OPTION )
779           set_remove_seqs_min_non_gap_length( f )
780         rescue ArgumentError => e
781           Util.fatal_error( PRG_NAME, "error: " + e.to_s, STDOUT )
782         end
783       end
784       if ( cla.is_option_set?( SPLIT ) )
785         begin
786           s = cla.get_option_value_as_int( SPLIT )
787           set_split( s )
788         rescue ArgumentError => e
789           Util.fatal_error( PRG_NAME, "error: " + e.to_s, STDOUT )
790         end
791
792       end
793       if ( cla.is_option_set?( REMOVE_MATCHING_SEQUENCES_OPTION ) )
794         begin
795           s = cla.get_option_value( REMOVE_MATCHING_SEQUENCES_OPTION )
796           set_remove_matching( s )
797         rescue ArgumentError => e
798           Util.fatal_error( PRG_NAME, "error: " + e.to_s, STDOUT )
799         end
800       end
801       if ( cla.is_option_set?( KEEP_MATCHING_SEQUENCES_OPTION ) )
802         begin
803           s = cla.get_option_value( KEEP_MATCHING_SEQUENCES_OPTION )
804           set_keep_matching( s )
805         rescue ArgumentError => e
806           Util.fatal_error( PRG_NAME, "error: " + e.to_s, STDOUT )
807         end
808       end
809
810
811     end
812
813     def print_help()
814       puts()
815       puts( "Usage:" )
816       puts()
817       puts( "  " + PRG_NAME + ".rb [options] <input alignment> <output>" )
818       puts()
819       puts( "  options: -" + INPUT_TYPE_OPTION + "=<input type>: f for fasta, p for phylip selex type" )
820       puts( "           -" + OUTPUT_TYPE_OPTION + "=<output type>: f for fasta, n for nexus, p for phylip sequential (default)" )
821       puts( "           -" + MAXIMAL_NAME_LENGTH_OPTION + "=<n>: n=maximal name length (default for phylip 10, for fasta: unlimited )" )
822       puts( "           -" + WIDTH_OPTION + "=<n>: n=width (fasta output only, default is 60)" )
823       puts( "           -" + CLEAN_UP_SEQ_OPTION + ": clean up sequences" )
824       puts( "           -" + REMOVE_GAP_COLUMNS_OPTION + ": remove gap columns" )
825       puts( "           -" + REMOVE_GAP_ONLY_COLUMNS + ": remove gap-only columns" )
826       puts( "           -" + REMOVE_COLUMNS_GAP_RATIO_OPTION + "=<n>: remove columns for which ( seqs with gap / number of sequences > n )" )
827       puts( "           -" + REMOVE_ALL_GAP_CHARACTERS_OPTION + ": remove all gap characters (destroys alignment, fasta output only)" )
828       puts( "           -" + REMOVE_ALL_SEQUENCES_LISTED_OPTION + "=<file>: remove all sequences listed in file" )
829       puts( "           -" + KEEP_ONLY_SEQUENCES_LISTED_OPTION + "=<file>: keep only sequences listed in file" )
830       puts( "           -" + TRIM_OPTION + "=<first>-<last>: remove columns before first and after last" )
831       puts( "           -" + REMOVE_SEQS_GAP_RATIO_OPTION + "=<n>: remove sequences for which the gap ratio > n (after column operations)" )
832       puts( "           -" + REMOVE_SEQS_NON_GAP_LENGTH_OPTION + "=<n> remove sequences with less than n non-gap characters (after column operations)" )
833       puts( "           -" + REMOVE_MATCHING_SEQUENCES_OPTION + "=<s> remove all sequences with names containing s" )
834       puts( "           -" + KEEP_MATCHING_SEQUENCES_OPTION + "=<s> keep only sequences with names containing s" )
835       puts( "           -" + SPLIT + "=<n> split a fasta file into n files of equal number of sequences (expect for " )
836       puts( "            last one), cannot be used with other options" )
837       puts( "           -" + REM_RED_OPTION + ": remove redundant sequences" )
838       puts()
839     end
840
841
842
843
844
845   end # class MsaProcessor
846
847
848 end # module Evoruby