https://github.com/smanskiLab/SWD_Agent_Model
Raw File
Tip revision: 83aa66850ff14305f81556c2f8ca9a5ac2557748 authored by adamsychla on 17 February 2022, 15:11:54 UTC
Add files via upload
Tip revision: 83aa668
SingleGenome_SWD.py
# -*- coding: utf-8 -*-
"""
Created on Mon Feb 12 13:03:27 2018

@author: smanski

This code is set up to simulate a 3 x 1 grid of individual population models. Because
there is no migration between the populations, each can be treated as an independent experiment.

TODO: make it possible for gestating eggs to move with migration rate

Modified on Wed Mar 25 11:31:00 2020

@author: Adam Sychla

This modification allows running at any number of nhej probabilities.
    Comment was set by definition of nhej variable.
    The for loop of nhejVar was set to run at length of variable nhej

Modifications made in commenting to clarify steps (and make sections easier to find)

Modified on Fri Mar 27 12:31:00 2020

@author: Adam Sychla

Genome for SGD consolidated into single genome assumes independent assortment
Adds Sex Chromosomes

Modified on Wed Apr 08 22:35:00

@author: Adam Sychla

Single Genome expanded to allow programing of linkage dysequillibrium through LM matrix
Uses typeExp value to determine SSIMS vs. FAMSS

Modified on Thurs Jul 22 09:01:00

@author: Adam Sychla

Cap development between 10 and 30 C 30 set based on https://doi.org/10.1603/EN13200

Modified on Thurs Jul 22 09:15:00

@author: Adam Sychla

Added accidental mortality parameter as a function of temperature from https://link.springer.com/article/10.1007/s10340-015-0681-z

Modified on Mon Jul 26 13:21:00

@author: Adam Sychla

Adjusted development to that of https://link.springer.com/article/10.1007/s10340-015-0681-z

Temperature dependent fecundity from http://dx.doi.org/10.1093/jee/tow006

Modified on Tues Aug 17 12:49:00

@author: Adam Sychla

Switched to include second EGI construct

Modified on Tues Aug 17 13:10:00

@author: Adam Sychla

Multiple Matings possible (equal choice probability)

Modified on Tues Oct 05 08:26:30

@author: Adam Sychla

Fully allow multiple matings


"""
windows=True #if True imports winsound and alerts end of simulation. Set to false if NOT running on Windows

import random
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from mesa import Agent, Model
from mesa.time import RandomActivation
from mesa.space import MultiGrid
from mesa.datacollection import DataCollector
import time
import math
if windows==True:
    import winsound
import sys



'''__________________________________________________
First the script will import a steady-state wild-type
population that will be used to seed each population
____________________________________________________'''


#seed = "seedDataNew.pkl"                                               
#StateGenPosData = pd.read_pickle(seed)
#seedData = StateGenPosData.loc[0].values

tempC = "tempData2010.csv"
TempData = pd.read_csv(tempC)
TempDataV2 = TempData = list(TempData['Temp'])
stepsize=1 #day equivalent of each timestep

'''__________________________________________________
Adjust the following parameters for a simulation of
interest.
__________________________________________________'''


#print(len(seedData))

#Locus Linkage Matrix range[0.5-1]=independent to fully linked/ Diagnol definitionally=1
LM = []
LM.append([1,0.5,0.5,0.5,0.5,0.5,0.5])#B locus
LM.append([0.5,1,0.5,0.5,0.5,0.5,0.5])#D locus
LM.append([0.5,0.5,1,0.5,0.5,0.5,0.5])#P locus
LM.append([0.5,0.5,0.5,1,0.5,0.5,0.5])#T locus
LM.append([0.5,0.5,0.5,0.5,1,0.5,0.5])#L locus
LM.append([0.5,0.5,0.5,0.5,0.5,1,0.5])#G locus
LM.append([0.5,0.5,0.5,0.5,0.5,0.5,1])#X chromosome

for nhejVar in range(1):


#Genotypes: p=wild-type promoter, P=engineered promoter G=Gene Drive R=Resistance Allele I=Resistant KO W=wild-type L=female lethal l=wild-type T=PTA t=wild-type U=DUpd+PTA u=Delta_Upd q=p promoter conversion r=natural mutation in p x=natural mutation in X
#Starting Genotypes will always start female.
#Upon generation of organsim last X may be switched to Y
#Allows for X linked GE
    startingGMOgenotype =  'bbddppttLLWWXX'     # SGD= 'bbddppttllGWXX', SSIMS = 'bbddPPTTLLWWXX', EGI = 'bbddPPTTllWWXX', FL = 'bbddppttLLWWXX', FAFL = bbdppttllWWUU
    wildtypeGenotype = 'ttllWWXX'         # for most simulations, wt = 'bbddppttllWWXX' NOTE:'bbddpp' is added further in the code to allow resistance


    #Resistance Frequencies
    HomingFreq = 0.98                   # Homing frequency (SGD), range: [0-1]
    NHEJfreq = 0            # NHEJ frequency (during gametogenesis, SGD), range: [0-1]
    promoterConversionFreq = 0          # Promoter Conversion Frequency (SSIMS/SGI), range: [0-1]
    mutationRate = 0                   # Mutation rate in targeted promoter

    #EDIT#
    Freq1 = 0                       #Rate of SNP1 in population
    Freq2 = 0                       #Rate of SNP2 in population

    startingGMO = 0                 #0 to account for reactionary release
    addedGMO = int(sys.argv[2])                        # intermittently added GE agents
    timeStepAdded = int(sys.argv[1])                 # number of time steps between intermittent addition.
    releaseCount = 0
    timeSteps = len(TempData)                     # number of time steps to simulate
    migrationRate = 0                   # range [0-1]; movement per adult per timestep;
    
    #Secondary Model parameters
    startingWT = 100          # wild-type agents placed at time step 0
    sexRatio = 0.50                     # range [0-1]; 0.25 = 25% females; 0.75 = 75% females
    GMsex = 0.5                           # range [0-1]; 0.25 = 25% females; 0.75 = 75% females
    
    gridWidth = 1                      # number of columns of population matrix
    gridHeight = 1                      # number of rows of population matrix
    borderCells = 0                     # width of 'Wild-type only' border
    
    #Density independent survival rates
    DayEggsPerFemale = 60
    MaxEggsPerFemale = 200

    carry=False # how much tet to raise the flies on. True==100mg/mL False==10mg/mL

    typeExp = 'FL'+str(startingGMO)+'start'+str(timeStepAdded)+'Release'+str(addedGMO)              # This is used for Filename generation '[typeExp]experiment[#].pkl'    
    
    '''____________________________________________
    End of Parameter Section; be careful if modifying
    values below
    ________________________________________________'''
    
    
    class Timer(object):
        def __init__(self, name=None):
            self.name = name
    
        def __enter__(self):
            self.tstart = time.time()
    
        def __exit__(self, type, value, traceback):
            if self.name:
                print('[{}]'.format(self.name))
            print('Elapsed: {}'.format(time.time() - self.tstart))
    
    class SWD(Agent):
        """A Spotted Wing Drosophila"""
        def __init__(self, unique_id, model):
            super().__init__(unique_id, model)
            self.lifeStage = 0                          
            self.state = 'egglv'
            self.pregnant = False
            self.mated = False
            self.gestating = 0
            self.mateGenotype = []
            self.moved = False
            self.fertile = True
            self.tet=False
            self.age = 0
            self.eggsLeft = MaxEggsPerFemale
            self.model.zzz += 1
    
            
        def mature(self):                                   # Progression from one life=stage to the next at each time step
            
            self.age += stepsize
            dayTemp=TempData[0]             #TempData has first data point removed with every timestep


            #Tempeture based mortality from Asplen et al (2015)
            Mfunc=stepsize*0.00035*(dayTemp-15)**2+0.01
            if random.random()<Mfunc and self.state!='dead':

                self.state = 'dead'
                self.lifeStage = 10000
                self.model.grid._remove_agent(self.pos, self)
                self.model.schedule.remove(self)
            
            #Max age: set at 100 days >> likely to survive. Left as a "clean up fucntion" in rare circumstance individual persists.
            if self.age >= 100 and self.state!='dead':

                self.state = 'dead'
                self.lifeStage = 10000
                self.model.grid._remove_agent(self.pos, self)
                self.model.schedule.remove(self)


            #progression of Egg/Larval Stage
            if self.state == 'egglv':


                if 'p' in self.genotype and 'T' in self.genotype:   #kill if wild-type promoter present with PTA
                    self.state = 'dead'
                    self.lifeStage = 10000
                    self.model.grid._remove_agent(self.pos, self)
                    self.model.schedule.remove(self)

                elif 'b' in self.genotype and 'D' in self.genotype:   #kill if wild-type promoter present with PTA
                    self.state = 'dead'
                    self.lifeStage = 10000
                    self.model.grid._remove_agent(self.pos, self)
                    self.model.schedule.remove(self)

                elif 'GG' in self.genotype:                         #kill if homozygous for Gene drive
                    self.lifeStage = 10000
                    self.state = 'dead'
                    self.model.grid._remove_agent(self.pos, self)
                    self.model.schedule.remove(self)
                    
                elif 'G' in self.genotype and 'I' in self.genotype: #Kill if no expression of WT gene for SGD
                    self.lifeStage = 10000
                    self.state = 'dead'
                    self.model.grid._remove_agent(self.pos, self)
                    self.model.schedule.remove(self)
                    
                elif 'U' in self.genotype and 'X' in self.genotype: #kill if FAFL allele present with Wt X
                    self.lifeStage = 10000
                    self.state = 'dead'
                    self.model.grid._remove_agent(self.pos, self)
                    self.model.schedule.remove(self)

                #development calculated from Asplen et al (2015) NOTE: 243 factor converts to degree-days
                dev = stepsize*234*(0.0044*(dayTemp-5.975))/(1+4.5**(dayTemp-31)) 
                self.lifeStage += dev
                y=self.lifeStage

                #Use Normal CDF centered around mean Egg degree days+ mean Larval degree days
                if random.random()<1/2*(1+math.erf((y-140.785)/(20.49*math.sqrt(2)))) and self.state!='dead':

                    self.state = 'pupa'
                    self.lifeStage = 0

            elif self.state == 'pupa':

                #development calculated from Asplen et al (2015) NOTE: 243 factor converts to degree-days
                dev = stepsize*234*(0.0044*(dayTemp-5.975))/(1+4.5**(dayTemp-31))
                self.lifeStage += dev
                y=self.lifeStage

                #Use Normal CDF centered around mean Pupal degree days
                if random.random()<1/2*(1+math.erf((y-93.22)/(6.18*math.sqrt(2)))):

                    self.state = 'adult'
                    self.lifeStage = 0


            elif self.state == 'adult':

                if 'L' in self.genotype and self.tet==False and self.sex == 'female': #Comment out '''and self.sex == 'female' ''' for RIDL           #kill by female lethality
                    self.lifeStage = 10000
                    self.state = 'dead'
                    self.model.grid._remove_agent(self.pos, self)
                    self.model.schedule.remove(self)

                else:

                    #development calculated from Asplen et al (2015) NOTE: 243 factor converts to degree-days
                    dev = stepsize*234*(0.0044*(dayTemp-5.975))/(1+4.5**(dayTemp-31))
                    self.lifeStage += dev
                    y=self.lifeStage

                    #Use Normal CDF centered around mean Adult degree days
                    if random.random()<1/2*(1+math.erf((y-1050)/(40.41*math.sqrt(2)))):

                        self.state = 'dead'
                        self.lifeStage = 10000
                        self.model.grid._remove_agent(self.pos, self)
                        self.model.schedule.remove(self)




            
            
                
        # Moves SWD between neighboring populations if simulating migration
        def move(self):                                                     
            possible_steps = self.model.grid.get_neighborhood(
                self.pos,
                moore=True,                                                 # includes diagonol moves, otherwise von neumann
                include_center=False)
            new_position = random.choice(possible_steps)
            self.model.grid.move_agent(self, new_position)
            self.pos = list(new_position)
            self.moved = True

        # Produce new eggs with genotypes determined by parents    
        def reproduce(self, maleGenotype, female):  
            if female.state == 'adult':

                dayTemp=TempData[0]
                if self.eggsLeft>0 and dayTemp>5 and dayTemp<30:
                    

                    #number of eggs laid determined from Ryan et al (2016)
                    Eggs2Lay = stepsize*3.38313e-304*(2700.66-(dayTemp-22.87)**2)**88.53 #Simplified form of: 659.06*((88.53+1)/(3.14*52.32**(2*88.53+2))*(52.32**2-(dayTemp-22.87)**2-6.06**2)**88.53)

                    if Eggs2Lay > self.eggsLeft:

                        Eggs2Lay = self.eggsLeft

                    if random.random()<Eggs2Lay-math.floor(Eggs2Lay):
                        Eggs2Lay=math.floor(Eggs2Lay)+1

                    else:
                        Eggs2Lay=math.floor(Eggs2Lay)

                    self.eggsLeft-=Eggs2Lay

                else:

                    Eggs2Lay=0

                    
                for i in range(Eggs2Lay):
                    egg = SWD(self.model.zzz,self.model)
                    #generate Paternal Alleles to pass on
                    genSelect=random.randint(0,len(maleGenotype)-1)
                    maleGenotype2 = maleGenotype[genSelect]
                    
                    #Gene Drive Conversion Rules
                    if 'G' in maleGenotype2:                                     # Decide on inherited genotype from drive allele
                        if 'W' in maleGenotype2:
                            randNum = random.random()
                            
                            if randNum < np.multiply(HomingFreq,np.subtract(1,NHEJfreq)):
                                maleGenotype2=maleGenotype2.replace('W','G')
                                
                            elif np.multiply(HomingFreq,np.subtract(1,NHEJfreq)) < randNum < HomingFreq:
                                if random.random() < 0.33:                  
                                    maleGenotype2=maleGenotype2.replace('W','R')
                                    
                                else:
                                    maleGenotype2=maleGenotype2.replace('W','I')
                                    
                            else:
                                pass
                            
                        elif 'R' in maleGenotype2:                               #pass of R or G depending by linkage
                            pass
                        
                        else:
                            raise NameError('invalid Male Genotype')
                    #/Gene Drive Conversion Rules
                    
                    haploM=''

                    #Uses Linkage Matrix to generate Paternal Alleles
                    for x in range(int(len(maleGenotype2)/2)): #ensures haploid germcell is half length of diploid
                        P=0.5 #first allele is passed along with 50% rate
                        z=0
                        for y in haploM:

                            #determines if next allele to generate is linked to any of the previously generated alleles. Sets to closest linkage
                            P=0.5
                            z=maleGenotype2.index(y)/2
                            if LM[x][int(z)]>P:
                                P=LM[x][int(z)]

                        #determines which of the two alleles is passed along
                        if random.random()<P:
                            if int(z)==z:
                                haploM+=maleGenotype2[x*2]
                            else:
                                haploM+=maleGenotype2[x*2+1]

                        else:
                            if int(z)==z:
                                haploM+=maleGenotype2[x*2+1]
                            else:
                                haploM+=maleGenotype2[x*2]
                                
                    #/generate Paternal Alleles to pass on
                                
                    #generate Maternal Allele to pass on
                    femaleGenotype = female.genotype
                    
                    #Gene Drive Conversion Rules
                    if 'G' in femaleGenotype:                                     # Decide on inherited genotype from drive allele
                        if 'W' in femaleGenotype:
                            randNum = random.random()
                            if randNum < np.multiply(HomingFreq,np.subtract(1,NHEJfreq)):
                                femaleGenotype=femaleGenotype.replace('W','G')
                            elif np.multiply(HomingFreq,np.subtract(1,NHEJfreq)) < randNum < HomingFreq:
                                if random.random() < 0.33:                  
                                    femaleGenotype=femaleGenotype.replace('W','R')
                                else:
                                    femaleGenotype=femaleGenotype.replace('W','I')
                            else:
                                pass
                            
                        elif 'R' in femaleGenotype:                               #pass of R or G depending by Mendelian genetics
                            pass
                        
                        else:
                            raise NameError('invalid feMale Genotype')
                    #/Gene Drive Conversion Rules

                    haploF=''

                    #Uses Linkage Matrix to generate Maternal Alleles
                    for x in range(int(len(femaleGenotype)/2)):
                        P=0.5 #first allele is passed along with 50% rate
                        z=0
                        
                        for y in haploF:

                            #determines if next allele to generate is linked to any of the previously generated alleles. Sets to closest linkage
                            P=0.5
                            z=femaleGenotype.index(y)/2
                            if LM[x][int(z)]>P:
                                P=LM[x][int(z)]

                        #determines which of the two alleles is passed along
                        if random.random()<P:
                            if int(z)==z:
                                haploF+=femaleGenotype[x*2]
                            else:
                                haploF+=femaleGenotype[x*2+1]

                        else:
                            if int(z)==z:
                                haploF+=femaleGenotype[x*2+1]
                            else:
                                haploF+=femaleGenotype[x*2]
                    #/generate Maternal Allele to pass on


                    #intercolates the two haploid genotypes into the final genome for the new agent
                    egg.genotype=''        
                    for x in range(len(haploM)):
                        egg.genotype+=haploM[x] + haploF[x]
                    
                    if 'Y' in egg.genotype:
                        egg.sex='male'
                    else:
                        egg.sex='female'

                    #RULES FOR PROMOTER CONVERSION
                    if 'Pp' in egg.genotype or 'pP' in egg.genotype:
                        if random.random() < promoterConversionFreq:
                            egg.genotype = egg.genotype.replace('p','r')

                    if 'Bb' in egg.genotype or 'bB' in egg.genotype:
                        if random.random() < promoterConversionFreq:
                            egg.genotype = egg.genotype.replace('b','c')

                    if 'XU' in egg.genotype or 'UX' in egg.genotype:
                        if random.random() < promoterConversionFreq:
                            egg.genotype = egg.genotype.replace('X','u')

                    if 'p' in egg.genotype:
                        if random.random() < mutationRate:
                            egg.genotype = egg.genotype.replace('p','r')

                    if 'b' in egg.genotype:
                        if random.random() < mutationRate:
                            egg.genotype = egg.genotype.replace('p','r')
                    
                    if 'X' in egg.genotype:
                        if random.random() < mutationRate:
                            egg.genotype = egg.genotype.replace('X','x')
                    ##############################
                    egg.state = 'egglv'
                    egg.lifeStage = 1
                    if carry==True and self.tet==True:
                        egg.tet = 'Carry'
                    else:
                        egg.tet = False
                    self.model.grid.place_agent(egg, tuple(female.pos))
                    self.model.schedule.add(egg)
            

                self.model.num_agents = self.model.num_agents + Eggs2Lay       


        
        def female_mate(self):                                                  # Mating-ready females find random mating partner male
            cellmates = self.model.grid.get_cell_list_contents([self.pos])
            matingPartners = []
            if len(cellmates) > 1:
                for i in range(len(cellmates)):
                    if cellmates[i].sex == 'male' and 'adult' in cellmates[i].state: # Will mate with any adult male
                        matingPartners.append(cellmates[i])
                    else:
                        i=i+1
        
                if len(matingPartners) > 0:
                    matingPartner = random.choice(matingPartners)
                    self.mateGenotype.append(matingPartner.genotype)
                    if self.fertile == True and matingPartner.fertile == True:
                        matingPartner.mated = False                                 # males can mate multiple times
                        self.mated = True
                        self.pregnant = True
                        self.gestating = 1
                    else:
                        self.mated = False
                        self.pregnant = False
                        print("female_fertility; ",self.fertile, " Male_fertility: ",matingPartner.fertile)
                else:
                    return
            else:
                return    
            
        #defines actions taken by agent at each timestep
        def step(self):
            self.mature()
            if self.state =='adult' and self.sex == 'female':
                self.female_mate()
            if self.state =='adult' and self.sex == 'female' and self.mated == True :
                self.reproduce(self.mateGenotype, self)
            if random.random() < self.model.migration:
                self.move()
            
            else:
                self.mature()
            
    #CHANGE NAME
    class SWDModel(Model):
        """A model with some number of agents."""
        def __init__(self, N, width, height):
            self.num_agents = N
            self.grid = MultiGrid(width, height, True)
            self.schedule = RandomActivation(self)
            self.migration = 0
            self.zzz = 0
    
            for i in range(self.num_agents):
                a = SWD(i, self)
                self.schedule.add(a)
                
                # Add the agent to a random grid cell, this step is overridden if agent is placed to specific cell
                x = random.randrange(self.grid.width)
                y = random.randrange(self.grid.height)
                self.grid.place_agent(a,(x,y))
                
            self.datacollector = DataCollector(
                agent_reporters={"Sex": lambda a: a.sex,
                    "State": lambda a: a.state,
                    "Genotype": lambda a: a.genotype,
                    "Position": lambda a: a.pos})
        #step model takes with each timestep
        def step(self,timestep):
            '''Advance the model by one stop.'''               
            self.datacollector.collect(self)
            self.schedule.step()
            del TempData[0]
            print("Model step # ")
            
    
    #RunParameters
    
    filename = sys.argv[3]+typeExp + '_Release' + str(timeStepAdded)  + '.pkl'
    model = SWDModel(0,gridHeight,gridWidth)
    cells = gridWidth * gridHeight
    model.migration = migrationRate
    zzz=1                                                                       # zzz tracks number of agents, increases by one with each birth
    
                                                                                # put WT SWD in each cell
    for i in range(gridHeight):
        for j in range(gridWidth):
            for h in range(startingWT):
                new = SWD(model.zzz,model)
                new.state = 'adult'
                new.lifeStage = 0
                tempGenoType=wildtypeGenotype

                #introduaces SNPs at p or b allele in the Wildtype based on frequency defined earlier
                if random.random()<Freq1:
                    tempGenoType='r'+tempGenoType
                else:
                    tempGenoType='p'+tempGenoType
                if random.random()<Freq1:
                    tempGenoType='r'+tempGenoType
                else:
                    tempGenoType='p'+tempGenoType

                tempGenoType='dd'+tempGenoType

                #introduaces SNPs at p or b allele in the Wildtype based on frequency defined earlier
                if random.random()<Freq2:
                    tempGenoType='c'+tempGenoType
                else:
                    tempGenoType='b'+tempGenoType
                if random.random()<Freq2:
                    tempGenoType='c'+tempGenoType
                else:
                    tempGenoType='b'+tempGenoType

                if random.random()<sexRatio:
                    new.sex = 'female'
                else:
                    new.sex = 'male'
                if new.sex == 'female':
                    new.genotype = tempGenoType
                else:
                    new.genotype = tempGenoType[:-1]+"Y"

                new.mated = False
                new.pregnant = False
                new.mateGenotype = []
                new.tet=False
                model.grid.place_agent(new,tuple([i,j]))
                model.schedule.add(new)
                
            print("Seeded ",startingWT," wildtype in [", i, ",", j, "]")
    
        
                                                                                # Put GMO mosquitoes in center cells   
    for i in range(gridHeight-(2*borderCells)):
        for j in range(gridWidth-(2*borderCells)):
            for h in range(startingGMO):
                new = SWD(model.zzz,model)
            
                new.genotype = startingGMOgenotype
                if random.random()<GMsex:
                    new.genotype = startingGMOgenotype
                    new.sex='female'
                else:
                    new.genotype = startingGMOgenotype[:-1]+"Y"
                    new.sex='male'
                new.state = 'adult'
                new.tet = True
                new.lifeStage = 0
                model.grid.place_agent(new, tuple([i+borderCells,j+borderCells]))
                model.schedule.add(new)
            print("Seeded ",startingGMO," GMO in [", i+borderCells, ",", j+borderCells, "]")
    
    timeList=[]                                                                 # Model counter for debugging purposes
    with Timer('FULL EXECUTION'):            
        for i in range(timeSteps):


            # Adding new GE organisms and saving compressed datafile at each multiple of timestep added
            if i > 0 and i % timeStepAdded == 0:
                for j in range(gridHeight-(2*borderCells)):
                    for k in range(gridWidth-(2*borderCells)):

                        for l in range(addedGMO):

                            new =  SWD(model.zzz,model)
                            if random.random()<GMsex:
                                new.genotype = startingGMOgenotype
                                new.sex='female'
                            else:
                                new.genotype = startingGMOgenotype[:-1]+"Y"
                                new.sex='male'
                            new.state = 'adult'
                            new.tet = True
                            new.lifeStage = 0
                            model.grid.place_agent(new,tuple([j,k]))
                            model.schedule.add(new)
                            
                        print("Added ", addedGMO," GMO to in [", j, ",", k, "]")
                model.datacollector.get_agent_vars_dataframe()[['State','Genotype','Position', 'Sex']].copy().to_pickle(filename)
                with Timer('model step {}'.format(i)):
                    model.step(i)
            else:
                with Timer('model step {}'.format(i)):
                    model.step(i)
    
    gestatingCtr=0
    eggCtr=0
    elseCtr=0
    for a in model.schedule.agents:
        if a.state == 'gestating':
            gestatingCtr+=1
        elif a.state == 'egglv':
            eggCtr+=1
        else:
            elseCtr+=1
    print('gestating: {}'.format(gestatingCtr))
    print('egg: {}'.format(eggCtr))
    print('elseCtr: {}'.format(elseCtr))

    model.datacollector.get_agent_vars_dataframe()[['State','Genotype','Position', 'Sex']].copy().to_pickle(filename)
    if windows==True:
        winsound.Beep(5000,2000)

if windows==True:
    winsound.Beep(2000,2000)

'''
https://link.springer.com/article/10.1007/s10340-020-01292-w
https://www.mdpi.com/2075-4450/11/11/751/htm
https://link.springer.com/article/10.1007/s10340-015-0681-z
https://www.sciencedirect.com/science/article/pii/S0304380021002313#fig1
https://academic.oup.com/jee/article/109/2/746/2379864
https://academic.oup.com/ee/article/43/2/501/533184
'''
back to top