Pygemmes is a huge toolbox for ecological economist that want to understand interdisciplinar complex systems through models.
It is :
- An ensemble of fields, concepts that makes sense in our world (temperature, inflation, debt, production, carbon concentration, productivity...)
- And ensemble of links : concepts that are related to each other in their definition or their evolution (the evolution of price is linked to inflation, the employement is linked to the workers and the population...)
- An ensemble of model : each model is an ensemble of links consistent altogether, you can compare each model on its construction and their consequence, couple models...
- An ensemble of tools to study the system : equation solvers, cycles analysis, sensitivity analysis, basin of attractions...
In a few lines one can :
- Explore and plot the litterature
- Write his own model, prototype it
- Analyse the outcomes
import pygemmes as pgm
hub = pgm.Hub(model='GK',preset='default')
hub.run()
hub.plot_preset(preset='default')
hub.get_summary()
A network automatically generated by the system. It is interactive !
Fast-cycle decoupling in analysis
Sensitivity impact Of initial conditions
Execute line by line doc/Tutorial.py
The goal of the library is to help the community of modellers, especially the ones working with IAM (Integrated assessment model). However, those are not constructed standard way : it is based on dynamical systems rather than intertemporal optimisation.
As a consequence, the model is much more suited to take into account economy as a part of the world (ecology) rather than seeing the ecology as a part of the economy. It is much more convenient that way to couple different disciplines that way. This formulation is also stock-flow consistent : nothing appear or disappear out of nowhere by construction. This is a great help to get closer to a thermodynamic consistent model.
The economic part is handled through Post-Keynesian approach, particularly efficient on rapidly-evolving, out of equilibrium dynamics with endogeneous crysis.
In the general methodology, one could see similitudes with 'Limits to growth' but with 50 years of update in term of dynamical systems and interdisciplinary research, and more policy oriented. The model are based on descriptivity and allow the user to develop normativity.
There are three layers of contributions possible
- User (just have fun with the library and use it for your work)
- Modeller (add new model in the system)
- Developper (add new functionalities)
- Do the tutorial in
doc\tutorial.py
- Try different models and preset
- Emit
issues
when something looks wronghttps://github.com/DaluS/GEMMES/issues/new
The goal of a modeller is to implement models given the framework of pygemmes
- Do everything in "contributing as a user" section just above
- Look at the list of proposed model to implement in
https://github.com/DaluS/GEMMES/projects/1
, or choose your own
- Choose what sectors you want to put in your model
- Choose the stocks they have (money, physical units)
- Choose the flux that links them
- Write stock-flow consistency (evolution of stock depending of flux)
- Detail the quantitative values of flux (Metabolix hypothesis, Behavior)
- You might have some circular dependency in your variable : a first round of simplification might be needed
- Copy a file model that you think is inspiring and write it with a new name
- Use all the fields alaready existing in
_def_fields
that exist in your model - Use all the function existing in
_def_functions
that correspond to your model - Write your presets
- Define new fields and parameters if needed
- Define new functions if needed
- Create a branch on your git
- Put your model file in the
pygemmes
folder - Push your branch
- Do a pull request explaining what you've put inside your model (you can do generalisation directly if you want and avoid the multiple pull request)
This step is optional but appreciated !
- Create a new branch
- put all your new fields inside
def_fields
either by creating a new group or adding elements in an existing one - put your new functions inside
def_functions
- put your new plots inside
def_plots
- Re-edit your models calling the functions of these files instead
- Do a new pull request
- First add a model in the system
- Look at the issues
- Choose which issue you want to work on and say it on the issue (or raise a new issue)
- Bring a PR with your new code !
There are many ways to write a model in pygemmes, and one might fit your project better than other ones.
As there are already some stuff coded, you should always have an eye on :
* Existing models ( list can be obtained using pgm.get_available_models
or in _models\model_*.py
* Existing fields ( list can be obtained using pgm.get_available_fields
or in _models\_def_fields.py
* Existing functions ( list can be obtained using pgm.get_available_functions
or in _models\_def_functions.py
That way you do not have to reinvent something that's already been added !
To explore the different approaches one can explore :
1. LorenzSystem
which contains all the basis (not using any external source)
2. G
as a Goodwin model using both the fields and functions library
3. G-CES
as an extension of G
model
A model file is two big dictionnary :
* _LOGICS
that contains all the logics that links fields together
* _PRESETS
that contains typical values and plots for simulations. it
is a help for new users who wants to understand the typical properties of the model.
_LOGICS contains in itself 3 dictionnary :
* ODE which contains all the fields which are defined by a differential equation
* Statevar which contains all the fields which are defined by a state variables
* param which contains all the fields which are not changing through time but are
not defined in pygemmes's library (read pgm.get_available_fields()
to check)
for example, let's define an exogenous equation for productivity :
da/dt = a * (alpha + zouplala/proutprout)
- we check if the fields do exist :
- a exist
- alpha exist
- zouplala do not exist : I will have to add it
- Proutprout do not exist either : We will have to add it also
- It is a differential equation, so it goes inside ODE section. we write in ode a new key named 'a' , with a dictionnary as value
- the dictionnary contains itself two fields :
- 'func': the logics that link fields (see point 4 on how to write it)
- 'com': a string to help user understanding the logic of equation
- How to write a function ?
- the recommended approach is a lambda function : It allow a better visualisation in get_summary and in the network. If you do not want the function to be easily read (or your function is way too long), you can use a def: function outside
- all the dependencies are explicit, and given a value that will not return an error (those value are just to check the integrity of the equation).
- It looks like this :
lambda GDP=0, w=0, L=0: GDP - w * L
- If it is an ODE using its own value, please call it using "itself" instead
- In consequence of last point of 4), 'a' will be written :
- as a lambda :
'ode': { [...] 'a': { 'func': lambda itself=0, alpha=0, zouplala=0, proutprout=1 : itself*(alpha + zouplala/proutprout), 'com': 'exogenous productivity + two weird terms for pleasure'}, [...] },
- as a function :
- define it above
_LOGICS
- for example you can do
term1 = itself*alpha term2 = zouplala/proutprout return term1 + term2
- And you use it as :
ode': { [...] 'a': { 'func': MyFunc_forA, 'com': 'exogenous productivity + two weird terms for pleasure written as a big function'}, [...] },
- define it above
- as a lambda :
- Now wou will have to define zouplala and proutprout our two new fields.
We will say for the sake of it that
zouplala
is a parameter,proutprout
a state variable- to write zouplala : we have to give him a value by default, and it's good practice to give
him a definition and an unit, for readability.
'param': { [...] 'zouplala': { 'value': 0.25 , 'definition': 'a weird thing I introduced', 'units': '$', }, [...] },
- we say for the sake of it that proutprout = w/a. we write it as :
'statevar': { [...] 'proutprout': {'func': lambda w=0,a=1: w/a, 'com': 'madeup expression', 'definition': 'a madeup term', 'units': '$^{-1}'}, [...] },
- if the field you introduce is dimensionless, then the unit is '',
- to write zouplala : we have to give him a value by default, and it's good practice to give
him a definition and an unit, for readability.
If the logic already exist with the same dependency in `def_functions` do :
`'a': Funcs.Productivity.exogenous,`
If you construct on top of a previous model, you can import all his logics.
For example, we want to add a CES production function on a Goodwin Keen model.
We first load the previous model
```
from pygemmes._models._model_G import _LOGICS as _LOGICS0
_LOGICS = deepcopy(_LOGICS0)
```
Then we write a dictionnary only containing the different and new fields
```
_CES_LOGICS = {
'statevar': {
# Characteristics of a CES
'cesLcarac': Funcs.ProductionWorkers.cesLcarac,
'cesYcarac': Funcs.ProductionWorkers.cesYcarac,
'omegacarac': Funcs.ProductionWorkers.omegacarac,
# From it are deduced optimised quantities
'nu': Funcs.ProductionWorkers.CES_Optimised.nu,
'l': Funcs.ProductionWorkers.CES_Optimised.l,
# From it are deduced Labor and Output
'Y': Funcs.ProductionWorkers.CES_Optimised.Y,
'L': Funcs.ProductionWorkers.CES_Optimised.L,
},
}
```
Then we overload the previous model with our new definitions
```
# We add them explicitely
for category, dic in _CES_LOGICS.items():
for k, v in dic.items():
_LOGICS[category][k] = v
```
- If you change the category of hypothesis (from a statevar to an ODE for example), be sure you delete it in the previous section.
- If you want to use the field lambda in a logic, call it
lamb
the system will understand !
- Paul Valcke
- Didier Vezinet