Skip to content
Snippets Groups Projects
Commit 7d918975 authored by abaucher's avatar abaucher
Browse files

Corrected the no comment problem

parents ae05871a 3c3a3de3
No related branches found
No related tags found
No related merge requests found
......@@ -6,3 +6,39 @@
- [ ] New table politic, c'est la variable qui est rentrée en paramètre.
- [x] Assertions que le system est bien run
- [ ] Deux change politic marche pas
- [ ] Ajouter shéma de documentation
- [ ] Fonctions graphiques et tout de World3 à mettre dans System
- [ ] add_function ça fonctionne ça ?
- [ ] Les new politic dans system directement.
- [ ] Demander: trop de fonctions dans System ?
- [ ] Demander: les dictionnaires de forme fixée, mieux avec plusieurs noms ?
- [ ] Demander: doublons d'informations pour rechercher plus vite, oui ou non ?
- [ ] Clarifier dans l'explication de simulation de System les appels et ordre
- [ ] Demander: ça vaut le coup de faire une documentaiton shématique etc. ?
## La documentation
### From equations to system.
Pydynamo equations are parsed to create a System object, through the function `new_system`.
1. We start with a list of string pydynamo equations.
2. The `parse_system.get_nodes_eqs_dicts` retrieve from this list all informations that a System needs to be created.
3. It uses functions of `parse_equations`, which analyse an equation to retrieve all relevant information about one equation:
- If it's a constant, update or initialisation equation
- What parameters are needed in the equation (constants, variables and their indices, special functions)
4. It also uses functions from `parse_dynamo_functions` to handle the case of special DYNAMO functions (clip, tabhl, etc.)
5. With all this informations, contained in the *main dictionnnaries*, a System object is created.
### System object
A system object only contains the informations retrieved by the above . Any user can modify the object:
- Add new equations or change it
- Change constant values
- Add new politic (which changes some equations)
Then, each time a System object is run:
1. The *main dictionnnaries* are updated, because maybe some dependencies has been changed.
2. All variables are initialized as empty arrays.
3. All constants are set at their values.
4. All special functions are set.
5. Thanks to the graph of dependencies, an updating order is defined.
6. All variables are initialized with the initialisation functions.
7. For each step, all variables are updated, and their new value set in the arrays.
8. The results can be plotted with new functions.
"""Depreciated functions.
"""
# Modifiers
def add_comments(self, comments):
for node, comment in comments.items():
self.comments[node] = comment
def add_function(self, fun, name=None):
if not name:
name = fun.__name__
for s in ('_', 'update', 'init', 'set'):
assert not name.startswith(s), "Fun name shouldn't start with '{s}'"
setattr(self, fun.__name__, fun)
def add_functions(self, *args, **kwargs):
for fun in args:
self.add_function(fun)
for name, fun in kwargs.items():
self.add_function(fun, name)
def add_system_function(self, fun, name=None):
if not name:
name = fun.__name__
if any(name.startswith(s) for s in ('update', 'init', 'set')):
setattr(self, name, fun)
fun.__okdic__ = False
fun.__doc__ = f"User defined function\n{fun.__doc__}"
return
assert False, "Invalid function name. Should starts with 'init', 'update' or 'set'"
......@@ -18,9 +18,10 @@ class System:
"""
Base class for system dynamics.
A System stores two dictionnaries containing all
A System stores 3 dictionnaries containing all
nodes (constants, variables, and functions)
and equations (constan values, updating equations and initialisation equations)
and comments about nodes.
From this dictionnaries, it generates the updating pattern
and run the simulation.
......@@ -63,7 +64,7 @@ class System:
>>>
>>> s = System(equations_function)
"""
self.comments = {}
# If code is given, create a System with equations
if code:
if isinstance(code, list):
......@@ -88,7 +89,6 @@ class System:
'update': dict(),
'init': dict()
}
self.comments = {}
self.code_lines = []
def add_equations(self, new_code_lines):
......@@ -105,13 +105,27 @@ class System:
def reset_eqs(self, prepare=True):
"""Set all nodes, equations and comments.
"""
self.nodes, self.eqs, self.comments = get_system_dicts(self.code_lines)
self.nodes, self.eqs, new_comments = get_system_dicts(self.code_lines)
# Keep old comments
for node, comment in new_comments.items():
if comment != '':
self.comments[node] = comment
if prepare:
self.prepare()
def add_comments(self, comments):
"""Add comments to the System.
Parameters
----------
comments : dict(str: str)
Each node name and its comment.
"""
for node, comment in comments.items():
self.comments[node] = comment
......@@ -140,7 +154,7 @@ class System:
np.array(float):
Array of values of the variable for the last run.
"""
assert name in self.nodes['var'], f"{name} is not a variable"
return getattr(self, name)
......@@ -228,11 +242,11 @@ class System:
Array of system time.
"""
return self.time
def get_tabhl_args(self, name):
"""
Get indications about a tabhl function.
Parameters
----------
name: str
......@@ -243,7 +257,7 @@ class System:
np.array, np.array, str, str, str:
x, f(x), x label, y label, title
"""
aa = list(self.eqs['update'][name]['args']['var'])
argname = aa[0][0].split('.')[0]
assert 'tabhl_' + name in dir(self), 'Error, no such tabhl function'
......@@ -563,7 +577,7 @@ class System:
if '__iter__' in dir(value):
value = np.array(value)
return value
except Exception as e:
raise(Exception(f"Error setting {cst}\n"
f" wih function {fun.__custom_repr__}\n"
......@@ -586,7 +600,7 @@ class System:
Values of each arguments.
"""
setattr(self, cst, self.get_cst_val(cst, args))
def set_all_csts(self):
"""Set every constant constant according to its equation and arguments ONLY IF the constant is not set yet.
"""
......@@ -604,7 +618,7 @@ class System:
if not cst in dir(self):
self.set_cst(cst, args)
def generate_var(self, var, N):
"""Initialise an empty array for a variable.
......@@ -651,7 +665,7 @@ class System:
table = getattr(self, p['table'])
fun = Interpol(x_low, x_high, x_incr, table)
setattr(self, p['fun'], fun)
if f_type == 'sample':
isam = eval(p['isam'])
fun = Sample(isam, self.time)
......@@ -659,7 +673,7 @@ class System:
if f_type == 'step' or type =='clip':
pass
def step(self, hght, sttm, k):
"""Step function. See specials.step.
"""
......@@ -703,11 +717,11 @@ class System:
fun_args[p['type']] = getattr(self, p['fun'])
fun_args['k'] = 0
cst_args = {c: getattr(self, c) for c in args['cst']}
# Assert that there is no variables considered as constants etc.
tps = {'cst', 'var', 'fun'}
dd = locals()
for t, n, tt in ((t, n, tt) for t in tps
for tt in tps.difference({t})
for n in dd[tt + '_args']):
......@@ -739,7 +753,7 @@ class System:
u = {'var': var}
try:
args = self.eqs['update'][var]['args']
u['cst_args'] = {c: getattr(self, c) for c in args['cst']}
u['var_args'] = {v + '_' + ni: (getattr(self, v), 0 if ni == 'k' else -1)
for v, ni in args['var']}
......@@ -748,10 +762,10 @@ class System:
p = self.eqs['update'][var]['args']['fun'][fun_type]
u['fun_args'][p['type']] = getattr(self, p['fun'])
u['fun_args']['k'] = None
u['update_fun'] = getattr(self, 'update_' + var)
self._update_loop.append(u)
except AttributeError as e:
line = self.eqs['update'][var]['line']
raise(AttributeError(f"In updating {var}:\n"
......@@ -890,7 +904,7 @@ class System:
msg += f"{j}.i = {line} \n"
msg +="Please design an initialisation scheme that is not cyclic."
raise AssertionError(msg)
def run(self, N=None, dt=1):
"""
After preparing and before running,
......@@ -906,10 +920,10 @@ class System:
>>> system.update_v1 = new_update # New fct for updating v1
>>> s.run(10, 1) # Run with new parameters
"""
self.change_functions_in_dict()
self.assert_update_acyclic()
self.assert_init_acyclic()
self.assert_init_acyclic()
try:
if not N:
......@@ -918,7 +932,7 @@ class System:
self.final_time = self.initial_time + N * dt
except:
raise Exception("Either pass N or define both final_time and initial_time")
self.time = self.initial_time + np.arange(N)*dt
self.dt = dt
self.generate_all_vars(N)
......
......@@ -14,11 +14,11 @@ class World3(System):
def __init__(self, scenario_number=2, sys=None):
"""Initialise a World3 object. By default, the scenario number is the second one, because it's the most "realistic" when we compare to the current situation (in 2022).
"""
self.code_lines = w3_code
ccode = w3_code.copy()
changes = scenarios[scenario_number - 1]['changes']
for cst, eq in changes.items():
self.code_lines.append(f'{cst} = {eq}')
self.reset_eqs()
ccode.append(f'{cst} = {eq}')
super().__init__(ccode, True)
self.add_comments(w3_defs)
def copy(self):
......
test.py 0 → 100644
from pydynamo import *
import matplotlib.pyplot as plt
w = World3()
w.run()
w4 = World3(4)
w.plot_world()
w4.run()
plt.show()
plt.show()
w.new_politic('amti', 2000, w.amti/2)
w.run()
w.plot('amti')
plt.show()
w.show_influence_graph().show('haha.html')
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