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