Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New function offline_run! to write data during run! #815

Merged
merged 43 commits into from
Jul 10, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
1f2241d
Allow writing data during `run!`
kavir1698 Jun 8, 2022
eef1e0c
fix conflicts
mastrof Jun 3, 2023
aa46620
define new `offline_run!` function
mastrof Jun 3, 2023
893aaa8
fix tests
mastrof Jun 3, 2023
a1a9361
cleanup `run!`
mastrof Jun 3, 2023
1267d2d
cleanup `run!` (again)
mastrof Jun 3, 2023
13fb707
fix typo
mastrof Jun 3, 2023
4c30cd0
fix docstrings and use `empty!` instead of reinitializing dataframes
mastrof Jun 10, 2023
3c42bba
remove duplicate CSV from project extras
mastrof Jun 10, 2023
15a6584
use semicolon for kwargs and fix docstring
mastrof Jun 11, 2023
c21d2f0
mention `offline_run!` in the `run!` docstring
mastrof Jun 11, 2023
03487ac
select writing backend via kwarg and update test
mastrof Jun 12, 2023
9207cc0
update project and changelog
mastrof Jun 12, 2023
088a956
add `offline_run!` to docs
mastrof Jun 12, 2023
dd0156c
introduce function barrier
mastrof Jun 15, 2023
e5a6457
Merge branch 'main' of https://github.com/JuliaDynamics/Agents.jl int…
mastrof Jun 15, 2023
6b2cab5
Backends as symbols; isolate writer functions
fbanning Jun 20, 2023
a5168c7
Add Arrow dependency
fbanning Jun 20, 2023
3368582
Add stub for arrow integration in AgentsIO
fbanning Jun 20, 2023
ab617f6
Simplify flow in functions
fbanning Jun 20, 2023
7c9d968
Update docstring
fbanning Jun 20, 2023
8958696
Add tests for Arrow
fbanning Jun 21, 2023
7728d81
Condense function defs
fbanning Jun 21, 2023
7630fa4
Convert ArgumentError to AssertionError
fbanning Jun 21, 2023
962d4e3
Fix docstring formatting
fbanning Jun 21, 2023
1073722
Condense append check
fbanning Jun 21, 2023
82b0617
Fix test for Arrow.Stream
fbanning Jun 21, 2023
9dbc101
Catch collected data not yet written to disk
fbanning Jun 21, 2023
86788bb
Update CHANGELOG
fbanning Jun 21, 2023
7336c91
Reintroduce function barrier
fbanning Jun 21, 2023
800b5c8
Move extensions into separate folders
fbanning Jun 21, 2023
b4f4a62
Add AgentsArrow extension
fbanning Jun 21, 2023
7992063
Remove AgentsIO for Arrow for now
fbanning Jun 21, 2023
875fb8c
Turn Arrow into weak dep for ext
fbanning Jun 21, 2023
fdc63fb
Create stub function for extension
fbanning Jun 21, 2023
2930f57
Directly use Arrow in tests
fbanning Jun 21, 2023
216f48a
Add Arrow as test dependency
fbanning Jun 21, 2023
3971829
Merge AgentsIO placeholder funcs into AgentsArrow
fbanning Jun 21, 2023
0f308cd
Add placeholders for AgentsIO with Arrow
fbanning Jun 21, 2023
c137a7e
maybe
Tortar Jul 10, 2023
80f9adc
Merge branch 'main' into offline_run
Tortar Jul 10, 2023
28c75b0
revert last change
Tortar Jul 10, 2023
b5a25ee
Handle Arrow.jl integration on Windows
fbanning Jul 10, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ julia = "1.5"
BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"
StableRNGs = "860ef19b-820b-49d6-a774-d7a799459cd3"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
mastrof marked this conversation as resolved.
Show resolved Hide resolved

