From 24a76101d79f22865a2ddf32a76ad0913ecfa8db Mon Sep 17 00:00:00 2001 From: BAUCHER Achille <achille.baucher@inria.fr> Date: Tue, 15 Mar 2022 09:50:47 +0100 Subject: [PATCH] Comments on System modifiers --- afaire.md | 3 + pydynamo/core/system.py | 135 +++++++++++++++++++++++++++++++--------- 2 files changed, 107 insertions(+), 31 deletions(-) diff --git a/afaire.md b/afaire.md index 2c3af311..965750a8 100644 --- a/afaire.md +++ b/afaire.md @@ -4,3 +4,6 @@ - [ ] tabhl se nomme avec le nom de la variable attribuée - [ ] Une seule fonction spéciale DYNAMO admise dans une équation - [ ] New table politic, c'est la variable qui est rentréer en paramètre. +- [ ] Ajouter shéma de documentation +- [ ] Fonctions graphiques et tout de World3 à mettre dans System +- [ ] add_function ça fonctionne ça ? \ No newline at end of file diff --git a/pydynamo/core/system.py b/pydynamo/core/system.py index 3c68050b..5f5ac752 100644 --- a/pydynamo/core/system.py +++ b/pydynamo/core/system.py @@ -1,3 +1,6 @@ +"""Define the System class, used to contain, modify, simulate and plot a model. +""" + import inspect import numpy as np import networkx as nx @@ -15,16 +18,17 @@ 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. """ def __init__(self): - """Initialise an empty System with nodes and equations dictionnaries""" + """Initialise an empty System with nodes, equations and comments dictionnaries""" self.nodes = { 'cst': set(), 'var': set(), @@ -36,67 +40,136 @@ class System: 'update': dict(), 'init': dict() } + self.comments = {} - # Modifiers + # ---------- Modifiers ---------- + def add_node(self, node, node_type): + """Add a node to the System. + + Parameters + ---------- + node : str + Name of the node. + node_type : str + Type (cst, var, fun) of the node. + """ self.nodes[node_type].add(node) def add_all_nodes(self, all_nodes): + """Add all nodes in the dictionnary `all_nodes`. + + Parameters + ---------- + all_nodes : dict(str: set(str)) + Dictionnary of all nodes to add. Like: + {'cst': {all constant names}, + 'var': {all variable names}, + 'fun': {all function names}} + """ for node_type in all_nodes: for node in all_nodes[node_type]: self.add_node(node, node_type) def add_eq(self, node, eq_type, arguments): + """Add an equation to the System. + + Parameters + ---------- + node : str + Name of the node set by the equation. + eq_type : str + Type (cst, init, update) of the equation. + arguments : dict(str: set) + Arguments needed in the equation. Like: + {'cst': {constant names}, + 'var': {( variable name, index name)}, + 'fun': {dict_of_function_infomations}} + """ + # Check if some special functions (clip, step) are in arguments: for fun in set(arguments['args']['fun']): if fun not in instance_fun_names and fun in globals(): del arguments['args']['fun'][fun] + self.eqs[eq_type][node] = arguments def add_all_eqs(self, all_eqs): + """Add all equations. + + Parameters + ---------- + all_nodes : dict(str: set(str)) + Dictionnary of all equations to add. Like: + {'cst': {node name: equation}, + 'init': {node name: equation}, + 'update': {node name: equation}} + """ for eq_type in all_eqs: for node in all_eqs[eq_type]: self.add_eq(node, eq_type, all_eqs[eq_type][node]) 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 def add_units(self, units): + """Unit of calculs. NOT USED. + """ self.units = units + + # Following functions are not used yet. + # def add_function(self, fun, name=None): + # """Add or reset a function to the system. + # The function should be any of init, update or set, and take the same arguments as defined in the system equations. - 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) + # Parameters + # ---------- + # fun : function + # Function taking appropriate arguments and return a value. If name is None, the function name should be one of `init_var`, `upadte_var`, `set_cst` with `var` a variable name and `cst` a constant name. + # name : str + # Name of the function in case we want it different than fun.__name__. + # """ + # 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'" - - def add_system_functions(self, *args, **kwargs): - for fun in args: - self.add_system_function(fun) - for fun, name in kwargs: - sefl.add_system_function(fun, name) + # 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'" + + # def add_system_functions(self, *args, **kwargs): + # for fun in args: + # self.add_system_function(fun) + # for fun, name in kwargs: + # sefl.add_system_function(fun, name) - # Getters + # ---------- Getters ---------- + def iter_all_nodes(self): return chain(*self.nodes.values()) -- GitLab