Data Model

    The first step in any empirical effort is to clean and organize the data. This is also true for computational experiments! GeneDrive.jl uses structs to enforce consistency, define relationships, and dynamically assign methods to data.

    Importantly, the struct approach enables modularity: users can construct experiments in a "building block" fashion by assembling information that has already been stored as proper GeneDrive.jl inputs. The Features section outlines the environmental, biological, and genetic details that can be defined thanks to the data model.

    Once the information for an experiment has been organized using the data model, we are ready to:

    The code below shows how to construct an example study population using data that is included with the package.

    using GeneDrive
    
    # Select species type
    species = AedesAegypti
    
    # Define how genetic information is passed on
    genetics = genetics_mendelian();
    
    # Choose functional form of environmental response for species life stages
    enviro_response = stages_rossi();
    
    # Update population size as desired
    update_population_size(enviro_response, 500);
    
    # Assemble organism
    organisms = make_organisms(species, genetics, enviro_response);
    OrderedCollections.OrderedDict{DataType, Organism{AedesAegypti}} with 1 entry:
      AedesAegypti => Organism{AedesAegypti}(Genetics{Mendelian}(Drive[Drive{AA}(AA…

    To fully define an experiment, additional information is relevant: the spatial structure of the population, the ambient temperature of the habitat, and its geographic location should also be defined. The code below demonstrates how to do this; as above, it draws on pre-structured data from GeneDrive.jl.

    # Define temperature functional form and data
    temperature = example_temperature_timeseries;
    
    # Specify the geographic coordinates
    coordinates = (16.1820, 145.7210);
    
    # Define the spatial structure, name the location, and "populate" it
    node1 = Node(:YorkeysKnob, organisms, temperature, coordinates);
    Node(:YorkeysKnob, OrderedCollections.OrderedDict{Type{<:Species}, Organism}(AedesAegypti => Organism{AedesAegypti}(Genetics{Mendelian}(Drive[Drive{AA}(AA, [1.0 0.5 0.0; 0.5 0.25 0.0; 0.0 0.0 0.0], 1.0, [1.0 1.0 1.0; 1.0 1.0 1.0; 1.0 1.0 1.0], 0.5, 1.0, 1.0, 0.0, 63.0, 1.0, 0, 1), Drive{Aa}(Aa, [0.0 0.5 1.0; 0.5 0.5 0.5; 1.0 0.5 0.0], 1.0, [1.0 1.0 1.0; 1.0 1.0 1.0; 1.0 1.0 1.0], 0.5, 1.0, 1.0, 0.0, 63.0, 1.0, 0, 0), Drive{aa}(aa, [0.0 0.0 0.0; 0.0 0.25 0.5; 0.0 0.5 1.0], 1.0, [1.0 1.0 1.0; 1.0 1.0 1.0; 1.0 1.0 1.0], 0.5, 1.0, 1.0, 0.0, 63.0, 1.0, 1, 0)], [1.0 0.5 0.0; 0.5 0.25 0.0; 0.0 0.0 0.0;;; 0.0 0.5 1.0; 0.5 0.5 0.5; 1.0 0.5 0.0;;; 0.0 0.0 0.0; 0.0 0.25 0.5; 0.0 0.5 1.0], [1.0, 1.0, 1.0], [1.0 1.0 1.0; 1.0 1.0 1.0; 1.0 1.0 1.0;;; 1.0 1.0 1.0; 1.0 1.0 1.0; 1.0 1.0 1.0;;; 1.0 1.0 1.0; 1.0 1.0 1.0; 1.0 1.0 1.0], [0.5, 0.5, 0.5], [1.0, 1.0, 1.0], [1.0, 1.0, 1.0], [0.0, 0.0, 0.0], [63.0, 63.0, 63.0], [1.0, 1.0, 1.0], [0, 0, 1], [1, 0, 0]), OrderedCollections.OrderedDict{Type{<:LifeStage}, Stage}(Egg => Stage{Egg}(EggMortalityRossi(0.0731, 0.0595), EggDurationRossi(0.00764, 273.0, 40.55, 13094.1, 92.501, 28169.2), 2, Density{NoDensity}(NoDensity, 1.0), nothing, 0), Larva => Stage{Larva}(LarvaMortalityRossi(0.0143, 0.00189), LarvaDurationRossi(0.00219, 273.0, 25.21, 7514.34), 3, Density{LogisticDensity}(LogisticDensity, 1.0), Egg, 0), Pupa => Stage{Pupa}(PupaMortalityRossi(0.0143, 0.00189), PupaDurationRossi(0.027, -1.7, 27.7), 2, Density{NoDensity}(NoDensity, 1.0), Larva, 0), Male => Stage{Male}(AdultMortalityRossi(0.053, 0.081, 23.0, 0.0006375000000000003), NoResponse(0.0), 1, Density{NoDensity}(NoDensity, 1.0), Pupa, 0), Female => Stage{Female}(AdultMortalityRossi(0.053, 0.081, 23.0, 0.0006375000000000003), NoResponse(0.0), 1, Density{NoDensity}(NoDensity, 1.0), Pupa, 500)))), TimeSeriesTemperature([27.0, 27.5, 28.05, 28.05, 28.3, 27.8, 27.9, 28.5, 27.75, 26.8  …  27.9, 26.0, 24.9, 26.6, 27.35, 28.0, 28.4, 28.5, 28.45, 28.8], 1.0, 1), (16.182, 145.721))

    If the desired spatial structure is a network, we must also define migration rates for subsets of the population that move from node to node within that network. Migration is defined as a nested dictionary wherein the rate at which each genotype and lifestage moves between locations can be optionally specified. When migration rates are not defined for adjacent nodes or specific life stages (e.g., eggs) and genotypes, the default rate is set to zero.

    # Define a second node
    coordinates2 = (17.0966, 145.7747);
    node2 = Node(:Gordonsvale, organisms, temperature, coordinates2);
    
    # Create a network comprised of the two nodes
    network = Network(:Queensland, node1, node2);
    
    # Specify that adult males and females of all genotypes move
    migration_data = Dict( # node1 <-> node2
        ("Male", "AA") => Dict((:YorkeysKnob, :Gordonsvale) => 0.02,
                               (:Gordonsvale, :YorkeysKnob) => 0.02),
        ("Male", "Aa") => Dict((:YorkeysKnob, :Gordonsvale) => 0.02,
                                (:Gordonsvale, :YorkeysKnob) => 0.02),
        ("Male", "aa") => Dict((:YorkeysKnob, :Gordonsvale) => 0.02,
                                (:Gordonsvale, :YorkeysKnob) => 0.02),
        ("Female", "AA") => Dict((:YorkeysKnob, :Gordonsvale) => 0.02,
                                (:Gordonsvale, :YorkeysKnob) => 0.02),
        ("Female", "Aa") => Dict((:YorkeysKnob, :Gordonsvale) => 0.02,
                                (:Gordonsvale, :YorkeysKnob) => 0.02),
        ("Female", "aa") => Dict((:YorkeysKnob, :Gordonsvale) => 0.02,
                                (:Gordonsvale, :YorkeysKnob) => 0.02)
    );
    
    # Add migration to the network object
    assign_migration!(network, migration_data, species);