Part 6: Using the model for a study¶
As we have seen, model components and models are implemented in an
object-oriented way as subpackages and modules of the pycopancore
package folder. Studies that use a model for a simulation experiment are
however implemented as python scripts and reside in the study folder.
So let us now switch into the role of a model end user and perform some such
‘study’. Again, we can use a template to get started:
Copy
templates/studies/SOME_STUDY.pytostudies/run_my_exploit.pyand edit the imports like this:import pycopancore.models.my_exploit as M
In this study, we have only one social system and allow our individuals to have only two possible
fishing_efforts, hence we adjust the parameters as follows:# model parameters: ncells = 100 nindseach = 1 # no. of individuals per cell link_density = 0.1 # random network link density low_effort = 30 * D.person_hours / D.weeks high_effort = 60 * D.person_hours / D.weeks # simulation parameters: t_max = 100 # interval for which the model will be simulated dt = 1 # desired temporal resolution of the resulting output.
Adjust the entity generation as follows:
world = M.World(environment = env, metabolism = met, culture = cul) soc = M.SocialSystem(world = world) cells = [M.Cell(social_system = soc) for j in range(ncells)] inds = [M.Individual(cell = c, fishing_effort = choice([low_effort, high_effort]) ) for c in cells for j in range(nindseach)]
Note how we have already set all individuals’ initial fishing effort here.
Another possibility for setting initial values for a whole list of entities
at the same time is by using the set_values method of the corresponding
Variable object in the entity-type’s class. Let’s do this for the initial
fish stocks:
Replace the random population block by this similar code:
S0 = uniform(size=ncells) M.Cell.fish_stock.set_values(cells, S0)
Note that here we did not specify a unit, so the numbers will be interpreted as
multiples of the variable’s default unit (t_fish in this case, as specified
in the interface of my_exploit_growth).
A third possibility to manipulate the initial value of a variable for some specific entity or process taxon is by accessing the variable’s value directly, so we could have instead written:
for c in cells:
c.fish_stock = uniform() * M.t_fish
We use this way of accessing values now for initializing the social network
between the individuals, which is stored in the variable
Culture.acquaintance_network. Since this is shipped with the base
component of pycopancore, it was automatically initialized to contain an empty
network when Culture was instantiated above. Likewise, each Individual
that was generated above has already registered itself automatically as a node
of this network. So the only thing that remains for us to do is add some links.
Since this is a common task, the template already contains suitable code for
this:
# initialize some network:
for index, i in enumerate(inds):
for j in inds[:index]:
if uniform() < link_density:
cul.acquaintance_network.add_edge(i, j)
The subsequent code block eventually runs the model, and we can also leave it as it is:
runner = Runner(model=model)
traj = runner.run(t_0=0, t_1=t_max, dt=dt)
After this simulation has finished, the traj object returned by
Runner.run() contains the time evolution of all variables from t_0
to t_1 in steps which are at most dt apart. The actual time steps
might vary since our model has irregularly timed events at completely random
time points and the runner returns all event time points plus sufficiently
many intermediate time points.
Since at event time points some variables will display discontinuous behaviour,
the runner actually returns two entries for each such event time point t
(but not for the intermediate time points), the first containing the variable
values right before t, the second those right after t.
The precise data structure of traj is this:
traj['t']is the list of reported time pointstraj[M.Cell.fish_stock][c]is the list of corresponding fish stocks of cellc.
Hence if we want the total fish stock and average fishing effort plotted as the final step of our study, we can do it like this:
Adjust the final plotting code as follows:
stock = traj[M.Cell.fish_stock] effort = traj[M.Individual.fishing_effort] total_stock = np.sum([stock[c] for c in cells], axis=0) avg_effort = np.mean([effort[i] for i in inds], axis=0) plt.plot(traj["t"], total_stock, 'g', label="fish stock") plt.plot(traj["t"], avg_effort, 'b', label="fishing effort") plt.legend() plt.show()
This finishes our coding work, so let’s finally try it out and hope we made no typos: Part 7: Running the study script