The first challenge was to create a Python class which could represent individual organisms. I named the class "bios" - the Greek word for "life". The class includes a number of parameters relevant to animal movement such a current (x, y) location, maximum move possible per iteration, vectors to other "bios" instances (other virtual critters, if you will), and many others. The real trick (at least, for me) was creating a class that could be called from an instance of itself to create new instances in addition to the original. Essentially, I needed instances of the bios class to be able to reproduce themselves. The approach I settled on uses the native Python dictionary data structure. The first bios instance is initialized as an object inside the dictionary (the class.name parameter serves as the key and the instance object itself as the value). I created a method for the bios class (appropriately named "reproduce") which creates new instances of the bios class inside the same python dictionary as the original instance. Using this approach had some significant benefits including: the dictionary of key:value (name:instance) pairs can be used to save pertinent information (such as location, age, health, etc...) to a geodatabase, new instances can be initialized as objects in the dictionary using data from a geodatabase, and the dictionary serves as an iterable list of all bios instances currently in memory (handy for calculating things like the next move). For example, using a dictionary assigned to "i", the first instance could be initialized as follows in the Python prompt:
>>> i["bios1"] = bios()
Now I've got a dictionary containing my first instance of the bios class "bios1". To create 9 new, child instances in the dictionary I would do the following:
Now the dictionary "i" contains a total of ten bios instances. The nine new instances have been automatically assigned the keys "bios2", "bios3", "bios4", etc... using a counter which is concatenated to the base name "bios" as each new instance is created. Each new instance is also randomly assigned an x, y position within 1 unit of the parent instance (an arbitrary choice really). In this case, "bios1" was originally at 0,0 and the nine new instances were initialized randomly around this origin (see figure).
Plot of bios instance tracks over 100 calculated moves with a maximum move of 1 (arbitrary units).
count = 0
while count < 99:
for key in i:
i[key].calc_vectors() #method calculates vectors from each instance to all other instances
i[key].calc_move() #method calculates delta x, delta y based on vectors (above)
i[key].move(i[key].nextMove, i[key].nextMove) #method updates self.location
(full code - just follow the link and select "Download" to get the goods)
The code block above glosses over a lot of the more tedious elements of the algorithm, but hopefully you get the idea (if you're not much for programming, I'm probably boring you to death). Presently, each instance moves away from other instances in an inverse distance squared fashion. That is, the closer one bios instance is to another, the more it will move away from that instance. This effect grows exponentially as the distance between instances decreases, resulting in a rapid separation of closely spaced instances. However, the rate of separation quickly falls as the distance between them grows. Calculating the next move for each instance was a matter of summing the influences of all the other instances. This isn't necessarily accurate for animal behavior, but the movement calculation is fairly easily modified. I just wanted to validate the approach before complicating things.
As you can see, all the bios instances are initialized within 1 unit of 0, 0 but they quickly "repel" each other. Because the size of each move is proportional to 1 over the distance squared, even after 100 moves, all the instances are still within 15 units of the origin.
In the future, I'd like to create different classes (perhaps one for predators and one for prey), incorporate the influence of environmental factors into the model, and display the output in ArcMap. That will require me to work in angular units (latitude vs. longitude) rather the standard Cartesian coordinates; hopefully that won't be a problem. Maybe I'll create a web map where people can create their own creatures, drop them into an existing environment and see how they do. Like I said at the beginning, this project is just beginning. I've learned a lot about Python but there's still a long way to go.