[targets]
test = ["Test", "BenchmarkTools", "StableRNGs"]
118 changes: 117 additions & 1 deletion src/simulations/collect.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export run!,
offline_run!,
collect_agent_data!,
collect_model_data!,
init_agent_dataframe,
Expand Down Expand Up @@ -101,7 +102,7 @@ If `a1.weight` but `a2` (type: Agent2) has no `weight`, use
or [`deepcopy`](https://docs.julialang.org/en/v1/base/base/#Base.deepcopy) if some data are
nested mutable containers. Both of these options have performance penalties.
* `agents_first=true` : Whether to update agents first and then the model, or vice versa.
* `showprogress=false` : Whether to show a progress bar.
* `showprogress=false` : Whether to show progress
"""
function run! end

Expand Down Expand Up @@ -164,6 +165,121 @@ function run!(
return df_agent, df_model
end

"""
offline_run!(model, agent_step! [, model_step!], n::Integer; kwargs...) → agent_df, model_df
offline_run!(model, agent_step!, model_step!, n::Function; kwargs...) → agent_df, model_df
mastrof marked this conversation as resolved.
Show resolved Hide resolved

Run the model while dumping data to CSV files. See [`run!`](@ref) for details.

mastrof marked this conversation as resolved.
Show resolved Hide resolved
## Keywords
* `writing_interval=1` : write to file every `writing_interval` times the data is collected. Small values have larger effects on performance.
Datseris marked this conversation as resolved.
Show resolved Hide resolved
* `adata_savefile="adata.csv"` : a file to write agent data on.
* `mdata_savefile="mdata.csv"`: a file to write the model data on.
"""
function offline_run! end

offline_run!(model::ABM, agent_step!, n::Int = 1; kwargs...) =
offline_run!(model::ABM, agent_step!, dummystep, n; kwargs...)

function offline_run!(
model,
agent_step!,
model_step!,
n;
when = true,
when_model = when,
mdata = nothing,
adata = nothing,
obtainer = identity,
agents_first = true,
showprogress = false,
writing_interval = 1,
adata_savefile = "adata.csv",
mdata_savefile = "mdata.csv"
)

df_agent = init_agent_dataframe(model, adata)
df_model = init_model_dataframe(model, mdata)
if n isa Integer
if when == true
for c in eachcol(df_agent)
sizehint!(c, n)
end
end
if when_model == true
for c in eachcol(df_model)
sizehint!(c, n)
end
end
end

close(open(adata_savefile, "w"))
close(open(mdata_savefile, "w"))
Datseris marked this conversation as resolved.
Show resolved Hide resolved
model_appendtocsv = false
agent_appendtocsv = false

agent_count_collections = 0
model_count_collections = 0
agent_collected = false
model_collected = false

s = 0
p = if typeof(n) <: Int
ProgressMeter.Progress(n; enabled=showprogress, desc="run! progress: ")
else
ProgressMeter.ProgressUnknown(desc="run! steps done: ", enabled=showprogress)
end
while until(s, n, model)
if should_we_collect(s, model, when)
collect_agent_data!(df_agent, model, adata, s; obtainer)
agent_count_collections += 1
agent_collected = true
end
if should_we_collect(s, model, when_model)
collect_model_data!(df_model, model, mdata, s; obtainer)
model_count_collections += 1
model_collected = true
end
step!(model, agent_step!, model_step!, 1, agents_first)
s += 1

if model_collected && model_count_collections % writing_interval == 0
AgentsIO.CSV.write(mdata_savefile, df_model, append=model_appendtocsv)
mastrof marked this conversation as resolved.
Show resolved Hide resolved
df_model = init_model_dataframe(model, mdata)
Datseris marked this conversation as resolved.
Show resolved Hide resolved
model_collected = false
model_appendtocsv = true
end
if agent_collected && agent_count_collections % writing_interval == 0
AgentsIO.CSV.write(adata_savefile, df_agent, append=agent_appendtocsv)
df_agent = init_agent_dataframe(model, adata)
agent_collected = false
agent_appendtocsv = true
end

ProgressMeter.next!(p)
end
if should_we_collect(s, model, when)
collect_agent_data!(df_agent, model, adata, s; obtainer)
agent_collected = true
end
if should_we_collect(s, model, when_model)
collect_model_data!(df_model, model, mdata, s; obtainer)
model_collected = true
end

if model_collected
AgentsIO.CSV.write(mdata_savefile, df_model, append=model_appendtocsv)
df_model = init_model_dataframe(model, mdata)
end
if agent_collected
AgentsIO.CSV.write(adata_savefile, df_agent, append=agent_appendtocsv)
df_agent = init_agent_dataframe(model, adata)
end

ProgressMeter.finish!(p)
return nothing
end

###################################################
# core data collection functions per step
###################################################
Expand Down
28 changes: 28 additions & 0 deletions test/collect_tests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,34 @@ end
mdata = [(m) -> (m.deep.data[i]) for i in 1:length(model.deep.data)],
)
@test Array{Float64,1}(model_data[1, 2:end]) == model.deep.data

@testset "Writing to file while running" begin

offline_run!(
model,
agent_step!,
model_step!,
365 * 5;
when_model=each_year,
when=six_months,
mdata=[:flag, :year],
adata=[(:weight, mean)],
writing_interval=3
)

adata_saved = CSV.read("adata.csv", DataFrame)
@test size(adata_saved) == (11, 2)
@test propertynames(adata_saved) == [:step, :mean_weight]

mdata_saved = CSV.read("mdata.csv", DataFrame)
@test size(mdata_saved) == (6, 3)
@test propertynames(mdata_saved) == [:step, :flag, :year]

rm("adata.csv")
rm("mdata.csv")
@test !isfile("adata.csv")
@test !isfile("mdata.csv")
end
end

@testset "Low-level API for Collections" begin
Expand Down
4 changes: 2 additions & 2 deletions test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
using Test, Agents, Random, LinearAlgebra
using Test, Agents, Random, LinearAlgebra, CSV
using Agents.Graphs, Agents.DataFrames
using StatsBase: mean
using StableRNGs

using Distributed
addprocs(2)
@everywhere begin
using Test, Agents, Random
using Test, Agents, Random, LinearAlgebra, CSV
using Agents.Graphs, Agents.DataFrames
using StatsBase: mean
using StableRNGs
Expand Down