X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=forester%2Fjava%2Fsrc%2Forg%2Fforester%2Fsdi%2FGSDI.java;h=19e2b7dcab13689c5eb5f25703d16f445d7c779e;hb=6005bacbd8aecc0d320b70568a24d321a30bc85c;hp=bbdbb740910d253560ed3678886ba77ecddc5089;hpb=9794a064aff842558c2afd65c884127f33b2fd5e;p=jalview.git diff --git a/forester/java/src/org/forester/sdi/GSDI.java b/forester/java/src/org/forester/sdi/GSDI.java index bbdbb74..19e2b7d 100644 --- a/forester/java/src/org/forester/sdi/GSDI.java +++ b/forester/java/src/org/forester/sdi/GSDI.java @@ -25,11 +25,17 @@ package org.forester.sdi; +import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; import org.forester.phylogeny.Phylogeny; +import org.forester.phylogeny.PhylogenyMethods; import org.forester.phylogeny.PhylogenyNode; import org.forester.phylogeny.data.Event; import org.forester.phylogeny.data.Taxonomy; @@ -58,134 +64,122 @@ import org.forester.util.ForesterUtil; * * @author Christian M. Zmasek */ -public final class GSDI extends SDI { +public class GSDI extends SDI { - private final HashMap _transversal_counts; - private final boolean _most_parsimonious_duplication_model; - private final boolean _strip_gene_tree; - private int _speciation_or_duplication_events_sum; - private int _speciations_sum; + private final boolean _most_parsimonious_duplication_model; + private final boolean _strip_gene_tree; + private final boolean _strip_species_tree; + private int _speciation_or_duplication_events_sum; + private int _speciations_sum; + private final List _stripped_gene_tree_nodes; + private final List _stripped_species_tree_nodes; + private final Set _mapped_species_tree_nodes; + private TaxonomyComparisonBase _tax_comp_base; + private final SortedSet _scientific_names_mapped_to_reduced_specificity; - /** - * Constructor which sets the gene tree and the species tree to be compared. - * species_tree is the species tree to which the gene tree gene_tree will be - * compared to - with method "infer(boolean)". Both Trees must be completely - * binary and rooted. The actual inference is accomplished with method - * "infer(boolean)". The mapping cost L can then be calculated with method - * "computeMappingCost()". - *

- * - * @see #infer(boolean) - * @see SDI#computeMappingCostL() - * @param gene_tree - * reference to a rooted gene tree to which assign duplication vs - * speciation, must have species names in the species name fields - * for all external nodes - * @param species_tree - * reference to a rooted binary species tree which might get - * stripped in the process, must have species names in the - * species name fields for all external nodes - * - * @param most_parsimonious_duplication_model - * set to true to assign nodes as speciations which would - * otherwise be assiged as unknown because of polytomies in the - * species tree. - * - */ public GSDI( final Phylogeny gene_tree, final Phylogeny species_tree, final boolean most_parsimonious_duplication_model, - final boolean strip_gene_tree ) { + final boolean strip_gene_tree, + final boolean strip_species_tree ) throws SDIException { super( gene_tree, species_tree ); _speciation_or_duplication_events_sum = 0; _speciations_sum = 0; _most_parsimonious_duplication_model = most_parsimonious_duplication_model; - _transversal_counts = new HashMap(); _duplications_sum = 0; _strip_gene_tree = strip_gene_tree; - getSpeciesTree().preOrderReId(); + _strip_species_tree = strip_species_tree; + _stripped_gene_tree_nodes = new ArrayList(); + _stripped_species_tree_nodes = new ArrayList(); + _mapped_species_tree_nodes = new HashSet(); + _scientific_names_mapped_to_reduced_specificity = new TreeSet(); linkNodesOfG(); - geneTreePostOrderTraversal( getGeneTree().getRoot() ); + PhylogenyMethods.preOrderReId( getSpeciesTree() ); + geneTreePostOrderTraversal(); } + GSDI( final Phylogeny gene_tree, final Phylogeny species_tree, final boolean most_parsimonious_duplication_model ) + throws SDIException { + this( gene_tree, species_tree, most_parsimonious_duplication_model, false, false ); + } + public GSDI( final Phylogeny gene_tree, final Phylogeny species_tree, - final boolean most_parsimonious_duplication_model ) { - this( gene_tree, species_tree, most_parsimonious_duplication_model, false ); - } - - private final Event createDuplicationEvent() { - final Event event = Event.createSingleDuplicationEvent(); - ++_duplications_sum; - return event; - } - - private final Event createSingleSpeciationOrDuplicationEvent() { - final Event event = Event.createSingleSpeciationOrDuplicationEvent(); - ++_speciation_or_duplication_events_sum; - return event; - } - - private final Event createSpeciationEvent() { - final Event event = Event.createSingleSpeciationEvent(); - ++_speciations_sum; - return event; + final boolean most_parsimonious_duplication_model, + final boolean strip_gene_tree, + final boolean strip_species_tree, + int x ) throws SDIException { + super( gene_tree, species_tree ); + _speciation_or_duplication_events_sum = 0; + _speciations_sum = 0; + _most_parsimonious_duplication_model = most_parsimonious_duplication_model; + _duplications_sum = 0; + _strip_gene_tree = strip_gene_tree; + _strip_species_tree = strip_species_tree; + _stripped_gene_tree_nodes = new ArrayList(); + _stripped_species_tree_nodes = new ArrayList(); + _mapped_species_tree_nodes = new HashSet(); + _scientific_names_mapped_to_reduced_specificity = new TreeSet(); + } // s is the node on the species tree g maps to. private final void determineEvent( final PhylogenyNode s, final PhylogenyNode g ) { - Event event = null; - // Determine how many children map to same node as parent. - int sum_g_childs_mapping_to_s = 0; - for( final PhylogenyNodeIterator iter = g.iterateChildNodesForward(); iter.hasNext(); ) { - if ( iter.next().getLink() == s ) { - ++sum_g_childs_mapping_to_s; - } + boolean oyako = false; + if ( ( g.getChildNode1().getLink() == s ) || ( g.getChildNode2().getLink() == s ) ) { + oyako = true; } - // Determine the sum of traversals. - int traversals_sum = 0; - int max_traversals = 0; - PhylogenyNode max_traversals_node = null; - if ( !s.isExternal() ) { - for( final PhylogenyNodeIterator iter = s.iterateChildNodesForward(); iter.hasNext(); ) { - final PhylogenyNode current_node = iter.next(); - final int traversals = getTraversalCount( current_node ); - traversals_sum += traversals; - if ( traversals > max_traversals ) { - max_traversals = traversals; - max_traversals_node = current_node; - } + if ( g.getLink().getNumberOfDescendants() == 2 ) { + if ( oyako ) { + g.getNodeData().setEvent( createDuplicationEvent() ); } - } - // System.out.println( " sum=" + traversals_sum ); - // System.out.println( " max=" + max_traversals ); - // System.out.println( " m=" + sum_g_childs_mapping_to_s ); - if ( sum_g_childs_mapping_to_s > 0 ) { - if ( traversals_sum == 2 ) { - event = createDuplicationEvent(); + else { + g.getNodeData().setEvent( createSpeciationEvent() ); } - else if ( traversals_sum > 2 ) { - if ( max_traversals <= 1 ) { - if ( _most_parsimonious_duplication_model ) { - event = createSpeciationEvent(); + } + else { + if ( oyako ) { + final Set set = new HashSet(); + for( PhylogenyNode n : g.getChildNode1().getAllExternalDescendants() ) { + n = n.getLink(); + while ( n.getParent() != s ) { + n = n.getParent(); + if ( n.isRoot() ) { + break; + } } - else { - event = createSingleSpeciationOrDuplicationEvent(); + set.add( n ); + } + boolean multiple = false; + for( PhylogenyNode n : g.getChildNode2().getAllExternalDescendants() ) { + n = n.getLink(); + while ( n.getParent() != s ) { + n = n.getParent(); + if ( n.isRoot() ) { + break; + } + } + if ( set.contains( n ) ) { + multiple = true; + break; } } + if ( multiple ) { + g.getNodeData().setEvent( createDuplicationEvent() ); + } else { - event = createDuplicationEvent(); - _transversal_counts.put( max_traversals_node, 1 ); + if ( _most_parsimonious_duplication_model ) { + g.getNodeData().setEvent( createSpeciationEvent() ); + } + else { + g.getNodeData().setEvent( createSingleSpeciationOrDuplicationEvent() ); + } } } else { - event = createDuplicationEvent(); + g.getNodeData().setEvent( createSpeciationEvent() ); } } - else { - event = createSpeciationEvent(); - } - g.getNodeData().setEvent( event ); } /** @@ -196,123 +190,258 @@ public final class GSDI extends SDI { * Preconditions: Mapping M for external nodes must have been calculated and * the species tree must be labeled in preorder. *

- * (Last modified: ) * - * @param g - * starting node of a gene tree - normally the root */ - final void geneTreePostOrderTraversal( final PhylogenyNode g ) { - if ( !g.isExternal() ) { - for( final PhylogenyNodeIterator iter = g.iterateChildNodesForward(); iter.hasNext(); ) { - geneTreePostOrderTraversal( iter.next() ); - } - final PhylogenyNode[] linked_nodes = new PhylogenyNode[ g.getNumberOfDescendants() ]; - for( int i = 0; i < linked_nodes.length; ++i ) { - linked_nodes[ i ] = g.getChildNode( i ).getLink(); - } - final int[] min_max = obtainMinMaxIdIndices( linked_nodes ); - int min_i = min_max[ 0 ]; - int max_i = min_max[ 1 ]; - // initTransversalCounts(); - while ( linked_nodes[ min_i ] != linked_nodes[ max_i ] ) { - increaseTraversalCount( linked_nodes[ max_i ] ); - linked_nodes[ max_i ] = linked_nodes[ max_i ].getParent(); - final int[] min_max_ = obtainMinMaxIdIndices( linked_nodes ); - min_i = min_max_[ 0 ]; - max_i = min_max_[ 1 ]; + final void geneTreePostOrderTraversal() { + for( final PhylogenyNodeIterator it = getGeneTree().iteratorPostorder(); it.hasNext(); ) { + final PhylogenyNode g = it.next(); + if ( g.isInternal() ) { + PhylogenyNode s1 = g.getChildNode1().getLink(); + PhylogenyNode s2 = g.getChildNode2().getLink(); + while ( s1 != s2 ) { + if ( s1.getId() > s2.getId() ) { + s1 = s1.getParent(); + } + else { + s2 = s2.getParent(); + } + } + g.setLink( s1 ); + determineEvent( s1, g ); } - final PhylogenyNode s = linked_nodes[ max_i ]; - g.setLink( s ); - // Determines whether dup. or spec. - determineEvent( s, g ); - // _transversal_counts.clear(); } } - public final int getSpeciationOrDuplicationEventsSum() { - return _speciation_or_duplication_events_sum; + private final Event createDuplicationEvent() { + final Event event = Event.createSingleDuplicationEvent(); + ++_duplications_sum; + return event; } - public final int getSpeciationsSum() { - return _speciations_sum; + private final Event createSingleSpeciationOrDuplicationEvent() { + final Event event = Event.createSingleSpeciationOrDuplicationEvent(); + ++_speciation_or_duplication_events_sum; + return event; } - private final int getTraversalCount( final PhylogenyNode node ) { - if ( _transversal_counts.containsKey( node ) ) { - return _transversal_counts.get( node ); - } - return 0; + private final Event createSpeciationEvent() { + final Event event = Event.createSingleSpeciationEvent(); + ++_speciations_sum; + return event; } - private final void increaseTraversalCount( final PhylogenyNode node ) { - if ( _transversal_counts.containsKey( node ) ) { - _transversal_counts.put( node, _transversal_counts.get( node ) + 1 ); - } - else { - _transversal_counts.put( node, 1 ); - } - // System.out.println( "count for node " + node.getID() + " is now " - // + getTraversalCount( node ) ); + public final int getSpeciationOrDuplicationEventsSum() { + return _speciation_or_duplication_events_sum; + } + + public final int getSpeciationsSum() { + return _speciations_sum; } /** * This allows for linking of internal nodes of the species tree (as opposed * to just external nodes, as in the method it overrides. + * @throws SDIException * */ @Override - final void linkNodesOfG() { - final HashMap speciestree_ext_nodes = new HashMap(); - for( final PhylogenyNodeIterator iter = _species_tree.iteratorLevelOrder(); iter.hasNext(); ) { - final PhylogenyNode n = iter.next(); - if ( n.getNodeData().isHasTaxonomy() ) { - if ( speciestree_ext_nodes.containsKey( n.getNodeData().getTaxonomy() ) ) { - throw new IllegalArgumentException( "taxonomy [" + n.getNodeData().getTaxonomy() - + "] is not unique in species phylogeny" ); + final void linkNodesOfG() throws SDIException { + final Map species_to_node_map = new HashMap(); + final List species_tree_ext_nodes = new ArrayList(); + _tax_comp_base = determineTaxonomyComparisonBase( _gene_tree ); + // Stringyfied taxonomy is the key, node is the value. + for( final PhylogenyNodeIterator iter = _species_tree.iteratorExternalForward(); iter.hasNext(); ) { + final PhylogenyNode s = iter.next(); + species_tree_ext_nodes.add( s ); + if ( s.getNodeData().isHasTaxonomy() ) { + final String tax_str = taxonomyToString( s, _tax_comp_base ); + if ( !ForesterUtil.isEmpty( tax_str ) ) { + if ( species_to_node_map.containsKey( tax_str ) ) { + throw new SDIException( "taxonomy \"" + s + "\" is not unique in species tree" ); + } + species_to_node_map.put( tax_str, s ); } - speciestree_ext_nodes.put( n.getNodeData().getTaxonomy(), n ); - } - } - if ( _strip_gene_tree ) { - stripGeneTree( speciestree_ext_nodes ); - if ( ( _gene_tree == null ) || ( _gene_tree.getNumberOfExternalNodes() < 2 ) ) { - throw new IllegalArgumentException( "species tree does not contain any" - + " nodes matching species in the gene tree" ); } } - // Retrieve the reference to the PhylogenyNode with a matching species. + // Retrieve the reference to the node with a matching stringyfied taxonomy. for( final PhylogenyNodeIterator iter = _gene_tree.iteratorExternalForward(); iter.hasNext(); ) { final PhylogenyNode g = iter.next(); if ( !g.getNodeData().isHasTaxonomy() ) { - throw new IllegalArgumentException( "gene tree node " + g + " has no taxonomic data" ); + if ( _strip_gene_tree ) { + _stripped_gene_tree_nodes.add( g ); + } + else { + throw new SDIException( "gene tree node \"" + g + "\" has no taxonomic data" ); + } } - final PhylogenyNode s = speciestree_ext_nodes.get( g.getNodeData().getTaxonomy() ); - if ( s == null ) { - throw new IllegalArgumentException( "species " + g.getNodeData().getTaxonomy() - + " not present in species tree" ); + else { + final String tax_str = taxonomyToString( g, _tax_comp_base ); + if ( ForesterUtil.isEmpty( tax_str ) ) { + if ( _strip_gene_tree ) { + _stripped_gene_tree_nodes.add( g ); + } + else { + throw new SDIException( "gene tree node \"" + g + "\" has no appropriate taxonomic data" ); + } + } + else { + PhylogenyNode s = species_to_node_map.get( tax_str ); + if ( ( _tax_comp_base == TaxonomyComparisonBase.SCIENTIFIC_NAME ) && ( s == null ) + && ( ForesterUtil.countChars( tax_str, ' ' ) > 1 ) ) { + s = tryMapByRemovingOverlySpecificData( species_to_node_map, tax_str ); + } + if ( s == null ) { + if ( _strip_gene_tree ) { + _stripped_gene_tree_nodes.add( g ); + } + else { + throw new SDIException( "taxonomy \"" + g.getNodeData().getTaxonomy() + + "\" not present in species tree" ); + } + } + else { + g.setLink( s ); + _mapped_species_tree_nodes.add( s ); + } + } } - g.setLink( s ); + } // for loop + if ( _strip_gene_tree ) { + stripGeneTree(); + if ( getGeneTree().isEmpty() || ( getGeneTree().getNumberOfExternalNodes() < 2 ) ) { + throw new SDIException( "species could not be mapped between gene tree and species tree" ); + } + } + if ( _strip_species_tree ) { + stripSpeciesTree( species_tree_ext_nodes ); } } - private final void stripGeneTree( final HashMap speciestree_ext_nodes ) { - final Set to_delete = new HashSet(); - for( final PhylogenyNodeIterator iter = _gene_tree.iteratorExternalForward(); iter.hasNext(); ) { - final PhylogenyNode g = iter.next(); - if ( !g.getNodeData().isHasTaxonomy() ) { - throw new IllegalArgumentException( "gene tree node " + g + " has no taxonomic data" ); + private final PhylogenyNode tryMapByRemovingOverlySpecificData( final Map species_to_node_map, + final String tax_str ) { + PhylogenyNode s = tryMapByRemovingOverlySpecificData( species_to_node_map, tax_str, " (" ); + if ( s == null ) { + if ( ForesterUtil.countChars( tax_str, ' ' ) == 2 ) { + final String new_tax_str = tax_str.substring( 0, tax_str.lastIndexOf( ' ' ) ).trim(); + s = species_to_node_map.get( new_tax_str ); + if ( s != null ) { + addScientificNamesMappedToReducedSpecificity( tax_str, new_tax_str ); + } + } + } + if ( s == null ) { + for( final String t : new String[] { " subspecies ", " strain ", " variety ", " varietas ", " subvariety ", + " form ", " subform ", " cultivar ", " section ", " subsection " } ) { + s = tryMapByRemovingOverlySpecificData( species_to_node_map, tax_str, t ); + if ( s != null ) { + break; + } + } + } + return s; + } + + private final PhylogenyNode tryMapByRemovingOverlySpecificData( final Map species_to_node_map, + final String tax_str, + final String term ) { + final int i = tax_str.indexOf( term ); + if ( i > 4 ) { + final String new_tax_str = tax_str.substring( 0, i ).trim(); + final PhylogenyNode s = species_to_node_map.get( new_tax_str ); + if ( s != null ) { + addScientificNamesMappedToReducedSpecificity( tax_str, new_tax_str ); + } + return s; + } + return null; + } + + private final void addScientificNamesMappedToReducedSpecificity( final String s1, final String s2 ) { + _scientific_names_mapped_to_reduced_specificity.add( s1 + " -> " + s2 ); + } + + public final SortedSet getReMappedScientificNamesFromGeneTree() { + return _scientific_names_mapped_to_reduced_specificity; + } + + public TaxonomyComparisonBase getTaxCompBase() { + return _tax_comp_base; + } + + private void stripSpeciesTree( final List species_tree_ext_nodes ) { + for( final PhylogenyNode s : species_tree_ext_nodes ) { + if ( !_mapped_species_tree_nodes.contains( s ) ) { + _species_tree.deleteSubtree( s, true ); + _stripped_species_tree_nodes.add( s ); } - final PhylogenyNode s = speciestree_ext_nodes.get( g.getNodeData().getTaxonomy() ); - if ( s == null ) { - to_delete.add( g ); + } + _species_tree.clearHashIdToNodeMap(); + _species_tree.externalNodesHaveChanged(); + } + + public List getStrippedSpeciesTreeNodes() { + return _stripped_species_tree_nodes; + } + + private void stripGeneTree() { + for( final PhylogenyNode g : _stripped_gene_tree_nodes ) { + _gene_tree.deleteSubtree( g, true ); + } + _gene_tree.clearHashIdToNodeMap(); + _gene_tree.externalNodesHaveChanged(); + } + + public Set getMappedExternalSpeciesTreeNodes() { + return _mapped_species_tree_nodes; + } + + public static TaxonomyComparisonBase determineTaxonomyComparisonBase( final Phylogeny gene_tree ) { + int with_id_count = 0; + int with_code_count = 0; + int with_sn_count = 0; + int max = 0; + for( final PhylogenyNodeIterator iter = gene_tree.iteratorExternalForward(); iter.hasNext(); ) { + final PhylogenyNode g = iter.next(); + if ( g.getNodeData().isHasTaxonomy() ) { + final Taxonomy tax = g.getNodeData().getTaxonomy(); + if ( ( tax.getIdentifier() != null ) && !ForesterUtil.isEmpty( tax.getIdentifier().getValue() ) ) { + if ( ++with_id_count > max ) { + max = with_id_count; + } + } + if ( !ForesterUtil.isEmpty( tax.getTaxonomyCode() ) ) { + if ( ++with_code_count > max ) { + max = with_code_count; + } + } + if ( !ForesterUtil.isEmpty( tax.getScientificName() ) ) { + if ( ++with_sn_count > max ) { + max = with_sn_count; + } + } } } - for( final PhylogenyNode n : to_delete ) { - _gene_tree.deleteSubtree( n, true ); - System.out.println( "deleted node from gene tree: " + n ); + if ( max == 0 ) { + throw new IllegalArgumentException( "gene tree has no taxonomic data" ); + } + else if ( max == 1 ) { + throw new IllegalArgumentException( "gene tree has only one node with taxonomic data" ); + } + else if ( max == with_id_count ) { + return SDI.TaxonomyComparisonBase.ID; + } + else if ( max == with_sn_count ) { + return SDI.TaxonomyComparisonBase.SCIENTIFIC_NAME; + } + else { + return SDI.TaxonomyComparisonBase.CODE; } } + public List getStrippedExternalGeneTreeNodes() { + return _stripped_gene_tree_nodes; + } + @Override public final String toString() { final StringBuffer sb = new StringBuffer(); @@ -329,96 +458,4 @@ public final class GSDI extends SDI { sb.append( "mapping cost L : " + computeMappingCostL() ); return sb.toString(); } - - static final int[] obtainMinMaxIdIndices( final PhylogenyNode[] linked_nodes ) { - int max_i = 0; - int min_i = 0; - int max_i_id = -Integer.MAX_VALUE; - int min_i_id = Integer.MAX_VALUE; - for( int i = 0; i < linked_nodes.length; ++i ) { - final int id_i = linked_nodes[ i ].getId(); - if ( id_i > max_i_id ) { - max_i = i; - max_i_id = linked_nodes[ max_i ].getId(); - } - if ( id_i < min_i_id ) { - min_i = i; - min_i_id = linked_nodes[ min_i ].getId(); - } - } - return new int[] { min_i, max_i }; - } - /** - * Updates the mapping function M after the root of the gene tree has been - * moved by one branch. It calculates M for the root of the gene tree and - * one of its two children. - *

- * To be used ONLY by method "SDIunrooted.fastInfer(Phylogeny,Phylogeny)". - *

- * (Last modfied: ) - * - * @param prev_root_was_dup - * true if the previous root was a duplication, false otherwise - * @param prev_root_c1 - * child 1 of the previous root - * @param prev_root_c2 - * child 2 of the previous root - * @return number of duplications which have been assigned in gene tree - */ - // int updateM( final boolean prev_root_was_dup, - // final PhylogenyNode prev_root_c1, final PhylogenyNode prev_root_c2 ) { - // final PhylogenyNode root = getGeneTree().getRoot(); - // if ( ( root.getChildNode1() == prev_root_c1 ) - // || ( root.getChildNode2() == prev_root_c1 ) ) { - // calculateMforNode( prev_root_c1 ); - // } - // else { - // calculateMforNode( prev_root_c2 ); - // } - // Event event = null; - // if ( prev_root_was_dup ) { - // event = Event.createSingleDuplicationEvent(); - // } - // else { - // event = Event.createSingleSpeciationEvent(); - // } - // root.getPhylogenyNodeData().setEvent( event ); - // calculateMforNode( root ); - // return getDuplications(); - // } // updateM( boolean, PhylogenyNode, PhylogenyNode ) - // Helper method for updateM( boolean, PhylogenyNode, PhylogenyNode ) - // Calculates M for PhylogenyNode n, given that M for the two children - // of n has been calculated. - // (Last modified: 10/02/01) - // private void calculateMforNode( final PhylogenyNode n ) { - // if ( !n.isExternal() ) { - // boolean was_duplication = n.isDuplication(); - // PhylogenyNode a = n.getChildNode1().getLink(), b = n - // .getChildNode2().getLink(); - // while ( a != b ) { - // if ( a.getID() > b.getID() ) { - // a = a.getParent(); - // } - // else { - // b = b.getParent(); - // } - // } - // n.setLink( a ); - // Event event = null; - // if ( ( a == n.getChildNode1().getLink() ) - // || ( a == n.getChildNode2().getLink() ) ) { - // event = Event.createSingleDuplicationEvent(); - // if ( !was_duplication ) { - // increaseDuplications(); - // } - // } - // else { - // event = Event.createSingleSpeciationEvent(); - // if ( was_duplication ) { - // decreaseDuplications(); - // } - // } - // n.getPhylogenyNodeData().setEvent( event ); - // } - // } // calculateMforNode( PhylogenyNode ) }