inprogress
[jalview.git] / forester / java / src / org / forester / application / phyloxml_converter.java
1 // $Id:
2 //
3 // FORESTER -- software libraries and applications
4 // for evolutionary biology research and applications.
5 //
6 // Copyright (C) 2008-2009 Christian M. Zmasek
7 // Copyright (C) 2008-2009 Burnham Institute for Medical Research
8 // All rights reserved
9 //
10 // This library is free software; you can redistribute it and/or
11 // modify it under the terms of the GNU Lesser General Public
12 // License as published by the Free Software Foundation; either
13 // version 2.1 of the License, or (at your option) any later version.
14 //
15 // This library is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 // Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public
21 // License along with this library; if not, write to the Free Software
22 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 //
24 // Contact: phylosoft @ gmail . com
25 // WWW: https://sites.google.com/site/cmzmasek/home/software/forester
26
27 package org.forester.application;
28
29 import java.io.File;
30 import java.io.IOException;
31 import java.util.ArrayList;
32 import java.util.List;
33
34 import org.forester.io.parsers.PhylogenyParser;
35 import org.forester.io.parsers.nexus.NexusPhylogeniesParser;
36 import org.forester.io.parsers.nhx.NHXParser;
37 import org.forester.io.parsers.phyloxml.PhyloXmlDataFormatException;
38 import org.forester.io.parsers.util.ParserUtils;
39 import org.forester.io.writers.PhylogenyWriter;
40 import org.forester.phylogeny.Phylogeny;
41 import org.forester.phylogeny.PhylogenyMethods;
42 import org.forester.phylogeny.PhylogenyMethods.DESCENDANT_SORT_PRIORITY;
43 import org.forester.phylogeny.PhylogenyNode;
44 import org.forester.phylogeny.factories.ParserBasedPhylogenyFactory;
45 import org.forester.phylogeny.factories.PhylogenyFactory;
46 import org.forester.phylogeny.iterators.PhylogenyNodeIterator;
47 import org.forester.util.CommandLineArguments;
48 import org.forester.util.ForesterUtil;
49
50 public class phyloxml_converter {
51
52     final static private String  HELP_OPTION_1                     = "help";
53     final static private String  HELP_OPTION_2                     = "h";
54     final static private String  FIELD_OPTION                      = "f";
55     final static private String  FIELD_CLADE_NAME                  = "nn";
56     final static private String  FIELD_TAXONOMY_CODE               = "tc";
57     final static private String  FIELD_TAXONOMY_SCI_NAME           = "sn";
58     final static private String  FIELD_TAXONOMY_COMM_NAME          = "cn";
59     final static private String  FIELD_SEQUENCE_GENE_NAME          = "gn";
60     final static private String  FIELD_SEQUENCE_SYMBOL             = "sy";
61     final static private String  FIELD_UNIPROT_TAXONOMY_ID_SPLIT_1 = "i1";
62     final static private String  FIELD_UNIPROT_TAXONOMY_ID_SPLIT_2 = "i2";
63     final static private String  FIELD_DUMMY                       = "dummy";
64     final static private String  INTERNAL_NAMES_ARE_BOOT_SUPPPORT  = "i";
65     final static private String  MIDPOINT_REROOT                   = "m";
66     final static private String  EXTRACT_TAXONOMY                  = "xt";
67     final static private String  EXTRACT_TAXONOMY_PF               = "xp";
68     final static private String  ORDER_SUBTREES                    = "o";
69     final static private String  NO_TREE_LEVEL_INDENDATION         = "ni";
70     final static private String  REPLACE_UNDER_SCORES              = "ru";
71     final static private String  IGNORE_QUOTES                     = "iqs";
72     final static private String  PRG_NAME                          = "phyloxml_converter";
73     final static private String  PRG_VERSION                       = "1.301";
74     final static private String  PRG_DATE                          = "2012.08.31";
75     final static private String  E_MAIL                            = "phylosoft@gmail.com";
76     final static private String  WWW                               = "www.phylosoft.org/forester/";
77     final static private boolean SPECIAL                           = false;
78
79     public static void main( final String args[] ) throws PhyloXmlDataFormatException {
80         ForesterUtil.printProgramInformation( PRG_NAME, PRG_VERSION, PRG_DATE, E_MAIL, WWW );
81         CommandLineArguments cla = null;
82         try {
83             cla = new CommandLineArguments( args );
84         }
85         catch ( final Exception e ) {
86             ForesterUtil.fatalError( PRG_NAME, e.getMessage() );
87         }
88         if ( cla.isOptionSet( HELP_OPTION_1 ) || cla.isOptionSet( HELP_OPTION_2 ) || ( args.length == 0 ) ) {
89             printHelp();
90             System.exit( 0 );
91         }
92         if ( args.length < 3 ) {
93             System.out.println();
94             System.out.println( "[" + PRG_NAME + "] incorrect number of arguments" );
95             System.out.println();
96             printHelp();
97             System.exit( -1 );
98         }
99         final List<String> allowed_options = new ArrayList<String>();
100         allowed_options.add( NO_TREE_LEVEL_INDENDATION );
101         allowed_options.add( FIELD_OPTION );
102         allowed_options.add( MIDPOINT_REROOT );
103         allowed_options.add( ORDER_SUBTREES );
104         allowed_options.add( INTERNAL_NAMES_ARE_BOOT_SUPPPORT );
105         allowed_options.add( REPLACE_UNDER_SCORES );
106         allowed_options.add( EXTRACT_TAXONOMY );
107         allowed_options.add( EXTRACT_TAXONOMY_PF );
108         allowed_options.add( IGNORE_QUOTES );
109         if ( cla.getNumberOfNames() != 2 ) {
110             System.out.println();
111             System.out.println( "[" + PRG_NAME + "] incorrect number of arguments" );
112             System.out.println();
113             printHelp();
114             System.exit( -1 );
115         }
116         final String dissallowed_options = cla.validateAllowedOptionsAsString( allowed_options );
117         if ( dissallowed_options.length() > 0 ) {
118             ForesterUtil.fatalError( PRG_NAME, "unknown option(s): " + dissallowed_options );
119         }
120         final List<String> mandatory_options = new ArrayList<String>();
121         mandatory_options.add( FIELD_OPTION );
122         final String missing_options = cla.validateMandatoryOptionsAsString( mandatory_options );
123         if ( missing_options.length() > 0 ) {
124             ForesterUtil.fatalError( PRG_NAME, "missing option(s): " + missing_options );
125         }
126         if ( !cla.isOptionValueSet( FIELD_OPTION ) ) {
127             System.out.println();
128             printHelp();
129             System.exit( -1 );
130         }
131         final String field_option_value = cla.getOptionValue( FIELD_OPTION );
132         PhylogenyMethods.PhylogenyNodeField field = null;
133         if ( field_option_value.equals( FIELD_CLADE_NAME ) ) {
134             field = PhylogenyMethods.PhylogenyNodeField.CLADE_NAME;
135         }
136         else if ( field_option_value.equals( FIELD_TAXONOMY_CODE ) ) {
137             field = PhylogenyMethods.PhylogenyNodeField.TAXONOMY_CODE;
138         }
139         else if ( field_option_value.equals( FIELD_TAXONOMY_SCI_NAME ) ) {
140             field = PhylogenyMethods.PhylogenyNodeField.TAXONOMY_SCIENTIFIC_NAME;
141         }
142         else if ( field_option_value.equals( FIELD_TAXONOMY_COMM_NAME ) ) {
143             field = PhylogenyMethods.PhylogenyNodeField.TAXONOMY_COMMON_NAME;
144         }
145         else if ( field_option_value.equals( FIELD_SEQUENCE_GENE_NAME ) ) {
146             field = PhylogenyMethods.PhylogenyNodeField.SEQUENCE_NAME;
147         }
148         else if ( field_option_value.equals( FIELD_SEQUENCE_SYMBOL ) ) {
149             field = PhylogenyMethods.PhylogenyNodeField.SEQUENCE_SYMBOL;
150         }
151         else if ( field_option_value.equals( FIELD_UNIPROT_TAXONOMY_ID_SPLIT_1 ) ) {
152             field = PhylogenyMethods.PhylogenyNodeField.TAXONOMY_ID_UNIPROT_1;
153         }
154         else if ( field_option_value.equals( FIELD_UNIPROT_TAXONOMY_ID_SPLIT_2 ) ) {
155             field = PhylogenyMethods.PhylogenyNodeField.TAXONOMY_ID_UNIPROT_2;
156         }
157         else if ( field_option_value.equals( FIELD_DUMMY ) ) {
158         }
159         else {
160             ForesterUtil.fatalError( PRG_NAME, "unknown value for -\"" + FIELD_OPTION + "\" option: \""
161                     + field_option_value + "\"" );
162         }
163         boolean ignore_quotes = false;
164         if ( cla.isOptionSet( IGNORE_QUOTES ) ) {
165             ignore_quotes = true;
166         }
167         boolean int_values_are_boots = false;
168         if ( cla.isOptionSet( INTERNAL_NAMES_ARE_BOOT_SUPPPORT ) ) {
169             int_values_are_boots = true;
170         }
171         boolean midpoint_reroot = false;
172         if ( cla.isOptionSet( MIDPOINT_REROOT ) ) {
173             midpoint_reroot = true;
174         }
175         boolean order_subtrees = false;
176         if ( cla.isOptionSet( ORDER_SUBTREES ) ) {
177             order_subtrees = true;
178         }
179         boolean replace_underscores = false;
180         if ( cla.isOptionSet( REPLACE_UNDER_SCORES ) ) {
181             replace_underscores = true;
182         }
183         boolean no_indendation = false;
184         if ( cla.isOptionSet( NO_TREE_LEVEL_INDENDATION ) ) {
185             no_indendation = true;
186         }
187         boolean extr_taxonomy = false;
188         if ( cla.isOptionSet( EXTRACT_TAXONOMY ) ) {
189             extr_taxonomy = true;
190         }
191         boolean extr_taxonomy_pf_only = false;
192         if ( cla.isOptionSet( EXTRACT_TAXONOMY_PF ) ) {
193             extr_taxonomy_pf_only = true;
194         }
195         final File infile = cla.getFile( 0 );
196         final File outfile = cla.getFile( 1 );
197         if ( outfile.exists() ) {
198             ForesterUtil.fatalError( PRG_NAME, "[" + outfile + "] already exists" );
199         }
200         if ( !infile.exists() ) {
201             ForesterUtil.fatalError( PRG_NAME, "[" + infile + "] does not exist" );
202         }
203         Phylogeny[] phys = null;
204         try {
205             final PhylogenyFactory factory = ParserBasedPhylogenyFactory.getInstance();
206             final PhylogenyParser parser = ParserUtils.createParserDependingOnFileType( infile, true );
207             if ( parser instanceof NHXParser ) {
208                 if ( ( field != PhylogenyMethods.PhylogenyNodeField.TAXONOMY_CODE )
209                         && ( field != PhylogenyMethods.PhylogenyNodeField.TAXONOMY_COMMON_NAME )
210                         && ( field != PhylogenyMethods.PhylogenyNodeField.TAXONOMY_SCIENTIFIC_NAME ) ) {
211                     if ( extr_taxonomy_pf_only ) {
212                         ( ( NHXParser ) parser )
213                                 .setTaxonomyExtraction( NHXParser.TAXONOMY_EXTRACTION.PFAM_STYLE_STRICT );
214                         replace_underscores = false;
215                     }
216                     else if ( extr_taxonomy ) {
217                         ( ( NHXParser ) parser )
218                                 .setTaxonomyExtraction( NHXParser.TAXONOMY_EXTRACTION.PFAM_STYLE_RELAXED );
219                         replace_underscores = false;
220                     }
221                 }
222                 else {
223                     ( ( NHXParser ) parser ).setTaxonomyExtraction( NHXParser.TAXONOMY_EXTRACTION.NO );
224                 }
225                 ( ( NHXParser ) parser ).setReplaceUnderscores( replace_underscores );
226                 ( ( NHXParser ) parser ).setIgnoreQuotes( ignore_quotes );
227             }
228             else if ( parser instanceof NexusPhylogeniesParser ) {
229                 ( ( NexusPhylogeniesParser ) parser ).setReplaceUnderscores( replace_underscores );
230                 ( ( NexusPhylogeniesParser ) parser ).setIgnoreQuotes( false );
231             }
232             phys = factory.create( infile, parser );
233         }
234         catch ( final IOException e ) {
235             ForesterUtil.fatalError( PRG_NAME, "failed to read phylogeny from [" + infile + "]: " + e.getMessage() );
236         }
237         if ( SPECIAL ) {
238             for( final Phylogeny phy : phys ) {
239                 performSpecialProcessing( phy );
240             }
241         }
242         if ( int_values_are_boots ) {
243             for( final Phylogeny phy : phys ) {
244                 PhylogenyMethods.transferInternalNamesToBootstrapSupport( phy );
245             }
246         }
247         if ( field != null ) {
248             for( final Phylogeny phy : phys ) {
249                 PhylogenyMethods.transferNodeNameToField( phy, field, false );
250             }
251         }
252         if ( midpoint_reroot ) {
253             try {
254                 for( final Phylogeny phy : phys ) {
255                     PhylogenyMethods.midpointRoot( phy );
256                 }
257             }
258             catch ( final Exception e ) {
259                 System.out.println( "" );
260                 ForesterUtil.printWarningMessage( PRG_NAME, "midpoint rerooting failed: " + e.getLocalizedMessage() );
261             }
262         }
263         if ( order_subtrees ) {
264             for( final Phylogeny phy : phys ) {
265                 PhylogenyMethods.orderAppearance( phy.getRoot(), true, true, DESCENDANT_SORT_PRIORITY.TAXONOMY );
266                 phy.externalNodesHaveChanged();
267                 phy.clearHashIdToNodeMap();
268                 phy.recalculateNumberOfExternalDescendants( true );
269             }
270         }
271         try {
272             final PhylogenyWriter writer = new PhylogenyWriter();
273             if ( no_indendation ) {
274                 writer.setIndentPhyloxml( false );
275             }
276             writer.toPhyloXML( phys, 0, outfile, ForesterUtil.LINE_SEPARATOR );
277         }
278         catch ( final IOException e ) {
279             ForesterUtil.fatalError( PRG_NAME, "failed to write to [" + outfile + "]: " + e.getMessage() );
280         }
281         System.out.println( "[" + PRG_NAME + "] wrote: [" + outfile + "]" );
282         System.out.println( "[" + PRG_NAME + "] OK" );
283         System.out.println();
284     }
285
286     private static void performSpecialProcessing( final Phylogeny phy ) {
287         // Can place some kind of custom processing here.
288         //        final List<PhylogenyNode> remove_us = new ArrayList<PhylogenyNode>();
289         //        int counter = 0;
290         //        for( final PhylogenyNodeIterator it = phy.iteratorPostorder(); it.hasNext(); ) {
291         //            final PhylogenyNode node = it.next();
292         //            final String name = node.getNodeName().toLowerCase();
293         //            if ( name.startsWith( "environmental_samples" ) || name.startsWith( "unclassified" )
294         //                    || name.startsWith( "bacteria" ) || name.startsWith( "other" )
295         //                    || name.startsWith( "viroids" ) || name.startsWith( "viruses" ) ) {
296         //                remove_us.add( node );
297         //                System.out.println( counter++ );
298         //            }
299         //        }
300         //        phy.hashIDs();
301         //        for( final PhylogenyNode node : remove_us ) {
302         //            if ( phy.getNode( node.getNodeId() ) != null ) {
303         //                phy.deleteSubtree( node );
304         //                System.out.println( "deleted: " + node );
305         //            }
306         //        }
307         //        phy.hashIDs();
308         //
309         //        for( final PhylogenyNodeIterator it = phy.iteratorPostorder(); it.hasNext(); ) {
310         //            final PhylogenyNode node = it.next();
311         //            node.getNodeData().setTaxonomy( null );
312         //        }
313         //        phy.reRoot( phy.getFirstExternalNode() );
314         //        PhylogenyMethods.midpointRoot( phy );
315         //        phy.orderAppearance( true );
316         for( final PhylogenyNodeIterator it = phy.iteratorPostorder(); it.hasNext(); ) {
317             final PhylogenyNode node = it.next();
318             final String name = node.getName();
319             if ( !ForesterUtil.isEmpty( name ) ) {
320                 //                final Taxonomy taxo = new Taxonomy();
321                 //                if ( node.isExternal() ) {
322                 //                    taxo.setTaxonomyCode( name );
323                 //                    node.getNodeData().setTaxonomy( taxo );
324                 //                }
325                 //                else if ( name.indexOf( '_' ) == -1 || name.length() > 6 ) {
326                 //                    taxo.setScientificName( name );
327                 //                    node.getNodeData().setTaxonomy( taxo );
328                 //                }
329                 //                node.setName( "" );
330                 //                if ( name.indexOf( "BF" ) >= 0 ) {
331                 //                    taxo.setTaxonomyCode( "BACFR" );
332                 //                }
333                 //                else if ( name.indexOf( "BT" ) >= 0 ) {
334                 //                    taxo.setTaxonomyCode( "BACTN" );
335                 //                }
336                 //                else if ( name.indexOf( "MXAN" ) >= 0 ) {
337                 //                    taxo.setTaxonomyCode( "MYXXD" );
338                 //                }
339                 //                else if ( name.indexOf( "STIAU" ) >= 0 ) {
340                 //                    taxo.setTaxonomyCode( "STIAU" );
341                 //                }
342                 //                else if ( name.indexOf( "BOVA" ) >= 0 ) {
343                 //                    taxo.setTaxonomyCode( "BACOV" );
344                 //                }
345                 //                else if ( name.indexOf( "BUNI" ) >= 0 ) {
346                 //                    taxo.setTaxonomyCode( "BACUN" );
347                 //                }
348                 //                else if ( name.indexOf( "Pgin" ) >= 0 ) {
349                 //                    taxo.setTaxonomyCode( "PORGI" );
350                 //                }
351                 //                else if ( name.equals( "3CGH" ) || name.equals( "3CK7" ) ) {
352                 //                    taxo.setTaxonomyCode( "BACTN" );
353                 //                }
354                 // node.getNodeData().setTaxonomy( taxo );
355             }
356         }
357     }
358
359     private static void printHelp() {
360         System.out.println( "Usage:" );
361         System.out.println();
362         System.out
363                 .println( PRG_NAME
364                         + " -"
365                         + FIELD_OPTION
366                         + "=<field option> [options] <infile in New Hamphshire, NHX, Nexus, ToL XML, or phyloXML format> <outfile>" );
367         System.out.println();
368         System.out.println( " field options: " );
369         System.out.println();
370         System.out.println( "   " + FIELD_CLADE_NAME + ": transfer name to node/clade name" );
371         System.out.println( "   " + FIELD_TAXONOMY_CODE + ": transfer name to taxonomy code" );
372         System.out.println( "   " + FIELD_TAXONOMY_SCI_NAME + ": transfer name to taxonomy scientific name" );
373         System.out.println( "   " + FIELD_TAXONOMY_COMM_NAME + ": transfer name to taxonomy common name" );
374         System.out.println( "   " + FIELD_SEQUENCE_GENE_NAME + ": transfer name to sequence name" );
375         System.out.println( "   " + FIELD_SEQUENCE_SYMBOL + ": transfer name to sequence symbol" );
376         System.out
377                 .println( "   "
378                         + FIELD_UNIPROT_TAXONOMY_ID_SPLIT_1
379                         + ": transfer/split name to taxonomy uniprot identifier\n       (split at underscore if \"id_name\" pattern, e.g. \"817_SusD\")" );
380         System.out
381                 .println( "   "
382                         + FIELD_UNIPROT_TAXONOMY_ID_SPLIT_2
383                         + ": transfer/split name to taxonomy uniprot identifier\n       (split at underscore if \"name_id\" pattern, e.g. \"SusD_817\")" );
384         System.out.println();
385         System.out.println( " options: " );
386         System.out.println( " -" + INTERNAL_NAMES_ARE_BOOT_SUPPPORT
387                 + "  : internal names in NH or NHX tree are bootstrap support values" );
388         System.out.println( " -" + REPLACE_UNDER_SCORES + " : replace all underscores with spaces" );
389         System.out.println( " -" + MIDPOINT_REROOT + "  : midpoint reroot" );
390         System.out.println( " -" + ORDER_SUBTREES + "  : order subtrees" );
391         System.out
392                 .println( " -"
393                         + EXTRACT_TAXONOMY
394                         + " : extract taxonomy to taxonomy code from \"seqname_TAXON\"-style names (cannot be used with the following field options: "
395                         + FIELD_TAXONOMY_CODE + ", " + FIELD_TAXONOMY_COMM_NAME + ", " + FIELD_TAXONOMY_SCI_NAME + ")" );
396         System.out
397                 .println( " -"
398                         + EXTRACT_TAXONOMY_PF
399                         + " : extract taxonomy to taxonomy code from Pfam (\"seqname_TAXON/x-y\") style names only (cannot be used with the following field options: "
400                         + FIELD_TAXONOMY_CODE + ", " + FIELD_TAXONOMY_COMM_NAME + ", " + FIELD_TAXONOMY_SCI_NAME + ")" );
401         System.out.println( " -" + NO_TREE_LEVEL_INDENDATION + " : no tree level indendation in phyloXML output" );
402         System.out.println( " -" + IGNORE_QUOTES + ": ignore quotes and whitespace (e.g. \"a b\" becomes ab)" );
403         System.out.println();
404     }
405 }