in progress
[jalview.git] / forester / java / src / org / forester / application / cladinator.java
1 // $Id:
2 // FORESTER -- software libraries and applications
3 // for evolutionary biology research and applications.
4 //
5 // Copyright (C) 2017 Christian M. Zmasek
6 // Copyright (C) 2017 J. Craig Venter Institute
7 // All rights reserved
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Lesser General Public
11 // License as published by the Free Software Foundation; either
12 // version 2.1 of the License, or (at your option) any later version.
13 //
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 // Lesser General Public License for more details.
18 //
19 // You should have received a copy of the GNU Lesser General Public
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 //
23 // Contact: phyloxml @ gmail . com
24 // WWW: https://sites.google.com/site/cmzmasek/home/software/forester
25
26 package org.forester.application;
27
28 import java.io.File;
29 import java.io.IOException;
30 import java.text.DecimalFormat;
31 import java.util.ArrayList;
32 import java.util.List;
33 import java.util.SortedMap;
34 import java.util.regex.Pattern;
35 import java.util.regex.PatternSyntaxException;
36
37 import org.forester.clade_analysis.AnalysisMulti;
38 import org.forester.clade_analysis.Prefix;
39 import org.forester.clade_analysis.ResultMulti;
40 import org.forester.io.parsers.PhylogenyParser;
41 import org.forester.io.parsers.util.ParserUtils;
42 import org.forester.phylogeny.Phylogeny;
43 import org.forester.phylogeny.factories.ParserBasedPhylogenyFactory;
44 import org.forester.phylogeny.factories.PhylogenyFactory;
45 import org.forester.util.BasicTable;
46 import org.forester.util.BasicTableParser;
47 import org.forester.util.CommandLineArguments;
48 import org.forester.util.EasyWriter;
49 import org.forester.util.ForesterUtil;
50 import org.forester.util.UserException;
51
52 public final class cladinator {
53
54     final static private String        PRG_NAME                             = "cladinator";
55     final static private String        PRG_VERSION                          = "1.07";
56     final static private String        PRG_DATE                             = "1711xx";
57     final static private String        PRG_DESC                             = "clades within clades of annotated labels -- analysis of pplacer-type outputs";
58     final static private String        E_MAIL                               = "phyloxml@gmail.com";
59     final static private String        WWW                                  = "https://sites.google.com/site/cmzmasek/home/software/forester";
60     final static private String        HELP_OPTION_1                        = "help";
61     final static private String        HELP_OPTION_2                        = "h";
62     final static private String        SEP_OPTION                           = "s";
63     final static private String        QUERY_PATTERN_OPTION                 = "q";
64     final static private String        SPECIFICS_CUTOFF_OPTION              = "c";
65     final static private String        MAPPING_FILE_OPTION                  = "m";
66     final static private String        EXTRA_PROCESSING_OPTION1             = "x";
67     final static private String        EXTRA_PROCESSING1_SEP_OPTION         = "xs";
68     final static private String        EXTRA_PROCESSING1_KEEP_EXTRA_OPTION  = "xk";
69     final static private String        QUIET_OPTION                         = "Q";
70     final static private String        SPECIAL_PROCESSING_OPTION            = "S";
71     final static private String        VERBOSE_OPTION                       = "v";
72     final static private String        REMOVE_ANNOT_SEP_OPTION              = "rs";
73     final static private double        SPECIFICS_CUTOFF_DEFAULT             = 0.7;
74     final static private String        SEP_DEFAULT                          = ".";
75     final static private Pattern       QUERY_PATTERN_DEFAULT                = AnalysisMulti.DEFAULT_QUERY_PATTERN_FOR_PPLACER_TYPE;
76     final static private String        EXTRA_PROCESSING1_SEP_DEFAULT        = "|";
77     final static private boolean       EXTRA_PROCESSING1_KEEP_EXTRA_DEFAULT = false;
78     private final static DecimalFormat df                                   = new DecimalFormat( "0.0###" );
79
80     public static void main( final String args[] ) {
81         try {
82             ForesterUtil.printProgramInformation( PRG_NAME,
83                                                   PRG_DESC,
84                                                   PRG_VERSION,
85                                                   PRG_DATE,
86                                                   E_MAIL,
87                                                   WWW,
88                                                   ForesterUtil.getForesterLibraryInformation() );
89             CommandLineArguments cla = null;
90             try {
91                 cla = new CommandLineArguments( args );
92             }
93             catch ( final Exception e ) {
94                 ForesterUtil.fatalError( PRG_NAME, e.getMessage() );
95             }
96             if ( cla.isOptionSet( HELP_OPTION_1 ) || cla.isOptionSet( HELP_OPTION_2 ) ) {
97                 System.out.println();
98                 print_help();
99                 System.exit( 0 );
100             }
101             if ( ( cla.getNumberOfNames() != 1 ) && ( cla.getNumberOfNames() != 2 ) ) {
102                 print_help();
103                 System.exit( -1 );
104             }
105             final List<String> allowed_options = new ArrayList<String>();
106             allowed_options.add( SEP_OPTION );
107             allowed_options.add( QUERY_PATTERN_OPTION );
108             allowed_options.add( SPECIFICS_CUTOFF_OPTION );
109             allowed_options.add( MAPPING_FILE_OPTION );
110             allowed_options.add( EXTRA_PROCESSING_OPTION1 );
111             allowed_options.add( EXTRA_PROCESSING1_SEP_OPTION );
112             allowed_options.add( EXTRA_PROCESSING1_KEEP_EXTRA_OPTION );
113             allowed_options.add( SPECIAL_PROCESSING_OPTION );
114             allowed_options.add( VERBOSE_OPTION );
115             allowed_options.add( QUIET_OPTION );
116             allowed_options.add( REMOVE_ANNOT_SEP_OPTION );
117             final String dissallowed_options = cla.validateAllowedOptionsAsString( allowed_options );
118             if ( dissallowed_options.length() > 0 ) {
119                 ForesterUtil.fatalError( PRG_NAME, "unknown option(s): " + dissallowed_options );
120             }
121             double cutoff_specifics = SPECIFICS_CUTOFF_DEFAULT;
122             if ( cla.isOptionSet( SPECIFICS_CUTOFF_OPTION ) ) {
123                 if ( cla.isOptionValueSet( SPECIFICS_CUTOFF_OPTION ) ) {
124                     cutoff_specifics = cla.getOptionValueAsDouble( SPECIFICS_CUTOFF_OPTION );
125                     if ( cutoff_specifics < 0 ) {
126                         ForesterUtil.fatalError( PRG_NAME, "cutoff cannot be negative" );
127                     }
128                 }
129                 else {
130                     ForesterUtil.fatalError( PRG_NAME, "no value for cutoff for specifics" );
131                 }
132             }
133             String separator = SEP_DEFAULT;
134             if ( cla.isOptionSet( SEP_OPTION ) ) {
135                 if ( cla.isOptionValueSet( SEP_OPTION ) ) {
136                     separator = cla.getOptionValue( SEP_OPTION );
137                 }
138                 else {
139                     ForesterUtil.fatalError( PRG_NAME, "no value for separator option" );
140                 }
141             }
142             Pattern compiled_query = null;
143             if ( cla.isOptionSet( QUERY_PATTERN_OPTION ) ) {
144                 if ( cla.isOptionValueSet( QUERY_PATTERN_OPTION ) ) {
145                     final String query_str = cla.getOptionValue( QUERY_PATTERN_OPTION );
146                     try {
147                         compiled_query = Pattern.compile( query_str );
148                     }
149                     catch ( final PatternSyntaxException e ) {
150                         ForesterUtil.fatalError( PRG_NAME,
151                                                  "error in regular expression: " + query_str + ": " + e.getMessage() );
152                     }
153                 }
154                 else {
155                     ForesterUtil.fatalError( PRG_NAME, "no value for query pattern option" );
156                 }
157             }
158             File mapping_file = null;
159             if ( cla.isOptionSet( MAPPING_FILE_OPTION ) ) {
160                 if ( cla.isOptionValueSet( MAPPING_FILE_OPTION ) ) {
161                     final String mapping_file_str = cla.getOptionValue( MAPPING_FILE_OPTION );
162                     final String error = ForesterUtil.isReadableFile( mapping_file_str );
163                     if ( !ForesterUtil.isEmpty( error ) ) {
164                         ForesterUtil.fatalError( PRG_NAME, error );
165                     }
166                     mapping_file = new File( mapping_file_str );
167                 }
168                 else {
169                     ForesterUtil.fatalError( PRG_NAME, "no value for mapping file" );
170                 }
171             }
172             final Pattern pattern = ( compiled_query != null ) ? compiled_query : QUERY_PATTERN_DEFAULT;
173             final File intreefile = cla.getFile( 0 );
174             final String error_intreefile = ForesterUtil.isReadableFile( intreefile );
175             if ( !ForesterUtil.isEmpty( error_intreefile ) ) {
176                 ForesterUtil.fatalError( PRG_NAME, error_intreefile );
177             }
178             final File outtablefile;
179             if ( cla.getNumberOfNames() > 1 ) {
180                 outtablefile = cla.getFile( 1 );
181                 final String error_outtablefile = ForesterUtil.isWritableFile( outtablefile );
182                 if ( !ForesterUtil.isEmpty( error_outtablefile ) ) {
183                     ForesterUtil.fatalError( PRG_NAME, error_outtablefile );
184                 }
185             }
186             else {
187                 outtablefile = null;
188             }
189             final BasicTable<String> t;
190             final SortedMap<String, String> map;
191             if ( mapping_file != null ) {
192                 t = BasicTableParser.parse( mapping_file, '\t' );
193                 if ( t.getNumberOfColumns() != 2 ) {
194                     ForesterUtil.fatalError( PRG_NAME,
195                                              "mapping file needs to have 2 tab-separated columns, not "
196                                                      + t.getNumberOfColumns() );
197                 }
198                 map = t.getColumnsAsMap( 0, 1 );
199             }
200             else {
201                 t = null;
202                 map = null;
203             }
204             final boolean extra_processing1;
205             if ( cla.isOptionSet( EXTRA_PROCESSING_OPTION1 ) ) {
206                 extra_processing1 = true;
207             }
208             else {
209                 extra_processing1 = false;
210             }
211             String extra_processing1_sep = EXTRA_PROCESSING1_SEP_DEFAULT;
212             if ( cla.isOptionSet( EXTRA_PROCESSING1_SEP_OPTION ) ) {
213                 if ( !extra_processing1 ) {
214                     ForesterUtil.fatalError( PRG_NAME,
215                                              "extra processing is not enabled, cannot set -"
216                                                      + EXTRA_PROCESSING1_SEP_OPTION + " option" );
217                 }
218                 if ( cla.isOptionValueSet( EXTRA_PROCESSING1_SEP_OPTION ) ) {
219                     extra_processing1_sep = cla.getOptionValue( EXTRA_PROCESSING1_SEP_OPTION );
220                 }
221                 else {
222                     ForesterUtil.fatalError( PRG_NAME, "no value for extra processing separator" );
223                 }
224             }
225             if ( ( extra_processing1_sep != null ) && extra_processing1_sep.equals( separator ) ) {
226                 ForesterUtil.fatalError( PRG_NAME,
227                                          "extra processing separator must not be the same the annotation-separator" );
228             }
229             boolean extra_processing1_keep = EXTRA_PROCESSING1_KEEP_EXTRA_DEFAULT;
230             if ( cla.isOptionSet( EXTRA_PROCESSING1_KEEP_EXTRA_OPTION ) ) {
231                 if ( !extra_processing1 ) {
232                     ForesterUtil.fatalError( PRG_NAME,
233                                              "extra processing is not enabled, cannot set -"
234                                                      + EXTRA_PROCESSING1_KEEP_EXTRA_OPTION + " option" );
235                 }
236                 extra_processing1_keep = true;
237             }
238             Pattern special_pattern = null;
239             boolean special_processing = false;
240             if ( cla.isOptionSet( SPECIAL_PROCESSING_OPTION ) ) {
241                 if ( extra_processing1 == true ) {
242                     ForesterUtil
243                             .fatalError( PRG_NAME,
244                                          "extra processing cannot be used together with special processing pattern" );
245                 }
246                 if ( cla.isOptionValueSet( SPECIAL_PROCESSING_OPTION ) ) {
247                     final String str = cla.getOptionValue( SPECIAL_PROCESSING_OPTION );
248                     try {
249                         special_pattern = Pattern.compile( str );
250                     }
251                     catch ( final PatternSyntaxException e ) {
252                         ForesterUtil
253                                 .fatalError( PRG_NAME,
254                                              "error in special processing pattern: " + str + ": " + e.getMessage() );
255                     }
256                     special_processing = true;
257                 }
258                 else {
259                     ForesterUtil.fatalError( PRG_NAME, "no value for special processing pattern" );
260                 }
261             }
262             final boolean remove_annotation_sep;
263             if ( cla.isOptionSet( REMOVE_ANNOT_SEP_OPTION ) ) {
264                 remove_annotation_sep = true;
265             }
266             else {
267                 remove_annotation_sep = false;
268             }
269             final boolean verbose;
270             if ( cla.isOptionSet( VERBOSE_OPTION ) ) {
271                 verbose = true;
272             }
273             else {
274                 verbose = false;
275             }
276             final boolean quit;
277             if ( cla.isOptionSet( QUIET_OPTION ) ) {
278                 quit = true;
279             }
280             else {
281                 quit = false;
282             }
283             System.out.println( "Input tree                 : " + intreefile );
284             System.out.println( "Specific-hit support cutoff: " + cutoff_specifics );
285             if ( mapping_file != null ) {
286                 System.out.println( "Mapping file               : " + mapping_file + " (" + t.getNumberOfRows()
287                         + " rows)" );
288             }
289             System.out.println( "Annotation-separator       : " + separator );
290             if ( remove_annotation_sep ) {
291                 System.out.println( "Remove anno.-sep. in output: " + remove_annotation_sep );
292             }
293             System.out.println( "Query pattern              : " + pattern );
294             if ( extra_processing1 ) {
295                 System.out.println( "Extra processing           : " + extra_processing1 );
296                 System.out.println( "Extra processing separator : " + extra_processing1_sep );
297                 System.out.println( "Keep extra annotations     : " + extra_processing1_keep );
298             }
299             if ( special_processing ) {
300                 System.out.println( "Special processing         : " + special_processing );
301                 System.out.println( "Special processing pattern : " + special_pattern );
302             }
303             if ( outtablefile != null ) {
304                 System.out.println( "Output table               : " + outtablefile );
305             }
306             Phylogeny phys[] = null;
307             try {
308                 final PhylogenyFactory factory = ParserBasedPhylogenyFactory.getInstance();
309                 final PhylogenyParser pp = ParserUtils.createParserDependingOnFileType( intreefile, true );
310                 phys = factory.create( intreefile, pp );
311             }
312             catch ( final IOException e ) {
313                 ForesterUtil.fatalError( PRG_NAME, "Could not read \"" + intreefile + "\" [" + e.getMessage() + "]" );
314             }
315             if ( phys.length == 0 ) {
316                 ForesterUtil.fatalError( PRG_NAME, "\"" + intreefile + "\" does not contain any trees" );
317             }
318             System.out.println( "Number of input trees      : " + phys.length );
319             if ( phys.length == 1 ) {
320                 System.out.println( "Ext. nodes in input tree   : " + phys[ 0 ].getNumberOfExternalNodes() );
321             }
322             else {
323                 System.out.println( "Ext. nodes in input tree 1 : " + phys[ 0 ].getNumberOfExternalNodes() );
324             }
325             final EasyWriter outtable_writer;
326             if ( outtablefile != null ) {
327                 outtable_writer = ForesterUtil.createEasyWriter( outtablefile );
328                 outtable_writer.print( "#" + PRG_NAME + " " + PRG_VERSION + " " + PRG_DATE );
329                 outtable_writer.print( " Input tree: " + intreefile );
330                 outtable_writer.println( " Specific-hit support cutoff: " + cutoff_specifics );
331             }
332             else {
333                 outtable_writer = null;
334             }
335             int counter = 0;
336             for( final Phylogeny phy : phys ) {
337                 if ( map != null ) {
338                     AnalysisMulti.performMapping( pattern, map, phy, verbose );
339                 }
340                 if ( extra_processing1 ) {
341                     AnalysisMulti.performExtraProcessing1( pattern,
342                                                            phy,
343                                                            extra_processing1_sep,
344                                                            extra_processing1_keep,
345                                                            separator,
346                                                            verbose );
347                 }
348                 else if ( special_processing ) {
349                     AnalysisMulti.performSpecialProcessing1( pattern, phy, separator, special_pattern, verbose );
350                 }
351                 final ResultMulti res = AnalysisMulti.execute( phy, pattern, separator, cutoff_specifics );
352                 if ( !quit ) {
353                     if ( phys.length == 1 ) {
354                         printResult( res, -1, remove_annotation_sep );
355                     }
356                     else {
357                         printResult( res, counter, remove_annotation_sep );
358                     }
359                 }
360                 if ( outtable_writer != null ) {
361                     writeResultToTable( res, outtable_writer, remove_annotation_sep );
362                     outtable_writer.flush();
363                 }
364                 ++counter;
365             }
366             if ( outtable_writer != null ) {
367                 outtable_writer.flush();
368                 outtable_writer.close();
369             }
370         }
371         catch ( final UserException e ) {
372             ForesterUtil.fatalError( PRG_NAME, e.getMessage() );
373         }
374         catch ( final IOException e ) {
375             ForesterUtil.fatalError( PRG_NAME, e.getMessage() );
376         }
377         catch ( final Exception e ) {
378             e.printStackTrace();
379             ForesterUtil.fatalError( PRG_NAME, "Unexpected errror!" );
380         }
381     }
382
383     private final static void printResult( final ResultMulti res,
384                                            final int counter,
385                                            final boolean remove_annotation_sep ) {
386         System.out.println();
387         if ( counter == -1 ) {
388             System.out.println( "Result for " + res.getQueryNamePrefix() );
389         }
390         else {
391             System.out.println( "Result for " + res.getQueryNamePrefix() + " [tree " + counter + "]" );
392         }
393         if ( ( res.getAllMultiHitPrefixes() == null ) | ( res.getAllMultiHitPrefixes().size() < 1 ) ) {
394             System.out.println( " No match to query pattern!" );
395         }
396         else {
397             System.out.println( " Matching Clade(s):" );
398             for( final Prefix prefix : res.getCollapsedMultiHitPrefixes() ) {
399                 if ( remove_annotation_sep ) {
400                     System.out.println( " " + prefix.toStringRemovSeparator() );
401                 }
402                 else {
403                     System.out.println( " " + prefix );
404                 }
405             }
406             if ( res.isHasSpecificMultiHitsPrefixes() ) {
407                 System.out.println();
408                 System.out.println( " Specific-hit(s):" );
409                 for( final Prefix prefix : res.getSpecificMultiHitPrefixes() ) {
410                     if ( remove_annotation_sep ) {
411                         System.out.println( " " + prefix.toStringRemovSeparator() );
412                     }
413                     else {
414                         System.out.println( " " + prefix );
415                     }
416                 }
417                 System.out.println();
418                 System.out.println( " Matching Clade(s) with Specific-hit(s):" );
419                 for( final Prefix prefix : res.getCollapsedMultiHitPrefixes() ) {
420                     if ( remove_annotation_sep ) {
421                         System.out.println( " " + prefix.toStringRemovSeparator() );
422                     }
423                     else {
424                         System.out.println( " " + prefix );
425                     }
426                     for( final Prefix spec : res.getSpecificMultiHitPrefixes() ) {
427                         if ( spec.getPrefix().startsWith( prefix.getPrefix() ) ) {
428                             if ( remove_annotation_sep ) {
429                                 System.out.println( "     " + spec.toStringRemovSeparator() );
430                             }
431                             else {
432                                 System.out.println( "     " + spec );
433                             }
434                         }
435                     }
436                 }
437             }
438             if ( !ForesterUtil.isEmpty( res.getAllMultiHitPrefixesDown() ) ) {
439                 System.out.println();
440                 System.out.println( " Matching Down-tree Bracketing Clade(s):" );
441                 for( final Prefix prefix : res.getCollapsedMultiHitPrefixesDown() ) {
442                     if ( remove_annotation_sep ) {
443                         System.out.println( " " + prefix.toStringRemovSeparator() );
444                     }
445                     else {
446                         System.out.println( " " + prefix );
447                     }
448                 }
449             }
450             if ( !ForesterUtil.isEmpty( res.getAllMultiHitPrefixesUp() ) ) {
451                 System.out.println();
452                 System.out.println( " Matching Up-tree Bracketing Clade(s):" );
453                 for( final Prefix prefix : res.getCollapsedMultiHitPrefixesUp() ) {
454                     if ( remove_annotation_sep ) {
455                         System.out.println( " " + prefix.toStringRemovSeparator() );
456                     }
457                     else {
458                         System.out.println( " " + prefix );
459                     }
460                 }
461             }
462             System.out.println();
463             System.out.println( " Total Number of Matches: " + res.getNumberOfMatches() + "/"
464                     + res.getReferenceTreeNumberOfExternalNodes() );
465         }
466         System.out.println();
467     }
468
469     private final static void writeResultToTable( final ResultMulti res,
470                                                   final EasyWriter w,
471                                                   final boolean remove_annotation_sep )
472             throws IOException {
473         if ( ( res.getAllMultiHitPrefixes() == null ) | ( res.getAllMultiHitPrefixes().size() < 1 ) ) {
474             w.print( res.getQueryNamePrefix() );
475             w.print( "\t" );
476             w.println( "No match to query pattern!" );
477         }
478         else {
479             for( final Prefix prefix : res.getCollapsedMultiHitPrefixes() ) {
480                 w.print( res.getQueryNamePrefix() );
481                 w.print( "\t" );
482                 w.print( "Matching Clades" );
483                 w.print( "\t" );
484                 if ( remove_annotation_sep ) {
485                     w.print( prefix.getPrefixRemovSeparator() );
486                 }
487                 else {
488                     w.print( prefix.getPrefix() );
489                 }
490                 w.print( "\t" );
491                 w.print( df.format( prefix.getConfidence() ) );
492                 w.print( "\t" );
493                 w.print( String.valueOf( res.getNumberOfMatches() ) );
494                 w.print( "\t" );
495                 w.print( String.valueOf( res.getReferenceTreeNumberOfExternalNodes() ) );
496                 w.println();
497             }
498             if ( res.isHasSpecificMultiHitsPrefixes() ) {
499                 for( final Prefix prefix : res.getSpecificMultiHitPrefixes() ) {
500                     w.print( res.getQueryNamePrefix() );
501                     w.print( "\t" );
502                     w.print( "Specific-hits" );
503                     w.print( "\t" );
504                     if ( remove_annotation_sep ) {
505                         w.print( prefix.getPrefixRemovSeparator() );
506                     }
507                     else {
508                         w.print( prefix.getPrefix() );
509                     }
510                     w.print( "\t" );
511                     w.print( df.format( prefix.getConfidence() ) );
512                     w.print( "\t" );
513                     w.print( String.valueOf( res.getNumberOfMatches() ) );
514                     w.print( "\t" );
515                     w.print( String.valueOf( res.getReferenceTreeNumberOfExternalNodes() ) );
516                     w.println();
517                 }
518             }
519             if ( !ForesterUtil.isEmpty( res.getAllMultiHitPrefixesDown() ) ) {
520                 for( final Prefix prefix : res.getCollapsedMultiHitPrefixesDown() ) {
521                     w.print( res.getQueryNamePrefix() );
522                     w.print( "\t" );
523                     w.print( "Matching Down-tree Bracketing Clades" );
524                     w.print( "\t" );
525                     if ( remove_annotation_sep ) {
526                         w.print( prefix.getPrefixRemovSeparator() );
527                     }
528                     else {
529                         w.print( prefix.getPrefix() );
530                     }
531                     w.print( "\t" );
532                     w.print( df.format( prefix.getConfidence() ) );
533                     w.print( "\t" );
534                     w.print( String.valueOf( res.getNumberOfMatches() ) );
535                     w.print( "\t" );
536                     w.print( String.valueOf( res.getReferenceTreeNumberOfExternalNodes() ) );
537                     w.println();
538                 }
539             }
540             if ( !ForesterUtil.isEmpty( res.getAllMultiHitPrefixesUp() ) ) {
541                 for( final Prefix prefix : res.getCollapsedMultiHitPrefixesUp() ) {
542                     w.print( res.getQueryNamePrefix() );
543                     w.print( "\t" );
544                     w.print( "Matching Up-tree Bracketing Clades" );
545                     w.print( "\t" );
546                     if ( remove_annotation_sep ) {
547                         w.print( prefix.getPrefixRemovSeparator() );
548                     }
549                     else {
550                         w.print( prefix.getPrefix() );
551                     }
552                     w.print( "\t" );
553                     w.print( df.format( prefix.getConfidence() ) );
554                     w.print( "\t" );
555                     w.print( String.valueOf( res.getNumberOfMatches() ) );
556                     w.print( "\t" );
557                     w.print( String.valueOf( res.getReferenceTreeNumberOfExternalNodes() ) );
558                     w.println();
559                 }
560             }
561         }
562     }
563
564     private final static void print_help() {
565         System.out.println( "Usage:" );
566         System.out.println();
567         System.out.println( PRG_NAME + " [options] <input tree(s) file> [output table file]" );
568         System.out.println();
569         System.out.println( " options:" );
570         System.out.println( "  -" + SPECIFICS_CUTOFF_OPTION
571                 + "=<double>        : the minimal confidence value for \"specific-hits\" to be reported (default: "
572                 + SPECIFICS_CUTOFF_DEFAULT + ")" );
573         System.out.println( "  -" + SEP_OPTION + "=<separator>     : the annotation-separator to be used (default: \""
574                 + SEP_DEFAULT + "\")" );
575         System.out.println( "  -" + MAPPING_FILE_OPTION
576                 + "=<mapping table> : to map node names to appropriate annotations (tab-separated, two columns) (default: no mapping)" );
577         System.out.println( "  -" + EXTRA_PROCESSING_OPTION1
578                 + "                 : to enable extra processing of annotations (e.g. \"Q16611|A.1.1\" becomes \"A.1.1\")" );
579         System.out.println( "  -" + EXTRA_PROCESSING1_SEP_OPTION
580                 + "=<separator>    : the separator for extra annotations (default: \"" + EXTRA_PROCESSING1_SEP_DEFAULT
581                 + "\")" );
582         System.out.println( "  -" + EXTRA_PROCESSING1_KEEP_EXTRA_OPTION
583                 + "                : to keep extra annotations (e.g. \"Q16611|A.1.1\" becomes \"A.1.1.Q16611\")" );
584         System.out.println( "  -" + SPECIAL_PROCESSING_OPTION
585                 + "=<pattern>       : special processing with pattern (e.g. \"(\\d+)([a-z]+)_.+\" for changing \"6q_EF42\" to \"6.q\")" );
586         System.out.println( "  -" + REMOVE_ANNOT_SEP_OPTION
587                 + "                : to remove the annotation-separator in the output (e.g. the \"" + SEP_DEFAULT
588                 + "\")" );
589         System.out.println( "  -" + VERBOSE_OPTION + "                 : verbose" );
590         System.out.println( "  -" + QUIET_OPTION
591                 + "                 : quiet (no output to console, for when used in a pipeline)" );
592         System.out.println( "  --" + QUERY_PATTERN_OPTION
593                 + "=<pattern>      : expert option: the regular expression pattern for the query (default: \""
594                 + QUERY_PATTERN_DEFAULT + "\" for pplacer output)" );
595         System.out.println();
596         System.out.println( "Examples:" );
597         System.out.println();
598         System.out.println( " " + PRG_NAME + " pp_out_tree.sing.tre result.tsv" );
599         System.out.println( " " + PRG_NAME + " -c=0.5 -s=. pp_out_tree.sing.tre result.tsv" );
600         System.out.println( " " + PRG_NAME + " -c=0.9 -s=_ -m=map.tsv pp_out_trees.sing.tre result.tsv" );
601         System.out.println( " " + PRG_NAME + " -x -xs=& -xk pp_out_trees.sing.tre result.tsv" );
602         System.out.println( " " + PRG_NAME + " -x -xs=\"|\" pp_out_trees.sing.tre result.tsv" );
603         System.out.println( " " + PRG_NAME + " -x -xk -m=map.tsv pp_out_trees.sing.tre result.tsv" );
604         System.out.println( " " + PRG_NAME + " -m=map.tsv -S='(\\d+)([a-z?]*)_.+' pp_out_trees.sing.tre result.tsv" );
605         System.out.println();
606     }
607 }