Skip to content
Snippets Groups Projects
Commit 937d851e authored by xo30xoqa's avatar xo30xoqa
Browse files

Reorganised code, splitting it up over more files

parent 22dae9e5
No related branches found
No related tags found
No related merge requests found
......@@ -3,42 +3,6 @@
### This file links the QML UI designs to the underlying model.
###
global model = nothing
global landcovermap = nothing
global runsimulation = nothing
global timer = nothing
const configfile = Observable("guiparams.toml")
const launching = Observable(false)
const running = Observable(false)
const ticks = Observable(0)
const date = Observable(today())
const progress = Observable(0.0)
const delay = Observable(0.5)
const runbuttontext = Observable(">>")
const runbuttontip = Observable("Run")
const mapimage = Observable(Figure().scene)
global guiproperties =
["running" => running,
"ticks" => ticks,
"date" => date,
"delay" => delay,
"progress" => progress,
"runbuttontext" => runbuttontext,
"runbuttontip" => runbuttontip]
function newsimulation()
global model, landcovermap
launching[] = true # trigger the launch screen
running[] = false
progress[] = 0.0
model = initialise(configfile[])
landcovermap = rotr90(load(@param(world.landcovermap)))
date[] = model.date
launching[] = false
println("Model initialised.")
end
function loadsimulation(filename)
global model
......@@ -73,59 +37,6 @@ end
#TODO saveoutput()
function nextstep()
global model
if date[] >= @param(core.enddate)
running[] = false
runbuttontext[] = ">>"
runbuttontip[] = "Run"
return
elseif date[] < model.date
# If we've "scrolled back" in time, step forward again without
# having to resimulate (see `previousstep()`)
date[] += Day(1)
else
# If we're already displaying the newest model update, we need to
# keep simulating
stepsimulation!(model)
date[] = model.date
end
progress[] = (date[]-@param(core.startdate)) /
(@param(core.enddate)-@param(core.startdate))
@emit updateMakie()
println("Updated model: $(date[]-Day(1))")
end
function previousstep()
# Since we store all model output in a dataframe, we can simply
# "scroll back" in time and visualise the state of the model at
# a previous date
global model
date[] <= @param(core.startdate) && return
date[] -= Day(1)
progress[] = (date[]-@param(core.startdate)) /
(@param(core.enddate)-@param(core.startdate))
@emit updateMakie()
println("Backtracked model: $(date[]-Day(1))")
end
#XXX This could also be done with Channels rather than ResumableFunctions,
# which would save us one dependency (Channels are inbuilt). However, the
# ResumableFunctions version seemed to work more smoothly.
@resumable function createrunfunction()
i = round(delay[]*10)
while running[]
i -= 1
if i <= 0
nextstep()
i = round(delay[]*10)
end
# to reduce interface lag, always only sleep for 0.1s
sleep(0.1)
@yield 1
end
end
function togglerunning()
global runsimulation, timer
if running[]
......@@ -137,7 +48,6 @@ function togglerunning()
running[] = true
runbuttontext[] = "||"
runbuttontip[] = "Pause"
runsimulation = createrunfunction()
QML.start(timer)
end
end
......@@ -195,16 +105,6 @@ on(delay) do d
println("Delay is now $(round(d, digits=1)) seconds.") #XXX DEBUG
end
on(running) do r
ticks = 0 #prevent overflows
r ? println("Simulation started.") : println("Simulation stopped.") #XXX DEBUG
end
on(ticks) do t
#launching[] && #FIXME
running[] && runsimulation()
end
on(launching) do l
if l
@emit showSplash()
......@@ -246,7 +146,7 @@ function launch()
qmlfile = joinpath(dirname(@__FILE__), "main.qml")
loadqml(qmlfile,
timer = timer,
vars = JuliaPropertyMap(guiproperties...,configproperties...),
vars = JuliaPropertyMap(guiproperties...),
render_map_callback = @safe_cfunction(render_map, Cvoid, (Any,)),
render_plot_callback = @safe_cfunction(render_plot, Cvoid, (Any,)))
launching[] = true
......
......@@ -26,6 +26,8 @@ using
DataFramesMeta,
ResumableFunctions
include("variables.jl")
include("logic.jl")
include("config.jl")
include("GUI.jl")
......@@ -33,7 +35,6 @@ precompile(launch, ())
precompile(render_map, (Any,)) #what's the input type?
export
configwindow,
launch
end
......@@ -3,41 +3,6 @@
### This file manages the backend of the setup window.
###
const userconfigfile = Observable("userconfig.toml")
const outdir = Observable("persefone_output")
const csvoutput = Observable(false)
const loglevel = Observable("warn")
const processors = Observable(1)
const seed = Observable(2)
const startdateday = Observable(1)
const startdatemonth = Observable(1)
const startdateyear = Observable(2022)
const enddateday = Observable(31)
const enddatemonth = Observable(12)
const enddateyear = Observable(2022)
const region = Observable("Jena") #XXX alternatives not yet implemented
#const farmmodel = Observable("FieldManager") #XXX not yet implemented
#const targetspecies = Observable() #TODO not sure how to configure a list?
#const insectmodel = Observable() #TODO not sure how to configure a list?
const cropmodel = Observable("ALMaSS") #XXX alternatives not yet implemented
global configproperties =
["userconfigfile" => userconfigfile,
"outdir" => outdir,
"csvoutput" => csvoutput,
"loglevel" => loglevel,
"processors" => processors,
"seed" => seed,
"startdateday" => startdateday,
"startdatemonth" => startdatemonth,
"startdateyear" => startdateyear,
"enddateday" => enddateday,
"enddatemonth" => enddatemonth,
"enddateyear" => enddateyear,
"region" => region,
"cropmodel" => cropmodel]
function writeconfig()
println("Wrote config file.")
......
### PersefoneDesktop - a GUI to the Persefone model of agriculture and ecosystems
###
### This file manages the model initialisation and run functions.
###
function newsimulation()
global model, landcovermap
launching[] = true # trigger the launch screen
running[] = false
progress[] = 0.0
model = initialise(configfile[])
landcovermap = rotr90(load(@param(world.landcovermap)))
date[] = model.date
launching[] = false
println("Model initialised.")
end
function nextstep()
global model
if date[] >= @param(core.enddate)
running[] = false
runbuttontext[] = ">>"
runbuttontip[] = "Run"
return
elseif date[] < model.date
# If we've "scrolled back" in time, step forward again without
# having to resimulate (see `previousstep()`)
date[] += Day(1)
else
# If we're already displaying the newest model update, we need to
# keep simulating
stepsimulation!(model)
date[] = model.date
end
progress[] = (date[]-@param(core.startdate)) /
(@param(core.enddate)-@param(core.startdate))
@emit updateMakie()
println("Updated model: $(date[]-Day(1))")
end
function previousstep()
# Since we store all model output in a dataframe, we can simply
# "scroll back" in time and visualise the state of the model at
# a previous date
global model
date[] <= @param(core.startdate) && return
date[] -= Day(1)
progress[] = (date[]-@param(core.startdate)) /
(@param(core.enddate)-@param(core.startdate))
@emit updateMakie()
println("Backtracked model: $(date[]-Day(1))")
end
#XXX This could also be done with Channels rather than ResumableFunctions,
# which would save us one dependency (Channels are inbuilt). However, the
# ResumableFunctions version seemed to work more smoothly.
@resumable function createrunfunction()
i = round(delay[]*10)
while running[]
i -= 1
if i <= 0
nextstep()
i = round(delay[]*10)
end
# to reduce interface lag, always only sleep for 0.1s
sleep(0.1)
@yield 1
end
end
on(running) do r
ticks = 0 #prevent overflows
runsimulation = createrunfunction()
r ? println("Simulation started.") : println("Simulation stopped.") #XXX DEBUG
end
on(ticks) do t
#launching[] && #FIXME
running[] && runsimulation()
end
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1067</width>
<height>614</height>
</rect>
</property>
<property name="windowTitle">
<string>Persefone Desktop</string>
</property>
<property name="windowIcon">
<iconset>
<normaloff>../eacf50ed/favicon.png</normaloff>../eacf50ed/favicon.png</iconset>
</property>
<property name="toolTipDuration">
<number>-1</number>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QGraphicsView" name="graphicsView"/>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_4">
<property name="leftMargin">
<number>5</number>
</property>
<item>
<widget class="QCalendarWidget" name="calendarWidget"/>
</item>
<item>
<widget class="QGraphicsView" name="graphicsView_2"/>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QPushButton" name="pushButton_3">
<property name="toolTip">
<string>Pause</string>
</property>
<property name="text">
<string>||</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton">
<property name="toolTip">
<string>Step</string>
</property>
<property name="text">
<string>&gt;</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_2">
<property name="toolTip">
<string>Run</string>
</property>
<property name="text">
<string>&gt;&gt;</string>
</property>
</widget>
</item>
<item>
<widget class="QProgressBar" name="progressBar">
<property name="value">
<number>24</number>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="horizontalSlider">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>200</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Delay between updates</string>
</property>
<property name="maximum">
<number>10</number>
</property>
<property name="value">
<number>5</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1067</width>
<height>25</height>
</rect>
</property>
<widget class="QMenu" name="menu_Menu">
<property name="title">
<string>&amp;Menu</string>
</property>
<addaction name="separator"/>
<addaction name="action_New_run"/>
<addaction name="actionLoad_saved_state"/>
<addaction name="actionSave_current_state"/>
<addaction name="separator"/>
<addaction name="action_Quit"/>
</widget>
<widget class="QMenu" name="menu_Help">
<property name="title">
<string>&amp;Help</string>
</property>
<addaction name="actionHelp"/>
<addaction name="actionWebsite"/>
<addaction name="actionAbout"/>
</widget>
<addaction name="menu_Menu"/>
<addaction name="menu_Help"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<action name="actionHelp">
<property name="text">
<string>Documentation</string>
</property>
</action>
<action name="actionAbout">
<property name="text">
<string>About</string>
</property>
</action>
<action name="action_New_run">
<property name="text">
<string>&amp;New run</string>
</property>
</action>
<action name="action_Quit">
<property name="text">
<string>&amp;Quit</string>
</property>
</action>
<action name="actionSave_current_state">
<property name="text">
<string>&amp;Save current state</string>
</property>
</action>
<action name="actionLoad_saved_state">
<property name="text">
<string>&amp;Load saved state</string>
</property>
</action>
<action name="actionWebsite">
<property name="text">
<string>Website</string>
</property>
</action>
</widget>
<resources/>
<connections/>
</ui>
/// PersefoneDesktop - a GUI to the Persefone model of agriculture and ecosystems
///
/// This file creates the splash screen. Load it using a QQuickView.
///
import QtQuick
import QtQuick.Controls
import org.julialang
Popup {
id: splashPopupExt
parent: Overlay.overlay
width: 600
height: 250
x: Math.round((parent.width - width) / 2)
y: Math.round((parent.height - height) / 2)
Rectangle {
anchors.fill: parent
Image {
source: "persefonejl_logo_v3_splash.png"
fillMode: Image.Stretch
}
Timer {
// Show the splash screen while the model object is initialised
//XXX is 15s a good time here?
interval: 15000; running: true; repeat: false
onTriggered: parent.Window.window.close()
}
}
}
### PersefoneDesktop - a GUI to the Persefone model of agriculture and ecosystems
###
### This file contains all globals and Observables.
###
## GUI parameters
global model = nothing
global landcovermap = nothing
global runsimulation = nothing
global timer = nothing
const configfile = Observable("guiparams.toml")
const launching = Observable(false)
const running = Observable(false)
const ticks = Observable(0)
const date = Observable(today())
const progress = Observable(0.0)
const delay = Observable(0.5)
const runbuttontext = Observable(">>")
const runbuttontip = Observable("Run")
const mapimage = Observable(Figure().scene)
## configuration parameters
const userconfigfile = Observable("userconfig.toml")
const outdir = Observable("persefone_output")
const csvoutput = Observable(false)
const loglevel = Observable("warn")
const processors = Observable(1)
const seed = Observable(2)
const startdateday = Observable(1)
const startdatemonth = Observable(1)
const startdateyear = Observable(2022)
const enddateday = Observable(31)
const enddatemonth = Observable(12)
const enddateyear = Observable(2022)
const region = Observable("Jena") #XXX alternatives not yet implemented
#const farmmodel = Observable("FieldManager") #XXX not yet implemented
#const targetspecies = Observable() #TODO not sure how to configure a list?
#const insectmodel = Observable() #TODO not sure how to configure a list?
const cropmodel = Observable("ALMaSS") #XXX alternatives not yet implemented
## the property list passed to QML
global guiproperties =
["running" => running,
"ticks" => ticks,
"date" => date,
"delay" => delay,
"progress" => progress,
"runbuttontext" => runbuttontext,
"runbuttontip" => runbuttontip,
"userconfigfile" => userconfigfile,
"outdir" => outdir,
"csvoutput" => csvoutput,
"loglevel" => loglevel,
"processors" => processors,
"seed" => seed,
"startdateday" => startdateday,
"startdatemonth" => startdatemonth,
"startdateyear" => startdateyear,
"enddateday" => enddateday,
"enddatemonth" => enddatemonth,
"enddateyear" => enddateyear,
"region" => region,
"cropmodel" => cropmodel]
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment