def _generate_lineages(self, **kwargs): current_time = 0.0 lineage_data = kwargs.get("lineage_data") max_time = kwargs.get("max_time", None) num_extant_lineages = kwargs.get("num_extant_lineages", None) num_extant_orthospecies = kwargs.get("num_extant_orthospecies", None) phase_idx = kwargs.get("phase_idx") lineage_taxon_namespace = kwargs.get("lineage_taxon_namespace", None) species_taxon_namespace = kwargs.get("species_taxon_namespace", None) if phase_idx == 0: lineage_data[phase_idx]["lineage_id"] = 1 lineage_data[phase_idx]["species_id"] = 1 initial_lineage = self._new_lineage( lineage_id=lineage_data[phase_idx]["lineage_id"], parent_lineage=None, origin_time=-1e-10, ) lineage_data[phase_idx]["orthospecies_lineages"] = [ initial_lineage ] lineage_data[phase_idx]["incipient_species_lineages"] = [] else: lineage_data[phase_idx]["lineage_id"] = lineage_data[0].get( "lineage_id", 0) + 1 lineage_data[phase_idx]["species_id"] = lineage_data[0].get( "species_id", 0) initial_lineage = self._new_lineage( lineage_id=lineage_data[phase_idx]["lineage_id"], parent_lineage=lineage_data[0]["lineage_collection"][0], origin_time=current_time, ) lineage_data[phase_idx]["orthospecies_lineages"] = [] lineage_data[phase_idx]["incipient_species_lineages"] = [ initial_lineage ] lineage_data[phase_idx]["lineage_collection"] = [initial_lineage] lineage_collection = lineage_data[phase_idx]["lineage_collection"] orthospecies_lineages = lineage_data[phase_idx][ "orthospecies_lineages"] incipient_species_lineages = lineage_data[phase_idx][ "incipient_species_lineages"] while True: num_orthospecies = len(orthospecies_lineages) num_incipient_species = len(incipient_species_lineages) if num_incipient_species + num_orthospecies == 0: raise TreeSimTotalExtinctionException() ## Draw time to next event event_rates = [] # Event type 0 event_rates.append( self.speciation_initiation_from_orthospecies_rate * num_orthospecies) # Event type 1 event_rates.append(self.orthospecies_extinction_rate * num_orthospecies) # Event type 2 event_rates.append( self.speciation_initiation_from_incipient_species_rate * num_incipient_species) # Event type 3 event_rates.append(self.speciation_completion_rate * num_incipient_species) # Event type 4 event_rates.append(self.incipient_species_extinction_rate * num_incipient_species) # All events rate_of_any_event = sum(event_rates) # Waiting time waiting_time = self.rng.expovariate(rate_of_any_event) # waiting_time = -math.log(self.rng.uniform(0, 1))/rate_of_any_event if max_time and (current_time + waiting_time) > max_time: current_time = max_time break # we do this here so that the (newest) tip lineages have the # waiting time to the next event branch lengths if num_extant_lineages is not None and ( num_incipient_species + num_orthospecies) >= num_extant_lineages: final_time = current_time + self.rng.uniform(0, waiting_time) lineage_data[phase_idx]["final_time"] = final_time break elif num_extant_orthospecies is not None: ## note: very expensive operation to count orthospecies leaves! final_time = current_time + self.rng.uniform(0, waiting_time) lineage_collection_snapshot = [ lineage.clone() for lineage in itertools.chain( lineage_data[0]["lineage_collection"], lineage_data[1] ["lineage_collection"]) ] try: orthospecies_tree = self._compile_species_tree( lineage_collection=lineage_collection_snapshot, max_time=final_time, ) num_leaves = len(orthospecies_tree.leaf_nodes()) if num_leaves >= num_extant_orthospecies: lineage_tree = self._compile_lineage_tree( lineage_collection=lineage_collection_snapshot, max_time=final_time, is_drop_extinct=True, ) lineage_tree, orthospecies_tree = self._finalize_trees( lineage_tree=lineage_tree, lineage_taxon_namespace=lineage_taxon_namespace, orthospecies_tree=orthospecies_tree, species_taxon_namespace=species_taxon_namespace, lineage_collection=lineage_collection_snapshot, ) lineage_data[phase_idx]["lineage_tree"] = lineage_tree lineage_data[phase_idx][ "orthospecies_tree"] = orthospecies_tree return except ProcessFailedException: pass # add to current time current_time += waiting_time # Select event event_type_idx = probability.weighted_index_choice( weights=event_rates, rng=self.rng) assert (event_type_idx >= 0 and event_type_idx <= 4) if event_type_idx == 0: # Splitting of new incipient species lineage from orthospecies lineage parent_lineage = self.rng.choice(orthospecies_lineages) lineage_data[phase_idx]["lineage_id"] += 1 new_lineage = self._new_lineage( lineage_id=lineage_data[phase_idx]["lineage_id"], parent_lineage=parent_lineage, origin_time=current_time, ) lineage_collection.append(new_lineage) incipient_species_lineages.append(new_lineage) elif event_type_idx == 1: # Extinction of an orthospecies lineage lineage_idx = self.rng.randint(0, len(orthospecies_lineages) - 1) orthospecies_lineages[ lineage_idx].extinction_time = current_time del orthospecies_lineages[lineage_idx] elif event_type_idx == 2: # Splitting of new incipient species lineage from incipient lineage parent_lineage = self.rng.choice(incipient_species_lineages) lineage_data[phase_idx]["lineage_id"] += 1 new_lineage = self._new_lineage( lineage_id=lineage_data[phase_idx]["lineage_id"], parent_lineage=parent_lineage, origin_time=current_time, ) lineage_collection.append(new_lineage) incipient_species_lineages.append(new_lineage) elif event_type_idx == 3: # Completion of speciation lineage_idx = self.rng.randint( 0, len(incipient_species_lineages) - 1) lineage = incipient_species_lineages[lineage_idx] lineage.speciation_completion_time = current_time lineage_data[phase_idx]["species_id"] += 1 lineage.species_id = lineage_data[phase_idx]["species_id"] orthospecies_lineages.append(lineage) del incipient_species_lineages[lineage_idx] elif event_type_idx == 4: # Extinction of an incipient_species lineage lineage_idx = self.rng.randint( 0, len(incipient_species_lineages) - 1) incipient_species_lineages[ lineage_idx].extinction_time = current_time del incipient_species_lineages[lineage_idx] else: raise Exception( "Unexpected event type index: {}".format(event_type_idx))
def _generate_lineages(self, **kwargs): current_time = 0.0 lineage_data = kwargs.get("lineage_data") max_time = kwargs.get("max_time", None) num_extant_lineages = kwargs.get("num_extant_lineages", None) num_extant_orthospecies = kwargs.get("num_extant_orthospecies", None) phase_idx = kwargs.get("phase_idx") lineage_taxon_namespace = kwargs.get("lineage_taxon_namespace", None) species_taxon_namespace = kwargs.get("species_taxon_namespace", None) if phase_idx == 0: lineage_data[phase_idx]["lineage_id"] = 1 lineage_data[phase_idx]["species_id"] = 1 initial_lineage = self._new_lineage( lineage_id=lineage_data[phase_idx]["lineage_id"], parent_lineage=None, origin_time=-1e-10, ) lineage_data[phase_idx]["orthospecies_lineages"] = [initial_lineage] lineage_data[phase_idx]["incipient_species_lineages"] = [] else: lineage_data[phase_idx]["lineage_id"] = lineage_data[0].get("lineage_id", 0) + 1 lineage_data[phase_idx]["species_id"] = lineage_data[0].get("species_id", 0) initial_lineage = self._new_lineage( lineage_id=lineage_data[phase_idx]["lineage_id"], parent_lineage=lineage_data[0]["lineage_collection"][0], origin_time=current_time, ) lineage_data[phase_idx]["orthospecies_lineages"] = [] lineage_data[phase_idx]["incipient_species_lineages"] = [initial_lineage] lineage_data[phase_idx]["lineage_collection"] = [initial_lineage] lineage_collection = lineage_data[phase_idx]["lineage_collection"] orthospecies_lineages = lineage_data[phase_idx]["orthospecies_lineages"] incipient_species_lineages = lineage_data[phase_idx]["incipient_species_lineages"] while True: num_orthospecies = len(orthospecies_lineages) num_incipient_species = len(incipient_species_lineages) if num_incipient_species + num_orthospecies == 0: raise TreeSimTotalExtinctionException() ## Draw time to next event event_rates = [] # Event type 0 event_rates.append(self.speciation_initiation_from_orthospecies_rate * num_orthospecies) # Event type 1 event_rates.append(self.orthospecies_extinction_rate * num_orthospecies) # Event type 2 event_rates.append(self.speciation_initiation_from_incipient_species_rate * num_incipient_species) # Event type 3 event_rates.append(self.speciation_completion_rate * num_incipient_species) # Event type 4 event_rates.append(self.incipient_species_extinction_rate * num_incipient_species) # All events rate_of_any_event = sum(event_rates) # Waiting time waiting_time = self.rng.expovariate(rate_of_any_event) # waiting_time = -math.log(self.rng.uniform(0, 1))/rate_of_any_event if max_time and (current_time + waiting_time) > max_time: current_time = max_time break # we do this here so that the (newest) tip lineages have the # waiting time to the next event branch lengths if num_extant_lineages is not None and (num_incipient_species + num_orthospecies) >= num_extant_lineages: final_time = current_time + self.rng.uniform(0, waiting_time) lineage_data[phase_idx]["final_time"] = final_time break elif num_extant_orthospecies is not None: ## note: very expensive operation to count orthospecies leaves! final_time = current_time + self.rng.uniform(0, waiting_time) lineage_collection_snapshot = [lineage.clone() for lineage in itertools.chain(lineage_data[0]["lineage_collection"], lineage_data[1]["lineage_collection"])] try: orthospecies_tree = self._compile_species_tree( lineage_collection=lineage_collection_snapshot, max_time=final_time, ) num_leaves = len(orthospecies_tree.leaf_nodes()) if num_leaves >= num_extant_orthospecies: lineage_tree = self._compile_lineage_tree( lineage_collection=lineage_collection_snapshot, max_time=final_time, is_drop_extinct=True, ) lineage_tree, orthospecies_tree = self._finalize_trees( lineage_tree=lineage_tree, lineage_taxon_namespace=lineage_taxon_namespace, orthospecies_tree=orthospecies_tree, species_taxon_namespace=species_taxon_namespace, lineage_collection=lineage_collection_snapshot, ) lineage_data[phase_idx]["lineage_tree"] = lineage_tree lineage_data[phase_idx]["orthospecies_tree"] = orthospecies_tree return except ProcessFailedException: pass # add to current time current_time += waiting_time # Select event event_type_idx = probability.weighted_index_choice(weights=event_rates, rng=self.rng) assert (event_type_idx >= 0 and event_type_idx <= 4) if event_type_idx == 0: # Splitting of new incipient species lineage from orthospecies lineage parent_lineage = self.rng.choice(orthospecies_lineages) lineage_data[phase_idx]["lineage_id"] += 1 new_lineage = self._new_lineage( lineage_id=lineage_data[phase_idx]["lineage_id"], parent_lineage=parent_lineage, origin_time=current_time, ) lineage_collection.append(new_lineage) incipient_species_lineages.append(new_lineage) elif event_type_idx == 1: # Extinction of an orthospecies lineage lineage_idx = self.rng.randint(0, len(orthospecies_lineages)-1) orthospecies_lineages[lineage_idx].extinction_time = current_time del orthospecies_lineages[lineage_idx] elif event_type_idx == 2: # Splitting of new incipient species lineage from incipient lineage parent_lineage = self.rng.choice(incipient_species_lineages) lineage_data[phase_idx]["lineage_id"] += 1 new_lineage = self._new_lineage( lineage_id=lineage_data[phase_idx]["lineage_id"], parent_lineage=parent_lineage, origin_time=current_time, ) lineage_collection.append(new_lineage) incipient_species_lineages.append(new_lineage) elif event_type_idx == 3: # Completion of speciation lineage_idx = self.rng.randint(0, len(incipient_species_lineages)-1) lineage = incipient_species_lineages[lineage_idx] lineage.speciation_completion_time = current_time lineage_data[phase_idx]["species_id"] += 1 lineage.species_id = lineage_data[phase_idx]["species_id"] orthospecies_lineages.append(lineage) del incipient_species_lineages[lineage_idx] elif event_type_idx == 4: # Extinction of an incipient_species lineage lineage_idx = self.rng.randint(0, len(incipient_species_lineages)-1) incipient_species_lineages[lineage_idx].extinction_time = current_time del incipient_species_lineages[lineage_idx] else: raise Exception("Unexpected event type index: {}".format(event_type_idx))
def _run_protracted_speciation_process(self, **kwargs): self.reset() max_time = kwargs.get("max_time", None) max_extant_protracted_speciation_lineages = kwargs.get("max_extant_protracted_speciation_lineages", None) max_full_species = kwargs.get("max_full_species", None) is_correlate_protracted_speciation_and_full_speciation_trees = kwargs.get("is_correlate_protracted_speciation_and_full_speciation_trees", False) taxon_namespace = kwargs.get("taxon_namespace", None) is_full_species = not kwargs.get("is_initial_species_incipient", False) if is_full_species: initial_lineage = self._new_lineage(parent_lineage=None, is_full_species=True) else: initial_lineage = self._new_lineage(parent_lineage=None, is_full_species=False) seed_node = self._new_node(lineage=initial_lineage) protracted_speciation_tree = self.tree_factory( taxon_namespace=taxon_namespace, seed_node=seed_node) protracted_speciation_tree.is_rooted = True while True: ## Draw time to next event event_rates = [] num_full_species = len(self.current_full_species_lineages) if max_full_species is not None: ## note: expensive operation to count leaves! try: full_species_tree = self._assemble_full_species_tree(taxon_namespace=taxon_namespace) num_leaves = len(full_species_tree.leaf_nodes()) if num_leaves >= max_full_species: return self._postprocess_psm_and_full_species_trees( full_species_tree=full_species_tree, protracted_speciation_tree=protracted_speciation_tree, is_correlate_protracted_speciation_and_full_speciation_trees=is_correlate_protracted_speciation_and_full_speciation_trees, ) except ProtractedSpeciationModel.ProcessFailedException: pass num_incipient_species = len(self.current_incipient_species_lineages) if max_extant_protracted_speciation_lineages is not None and (num_incipient_species + num_full_species) >= max_extant_protracted_speciation_lineages: break # Event type 0 event_rates.append(self.full_species_birth_rate * num_full_species) # Event type 1 event_rates.append(self.full_species_extinction_rate * num_full_species) # Event type 2 event_rates.append(self.incipient_species_birth_rate * num_incipient_species) # Event type 3 event_rates.append(self.incipient_species_conversion_rate * num_incipient_species) # Event type 4 event_rates.append(self.incipient_species_extinction_rate * num_incipient_species) # All events rate_of_any_event = sum(event_rates) # Waiting time waiting_time = self.rng.expovariate(rate_of_any_event) if max_time and (self.current_time + waiting_time) > max_time: t = max_time - self.current_time for lineage in itertools.chain(self.current_full_species_lineages, self.current_incipient_species_lineages): lineage.node.edge.length += t self.current_time = max_time break self.current_time += waiting_time for lineage in itertools.chain(self.current_full_species_lineages, self.current_incipient_species_lineages): lineage.node.edge.length += waiting_time # Select event event_type_idx = probability.weighted_index_choice(weights=event_rates, rng=self.rng) assert (event_type_idx >= 0 and event_type_idx <= 4) # print("time {}: {}, selected = {}".format(self.current_time, event_rates, event_type_idx)) if event_type_idx == 0: self._process_full_species_birth(protracted_speciation_tree) elif event_type_idx == 1: self._process_full_species_extinction(protracted_speciation_tree) elif event_type_idx == 2: self._process_incipient_species_birth(protracted_speciation_tree) elif event_type_idx == 3: self._process_incipient_species_conversion(protracted_speciation_tree) elif event_type_idx == 4: self._process_incipient_species_extinction(protracted_speciation_tree) else: raise Exception("Unexpected event type index: {}".format(event_type_idx)) if len(self.current_full_species_lineages) + len(self.current_incipient_species_lineages) == 0: raise TreeSimTotalExtinctionException() full_species_tree = self._assemble_full_species_tree(taxon_namespace=taxon_namespace) return self._postprocess_psm_and_full_species_trees( protracted_speciation_tree=protracted_speciation_tree, full_species_tree=full_species_tree, is_correlate_protracted_speciation_and_full_speciation_trees=is_correlate_protracted_speciation_and_full_speciation_trees, )
def _run_protracted_speciation_process(self, **kwargs): self.reset() max_time = kwargs.get("max_time", None) max_extant_lineages = kwargs.get("max_extant_lineages", None) max_extant_orthospecies = kwargs.get("max_extant_orthospecies", None) is_correlate_lineage_and_species_trees = kwargs.get( "is_correlate_lineage_and_species_trees", False) taxon_namespace = kwargs.get("taxon_namespace", None) initial_lineage = self._new_lineage( parent_lineage=None, orthospecies_index=self.current_orthospecies_index, is_orthospecies=kwargs.get("is_initial_lineage_orthospecies", True), ) seed_node = self._new_node(lineage=initial_lineage) lineage_tree = self.tree_factory(taxon_namespace=taxon_namespace, seed_node=seed_node) lineage_tree.is_rooted = True while True: ## Draw time to next event event_rates = [] num_orthospecies = len(self.current_orthospecies_lineages) if max_extant_orthospecies is not None: ## note: expensive operation to count leaves! try: orthospecies_tree = self._assemble_orthospecies_tree( taxon_namespace=taxon_namespace) num_leaves = len(orthospecies_tree.leaf_nodes()) if num_leaves >= max_extant_orthospecies: return self._postprocess_psm_and_orthospecies_trees( orthospecies_tree=orthospecies_tree, lineage_tree=lineage_tree, is_correlate_lineage_and_species_trees= is_correlate_lineage_and_species_trees, ) except ProcessFailedException: pass num_incipient_species = len( self.current_incipient_species_lineages) if max_extant_lineages is not None and ( num_incipient_species + num_orthospecies) >= max_extant_lineages: break # Event type 0 event_rates.append( self.speciation_initiation_from_orthospecies_rate * num_orthospecies) # Event type 1 event_rates.append(self.orthospecies_extinction_rate * num_orthospecies) # Event type 2 event_rates.append( self.speciation_initiation_from_incipient_species_rate * num_incipient_species) # Event type 3 event_rates.append(self.speciation_completion_rate * num_incipient_species) # Event type 4 event_rates.append(self.incipient_species_extinction_rate * num_incipient_species) # All events rate_of_any_event = sum(event_rates) # Waiting time waiting_time = self.rng.expovariate(rate_of_any_event) if max_time and (self.current_time + waiting_time) > max_time: t = max_time - self.current_time for lineage in itertools.chain( self.current_orthospecies_lineages, self.current_incipient_species_lineages): lineage.node.edge.length += t self.current_time = max_time break self.current_time += waiting_time for lineage in itertools.chain( self.current_orthospecies_lineages, self.current_incipient_species_lineages): lineage.node.edge.length += waiting_time # Select event event_type_idx = probability.weighted_index_choice( weights=event_rates, rng=self.rng) assert (event_type_idx >= 0 and event_type_idx <= 4) # print("time {}: {}, selected = {}".format(self.current_time, event_rates, event_type_idx)) if event_type_idx == 0: self._process_initiation_of_speciation_from_orthospecies( lineage_tree) elif event_type_idx == 1: self._process_orthospecies_extinction(lineage_tree) elif event_type_idx == 2: self._process_initiation_of_speciation_from_incipient_species( lineage_tree) elif event_type_idx == 3: self._process_completion_of_specation(lineage_tree) elif event_type_idx == 4: self._process_incipient_species_extinction(lineage_tree) else: raise Exception( "Unexpected event type index: {}".format(event_type_idx)) if len(self.current_orthospecies_lineages) + len( self.current_incipient_species_lineages) == 0: raise TreeSimTotalExtinctionException() orthospecies_tree = self._assemble_orthospecies_tree( taxon_namespace=taxon_namespace) return self._postprocess_psm_and_orthospecies_trees( lineage_tree=lineage_tree, orthospecies_tree=orthospecies_tree, is_correlate_lineage_and_species_trees= is_correlate_lineage_and_species_trees, )