capitalisation
[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.05";
56     final static private String        PRG_DATE                             = "170920";
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 double        SPECIFICS_CUTOFF_DEFAULT             = 0.8;
73     final static private String        SEP_DEFAULT                          = ".";
74     final static private Pattern       QUERY_PATTERN_DEFAULT                = AnalysisMulti.DEFAULT_QUERY_PATTERN_FOR_PPLACER_TYPE;
75     final static private String        EXTRA_PROCESSING1_SEP_DEFAULT        = "|";
76     final static private boolean       EXTRA_PROCESSING1_KEEP_EXTRA_DEFAULT = false;
77     private final static DecimalFormat df                                   = new DecimalFormat( "0.0###" );
78
79     public static void main( final String args[] ) {
80         try {
81             ForesterUtil.printProgramInformation( PRG_NAME,
82                                                   PRG_DESC,
83                                                   PRG_VERSION,
84                                                   PRG_DATE,
85                                                   E_MAIL,
86                                                   WWW,
87                                                   ForesterUtil.getForesterLibraryInformation() );
88             CommandLineArguments cla = null;
89             try {
90                 cla = new CommandLineArguments( args );
91             }
92             catch ( final Exception e ) {
93                 ForesterUtil.fatalError( PRG_NAME, e.getMessage() );
94             }
95             if ( cla.isOptionSet( HELP_OPTION_1 ) || cla.isOptionSet( HELP_OPTION_2 ) ) {
96                 System.out.println();
97                 print_help();
98                 System.exit( 0 );
99             }
100             if ( ( cla.getNumberOfNames() != 1 ) && ( cla.getNumberOfNames() != 2 ) ) {
101                 print_help();
102                 System.exit( -1 );
103             }
104             final List<String> allowed_options = new ArrayList<>();
105             allowed_options.add( SEP_OPTION );
106             allowed_options.add( QUERY_PATTERN_OPTION );
107             allowed_options.add( SPECIFICS_CUTOFF_OPTION );
108             allowed_options.add( MAPPING_FILE_OPTION );
109             allowed_options.add( EXTRA_PROCESSING_OPTION1 );
110             allowed_options.add( EXTRA_PROCESSING1_SEP_OPTION );
111             allowed_options.add( EXTRA_PROCESSING1_KEEP_EXTRA_OPTION );
112             allowed_options.add( SPECIAL_PROCESSING_OPTION );
113             allowed_options.add( VERBOSE_OPTION );
114             allowed_options.add( QUIET_OPTION );
115             final String dissallowed_options = cla.validateAllowedOptionsAsString( allowed_options );
116             if ( dissallowed_options.length() > 0 ) {
117                 ForesterUtil.fatalError( PRG_NAME, "unknown option(s): " + dissallowed_options );
118             }
119             double cutoff_specifics = SPECIFICS_CUTOFF_DEFAULT;
120             if ( cla.isOptionSet( SPECIFICS_CUTOFF_OPTION ) ) {
121                 if ( cla.isOptionValueSet( SPECIFICS_CUTOFF_OPTION ) ) {
122                     cutoff_specifics = cla.getOptionValueAsDouble( SPECIFICS_CUTOFF_OPTION );
123                     if ( cutoff_specifics < 0 ) {
124                         ForesterUtil.fatalError( PRG_NAME, "cutoff cannot be negative" );
125                     }
126                 }
127                 else {
128                     ForesterUtil.fatalError( PRG_NAME, "no value for cutoff for specifics" );
129                 }
130             }
131             String separator = SEP_DEFAULT;
132             if ( cla.isOptionSet( SEP_OPTION ) ) {
133                 if ( cla.isOptionValueSet( SEP_OPTION ) ) {
134                     separator = cla.getOptionValue( SEP_OPTION );
135                 }
136                 else {
137                     ForesterUtil.fatalError( PRG_NAME, "no value for separator option" );
138                 }
139             }
140             Pattern compiled_query = null;
141             if ( cla.isOptionSet( QUERY_PATTERN_OPTION ) ) {
142                 if ( cla.isOptionValueSet( QUERY_PATTERN_OPTION ) ) {
143                     final String query_str = cla.getOptionValue( QUERY_PATTERN_OPTION );
144                     try {
145                         compiled_query = Pattern.compile( query_str );
146                     }
147                     catch ( final PatternSyntaxException e ) {
148                         ForesterUtil.fatalError( PRG_NAME,
149                                                  "error in regular expression: " + query_str + ": " + e.getMessage() );
150                     }
151                 }
152                 else {
153                     ForesterUtil.fatalError( PRG_NAME, "no value for query pattern option" );
154                 }
155             }
156             File mapping_file = null;
157             if ( cla.isOptionSet( MAPPING_FILE_OPTION ) ) {
158                 if ( cla.isOptionValueSet( MAPPING_FILE_OPTION ) ) {
159                     final String mapping_file_str = cla.getOptionValue( MAPPING_FILE_OPTION );
160                     final String error = ForesterUtil.isReadableFile( mapping_file_str );
161                     if ( !ForesterUtil.isEmpty( error ) ) {
162                         ForesterUtil.fatalError( PRG_NAME, error );
163                     }
164                     mapping_file = new File( mapping_file_str );
165                 }
166                 else {
167                     ForesterUtil.fatalError( PRG_NAME, "no value for mapping file" );
168                 }
169             }
170             final Pattern pattern = ( compiled_query != null ) ? compiled_query : QUERY_PATTERN_DEFAULT;
171             final File intreefile = cla.getFile( 0 );
172             final String error_intreefile = ForesterUtil.isReadableFile( intreefile );
173             if ( !ForesterUtil.isEmpty( error_intreefile ) ) {
174                 ForesterUtil.fatalError( PRG_NAME, error_intreefile );
175             }
176             final File outtablefile;
177             if ( cla.getNumberOfNames() > 1 ) {
178                 outtablefile = cla.getFile( 1 );
179                 final String error_outtablefile = ForesterUtil.isWritableFile( outtablefile );
180                 if ( !ForesterUtil.isEmpty( error_outtablefile ) ) {
181                     ForesterUtil.fatalError( PRG_NAME, error_outtablefile );
182                 }
183             }
184             else {
185                 outtablefile = null;
186             }
187             final BasicTable<String> t;
188             final SortedMap<String, String> map;
189             if ( mapping_file != null ) {
190                 t = BasicTableParser.parse( mapping_file, '\t' );
191                 if ( t.getNumberOfColumns() != 2 ) {
192                     ForesterUtil.fatalError( PRG_NAME,
193                                              "mapping file needs to have 2 tab-separated columns, not "
194                                                      + t.getNumberOfColumns() );
195                 }
196                 map = t.getColumnsAsMap( 0, 1 );
197             }
198             else {
199                 t = null;
200                 map = null;
201             }
202             final boolean extra_processing1;
203             if ( cla.isOptionSet( EXTRA_PROCESSING_OPTION1 ) ) {
204                 extra_processing1 = true;
205             }
206             else {
207                 extra_processing1 = false;
208             }
209             String extra_processing1_sep = EXTRA_PROCESSING1_SEP_DEFAULT;
210             if ( cla.isOptionSet( EXTRA_PROCESSING1_SEP_OPTION ) ) {
211                 if ( !extra_processing1 ) {
212                     ForesterUtil.fatalError( PRG_NAME,
213                                              "extra processing is not enabled, cannot set -"
214                                                      + EXTRA_PROCESSING1_SEP_OPTION + " option" );
215                 }
216                 if ( cla.isOptionValueSet( EXTRA_PROCESSING1_SEP_OPTION ) ) {
217                     extra_processing1_sep = cla.getOptionValue( EXTRA_PROCESSING1_SEP_OPTION );
218                 }
219                 else {
220                     ForesterUtil.fatalError( PRG_NAME, "no value for extra processing separator" );
221                 }
222             }
223             if ( ( extra_processing1_sep != null ) && extra_processing1_sep.equals( separator ) ) {
224                 ForesterUtil.fatalError( PRG_NAME,
225                                          "extra processing separator must not be the same the annotation-separator" );
226             }
227             boolean extra_processing1_keep = EXTRA_PROCESSING1_KEEP_EXTRA_DEFAULT;
228             if ( cla.isOptionSet( EXTRA_PROCESSING1_KEEP_EXTRA_OPTION ) ) {
229                 if ( !extra_processing1 ) {
230                     ForesterUtil.fatalError( PRG_NAME,
231                                              "extra processing is not enabled, cannot set -"
232                                                      + EXTRA_PROCESSING1_KEEP_EXTRA_OPTION + " option" );
233                 }
234                 extra_processing1_keep = true;
235             }
236             Pattern special_pattern = null;
237             boolean special_processing = false;
238             if ( cla.isOptionSet( SPECIAL_PROCESSING_OPTION ) ) {
239                 if ( extra_processing1 == true ) {
240                     ForesterUtil
241                             .fatalError( PRG_NAME,
242                                          "extra processing cannot be used together with special processing pattern" );
243                 }
244                 if ( cla.isOptionValueSet( SPECIAL_PROCESSING_OPTION ) ) {
245                     final String str = cla.getOptionValue( SPECIAL_PROCESSING_OPTION );
246                     try {
247                         special_pattern = Pattern.compile( str );
248                     }
249                     catch ( final PatternSyntaxException e ) {
250                         ForesterUtil
251                                 .fatalError( PRG_NAME,
252                                              "error in special processing pattern: " + str + ": " + e.getMessage() );
253                     }
254                     special_processing = true;
255                 }
256                 else {
257                     ForesterUtil.fatalError( PRG_NAME, "no value for special processing pattern" );
258                 }
259             }
260             final boolean verbose;
261             if ( cla.isOptionSet( VERBOSE_OPTION ) ) {
262                 verbose = true;
263             }
264             else {
265                 verbose = false;
266             }
267             final boolean quit;
268             if ( cla.isOptionSet( QUIET_OPTION ) ) {
269                 quit = true;
270             }
271             else {
272                 quit = false;
273             }
274             System.out.println( "Input tree                 : " + intreefile );
275             System.out.println( "Specific-hit support cutoff: " + cutoff_specifics );
276             if ( mapping_file != null ) {
277                 System.out.println( "Mapping file               : " + mapping_file + " (" + t.getNumberOfRows()
278                         + " rows)" );
279             }
280             System.out.println( "Annotation-separator       : " + separator );
281             System.out.println( "Query pattern              : " + pattern );
282             if ( extra_processing1 ) {
283                 System.out.println( "Extra processing           : " + extra_processing1 );
284                 System.out.println( "Extra processing separator : " + extra_processing1_sep );
285                 System.out.println( "Keep extra annotations     : " + extra_processing1_keep );
286             }
287             if ( special_processing ) {
288                 System.out.println( "Special processing         : " + special_processing );
289                 System.out.println( "Special processing pattern : " + special_pattern );
290             }
291             if ( outtablefile != null ) {
292                 System.out.println( "Output table               : " + outtablefile );
293             }
294             Phylogeny phys[] = null;
295             try {
296                 final PhylogenyFactory factory = ParserBasedPhylogenyFactory.getInstance();
297                 final PhylogenyParser pp = ParserUtils.createParserDependingOnFileType( intreefile, true );
298                 phys = factory.create( intreefile, pp );
299             }
300             catch ( final IOException e ) {
301                 ForesterUtil.fatalError( PRG_NAME, "Could not read \"" + intreefile + "\" [" + e.getMessage() + "]" );
302             }
303             if ( phys.length == 0 ) {
304                 ForesterUtil.fatalError( PRG_NAME, "\"" + intreefile + "\" does not contain any trees" );
305             }
306             System.out.println( "Number of input trees      : " + phys.length );
307             if ( phys.length == 1 ) {
308                 System.out.println( "Ext. nodes in input tree   : " + phys[ 0 ].getNumberOfExternalNodes() );
309             }
310             else {
311                 System.out.println( "Ext. nodes in input tree 1 : " + phys[ 0 ].getNumberOfExternalNodes() );
312             }
313             final EasyWriter outtable_writer;
314             if ( outtablefile != null ) {
315                 outtable_writer = ForesterUtil.createEasyWriter( outtablefile );
316                 outtable_writer.print( "#" + PRG_NAME + " " + PRG_VERSION + " " + PRG_DATE );
317                 outtable_writer.print( " Input tree: " + intreefile );
318                 outtable_writer.println( " Specific-hit support cutoff: " + cutoff_specifics );
319             }
320             else {
321                 outtable_writer = null;
322             }
323             int counter = 0;
324             for( final Phylogeny phy : phys ) {
325                 if ( map != null ) {
326                     AnalysisMulti.performMapping( pattern, map, phy, verbose );
327                 }
328                 if ( extra_processing1 ) {
329                     AnalysisMulti.performExtraProcessing1( pattern,
330                                                            phy,
331                                                            extra_processing1_sep,
332                                                            extra_processing1_keep,
333                                                            separator,
334                                                            verbose );
335                 }
336                 else if ( special_processing ) {
337                     AnalysisMulti.performSpecialProcessing1( pattern, phy, separator, special_pattern, verbose );
338                 }
339                 final ResultMulti res = AnalysisMulti.execute( phy, pattern, separator, cutoff_specifics );
340                 if ( !quit ) {
341                     if ( phys.length == 1 ) {
342                         printResult( res, -1 );
343                     }
344                     else {
345                         printResult( res, counter );
346                     }
347                 }
348                 if ( outtable_writer != null ) {
349                     writeResultToTable( res, outtable_writer );
350                     outtable_writer.flush();
351                 }
352                 ++counter;
353             }
354             if ( outtable_writer != null ) {
355                 outtable_writer.flush();
356                 outtable_writer.close();
357             }
358         }
359         catch ( final UserException e ) {
360             ForesterUtil.fatalError( PRG_NAME, e.getMessage() );
361         }
362         catch ( final IOException e ) {
363             ForesterUtil.fatalError( PRG_NAME, e.getMessage() );
364         }
365         catch ( final Exception e ) {
366             e.printStackTrace();
367             ForesterUtil.fatalError( PRG_NAME, "Unexpected errror!" );
368         }
369     }
370
371     private final static void printResult( final ResultMulti res, final int counter ) {
372         System.out.println();
373         if ( counter == -1 ) {
374             System.out.println( "Result for " + res.getQueryNamePrefix() );
375         }
376         else {
377             System.out.println( "Result for " + res.getQueryNamePrefix() + " [tree " + counter + "]" );
378         }
379         if ( ( res.getAllMultiHitPrefixes() == null ) | ( res.getAllMultiHitPrefixes().size() < 1 ) ) {
380             System.out.println( " No match to query pattern!" );
381         }
382         else {
383             System.out.println( " Matching Clade(s):" );
384             for( final Prefix prefix : res.getCollapsedMultiHitPrefixes() ) {
385                 System.out.println( " " + prefix );
386             }
387             if ( res.isHasSpecificMultiHitsPrefixes() ) {
388                 System.out.println();
389                 System.out.println( " Specific-hit(s):" );
390                 for( final Prefix prefix : res.getSpecificMultiHitPrefixes() ) {
391                     System.out.println( " " + prefix );
392                 }
393                 System.out.println();
394                 System.out.println( " Matching Clade(s) with Specific-hit(s):" );
395                 for( final Prefix prefix : res.getCollapsedMultiHitPrefixes() ) {
396                     System.out.println( " " + prefix );
397                     for( final Prefix spec : res.getSpecificMultiHitPrefixes() ) {
398                         if ( spec.getPrefix().startsWith( prefix.getPrefix() ) ) {
399                             System.out.println( "     " + spec );
400                         }
401                     }
402                 }
403             }
404             if ( !ForesterUtil.isEmpty( res.getAllMultiHitPrefixesDown() ) ) {
405                 System.out.println();
406                 System.out.println( " Matching Down-tree Bracketing Clade(s):" );
407                 for( final Prefix prefix : res.getCollapsedMultiHitPrefixesDown() ) {
408                     System.out.println( " " + prefix );
409                 }
410             }
411             if ( !ForesterUtil.isEmpty( res.getAllMultiHitPrefixesUp() ) ) {
412                 System.out.println();
413                 System.out.println( " Matching Up-tree Bracketing Clade(s):" );
414                 for( final Prefix prefix : res.getCollapsedMultiHitPrefixesUp() ) {
415                     System.out.println( " " + prefix );
416                 }
417             }
418             System.out.println();
419             System.out.println( " Total Number of Matches: " + res.getNumberOfMatches() + "/"
420                     + res.getReferenceTreeNumberOfExternalNodes() );
421         }
422         System.out.println();
423     }
424
425     private final static void writeResultToTable( final ResultMulti res, final EasyWriter w ) throws IOException {
426         if ( ( res.getAllMultiHitPrefixes() == null ) | ( res.getAllMultiHitPrefixes().size() < 1 ) ) {
427             w.print( res.getQueryNamePrefix() );
428             w.print( "\t" );
429             w.println( "No match to query pattern!" );
430         }
431         else {
432             for( final Prefix prefix : res.getCollapsedMultiHitPrefixes() ) {
433                 w.print( res.getQueryNamePrefix() );
434                 w.print( "\t" );
435                 w.print( "Matching Clades" );
436                 w.print( "\t" );
437                 w.print( prefix.getPrefix() );
438                 w.print( "\t" );
439                 w.print( df.format( prefix.getConfidence() ) );
440                 w.print( "\t" );
441                 w.print( String.valueOf( res.getNumberOfMatches() ) );
442                 w.print( "\t" );
443                 w.print( String.valueOf( res.getReferenceTreeNumberOfExternalNodes() ) );
444                 w.println();
445             }
446             if ( res.isHasSpecificMultiHitsPrefixes() ) {
447                 for( final Prefix prefix : res.getSpecificMultiHitPrefixes() ) {
448                     w.print( res.getQueryNamePrefix() );
449                     w.print( "\t" );
450                     w.print( "Specific-hits" );
451                     w.print( "\t" );
452                     w.print( prefix.getPrefix() );
453                     w.print( "\t" );
454                     w.print( df.format( prefix.getConfidence() ) );
455                     w.print( "\t" );
456                     w.print( String.valueOf( res.getNumberOfMatches() ) );
457                     w.print( "\t" );
458                     w.print( String.valueOf( res.getReferenceTreeNumberOfExternalNodes() ) );
459                     w.println();
460                 }
461             }
462             if ( !ForesterUtil.isEmpty( res.getAllMultiHitPrefixesDown() ) ) {
463                 for( final Prefix prefix : res.getCollapsedMultiHitPrefixesDown() ) {
464                     w.print( res.getQueryNamePrefix() );
465                     w.print( "\t" );
466                     w.print( "Matching Down-tree Bracketing Clades" );
467                     w.print( "\t" );
468                     w.print( prefix.getPrefix() );
469                     w.print( "\t" );
470                     w.print( df.format( prefix.getConfidence() ) );
471                     w.print( "\t" );
472                     w.print( String.valueOf( res.getNumberOfMatches() ) );
473                     w.print( "\t" );
474                     w.print( String.valueOf( res.getReferenceTreeNumberOfExternalNodes() ) );
475                     w.println();
476                 }
477             }
478             if ( !ForesterUtil.isEmpty( res.getAllMultiHitPrefixesUp() ) ) {
479                 for( final Prefix prefix : res.getCollapsedMultiHitPrefixesUp() ) {
480                     w.print( res.getQueryNamePrefix() );
481                     w.print( "\t" );
482                     w.print( "Matching Up-tree Bracketing Clades" );
483                     w.print( "\t" );
484                     w.print( prefix.getPrefix() );
485                     w.print( "\t" );
486                     w.print( df.format( prefix.getConfidence() ) );
487                     w.print( "\t" );
488                     w.print( String.valueOf( res.getNumberOfMatches() ) );
489                     w.print( "\t" );
490                     w.print( String.valueOf( res.getReferenceTreeNumberOfExternalNodes() ) );
491                     w.println();
492                 }
493             }
494         }
495     }
496
497     private final static void print_help() {
498         System.out.println( "Usage:" );
499         System.out.println();
500         System.out.println( PRG_NAME + " [options] <input tree(s) file> [output table file]" );
501         System.out.println();
502         System.out.println( " options:" );
503         System.out.println( "  -" + SPECIFICS_CUTOFF_OPTION
504                 + "=<double>        : the minimal confidence value for \"specific-hits\" to be reported (default: "
505                 + SPECIFICS_CUTOFF_DEFAULT + ")" );
506         System.out.println( "  -" + SEP_OPTION + "=<separator>     : the annotation-separator to be used (default: "
507                 + SEP_DEFAULT + ")" );
508         System.out.println( "  -" + MAPPING_FILE_OPTION
509                 + "=<mapping table> : to map node names to appropriate annotations (tab-separated, two columns) (default: no mapping)" );
510         System.out.println( "  -" + EXTRA_PROCESSING_OPTION1
511                 + "                 : to enable extra processing of annotations (e.g. \"Q16611|A.1.1\" becomes \"A.1.1\")" );
512         System.out.println( "  -" + EXTRA_PROCESSING1_SEP_OPTION
513                 + "=<separator>    : the separator for extra annotations (default: \"" + EXTRA_PROCESSING1_SEP_DEFAULT
514                 + "\")" );
515         System.out.println( "  -" + EXTRA_PROCESSING1_KEEP_EXTRA_OPTION
516                 + "                : to keep extra annotations (e.g. \"Q16611|A.1.1\" becomes \"A.1.1.Q16611\")" );
517         System.out.println( "  -" + SPECIAL_PROCESSING_OPTION
518                 + "=<pattern>       : special processing with pattern (e.g. \"(\\d+)([a-z]+)_.+\" for changing \"6q_EF42\" to \"6.q\")" );
519         System.out.println( "  -" + VERBOSE_OPTION + "                 : verbose" );
520         System.out.println( "  -" + QUIET_OPTION + "                 : quiet (for when used in a pipeline)" );
521         System.out.println( "  --" + QUERY_PATTERN_OPTION
522                 + "=<pattern>      : the regular expression pattern for the query (default: \"" + QUERY_PATTERN_DEFAULT
523                 + "\" for pplacer output)" );
524         System.out.println();
525         System.out.println( "Examples:" );
526         System.out.println();
527         System.out.println( " " + PRG_NAME + " pp_out_tree.sing.tre result.tsv" );
528         System.out.println( " " + PRG_NAME + " -c=0.5 -s=. pp_out_tree.sing.tre result.tsv" );
529         System.out.println( " " + PRG_NAME + " -c=0.9 -s=_ -m=map.tsv pp_out_trees.sing.tre result.tsv" );
530         System.out.println( " " + PRG_NAME + " -x -xs=& -xk pp_out_trees.sing.tre result.tsv" );
531         System.out.println( " " + PRG_NAME + " -x -xs=\"|\" pp_out_trees.sing.tre result.tsv" );
532         System.out.println( " " + PRG_NAME + " -x -xk -m=map.tsv pp_out_trees.sing.tre result.tsv" );
533         System.out.println( " " + PRG_NAME + " -m=map.tsv -S='(\\d+)([a-z?]*)_.+' pp_out_trees.sing.tre result.tsv" );
534         System.out.println();
535     }
536 }