Skip to content

Commit

Permalink
Merge pull request #23 from MRC-CSO-SPHSU/develop
Browse files Browse the repository at this point in the history
V0.3.2
  • Loading branch information
AtiyahElsheikh authored Jan 20, 2023
2 parents 223cae8 + b5929a0 commit 99ff182
Show file tree
Hide file tree
Showing 9 changed files with 173 additions and 142 deletions.
11 changes: 11 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"[julia]": {
"editor.detectIndentation": false,
"editor.insertSpaces": true,
"editor.tabSize": 4,
"files.insertFinalNewline": true,
"files.trimFinalNewlines": true,
"files.trimTrailingWhitespace": true,
"editor.rulers": [92],
},
}
15 changes: 12 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
# LPM.jl

[![Code Style: Blue](https://img.shields.io/badge/code%20style-blue-4495d1.svg)](https://github.com/invenia/BlueStyle)

Implementation of the Lone Parents Model based on the SocioEconomics.jl Library. The initial code is based on the LoneParentsModel.jl package that was implemented together by Martin Hinsch and Atiyah Elsheikh.

Releases
Expand All @@ -19,9 +22,11 @@ Releases
- V0.2.4 (14.12) : adjusting to SimpleABM types of MA Version 0.4, improved model data structure
- V0.2.5 (21.12) : exploits some tuned simulation functions from SE* V0.2.5 and improved performance
- V0.2.6 (27.12) : Improved implementation of allocation algorithms (no temporary arrays), tuned do marriage algorithm (memoization can be avoided) & Improved runtime performance (3x faster & 4x less memory allocation and storage w.r.t. V0.2.5)
- V0.2.7 (6.1.2023) : (MALPM only) Memoization with domarriage alg can be done only externally (if desired). Employing newly tuned and exact API of four simulation functions. Optimized simulation (with deads removal) vs. normal simulation (without deads removal)
- V0.2.8 (8.1.2023) : (MALPM only) employing tuned API of assigning guardians
- **V0.3 (14-01-2022)** : Making use of the rest of the fixed API of SE's Simulate function, further code simplification and tuning. Signficant memory allocation reduction and runtime performance improvement
- V0.2.7 (6.1.2023) : Memoization with domarriage alg can be done only externally (if desired). Employing newly tuned and exact API of four simulation functions. Optimized simulation (with deads removal) vs. normal simulation (without deads removal)
- V0.2.8 (8.1.2023) : employing tuned API of assigning guardians
- **V0.3 (14.01.2023)** : Making use of the rest of the fixed API of SE's Simulate function, further code simplification and tuning. Signficant memory allocation reduction and runtime performance improvement
- V0.3.1 (16.1) : Blue style badge, separating mainMAHelpers.jl from mainHelpers.jl, arbitrary population size
- V0.3.2 (20.1) : Employing the blue-styled SE V0.3.2

Performance Progress History
============================
Expand All @@ -38,7 +43,11 @@ V0.2.6 | 7.6 sec. | ~ 37 M | ~ 2.2 GB |
V0.2.8 | 6.3 sec. | ~ 24 M | ~ 1.6 GB |
V0.3 | 4.7 sec | ~ 380 K | ~ 90 MB |

The following is the initial population size for a 1-minute simulation

Version | 1 Min.
--- | ---
0.3.1 | 56200 (~ 2.1 M Allocations + 520 MB)



Expand Down
6 changes: 3 additions & 3 deletions analysis.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ const MMA = MaxMinAcc{Float64}
end

@for person in model.pop begin
@stat("married", CountAcc) <| (alive(person) && !isSingle(person))
@stat("married", CountAcc) <| (alive(person) && !issingle(person))
@stat("age", MVA) <| Float64(age(person))
@stat("alive", CountAcc) <| alive(person)
@stat("eligible", CountAcc) <| (alive(person) && isFemale(person) && age(person) > 17)
@stat("eligible2", CountAcc) <| (alive(person) && isSingle(person) && isFemale(person) && age(person) > 17)
@stat("eligible", CountAcc) <| (alive(person) && isfemale(person) && age(person) > 17)
@stat("eligible2", CountAcc) <| (alive(person) && issingle(person) && isfemale(person) && age(person) > 17)
end


Expand Down
8 changes: 4 additions & 4 deletions libspath.jl
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
function addToLoadPath!(paths...)
function add_to_loadpath!(paths...)
for path in paths
if ! (path in LOAD_PATH)
push!(LOAD_PATH, path)
end
end
end

addToLoadPath!("../SocioEconomics.jl/src")
addToLoadPath!("./src")
addToLoadPath!(".")
add_to_loadpath!("../SocioEconomics.jl/src")
add_to_loadpath!("./src")
add_to_loadpath!(".")



Expand Down
43 changes: 20 additions & 23 deletions mainHelpers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,18 @@ function createDemography!(datapars, pars)
# maybe switch using parameter
#ukPopulation = createPopulation(pars)
ukPopulation = createPyramidPopulation(pars)
# temporarily solution , input files and command line arguments
# should be invistigated

# temporarily solution , input files and command line arguments
# should be invistigated
ukDemoData = loadDemographyData(datapars)

Model(ukTowns, ukHouses, ukPopulation,
Model(ukTowns, ukHouses, ukPopulation,
ukDemoData.fertility , ukDemoData.deathFemale, ukDemoData.deathMale)
end

function initializeDemography!(model, pars)
initialConnect!(model.houses, model.towns, pars)
#initialConnect!(model.pop, model.houses, pars) # works too
#initialConnect!(model.pop, model.houses, pars) # works too
initialConnect!(model.houses, model.pop, pars)
init!(model.pop,pars,InitClassesProcess())
init!(model.pop,pars,InitWorkProcess())
Expand All @@ -39,53 +39,53 @@ end
"Apply a transition function to an iterator."
function applyTransition!(people, transition, name, args...)
count = 0
for p in people
for p in people
transition(p, args...)
count += 1
end

verbose() do
verbose() do
if name != ""
println(count, " agents processed in ", name)
end
end
end

# Atiyah: remove this for the primative API simulation function
# alivePeople(model) = Iterators.filter(a->alive(a), model.pop)
# data(model) = model
# alive_people(model) = Iterators.filter(a->alive(a), model.pop)
# data(model) = model

function stepModel!(model, time, simPars, pars)
# TODO remove dead people?
# Atiyah:
doDeaths!(model,time,pars) # a possible unified way
# or the primiative-API
# doDeaths!(alivePeople(model), time, data(model), pars.poppars)

# Atiyah:
doDeaths!(model,time,pars) # a possible unified way
# or the primiative-API
# doDeaths!(alive_people(model), time, data(model), pars.poppars)

orphans = Iterators.filter(p->selectAssignGuardian(p), model.pop)
applyTransition!(orphans, assignGuardian!, "adoption", time, model, pars)

# Atiyah:
# Atiyah:
babies = doBirths!(model,time,pars)
# babies = doBirths!(alivePeople(model), model.pop), time, model, pars.birthpars)
# babies = doBirths!(alive_people(model), model.pop), time, model, pars.birthpars)

selected = Iterators.filter(p->selectAgeTransition(p, pars.workpars), model.pop)
applyTransition!(selected, ageTransition!, "age", time, model, pars.workpars)

selected = Iterators.filter(p->selectWorkTransition(p, pars.workpars), model.pop)
applyTransition!(selected, workTransition!, "work", time, model, pars.workpars)

selected = Iterators.filter(p->selectSocialTransition(p, pars.workpars), model.pop)
applyTransition!(selected, socialTransition!, "social", time, model, pars.workpars)
selected = Iterators.filter(p->selectSocialTransition(p, pars.workpars), model.pop)
applyTransition!(selected, socialTransition!, "social", time, model, pars.workpars)

selected = Iterators.filter(p->selectDivorce(p, pars), model.pop)
applyTransition!(selected, divorce!, "divorce", time, model,
applyTransition!(selected, divorce!, "divorce", time, model,
fuse(pars.divorcepars, pars.workpars))

resetCacheMarriages()
selected = Iterators.filter(p->selectMarriage(p, pars.workpars), model.pop)
applyTransition!(selected, marriage!, "marriage", time, model,
applyTransition!(selected, marriage!, "marriage", time, model,
fuse(pars.poppars, pars.marriagepars, pars.birthpars, pars.mappars))

append!(model.pop, babies)
Expand Down Expand Up @@ -130,6 +130,3 @@ function runModel!(model, simPars, pars, logfile = nothing; FS = "\t")
time += simPars.dt
end
end



50 changes: 26 additions & 24 deletions mainMA.jl
Original file line number Diff line number Diff line change
@@ -1,54 +1,56 @@
"""
Main simulation of the lone parent model
Main simulation of the lone parent model
Run this script from shell as
Run this script from shell as
# julia mainMA.jl
from REPL execute it using
from REPL execute it using
> include("mainMA.jl")
"""

include("mainMAHelpers.jl")

using MultiAgents: ABMSimulatorP
using MultiAgents: run!, setup!
using MultiAgents: run!, setup!
using MALPM.Models: MAModel
using SocioEconomics.Specification.Initialize: init!
using MALPM.Examples

const mainConfig = Light() # no input files, logging or flags (REPL Exec.)
# mainConfig = WithInputFiles()
const mainConfig = Light() # no input files, logging or flags (REPL Exec.)
# const mainConfig = WithInputFiles()

# lpmExample = LPMUKDemography() # don't remove deads
lpmExample = LPMUKDemographyOpt() # remove deads
lpmExample = LPMUKDemographyOpt() # remove deads

const simPars, dataPars, pars = loadParameters(mainConfig)
const simPars, dataPars, pars = load_parameters(mainConfig)

# Most significant simulation and model parameters
# Most significant simulation and model parameters
# The following works only with Light() configuration
# useful when executing from REPL
if mainConfig == Light()
if mainConfig == Light()
simPars.seed = 0; seed!(simPars)
simPars.verbose = false
simPars.checkassumption = false
simPars.verbose = false
simPars.checkassumption = false
simPars.sleeptime = 0
pars.poppars.initialPop = 5000
pars.poppars.initialPop = 28200 # 28100 for 1-min simulation
end

const model = setupModel(dataPars, pars)
const logfile = setup_logging(simPars,mainConfig)

const logfile = setupLogging(simPars,mainConfig)
const data = load_demography_data(dataPars)

const demoData = loadDemographyData(dataPars)
const ukTowns, ukHouses, ukPop = create_uk_demography(pars,data)

const ukDemography = MAModel(model,pars,demoData)
const ukDemography = MAModel(ukTowns, ukHouses, ukPop, pars, data)

const lpmDemographySim =
init!(ukDemography)

const lpmDemographySim =
ABMSimulatorP{typeof(simPars)}(simPars,setupEnabled = false)
setup!(lpmDemographySim,lpmExample)
# Execution

setup!(lpmDemographySim,lpmExample)

# Execution
@time run!(ukDemography,lpmDemographySim,lpmExample)

closeLogfile(logfile,mainConfig)

close_logfile(logfile,mainConfig)
44 changes: 31 additions & 13 deletions mainMAHelpers.jl
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
using Random

include("libspath.jl")
addToLoadPath!("../MultiAgents.jl")
include("analysis.jl")
add_to_loadpath!("../MultiAgents.jl")

using SocioEconomics: SEVERSION, SEPATH, SESRCPATH
using MiniObserve

@assert SEVERSION == v"0.3"
using SocioEconomics: SEVERSION, SEPATH, SESRCPATH
@assert SEVERSION == v"0.3.2"

using SocioEconomics.ParamTypes
import SocioEconomics.ParamTypes: load_parameters
using SocioEconomics.XAgents
using SocioEconomics.Specification.Create
using SocioEconomics.Specification.Initialize

include("mainHelpers.jl")
# include("mainHelpers.jl")

using MultiAgents: init_majl
using MultiAgents: SimpleABM
init_majl() # reset agents id counter

using SocioEconomics.ParamTypes: seed!

"""
How simulations is to be executed:
- with or without input files, arguments and logging
Expand All @@ -27,22 +29,38 @@ abstract type MainSim end
struct WithInputFiles <: MainSim end # Input parameter files
struct Light <: MainSim end # no input files

function loadParameters(::WithInputFiles)
simPars, dataPars, pars = loadParameters(ARGS)
function load_parameters(::WithInputFiles)
simPars, dataPars, pars = load_parameters(ARGS)
seed!(simPars)
simPars, dataPars, pars
end

function loadParameters(::Light)
function load_parameters(::Light)
simPars = SimulationPars()
seed!(simPars)
dataPars = DataPars()
pars = DemographyPars()
simPars, dataPars, pars
end

setupLogging(simPars,::WithInputFiles) = setupLogging(simPars)
setupLogging(simPars,::Light) = nothing
function create_uk_demography(pars,data)
ukTowns = SimpleABM{PersonTown}(create_inhabited_towns(pars))
ukHouses = SimpleABM{PersonHouse}()
ukPopulation = SimpleABM{Person}(create_pyramid_population(pars))
ukTowns, ukHouses, ukPopulation
end

function setup_logging(simPars; FS = "\t")
if simPars.logfile == ""
return nothing
end
file = open(simPars.logfile, "w")
print_header(file, Data; FS)
file
end

setup_logging(simPars,::WithInputFiles) = setup_logging(simPars)
setup_logging(simPars,::Light) = nothing

closeLogfile(loffile,::WithInputFiles) = close(logfile)
closeLogfile(logfile,::Light) = nothing
close_logfile(loffile,::WithInputFiles) = close(logfile)
close_logfile(logfile,::Light) = nothing
Loading

0 comments on commit 99ff182

Please sign in to comment.