{"id":42036884,"url":"https://github.com/uablrek/system-dynamics","last_synced_at":"2026-01-26T05:09:08.975Z","repository":{"id":258821391,"uuid":"875160287","full_name":"uablrek/system-dynamics","owner":"uablrek","description":null,"archived":false,"fork":false,"pushed_at":"2025-10-26T09:42:59.000Z","size":686,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-26T11:28:46.506Z","etag":null,"topics":["system-dynamics"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/uablrek.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-10-19T08:52:25.000Z","updated_at":"2025-10-26T09:43:02.000Z","dependencies_parsed_at":"2024-11-03T10:18:27.260Z","dependency_job_id":"2d6b39bd-1c35-439d-b38b-486afe97db71","html_url":"https://github.com/uablrek/system-dynamics","commit_stats":null,"previous_names":["uablrek/system-dynamics"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/uablrek/system-dynamics","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uablrek%2Fsystem-dynamics","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uablrek%2Fsystem-dynamics/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uablrek%2Fsystem-dynamics/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uablrek%2Fsystem-dynamics/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/uablrek","download_url":"https://codeload.github.com/uablrek/system-dynamics/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uablrek%2Fsystem-dynamics/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28767036,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-26T03:54:34.369Z","status":"ssl_error","status_checked_at":"2026-01-26T03:54:33.031Z","response_time":59,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["system-dynamics"],"created_at":"2026-01-26T05:09:08.351Z","updated_at":"2026-01-26T05:09:08.963Z","avatar_url":"https://github.com/uablrek.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# System Dynamics\n\nExperiments with [System Dynamics](\nhttps://en.wikipedia.org/wiki/System_dynamics) (SD) models, mostly in\nPython. The aim is to learn how to write a SD model and to modify the\n[world3 model](WORLD3.md). There are several graphic tools for SD, but\nI prefer writing code and generate the model graph afterwards. It's\nfaster and more flexible (no tool limitations). Besides, the graphic\ntools are mostly commercial and can't be used on Linux.\n\nFor Python the `system_dynamic` module from\n[MyWorld3](https://github.com/Juji29/MyWorld3) is used as a\nlibrary. It is modified to be generic, and functions like plots and\nmodel graphs are added. The model graphs are generated with\n[graphviz](https://graphviz.org/).\n\n I use Ubuntu 24.04 Linux. Plots (not graphwiz) has been tested on Windows 11 with VSCode.\n\n\n## Lotka–Volterra predator–prey model\n\nThe [Lotka–Volterra predator–prey model](\nhttps://en.wikipedia.org/wiki/Lotka%E2%80%93Volterra_equations) is\nsimple and a good example ([graph](figures/predator_prey.svg)). Run with:\n```\n./predator_prey.py -h      # help\n./predator_prey.py run -h  # help for the \"run\" command\n./predator_prey.py run\n```\nBy default parameters for \"A simple example\" from the [wiki page](\nhttps://en.wikipedia.org/wiki/Lotka%E2%80%93Volterra_equations) is used:\n\n\u003cimg src=\"figures/plot_predator_prey.svg\" /\u003e\n\n\n## The grass+sheep model\n\n\u003cimg src=\"figures/grass+sheep.svg\" /\u003e\n\nItems have \"tooltips\" with information that should popup when you\nhoover over the item. I must right-click on the graph and \"Open Image\nin New Tab\" to get tooltips working (both in Chrome and Firefox).\n\nThe model is *greatly* simplified! For instance grass grows at a\nconstant rate, the number of sheep is a float, etc. It is intended for\nlearning only. The *real* science of plant-herbivore systems seems\n[horribly complex](http://www.google.com/search?q=system+dynamics+herbivore).\n\nSome care has been taken to get reasonable values. A sustainable\nestimate is 6 sheep per ha, and we want the model to be at least in\nthe neighbourhood. All weights are in \"dry matter\". Examples:\n\n```\nGrass Limit = 5500 kg/ha\nGrass Growth = 5500 kg/ha/year\nSheep Consume = 2.5 kg/day ~ 900 kg/year\n```\n\nRun it (on Linux):\n```\n./grass_sheep.py             # Help printout\n./grass_sheep.py run -h      # Help for the \"run\" command\n./grass_sheep.py run\n# To generate the model graph:\n./grass_sheep.py graph | dot -Tsvg \u003e model.svg\n```\nYou should see something like:\n\n\u003cimg src=\"figures/plot_grass+sheep.svg\" /\u003e\n\nThe delay for death by starvation (dd) has default 0 (zero). But even\nwith zero delay there are oscillations. I think some delay is\n\"built-in\". For instance `starvation` is computed from the *last*\niteration of `grass`, so the number of sheep can overshoot.\n\nThe interresting part (IMHO) is what happens when you alter the delay\nfor death by starvation (dd). With --dd=0.5 you get \"lemming oscillations\":\n\n\u003cimg src=\"figures/plot_grass+sheep_dd0.5.svg\" /\u003e\n\nAnd with --dd=0.7, you get a [Seneca cliff](\nhttps://en.wikipedia.org/wiki/Seneca_effect):\n\n\u003cimg src=\"figures/plot_grass+sheep_dd0.7.svg\" /\u003e\n\n\n## NodeDelay3 and the pond model\n\nIt's not at all clear to me how `NodeDelay3` works. The \"explanation\" in the\n[PDF](https://github.com/Juji29/MyWorld3/blob/master/MyWorld3%20Equations%20and%20Explanations.pdf)\nis just the code expressed with math symbols. To investigate this, the\n[pond model](pond.py) is used. It models a pond filled through a\nstream and the flow is controlled by a gate. The stream is supposed to\nhave some length and is modelled with a delay.\n\n\u003cimg src=\"figures/pond.svg\" /\u003e\n\nThe `gate` can be opened or closed and create a step or a pulse in the\nflow. The `f_delayinit()` method in `NodeDelay3` takes a flow and a\nconstant as input. The constant influences how long the flow is\ndelayed, and make sure that it's well above the time-step (or weird\nthings happen).  The [pond model](pond.py) animates a pulse for\ndifferent delays.\n\n\u003cimg src=\"figures/plot_pond_pulse.svg\" /\u003e\n\n## Animation\n\nI couldn't find a way to generate an animated svg directly by\n`matplotlib.pyplot`, but it can generate an svg for each iteration\nwhich can be combined using [svgasm](https://github.com/tomkwok/svgasm/).\nTo create the animation above, uncomment the `plt.savefig()` call and do:\n\n```\n./pond.py\n./admin.sh animate --out=testplot.svg pond-*.svg\n```\n\nSvg files are optimized with [svgo](https://github.com/svg/svgo)\nif it's available.\n\n\n## JSON and post-processing\n\nA model can partially be converted to/from a dictionary. Partially\nbecause only nodes are handled, not equations (edges). This can for\ninstance be used run a model with different values without altering\nthe code, or to emit json data for post-processing. After a run all\ndata is in the `hist` arrays.\n\n```python\nimport system_dynamic as sd\nimport json\nimport pond\ns = sd.System(time_step=0.5, time_unit='Day')\npond.load_model(s)\ns.run(end_time=8)\njson.dumps(s.dict_nodes('time', 'pond'))\n```\n\nThe `time` stock should always be included.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuablrek%2Fsystem-dynamics","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fuablrek%2Fsystem-dynamics","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuablrek%2Fsystem-dynamics/lists"}