-
Notifications
You must be signed in to change notification settings - Fork 14
Expand file tree
/
Copy pathdemographySim_orig.py
More file actions
executable file
·206 lines (171 loc) · 6.67 KB
/
Copy pathdemographySim_orig.py
File metadata and controls
executable file
·206 lines (171 loc) · 6.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
#!/usr/bin/env python
# Simulation to model demography on a landscape. This simulation
# will include:
# - birth
# - death
# - dispersal
# First Version
# - Asexual reproduction
# - Annual generation times
# - Poisson-distributed number of offspring
# - Discrete landscape
# - Max dispersal of 1 grid
# - No diagonal dispersal
# - Equal probability of different directions
# - Non-zero probably of not dispersing
# - Starts in the middle
# - Start size of 50
# - No carrying capacity
# Object types
# - Individuals
# - Landscape
# - Cell
# Each generation first disperses, then reproduces
import numpy.random as nr
# Class Definitions
class landscape:
"""This class holds all individuals across the landscape"""
def __init__(self,nRows=5,nCols=5,startSize=50):
"""
Creates a new grid-based with the number of rows, columns, and
starting population size specified by the user.
"""
self.nRows = nRows
self.nCols = nCols
self.startSize = startSize
self.sections = self.setup(self.nRows,self.nCols)
for _ in range(self.startSize):
self.sections[0][0].individuals.append(ind(myLandscape=self,myCell=self.sections[0][0]))
def setup(self,nRows,nCols):
"""Sets up the landscape as a list of lists containing cells."""
land = []
for rowNum in range(nRows):
row = []
for colNum in range(nCols):
row.append(cell(("%d_%d") % (rowNum,colNum)))
land.append(row)
return land
def printLandscape(self):
"""Print all id numbers of cells in landscape"""
for row in self.sections:
for col in row:
print("%d" % (len(col.individuals)), "\t", end="")
print("\n")
class cell:
"""This class represents a grid square on our landscape."""
def __init__(self,id):
self.id = id
self.individuals = []
class ind:
"""This class represents individuals in our population."""
def __init__(self,myLandscape,myCell,name="",rowPos=0,colPos=0,disProb=0.5):
self.myLandscape = myLandscape
self.myCell = myCell
self.name = name
self.offspring = []
self.meanOffNum = 2.0
self.rowPos = rowPos
self.colPos = colPos
self.disProb = disProb
def reproduce(self):
"""Return list of offspring"""
numOff = nr.poisson(self.meanOffNum)
offspringList = []
for _ in range(numOff):
offspringList.append(ind())
return offspringList
def disperse(self):
"""Move, if necessary, to new cell. disProb is dispersal probability."""
if (nr.random() < self.disProb):
# Middle cell
if (self.rowPos > 0) & (self.rowPos < self.myLandscape.nRows-1) & (self.colPos > 0) & (self.colPos < self.myLandscape.nCols-1):
ranNum = nr.random()
if (ranNum < 0.25):
self.rowPos = self.rowPos - 1
elif (ranNum < 0.5):
self.rowPos = self.rowPos + 1
elif (ranNum < 0.75):
self.colPos = self.colPos - 1
else:
self.colPos = self.colPos + 1
# Upper left cell
elif (self.rowPos == 0) & (self.colPos == 0):
ranNum = nr.random()
if (ranNum < 0.5):
self.rowPos = self.rowPos + 1
else:
self.colPos = self.colPos + 1
# Left edge cell
elif (self.rowPos > 0) & (self.rowPos < self.myLandscape.nRows-1) & (self.colPos == 0):
ranNum = nr.random()
if (ranNum < 0.33):
self.rowPos = self.rowPos - 1
elif (ranNum < 0.66):
self.rowPos = self.rowPos + 1
else:
self.colPos = self.colPos + 1
# Bottom left cell
elif (self.rowPos == self.myLandscape.nRows-1) & (self.colPos == 0):
ranNum = nr.random()
if (ranNum < 0.5):
self.rowPos = self.rowPos - 1
else:
self.colPos = self.colPos + 1
# Bottom edge cell
elif (self.rowPos == self.myLandscape.nRows-1) & (self.colPos > 0) & (self.colPos < self.myLandscape.nCols-1):
ranNum = nr.random()
if (ranNum < 0.33):
self.rowPos = self.rowPos - 1
elif (ranNum < 0.66):
self.colPos = self.colPos - 1
else:
self.colPos = self.colPos + 1
# Bottom right cell
elif (self.rowPos == self.myLandscape.nRows-1) & (self.colPos == self.myLandscape.nCols-1):
ranNum = nr.random()
if (ranNum < 0.5):
self.rowPos = self.rowPos - 1
else:
self.colPos = self.colPos - 1
# Right edge cell
elif (self.rowPos > 0) & (self.rowPos < self.myLandscape.nRows-1) & (self.colPos == self.myLandscape.nCols-1):
ranNum = nr.random()
if (ranNum < 0.33):
self.rowPos = self.rowPos - 1
elif (ranNum < 0.66):
self.rowPos = self.rowPos + 1
else:
self.colPos = self.colPos - 1
# Upper right cell
elif (self.rowPos == 0) & (self.colPos == self.myLandscape.nCols-1):
ranNum = nr.random()
if (ranNum < 0.5):
self.rowPos = self.rowPos + 1
else:
self.colPos = self.colPos - 1
# Upper edge cell
else:
ranNum = nr.random()
if (ranNum < 0.33):
self.rowPos = self.rowPos + 1
elif (ranNum < 0.66):
self.colPos = self.colPos - 1
else:
self.colPos = self.colPos + 1
self.myCell.individuals.remove(self)
self.myLandscape.sections[self.rowPos][self.colPos].individuals.append(self)
self.myCell = self.myLandscape.sections[self.rowPos][self.colPos]
# Run demographic simulation
simLandscape = landscape()
print("Generation 0:"); print()
simLandscape.printLandscape()
gens = 20
for g in range(gens):
allIndividuals = []
for r in range(simLandscape.nRows):
for c in range(simLandscape.nCols):
allIndividuals.extend(simLandscape.sections[r][c].individuals)
for i in allIndividuals:
i.disperse()
print("Generation %d:" % (g+1)); print()
simLandscape.printLandscape()