Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feedbacks #184

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions doc/whats_new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ v0.6.0 (Unreleased)
This will be set to the main clock when storing the dataset.
- Changed default ``fill_value`` in the zarr stores to maximum dtype value
for integer dtypes and ``np.nan`` for floating-point variables.
- Added feedback arrows from the last process that updates a variable to all
processes that use it before it is updated, for all variables. Can be used as:
``model.visualize(show_feedbacks=True)`` default: ``True``

v0.5.0 (26 January 2021)
------------------------
Expand Down
44 changes: 44 additions & 0 deletions xsimlab/dot.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
from functools import partial

from .utils import variables_dict, import_required, maybe_to_list

# from .process import filter_variables
from .variable import VarIntent, VarType


Expand Down Expand Up @@ -136,6 +138,37 @@ def add_var_and_targets(self, p_name, var_name):
):
self._add_var(var, p_name)

def add_feedback_arrows(self):
"""
adds dotted arrows from the last inout processes to all in processes
before the first inout process
"""
# in->inout1->inout2
# ^ /
# \- - - - - /
in_vars = {}
inout_vars = {}
for p_name, p_obj in self.model._processes.items():
print(in_vars,inout_vars)
p_cls = type(p_obj)
for var_name, var in variables_dict(p_cls).items():
target_keys = tuple(_get_target_keys(p_obj, var_name))
if (
var.metadata["intent"] == VarIntent.IN
and not target_keys in inout_vars
):
if target_keys in in_vars:
in_vars[target_keys].add(p_name)
else:
in_vars[target_keys] = {p_name}
if var.metadata["intent"] == VarIntent.INOUT:
inout_vars[target_keys] = p_name

for target_keys, io_p in inout_vars.items():
for in_p in in_vars[target_keys]:
print("adding edge: ", io_p,in_p)
self.g.edge(io_p, in_p, weight="200", style="dashed")

def get_graph(self):
return self.g

Expand All @@ -146,6 +179,7 @@ def to_graphviz(
show_only_variable=None,
show_inputs=False,
show_variables=False,
show_feedbacks=True,
graph_attr={},
**kwargs,
):
Expand All @@ -158,6 +192,7 @@ def to_graphviz(
builder.add_processes()

if show_only_variable is not None:
print(show_only_variable)
p_name, var_name = show_only_variable
builder.add_var_and_targets(p_name, var_name)

Expand All @@ -167,6 +202,9 @@ def to_graphviz(
elif show_inputs:
builder.add_inputs()

elif show_feedbacks:
builder.add_feedback_arrows()

return builder.get_graph()


Expand Down Expand Up @@ -211,6 +249,7 @@ def dot_graph(
show_only_variable=None,
show_inputs=False,
show_variables=False,
show_feedbacks=True,
**kwargs,
):
"""
Expand All @@ -236,6 +275,10 @@ def dot_graph(
show_variables : bool, optional
If True, show also the other variables (default: False).
Ignored if `show_only_variable` is not None.
show_feedbacks: bool, optional
if True, draws dotted arrows to indicate what processes use updated
variables in the next timestep. (default: True)
Ignored if `show_variables` is not None
**kwargs
Additional keyword arguments to forward to `to_graphviz`.

Expand All @@ -262,6 +305,7 @@ def dot_graph(
show_only_variable=show_only_variable,
show_inputs=show_inputs,
show_variables=show_variables,
show_feedbacks=show_feedbacks,
**kwargs,
)

Expand Down
Loading