From a442225ce1c5e65bf4128cf806eef9479e271fca Mon Sep 17 00:00:00 2001 From: superstar54 Date: Fri, 28 Jul 2023 11:01:09 +0200 Subject: [PATCH 1/3] add ToCtx and FromCtx --- aiida_worktree/engine/worktree.py | 36 +++++++++++++++++--- aiida_worktree/nodes/__init__.py | 4 ++- aiida_worktree/nodes/builtin.py | 47 ++++++++++++++++++++++++++- aiida_worktree/properties/built_in.py | 32 +++++++++++++++++- tests/test_ctx.py | 18 ++++++++++ 5 files changed, 130 insertions(+), 7 deletions(-) create mode 100644 tests/test_ctx.py diff --git a/aiida_worktree/engine/worktree.py b/aiida_worktree/engine/worktree.py index 172d4e83..adafcdc5 100644 --- a/aiida_worktree/engine/worktree.py +++ b/aiida_worktree/engine/worktree.py @@ -560,6 +560,16 @@ def run_nodes(self, names): # self.ctx.nodes[name]["group_outputs"] = executor.group_outputs self.ctx.nodes[name]["state"] = "RUNNING" return self.to_context(process=process) + elif node["metadata"]["node_type"] in ["Control"]: + if node["metadata"]["identifier"] == "ToCtx": + self.ctx[args[0]] = args[1] + results = None + elif node["metadata"]["identifier"] == "FromCtx": + results = {"result": self.ctx[args[0]]} + node["results"] = results + # print("results: ", results) + node["process"] = None + self.ctx.nodes[name]["state"] = "FINISHED" elif node["metadata"]["node_type"] in ["Normal"]: print("node type: Normal.") # normal function does not have a process @@ -593,7 +603,9 @@ def get_inputs(self, node): for input in node["inputs"]: # print(f"input: {input['name']}") if len(input["links"]) == 0: - inputs[input["name"]] = properties[input["name"]]["value"] + inputs[input["name"]] = self.update_ctx_variable( + properties[input["name"]]["value"] + ) elif len(input["links"]) == 1: link = input["links"][0] if self.ctx.nodes[link["from_node"]]["results"] is None: @@ -613,19 +625,35 @@ def get_inputs(self, node): link["from_socket"] ] inputs[input["name"]] = value - for name in node["metadata"].get("args", []): if name in inputs: args.append(inputs[name]) else: - args.append(properties[name]["value"]) + value = self.update_ctx_variable(properties[name]["value"]) + args.append(value) for name in node["metadata"].get("kwargs", []): if name in inputs: kwargs[name] = inputs[name] else: - kwargs[name] = properties[name]["value"] + value = self.update_ctx_variable(properties[name]["value"]) + kwargs[name] = value return args, kwargs + def update_ctx_variable(self, value): + # replace context variables + """Get value from context.""" + if ( + isinstance(value, str) + and value.strip().startswith("{{") + and value.strip().endswith("}}") + ): + name = value[2:-2].strip() + if name not in self.ctx: + raise ValueError(f"Context variable {name} not found.") + return self.ctx[name] + else: + return value + def check_node_state(self, name): """Check node states. diff --git a/aiida_worktree/nodes/__init__.py b/aiida_worktree/nodes/__init__.py index aeb2d295..aedfb32e 100644 --- a/aiida_worktree/nodes/__init__.py +++ b/aiida_worktree/nodes/__init__.py @@ -1,4 +1,4 @@ -from .builtin import AiiDAGather +from .builtin import AiiDAGather, AiiDAToCtx, AiiDAFromCtx from .test import ( AiiDAInt, AiiDAFloat, @@ -24,6 +24,8 @@ node_list = [ AiiDAGather, + AiiDAToCtx, + AiiDAFromCtx, AiiDAInt, AiiDAFloat, AiiDAString, diff --git a/aiida_worktree/nodes/builtin.py b/aiida_worktree/nodes/builtin.py index 2e665c84..140d9976 100644 --- a/aiida_worktree/nodes/builtin.py +++ b/aiida_worktree/nodes/builtin.py @@ -25,5 +25,50 @@ def get_executor(self): } +class AiiDAToCtx(Node): + """AiiDAToCtx""" + + identifier = "ToCtx" + name = "ToCtx" + node_type = "Control" + catalog = "AiiDA" + args = ["key", "value"] + + def create_sockets(self): + self.inputs.clear() + self.outputs.clear() + self.inputs.new("General", "key") + self.inputs.new("General", "value") + self.outputs.new("General", "result") + + def get_executor(self): + return { + "path": "builtins", + "name": "setattr", + } + + +class AiiDAFromCtx(Node): + """AiiDAFromCtx""" + + identifier = "FromCtx" + name = "FromCtx" + node_type = "Control" + catalog = "AiiDA" + args = ["key"] + + def create_sockets(self): + self.inputs.clear() + self.outputs.clear() + self.inputs.new("General", "key") + self.outputs.new("General", "result") + + def get_executor(self): + return { + "path": "builtins", + "name": "getattr", + } + + if __name__ == "__main__": - print(gather_node) + print() diff --git a/aiida_worktree/properties/built_in.py b/aiida_worktree/properties/built_in.py index d5cdbe31..c87a38f1 100644 --- a/aiida_worktree/properties/built_in.py +++ b/aiida_worktree/properties/built_in.py @@ -22,6 +22,12 @@ def set_value(self, value): self._value = value if self.update is not None: self.update() + elif ( + isinstance(value, str) + and value.rstrip().startswith("{{") + and value.endswith("}}") + ): + self._value = value else: raise Exception("{} is not a integer.".format(value)) @@ -45,6 +51,12 @@ def set_value(self, value): self._value = value if self.update is not None: self.update() + elif ( + isinstance(value, str) + and value.rstrip().startswith("{{") + and value.endswith("}}") + ): + self._value = value else: raise Exception("{} is not a float.".format(value)) @@ -68,6 +80,12 @@ def set_value(self, value): self._value = value if self.update is not None: self.update() + elif ( + isinstance(value, str) + and value.rstrip().startswith("{{") + and value.endswith("}}") + ): + self._value = value else: raise Exception("{} is not a bool.".format(value)) @@ -90,6 +108,12 @@ def set_value(self, value): self._value = value if self.update is not None: self.update() + elif ( + isinstance(value, str) + and value.rstrip().startswith("{{") + and value.endswith("}}") + ): + self._value = value else: raise Exception("{} is not a string.".format(value)) @@ -108,10 +132,16 @@ def set_value(self, value): self._value = orm.Dict(value) if self.update is not None: self.update() - if isinstance(value, orm.Dict): + elif isinstance(value, orm.Dict): self._value = value if self.update is not None: self.update() + elif ( + isinstance(value, str) + and value.rstrip().startswith("{{") + and value.endswith("}}") + ): + self._value = value else: raise Exception("{} is not a dict.".format(value)) diff --git a/tests/test_ctx.py b/tests/test_ctx.py new file mode 100644 index 00000000..afc4dbf4 --- /dev/null +++ b/tests/test_ctx.py @@ -0,0 +1,18 @@ +import aiida + +aiida.load_profile() + + +def test_ctx(decorated_add): + """Set/get data to/from context.""" + from aiida_worktree import WorkTree + from aiida.orm import Float + + nt = WorkTree(name="test_ctx") + add1 = nt.nodes.new(decorated_add, "add1", x=Float(2).store(), y=Float(3).store()) + nt.nodes.new("ToCtx", "to_ctx1", key="count", value=Float(2).store()) + add2 = nt.nodes.new(decorated_add, "add2", y="{{ count }}") + nt.links.new(add1.outputs[0], add2.inputs["x"]) + nt.submit(wait=True) + # print("results: ", results[]) + assert add2.node.outputs.result.value == 7 From 64efbf7b927a75d81eb4cdfa62472ff2579fff31 Mon Sep 17 00:00:00 2001 From: superstar54 Date: Fri, 28 Jul 2023 11:57:03 +0200 Subject: [PATCH 2/3] add to_ctx to node --- aiida_worktree/engine/worktree.py | 15 ++++++++++++++- aiida_worktree/worktree.py | 6 ++++++ tests/test_ctx.py | 15 ++++++++++++++- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/aiida_worktree/engine/worktree.py b/aiida_worktree/engine/worktree.py index adafcdc5..436b0db6 100644 --- a/aiida_worktree/engine/worktree.py +++ b/aiida_worktree/engine/worktree.py @@ -447,6 +447,7 @@ def is_worktree_finished(self): node["results"] = node["process"].outputs # self.ctx.new_data[name] = node["results"] self.ctx.nodes[name]["state"] = "FINISHED" + self.node_to_ctx(name) print(f"Node: {name} finished.") elif state == "EXCEPTED": node["state"] = state @@ -501,6 +502,7 @@ def run_nodes(self, names): node["results"] = {node["outputs"][0]["name"]: results} self.ctx.input_nodes[name] = results self.ctx.nodes[name]["state"] = "FINISHED" + self.node_to_ctx(name) # ValueError: attempted to add an input link after the process node was already stored. # self.node.base.links.add_incoming(results, "INPUT_WORK", name) elif node["metadata"]["node_type"] == "data": @@ -510,6 +512,7 @@ def run_nodes(self, names): node["process"] = results self.ctx.new_data[name] = results self.ctx.nodes[name]["state"] = "FINISHED" + self.node_to_ctx(name) elif node["metadata"]["node_type"] in ["calcfunction", "workfunction"]: print("node type: calcfunction/workfunction.") kwargs.setdefault("metadata", {}) @@ -523,6 +526,7 @@ def run_nodes(self, names): # print("results: ", results) node["process"] = process self.ctx.nodes[name]["state"] = "FINISHED" + self.node_to_ctx(name) except Exception as e: print(e) self.report(e) @@ -560,12 +564,15 @@ def run_nodes(self, names): # self.ctx.nodes[name]["group_outputs"] = executor.group_outputs self.ctx.nodes[name]["state"] = "RUNNING" return self.to_context(process=process) - elif node["metadata"]["node_type"] in ["Control"]: + elif node["metadata"]["node_type"].upper() in ["CONTROL"]: if node["metadata"]["identifier"] == "ToCtx": self.ctx[args[0]] = args[1] results = None elif node["metadata"]["identifier"] == "FromCtx": results = {"result": self.ctx[args[0]]} + elif node["metadata"]["identifier"] == "AiiDAWhile": + self.reset_node(node["name"]) + results = {"result": self.ctx[args[0]]} node["results"] = results # print("results: ", results) node["process"] = None @@ -587,6 +594,7 @@ def run_nodes(self, names): node["results"][node["outputs"][0]["name"]] = results self.ctx.input_nodes[name] = results self.ctx.nodes[name]["state"] = "FINISHED" + self.node_to_ctx(name) # print("result from node: ", node["results"]) else: print("node type: unknown.") @@ -654,6 +662,11 @@ def update_ctx_variable(self, value): else: return value + def node_to_ctx(self, name): + items = self.ctx.nodes[name]["to_ctx"] + for item in items: + self.ctx[item[1]] = self.ctx.nodes[name]["results"][item[0]] + def check_node_state(self, name): """Check node states. diff --git a/aiida_worktree/worktree.py b/aiida_worktree/worktree.py index 02f3be1a..10ddd96a 100644 --- a/aiida_worktree/worktree.py +++ b/aiida_worktree/worktree.py @@ -54,6 +54,12 @@ def submit(self, wait=False, timeout=60): if wait: self.wait(timeout=timeout) + def to_dict(self): + ntdata = super().to_dict() + for node in self.nodes: + ntdata["nodes"][node.name]["to_ctx"] = getattr(node, "to_ctx", []) + return ntdata + def wait(self, timeout=50): """ Periodically checks and waits for the AiiDA worktree process to finish until a given timeout. diff --git a/tests/test_ctx.py b/tests/test_ctx.py index afc4dbf4..11607f56 100644 --- a/tests/test_ctx.py +++ b/tests/test_ctx.py @@ -3,6 +3,20 @@ aiida.load_profile() +def test_to_ctx(decorated_add): + """Set/get data to/from context.""" + from aiida_worktree import WorkTree + from aiida.orm import Float + + nt = WorkTree(name="test_ctx") + add1 = nt.nodes.new(decorated_add, "add1", x=Float(2).store(), y=Float(3).store()) + add1.to_ctx = [["result", "sum"]] + add2 = nt.nodes.new(decorated_add, "add2", y="{{ sum }}") + nt.links.new(add1.outputs[0], add2.inputs["x"]) + nt.submit(wait=True) + assert add2.node.outputs.result.value == 10 + + def test_ctx(decorated_add): """Set/get data to/from context.""" from aiida_worktree import WorkTree @@ -14,5 +28,4 @@ def test_ctx(decorated_add): add2 = nt.nodes.new(decorated_add, "add2", y="{{ count }}") nt.links.new(add1.outputs[0], add2.inputs["x"]) nt.submit(wait=True) - # print("results: ", results[]) assert add2.node.outputs.result.value == 7 From 0d4e3b4805c1cd1a976322f93f358c1b83141afa Mon Sep 17 00:00:00 2001 From: superstar54 Date: Sat, 29 Jul 2023 14:38:41 +0200 Subject: [PATCH 3/3] support while --- README.md | 2 +- aiida_worktree/engine/worktree.py | 66 ++++++-- aiida_worktree/worktree.py | 8 + docs/source/howto/for_gather.ipynb | 75 ++++----- docs/source/howto/if.ipynb | 82 +++++----- docs/source/howto/index.rst | 1 + docs/source/howto/while.ipynb | 254 +++++++++++++++++++++++++++++ docs/source/index.rst | 4 +- docs/source/node.rst | 6 +- docs/source/quick_start.ipynb | 85 +++++----- docs/source/tutorial/qe.ipynb | 84 +++++----- docs/source/worktree.rst | 14 +- tests/conftest.py | 15 +- tests/test_ctx.py | 22 ++- tests/test_while.py | 32 ++++ 15 files changed, 538 insertions(+), 212 deletions(-) create mode 100644 docs/source/howto/while.ipynb create mode 100644 tests/test_while.py diff --git a/README.md b/README.md index a20f9dbf..8773d54f 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,8 @@ Here is a detailed comparison between the ``WorkTree`` with two AiiDA built-in w | Implementation | Easy | ``Difficult`` | Easy | | Dynamic | ``No`` | ``No`` | Yes | | Ready to Use | Yes | ``No``,Need PYTHONPATH | Yes | -| Flow Control | All | `if`, `while` | `if` | | Subprocesses Handling | ``No`` | Launches & waits | Launches & waits | +| Flow Control | All | `if`, `while` | `if`, `while` | | Termination | ``Hard exit`` | ExitCode | ExitCode | | Capabilities | Calls calcs and works | Calls any process | Calls any process | | Data Passing | Direct passing | Context dictionary | Link | diff --git a/aiida_worktree/engine/worktree.py b/aiida_worktree/engine/worktree.py index 436b0db6..c165c588 100644 --- a/aiida_worktree/engine/worktree.py +++ b/aiida_worktree/engine/worktree.py @@ -386,6 +386,7 @@ def setup(self): # ntdata = jsonref.JsonRef.replace_refs(tntdata, loader = JsonYamlLoader()) build_node_link(ntdata) + self.init_ctx(ntdata["ctx"]) self.ctx.nodes = ntdata["nodes"] self.ctx.links = ntdata["links"] self.ctx.ctrl_links = ntdata["ctrl_links"] @@ -400,9 +401,23 @@ def setup(self): self.ctx.connectivity = nc.build_connectivity() self.ctx.msgs = [] self.node.set_process_label(f"WorkTree: {self.ctx.worktree['name']}") + # while worktree + if self.ctx.worktree["is_while"]: + should_run = self.check_while_conditions() + if not should_run: + self.set_node_state(self.ctx.nodes.keys(), "SKIPPED") + + def init_ctx(self, datas): + for key, value in datas.items(): + self.ctx[key] = value def launch_worktree(self): + print("launch_worktree: ") self.report("Lanch worktree.") + if len(self.ctx.worktree["starts"]) > 0: + self.run_nodes(self.ctx.worktree["starts"]) + self.ctx.worktree["starts"] = [] + return node_to_run = [] for name, node in self.ctx.nodes.items(): # update node state @@ -416,7 +431,9 @@ def launch_worktree(self): self.run_nodes(node_to_run) def is_worktree_finished(self): - flag = True + """Check if the worktree is finished. + For `while` worktree, we need check its conditions""" + is_finished = True # print("is_worktree_finished:") for name, node in self.ctx.nodes.items(): print(name, node["state"]) @@ -460,8 +477,27 @@ def is_worktree_finished(self): ) print(f"Node: {name} failed.") if node["state"] in ["RUNNING", "CREATED", "READY"]: - flag = False - return flag + is_finished = False + if is_finished: + if self.ctx.worktree["is_while"]: + should_run = self.check_while_conditions() + is_finished = not should_run + return is_finished + + def check_while_conditions(self): + print("Is a while worktree") + condition_nodes = [c[0] for c in self.ctx.worktree["conditions"]] + self.run_nodes(condition_nodes) + conditions = [ + self.ctx.nodes[c[0]]["results"][c[1]] + for c in self.ctx.worktree["conditions"] + ] + print("conditions: ", conditions) + should_run = False not in conditions + if should_run: + self.reset() + self.set_node_state(condition_nodes, "SKIPPED") + return should_run def run_nodes(self, names): """Run node @@ -564,19 +600,6 @@ def run_nodes(self, names): # self.ctx.nodes[name]["group_outputs"] = executor.group_outputs self.ctx.nodes[name]["state"] = "RUNNING" return self.to_context(process=process) - elif node["metadata"]["node_type"].upper() in ["CONTROL"]: - if node["metadata"]["identifier"] == "ToCtx": - self.ctx[args[0]] = args[1] - results = None - elif node["metadata"]["identifier"] == "FromCtx": - results = {"result": self.ctx[args[0]]} - elif node["metadata"]["identifier"] == "AiiDAWhile": - self.reset_node(node["name"]) - results = {"result": self.ctx[args[0]]} - node["results"] = results - # print("results: ", results) - node["process"] = None - self.ctx.nodes[name]["state"] = "FINISHED" elif node["metadata"]["node_type"] in ["Normal"]: print("node type: Normal.") # normal function does not have a process @@ -727,6 +750,9 @@ def check_parent_state(self, name): # node = outgoing.get_node_by_label(output[0]) # outputs[output[2]] = getattr(node.outputs, output[1]) # return outputs + def reset(self): + print("Reset") + self.set_node_state(self.ctx.nodes.keys(), "CREATED") def set_node_state(self, names, value): """Set node state""" @@ -736,11 +762,17 @@ def set_node_state(self, names, value): def finalize(self): """""" # expose group outputs + print("finalize") group_outputs = {} print("group outputs: ", self.ctx.worktree["metadata"]["group_outputs"]) for output in self.ctx.worktree["metadata"]["group_outputs"]: print("output: ", output) - group_outputs[output[2]] = self.ctx.nodes[output[0]]["results"][output[1]] + if output[0] == "ctx": + group_outputs[output[2]] = self.ctx[output[1]] + else: + group_outputs[output[2]] = self.ctx.nodes[output[0]]["results"][ + output[1] + ] self.out("group_outputs", group_outputs) self.out("new_data", self.ctx.new_data) self.report("Finalize") diff --git a/aiida_worktree/worktree.py b/aiida_worktree/worktree.py index 10ddd96a..e1b76911 100644 --- a/aiida_worktree/worktree.py +++ b/aiida_worktree/worktree.py @@ -23,6 +23,10 @@ def __init__(self, name="WorkTree", **kwargs): **kwargs: Additional keyword arguments to be passed to the NodeTree class. """ super().__init__(name, **kwargs) + self.ctx = {} + self.starts = [] + self.is_while = False + self.conditions = [] def run(self): """ @@ -58,6 +62,10 @@ def to_dict(self): ntdata = super().to_dict() for node in self.nodes: ntdata["nodes"][node.name]["to_ctx"] = getattr(node, "to_ctx", []) + ntdata["ctx"] = self.ctx + ntdata["starts"] = self.starts + ntdata["is_while"] = self.is_while + ntdata["conditions"] = self.conditions return ntdata def wait(self, timeout=50): diff --git a/docs/source/howto/for_gather.ipynb b/docs/source/howto/for_gather.ipynb index 2eb9da29..03535996 100644 --- a/docs/source/howto/for_gather.ipynb +++ b/docs/source/howto/for_gather.ipynb @@ -5,7 +5,7 @@ "id": "22d177dc-6cfb-4de2-9509-f1eb45e10cf2", "metadata": {}, "source": [ - "# How to run node in parallel" + "# How to use `for` to run node in parallel" ] }, { @@ -98,12 +98,13 @@ "@node.group()\n", "def multiply_for(uuids, y):\n", " from aiida.orm import load_node\n", - " nt = WorkTree(\"multiply_for\")\n", + " wt = WorkTree(\"multiply_for\")\n", " # here the node `multiply` is created and will run in parallel\n", " for uuid in uuids:\n", " x = load_node(uuid)\n", - " nt.nodes.new(multiply, x=x, y=y)\n", - " return nt" + " wt.nodes.new(multiply, x=x, y=y)\n", + " # don't forget to return the wt\n", + " return wt" ] }, { @@ -124,7 +125,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "[INFO] 2023-07-26 14:39:21 nodetree: Create NodeTree: parallel_node\n" + "[INFO] 2023-07-29 14:25:06 nodetree: Create NodeTree: parallel_node\n" ] } ], @@ -135,12 +136,12 @@ "X = List([1, 2, 3])\n", "y = Int(2)\n", "z = Int(3)\n", - "nt = WorkTree(\"parallel_node\")\n", - "add1 = nt.nodes.new(add, name=\"add1\", X=X, y=y)\n", - "multiply_for1 = nt.nodes.new(multiply_for, name=\"multiply_for1\", y=z)\n", - "nt.links.new(add1.outputs[0], multiply_for1.inputs[\"uuids\"])\n", + "wt = WorkTree(\"parallel_node\")\n", + "add1 = wt.nodes.new(add, name=\"add1\", X=X, y=y)\n", + "multiply_for1 = wt.nodes.new(multiply_for, name=\"multiply_for1\", y=z)\n", + "wt.links.new(add1.outputs[0], multiply_for1.inputs[\"uuids\"])\n", "\n", - "nt.submit(wait=True)" + "wt.submit(wait=True)" ] }, { @@ -153,7 +154,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 4, "id": "9ebf35aa", "metadata": {}, "outputs": [ @@ -162,13 +163,13 @@ "output_type": "stream", "text": [ "State of WorkTree: FINISHED\n", - "Result of add : ['fbf86539-f17f-4e6b-a933-95522f407f21', '5f723bf8-0676-4a4e-b54c-f3245691aac3', '6b2443ba-f1f5-4023-ba6c-97b46766b85a']\n" + "Result of add : ['8210ca86-0993-449a-af8f-12b0033c2689', 'b8aa7e98-c1ac-4100-b158-d5fbfc738a5e', '9350e27f-ce74-4a58-9b8d-7a10108e8de7']\n" ] } ], "source": [ - "print(\"State of WorkTree: {}\".format(nt.state))\n", - "print('Result of add : {}'.format(nt.nodes[\"add1\"].node.outputs.result.get_list()))" + "print(\"State of WorkTree: {}\".format(wt.state))\n", + "print('Result of add : {}'.format(wt.nodes[\"add1\"].node.outputs.result.get_list()))" ] }, { @@ -181,25 +182,25 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 5, "id": "0060e380", "metadata": {}, "outputs": [ { "data": { - "image/svg+xml": "\n\n\n\n\n\n%3\n\n\n\nN1116\n\nWorkTree: parallel_node (1116)\nState: excepted\n\n\n\nN1117\n\nadd (1117)\nState: finished\nExit Code: 0\n\n\n\nN1116->N1117\n\n\nCALL_CALC\nadd1\n\n\n\nN1122\n\nWorkTree: multiply_for1 (1122)\nState: finished\nExit Code: 0\n\n\n\nN1116->N1122\n\n\nCALL_WORK\nmultiply_for1\n\n\n\nN1113\n\nList (1113)\n\n\n\nN1113->N1116\n\n\nINPUT_WORK\nnt__nodes__add1__properties__X__value\n\n\n\nN1114\n\nInt (1114)\nvalue: 2\n\n\n\nN1114->N1116\n\n\nINPUT_WORK\nnt__nodes__add1__properties__y__value\n\n\n\nN1115\n\nInt (1115)\nvalue: 3\n\n\n\nN1115->N1116\n\n\nINPUT_WORK\nnt__nodes__multiply_for1__properties__y__value\n\n\n\nN1121\n\nList (1121)\n\n\n\nN1117->N1121\n\n\nCREATE\nresult\n\n\n\nN1123\n\nmultiply (1123)\nState: finished\nExit Code: 0\n\n\n\nN1122->N1123\n\n\nCALL_CALC\nmultiply1\n\n\n\nN1125\n\nmultiply (1125)\nState: finished\nExit Code: 0\n\n\n\nN1122->N1125\n\n\nCALL_CALC\nmultiply2\n\n\n\nN1127\n\nmultiply (1127)\nState: finished\nExit Code: 0\n\n\n\nN1122->N1127\n\n\nCALL_CALC\nmultiply3\n\n\n\nN1124\n\nInt (1124)\nvalue: 9\n\n\n\nN1123->N1124\n\n\nCREATE\nresult\n\n\n\nN1126\n\nInt (1126)\nvalue: 12\n\n\n\nN1125->N1126\n\n\nCREATE\nresult\n\n\n\nN1128\n\nInt (1128)\nvalue: 15\n\n\n\nN1127->N1128\n\n\nCREATE\nresult\n\n\n\n", + "image/svg+xml": "\n\n\n\n\n\n%3\n\n\n\nN2698\n\nWorkTree: parallel_node (2698)\nState: finished\nExit Code: 0\n\n\n\nN2699\n\nadd (2699)\nState: finished\nExit Code: 0\n\n\n\nN2698->N2699\n\n\nCALL_CALC\nadd1\n\n\n\nN2704\n\nWorkTree: multiply_for1 (2704)\nState: finished\nExit Code: 0\n\n\n\nN2698->N2704\n\n\nCALL_WORK\nmultiply_for1\n\n\n\nN2695\n\nList (2695)\n\n\n\nN2695->N2698\n\n\nINPUT_WORK\nnt__nodes__add1__properties__X__value\n\n\n\nN2696\n\nInt (2696)\nvalue: 2\n\n\n\nN2696->N2698\n\n\nINPUT_WORK\nnt__nodes__add1__properties__y__value\n\n\n\nN2697\n\nInt (2697)\nvalue: 3\n\n\n\nN2697->N2698\n\n\nINPUT_WORK\nnt__nodes__multiply_for1__properties__y__value\n\n\n\nN2703\n\nList (2703)\n\n\n\nN2699->N2703\n\n\nCREATE\nresult\n\n\n\nN2705\n\nmultiply (2705)\nState: finished\nExit Code: 0\n\n\n\nN2704->N2705\n\n\nCALL_CALC\nmultiply1\n\n\n\nN2707\n\nmultiply (2707)\nState: finished\nExit Code: 0\n\n\n\nN2704->N2707\n\n\nCALL_CALC\nmultiply2\n\n\n\nN2709\n\nmultiply (2709)\nState: finished\nExit Code: 0\n\n\n\nN2704->N2709\n\n\nCALL_CALC\nmultiply3\n\n\n\nN2706\n\nInt (2706)\nvalue: 9\n\n\n\nN2705->N2706\n\n\nCREATE\nresult\n\n\n\nN2708\n\nInt (2708)\nvalue: 12\n\n\n\nN2707->N2708\n\n\nCREATE\nresult\n\n\n\nN2710\n\nInt (2710)\nvalue: 15\n\n\n\nN2709->N2710\n\n\nCREATE\nresult\n\n\n\n", "text/plain": [ - "" + "" ] }, - "execution_count": 8, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from aiida_worktree.utils import generate_node_graph\n", - "generate_node_graph(nt.pk)" + "generate_node_graph(wt.pk)" ] }, { @@ -214,7 +215,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 6, "id": "051b2ffc", "metadata": {}, "outputs": [], @@ -250,7 +251,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 7, "id": "d05167e6", "metadata": {}, "outputs": [ @@ -258,7 +259,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "[INFO] 2023-07-26 14:46:24 nodetree: Create NodeTree: parallel_node\n" + "[INFO] 2023-07-29 14:25:17 nodetree: Create NodeTree: parallel_node\n" ] } ], @@ -269,14 +270,14 @@ "X = List([1, 2, 3])\n", "y = Int(2)\n", "z = Int(3)\n", - "nt = WorkTree(\"parallel_node\")\n", - "add1 = nt.nodes.new(add, name=\"add1\", X=X, y=y)\n", - "multiply_for_gather1 = nt.nodes.new(multiply_for_gather, name=\"multiply_for_gather1\", y=z)\n", - "sum1 = nt.nodes.new(sum, name=\"sum1\")\n", - "nt.links.new(add1.outputs[0], multiply_for_gather1.inputs[\"uuids\"])\n", - "nt.links.new(multiply_for_gather1.outputs[0], sum1.inputs[0])\n", + "wt = WorkTree(\"parallel_node\")\n", + "add1 = wt.nodes.new(add, name=\"add1\", X=X, y=y)\n", + "multiply_for_gather1 = wt.nodes.new(multiply_for_gather, name=\"multiply_for_gather1\", y=z)\n", + "sum1 = wt.nodes.new(sum, name=\"sum1\")\n", + "wt.links.new(add1.outputs[0], multiply_for_gather1.inputs[\"uuids\"])\n", + "wt.links.new(multiply_for_gather1.outputs[0], sum1.inputs[0])\n", "\n", - "nt.submit(wait=True)" + "wt.submit(wait=True)" ] }, { @@ -289,7 +290,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 8, "id": "fbbb4f10", "metadata": {}, "outputs": [ @@ -303,31 +304,31 @@ } ], "source": [ - "print(\"State of WorkTree: {}\".format(nt.state))\n", - "print('Result of node add1: {}'.format(nt.nodes[\"sum1\"].node.outputs.result.value))" + "print(\"State of WorkTree: {}\".format(wt.state))\n", + "print('Result of node add1: {}'.format(wt.nodes[\"sum1\"].node.outputs.result.value))" ] }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 9, "id": "dce628d4", "metadata": {}, "outputs": [ { "data": { - "image/svg+xml": "\n\n\n\n\n\n%3\n\n\n\nN1166\n\nWorkTree: parallel_node (1166)\nState: finished\nExit Code: 0\n\n\n\nN1167\n\nadd (1167)\nState: finished\nExit Code: 0\n\n\n\nN1166->N1167\n\n\nCALL_CALC\nadd1\n\n\n\nN1172\n\nWorkTree: multiply_for_gather1 (1172)\nState: finished\nExit Code: 0\n\n\n\nN1166->N1172\n\n\nCALL_WORK\nmultiply_for_gather1\n\n\n\nN1181\n\nsum (1181)\nState: finished\nExit Code: 0\n\n\n\nN1166->N1181\n\n\nCALL_CALC\nsum1\n\n\n\nN1163\n\nList (1163)\n\n\n\nN1163->N1166\n\n\nINPUT_WORK\nnt__nodes__add1__properties__X__value\n\n\n\nN1164\n\nInt (1164)\nvalue: 2\n\n\n\nN1164->N1166\n\n\nINPUT_WORK\nnt__nodes__add1__properties__y__value\n\n\n\nN1165\n\nInt (1165)\nvalue: 3\n\n\n\nN1165->N1166\n\n\nINPUT_WORK\nnt__nodes__multiply_for_gather1__properties__y__value\n\n\n\nN1171\n\nList (1171)\n\n\n\nN1167->N1171\n\n\nCREATE\nresult\n\n\n\nN1173\n\nmultiply (1173)\nState: finished\nExit Code: 0\n\n\n\nN1172->N1173\n\n\nCALL_CALC\nmultiply2\n\n\n\nN1175\n\nmultiply (1175)\nState: finished\nExit Code: 0\n\n\n\nN1172->N1175\n\n\nCALL_CALC\nmultiply3\n\n\n\nN1177\n\nmultiply (1177)\nState: finished\nExit Code: 0\n\n\n\nN1172->N1177\n\n\nCALL_CALC\nmultiply4\n\n\n\nN1179\n\nGatherWorkChain (1179)\nState: finished\nExit Code: 0\n\n\n\nN1172->N1179\n\n\nCALL_WORK\ngather1\n\n\n\nN1180\n\nList (1180)\n\n\n\nN1172->N1180\n\n\nRETURN\ngroup_outputs__result\n\n\n\nN1174\n\nInt (1174)\nvalue: 9\n\n\n\nN1173->N1174\n\n\nCREATE\nresult\n\n\n\nN1174->N1179\n\n\nINPUT_WORK\ndatas__multiply2_result\n\n\n\nN1176\n\nInt (1176)\nvalue: 12\n\n\n\nN1175->N1176\n\n\nCREATE\nresult\n\n\n\nN1176->N1179\n\n\nINPUT_WORK\ndatas__multiply3_result\n\n\n\nN1178\n\nInt (1178)\nvalue: 15\n\n\n\nN1177->N1178\n\n\nCREATE\nresult\n\n\n\nN1178->N1179\n\n\nINPUT_WORK\ndatas__multiply4_result\n\n\n\nN1179->N1180\n\n\nRETURN\nresult\n\n\n\nN1180->N1181\n\n\nINPUT_CALC\nuuids\n\n\n\nN1182\n\nFloat (1182)\nvalue: 36.0\n\n\n\nN1181->N1182\n\n\nCREATE\nresult\n\n\n\n", + "image/svg+xml": "\n\n\n\n\n\n%3\n\n\n\nN2714\n\nWorkTree: parallel_node (2714)\nState: finished\nExit Code: 0\n\n\n\nN2715\n\nadd (2715)\nState: finished\nExit Code: 0\n\n\n\nN2714->N2715\n\n\nCALL_CALC\nadd1\n\n\n\nN2720\n\nWorkTree: multiply_for_gather1 (2720)\nState: finished\nExit Code: 0\n\n\n\nN2714->N2720\n\n\nCALL_WORK\nmultiply_for_gather1\n\n\n\nN2729\n\nsum (2729)\nState: finished\nExit Code: 0\n\n\n\nN2714->N2729\n\n\nCALL_CALC\nsum1\n\n\n\nN2711\n\nList (2711)\n\n\n\nN2711->N2714\n\n\nINPUT_WORK\nnt__nodes__add1__properties__X__value\n\n\n\nN2712\n\nInt (2712)\nvalue: 2\n\n\n\nN2712->N2714\n\n\nINPUT_WORK\nnt__nodes__add1__properties__y__value\n\n\n\nN2713\n\nInt (2713)\nvalue: 3\n\n\n\nN2713->N2714\n\n\nINPUT_WORK\nnt__nodes__multiply_for_gather1__properties__y__value\n\n\n\nN2719\n\nList (2719)\n\n\n\nN2715->N2719\n\n\nCREATE\nresult\n\n\n\nN2722\n\nInt (2722)\nvalue: 9\n\n\n\nN2727\n\nGatherWorkChain (2727)\nState: finished\nExit Code: 0\n\n\n\nN2722->N2727\n\n\nINPUT_WORK\ndatas__multiply2_result\n\n\n\nN2721\n\nmultiply (2721)\nState: finished\nExit Code: 0\n\n\n\nN2721->N2722\n\n\nCREATE\nresult\n\n\n\nN2724\n\nInt (2724)\nvalue: 12\n\n\n\nN2724->N2727\n\n\nINPUT_WORK\ndatas__multiply3_result\n\n\n\nN2723\n\nmultiply (2723)\nState: finished\nExit Code: 0\n\n\n\nN2723->N2724\n\n\nCREATE\nresult\n\n\n\nN2726\n\nInt (2726)\nvalue: 15\n\n\n\nN2726->N2727\n\n\nINPUT_WORK\ndatas__multiply4_result\n\n\n\nN2725\n\nmultiply (2725)\nState: finished\nExit Code: 0\n\n\n\nN2725->N2726\n\n\nCREATE\nresult\n\n\n\nN2720->N2721\n\n\nCALL_CALC\nmultiply2\n\n\n\nN2720->N2723\n\n\nCALL_CALC\nmultiply3\n\n\n\nN2720->N2725\n\n\nCALL_CALC\nmultiply4\n\n\n\nN2720->N2727\n\n\nCALL_WORK\ngather1\n\n\n\nN2728\n\nList (2728)\n\n\n\nN2720->N2728\n\n\nRETURN\ngroup_outputs__result\n\n\n\nN2727->N2728\n\n\nRETURN\nresult\n\n\n\nN2728->N2729\n\n\nINPUT_CALC\nuuids\n\n\n\nN2730\n\nFloat (2730)\nvalue: 36.0\n\n\n\nN2729->N2730\n\n\nCREATE\nresult\n\n\n\n", "text/plain": [ - "" + "" ] }, - "execution_count": 16, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from aiida_worktree.utils import generate_node_graph\n", - "generate_node_graph(nt.pk)" + "generate_node_graph(wt.pk)" ] }, { diff --git a/docs/source/howto/if.ipynb b/docs/source/howto/if.ipynb index 1b01e10b..9a8888f7 100644 --- a/docs/source/howto/if.ipynb +++ b/docs/source/howto/if.ipynb @@ -75,7 +75,7 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 2, "id": "11e3bca1-dda6-44e9-9585-54feeda7e7db", "metadata": {}, "outputs": [], @@ -96,25 +96,21 @@ "def multiply(x, y):\n", " return x*y\n", "\n", - "# define assign node to clone the input value to the output\n", - "@node()\n", - "@calcfunction\n", - "def assign(x):\n", - " return x.clone()\n", - "\n", "# Create a WorkTree which is dynamically generated based on the input\n", - "@node.group(outputs = [[\"assign1\", \"result\", \"result\"]])\n", + "# then we output the result of from the context (ctx)\n", + "@node.group(outputs = [[\"ctx\", \"result\", \"result\"]])\n", "def add_multiply_if(x, y):\n", " from aiida.orm import load_node\n", - " nt = WorkTree(\"add_multiply_if\")\n", - " nt.nodes.new(assign, name=\"assign1\")\n", - " if x.value > 0: \n", - " nt.nodes.new(add, name=\"add1\", x=x, y=y)\n", - " nt.links.new(nt.nodes[\"add1\"].outputs[0], nt.nodes[\"assign1\"].inputs[0])\n", + " wt = WorkTree(\"add_multiply_if\")\n", + " if x.value > 0:\n", + " add1 = wt.nodes.new(add, name=\"add1\", x=x, y=y)\n", + " # export the result of add1 to the context\n", + " add1.to_ctx = [[\"result\", \"result\"]]\n", " else:\n", - " nt.nodes.new(multiply, name=\"multiply1\", x=x, y=y)\n", - " nt.links.new(nt.nodes[\"multiply1\"].outputs[0], nt.nodes[\"assign1\"].inputs[0])\n", - " return nt" + " multiply1 = wt.nodes.new(multiply, name=\"multiply1\", x=x, y=y)\n", + " # export the result of multiply1 to the context\n", + " multiply1.to_ctx = [[\"result\", \"result\"]]\n", + " return wt" ] }, { @@ -127,7 +123,7 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 3, "id": "8ee799d2-0b5b-4609-957f-6b3f2cd451f0", "metadata": {}, "outputs": [ @@ -135,7 +131,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "[INFO] 2023-07-26 16:05:36 nodetree: Create NodeTree: if_node\n" + "[INFO] 2023-07-29 14:22:58 nodetree: Create NodeTree: if_node\n" ] } ], @@ -145,10 +141,12 @@ "\n", "x = Int(-1)\n", "y = Int(2)\n", - "nt = WorkTree(\"if_node\")\n", - "add_multiply_if1 = nt.nodes.new(add_multiply_if, name=\"add_multiply_if1\", x=x, y=y)\n", + "wt = WorkTree(\"if_node\")\n", + "add_multiply_if1 = wt.nodes.new(add_multiply_if, name=\"add_multiply_if1\", x=x, y=y)\n", + "add1 = wt.nodes.new(add, name=\"add1\", x=x)\n", + "wt.links.new(add_multiply_if1.outputs[0], add1.inputs[\"y\"])\n", "\n", - "nt.submit(wait=True)" + "wt.submit(wait=True)" ] }, { @@ -161,7 +159,7 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 4, "id": "9ebf35aa", "metadata": {}, "outputs": [ @@ -169,14 +167,16 @@ "name": "stdout", "output_type": "stream", "text": [ - "State of WorkTree: FINISHED\n", - "Result of add_if1 : -2\n" + "State of WorkTree : FINISHED\n", + "Result of add_multiply_if1: -2\n", + "Result of add1 : -3\n" ] } ], "source": [ - "print(\"State of WorkTree: {}\".format(nt.state))\n", - "print('Result of add_if1 : {}'.format(nt.nodes[\"add_multiply_if1\"].node.outputs.group_outputs.result.value))" + "print(\"State of WorkTree : {}\".format(wt.state))\n", + "print('Result of add_multiply_if1: {}'.format(wt.nodes[\"add_multiply_if1\"].node.outputs.group_outputs.result.value))\n", + "print('Result of add1 : {}'.format(wt.nodes[\"add1\"].node.outputs.result.value))" ] }, { @@ -189,25 +189,25 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": 5, "id": "0060e380", "metadata": {}, "outputs": [ { "data": { - "image/svg+xml": "\n\n\n\n\n\n%3\n\n\n\nN1229\n\nWorkTree: if_node (1229)\nState: finished\nExit Code: 0\n\n\n\nN1230\n\nWorkTree: add_multiply_if1 (1230)\nState: finished\nExit Code: 0\n\n\n\nN1229->N1230\n\n\nCALL_WORK\nadd_multiply_if1\n\n\n\nN1227\n\nInt (1227)\nvalue: -1\n\n\n\nN1227->N1229\n\n\nINPUT_WORK\nnt__nodes__add_multiply_if1__properties__x__value\n\n\n\nN1228\n\nInt (1228)\nvalue: 2\n\n\n\nN1228->N1229\n\n\nINPUT_WORK\nnt__nodes__add_multiply_if1__properties__y__value\n\n\n\nN1231\n\nmultiply (1231)\nState: finished\nExit Code: 0\n\n\n\nN1230->N1231\n\n\nCALL_CALC\nmultiply1\n\n\n\nN1233\n\nassign (1233)\nState: finished\nExit Code: 0\n\n\n\nN1230->N1233\n\n\nCALL_CALC\nassign1\n\n\n\nN1234\n\nInt (1234)\nvalue: -2\n\n\n\nN1230->N1234\n\n\nRETURN\ngroup_outputs__result\n\n\n\nN1232\n\nInt (1232)\nvalue: -2\n\n\n\nN1231->N1232\n\n\nCREATE\nresult\n\n\n\nN1232->N1233\n\n\nINPUT_CALC\nx\n\n\n\nN1233->N1234\n\n\nCREATE\nresult\n\n\n\n", + "image/svg+xml": "\n\n\n\n\n\n%3\n\n\n\nN2681\n\nWorkTree: if_node (2681)\nState: finished\nExit Code: 0\n\n\n\nN2682\n\nWorkTree: add_multiply_if1 (2682)\nState: finished\nExit Code: 0\n\n\n\nN2681->N2682\n\n\nCALL_WORK\nadd_multiply_if1\n\n\n\nN2685\n\nadd (2685)\nState: finished\nExit Code: 0\n\n\n\nN2681->N2685\n\n\nCALL_CALC\nadd1\n\n\n\nN2679\n\nInt (2679)\nvalue: -1\n\n\n\nN2679->N2681\n\n\nINPUT_WORK\nnt__nodes__add1__properties__x__value\n\n\n\nN2679->N2681\n\n\nINPUT_WORK\nnt__nodes__add_multiply_if1__properties__x__value\n\n\n\nN2680\n\nInt (2680)\nvalue: 2\n\n\n\nN2680->N2681\n\n\nINPUT_WORK\nnt__nodes__add_multiply_if1__properties__y__value\n\n\n\nN2683\n\nmultiply (2683)\nState: finished\nExit Code: 0\n\n\n\nN2682->N2683\n\n\nCALL_CALC\nmultiply1\n\n\n\nN2684\n\nInt (2684)\nvalue: -2\n\n\n\nN2682->N2684\n\n\nRETURN\ngroup_outputs__result\n\n\n\nN2683->N2684\n\n\nCREATE\nresult\n\n\n\nN2684->N2685\n\n\nINPUT_CALC\ny\n\n\n\nN2686\n\nInt (2686)\nvalue: -3\n\n\n\nN2685->N2686\n\n\nCREATE\nresult\n\n\n\n", "text/plain": [ - "" + "" ] }, - "execution_count": 37, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from aiida_worktree.utils import generate_node_graph\n", - "generate_node_graph(nt.pk)" + "generate_node_graph(wt.pk)" ] }, { @@ -220,7 +220,7 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": 6, "id": "140461b7", "metadata": {}, "outputs": [ @@ -228,17 +228,17 @@ "name": "stderr", "output_type": "stream", "text": [ - "[INFO] 2023-07-26 16:16:30 nodetree: Create NodeTree: if_node\n" + "[INFO] 2023-07-29 14:23:08 nodetree: Create NodeTree: if_node\n" ] }, { "data": { - "image/svg+xml": "\n\n\n\n\n\n%3\n\n\n\nN1237\n\nWorkTree: if_node (1237)\nState: finished\nExit Code: 0\n\n\n\nN1238\n\nWorkTree: add_multiply_if1 (1238)\nState: finished\nExit Code: 0\n\n\n\nN1237->N1238\n\n\nCALL_WORK\nadd_multiply_if1\n\n\n\nN1235\n\nInt (1235)\nvalue: 1\n\n\n\nN1235->N1237\n\n\nINPUT_WORK\nnt__nodes__add_multiply_if1__properties__x__value\n\n\n\nN1236\n\nInt (1236)\nvalue: 2\n\n\n\nN1236->N1237\n\n\nINPUT_WORK\nnt__nodes__add_multiply_if1__properties__y__value\n\n\n\nN1239\n\nadd (1239)\nState: finished\nExit Code: 0\n\n\n\nN1238->N1239\n\n\nCALL_CALC\nadd1\n\n\n\nN1241\n\nassign (1241)\nState: finished\nExit Code: 0\n\n\n\nN1238->N1241\n\n\nCALL_CALC\nassign1\n\n\n\nN1242\n\nInt (1242)\nvalue: 3\n\n\n\nN1238->N1242\n\n\nRETURN\ngroup_outputs__result\n\n\n\nN1240\n\nInt (1240)\nvalue: 3\n\n\n\nN1239->N1240\n\n\nCREATE\nresult\n\n\n\nN1240->N1241\n\n\nINPUT_CALC\nx\n\n\n\nN1241->N1242\n\n\nCREATE\nresult\n\n\n\n", + "image/svg+xml": "\n\n\n\n\n\n%3\n\n\n\nN2689\n\nWorkTree: if_node (2689)\nState: finished\nExit Code: 0\n\n\n\nN2690\n\nWorkTree: add_multiply_if1 (2690)\nState: finished\nExit Code: 0\n\n\n\nN2689->N2690\n\n\nCALL_WORK\nadd_multiply_if1\n\n\n\nN2693\n\nadd (2693)\nState: finished\nExit Code: 0\n\n\n\nN2689->N2693\n\n\nCALL_CALC\nadd1\n\n\n\nN2687\n\nInt (2687)\nvalue: 1\n\n\n\nN2687->N2689\n\n\nINPUT_WORK\nnt__nodes__add1__properties__x__value\n\n\n\nN2687->N2689\n\n\nINPUT_WORK\nnt__nodes__add_multiply_if1__properties__x__value\n\n\n\nN2688\n\nInt (2688)\nvalue: 2\n\n\n\nN2688->N2689\n\n\nINPUT_WORK\nnt__nodes__add_multiply_if1__properties__y__value\n\n\n\nN2691\n\nadd (2691)\nState: finished\nExit Code: 0\n\n\n\nN2690->N2691\n\n\nCALL_CALC\nadd1\n\n\n\nN2692\n\nInt (2692)\nvalue: 3\n\n\n\nN2690->N2692\n\n\nRETURN\ngroup_outputs__result\n\n\n\nN2691->N2692\n\n\nCREATE\nresult\n\n\n\nN2692->N2693\n\n\nINPUT_CALC\ny\n\n\n\nN2694\n\nInt (2694)\nvalue: 4\n\n\n\nN2693->N2694\n\n\nCREATE\nresult\n\n\n\n", "text/plain": [ - "" + "" ] }, - "execution_count": 38, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -246,11 +246,13 @@ "source": [ "x = Int(1)\n", "y = Int(2)\n", - "nt = WorkTree(\"if_node\")\n", - "add_multiply_if1 = nt.nodes.new(add_multiply_if, name=\"add_multiply_if1\", x=x, y=y)\n", + "wt = WorkTree(\"if_node\")\n", + "add_multiply_if1 = wt.nodes.new(add_multiply_if, name=\"add_multiply_if1\", x=x, y=y)\n", + "add1 = wt.nodes.new(add, name=\"add1\", x=x)\n", + "wt.links.new(add_multiply_if1.outputs[0], add1.inputs[\"y\"])\n", "\n", - "nt.submit(wait=True)\n", - "generate_node_graph(nt.pk)\n" + "wt.submit(wait=True)\n", + "generate_node_graph(wt.pk)\n" ] } ], diff --git a/docs/source/howto/index.rst b/docs/source/howto/index.rst index d734d33c..03dd54bd 100644 --- a/docs/source/howto/index.rst +++ b/docs/source/howto/index.rst @@ -10,3 +10,4 @@ This section contains a collection of HowTos for various topics. if for_gather + while diff --git a/docs/source/howto/while.ipynb b/docs/source/howto/while.ipynb new file mode 100644 index 00000000..8c62eb4e --- /dev/null +++ b/docs/source/howto/while.ipynb @@ -0,0 +1,254 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "22d177dc-6cfb-4de2-9509-f1eb45e10cf2", + "metadata": {}, + "source": [ + "# How to use `while` loop" + ] + }, + { + "cell_type": "markdown", + "id": "58696c91", + "metadata": {}, + "source": [ + "## Introduction\n", + "With the while loop we can execute a set of nodes as long as the condition is true. In this tutorial, you will learn how to use `while` loop in WorkTree.\n", + "\n", + "Load the AiiDA profile." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "c6b83fb5", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The aiida extension is already loaded. To reload it, use:\n", + " %reload_ext aiida\n" + ] + }, + { + "data": { + "text/plain": [ + "Profile" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%load_ext aiida\n", + "from aiida import load_profile\n", + "load_profile()" + ] + }, + { + "cell_type": "markdown", + "id": "30719f9a", + "metadata": {}, + "source": [ + "## First workflow: while\n", + "Suppose we want to calculate:\n", + "```python\n", + "# start while block\n", + "n=1\n", + "while n < 100:\n", + " n = n*2\n", + " n = n + 3\n", + "# end while block\n", + "z = n+1\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "0f46d277", + "metadata": {}, + "source": [ + "### Create node\n", + "We first create the nodes to do the calculation." + ] + }, + { + "cell_type": "markdown", + "id": "9e6360d8", + "metadata": {}, + "source": [] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "11e3bca1-dda6-44e9-9585-54feeda7e7db", + "metadata": {}, + "outputs": [], + "source": [ + "from aiida_worktree import node, WorkTree\n", + "from aiida.engine import calcfunction\n", + "from aiida.orm import Int, Bool\n", + "\n", + "# we need a compare node for `n<100`\n", + "@node()\n", + "@calcfunction\n", + "def compare(x, y):\n", + " return Bool(x < y)\n", + "\n", + "# define multiply node for n*2\n", + "@node()\n", + "@calcfunction\n", + "def multiply(x, y):\n", + " return x*y\n", + "\n", + "# define add node for n+3\n", + "@node()\n", + "@calcfunction\n", + "def add(x, y):\n", + " return x + y\n", + "\n", + "# Create a WorkTree will repeat itself based on the conditions\n", + "# then we output the result of from the context (ctx)\n", + "@node.group(outputs = [[\"ctx\", \"n\", \"result\"]])\n", + "@node.group()\n", + "def add_multiply_while(n, limit):\n", + " wt = WorkTree(\"add_multiply_while\")\n", + " # tell the engine that this is a `while` worktree\n", + " wt.is_while = True\n", + " # the `result` of compares1 node is used as condition\n", + " wt.conditions = [[\"compare1\", \"result\"]]\n", + " # set a context variable before running.\n", + " wt.ctx = {\"n\": n}\n", + " compare1 = wt.nodes.new(compare, name=\"compare1\", x=\"{{n}}\", y=Int(limit))\n", + " multiply1 = wt.nodes.new(multiply, name=\"multiply1\", x=\"{{ n }}\", y=Int(2))\n", + " add1 = wt.nodes.new(add, name=\"add1\", y=3)\n", + " # update the context variable\n", + " add1.to_ctx = [[\"result\", \"n\"]]\n", + " wt.links.new(multiply1.outputs[0], add1.inputs[0])\n", + " # don't forget to return the worktree\n", + " return wt" + ] + }, + { + "cell_type": "markdown", + "id": "65f4c44d", + "metadata": {}, + "source": [ + "### Create the workflow\n", + "We will use a special `AiiDAWhile` node in the workflow." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "8ee799d2-0b5b-4609-957f-6b3f2cd451f0", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[INFO] 2023-07-29 14:17:37 nodetree: Create NodeTree: test_while\n" + ] + } + ], + "source": [ + "wt = WorkTree(\"test_while\")\n", + "while1 = wt.nodes.new(add_multiply_while, n=Int(1), limit=50)\n", + "add1 = wt.nodes.new(add, y=Int(1))\n", + "wt.links.new(while1.outputs[0], add1.inputs[0])\n", + "wt.submit(wait=True)" + ] + }, + { + "cell_type": "markdown", + "id": "d25beb02-ee82-4a27-ae48-edc5c147904c", + "metadata": {}, + "source": [ + "### Check status and results\n" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "9ebf35aa", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "State of WorkTree: FINISHED\n", + "Result of add1 : 62\n" + ] + } + ], + "source": [ + "print(\"State of WorkTree: {}\".format(wt.state))\n", + "print('Result of add1 : {}'.format(add1.node.outputs.result.value))" + ] + }, + { + "cell_type": "markdown", + "id": "125ac629", + "metadata": {}, + "source": [ + "Generate node graph from the AiiDA process,and we can see that when `compare1` node outputs `False`, the worktree stops." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "0060e380", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": "\n\n\n\n\n\n%3\n\n\n\nN2643\n\nWorkTree: test_while (2643)\nState: finished\nExit Code: 0\n\n\n\nN2646\n\nWorkTree: add_multiply_while1 (2646)\nState: finished\nExit Code: 0\n\n\n\nN2643->N2646\n\n\nCALL_WORK\nadd_multiply_while1\n\n\n\nN2677\n\nadd (2677)\nState: finished\nExit Code: 0\n\n\n\nN2643->N2677\n\n\nCALL_CALC\nadd2\n\n\n\nN2641\n\nInt (2641)\nvalue: 1\n\n\n\nN2641->N2643\n\n\nINPUT_WORK\nnt__nodes__add_multiply_while1__properties__n__value\n\n\n\nN2642\n\nInt (2642)\nvalue: 1\n\n\n\nN2642->N2643\n\n\nINPUT_WORK\nnt__nodes__add2__properties__y__value\n\n\n\nN2648\n\nBool (2648)\nTrue\n\n\n\nN2647\n\ncompare (2647)\nState: finished\nExit Code: 0\n\n\n\nN2647->N2648\n\n\nCREATE\nresult\n\n\n\nN2650\n\nInt (2650)\nvalue: 2\n\n\n\nN2652\n\nadd (2652)\nState: finished\nExit Code: 0\n\n\n\nN2650->N2652\n\n\nINPUT_CALC\nx\n\n\n\nN2649\n\nmultiply (2649)\nState: finished\nExit Code: 0\n\n\n\nN2649->N2650\n\n\nCREATE\nresult\n\n\n\nN2653\n\nInt (2653)\nvalue: 5\n\n\n\nN2654\n\ncompare (2654)\nState: finished\nExit Code: 0\n\n\n\nN2653->N2654\n\n\nINPUT_CALC\nx\n\n\n\nN2656\n\nmultiply (2656)\nState: finished\nExit Code: 0\n\n\n\nN2653->N2656\n\n\nINPUT_CALC\nx\n\n\n\nN2652->N2653\n\n\nCREATE\nresult\n\n\n\nN2655\n\nBool (2655)\nTrue\n\n\n\nN2654->N2655\n\n\nCREATE\nresult\n\n\n\nN2657\n\nInt (2657)\nvalue: 10\n\n\n\nN2659\n\nadd (2659)\nState: finished\nExit Code: 0\n\n\n\nN2657->N2659\n\n\nINPUT_CALC\nx\n\n\n\nN2656->N2657\n\n\nCREATE\nresult\n\n\n\nN2660\n\nInt (2660)\nvalue: 13\n\n\n\nN2661\n\ncompare (2661)\nState: finished\nExit Code: 0\n\n\n\nN2660->N2661\n\n\nINPUT_CALC\nx\n\n\n\nN2663\n\nmultiply (2663)\nState: finished\nExit Code: 0\n\n\n\nN2660->N2663\n\n\nINPUT_CALC\nx\n\n\n\nN2659->N2660\n\n\nCREATE\nresult\n\n\n\nN2662\n\nBool (2662)\nTrue\n\n\n\nN2661->N2662\n\n\nCREATE\nresult\n\n\n\nN2646->N2647\n\n\nCALL_CALC\ncompare1\n\n\n\nN2646->N2649\n\n\nCALL_CALC\nmultiply1\n\n\n\nN2646->N2652\n\n\nCALL_CALC\nadd1\n\n\n\nN2646->N2654\n\n\nCALL_CALC\ncompare1\n\n\n\nN2646->N2656\n\n\nCALL_CALC\nmultiply1\n\n\n\nN2646->N2659\n\n\nCALL_CALC\nadd1\n\n\n\nN2646->N2661\n\n\nCALL_CALC\ncompare1\n\n\n\nN2646->N2663\n\n\nCALL_CALC\nmultiply1\n\n\n\nN2666\n\nadd (2666)\nState: finished\nExit Code: 0\n\n\n\nN2646->N2666\n\n\nCALL_CALC\nadd1\n\n\n\nN2668\n\ncompare (2668)\nState: finished\nExit Code: 0\n\n\n\nN2646->N2668\n\n\nCALL_CALC\ncompare1\n\n\n\nN2670\n\nmultiply (2670)\nState: finished\nExit Code: 0\n\n\n\nN2646->N2670\n\n\nCALL_CALC\nmultiply1\n\n\n\nN2674\n\nInt (2674)\nvalue: 61\n\n\n\nN2646->N2674\n\n\nRETURN\ngroup_outputs__result\n\n\n\nN2673\n\nadd (2673)\nState: finished\nExit Code: 0\n\n\n\nN2646->N2673\n\n\nCALL_CALC\nadd1\n\n\n\nN2675\n\ncompare (2675)\nState: finished\nExit Code: 0\n\n\n\nN2646->N2675\n\n\nCALL_CALC\ncompare1\n\n\n\nN2664\n\nInt (2664)\nvalue: 26\n\n\n\nN2664->N2666\n\n\nINPUT_CALC\nx\n\n\n\nN2663->N2664\n\n\nCREATE\nresult\n\n\n\nN2667\n\nInt (2667)\nvalue: 29\n\n\n\nN2667->N2668\n\n\nINPUT_CALC\nx\n\n\n\nN2667->N2670\n\n\nINPUT_CALC\nx\n\n\n\nN2666->N2667\n\n\nCREATE\nresult\n\n\n\nN2669\n\nBool (2669)\nTrue\n\n\n\nN2668->N2669\n\n\nCREATE\nresult\n\n\n\nN2671\n\nInt (2671)\nvalue: 58\n\n\n\nN2671->N2673\n\n\nINPUT_CALC\nx\n\n\n\nN2670->N2671\n\n\nCREATE\nresult\n\n\n\nN2674->N2675\n\n\nINPUT_CALC\nx\n\n\n\nN2674->N2677\n\n\nINPUT_CALC\nx\n\n\n\nN2673->N2674\n\n\nCREATE\nresult\n\n\n\nN2676\n\nBool (2676)\nFalse\n\n\n\nN2675->N2676\n\n\nCREATE\nresult\n\n\n\nN2678\n\nInt (2678)\nvalue: 62\n\n\n\nN2677->N2678\n\n\nCREATE\nresult\n\n\n\n", + "text/plain": [ + "" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from aiida_worktree.utils import generate_node_graph\n", + "generate_node_graph(wt.pk)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.10.4 ('scinode')", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.4" + }, + "vscode": { + "interpreter": { + "hash": "2f450c1ff08798c4974437dd057310afef0de414c25d1fd960ad375311c3f6ff" + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/source/index.rst b/docs/source/index.rst index 5d1b1ce2..744b9e2d 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -26,10 +26,10 @@ Here is a detailed comparison between the ``WorkTree`` with two AiiDA built-in w +--------------------------+------------------------+------------------------+------------------------+ | Ready to Use | Yes | ``No``,Need PYTHONPATH | Yes | +--------------------------+------------------------+------------------------+------------------------+ -| Flow Control | All | `if`, `while` | `if` | -+--------------------------+------------------------+------------------------+------------------------+ | Subprocesses Handling | ``No`` | Launches & waits | Launches & waits | +--------------------------+------------------------+------------------------+------------------------+ +| Flow Control | All | `if`, `while` | `if`, `while` | ++--------------------------+------------------------+------------------------+------------------------+ | Termination | ``Hard exit`` | ExitCode | ExitCode | +--------------------------+------------------------+------------------------+------------------------+ | Capabilities | Calls calcs and works | Calls any process | Calls any process | diff --git a/docs/source/node.rst b/docs/source/node.rst index 0ddc163f..eae41f38 100644 --- a/docs/source/node.rst +++ b/docs/source/node.rst @@ -25,7 +25,7 @@ Then, one can use the node by using its identifier. .. code:: python - nt.nodes.new(add.identifier) + wt.nodes.new(add.identifier) Register -------- @@ -37,7 +37,7 @@ Register a already existing `calcfunction`, `workfunction`, `calcjob`, `Workcha ndata = {"path": "aiida.calculations.arithmetic.add.ArithmeticAddCalculation"} add = register_node(ndata) # use the node - nt.nodes.new(add.identifier) + wt.nodes.new(add.identifier) Define a Node @@ -73,4 +73,4 @@ Then, one can use the node by using its identifier. .. code:: python - nt.nodes.new("MyAdd") + wt.nodes.new("MyAdd") diff --git a/docs/source/quick_start.ipynb b/docs/source/quick_start.ipynb index a9b5b8cf..1c5bd9f6 100644 --- a/docs/source/quick_start.ipynb +++ b/docs/source/quick_start.ipynb @@ -37,7 +37,7 @@ { "data": { "text/plain": [ - "Profile" + "Profile" ] }, "execution_count": 1, @@ -121,7 +121,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "[INFO] 2023-07-21 15:27:17 nodetree: Create NodeTree: first_workflow\n" + "[INFO] 2023-07-29 14:25:57 nodetree: Create NodeTree: first_workflow\n" ] } ], @@ -132,12 +132,12 @@ "y = Int(3.0)\n", "z = Int(4.0)\n", "\n", - "nt = WorkTree(\"first_workflow\")\n", - "nt.nodes.new(add, name=\"add\", x=x, y=y)\n", - "nt.nodes.new(multiply, name=\"multiply\", y=z)\n", - "nt.links.new(nt.nodes[\"add\"].outputs[0], nt.nodes[\"multiply\"].inputs[\"x\"])\n", + "wt = WorkTree(\"first_workflow\")\n", + "wt.nodes.new(add, name=\"add\", x=x, y=y)\n", + "wt.nodes.new(multiply, name=\"multiply\", y=z)\n", + "wt.links.new(wt.nodes[\"add\"].outputs[0], wt.nodes[\"multiply\"].inputs[\"x\"])\n", "\n", - "nt.submit(wait=True)" + "wt.submit(wait=True)" ] }, { @@ -165,9 +165,9 @@ } ], "source": [ - "print(\"State of WorkTree: {}\".format(nt.state))\n", - "print('Result of add : {}'.format(nt.nodes[\"add\"].node.outputs.result.value))\n", - "print('Result of multiply : {}'.format(nt.nodes[\"multiply\"].node.outputs.result.value))" + "print(\"State of WorkTree: {}\".format(wt.state))\n", + "print('Result of add : {}'.format(wt.nodes[\"add\"].node.outputs.result.value))\n", + "print('Result of multiply : {}'.format(wt.nodes[\"multiply\"].node.outputs.result.value))" ] }, { @@ -186,9 +186,9 @@ "outputs": [ { "data": { - "image/svg+xml": "\n\n\n\n\n\n%3\n\n\n\nN11146\n\nWorkTree: first_workflow (11146)\nState: finished\nExit Code: 0\n\n\n\nN11147\n\nadd (11147)\nState: finished\nExit Code: 0\n\n\n\nN11146->N11147\n\n\nCALL_CALC\nadd\n\n\n\nN11149\n\nmultiply (11149)\nState: finished\nExit Code: 0\n\n\n\nN11146->N11149\n\n\nCALL_CALC\nmultiply\n\n\n\nN11143\n\nInt (11143)\nvalue: 2\n\n\n\nN11143->N11146\n\n\nINPUT_WORK\nnt__nodes__add__properties__x__value\n\n\n\nN11144\n\nInt (11144)\nvalue: 3\n\n\n\nN11144->N11146\n\n\nINPUT_WORK\nnt__nodes__add__properties__y__value\n\n\n\nN11145\n\nInt (11145)\nvalue: 4\n\n\n\nN11145->N11146\n\n\nINPUT_WORK\nnt__nodes__multiply__properties__y__value\n\n\n\nN11148\n\nInt (11148)\nvalue: 5\n\n\n\nN11147->N11148\n\n\nCREATE\nresult\n\n\n\nN11148->N11149\n\n\nINPUT_CALC\nx\n\n\n\nN11154\n\nInt (11154)\nvalue: 20\n\n\n\nN11149->N11154\n\n\nCREATE\nresult\n\n\n\n", + "image/svg+xml": "\n\n\n\n\n\n%3\n\n\n\nN2734\n\nWorkTree: first_workflow (2734)\nState: finished\nExit Code: 0\n\n\n\nN2735\n\nadd (2735)\nState: finished\nExit Code: 0\n\n\n\nN2734->N2735\n\n\nCALL_CALC\nadd\n\n\n\nN2737\n\nmultiply (2737)\nState: finished\nExit Code: 0\n\n\n\nN2734->N2737\n\n\nCALL_CALC\nmultiply\n\n\n\nN2731\n\nInt (2731)\nvalue: 2\n\n\n\nN2731->N2734\n\n\nINPUT_WORK\nnt__nodes__add__properties__x__value\n\n\n\nN2732\n\nInt (2732)\nvalue: 3\n\n\n\nN2732->N2734\n\n\nINPUT_WORK\nnt__nodes__add__properties__y__value\n\n\n\nN2733\n\nInt (2733)\nvalue: 4\n\n\n\nN2733->N2734\n\n\nINPUT_WORK\nnt__nodes__multiply__properties__y__value\n\n\n\nN2736\n\nInt (2736)\nvalue: 5\n\n\n\nN2735->N2736\n\n\nCREATE\nresult\n\n\n\nN2736->N2737\n\n\nINPUT_CALC\nx\n\n\n\nN2738\n\nInt (2738)\nvalue: 20\n\n\n\nN2737->N2738\n\n\nCREATE\nresult\n\n\n\n", "text/plain": [ - "" + "" ] }, "execution_count": 5, @@ -198,7 +198,7 @@ ], "source": [ "from aiida_worktree.utils import generate_node_graph\n", - "generate_node_graph(nt.pk)" + "generate_node_graph(wt.pk)" ] }, { @@ -287,18 +287,18 @@ "name": "stderr", "output_type": "stream", "text": [ - "[INFO] 2023-07-21 15:27:30 nodetree: Create NodeTree: test_add_multiply\n" + "[INFO] 2023-07-29 14:26:26 nodetree: Create NodeTree: test_add_multiply\n" ] } ], "source": [ "from aiida_worktree import WorkTree\n", "\n", - "nt = WorkTree(\"test_add_multiply\")\n", - "nt.nodes.new(\"AiiDACode\", \"code1\", value=\"add@localhost\")\n", - "nt.nodes.new(add_calcjob, name=\"add1\", x=x, y=y)\n", - "nt.links.new(nt.nodes[\"code1\"].outputs[0], nt.nodes[\"add1\"].inputs[\"code\"])\n", - "nt.submit(wait=True)" + "wt = WorkTree(\"test_add_multiply\")\n", + "wt.nodes.new(\"AiiDACode\", \"code1\", value=\"add@localhost\")\n", + "wt.nodes.new(add_calcjob, name=\"add1\", x=x, y=y)\n", + "wt.links.new(wt.nodes[\"code1\"].outputs[0], wt.nodes[\"add1\"].inputs[\"code\"])\n", + "wt.submit(wait=True)" ] }, { @@ -324,7 +324,7 @@ } ], "source": [ - "print('Result of node add1: {}'.format(nt.nodes[\"add1\"].node.outputs.sum.value))" + "print('Result of node add1: {}'.format(wt.nodes[\"add1\"].node.outputs.sum.value))" ] }, { @@ -335,9 +335,9 @@ "outputs": [ { "data": { - "image/svg+xml": "\n\n\n\n\n\n%3\n\n\n\nN11155\n\nWorkTree: test_add_multiply (11155)\nState: finished\nExit Code: 0\n\n\n\nN11161\n\nArithmeticAddCalculation (11161)\nState: finished\nExit Code: 0\n\n\n\nN11155->N11161\n\n\nCALL_CALC\nadd1\n\n\n\nN11143\n\nInt (11143)\nvalue: 2\n\n\n\nN11143->N11155\n\n\nINPUT_WORK\nnt__nodes__add1__properties__x__value\n\n\n\nN11144\n\nInt (11144)\nvalue: 3\n\n\n\nN11144->N11155\n\n\nINPUT_WORK\nnt__nodes__add1__properties__y__value\n\n\n\nN11162\n\nRemoteData (11162)\n@localhost\n\n\n\nN11161->N11162\n\n\nCREATE\nremote_folder\n\n\n\nN11163\n\nFolderData (11163)\n\n\n\nN11161->N11163\n\n\nCREATE\nretrieved\n\n\n\nN11164\n\nInt (11164)\nvalue: 5\n\n\n\nN11161->N11164\n\n\nCREATE\nsum\n\n\n\n", + "image/svg+xml": "\n\n\n\n\n\n%3\n\n\n\nN2739\n\nWorkTree: test_add_multiply (2739)\nState: finished\nExit Code: 0\n\n\n\nN2740\n\nArithmeticAddCalculation (2740)\nState: finished\nExit Code: 0\n\n\n\nN2739->N2740\n\n\nCALL_CALC\nadd1\n\n\n\nN2731\n\nInt (2731)\nvalue: 2\n\n\n\nN2731->N2739\n\n\nINPUT_WORK\nnt__nodes__add1__properties__x__value\n\n\n\nN2732\n\nInt (2732)\nvalue: 3\n\n\n\nN2732->N2739\n\n\nINPUT_WORK\nnt__nodes__add1__properties__y__value\n\n\n\nN2741\n\nRemoteData (2741)\n@localhost\n\n\n\nN2740->N2741\n\n\nCREATE\nremote_folder\n\n\n\nN2742\n\nFolderData (2742)\n\n\n\nN2740->N2742\n\n\nCREATE\nretrieved\n\n\n\nN2743\n\nInt (2743)\nvalue: 5\n\n\n\nN2740->N2743\n\n\nCREATE\nsum\n\n\n\n", "text/plain": [ - "" + "" ] }, "execution_count": 10, @@ -346,7 +346,7 @@ } ], "source": [ - "generate_node_graph(nt.pk)" + "generate_node_graph(wt.pk)" ] }, { @@ -372,11 +372,12 @@ "@node.group(outputs = [[\"multiply\", \"result\", \"result\"]])\n", "def add_multiply(x, y, z):\n", " # Create a WorkTree\n", - " nt = WorkTree()\n", - " nt.nodes.new(add, name=\"add\", x=x, y=y)\n", - " nt.nodes.new(multiply, name=\"multiply\", x=z)\n", - " nt.links.new(nt.nodes[\"add\"].outputs[0], nt.nodes[\"multiply\"].inputs[\"y\"])\n", - " return nt" + " wt = WorkTree()\n", + " wt.nodes.new(add, name=\"add\", x=x, y=y)\n", + " wt.nodes.new(multiply, name=\"multiply\", x=z)\n", + " wt.links.new(wt.nodes[\"add\"].outputs[0], wt.nodes[\"multiply\"].inputs[\"y\"])\n", + " # don't forget to return the `wt`\n", + " return wt" ] }, { @@ -397,7 +398,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "[INFO] 2023-07-21 15:27:48 nodetree: Create NodeTree: test_node_group\n" + "[INFO] 2023-07-29 14:27:22 nodetree: Create NodeTree: test_node_group\n" ] }, { @@ -412,14 +413,14 @@ "\n", "from aiida_worktree import WorkTree\n", "\n", - "nt = WorkTree(\"test_node_group\")\n", + "wt = WorkTree(\"test_node_group\")\n", "# create a node using the node group\n", - "add_multiply1 = nt.nodes.new(add_multiply, x=x, y=y, z=z)\n", - "add_multiply2 = nt.nodes.new(add_multiply, x=x, y=y)\n", + "add_multiply1 = wt.nodes.new(add_multiply, x=x, y=y, z=z)\n", + "add_multiply2 = wt.nodes.new(add_multiply, x=x, y=y)\n", "# link the output of int node to the input of add node\n", - "nt.links.new(add_multiply1.outputs[0], add_multiply2.inputs[\"z\"])\n", - "nt.submit(wait=True)\n", - "print(\"Worktree staet: \", nt.state)" + "wt.links.new(add_multiply1.outputs[0], add_multiply2.inputs[\"z\"])\n", + "wt.submit(wait=True)\n", + "print(\"Worktree staet: \", wt.state)" ] }, { @@ -456,9 +457,9 @@ "outputs": [ { "data": { - "image/svg+xml": "\n\n\n\n\n\n%3\n\n\n\nN11169\n\nWorkTree: test_node_group (11169)\nState: finished\nExit Code: 0\n\n\n\nN11171\n\nWorkTree: add_multiply1 (11171)\nState: finished\nExit Code: 0\n\n\n\nN11169->N11171\n\n\nCALL_WORK\nadd_multiply1\n\n\n\nN11181\n\nWorkTree: add_multiply2 (11181)\nState: finished\nExit Code: 0\n\n\n\nN11169->N11181\n\n\nCALL_WORK\nadd_multiply2\n\n\n\nN11143\n\nInt (11143)\nvalue: 2\n\n\n\nN11143->N11169\n\n\nINPUT_WORK\nnt__nodes__add_multiply2__properties__x__value\n\n\n\nN11143->N11169\n\n\nINPUT_WORK\nnt__nodes__add_multiply1__properties__x__value\n\n\n\nN11144\n\nInt (11144)\nvalue: 3\n\n\n\nN11144->N11169\n\n\nINPUT_WORK\nnt__nodes__add_multiply2__properties__y__value\n\n\n\nN11144->N11169\n\n\nINPUT_WORK\nnt__nodes__add_multiply1__properties__y__value\n\n\n\nN11145\n\nInt (11145)\nvalue: 4\n\n\n\nN11145->N11169\n\n\nINPUT_WORK\nnt__nodes__add_multiply1__properties__z__value\n\n\n\nN11173\n\nadd (11173)\nState: finished\nExit Code: 0\n\n\n\nN11171->N11173\n\n\nCALL_CALC\nadd\n\n\n\nN11177\n\nmultiply (11177)\nState: finished\nExit Code: 0\n\n\n\nN11171->N11177\n\n\nCALL_CALC\nmultiply\n\n\n\nN11178\n\nInt (11178)\nvalue: 20\n\n\n\nN11171->N11178\n\n\nRETURN\ngroup_outputs__result\n\n\n\nN11174\n\nInt (11174)\nvalue: 5\n\n\n\nN11173->N11174\n\n\nCREATE\nresult\n\n\n\nN11174->N11177\n\n\nINPUT_CALC\ny\n\n\n\nN11177->N11178\n\n\nCREATE\nresult\n\n\n\nN11178->N11181\n\n\nINPUT_WORK\nnt__nodes__multiply__properties__x__value\n\n\n\nN11187\n\nmultiply (11187)\nState: finished\nExit Code: 0\n\n\n\nN11178->N11187\n\n\nINPUT_CALC\nx\n\n\n\nN11183\n\nadd (11183)\nState: finished\nExit Code: 0\n\n\n\nN11181->N11183\n\n\nCALL_CALC\nadd\n\n\n\nN11181->N11187\n\n\nCALL_CALC\nmultiply\n\n\n\nN11188\n\nInt (11188)\nvalue: 100\n\n\n\nN11181->N11188\n\n\nRETURN\ngroup_outputs__result\n\n\n\nN11184\n\nInt (11184)\nvalue: 5\n\n\n\nN11183->N11184\n\n\nCREATE\nresult\n\n\n\nN11184->N11187\n\n\nINPUT_CALC\ny\n\n\n\nN11187->N11188\n\n\nCREATE\nresult\n\n\n\n", + "image/svg+xml": "\n\n\n\n\n\n%3\n\n\n\nN2744\n\nWorkTree: test_node_group (2744)\nState: finished\nExit Code: 0\n\n\n\nN2745\n\nWorkTree: add_multiply1 (2745)\nState: finished\nExit Code: 0\n\n\n\nN2744->N2745\n\n\nCALL_WORK\nadd_multiply1\n\n\n\nN2750\n\nWorkTree: add_multiply2 (2750)\nState: finished\nExit Code: 0\n\n\n\nN2744->N2750\n\n\nCALL_WORK\nadd_multiply2\n\n\n\nN2731\n\nInt (2731)\nvalue: 2\n\n\n\nN2731->N2744\n\n\nINPUT_WORK\nnt__nodes__add_multiply1__properties__x__value\n\n\n\nN2731->N2744\n\n\nINPUT_WORK\nnt__nodes__add_multiply2__properties__x__value\n\n\n\nN2732\n\nInt (2732)\nvalue: 3\n\n\n\nN2732->N2744\n\n\nINPUT_WORK\nnt__nodes__add_multiply2__properties__y__value\n\n\n\nN2732->N2744\n\n\nINPUT_WORK\nnt__nodes__add_multiply1__properties__y__value\n\n\n\nN2733\n\nInt (2733)\nvalue: 4\n\n\n\nN2733->N2744\n\n\nINPUT_WORK\nnt__nodes__add_multiply1__properties__z__value\n\n\n\nN2747\n\nInt (2747)\nvalue: 5\n\n\n\nN2748\n\nmultiply (2748)\nState: finished\nExit Code: 0\n\n\n\nN2747->N2748\n\n\nINPUT_CALC\ny\n\n\n\nN2746\n\nadd (2746)\nState: finished\nExit Code: 0\n\n\n\nN2746->N2747\n\n\nCREATE\nresult\n\n\n\nN2749\n\nInt (2749)\nvalue: 20\n\n\n\nN2753\n\nmultiply (2753)\nState: finished\nExit Code: 0\n\n\n\nN2749->N2753\n\n\nINPUT_CALC\nx\n\n\n\nN2749->N2750\n\n\nINPUT_WORK\nnt__nodes__multiply__properties__x__value\n\n\n\nN2748->N2749\n\n\nCREATE\nresult\n\n\n\nN2745->N2746\n\n\nCALL_CALC\nadd\n\n\n\nN2745->N2749\n\n\nRETURN\ngroup_outputs__result\n\n\n\nN2745->N2748\n\n\nCALL_CALC\nmultiply\n\n\n\nN2752\n\nInt (2752)\nvalue: 5\n\n\n\nN2752->N2753\n\n\nINPUT_CALC\ny\n\n\n\nN2751\n\nadd (2751)\nState: finished\nExit Code: 0\n\n\n\nN2751->N2752\n\n\nCREATE\nresult\n\n\n\nN2754\n\nInt (2754)\nvalue: 100\n\n\n\nN2753->N2754\n\n\nCREATE\nresult\n\n\n\nN2750->N2751\n\n\nCALL_CALC\nadd\n\n\n\nN2750->N2754\n\n\nRETURN\ngroup_outputs__result\n\n\n\nN2750->N2753\n\n\nCALL_CALC\nmultiply\n\n\n\n", "text/plain": [ - "" + "" ] }, "execution_count": 14, @@ -467,16 +468,8 @@ } ], "source": [ - "generate_node_graph(nt.pk)" + "generate_node_graph(wt.pk)" ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9ae26224", - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { diff --git a/docs/source/tutorial/qe.ipynb b/docs/source/tutorial/qe.ipynb index d57c43f3..043f0f30 100644 --- a/docs/source/tutorial/qe.ipynb +++ b/docs/source/tutorial/qe.ipynb @@ -47,7 +47,7 @@ { "data": { "text/plain": [ - "Profile" + "Profile" ] }, "execution_count": 1, @@ -223,24 +223,24 @@ "name": "stderr", "output_type": "stream", "text": [ - "[INFO] 2023-07-21 15:34:03 nodetree: Create NodeTree: energy_n2\n" + "[INFO] 2023-07-29 14:28:44 nodetree: Create NodeTree: energy_n2\n" ] } ], "source": [ - "nt = WorkTree(\"energy_n2\")\n", + "wt = WorkTree(\"energy_n2\")\n", "# structure node\n", - "structure1 = nt.nodes.new(\"AiiDANode\", \"n2\", value=structure_n2)\n", + "structure1 = wt.nodes.new(\"AiiDANode\", \"n2\", value=structure_n2)\n", "# pw node\n", - "pw1 = nt.nodes.new(pw_node, name=\"pw1\")\n", + "pw1 = wt.nodes.new(pw_node, name=\"pw1\")\n", "pw1.set({\"code\": code,\n", " \"parameters\": paras,\n", " \"kpoints\": kpoints,\n", " \"pseudos\": pseudos,\n", " \"metadata\": metadata\n", " })\n", - "nt.links.new(structure1.outputs[0], pw1.inputs[\"structure\"])\n", - "nt.submit(wait=True, timeout=200)" + "wt.links.new(structure1.outputs[0], pw1.inputs[\"structure\"])\n", + "wt.submit(wait=True, timeout=200)" ] }, { @@ -292,9 +292,9 @@ "outputs": [ { "data": { - "image/svg+xml": "\n\n\n\n\n\n%3\n\n\n\nN11214\n\nWorkTree: energy_n2 (11214)\nState: finished\nExit Code: 0\n\n\n\nN11219\n\nPwCalculation (11219)\nState: finished\nExit Code: 0\n\n\n\nN11214->N11219\n\n\nCALL_CALC\npw1\n\n\n\nN7592\n\nInstalledCode (7592)\nQuantum ESPRESSO pw.x\n\n\n\nN7592->N11214\n\n\nINPUT_WORK\nnt__nodes__pw1__properties__code__value\n\n\n\nN7610\n\nUpfData (7610)\n\n\n\nN7610->N11214\n\n\nINPUT_WORK\nnt__nodes__pw1__properties__pseudos__value__N\n\n\n\nN11211\n\nStructureData (11211)\nN2\n\n\n\nN11211->N11214\n\n\nINPUT_WORK\nnt__nodes__n2__properties__value__value\n\n\n\nN11212\n\nDict (11212)\n\n\n\nN11212->N11214\n\n\nINPUT_WORK\nnt__nodes__pw1__properties__parameters__value\n\n\n\nN11213\n\nKpointsData (11213)\nKpoints mesh: 1x1x1 (+0.0,0.0,0.0)\n\n\n\nN11213->N11214\n\n\nINPUT_WORK\nnt__nodes__pw1__properties__kpoints__value\n\n\n\nN11220\n\nRemoteData (11220)\n@localhost\n\n\n\nN11219->N11220\n\n\nCREATE\nremote_folder\n\n\n\nN11223\n\nFolderData (11223)\n\n\n\nN11219->N11223\n\n\nCREATE\nretrieved\n\n\n\nN11225\n\nBandsData (11225)\n(Path of 1 kpts)\n\n\n\nN11219->N11225\n\n\nCREATE\noutput_band\n\n\n\nN11226\n\nTrajectoryData (11226)\n\n\n\nN11219->N11226\n\n\nCREATE\noutput_trajectory\n\n\n\nN11227\n\nDict (11227)\n\n\n\nN11219->N11227\n\n\nCREATE\noutput_parameters\n\n\n\n", + "image/svg+xml": "\n\n\n\n\n\n%3\n\n\n\nN2758\n\nWorkTree: energy_n2 (2758)\nState: finished\nExit Code: 0\n\n\n\nN2759\n\nPwCalculation (2759)\nState: finished\nExit Code: 0\n\n\n\nN2758->N2759\n\n\nCALL_CALC\npw1\n\n\n\nN29\n\nUpfData (29)\n\n\n\nN29->N2758\n\n\nINPUT_WORK\nnt__nodes__pw1__properties__pseudos__value__N\n\n\n\nN158\n\nInstalledCode (158)\nQuantum ESPRESSO pw.x\n\n\n\nN158->N2758\n\n\nINPUT_WORK\nnt__nodes__pw1__properties__code__value\n\n\n\nN2755\n\nStructureData (2755)\nN2\n\n\n\nN2755->N2758\n\n\nINPUT_WORK\nnt__nodes__n2__properties__value__value\n\n\n\nN2756\n\nDict (2756)\n\n\n\nN2756->N2758\n\n\nINPUT_WORK\nnt__nodes__pw1__properties__parameters__value\n\n\n\nN2757\n\nKpointsData (2757)\nKpoints mesh: 1x1x1 (+0.0,0.0,0.0)\n\n\n\nN2757->N2758\n\n\nINPUT_WORK\nnt__nodes__pw1__properties__kpoints__value\n\n\n\nN2760\n\nRemoteData (2760)\n@localhost\n\n\n\nN2761\n\nFolderData (2761)\n\n\n\nN2762\n\nBandsData (2762)\n(Path of 1 kpts)\n\n\n\nN2763\n\nTrajectoryData (2763)\n\n\n\nN2764\n\nDict (2764)\n\n\n\nN2759->N2760\n\n\nCREATE\nremote_folder\n\n\n\nN2759->N2761\n\n\nCREATE\nretrieved\n\n\n\nN2759->N2762\n\n\nCREATE\noutput_band\n\n\n\nN2759->N2763\n\n\nCREATE\noutput_trajectory\n\n\n\nN2759->N2764\n\n\nCREATE\noutput_parameters\n\n\n\n", "text/plain": [ - "" + "" ] }, "execution_count": 7, @@ -304,7 +304,7 @@ ], "source": [ "from aiida_worktree.utils import generate_node_graph\n", - "generate_node_graph(nt.pk)" + "generate_node_graph(wt.pk)" ] }, { @@ -383,7 +383,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "[INFO] 2023-07-21 15:35:04 nodetree: Create NodeTree: atomization_energy\n" + "[INFO] 2023-07-29 14:29:20 nodetree: Create NodeTree: atomization_energy\n" ] } ], @@ -391,26 +391,26 @@ "from aiida_worktree import WorkTree\n", "from aiida.orm import Dict, KpointsData, StructureData, load_code, load_group\n", "\n", - "nt = WorkTree(\"atomization_energy\")\n", + "wt = WorkTree(\"atomization_energy\")\n", "\n", - "nt.nodes.new(\"AiiDANode\", \"n2\", value=structure_n2)\n", - "nt.nodes.new(\"AiiDANode\", \"n\", value=structure_n)\n", + "wt.nodes.new(\"AiiDANode\", \"n2\", value=structure_n2)\n", + "wt.nodes.new(\"AiiDANode\", \"n\", value=structure_n)\n", "# create the PW node\n", - "pw_n = nt.nodes.new(pw_node, name=\"pw_n\")\n", + "pw_n = wt.nodes.new(pw_node, name=\"pw_n\")\n", "pw_n.set({\"code\": code, \"parameters\": paras, \"kpoints\": kpoints,\n", " \"pseudos\": pseudos, \"metadata\": metadata\n", " })\n", - "pw_n2 = nt.nodes.new(pw_node, name=\"pw_n2\")\n", + "pw_n2 = wt.nodes.new(pw_node, name=\"pw_n2\")\n", "pw_n2.set({\"code\": code, \"parameters\": paras, \"kpoints\": kpoints,\n", " \"pseudos\": pseudos, \"metadata\": metadata\n", " })\n", "# create the node to calculate the atomization energy\n", - "atomization = nt.nodes.new(atomization_energy, name=\"atomization_energy\")\n", - "nt.links.new(nt.nodes[\"n\"].outputs[0], pw_n.inputs[\"structure\"])\n", - "nt.links.new(nt.nodes[\"n2\"].outputs[0], pw_n2.inputs[\"structure\"])\n", - "nt.links.new(pw_n.outputs[\"output_parameters\"], atomization.inputs[\"output_atom\"])\n", - "nt.links.new(pw_n2.outputs[\"output_parameters\"], atomization.inputs[\"output_mol\"])\n", - "nt.submit(wait=True, timeout=300)\n" + "atomization = wt.nodes.new(atomization_energy, name=\"atomization_energy\")\n", + "wt.links.new(wt.nodes[\"n\"].outputs[0], pw_n.inputs[\"structure\"])\n", + "wt.links.new(wt.nodes[\"n2\"].outputs[0], pw_n2.inputs[\"structure\"])\n", + "wt.links.new(pw_n.outputs[\"output_parameters\"], atomization.inputs[\"output_atom\"])\n", + "wt.links.new(pw_n2.outputs[\"output_parameters\"], atomization.inputs[\"output_mol\"])\n", + "wt.submit(wait=True, timeout=300)\n" ] }, { @@ -428,7 +428,7 @@ } ], "source": [ - "nt.update()\n", + "wt.update()\n", "print('Atomization energy: {:0.3f} eV'.format(atomization.node.outputs.result.value))\n" ] }, @@ -448,9 +448,9 @@ "outputs": [ { "data": { - "image/svg+xml": "\n\n\n\n\n\n%3\n\n\n\nN11234\n\nWorkTree: atomization_energy (11234)\nState: finished\nExit Code: 0\n\n\n\nN11236\n\nPwCalculation (11236)\nState: finished\nExit Code: 0\n\n\n\nN11234->N11236\n\n\nCALL_CALC\npw_n\n\n\n\nN11238\n\nPwCalculation (11238)\nState: finished\nExit Code: 0\n\n\n\nN11234->N11238\n\n\nCALL_CALC\npw_n2\n\n\n\nN11259\n\natomization_energy (11259)\nState: finished\nExit Code: 0\n\n\n\nN11234->N11259\n\n\nCALL_CALC\natomization_energy\n\n\n\nN7592\n\nInstalledCode (7592)\nQuantum ESPRESSO pw.x\n\n\n\nN7592->N11234\n\n\nINPUT_WORK\nnt__nodes__pw_n__properties__code__value\n\n\n\nN7592->N11234\n\n\nINPUT_WORK\nnt__nodes__pw_n2__properties__code__value\n\n\n\nN7610\n\nUpfData (7610)\n\n\n\nN7610->N11234\n\n\nINPUT_WORK\nnt__nodes__pw_n2__properties__pseudos__value__N\n\n\n\nN7610->N11234\n\n\nINPUT_WORK\nnt__nodes__pw_n__properties__pseudos__value__N\n\n\n\nN11211\n\nStructureData (11211)\nN2\n\n\n\nN11211->N11234\n\n\nINPUT_WORK\nnt__nodes__n2__properties__value__value\n\n\n\nN11212\n\nDict (11212)\n\n\n\nN11212->N11234\n\n\nINPUT_WORK\nnt__nodes__pw_n__properties__parameters__value\n\n\n\nN11212->N11234\n\n\nINPUT_WORK\nnt__nodes__pw_n2__properties__parameters__value\n\n\n\nN11213\n\nKpointsData (11213)\nKpoints mesh: 1x1x1 (+0.0,0.0,0.0)\n\n\n\nN11213->N11234\n\n\nINPUT_WORK\nnt__nodes__pw_n2__properties__kpoints__value\n\n\n\nN11213->N11234\n\n\nINPUT_WORK\nnt__nodes__pw_n__properties__kpoints__value\n\n\n\nN11233\n\nStructureData (11233)\nN\n\n\n\nN11233->N11234\n\n\nINPUT_WORK\nnt__nodes__n__properties__value__value\n\n\n\nN11240\n\nRemoteData (11240)\n@localhost\n\n\n\nN11236->N11240\n\n\nCREATE\nremote_folder\n\n\n\nN11244\n\nFolderData (11244)\n\n\n\nN11236->N11244\n\n\nCREATE\nretrieved\n\n\n\nN11245\n\nBandsData (11245)\n(Path of 1 kpts)\n\n\n\nN11236->N11245\n\n\nCREATE\noutput_band\n\n\n\nN11246\n\nTrajectoryData (11246)\n\n\n\nN11236->N11246\n\n\nCREATE\noutput_trajectory\n\n\n\nN11247\n\nDict (11247)\n\n\n\nN11236->N11247\n\n\nCREATE\noutput_parameters\n\n\n\nN11242\n\nRemoteData (11242)\n@localhost\n\n\n\nN11238->N11242\n\n\nCREATE\nremote_folder\n\n\n\nN11251\n\nFolderData (11251)\n\n\n\nN11238->N11251\n\n\nCREATE\nretrieved\n\n\n\nN11253\n\nBandsData (11253)\n(Path of 1 kpts)\n\n\n\nN11238->N11253\n\n\nCREATE\noutput_band\n\n\n\nN11254\n\nTrajectoryData (11254)\n\n\n\nN11238->N11254\n\n\nCREATE\noutput_trajectory\n\n\n\nN11255\n\nDict (11255)\n\n\n\nN11238->N11255\n\n\nCREATE\noutput_parameters\n\n\n\nN11247->N11259\n\n\nINPUT_CALC\noutput_atom\n\n\n\nN11255->N11259\n\n\nINPUT_CALC\noutput_mol\n\n\n\nN11261\n\nFloat (11261)\nvalue: 14.45126288059\n\n\n\nN11259->N11261\n\n\nCREATE\nresult\n\n\n\n", + "image/svg+xml": "\n\n\n\n\n\n%3\n\n\n\nN2766\n\nWorkTree: atomization_energy (2766)\nState: finished\nExit Code: 0\n\n\n\nN2768\n\nPwCalculation (2768)\nState: finished\nExit Code: 0\n\n\n\nN2766->N2768\n\n\nCALL_CALC\npw_n2\n\n\n\nN2767\n\nPwCalculation (2767)\nState: finished\nExit Code: 0\n\n\n\nN2766->N2767\n\n\nCALL_CALC\npw_n\n\n\n\nN2779\n\natomization_energy (2779)\nState: finished\nExit Code: 0\n\n\n\nN2766->N2779\n\n\nCALL_CALC\natomization_energy\n\n\n\nN29\n\nUpfData (29)\n\n\n\nN29->N2766\n\n\nINPUT_WORK\nnt__nodes__pw_n2__properties__pseudos__value__N\n\n\n\nN29->N2766\n\n\nINPUT_WORK\nnt__nodes__pw_n__properties__pseudos__value__N\n\n\n\nN158\n\nInstalledCode (158)\nQuantum ESPRESSO pw.x\n\n\n\nN158->N2766\n\n\nINPUT_WORK\nnt__nodes__pw_n__properties__code__value\n\n\n\nN158->N2766\n\n\nINPUT_WORK\nnt__nodes__pw_n2__properties__code__value\n\n\n\nN2755\n\nStructureData (2755)\nN2\n\n\n\nN2755->N2766\n\n\nINPUT_WORK\nnt__nodes__n2__properties__value__value\n\n\n\nN2756\n\nDict (2756)\n\n\n\nN2756->N2766\n\n\nINPUT_WORK\nnt__nodes__pw_n__properties__parameters__value\n\n\n\nN2756->N2766\n\n\nINPUT_WORK\nnt__nodes__pw_n2__properties__parameters__value\n\n\n\nN2757\n\nKpointsData (2757)\nKpoints mesh: 1x1x1 (+0.0,0.0,0.0)\n\n\n\nN2757->N2766\n\n\nINPUT_WORK\nnt__nodes__pw_n__properties__kpoints__value\n\n\n\nN2757->N2766\n\n\nINPUT_WORK\nnt__nodes__pw_n2__properties__kpoints__value\n\n\n\nN2765\n\nStructureData (2765)\nN\n\n\n\nN2765->N2766\n\n\nINPUT_WORK\nnt__nodes__n__properties__value__value\n\n\n\nN2769\n\nRemoteData (2769)\n@localhost\n\n\n\nN2770\n\nRemoteData (2770)\n@localhost\n\n\n\nN2771\n\nFolderData (2771)\n\n\n\nN2772\n\nBandsData (2772)\n(Path of 1 kpts)\n\n\n\nN2768->N2770\n\n\nCREATE\nremote_folder\n\n\n\nN2775\n\nFolderData (2775)\n\n\n\nN2768->N2775\n\n\nCREATE\nretrieved\n\n\n\nN2776\n\nBandsData (2776)\n(Path of 1 kpts)\n\n\n\nN2768->N2776\n\n\nCREATE\noutput_band\n\n\n\nN2777\n\nTrajectoryData (2777)\n\n\n\nN2768->N2777\n\n\nCREATE\noutput_trajectory\n\n\n\nN2778\n\nDict (2778)\n\n\n\nN2768->N2778\n\n\nCREATE\noutput_parameters\n\n\n\nN2773\n\nTrajectoryData (2773)\n\n\n\nN2774\n\nDict (2774)\n\n\n\nN2774->N2779\n\n\nINPUT_CALC\noutput_atom\n\n\n\nN2767->N2769\n\n\nCREATE\nremote_folder\n\n\n\nN2767->N2771\n\n\nCREATE\nretrieved\n\n\n\nN2767->N2772\n\n\nCREATE\noutput_band\n\n\n\nN2767->N2773\n\n\nCREATE\noutput_trajectory\n\n\n\nN2767->N2774\n\n\nCREATE\noutput_parameters\n\n\n\nN2778->N2779\n\n\nINPUT_CALC\noutput_mol\n\n\n\nN2780\n\nFloat (2780)\nvalue: 14.45126288059\n\n\n\nN2779->N2780\n\n\nCREATE\nresult\n\n\n\n", "text/plain": [ - "" + "" ] }, "execution_count": 12, @@ -460,7 +460,7 @@ ], "source": [ "from aiida_worktree.utils import generate_node_graph\n", - "generate_node_graph(nt.pk)" + "generate_node_graph(wt.pk)" ] }, { @@ -532,16 +532,16 @@ "name": "stderr", "output_type": "stream", "text": [ - "[INFO] 2023-07-21 15:36:32 nodetree: Create NodeTree: test_add_multiply\n" + "[INFO] 2023-07-29 14:30:03 nodetree: Create NodeTree: test_pw_relax\n" ] } ], "source": [ - "nt = WorkTree(\"test_pw_relax\")\n", + "wt = WorkTree(\"test_pw_relax\")\n", "# structure node\n", - "nt.nodes.new(\"AiiDANode\", \"n2\", value=structure_n2)\n", + "wt.nodes.new(\"AiiDANode\", \"n2\", value=structure_n2)\n", "# pw node\n", - "pw_relax1 = nt.nodes.new(pw_relax_node, name=\"pw_relax1\")\n", + "pw_relax1 = wt.nodes.new(pw_relax_node, name=\"pw_relax1\")\n", "pw_relax1.set({\n", " \"base\": {\n", " \"pw\": {\n", @@ -553,12 +553,12 @@ " },\n", " \n", " })\n", - "paras_node = nt.nodes.new(pw_parameters, \"parameters\",\n", + "paras_node = wt.nodes.new(pw_parameters, \"parameters\",\n", " paras = paras,\n", " relax_type = \"relax\")\n", - "nt.links.new(nt.nodes[\"n2\"].outputs[0], pw_relax1.inputs[\"structure\"])\n", - "nt.links.new(paras_node.outputs[0], pw_relax1.inputs[\"base.pw.parameters\"])\n", - "nt.submit(wait=True, timeout=200)" + "wt.links.new(wt.nodes[\"n2\"].outputs[0], pw_relax1.inputs[\"structure\"])\n", + "wt.links.new(paras_node.outputs[0], pw_relax1.inputs[\"base.pw.parameters\"])\n", + "wt.submit(wait=True, timeout=200)" ] }, { @@ -576,7 +576,7 @@ } ], "source": [ - "nt.update()\n", + "wt.update()\n", "print('Energy of a relaxed N2 molecule: {:0.3f}'.format(pw_relax1.node.outputs.output_parameters.get_dict()[\"energy\"]))" ] }, @@ -596,9 +596,9 @@ "outputs": [ { "data": { - "image/svg+xml": "\n\n\n\n\n\n%3\n\n\n\nN11264\n\nWorkTree: test_add_multiply (11264)\nState: finished\nExit Code: 0\n\n\n\nN11269\n\npw_parameters (11269)\nState: finished\nExit Code: 0\n\n\n\nN11264->N11269\n\n\nCALL_CALC\nparameters\n\n\n\nN11282\n\nPwRelaxWorkChain (11282)\nState: finished\nExit Code: 0\n\n\n\nN11264->N11282\n\n\nCALL_WORK\npw_relax1\n\n\n\nN7592\n\nInstalledCode (7592)\nQuantum ESPRESSO pw.x\n\n\n\nN7592->N11264\n\n\nINPUT_WORK\nnt__nodes__pw_relax1__properties__base__value__pw__code\n\n\n\nN7610\n\nUpfData (7610)\n\n\n\nN7610->N11264\n\n\nINPUT_WORK\nnt__nodes__pw_relax1__properties__base__value__pw__pseudos__N\n\n\n\nN11211\n\nStructureData (11211)\nN2\n\n\n\nN11211->N11264\n\n\nINPUT_WORK\nnt__nodes__n2__properties__value__value\n\n\n\nN11212\n\nDict (11212)\n\n\n\nN11212->N11264\n\n\nINPUT_WORK\nnt__nodes__parameters__properties__paras__value\n\n\n\nN11213\n\nKpointsData (11213)\nKpoints mesh: 1x1x1 (+0.0,0.0,0.0)\n\n\n\nN11213->N11264\n\n\nINPUT_WORK\nnt__nodes__pw_relax1__properties__base__value__kpoints\n\n\n\nN11270\n\nDict (11270)\n\n\n\nN11269->N11270\n\n\nCREATE\nresult\n\n\n\nN11270->N11282\n\n\nINPUT_WORK\nbase__pw__parameters\n\n\n\nN11291\n\nPwBaseWorkChain (11291)\nState: finished\nExit Code: 0\n\n\n\nN11282->N11291\n\n\nCALL_WORK\niteration_01\n\n\n\nN11296\n\nRemoteData (11296)\n@localhost\n\n\n\nN11282->N11296\n\n\nRETURN\nremote_folder\n\n\n\nN11302\n\nFolderData (11302)\n\n\n\nN11282->N11302\n\n\nRETURN\nretrieved\n\n\n\nN11303\n\nBandsData (11303)\n(Path of 1 kpts)\n\n\n\nN11282->N11303\n\n\nRETURN\noutput_band\n\n\n\nN11304\n\nTrajectoryData (11304)\n\n\n\nN11282->N11304\n\n\nRETURN\noutput_trajectory\n\n\n\nN11305\n\nStructureData (11305)\nN2\n\n\n\nN11282->N11305\n\n\nRETURN\noutput_structure\n\n\n\nN11306\n\nDict (11306)\n\n\n\nN11282->N11306\n\n\nRETURN\noutput_parameters\n\n\n\nN11294\n\nPwCalculation (11294)\nState: finished\nExit Code: 0\n\n\n\nN11291->N11294\n\n\nCALL_CALC\niteration_01\n\n\n\nN11291->N11296\n\n\nRETURN\nremote_folder\n\n\n\nN11291->N11302\n\n\nRETURN\nretrieved\n\n\n\nN11291->N11303\n\n\nRETURN\noutput_band\n\n\n\nN11291->N11304\n\n\nRETURN\noutput_trajectory\n\n\n\nN11291->N11305\n\n\nRETURN\noutput_structure\n\n\n\nN11291->N11306\n\n\nRETURN\noutput_parameters\n\n\n\nN11294->N11296\n\n\nCREATE\nremote_folder\n\n\n\nN11294->N11302\n\n\nCREATE\nretrieved\n\n\n\nN11294->N11303\n\n\nCREATE\noutput_band\n\n\n\nN11294->N11304\n\n\nCREATE\noutput_trajectory\n\n\n\nN11294->N11305\n\n\nCREATE\noutput_structure\n\n\n\nN11294->N11306\n\n\nCREATE\noutput_parameters\n\n\n\n", + "image/svg+xml": "\n\n\n\n\n\n%3\n\n\n\nN2781\n\nWorkTree: test_pw_relax (2781)\nState: finished\nExit Code: 0\n\n\n\nN2783\n\npw_parameters (2783)\nState: finished\nExit Code: 0\n\n\n\nN2781->N2783\n\n\nCALL_CALC\nparameters\n\n\n\nN2790\n\nPwRelaxWorkChain (2790)\nState: finished\nExit Code: 0\n\n\n\nN2781->N2790\n\n\nCALL_WORK\npw_relax1\n\n\n\nN29\n\nUpfData (29)\n\n\n\nN29->N2781\n\n\nINPUT_WORK\nnt__nodes__pw_relax1__properties__base__value__pw__pseudos__N\n\n\n\nN158\n\nInstalledCode (158)\nQuantum ESPRESSO pw.x\n\n\n\nN158->N2781\n\n\nINPUT_WORK\nnt__nodes__pw_relax1__properties__base__value__pw__code\n\n\n\nN2755\n\nStructureData (2755)\nN2\n\n\n\nN2755->N2781\n\n\nINPUT_WORK\nnt__nodes__n2__properties__value__value\n\n\n\nN2756\n\nDict (2756)\n\n\n\nN2756->N2781\n\n\nINPUT_WORK\nnt__nodes__parameters__properties__paras__value\n\n\n\nN2757\n\nKpointsData (2757)\nKpoints mesh: 1x1x1 (+0.0,0.0,0.0)\n\n\n\nN2757->N2781\n\n\nINPUT_WORK\nnt__nodes__pw_relax1__properties__base__value__kpoints\n\n\n\nN2784\n\nDict (2784)\n\n\n\nN2784->N2790\n\n\nINPUT_WORK\nbase__pw__parameters\n\n\n\nN2783->N2784\n\n\nCREATE\nresult\n\n\n\nN2793\n\nPwBaseWorkChain (2793)\nState: finished\nExit Code: 0\n\n\n\nN2797\n\nRemoteData (2797)\n@localhost\n\n\n\nN2793->N2797\n\n\nRETURN\nremote_folder\n\n\n\nN2798\n\nFolderData (2798)\n\n\n\nN2793->N2798\n\n\nRETURN\nretrieved\n\n\n\nN2799\n\nBandsData (2799)\n(Path of 1 kpts)\n\n\n\nN2793->N2799\n\n\nRETURN\noutput_band\n\n\n\nN2800\n\nTrajectoryData (2800)\n\n\n\nN2793->N2800\n\n\nRETURN\noutput_trajectory\n\n\n\nN2801\n\nStructureData (2801)\nN2\n\n\n\nN2793->N2801\n\n\nRETURN\noutput_structure\n\n\n\nN2802\n\nDict (2802)\n\n\n\nN2793->N2802\n\n\nRETURN\noutput_parameters\n\n\n\nN2796\n\nPwCalculation (2796)\nState: finished\nExit Code: 0\n\n\n\nN2793->N2796\n\n\nCALL_CALC\niteration_01\n\n\n\nN2796->N2797\n\n\nCREATE\nremote_folder\n\n\n\nN2796->N2798\n\n\nCREATE\nretrieved\n\n\n\nN2796->N2799\n\n\nCREATE\noutput_band\n\n\n\nN2796->N2800\n\n\nCREATE\noutput_trajectory\n\n\n\nN2796->N2801\n\n\nCREATE\noutput_structure\n\n\n\nN2796->N2802\n\n\nCREATE\noutput_parameters\n\n\n\nN2790->N2793\n\n\nCALL_WORK\niteration_01\n\n\n\nN2790->N2797\n\n\nRETURN\nremote_folder\n\n\n\nN2790->N2798\n\n\nRETURN\nretrieved\n\n\n\nN2790->N2799\n\n\nRETURN\noutput_band\n\n\n\nN2790->N2800\n\n\nRETURN\noutput_trajectory\n\n\n\nN2790->N2801\n\n\nRETURN\noutput_structure\n\n\n\nN2790->N2802\n\n\nRETURN\noutput_parameters\n\n\n\n", "text/plain": [ - "" + "" ] }, "execution_count": 17, @@ -608,16 +608,8 @@ ], "source": [ "from aiida_worktree.utils import generate_node_graph\n", - "generate_node_graph(nt.pk)" + "generate_node_graph(wt.pk)" ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8465178d", - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { diff --git a/docs/source/worktree.rst b/docs/source/worktree.rst index 9e9a50bb..9121d8b9 100644 --- a/docs/source/worktree.rst +++ b/docs/source/worktree.rst @@ -15,28 +15,28 @@ Create and launch worktree .. code-block:: python from aiida_worktree import WorkTree - nt = WorkTree(name="my_first_worktree") + wt = WorkTree(name="my_first_worktree") - Add nodes by using the node identifier. .. code-block:: python - float1 = nt.nodes.new("AiiDAFloat", name = "float1") - float2 = nt.nodes.new("AiiDAFloat", name = "float2") - sumdiff1 = nt.nodes.new("AiiDASumDiff", name = "sumdiff1") + float1 = wt.nodes.new("AiiDAFloat", name = "float1") + float2 = wt.nodes.new("AiiDAFloat", name = "float2") + sumdiff1 = wt.nodes.new("AiiDASumDiff", name = "sumdiff1") - Add link between nodes: .. code-block:: python - nt.links.new(float1.outputs[0], sumdiff1.inputs[0]) - nt.links.new(float2.outputs[0], sumdiff1.inputs[1]) + wt.links.new(float1.outputs[0], sumdiff1.inputs[0]) + wt.links.new(float2.outputs[0], sumdiff1.inputs[1]) - Submit the worktree: .. code-block:: python - nt.submit() + wt.submit() Execute order diff --git a/tests/conftest.py b/tests/conftest.py index 1b8e4f30..b948effb 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,7 +1,7 @@ import pytest from aiida_worktree import node, WorkTree from aiida.engine import calcfunction, workfunction -from aiida.orm import Float, Int +from aiida.orm import Float, Int, Bool @pytest.fixture @@ -102,6 +102,19 @@ def mysqrt(x): return mysqrt +@pytest.fixture +def decorated_compare(): + """Generate a decorated node for test.""" + + # define compare node + @node() + @calcfunction + def compare(x, y): + return Bool(x < y) + + return compare + + @pytest.fixture def decorated_add_multiply(decorated_add, decorated_multiply): """Generate a decorated node for test.""" diff --git a/tests/test_ctx.py b/tests/test_ctx.py index 11607f56..903648d6 100644 --- a/tests/test_ctx.py +++ b/tests/test_ctx.py @@ -3,29 +3,27 @@ aiida.load_profile() -def test_to_ctx(decorated_add): +def test_worktree_ctx(decorated_add): """Set/get data to/from context.""" from aiida_worktree import WorkTree from aiida.orm import Float - nt = WorkTree(name="test_ctx") - add1 = nt.nodes.new(decorated_add, "add1", x=Float(2).store(), y=Float(3).store()) - add1.to_ctx = [["result", "sum"]] - add2 = nt.nodes.new(decorated_add, "add2", y="{{ sum }}") - nt.links.new(add1.outputs[0], add2.inputs["x"]) + nt = WorkTree(name="test_worktree_ctx") + nt.ctx = {"x": Float(2)} + add1 = nt.nodes.new(decorated_add, "add1", x="{{x}}", y=Float(3).store()) nt.submit(wait=True) - assert add2.node.outputs.result.value == 10 + assert add1.node.outputs.result.value == 5 -def test_ctx(decorated_add): +def test_node_to_ctx(decorated_add): """Set/get data to/from context.""" from aiida_worktree import WorkTree from aiida.orm import Float - nt = WorkTree(name="test_ctx") + nt = WorkTree(name="test_node_to_ctx") add1 = nt.nodes.new(decorated_add, "add1", x=Float(2).store(), y=Float(3).store()) - nt.nodes.new("ToCtx", "to_ctx1", key="count", value=Float(2).store()) - add2 = nt.nodes.new(decorated_add, "add2", y="{{ count }}") + add1.to_ctx = [["result", "sum"]] + add2 = nt.nodes.new(decorated_add, "add2", y="{{ sum }}") nt.links.new(add1.outputs[0], add2.inputs["x"]) nt.submit(wait=True) - assert add2.node.outputs.result.value == 7 + assert add2.node.outputs.result.value == 10 diff --git a/tests/test_while.py b/tests/test_while.py new file mode 100644 index 00000000..a8032852 --- /dev/null +++ b/tests/test_while.py @@ -0,0 +1,32 @@ +from aiida_worktree import node, WorkTree +from aiida import load_profile, orm + +load_profile() + + +def test_while(decorated_add, decorated_multiply, decorated_compare): + # Create a WorkTree will repeat itself based on the conditions + @node.group(outputs=[["ctx", "n", "result"]]) + def my_while(n, limit): + nt = WorkTree("while_worktree") + nt.is_while = True + nt.conditions = [["compare1", "result"]] + nt.ctx = {"n": n} + nt.nodes.new(decorated_compare, name="compare1", x="{{n}}", y=orm.Int(limit)) + multiply1 = nt.nodes.new( + decorated_multiply, name="multiply1", x="{{ n }}", y=orm.Int(2) + ) + add1 = nt.nodes.new(decorated_add, name="add1", y=3) + add1.to_ctx = [["result", "n"]] + nt.links.new(multiply1.outputs[0], add1.inputs[0]) + return nt + + # ----------------------------------------- + nt = WorkTree("while") + add1 = nt.nodes.new(decorated_add, x=orm.Int(25), y=orm.Int(25)) + my_while1 = nt.nodes.new(my_while, n=orm.Int(1)) + add2 = nt.nodes.new(decorated_add, y=orm.Int(2)) + nt.links.new(add1.outputs[0], my_while1.inputs["limit"]) + nt.links.new(my_while1.outputs[0], add2.inputs[0]) + nt.submit(wait=True) + assert add2.node.outputs.result.value == 63