Skip to content
This repository was archived by the owner on Jun 21, 2024. It is now read-only.

Commit def604f

Browse files
committed
Make daisyworld runnable
1 parent 3271958 commit def604f

4 files changed

Lines changed: 34 additions & 49 deletions

File tree

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "InteractiveDynamics"
22
uuid = "ec714cd0-5f51-11eb-0b6e-452e7367ff84"
33
repo = "https://github.com/JuliaDynamics/InteractiveDynamics.jl.git"
4-
version = "0.21.5"
4+
version = "0.21.6"
55

66
[deps]
77
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"

src/agents/abmplot.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Requires `Agents`. See also [`abmvideo`](@ref) and [`abmexploration`](@ref).
2020
each agent will be plotted as. They can each be either a constant or a *function*,
2121
which takes as an input a single agent and outputs the corresponding value.
2222
23-
Using constants: `ac = "#338c54", as = 10, am = :diamond`
23+
Using constants: `ac = "#338c54", as = 15, am = :diamond`
2424
2525
Using functions:
2626
```julia
@@ -156,7 +156,7 @@ This is the internal recipe for creating an `_ABMPlot`.
156156

157157
# Agent
158158
ac = JULIADYNAMICS_COLORS[1],
159-
as = 10,
159+
as = 15,
160160
am = :circle,
161161
offset = nothing,
162162
scatterkwargs = NamedTuple(),

src/agents/daisyworld_def.jl

Lines changed: 30 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,96 +1,83 @@
11
using Agents
2-
using Statistics: mean
32
import StatsBase
43
using Random
54

6-
75
@agent Daisy GridAgent{2} begin
86
breed::Symbol
97
age::Int
108
albedo::Float64 # 0-1 fraction
119
end
1210

13-
DaisyWorld = ABM{<:GridSpaceSingle, Daisy};
11+
DaisyWorld = ABM{<:GridSpaceSingle, Daisy}
1412

1513
function update_surface_temperature!(pos, model::DaisyWorld)
16-
ids = ids_in_position(pos, model)
17-
absorbed_luminosity = if isempty(ids) # no daisy
18-
## Set luminosity via surface albedo
14+
absorbed_luminosity = if isempty(pos, model) # no daisy
1915
(1 - model.surface_albedo) * model.solar_luminosity
2016
else
21-
## Set luminosity via daisy albedo
22-
(1 - model[ids[1]].albedo) * model.solar_luminosity
17+
daisy = model[id_in_position(pos, model)]
18+
(1 - daisy.albedo) * model.solar_luminosity
2319
end
24-
## We expect local heating to be 80 ᵒC for an absorbed luminosity of 1,
25-
## approximately 30 for 0.5 and approximately -273 for 0.01.
2620
local_heating = absorbed_luminosity > 0 ? 72 * log(absorbed_luminosity) + 80 : 80
27-
## Surface temperature is the average of the current temperature and local heating.
2821
model.temperature[pos...] = (model.temperature[pos...] + local_heating) / 2
2922
end
3023

3124
function diffuse_temperature!(pos, model::DaisyWorld)
32-
ratio = get(model.properties, :ratio, 0.5) # diffusion ratio
25+
ratio = model.ratio # diffusion ratio
3326
npos = nearby_positions(pos, model)
3427
model.temperature[pos...] =
3528
(1 - ratio) * model.temperature[pos...] +
36-
## Each neighbor is giving up 1/8 of the diffused
37-
## amount to each of *its* neighbors
3829
sum(model.temperature[p...] for p in npos) * 0.125 * ratio
3930
end
4031

41-
function propagate_daisy!(pos, model::DaisyWorld)
42-
ids = ids_in_position(pos, model)
43-
if !isempty(ids)
44-
daisy = model[ids[1]]
45-
temperature = model.temperature[pos...]
46-
## Set optimum growth rate to 22.5 ᵒC, with bounds of [5, 40]
47-
seed_threshold = (0.1457 * temperature - 0.0032 * temperature^2) - 0.6443
48-
if rand(model.rng) < seed_threshold
49-
## Collect all adjacent position that have no daisies
50-
empty_neighbors = Tuple{Int,Int}[]
51-
neighbors = nearby_positions(pos, model)
52-
for n in neighbors
53-
if isempty(ids_in_position(n, model))
54-
push!(empty_neighbors, n)
55-
end
56-
end
57-
if !isempty(empty_neighbors)
58-
## Seed a new daisy in one of those position
59-
seeding_place = rand(model.rng, empty_neighbors)
60-
add_agent!(seeding_place, model, daisy.breed, 0, daisy.albedo)
32+
function propagate!(pos, model::DaisyWorld)
33+
isempty(pos, model) && return
34+
daisy = model[id_in_position(pos, model)]
35+
temperature = model.temperature[pos...]
36+
seed_threshold = (0.1457 * temperature - 0.0032 * temperature^2) - 0.6443
37+
if rand(model.rng) < seed_threshold
38+
empty_near_pos = Tuple{Int,Int}[]
39+
for near_pos in nearby_positions(pos, model)
40+
if isempty(near_pos, model)
41+
push!(empty_near_pos, near_pos)
6142
end
6243
end
44+
if !isempty(empty_near_pos)
45+
seeding_place = rand(model.rng, empty_near_pos)
46+
add_agent!(seeding_place, model, daisy.breed, 0, daisy.albedo)
47+
end
6348
end
6449
end
6550

6651
function daisy_step!(agent::Daisy, model::DaisyWorld)
6752
agent.age += 1
68-
agent.age >= model.max_age && kill_agent!(agent, model)
53+
agent.age model.max_age && kill_agent!(agent, model)
6954
end
7055

7156
function daisyworld_step!(model)
7257
for p in positions(model)
7358
update_surface_temperature!(p, model)
7459
diffuse_temperature!(p, model)
75-
propagate_daisy!(p, model)
60+
propagate!(p, model)
7661
end
77-
model.tick += 1
62+
model.tick[] = model.tick[] + 1
7863
solar_activity!(model)
7964
end
8065

8166
function solar_activity!(model::DaisyWorld)
8267
if model.scenario == :ramp
83-
if model.tick > 200 && model.tick <= 400
68+
if model.tick[] > 200 && model.tick[] 400
8469
model.solar_luminosity += model.solar_change
8570
end
86-
if model.tick > 500 && model.tick <= 750
71+
if model.tick[] > 500 && model.tick[] 750
8772
model.solar_luminosity -= model.solar_change / 2
8873
end
8974
elseif model.scenario == :change
9075
model.solar_luminosity += model.solar_change
9176
end
9277
end
9378

79+
using Random
80+
9481
function daisyworld(;
9582
griddims = (30, 30),
9683
max_age = 25,
@@ -107,14 +94,12 @@ function daisyworld(;
10794

10895
rng = MersenneTwister(seed)
10996
space = GridSpaceSingle(griddims)
110-
properties = (;max_age, surface_albedo, solar_luminosity, solar_change, scenario,)
111-
properties = Dict(pairs(properties))
112-
properties[:tick] = 0
113-
properties[:temperature] = zeros(griddims)
97+
properties = (;max_age, surface_albedo, solar_luminosity, solar_change, scenario,
98+
tick = Ref(0), ratio = 0.5, temperature = zeros(griddims)
99+
)
114100

115101
model = ABM(Daisy, space; properties, rng)
116102

117-
## Populate with daisies: each position has only one daisy (black or white)
118103
grid = collect(positions(model))
119104
num_positions = prod(griddims)
120105
white_positions =
@@ -131,10 +116,9 @@ function daisyworld(;
131116
add_agent_pos!(wd, model)
132117
end
133118

134-
## Adjust temperature to initial daisy distribution
135119
for p in positions(model)
136120
update_surface_temperature!(p, model)
137121
end
138122

139-
return model, daisy_step!, daisyworld_step!
123+
return model
140124
end

src/agents/interaction.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ end
107107
function add_param_sliders!(fig, model, params, resetclick)
108108
datalayout = fig[end,:][1,2] = GridLayout(tellheight = true)
109109

110+
# TODO: This needs to become `SliderGrid`.
110111
slidervals = Dict{Symbol, Observable}()
111112
for (i, (k, vals)) in enumerate(params)
112113
startvalue = has_key(model[].properties, k) ?

0 commit comments

Comments
 (0)