diff --git a/src/core/simulation.jl b/src/core/simulation.jl
index e24686d53d8d806ccec70a27e511f8bd8b40bd40..cbd76be58dbbed463b24029a5786963ac03f7378 100644
--- a/src/core/simulation.jl
+++ b/src/core/simulation.jl
@@ -24,7 +24,7 @@ mutable struct SimulationModel
     crops::Dict{String,CropType}
     farmers::Vector{Farmer}
     farmplots::Vector{FarmPlot}
-    animals::Vector{Animal}
+    animals::Vector{Union{Animals,Nothing}}
     migrants::Vector{Pair{Animal,Date}}
     events::Vector{FarmEvent}
 end
@@ -85,7 +85,6 @@ a helper function for `initialise()`.
 """
 function initmodel(settings::Dict{String, Any})
     #TODO catch exceptions and print them to the log file
-    #TODO remove Agents.jl-related code, reimplement this more cleanly (#72)
     @debug "Initialising model object."
     createdatadir(settings["core.outdir"], settings["core.overwrite"])
     logger = modellogger(settings["core.loglevel"], settings["core.outdir"])
@@ -97,20 +96,20 @@ function initmodel(settings::Dict{String, Any})
                               settings["core.enddate"])
         crops = readcropparameters(settings["crop.cropfile"],
                                    settings["crop.growthfile"])
-        space = GridSpace(size(landscape), periodic=false)
-        properties = Dict{Symbol,Any}(:settings=>settings,
-                                      :logger=>logger,
-                                      :date=>settings["core.startdate"],
-                                      :landscape=>landscape,
-                                      :weather=>weather,
-                                      :crops=>crops,
-                                      :migrants=>Vector{Pair{Animal, Date}}(),
-                                      :dataoutputs=>Vector{DataOutput}(),
-                                      :datatables=>Dict{String, DataFrame}(),
-                                      :events=>Vector{FarmEvent}())
-        model = AgentBasedModel(Union{Farmer,Animal,FarmPlot},
-                                space, properties=properties,
-                                rng=StableRNG(settings["core.seed"]), warn=false)
+        model = SimulationModel(settings,
+                                StableRNG(settings["core.seed"]),
+                                logger,
+                                Vector{DataOutput}(),
+                                Dict{String, DataFrame}(),
+                                settings["core.startdate"],
+                                landscape,
+                                weather,
+                                crops,
+                                Vector{Farmer}(),
+                                Vector{FarmPlot}(),
+                                Vector{Union{Animals,Nothing}}(),
+                                Vector{Pair{Animal, Date}}(),
+                                Vector{FarmEvent}())
         saveinputfiles(model)
         initfields!(model)
         initfarms!(model)
@@ -156,19 +155,15 @@ function stepsimulation!(model::AgentBasedModel)
     #TODO catch exceptions and print them to the log file
     with_logger(model.logger) do
         @info "Simulating day $(model.date)."
-        #TODO remove Agents.jl-related code, reimplement this more cleanly (#72)
-        for a in Schedulers.ByType((Farmer,FarmPlot,Animal), true)(model)
-            try #The animal may have been killed
-                stepagent!(model[a], model)
-            catch exc
-                # check if the KeyError comes from the `model[a]` or the function call
-                #FIXME this also silences KeyErrors caused in the species code (e.g.
-                # by accessing dead mates) - will be fixed once I reorganise the code
-                isa(exc, KeyError) && isa(exc.key, Int) ? continue : throw(exc)
-            end
+        #XXX move the two loops into the relevant submodels?
+        for f in model.farmers
+            stepagent!(f, model)
+        end
+        for p in model.farmplots
+            stepagent!(p, model)
         end
-        updateevents!(model)
         updatenature!(model)
+        updateevents!(model)
         outputdata(model)
         model.date += Day(1)
         model