landlab.components.species_evolution.species_evolver¶
Evolve life in a landscape.
Life evolves alongside landscapes by biotic and abiotic processes under complex dynamics at Earth’s surface. Researchers who wish to explore these dynamics can use this component as a tool for them to build landscape-life evolution models. Landlab components, including SpeciesEvolver are designed to work with a shared model grid. Researchers can build novel models using plug-and-play surface process components to evolve the grid’s landscape alongside the life tracked by SpeciesEvolver. The simulated life evolves following customizable processes.
Component written by Nathan Lyons beginning August 2017.
- class SpeciesEvolver[source]¶
Bases:
Component
Evolve life in a landscape.
This component tracks
Taxon
objects as they evolve in a landscape. The component calls the evolutionary process methods of trackedTaxon
objects.Taxon
are intended to be subclassed for unique behavior, attributes, and model approaches, including different implementations of evolutionary processes.The general workflow to use this component in a model is
Instantiate the component.
Instantiate taxa.
Introduce taxa to SpeciesEvolver using the
track_taxon
method.Advance the component instance in time using
run_one_step
method.
Taxa can be introduced at model onset and later time steps. Multiple types can be tracked by the same SpeciesEvolver instance.
The taxon type,
ZoneTaxon
is distributed with SpeciesEvolver. The spatial aspect ofZoneTaxon
macroevolutionary processes is determined usingZone
objects. AZoneController
is used to create and manage zones as well as efficiently create multiple ZoneTaxon objects. See the documentation ofZoneController
andZoneTaxon
for more information. SpeciesEvolver knows nothing about zones and their controller, meaning the concept of zones are not required for other taxon types.Model time and other variables can be viewed with the class attribute,
record_data_frame
. Time is recorded to track the history of taxa lineages. The unit of time is not considered within the component other than the record, and can be thought of as in years or whatever unit is needed. Time is advanced with thedt
parameter of therun_one_step
method.The geographic ranges of the taxa at the current model time are evaluated during the
run_one_step
method. Each taxon object determines if it persists or becomes extinct, and if it creates childTaxon
objects. Metadata of all taxa introduced to the component can be viewed with the attribute,taxa_data_frame
.Taxa are automatically assigned unique taxon identifiers,
tid
. Identifiers are used to reference and retrieve taxon objects. Identifiers are assigned in the order taxa are introduced to SpeciesEvolver.Examples
The evolution of a lowland taxa lineage in response to mountain range formation is simulated using ZoneTaxon managed by ZoneController. Mountain range formation is forced without processes for simplicity in this example.
Import modules used in the following examples.
>>> from landlab import RasterModelGrid >>> from landlab.components import SpeciesEvolver >>> from landlab.components.species_evolution import ZoneController
Create a model grid with mountain scale resolution. The elevation is equally low throughout the grid at model onset.
>>> mg = RasterModelGrid((3, 7), 1000) >>> z = mg.add_ones("topographic__elevation", at="node") >>> z.reshape(mg.shape) array([[1., 1., 1., 1., 1., 1., 1.], [1., 1., 1., 1., 1., 1., 1.], [1., 1., 1., 1., 1., 1., 1.]])
Instantiate the component with the grid as the first parameter.
>>> se = SpeciesEvolver(mg)
ZoneController requires a function that returns a mask of the total extent of taxa habitat. The mask is a boolean array where True values represent nodes that satisfy habitat conditions. Zone objects are not created here. The mask only maps the extent where taxa can exist. This function returns True where elevation is below 100, which is where the simulated lowland taxa of this model can inhabit.
>>> def zone_func(grid): ... return grid.at_node["topographic__elevation"] < 100 ...
Instantiate ZoneController with the grid and zone function. The initial zones are created at controller instantiation. In this example, one zone is created because all nodes of the zone mask are adjacent to each other.
>>> zc = ZoneController(mg, zone_func) >>> len(zc.zones) == 1 True
Additional examples of controller usage are provided in
ZoneController
documentation.The
mask
of the zone is True where the conditions of the zone function are met. All nodes of the grid are included because the elevation of each node is below 100. Thezones
attribute ofZoneController
returns a list of the zones that currently exist in the model. Below we return the mask of the single zone by indexing this list.>>> zc.zones[0].mask array([ True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True])
Populate a taxon to the zone.
>>> taxon = zc.populate_zones_uniformly(1) >>> se.track_taxa(taxon)
The attribute,
taxa_data_frame
indicates only the one taxon exists because we populated each zone with one taxon, and only the one zone exists.>>> se.taxa_data_frame pid type t_first t_final tid 0 <NA> ZoneTaxon 0 <NA>
The identifier of the taxon,
tid
is 0. The identifier of the taxon’s parent,pid
, is ‘<NA>’ because it does not have a parent taxon given that it was manually introduced using thetrack_taxa
method. The taxon was introduced at time,t_first
and time,t_final
is ‘<NA>’ because the taxon remains extant. See the documentation of this attribute for further explanation of data frame columns.Force a change in the zone mask to demonstrate component functionality. Here we begin a new time step where topography is uplifted by 200 that forms a ridge trending north-south in the center of the grid.
>>> z[[3, 10, 17]] = 200 >>> z.reshape(mg.shape) array([[ 1., 1., 1., 200., 1., 1., 1.], [ 1., 1., 1., 200., 1., 1., 1.], [ 1., 1., 1., 200., 1., 1., 1.]])
The current elevation, the elevation following uplift, is represented here.
- - - ^ - - - elevation: - 1 - - - ^ - - - ^ 200 - - - ^ - - -
The updated zone mask is below.
. . . x . . . key: . node in zone mask . . . x . . . x node outside of zone mask . . . x . . .
Run a step of both the ZoneController and SpeciesEvolver. Both are run to keep time in sync between the
ZoneController``and ``SpeciesEvolver
instances. >>> delta_time = 1000 >>> zc.run_one_step(delta_time) >>> se.run_one_step(delta_time)Two zones exist following this time step.
>>> len(zc.zones) == 2 True
An additional zone was created because the zone mask was not continuous.
. . . ^ * * * key: . a zone . . . ^ * * * * another zone . . . ^ * * * ^ mountain range
The split of the initial zone triggered speciation of taxon 1 by taxon 0.
>>> se.taxa_data_frame pid type t_first t_final tid 0 <NA> ZoneTaxon 0 <NA> 1 0 ZoneTaxon 1000 <NA>
The phylogenetic tree of the simulated taxa is represented below. The number at the line tips are the taxa identifiers.
0 ──────┬── 0 │ └── 1 _________ 0 1000 time
The split of the initial zone into two zones at time 1000 triggered taxon 0 to speciate. Taxon 0 occupies a zone on one side of the mountain range, and the child, taxon 1 occupies a zone on the other side. This outcome is the result of the evolutionary processes programmed within
ZoneTaxon
as well as the parameters used in this example (default values were used as optional parameters were not set). Different behavior can be achieved by subclassingZoneTaxon
orTaxon
.References
Required Software Citation(s) Specific to this Component
Lyons, N.J., Albert, J.S., Gasparini, N.M. (2020). SpeciesEvolver: A Landlab component to evolve life in simulated landscapes. Journal of Open Source Software 5(46), 2066, https://doi.org/10.21105/joss.02066
Additional References
Albert, J.S., Schoolmaster Jr, D.R., Tagliacollo, V., Duke-Sylvester, S.M. (2016). Barrier displacement on a neutral landscape: Toward a theory of continental biogeography. Systematic Biology 66(2), 167–182.
Lyons, N.J., Val, P., Albert, J.S., Willenbring, J.K., Gasparini, N.M., in review. Topographic controls on divide migration, stream capture, and diversification in riverine life. Earth Surface Dynamics.
Instantiate SpeciesEvolver.
- Parameters:
- static __new__(cls, *args, **kwds)¶
- cite_as = '@article{lyons2020species,\n author = {Lyons, N.J. and Albert, J.S. and Gasparini, N.M.},\n title = {SpeciesEvolver: A Landlab component to evolve life in simulated landscapes},\n year = {2020},\n journal = {Journal of Open Source Software},\n volume = {5},\n number = {46},\n doi = {10.21105/joss.02066},\n url = {https://doi.org/10.21105/joss.02066}\n }'¶
- property coords¶
Return the coordinates of nodes on grid attached to the component.
- property current_time¶
Current time.
Some components may keep track of the current time. In this case, the
current_time
attribute is incremented. Otherwise it is set to None.- Return type:
current_time
- definitions = (('taxa__richness', 'The number of taxa at each node'),)¶
- classmethod from_path(grid, path)¶
Create a component from an input file.
- get_extant_taxon_objects(tids=nan, ancestor=nan, time=nan)[source]¶
Get extant taxon objects filtered by parameters.
This method returns all taxon objects tracked by the component when no optional parameters are included. The objects returned can be limited using one or more parameters.
- Parameters:
tids (list of int, optional) – The taxa with these identifiers will be returned. A list is returned even if only one object is contained within the list. By default, when tids is not specified, extant taxa with any identifier can be returned.
ancestor (int, optional) – Limit the taxa returned to those descending from the taxon designated as the ancestor. The ancestor is designated using its
tid
. By default, taxa with any or no ancestors are returned.time (float, int, optional) – Limit the taxa returned to those that were extant at the time designated by this parameter as well as extant at the current model time. By default, extant taxa at all of the times listed in the component record can be returned.
- Returns:
taxa – The Taxon objects that pass through the filter. The list is sorted by
tid
. An empty list is returned if no taxa pass through the filter.- Return type:
a list of Taxon
Examples
ZoneTaxon are used to demonstrate this method.
Import modules used in the following examples.
>>> from landlab import RasterModelGrid >>> from landlab.components import SpeciesEvolver >>> from landlab.components.species_evolution import ZoneController
Create a model grid.
>>> mg = RasterModelGrid((3, 7), 1000) >>> z = mg.add_ones("topographic__elevation", at="node")
Instantiate SpeciesEvolver and a ZoneController. Instantiate the latter with a function that masks the low elevation zone extent. Only one zone is created.
>>> se = SpeciesEvolver(mg) >>> def zone_func(grid): ... return grid.at_node["topographic__elevation"] < 100 ... >>> zc = ZoneController(mg, zone_func) >>> len(zc.zones) == 1 True
Introduce two taxa to the zone.
>>> taxa = zc.populate_zones_uniformly(2) >>> se.track_taxa(taxa)
Force north-south mountain ranges over two time steps that drives taxa evolution.
>>> z[mg.x_of_node == 2000] = 200 >>> zc.run_one_step(1000) >>> se.run_one_step(1000) >>> z[mg.x_of_node == 4000] = 200 >>> zc.run_one_step(1000) >>> se.run_one_step(1000)
Display taxa metadata.
>>> se.taxa_data_frame pid type t_first t_final tid 0 <NA> ZoneTaxon 0 <NA> 1 <NA> ZoneTaxon 0 <NA> 2 0 ZoneTaxon 1000 <NA> 3 1 ZoneTaxon 1000 <NA> 4 0 ZoneTaxon 2000 <NA> 5 1 ZoneTaxon 2000 <NA>
Objects of all extant taxon are returned when no parameters are inputted.
>>> se.get_extant_taxon_objects() [<ZoneTaxon, tid=0>, <ZoneTaxon, tid=1>, <ZoneTaxon, tid=2>, <ZoneTaxon, tid=3>, <ZoneTaxon, tid=4>, <ZoneTaxon, tid=5>]
The returned objects of extant species can be limited using parameters. Here, get the taxon objects with identifiers, 4 and 5.
>>> se.get_extant_taxon_objects(tids=[4, 5]) [<ZoneTaxon, tid=4>, <ZoneTaxon, tid=5>]
Extant taxon objects descending from a taxon can be obtained using the
ancestor
property. Here, get the taxa that descended from taxon 0.>>> se.get_extant_taxon_objects(ancestor=0) [<ZoneTaxon, tid=2>, <ZoneTaxon, tid=4>]
Taxa can be limited to those that were extant
time
.>>> se.get_extant_taxon_objects(time=1000) [<ZoneTaxon, tid=0>, <ZoneTaxon, tid=1>, <ZoneTaxon, tid=2>, <ZoneTaxon, tid=3>]
The returned taxa can be further limited by including multiple method properties.
>>> se.get_extant_taxon_objects(ancestor=0, time=1000) [<ZoneTaxon, tid=2>]
An empty list is returned when no extant taxa match parameter criteria.
>>> se.get_extant_taxon_objects(tids=[11]) []
- property grid¶
Return the grid attached to the component.
- initialize_optional_output_fields()¶
Create fields for a component based on its optional field outputs, if declared in _optional_var_names.
This method will create new fields (without overwrite) for any fields output by the component as optional. New fields are initialized to zero. New fields are created as arrays of floats, unless the component also contains the specifying property _var_type.
- initialize_output_fields(values_per_element=None)¶
Create fields for a component based on its input and output var names.
This method will create new fields (without overwrite) for any fields output by, but not supplied to, the component. New fields are initialized to zero. Ignores optional fields. New fields are created as arrays of floats, unless the component specifies the variable type.
- Parameters:
values_per_element (int (optional)) – On occasion, it is necessary to create a field that is of size (n_grid_elements, values_per_element) instead of the default size (n_grid_elements,). Use this keyword argument to acomplish this task.
- input_var_names = ()¶
- name = 'SpeciesEvolver'¶
- optional_var_names = ()¶
- output_var_names = ('taxa__richness',)¶
- property record_data_frame¶
A Pandas DataFrame of SpeciesEvolver variables over time.
Each row is data of a model time step. The time of the step is recorded in the time column. taxa is the count of taxa extant at a time. Additional columns can be added and updated by SpeciesEvolver objects during the component
run_one_step
method. See documention of Taxon objects for an explanation of these columns.The DataFrame is created from a dictionary associated with a SpeciesEvolver
Record
object. nan values in Pandas DataFrame force the column to become float values even when data are integers. The original value type is retained in theRecord
object.
- run_one_step(dt)[source]¶
Update the taxa for a single time step.
This method advances the model time in the component record, calls the evolve method of taxa extant at the current time, and updates the variables in the record and taxa dataframes.
- Parameters:
dt (float) – The model time step duration. Time in the record is advanced by the value of this parameter.
- property shape¶
Return the grid shape attached to the component, if defined.
- property taxa_data_frame¶
A Pandas DataFrame of taxa metadata.
Each row is the metadata of a taxon. The column,
tid
is the taxon identifier assigned when SpeciesEvolver begins tracking the taxon. The column,pid
is the tid of the parent of the taxon. A pid of <NA> indicates no parent taxon.type
is the type ofTaxon
object.t_first
is the initial model time the taxon was added to SpeciesEvolver.t_final
is the model time the taxon was recognized as extinct. A t_final of <NA> indicates the taxon is extant.Additional columns may be added by some taxon types. See the documentation of these taxa for column description.
The DataFrame is created from a data structure within the component.
- track_taxa(taxa)[source]¶
Add taxa to be tracked over time by SpeciesEvolver.
The taxon/taxa are introduced at the latest time in the record and also tracked during following model times. Each taxon is assigned an identifier and then can be viewed in
taxa_data_frame
.Examples
ZoneTaxon are used to demonstrate this method.
Import modules used in the following examples.
>>> from landlab import RasterModelGrid >>> from landlab.components import SpeciesEvolver >>> from landlab.components.species_evolution import ZoneController
Create a model grid with flat topography.
>>> mg = RasterModelGrid((3, 7), 1000) >>> z = mg.add_ones("topographic__elevation", at="node")
Instantiate SpeciesEvolver and a ZoneController. Instantiate the latter with a function that masks the low elevation zone extent. Only one zone is created.
>>> se = SpeciesEvolver(mg) >>> def zone_func(grid): ... return grid.at_node["topographic__elevation"] < 100 ... >>> zc = ZoneController(mg, zone_func) >>> len(zc.zones) == 1 True
Track the taxon of the one zone.
>>> taxon = zc.populate_zones_uniformly(1) >>> se.track_taxa(taxon)
The one taxon is now tracked by SpeciesEvolver as indicated by the taxa DataFrame.
>>> se.taxa_data_frame pid type t_first t_final tid 0 <NA> ZoneTaxon 0 <NA>
- unit_agnostic = True¶
- units = (('taxa__richness', '-'),)¶
- classmethod var_definition(name)¶
Get a description of a particular field.
- Parameters:
name (str) – A field name.
- Returns:
A description of each field.
- Return type:
tuple of (name, *description*)
- classmethod var_help(name)¶
Print a help message for a particular field.
- Parameters:
name (str) – A field name.
- classmethod var_loc(name)¶
Location where a particular variable is defined.
- var_mapping = (('taxa__richness', 'node'),)¶