diff --git a/README.md b/README.md index de9ec21db..5ee2c292b 100644 --- a/README.md +++ b/README.md @@ -47,40 +47,43 @@ Nodes can be used by themselves and -- other than being "delayed" in that their ``` -But the intent is to collect them together into a workflow and leverage existing nodes: +But the intent is to collect them together into a workflow and leverage existing nodes. We can directly perform (many but not quite all) python actions natively on output channels, can build up data graph topology by simply assigning values (to attributes or at instantiation), and can package things together into reusable macros with customizable IO interfaces: ```python >>> from pyiron_workflow import Workflow +>>> Workflow.register("plotting", "pyiron_workflow.node_library.plotting") >>> >>> @Workflow.wrap_as.single_value_node() -... def add_one(x): -... return x + 1 +... def Arange(n: int): +... import numpy as np +... return np.arange(n) >>> >>> @Workflow.wrap_as.macro_node() -... def add_three_macro(macro): -... macro.start = add_one() -... macro.middle = add_one(x=macro.start) -... macro.end = add_one(x=macro.middle) -... macro.inputs_map = {"start__x": "x"} -... macro.outputs_map = {"end__x + 1": "y"} ->>> ->>> Workflow.register( -... "plotting", -... "pyiron_workflow.node_library.plotting" -... ) +... def PlotShiftedSquare(macro): +... macro.shift = macro.create.standard.UserInput(0) +... macro.arange = Arange() +... macro.plot = macro.create.plotting.Scatter( +... x=macro.arange + macro.shift, +... y=macro.arange**2 +... ) +... macro.inputs_map = { +... "shift__user_input": "shift", +... "arange__n": "n", +... } +... macro.outputs_map = {"plot__fig": "fig"} >>> ->>> wf = Workflow("add_5_and_plot") ->>> wf.add_one = add_one() ->>> wf.add_three = add_three_macro(x=wf.add_one) ->>> wf.plot = wf.create.plotting.Scatter( -... x=wf.add_one, -... y=wf.add_three.outputs.y -... ) +>>> wf = Workflow("plot_with_and_without_shift") +>>> wf.n = wf.create.standard.UserInput() +>>> wf.no_shift = PlotShiftedSquare(shift=0, n=10) +>>> wf.shift = PlotShiftedSquare(shift=2, n=10) +>>> wf.inputs_map = { +... "n__user_input": "n", +... "shift__shift": "shift" +... } >>> >>> diagram = wf.draw() >>> ->>> import numpy as np ->>> fig = wf(add_one__x=np.arange(5)).plot__fig +>>> out = wf(shift=3, n=10) ``` @@ -90,7 +93,7 @@ Which gives the workflow `diagram` And the resulting `fig` -![](docs/_static/readme_shifted.png) +![](docs/_static/readme_fig.png) ## Installation diff --git a/docs/_static/readme_diagram.png b/docs/_static/readme_diagram.png index b5e242731..45e495153 100644 Binary files a/docs/_static/readme_diagram.png and b/docs/_static/readme_diagram.png differ diff --git a/docs/_static/readme_shifted.png b/docs/_static/readme_shifted.png deleted file mode 100644 index 7daa81dac..000000000 Binary files a/docs/_static/readme_shifted.png and /dev/null differ diff --git a/notebooks/atomistics_nodes.ipynb b/notebooks/atomistics_nodes.ipynb index 1ecd1c5a1..cfd988d1d 100644 --- a/notebooks/atomistics_nodes.ipynb +++ b/notebooks/atomistics_nodes.ipynb @@ -29,7 +29,8 @@ "source": [ "Workflow.register(\"calculator\", \"pyiron_workflow.node_library.atomistics.calculator\")\n", "Workflow.register(\"macro\", \"pyiron_workflow.node_library.atomistics.macro\")\n", - "Workflow.register(\"task\", \"pyiron_workflow.node_library.atomistics.task\")" + "Workflow.register(\"task\", \"pyiron_workflow.node_library.atomistics.task\")\n", + "Workflow.register(\"plotting\", \"pyiron_workflow.node_library.plotting\")" ] }, { @@ -37,24 +38,49 @@ "execution_count": 3, "id": "bc0e6187-236d-4cba-8674-de14a0520257", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "wf = Workflow(\"ev_curve\")\n", "\n", "wf.structure = wf.create.task.Bulk(\"Al\")\n", "wf.calculator = wf.create.calculator.Emt()\n", + "\n", "wf.ev = wf.create.macro.EnergyVolumeCurve(\n", " structure=wf.structure, \n", " calculator=wf.calculator,\n", ")\n", + "wf.ev_plot = wf.create.plotting.Scatter(\n", + " wf.ev.outputs.result_dict['volume'],\n", + " wf.ev.outputs.result_dict['energy']\n", + ")\n", + "\n", "wf.elastic = wf.create.macro.ElasticMatrix(\n", " structure=wf.structure, \n", " calculator=wf.calculator,\n", ")\n", + "wf.C = wf.elastic.outputs.result_dict[\"C\"]\n", + "\n", "wf.phonons = wf.create.macro.Phonons(\n", " structure=wf.structure, \n", " calculator=wf.calculator,\n", - ")" + ")\n", + "wf.dos_plot = wf.create.plotting.Scatter(\n", + " wf.phonons.outputs.result_dict[1][\"frequency_points\"],\n", + " wf.phonons.outputs.result_dict[1][\"total_dos\"],\n", + ")\n", + "\n", + "out = wf()" ] }, { @@ -62,36 +88,51 @@ "execution_count": 4, "id": "585b69dc-7140-4891-be1d-9250827f96ac", "metadata": {}, - "outputs": [], - "source": [ - "out = wf()" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "a523bcd8-c7f0-4b55-9592-5a3c37c6f34e", - "metadata": {}, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/huber/work/pyiron/pyiron_workflow/pyiron_workflow/channels.py:164: UserWarning: The channel accumulate_and_run was not connected to ran, andthus could not disconnect from it.\n", + " warn(\n", + "/Users/huber/work/pyiron/pyiron_workflow/pyiron_workflow/channels.py:164: UserWarning: The channel ran was not connected to accumulate_and_run, andthus could not disconnect from it.\n", + " warn(\n", + "/Users/huber/work/pyiron/pyiron_workflow/pyiron_workflow/channels.py:164: UserWarning: The channel run was not connected to ran, andthus could not disconnect from it.\n", + " warn(\n" + ] + }, { "data": { "text/plain": [ - "39.544084907317895" + "" ] }, - "execution_count": 5, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" } ], "source": [ - "out.ev__result_dict[\"bulkmodul_eq\"]" + "wf.ev_plot() \n", + "# We should be able to look at .value.figure\n", + "# but we need to get matplotlib to clear the previous double plot\n", + "# This is something to fix in the plotting package." ] }, { "cell_type": "code", - "execution_count": 6, - "id": "65c4cd50-85dd-405f-9d2f-a0f89cb39c7f", + "execution_count": 5, + "id": "56ec091c-c05a-4d98-8ec3-a98099a26857", "metadata": {}, "outputs": [ { @@ -111,74 +152,44 @@ " 32.8950073 ]])" ] }, - "execution_count": 6, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "out.elastic__result_dict[\"C\"]" + "wf.C" ] }, { "cell_type": "code", - "execution_count": 7, - "id": "f36b7134-fdaf-439c-a8ed-8e0d12dea6ac", + "execution_count": 6, + "id": "b738be10-20f0-4be1-abf7-b2fe8053d170", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "array([0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0.00694078, 0.00988315, 0.01328576,\n", - " 0.01714862, 0.02147171, 0.02625505, 0.02985557, 0.037727 ,\n", - " 0.0434232 , 0.04946553, 0.05566541, 0.06215958, 0.07115592,\n", - " 0.08064991, 0.09079663, 0.09922499, 0.107314 , 0.11598167,\n", - " 0.12677452, 0.13892215, 0.15277843, 0.16509068, 0.17714585,\n", - " 0.18908449, 0.20207234, 0.21663715, 0.23193372, 0.24787345,\n", - " 0.26531108, 0.28151195, 0.29720939, 0.31555894, 0.33441182,\n", - " 0.35381457, 0.37348888, 0.39467179, 0.41600753, 0.43856869,\n", - " 0.46236269, 0.48653458, 0.51129518, 0.53659094, 0.56254718,\n", - " 0.59054813, 0.62101398, 0.65275413, 0.68514049, 0.71793811,\n", - " 0.75144708, 0.78583379, 0.82253802, 0.86542963, 0.90976761,\n", - " 0.95550071, 1.00263393, 1.05112517, 1.10148731, 1.33991857,\n", - " 1.36193113, 1.34430559, 1.32697925, 1.30233052, 1.2507499 ,\n", - " 1.49092299, 1.63962028, 3.26506443, 2.06872102, 2.14988263,\n", - " 2.25562045, 2.26389212, 2.24957095, 2.23068922, 2.19906969,\n", - " 2.0990768 , 1.92248659, 2.05381061, 2.22262812, 2.26534629,\n", - " 2.39290591, 2.44805769, 2.51126138, 2.56481713, 2.44897559,\n", - " 2.39584353, 2.4114828 , 2.49193391, 2.57081989, 2.57019593,\n", - " 2.41341987, 2.25573881, 2.29896005, 2.57661295, 2.6898915 ,\n", - " 2.52674647, 2.40732058, 2.39797664, 2.6860019 , 2.77461177,\n", - " 2.74267508, 2.68147413, 2.65588543, 2.70193114, 2.76928622,\n", - " 2.6439207 , 2.65435265, 2.90982222, 2.73490294, 1.98457979,\n", - " 1.72106217, 1.58627925, 1.56213379, 1.62154002, 1.73544337,\n", - " 1.70256902, 1.65407997, 1.66713389, 1.67643965, 1.63648852,\n", - " 1.60695654, 1.56655864, 1.61633361, 1.61150893, 1.55133986,\n", - " 1.53831926, 1.50303936, 1.46605859, 1.56752315, 1.43714305,\n", - " 1.24968842, 1.45944483, 1.66145587, 1.75923322, 1.73118812,\n", - " 1.5623509 , 1.49846885, 1.41120813, 1.37756017, 1.49546786,\n", - " 1.17761685, 1.07980165, 0.98605362, 1.08530243, 1.21699949,\n", - " 1.93599882, 2.10774636, 2.30948133, 2.46933119, 2.71827848,\n", - " 2.83882417, 2.97242386, 3.17702959, 3.24129876, 3.4949328 ,\n", - " 3.60987129, 3.83610362, 2.90427366, 2.52017744, 2.24833264,\n", - " 2.03412564, 1.82270575, 1.63369566, 1.45666495, 1.27615313,\n", - " 1.07133396, 0.8484739 , 0.60012783, 0.15450282, 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. ])" + "" ] }, - "execution_count": 7, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" + }, + { + "data": { + "image/png": "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qKKigmAkCcgZSZB+/fppwoQJqqmpCTpeU1Oj6667zqZROVMgENDixYv14osvatu2bSoqKrJ7SI41bdo0vf3226qrq+t8TJw4UX/zN3+juro6ApE4mjx5co8S9XfeeUeXXXaZTSNytk8++UR9+gRfErOysijtTRJmRhKovLxct912myZOnKiysjKtX79ex44d04IFC+wemqMsWrRIzz33nF5++WXl5eV1zka53W7179/f5tE5S15eXo9cnIEDB2rIkCHk6MTZvffeq+uuu04///nP9Vd/9Vfau3ev1q9fr/Xr19s9NEeaO3eufvazn+nSSy9VSUmJDh48qH/+53/W97//fbuHlhkCSKhf/OIXgcsuuyzQr1+/wPjx4wM7duywe0iOIynk45lnnrF7aBnhxhtvDCxZssTuYTjS5s2bA6WlpYGcnJzAVVddFVi/fr3dQ3Isv98fWLJkSeDSSy8N5ObmBi6//PLAj370o0Bra6vdQ8sI9BkBAAC2ImcEAADYimAEAADYimAEAADYimAEAADYimAEAADYimAEAADYimAEAADYimAEAADYimAEAADYimAEAADYimAEAADYimAEAADY6v8BEKVk8pHuah4AAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" } ], "source": [ - "out.phonons__result_dict[1][\"total_dos\"]" + "wf.dos_plot()" ] } ], diff --git a/notebooks/deepdive.ipynb b/notebooks/deepdive.ipynb index 1c4d22eea..781dd5369 100644 --- a/notebooks/deepdive.ipynb +++ b/notebooks/deepdive.ipynb @@ -524,8 +524,6 @@ "name": "stderr", "output_type": "stream", "text": [ - "/Users/huber/work/pyiron/pyiron_workflow/pyiron_workflow/channels.py:164: UserWarning: The channel ran was not connected to run, andthus could not disconnect from it.\n", - " warn(\n", "/Users/huber/work/pyiron/pyiron_workflow/pyiron_workflow/channels.py:164: UserWarning: The channel run was not connected to ran, andthus could not disconnect from it.\n", " warn(\n" ] @@ -636,6 +634,210 @@ "This let's us set up nodes which only start running after _all_ of their up-data-stream nodes have fired their `ran` signal. This is the default behaviour when `Composite` `Workflow` or `Macro` nodes automate their execution flow for DAG data graphs. We'll look at it again near the end of the notebook when we talk about remote execution." ] }, + { + "cell_type": "markdown", + "id": "6d464066-4271-41be-a34f-20c78d75867c", + "metadata": {}, + "source": [ + "# Output manipulation\n", + "\n", + "Most (but not all) python operations can be performed _directly on output channels_. This works by injecting new nodes after the output channels to perform the requested operation.\n", + "\n", + "Let's look at how we can repeat some of the above examples much more succinctly using this feature:" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "98312fbb-0e87-417c-9780-d22903cdb3f4", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "9" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Subtract and square\n", + "\n", + "x = Linear(x=4)\n", + "y = Linear(x=1)\n", + "((x.outputs.x - y.outputs.x)**2).pull() # It's just a node so we can pull it" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "b0e8fc87-fba1-4501-882b-f162c4eadf97", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "20" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Times two\n", + "l = Linear(x=10, run_after_init=True)\n", + "(2*l.outputs.x).value # These nodes will try to run right away if everything upstream is ready" + ] + }, + { + "cell_type": "markdown", + "id": "3052c26c-3559-4d61-8c93-08708293b88c", + "metadata": {}, + "source": [ + "This also works with more sophisticated features like attribute and item access, including slicing:" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "8a195c41-233e-4076-ad77-008c93297f9c", + "metadata": {}, + "outputs": [], + "source": [ + "foo = [1, 2, 3]" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "6805b0c3-9103-49f4-bc29-569b0b4d6ed0", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "foo.reverse" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "7c4cbe66-9b0a-428b-835f-31959a7f75bb", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[1, 2]" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "a_list = Linear(x=[1,2,3,4], run_after_init=True)\n", + "a_list.outputs.x[:2].value" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "16c2d0de-de6f-4b33-84e4-aefbe5db4177", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "a_dict = Linear(x={\"a\": 1, \"b\": 2}, run_after_init=True)\n", + "a_dict.outputs.x[\"a\"].value" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "30b4ed75-bb73-44bb-b6d9-fe525b924652", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "42" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "class Foo:\n", + " bar = 42\n", + " \n", + "an_object = Linear(x=Foo(), run_after_init=True)\n", + "an_object.outputs.x.bar.value" + ] + }, + { + "cell_type": "markdown", + "id": "eab9c6b6-c954-471a-8613-792590e0464f", + "metadata": {}, + "source": [ + "Some features don't work this way, e.g. overriding the `==` operator has other deterious effects so we don't do that. Most of these operators are available as a method on output channels, based on their dunder name. E.g." + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "786b1402-b595-4337-8872-fd58687c2725", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(True, False)" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "a = Linear(x=42)\n", + "b = Linear(x=42)\n", + "c = Linear(x=0)\n", + "\n", + "a_eq_b = a.outputs.x.eq(b.outputs.x)\n", + "a_eq_c = a.outputs.x.eq(c.outputs.x)\n", + "\n", + "(a_eq_b | a_eq_c).pull(), (a_eq_b & a_eq_c).pull()" + ] + }, { "cell_type": "markdown", "id": "e5c531a3-77e4-48ad-a189-fed619e79baa", @@ -645,14 +847,14 @@ "\n", "Many functions return just a single value. In this case, we can take advantage of the `SingleValue` node class which employs a bunch of syntactic tricks to make our lives easier.\n", "\n", - "The main difference between this and it's parent the `Function` class is that attribute and item access fall back to looking for attributes and items of this single output value.\n", + "The main difference between this and it's parent the `Function` class is that attribute and item access fall back to looking for attributes and items of this single output channel. I.e. you can use a single value node in many places you'd use an output channel, including in connection formation and output manipulation\n", "\n", - "Let's look at a use case:" + "Let's look at a use case for output manipulation:" ] }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 31, "id": "1a4e9693-0980-4435-aecc-3331d8b608dd", "metadata": {}, "outputs": [], @@ -664,7 +866,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 32, "id": "7c4d314b-33bb-4a67-bfb9-ed77fba3949c", "metadata": {}, "outputs": [ @@ -689,8 +891,8 @@ "lin()\n", "\n", "print(type(lin.outputs.linspace.value)) # Output is just what we expect\n", - "print(lin[1:4]) # Gets items from the output\n", - "print(lin.mean()) # Finds the method on the output -- a special feature of SingleValueNode" + "print(lin[1:4].value) # Gets items from the output\n", + "print(lin.mean.value()) # Outputs the method on the output, which we can then call" ] }, { @@ -698,12 +900,12 @@ "id": "eef23cb0-6192-4fe6-b9cc-007e261e347a", "metadata": {}, "source": [ - "The other advantage is that single value nodes can also be connected directly to input, since there is only one possible data connection. Of course it has a construction decorator just like `Function`, so let's replace `@function_node` with `@single_value_node` in one of our examples above to see how it tightens up the syntax a bit:" + "Our examples above also become more compact:" ] }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 33, "id": "61ae572f-197b-4a60-8d3e-e19c1b9cc6e2", "metadata": {}, "outputs": [ @@ -713,7 +915,7 @@ "4" ] }, - "execution_count": 25, + "execution_count": 33, "metadata": {}, "output_type": "execute_result" } @@ -734,6 +936,35 @@ "t2.pull()" ] }, + { + "cell_type": "markdown", + "id": "01780601-f2fd-4730-acb8-95a7359d4b3c", + "metadata": {}, + "source": [ + "Or even just" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "5dd7ebc2-b45f-4759-bfc4-d4dd29afe216", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "4" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "(2*l).value" + ] + }, { "cell_type": "markdown", "id": "b2e56a64-d053-4127-bb8c-069777c1c6b5", @@ -744,7 +975,7 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 35, "id": "6569014a-815b-46dd-8b47-4e1cd4584b3b", "metadata": {}, "outputs": [ @@ -758,7 +989,7 @@ }, { "data": { - "image/png": "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HAAAMAiD/f3m2jQAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKtCCiPl5eXKyMiQ2+1WTk6OampqvrJ/V1eX1qxZo/T0dCUlJWnq1KnatGlTSAUDAIDRJcHpBtu3b9fy5ctVXl6u2bNn68knn9T8+fNVX1+v//mf/+l3mxtvvFEfffSRNm7cqPPOO0/Nzc06derUkIsHAAAjn8sYY5xsMGvWLGVnZ6uioqK3bfr06VqwYIHKysr69K+qqtJNN92ko0ePKiUlJaQi29vb5fF45Pf7lZycHNJjAACA6Brs77ej3TQnT57U/v37VVBQENReUFCgvXv39rvNyy+/rJkzZ+rBBx/UpEmTdMEFF+jee+/V559/PuDzdHV1qb29PegGAABGJ0e7aVpaWhQIBJSamhrUnpqaqqampn63OXr0qHbv3i23260dO3aopaVFd9xxh9ra2gY8bqSsrEylpaVOSgMAACNUSAewulyuoPvGmD5tPbq7u+VyubRlyxbl5ubq2muv1cMPP6xnnnlmwNmR1atXy+/3996OHTsWSpkAgDALdBu9daRVfzz4od460qpAt6M9/UC/HM2MTJgwQfHx8X1mQZqbm/vMlvTwer2aNGmSPB5Pb9v06dNljNHx48d1/vnn99kmKSlJSUlJTkoDAERYVZ1PpTvr5fN39rZ5PW6VFGZqXpbXYmUY6RzNjCQmJionJ0fV1dVB7dXV1crPz+93m9mzZ+vEiRP65JNPetsOHz6suLg4TZ48OYSSAQDRVlXn09LNB4KCiCQ1+Tu1dPMBVdX5LFWG0cDxbpoVK1boqaee0qZNm3To0CHdc889amxsVHFxsaTTu1gWL17c2//mm2/W+PHjddttt6m+vl5vvvmmVq5cqR/96EcaM2ZM+F4JACAiAt1GpTvr1d8OmZ620p317LJByByvM1JUVKTW1latW7dOPp9PWVlZqqysVHp6uiTJ5/OpsbGxt/83vvENVVdX6yc/+Ylmzpyp8ePH68Ybb9T9998fvlcBAIiYfQ1tfWZEvshI8vk7ta+hTXlTx0evMIwajtcZsYF1RgDAnj8e/FB3/+7g1/Z79KZL9H8umRT5gjBiRGSdEQBA7Jk4zh3WfsCXEUYAAF8pNyNFXo9b/S/gILl0+qya3IzQVtkGCCMAgK8UH+dSSWGmJPUJJD33SwozFR83UFwBvhphBADwteZleVWxMFtpnuBdMWketyoWZrPOCIbE8dk0AIDYNC/Lq7mZadrX0Kbmjk5NHHd61wwzIhgqwggAYNDi41ycvouwYzcNAACwipkRAABiVKDbDIvdboQRAABi0HC68CG7aQAAiDHD7cKHhBEAAGLIcLzwIWEEAIAY4uTCh9FCGAEAIIY0dwwcRELpFw6EEQAAYshwvPAhYQQAgBgyHC98SBgBACCGDMcLHxJGAACIMcPtwocsegYAQAwaThc+JIwAABCjhsuFD9lNAwAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwKKYyUl5crIyNDbrdbOTk5qqmpGdR2e/bsUUJCgi655JJQnhYAAIxCjsPI9u3btXz5cq1Zs0a1tbWaM2eO5s+fr8bGxq/czu/3a/HixbrqqqtCLhYAAIw+LmOMcbLBrFmzlJ2drYqKit626dOna8GCBSorKxtwu5tuuknnn3++4uPj9Yc//EEHDx4c9HO2t7fL4/HI7/crOTnZSbkAAMCSwf5+O5oZOXnypPbv36+CgoKg9oKCAu3du3fA7Z5++mkdOXJEJSUlg3qerq4utbe3B90AAMDo5CiMtLS0KBAIKDU1Nag9NTVVTU1N/W7z/vvva9WqVdqyZYsSEhIG9TxlZWXyeDy9tylTpjgpEwAAjCAhHcDqcrmC7htj+rRJUiAQ0M0336zS0lJdcMEFg3781atXy+/3996OHTsWSpkAAGAEGNxUxX9NmDBB8fHxfWZBmpub+8yWSFJHR4feeecd1dbW6q677pIkdXd3yxijhIQEvfbaa7ryyiv7bJeUlKSkpCQnpQEAgBHK0cxIYmKicnJyVF1dHdReXV2t/Pz8Pv2Tk5P17rvv6uDBg7234uJiTZs2TQcPHtSsWbOGVj0AABjxHM2MSNKKFSu0aNEizZw5U3l5edqwYYMaGxtVXFws6fQulg8//FDPPvus4uLilJWVFbT9xIkT5Xa7+7QDAIDY5DiMFBUVqbW1VevWrZPP51NWVpYqKyuVnp4uSfL5fF+75ggAAEAPx+uM2MA6IwAAjDwRWWcEAAAg3AgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArEqwXQAAAIMR6Dba19Cm5o5OTRznVm5GiuLjXLbLQhgQRgAAw15VnU+lO+vl83f2tnk9bpUUZmpeltdiZQgHdtMAAIa1qjqflm4+EBREJKnJ36mlmw+oqs5nqTKEC2EEADBsBbqNSnfWy/Tzt5620p31CnT31wMjBWEEADBs7Wto6zMj8kVGks/fqX0NbdErCmFHGAEADFvNHQMHkVD6YXgijAAAhq2J49xh7YfhiTACABi2cjNS5PW4NdAJvC6dPqsmNyMlmmUhzAgjAIBhKz7OpZLCTEnqE0h67pcUZrLeyAhHGAEADGvzsryqWJitNE/wrpg0j1sVC7NZZ2QUYNEzAMCwNy/Lq7mZaazAOkoRRgAAI0J8nEt5U8fbLgMRwG4aAABgFWEEAABYRRgBAABWEUYAAIBVhBEAAGAVYQQAAFhFGAEAAFYRRgAAgFWEEQAAYBVhBAAAWEUYAQAAVhFGAACAVYQRAABgFVftBYaZQLfhMukAYgphBBhGqup8Kt1ZL5+/s7fN63GrpDBT87K8FisDgMgJaTdNeXm5MjIy5Ha7lZOTo5qamgH7vvTSS5o7d67OPvtsJScnKy8vT6+++mrIBQOjVVWdT0s3HwgKIpLU5O/U0s0HVFXns1QZAESW4zCyfft2LV++XGvWrFFtba3mzJmj+fPnq7Gxsd/+b775pubOnavKykrt379f3/3ud1VYWKja2tohFw+MFoFuo9Kd9TL9/K2nrXRnvQLd/fUAgJHNZYxx9O02a9YsZWdnq6Kiordt+vTpWrBggcrKygb1GDNmzFBRUZHuu+++QfVvb2+Xx+OR3+9XcnKyk3JhAcc8OPfWkVb94Ldvf22/bf/3MuVNHR+FigBg6Ab7++3omJGTJ09q//79WrVqVVB7QUGB9u7dO6jH6O7uVkdHh1JSUpw8NUYIjnkITXNH59d3ctAPAEYSR7tpWlpaFAgElJqaGtSempqqpqamQT3GQw89pE8//VQ33njjgH26urrU3t4edMPwxzEPoZs4zh3WfgAwkoR0AKvLFTzlbozp09afbdu2ae3atdq+fbsmTpw4YL+ysjJ5PJ7e25QpU0IpE1HEMQ9Dk5uRIq/HrYE+RS6dnmHKzWBGEcDo4yiMTJgwQfHx8X1mQZqbm/vMlnzZ9u3btWTJEv3+97/X1Vdf/ZV9V69eLb/f33s7duyYkzJhwb6Gtj4zIl9kJPn8ndrX0Ba9okaQ+DiXSgozJalPIOm5X1KYybE3AEYlR2EkMTFROTk5qq6uDmqvrq5Wfn7+gNtt27ZNt956q7Zu3arrrrvua58nKSlJycnJQTcMbxzzMHTzsryqWJitNE/wrpg0j1sVC7M55gbAqOV40bMVK1Zo0aJFmjlzpvLy8rRhwwY1NjaquLhY0ulZjQ8//FDPPvuspNNBZPHixXr00Ud12WWX9c6qjBkzRh6PJ4wvBTZxzEN4zMvyam5mGmcjAYgpjsNIUVGRWltbtW7dOvl8PmVlZamyslLp6emSJJ/PF7TmyJNPPqlTp07pzjvv1J133tnbfsstt+iZZ54Z+ivAsNBzzEOTv7Pf40ZcOv0fPsc8fL34OBen7wKIKY7XGbGBdUZGhp6zaSQFBZKe/+nZ1QAAsWWwv99ctRdhwzEPAIBQcKE8hBXHPAAAnCKMIOw45gEA4AS7aQAAgFWEEQAAYBVhBAAAWEUYAQAAVhFGAACAVYQRAABgFWEEAABYRRgBAABWEUYAAIBVhBEAAGAVy8EDABwLdBuuQYWwIYz8Fx8sABicqjqfSnfWy+fv7G3zetwqKczk6twICWFEfLAAYLCq6nxauvmAzJfam/ydWrr5gCoWZvO9Ccdi/piRng/WF4OI9L8frKo6n6XKAGB4CXQble6s7xNEJPW2le6sV6C7vx7AwGI6jPDBAoDB29fQ1ucfty8yknz+Tu1raIteURgVYjqM8MECgMFr7hj4+zKUfkCPmA4jfLAAYPAmjnOHtR/QI6bDCB8sABi83IwUeT1uDXSeoUunD/7PzUiJZlkYBWI6jPDBAoDBi49zqaQwU5L6fG/23C8pzGRZBDgW02GEDxYAODMvy6uKhdlK8wTPGKd53JzWi5C5jDHD/lSR9vZ2eTwe+f1+JScnh/3xWWcEAJxhoUgMxmB/vwkj/8UHCwCA8Brs7zcrsP5XfJxLeVPH2y4DAICYE9PHjAAAAPsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrEmwXYEug22hfQ5uaOzo1cZxbuRkpio9z2S4LAICYE5NhpKrOp9Kd9fL5O3vbvB63SgozNS/La7EyAABiT8ztpqmq82np5gNBQUSSmvydWrr5gKrqfJYqAwAgNsVUGAl0G5XurJfp5289baU76xXo7q8HAACIhJgKI/sa2vrMiHyRkeTzd2pfQ1v0igIAIMaFFEbKy8uVkZEht9utnJwc1dTUfGX/Xbt2KScnR263W+eee65+85vfhFTsUDV3DBxEQukHAACGznEY2b59u5YvX641a9aotrZWc+bM0fz589XY2Nhv/4aGBl177bWaM2eOamtr9fOf/1zLli3Tiy++OOTinZo4zh3WfgAAYOhcxhhHB0jMmjVL2dnZqqio6G2bPn26FixYoLKysj79f/azn+nll1/WoUOHetuKi4v117/+VW+99dagnrO9vV0ej0d+v1/JyclOyg0S6Da6/IH/pyZ/Z7/HjbgkpXnc2v2zKznNFwCAIRrs77ejmZGTJ09q//79KigoCGovKCjQ3r17+93mrbfe6tP/mmuu0TvvvKP//Oc//W7T1dWl9vb2oFs4xMe5VFKYKel08PiinvslhZkEEQAAoshRGGlpaVEgEFBqampQe2pqqpqamvrdpqmpqd/+p06dUktLS7/blJWVyePx9N6mTJnipMyvNC/Lq4qF2UrzBO+KSfO4VbEwm3VGAACIspAWPXO5gmcOjDF92r6uf3/tPVavXq0VK1b03m9vbw97IJmbmcYKrAAADAOOwsiECRMUHx/fZxakubm5z+xHj7S0tH77JyQkaPz48f1uk5SUpKSkJCelORYf51Le1P6fHwAARI+j3TSJiYnKyclRdXV1UHt1dbXy8/P73SYvL69P/9dee00zZ87UGWec4bBcAAAw2jg+tXfFihV66qmntGnTJh06dEj33HOPGhsbVVxcLOn0LpbFixf39i8uLtYHH3ygFStW6NChQ9q0aZM2btyoe++9N3yvAgAAjFiOjxkpKipSa2ur1q1bJ5/Pp6ysLFVWVio9PV2S5PP5gtYcycjIUGVlpe655x6tX79e55xzjh577DF9//vfD9+rAAAAI5bjdUZsCNc6IwAAIHoiss4IAABAuBFGAACAVYQRAABgFWEEAABYRRgBAABWhbQcfLT1nPATrgvmAQCAyOv53f66E3dHRBjp6OiQpLBenwYAAERHR0eHPB7PgH8fEeuMdHd368SJExo3btxXXpBvtOq5UOCxY8didp0VxoAx6ME4MAY9GIfhPwbGGHV0dOicc85RXNzAR4aMiJmRuLg4TZ482XYZ1iUnJw/LN1s0MQaMQQ/GgTHowTgM7zH4qhmRHhzACgAArCKMAAAAqwgjI0BSUpJKSkqUlJRkuxRrGAPGoAfjwBj0YBxGzxiMiANYAQDA6MXMCAAAsIowAgAArCKMAAAAqwgjAADAKsLIMFBeXq6MjAy53W7l5OSopqZmwL4vvfSS5s6dq7PPPlvJycnKy8vTq6++GsVqI8fJOOzevVuzZ8/W+PHjNWbMGF144YV65JFHolhtZDgZgy/as2ePEhISdMkll0S2wChxMg5vvPGGXC5Xn9vf/va3KFYcfk7fC11dXVqzZo3S09OVlJSkqVOnatOmTVGqNnKcjMOtt97a73thxowZUaw4/Jy+F7Zs2aKLL75YZ555prxer2677Ta1trZGqdoQGVj1u9/9zpxxxhnmt7/9ramvrzd33323GTt2rPnggw/67X/33XebBx54wOzbt88cPnzYrF692pxxxhnmwIEDUa48vJyOw4EDB8zWrVtNXV2daWhoMM8995w588wzzZNPPhnlysPH6Rj0+Pjjj825555rCgoKzMUXXxydYiPI6Ti8/vrrRpL5+9//bnw+X+/t1KlTUa48fEJ5L1x//fVm1qxZprq62jQ0NJg///nPZs+ePVGsOvycjsPHH38c9B44duyYSUlJMSUlJdEtPIycjkFNTY2Ji4szjz76qDl69KipqakxM2bMMAsWLIhy5c4QRizLzc01xcXFQW0XXnihWbVq1aAfIzMz05SWloa7tKgKxzh873vfMwsXLgx3aVET6hgUFRWZX/ziF6akpGRUhBGn49ATRv79739HobrocDoGr7zyivF4PKa1tTUa5UXNUL8XduzYYVwul/nnP/8ZifKiwukY/PKXvzTnnntuUNtjjz1mJk+eHLEaw4HdNBadPHlS+/fvV0FBQVB7QUGB9u7dO6jH6O7uVkdHh1JSUiJRYlSEYxxqa2u1d+9eXXHFFZEoMeJCHYOnn35aR44cUUlJSaRLjIqhvBcuvfRSeb1eXXXVVXr99dcjWWZEhTIGL7/8smbOnKkHH3xQkyZN0gUXXKB7771Xn3/+eTRKjohwfC9s3LhRV199tdLT0yNRYsSFMgb5+fk6fvy4KisrZYzRRx99pBdeeEHXXXddNEoO2Yi4UN5o1dLSokAgoNTU1KD21NRUNTU1DeoxHnroIX366ae68cYbI1FiVAxlHCZPnqx//etfOnXqlNauXavbb789kqVGTChj8P7772vVqlWqqalRQsLo+CiHMg5er1cbNmxQTk6Ourq69Nxzz+mqq67SG2+8oe985zvRKDusQhmDo0ePavfu3XK73dqxY4daWlp0xx13qK2tbcQeNzLU70efz6dXXnlFW7dujVSJERfKGOTn52vLli0qKipSZ2enTp06peuvv16PP/54NEoO2ej4BhvhXC5X0H1jTJ+2/mzbtk1r167VH//4R02cODFS5UVNKONQU1OjTz75RG+//bZWrVql8847Tz/4wQ8iWWZEDXYMAoGAbr75ZpWWluqCCy6IVnlR4+S9MG3aNE2bNq33fl5eno4dO6Zf/epXIzKM9HAyBt3d3XK5XNqyZUvvFVIffvhh3XDDDVq/fr3GjBkT8XojJdTvx2eeeUZnnXWWFixYEKHKosfJGNTX12vZsmW67777dM0118jn82nlypUqLi7Wxo0bo1FuSAgjFk2YMEHx8fF9Em5zc3OfJPxl27dv15IlS/T888/r6quvjmSZETeUccjIyJAkffvb39ZHH32ktWvXjsgw4nQMOjo69M4776i2tlZ33XWXpNM/SMYYJSQk6LXXXtOVV14ZldrDaSjvhS+67LLLtHnz5nCXFxWhjIHX69WkSZOCLtU+ffp0GWN0/PhxnX/++RGtORKG8l4wxmjTpk1atGiREhMTI1lmRIUyBmVlZZo9e7ZWrlwpSbrooos0duxYzZkzR/fff7+8Xm/E6w4Fx4xYlJiYqJycHFVXVwe1V1dXKz8/f8Dttm3bpltvvVVbt24d9vsBByPUcfgyY4y6urrCXV5UOB2D5ORkvfvuuzp48GDvrbi4WNOmTdPBgwc1a9asaJUeVuF6L9TW1g7bL92vE8oYzJ49WydOnNAnn3zS23b48GHFxcVp8uTJEa03UobyXti1a5f+8Y9/aMmSJZEsMeJCGYPPPvtMcXHBP+3x8fGSTn9HDltWDptFr57TtjZu3Gjq6+vN8uXLzdixY3uP/l61apVZtGhRb/+tW7eahIQEs379+qBT2D7++GNbLyEsnI7DE088YV5++WVz+PBhc/jwYbNp0yaTnJxs1qxZY+slDJnTMfiy0XI2jdNxeOSRR8yOHTvM4cOHTV1dnVm1apWRZF588UVbL2HInI5BR0eHmTx5srnhhhvMe++9Z3bt2mXOP/98c/vtt9t6CWER6mdi4cKFZtasWdEuNyKcjsHTTz9tEhISTHl5uTly5IjZvXu3mTlzpsnNzbX1EgaFMDIMrF+/3qSnp5vExESTnZ1tdu3a1fu3W265xVxxxRW996+44gojqc/tlltuiX7hYeZkHB577DEzY8YMc+aZZ5rk5GRz6aWXmvLychMIBCxUHj5OxuDLRksYMcbZODzwwANm6tSpxu12m29+85vm8ssvN3/6058sVB1eTt8Lhw4dMldffbUZM2aMmTx5slmxYoX57LPPolx1+Dkdh48//tiMGTPGbNiwIcqVRo7TMXjsscdMZmamGTNmjPF6veaHP/yhOX78eJSrdsZlzHCetwEAAKMdx4wAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACs+v+L01PP7QJlgQAAAABJRU5ErkJggg==", + "image/png": "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", "text/plain": [ "
" ] @@ -813,7 +1044,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 36, "id": "1cd000bd-9b24-4c39-9cac-70a3291d0660", "metadata": {}, "outputs": [], @@ -840,7 +1071,7 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 37, "id": "7964df3c-55af-4c25-afc5-9e07accb606a", "metadata": {}, "outputs": [ @@ -866,7 +1097,7 @@ "for i, (label, node) in enumerate(wf.nodes.items()):\n", " x = i / len(wf)\n", " node(x=x)\n", - " print(f\"{label} == {node.label}) {x} > 0.5 {node.single_value}\")" + " print(f\"{label} == {node.label}) {x} > 0.5 {node.value}\")" ] }, { @@ -887,7 +1118,7 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 38, "id": "809178a5-2e6b-471d-89ef-0797db47c5ad", "metadata": {}, "outputs": [ @@ -941,7 +1172,7 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 39, "id": "52c48d19-10a2-4c48-ae81-eceea4129a60", "metadata": {}, "outputs": [ @@ -951,7 +1182,7 @@ "{'ay': 3, 'a + b + 2': 7}" ] }, - "execution_count": 30, + "execution_count": 39, "metadata": {}, "output_type": "execute_result" } @@ -979,7 +1210,7 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 40, "id": "bb35ba3e-602d-4c9c-b046-32da9401dd1c", "metadata": {}, "outputs": [ @@ -989,7 +1220,7 @@ "(7, 3)" ] }, - "execution_count": 31, + "execution_count": 40, "metadata": {}, "output_type": "execute_result" } @@ -1008,7 +1239,7 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 41, "id": "2b0d2c85-9049-417b-8739-8a8432a1efbe", "metadata": {}, "outputs": [ @@ -1350,10 +1581,10 @@ "\n" ], "text/plain": [ - "" + "" ] }, - "execution_count": 32, + "execution_count": 41, "metadata": {}, "output_type": "execute_result" } @@ -1380,14 +1611,14 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 42, "id": "ae500d5e-e55b-432c-8b5f-d5892193cdf5", "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "a4dc82761024407e909840aab64b54de", + "model_id": "f77a418c673c4579b9a3a6cbd090ef8e", "version_major": 2, "version_minor": 0 }, @@ -1406,10 +1637,10 @@ { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 33, + "execution_count": 42, "metadata": {}, "output_type": "execute_result" }, @@ -1452,7 +1683,7 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 43, "id": "2114d0c3-cdad-43c7-9ffa-50c36d56d18f", "metadata": {}, "outputs": [ @@ -1666,10 +1897,10 @@ "\n" ], "text/plain": [ - "" + "" ] }, - "execution_count": 34, + "execution_count": 43, "metadata": {}, "output_type": "execute_result" } @@ -1706,7 +1937,7 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 44, "id": "c71a8308-f8a1-4041-bea0-1c841e072a6d", "metadata": {}, "outputs": [], @@ -1716,7 +1947,7 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 45, "id": "2b9bb21a-73cd-444e-84a9-100e202aa422", "metadata": {}, "outputs": [ @@ -1734,7 +1965,7 @@ "13" ] }, - "execution_count": 36, + "execution_count": 45, "metadata": {}, "output_type": "execute_result" } @@ -1781,7 +2012,7 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": 46, "id": "3668f9a9-adca-48a4-84ea-13add965897c", "metadata": {}, "outputs": [ @@ -1791,7 +2022,7 @@ "{'intermediate': 102, 'plus_three': 103}" ] }, - "execution_count": 37, + "execution_count": 46, "metadata": {}, "output_type": "execute_result" } @@ -1829,7 +2060,7 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": 47, "id": "9aaeeec0-5f88-4c94-a6cc-45b56d2f0111", "metadata": {}, "outputs": [], @@ -1848,18 +2079,12 @@ " macro.outputs_map = {\n", " \"calc__energy_pot\": \"energy\",\n", " \"structure__structure\": \"structure\",\n", - " }\n", - "\n", - "@Workflow.wrap_as.single_value_node()\n", - "def PerAtomEnergyDifference(structure1, energy1, structure2, energy2):\n", - " # The unrelaxed structure is fine, we're just using it to get n_atoms\n", - " de = (energy2[-1]/len(structure2)) - (energy1[-1]/len(structure1))\n", - " return de" + " }" ] }, { "cell_type": "code", - "execution_count": 39, + "execution_count": 48, "id": "a832e552-b3cc-411a-a258-ef21574fc439", "metadata": {}, "outputs": [], @@ -1868,12 +2093,28 @@ "wf.element = wf.create.standard.UserInput()\n", "wf.min_phase1 = LammpsMinimize(element=wf.element)\n", "wf.min_phase2 = LammpsMinimize(element=wf.element)\n", - "wf.compare = PerAtomEnergyDifference(\n", - " wf.min_phase1.outputs.structure,\n", - " wf.min_phase1.outputs.energy,\n", - " wf.min_phase2.outputs.structure,\n", - " wf.min_phase2.outputs.energy,\n", - ")\n", + "\n", + "wf.e1 = wf.min_phase1.outputs.energy[-1]\n", + "wf.n1 = wf.min_phase1.outputs.structure.len()\n", + "wf.e2 = wf.min_phase2.outputs.energy[-1]\n", + "wf.n2 = wf.min_phase2.outputs.structure.len()\n", + "wf.compare = (wf.e2 / wf.n2) - (wf.e1 / wf.n1)\n", + "\n", + "\n", + "# Or we could write a single node to do that:\n", + "\n", + "# @Workflow.wrap_as.single_value_node()\n", + "# def PerAtomEnergyDifference(structure1, energy1, structure2, energy2):\n", + "# # The unrelaxed structure is fine, we're just using it to get n_atoms\n", + "# sub = (energy2[-1]/len(structure2)) - (energy1[-1]/len(structure1))\n", + "# return sub\n", + "\n", + "# wf.compare = PerAtomEnergyDifference(\n", + "# wf.min_phase1.outputs.structure,\n", + "# wf.min_phase1.outputs.energy,\n", + "# wf.min_phase2.outputs.structure,\n", + "# wf.min_phase2.outputs.energy,\n", + "# )\n", "\n", "wf.inputs_map = {\n", " \"element__user_input\": \"element\",\n", @@ -1886,7 +2127,7 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": 49, "id": "b764a447-236f-4cb7-952a-7cba4855087d", "metadata": {}, "outputs": [ @@ -1899,1251 +2140,1715 @@ "\n", "\n", - "\n", - "\n", + "\n", + "\n", "clusterphase_preference\n", - "\n", - "phase_preference: Workflow\n", - "\n", - "clusterphase_preferencecompare\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "compare: PerAtomEnergyDifference\n", - "\n", - "\n", - "clusterphase_preferencecompareInputs\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "Inputs\n", - "\n", - "\n", - "clusterphase_preferencecompareOutputs\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "Outputs\n", - "\n", + "\n", + "phase_preference: Workflow\n", "\n", "clusterphase_preferenceInputs\n", "\n", - "\n", + "\n", "\n", "\n", "\n", "\n", - "\n", - "Inputs\n", + "\n", + "Inputs\n", "\n", "\n", "clusterphase_preferenceOutputs\n", "\n", - "\n", + "\n", "\n", "\n", "\n", "\n", - "\n", - "Outputs\n", + "\n", + "Outputs\n", "\n", "\n", "clusterphase_preferenceelement\n", "\n", - "\n", + "\n", "\n", "\n", "\n", "\n", - "\n", - "element: UserInput\n", + "\n", + "element: UserInput\n", "\n", "\n", "clusterphase_preferenceelementInputs\n", "\n", - "\n", + "\n", "\n", "\n", "\n", "\n", - "\n", - "Inputs\n", + "\n", + "Inputs\n", "\n", "\n", "clusterphase_preferenceelementOutputs\n", "\n", - "\n", + "\n", "\n", "\n", "\n", "\n", - "\n", - "Outputs\n", + "\n", + "Outputs\n", "\n", "\n", "clusterphase_preferencemin_phase1\n", "\n", - "\n", + "\n", "\n", "\n", "\n", "\n", - "\n", - "min_phase1: LammpsMinimize\n", + "\n", + "min_phase1: LammpsMinimize\n", "\n", "\n", "clusterphase_preferencemin_phase1Inputs\n", "\n", - "\n", + "\n", "\n", "\n", "\n", "\n", - "\n", - "Inputs\n", + "\n", + "Inputs\n", "\n", "\n", "clusterphase_preferencemin_phase1Outputs\n", "\n", - "\n", + "\n", "\n", "\n", "\n", "\n", - "\n", - "Outputs\n", + "\n", + "Outputs\n", "\n", "\n", "clusterphase_preferencemin_phase2\n", "\n", - "\n", + "\n", "\n", "\n", "\n", "\n", - "\n", - "min_phase2: LammpsMinimize\n", + "\n", + "min_phase2: LammpsMinimize\n", "\n", "\n", "clusterphase_preferencemin_phase2Inputs\n", "\n", - "\n", + "\n", "\n", "\n", "\n", "\n", - "\n", - "Inputs\n", + "\n", + "Inputs\n", "\n", "\n", "clusterphase_preferencemin_phase2Outputs\n", "\n", - "\n", + "\n", "\n", "\n", "\n", "\n", - "\n", - "Outputs\n", + "\n", + "Outputs\n", "\n", - "\n", - "\n", - "clusterphase_preferenceInputsrun\n", - "\n", - "run\n", + "\n", + "clusterphase_preferencee1\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "e1: GetItem\n", + "\n", + "\n", + "clusterphase_preferencee1Inputs\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "Inputs\n", + "\n", + "\n", + "clusterphase_preferencee1Outputs\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "Outputs\n", + "\n", + "\n", + "clusterphase_preferencen1\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1: Length\n", + "\n", + "\n", + "clusterphase_preferencen1Inputs\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "Inputs\n", + "\n", + "\n", + "clusterphase_preferencen1Outputs\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "Outputs\n", + "\n", + "\n", + "clusterphase_preferencee2\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "e2: GetItem\n", + "\n", + "\n", + "clusterphase_preferencee2Inputs\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "Inputs\n", + "\n", + "\n", + "clusterphase_preferencee2Outputs\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "Outputs\n", + "\n", + "\n", + "clusterphase_preferencen2\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2: Length\n", + "\n", + "\n", + "clusterphase_preferencen2Inputs\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "Inputs\n", + "\n", + "\n", + "clusterphase_preferencen2Outputs\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "Outputs\n", + "\n", + "\n", + "clusterphase_preferencee2__getitem_Divide_n2__len\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "e2__getitem_Divide_n2__len: Divide\n", + "\n", + "\n", + "clusterphase_preferencee2__getitem_Divide_n2__lenInputs\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "Inputs\n", + "\n", + "\n", + "clusterphase_preferencee2__getitem_Divide_n2__lenOutputs\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "Outputs\n", + "\n", + "\n", + "clusterphase_preferencee1__getitem_Divide_n1__len\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "e1__getitem_Divide_n1__len: Divide\n", + "\n", + "\n", + "clusterphase_preferencee1__getitem_Divide_n1__lenInputs\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "Inputs\n", + "\n", + "\n", + "clusterphase_preferencee1__getitem_Divide_n1__lenOutputs\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "Outputs\n", + "\n", + "\n", + "clusterphase_preferencecompare\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "compare: Subtract\n", + "\n", + "\n", + "clusterphase_preferencecompareInputs\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "Inputs\n", + "\n", + "\n", + "clusterphase_preferencecompareOutputs\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "Outputs\n", + "\n", + "\n", + "\n", + "clusterphase_preferenceInputsrun\n", + "\n", + "run\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceOutputsran\n", - "\n", - "ran\n", + "\n", + "ran\n", "\n", "\n", "\n", "\n", "clusterphase_preferenceInputsaccumulate_and_run\n", - "\n", - "accumulate_and_run\n", + "\n", + "accumulate_and_run\n", "\n", "\n", "\n", "clusterphase_preferenceInputselement\n", - "\n", - "element\n", + "\n", + "element\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceelementInputsuser_input\n", - "\n", - "user_input\n", + "\n", + "user_input\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceInputselement->clusterphase_preferenceelementInputsuser_input\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", "\n", "clusterphase_preferenceInputsphase1\n", - "\n", - "phase1\n", + "\n", + "phase1\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Inputscrystalstructure\n", - "\n", - "crystalstructure\n", + "\n", + "crystalstructure\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceInputsphase1->clusterphase_preferencemin_phase1Inputscrystalstructure\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", "\n", "clusterphase_preferenceInputslattice_guess1\n", - "\n", - "lattice_guess1\n", + "\n", + "lattice_guess1\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Inputslattice_guess\n", - "\n", - "lattice_guess\n", + "\n", + "lattice_guess\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceInputslattice_guess1->clusterphase_preferencemin_phase1Inputslattice_guess\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", "\n", "clusterphase_preferenceInputsmin_phase1__structure__c\n", - "\n", - "min_phase1__structure__c\n", + "\n", + "min_phase1__structure__c\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Inputsstructure__c\n", - "\n", - "structure__c\n", + "\n", + "structure__c\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceInputsmin_phase1__structure__c->clusterphase_preferencemin_phase1Inputsstructure__c\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", "\n", "clusterphase_preferenceInputsmin_phase1__structure__covera\n", - "\n", - "min_phase1__structure__covera\n", + "\n", + "min_phase1__structure__covera\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Inputsstructure__covera\n", - "\n", - "structure__covera\n", + "\n", + "structure__covera\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceInputsmin_phase1__structure__covera->clusterphase_preferencemin_phase1Inputsstructure__covera\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", "\n", "clusterphase_preferenceInputsmin_phase1__structure__u\n", - "\n", - "min_phase1__structure__u\n", + "\n", + "min_phase1__structure__u\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Inputsstructure__u\n", - "\n", - "structure__u\n", + "\n", + "structure__u\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceInputsmin_phase1__structure__u->clusterphase_preferencemin_phase1Inputsstructure__u\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", "\n", "clusterphase_preferenceInputsmin_phase1__structure__orthorhombic\n", - "\n", - "min_phase1__structure__orthorhombic\n", + "\n", + "min_phase1__structure__orthorhombic\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Inputsstructure__orthorhombic\n", - "\n", - "structure__orthorhombic\n", + "\n", + "structure__orthorhombic\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceInputsmin_phase1__structure__orthorhombic->clusterphase_preferencemin_phase1Inputsstructure__orthorhombic\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", "\n", "clusterphase_preferenceInputsmin_phase1__structure__cubic\n", - "\n", - "min_phase1__structure__cubic\n", + "\n", + "min_phase1__structure__cubic\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Inputsstructure__cubic\n", - "\n", - "structure__cubic\n", + "\n", + "structure__cubic\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceInputsmin_phase1__structure__cubic->clusterphase_preferencemin_phase1Inputsstructure__cubic\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", "\n", "clusterphase_preferenceInputsmin_phase1__calc__n_ionic_steps\n", - "\n", - "min_phase1__calc__n_ionic_steps: int\n", + "\n", + "min_phase1__calc__n_ionic_steps: int\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Inputscalc__n_ionic_steps\n", - "\n", - "calc__n_ionic_steps: int\n", + "\n", + "calc__n_ionic_steps: int\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceInputsmin_phase1__calc__n_ionic_steps->clusterphase_preferencemin_phase1Inputscalc__n_ionic_steps\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", "\n", "clusterphase_preferenceInputsmin_phase1__calc__n_print\n", - "\n", - "min_phase1__calc__n_print: int\n", + "\n", + "min_phase1__calc__n_print: int\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Inputscalc__n_print\n", - "\n", - "calc__n_print: int\n", + "\n", + "calc__n_print: int\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceInputsmin_phase1__calc__n_print->clusterphase_preferencemin_phase1Inputscalc__n_print\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", "\n", "clusterphase_preferenceInputsmin_phase1__calc__pressure\n", - "\n", - "min_phase1__calc__pressure\n", + "\n", + "min_phase1__calc__pressure\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Inputscalc__pressure\n", - "\n", - "calc__pressure\n", + "\n", + "calc__pressure\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceInputsmin_phase1__calc__pressure->clusterphase_preferencemin_phase1Inputscalc__pressure\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", "\n", "clusterphase_preferenceInputsphase2\n", - "\n", - "phase2\n", + "\n", + "phase2\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Inputscrystalstructure\n", - "\n", - "crystalstructure\n", + "\n", + "crystalstructure\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceInputsphase2->clusterphase_preferencemin_phase2Inputscrystalstructure\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", "\n", "clusterphase_preferenceInputslattice_guess2\n", - "\n", - "lattice_guess2\n", + "\n", + "lattice_guess2\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Inputslattice_guess\n", - "\n", - "lattice_guess\n", + "\n", + "lattice_guess\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceInputslattice_guess2->clusterphase_preferencemin_phase2Inputslattice_guess\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", "\n", "clusterphase_preferenceInputsmin_phase2__structure__c\n", - "\n", - "min_phase2__structure__c\n", + "\n", + "min_phase2__structure__c\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Inputsstructure__c\n", - "\n", - "structure__c\n", + "\n", + "structure__c\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceInputsmin_phase2__structure__c->clusterphase_preferencemin_phase2Inputsstructure__c\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", "\n", "clusterphase_preferenceInputsmin_phase2__structure__covera\n", - "\n", - "min_phase2__structure__covera\n", + "\n", + "min_phase2__structure__covera\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Inputsstructure__covera\n", - "\n", - "structure__covera\n", + "\n", + "structure__covera\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceInputsmin_phase2__structure__covera->clusterphase_preferencemin_phase2Inputsstructure__covera\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", "\n", "clusterphase_preferenceInputsmin_phase2__structure__u\n", - "\n", - "min_phase2__structure__u\n", + "\n", + "min_phase2__structure__u\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Inputsstructure__u\n", - "\n", - "structure__u\n", + "\n", + "structure__u\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceInputsmin_phase2__structure__u->clusterphase_preferencemin_phase2Inputsstructure__u\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", "\n", "clusterphase_preferenceInputsmin_phase2__structure__orthorhombic\n", - "\n", - "min_phase2__structure__orthorhombic\n", + "\n", + "min_phase2__structure__orthorhombic\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Inputsstructure__orthorhombic\n", - "\n", - "structure__orthorhombic\n", + "\n", + "structure__orthorhombic\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceInputsmin_phase2__structure__orthorhombic->clusterphase_preferencemin_phase2Inputsstructure__orthorhombic\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", "\n", "clusterphase_preferenceInputsmin_phase2__structure__cubic\n", - "\n", - "min_phase2__structure__cubic\n", + "\n", + "min_phase2__structure__cubic\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Inputsstructure__cubic\n", - "\n", - "structure__cubic\n", + "\n", + "structure__cubic\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceInputsmin_phase2__structure__cubic->clusterphase_preferencemin_phase2Inputsstructure__cubic\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", "\n", "clusterphase_preferenceInputsmin_phase2__calc__n_ionic_steps\n", - "\n", - "min_phase2__calc__n_ionic_steps: int\n", + "\n", + "min_phase2__calc__n_ionic_steps: int\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Inputscalc__n_ionic_steps\n", - "\n", - "calc__n_ionic_steps: int\n", + "\n", + "calc__n_ionic_steps: int\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceInputsmin_phase2__calc__n_ionic_steps->clusterphase_preferencemin_phase2Inputscalc__n_ionic_steps\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", "\n", "clusterphase_preferenceInputsmin_phase2__calc__n_print\n", - "\n", - "min_phase2__calc__n_print: int\n", + "\n", + "min_phase2__calc__n_print: int\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Inputscalc__n_print\n", - "\n", - "calc__n_print: int\n", + "\n", + "calc__n_print: int\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceInputsmin_phase2__calc__n_print->clusterphase_preferencemin_phase2Inputscalc__n_print\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", "\n", "clusterphase_preferenceInputsmin_phase2__calc__pressure\n", - "\n", - "min_phase2__calc__pressure\n", + "\n", + "min_phase2__calc__pressure\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Inputscalc__pressure\n", - "\n", - "calc__pressure\n", + "\n", + "calc__pressure\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceInputsmin_phase2__calc__pressure->clusterphase_preferencemin_phase2Inputscalc__pressure\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", - "\n", + "\n", + "\n", + "clusterphase_preferenceInputse1__item\n", + "\n", + "e1__item\n", + "\n", + "\n", + "\n", + "clusterphase_preferencee1Inputsitem\n", + "\n", + "item\n", + "\n", + "\n", + "\n", + "clusterphase_preferenceInputse1__item->clusterphase_preferencee1Inputsitem\n", + "\n", + "\n", + "\n", + "\n", + "\n", "\n", + "clusterphase_preferenceInputse2__item\n", + "\n", + "e2__item\n", + "\n", + "\n", + "\n", + "clusterphase_preferencee2Inputsitem\n", + "\n", + "item\n", + "\n", + "\n", + "\n", + "clusterphase_preferenceInputse2__item->clusterphase_preferencee2Inputsitem\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", "clusterphase_preferenceOutputsmin_phase1__calc__cells\n", - "\n", - "min_phase1__calc__cells\n", + "\n", + "min_phase1__calc__cells\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceOutputsmin_phase1__calc__displacements\n", - "\n", - "min_phase1__calc__displacements\n", + "\n", + "min_phase1__calc__displacements\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceOutputsmin_phase1__calc__energy_tot\n", - "\n", - "min_phase1__calc__energy_tot\n", + "\n", + "min_phase1__calc__energy_tot\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceOutputsmin_phase1__calc__force_max\n", - "\n", - "min_phase1__calc__force_max\n", + "\n", + "min_phase1__calc__force_max\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceOutputsmin_phase1__calc__forces\n", - "\n", - "min_phase1__calc__forces\n", + "\n", + "min_phase1__calc__forces\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceOutputsmin_phase1__calc__indices\n", - "\n", - "min_phase1__calc__indices\n", + "\n", + "min_phase1__calc__indices\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceOutputsmin_phase1__calc__positions\n", - "\n", - "min_phase1__calc__positions\n", + "\n", + "min_phase1__calc__positions\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceOutputsmin_phase1__calc__pressures\n", - "\n", - "min_phase1__calc__pressures\n", + "\n", + "min_phase1__calc__pressures\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceOutputsmin_phase1__calc__steps\n", - "\n", - "min_phase1__calc__steps\n", + "\n", + "min_phase1__calc__steps\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceOutputsmin_phase1__calc__total_displacements\n", - "\n", - "min_phase1__calc__total_displacements\n", + "\n", + "min_phase1__calc__total_displacements\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceOutputsmin_phase1__calc__unwrapped_positions\n", - "\n", - "min_phase1__calc__unwrapped_positions\n", + "\n", + "min_phase1__calc__unwrapped_positions\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceOutputsmin_phase1__calc__volume\n", - "\n", - "min_phase1__calc__volume\n", + "\n", + "min_phase1__calc__volume\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceOutputsmin_phase2__calc__cells\n", - "\n", - "min_phase2__calc__cells\n", + "\n", + "min_phase2__calc__cells\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceOutputsmin_phase2__calc__displacements\n", - "\n", - "min_phase2__calc__displacements\n", + "\n", + "min_phase2__calc__displacements\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceOutputsmin_phase2__calc__energy_tot\n", - "\n", - "min_phase2__calc__energy_tot\n", + "\n", + "min_phase2__calc__energy_tot\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceOutputsmin_phase2__calc__force_max\n", - "\n", - "min_phase2__calc__force_max\n", + "\n", + "min_phase2__calc__force_max\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceOutputsmin_phase2__calc__forces\n", - "\n", - "min_phase2__calc__forces\n", + "\n", + "min_phase2__calc__forces\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceOutputsmin_phase2__calc__indices\n", - "\n", - "min_phase2__calc__indices\n", + "\n", + "min_phase2__calc__indices\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceOutputsmin_phase2__calc__positions\n", - "\n", - "min_phase2__calc__positions\n", + "\n", + "min_phase2__calc__positions\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceOutputsmin_phase2__calc__pressures\n", - "\n", - "min_phase2__calc__pressures\n", + "\n", + "min_phase2__calc__pressures\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceOutputsmin_phase2__calc__steps\n", - "\n", - "min_phase2__calc__steps\n", + "\n", + "min_phase2__calc__steps\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceOutputsmin_phase2__calc__total_displacements\n", - "\n", - "min_phase2__calc__total_displacements\n", + "\n", + "min_phase2__calc__total_displacements\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceOutputsmin_phase2__calc__unwrapped_positions\n", - "\n", - "min_phase2__calc__unwrapped_positions\n", + "\n", + "min_phase2__calc__unwrapped_positions\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceOutputsmin_phase2__calc__volume\n", - "\n", - "min_phase2__calc__volume\n", + "\n", + "min_phase2__calc__volume\n", "\n", - "\n", - "\n", - "clusterphase_preferenceOutputscompare__de\n", - "\n", - "compare__de\n", + "\n", + "\n", + "clusterphase_preferenceOutputscompare__sub\n", + "\n", + "compare__sub\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceelementInputsrun\n", - "\n", - "run\n", + "\n", + "run\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceelementOutputsran\n", - "\n", - "ran\n", + "\n", + "ran\n", "\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceelementInputsaccumulate_and_run\n", - "\n", - "accumulate_and_run\n", + "\n", + "accumulate_and_run\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceelementOutputsuser_input\n", - "\n", - "user_input\n", + "\n", + "user_input\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Inputselement\n", - "\n", - "element\n", + "\n", + "element\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceelementOutputsuser_input->clusterphase_preferencemin_phase1Inputselement\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Inputselement\n", - "\n", - "element\n", + "\n", + "element\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferenceelementOutputsuser_input->clusterphase_preferencemin_phase2Inputselement\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Inputsrun\n", - "\n", - "run\n", + "\n", + "run\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Outputsran\n", - "\n", - "ran\n", + "\n", + "ran\n", "\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Inputsaccumulate_and_run\n", - "\n", - "accumulate_and_run\n", + "\n", + "accumulate_and_run\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Outputsstructure\n", - "\n", - "structure\n", + "\n", + "structure\n", "\n", - "\n", - "\n", - "clusterphase_preferencecompareInputsstructure1\n", - "\n", - "structure1\n", + "\n", + "\n", + "clusterphase_preferencen1Inputsobj\n", + "\n", + "obj\n", "\n", - "\n", - "\n", - "clusterphase_preferencemin_phase1Outputsstructure->clusterphase_preferencecompareInputsstructure1\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "clusterphase_preferencemin_phase1Outputsstructure->clusterphase_preferencen1Inputsobj\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Outputscalc__cells\n", - "\n", - "calc__cells\n", + "\n", + "calc__cells\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Outputscalc__cells->clusterphase_preferenceOutputsmin_phase1__calc__cells\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Outputscalc__displacements\n", - "\n", - "calc__displacements\n", + "\n", + "calc__displacements\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Outputscalc__displacements->clusterphase_preferenceOutputsmin_phase1__calc__displacements\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Outputsenergy\n", - "\n", - "energy\n", + "\n", + "energy\n", "\n", - "\n", - "\n", - "clusterphase_preferencecompareInputsenergy1\n", - "\n", - "energy1\n", + "\n", + "\n", + "clusterphase_preferencee1Inputsobj\n", + "\n", + "obj\n", "\n", - "\n", - "\n", - "clusterphase_preferencemin_phase1Outputsenergy->clusterphase_preferencecompareInputsenergy1\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "clusterphase_preferencemin_phase1Outputsenergy->clusterphase_preferencee1Inputsobj\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Outputscalc__energy_tot\n", - "\n", - "calc__energy_tot\n", + "\n", + "calc__energy_tot\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Outputscalc__energy_tot->clusterphase_preferenceOutputsmin_phase1__calc__energy_tot\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Outputscalc__force_max\n", - "\n", - "calc__force_max\n", + "\n", + "calc__force_max\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Outputscalc__force_max->clusterphase_preferenceOutputsmin_phase1__calc__force_max\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Outputscalc__forces\n", - "\n", - "calc__forces\n", + "\n", + "calc__forces\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Outputscalc__forces->clusterphase_preferenceOutputsmin_phase1__calc__forces\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Outputscalc__indices\n", - "\n", - "calc__indices\n", + "\n", + "calc__indices\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Outputscalc__indices->clusterphase_preferenceOutputsmin_phase1__calc__indices\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Outputscalc__positions\n", - "\n", - "calc__positions\n", + "\n", + "calc__positions\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Outputscalc__positions->clusterphase_preferenceOutputsmin_phase1__calc__positions\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Outputscalc__pressures\n", - "\n", - "calc__pressures\n", + "\n", + "calc__pressures\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Outputscalc__pressures->clusterphase_preferenceOutputsmin_phase1__calc__pressures\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Outputscalc__steps\n", - "\n", - "calc__steps\n", + "\n", + "calc__steps\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Outputscalc__steps->clusterphase_preferenceOutputsmin_phase1__calc__steps\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Outputscalc__total_displacements\n", - "\n", - "calc__total_displacements\n", + "\n", + "calc__total_displacements\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Outputscalc__total_displacements->clusterphase_preferenceOutputsmin_phase1__calc__total_displacements\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Outputscalc__unwrapped_positions\n", - "\n", - "calc__unwrapped_positions\n", + "\n", + "calc__unwrapped_positions\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Outputscalc__unwrapped_positions->clusterphase_preferenceOutputsmin_phase1__calc__unwrapped_positions\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Outputscalc__volume\n", - "\n", - "calc__volume\n", + "\n", + "calc__volume\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase1Outputscalc__volume->clusterphase_preferenceOutputsmin_phase1__calc__volume\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Inputsrun\n", - "\n", - "run\n", + "\n", + "run\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Outputsran\n", - "\n", - "ran\n", + "\n", + "ran\n", "\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Inputsaccumulate_and_run\n", - "\n", - "accumulate_and_run\n", + "\n", + "accumulate_and_run\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Outputsstructure\n", - "\n", - "structure\n", + "\n", + "structure\n", "\n", - "\n", - "\n", - "clusterphase_preferencecompareInputsstructure2\n", - "\n", - "structure2\n", + "\n", + "\n", + "clusterphase_preferencen2Inputsobj\n", + "\n", + "obj\n", "\n", - "\n", - "\n", - "clusterphase_preferencemin_phase2Outputsstructure->clusterphase_preferencecompareInputsstructure2\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "clusterphase_preferencemin_phase2Outputsstructure->clusterphase_preferencen2Inputsobj\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Outputscalc__cells\n", - "\n", - "calc__cells\n", + "\n", + "calc__cells\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Outputscalc__cells->clusterphase_preferenceOutputsmin_phase2__calc__cells\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Outputscalc__displacements\n", - "\n", - "calc__displacements\n", + "\n", + "calc__displacements\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Outputscalc__displacements->clusterphase_preferenceOutputsmin_phase2__calc__displacements\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Outputsenergy\n", - "\n", - "energy\n", + "\n", + "energy\n", "\n", - "\n", - "\n", - "clusterphase_preferencecompareInputsenergy2\n", - "\n", - "energy2\n", + "\n", + "\n", + "clusterphase_preferencee2Inputsobj\n", + "\n", + "obj\n", "\n", - "\n", - "\n", - "clusterphase_preferencemin_phase2Outputsenergy->clusterphase_preferencecompareInputsenergy2\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "clusterphase_preferencemin_phase2Outputsenergy->clusterphase_preferencee2Inputsobj\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Outputscalc__energy_tot\n", - "\n", - "calc__energy_tot\n", + "\n", + "calc__energy_tot\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Outputscalc__energy_tot->clusterphase_preferenceOutputsmin_phase2__calc__energy_tot\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Outputscalc__force_max\n", - "\n", - "calc__force_max\n", + "\n", + "calc__force_max\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Outputscalc__force_max->clusterphase_preferenceOutputsmin_phase2__calc__force_max\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Outputscalc__forces\n", - "\n", - "calc__forces\n", + "\n", + "calc__forces\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Outputscalc__forces->clusterphase_preferenceOutputsmin_phase2__calc__forces\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Outputscalc__indices\n", - "\n", - "calc__indices\n", + "\n", + "calc__indices\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Outputscalc__indices->clusterphase_preferenceOutputsmin_phase2__calc__indices\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Outputscalc__positions\n", - "\n", - "calc__positions\n", + "\n", + "calc__positions\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Outputscalc__positions->clusterphase_preferenceOutputsmin_phase2__calc__positions\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Outputscalc__pressures\n", - "\n", - "calc__pressures\n", + "\n", + "calc__pressures\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Outputscalc__pressures->clusterphase_preferenceOutputsmin_phase2__calc__pressures\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Outputscalc__steps\n", - "\n", - "calc__steps\n", + "\n", + "calc__steps\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Outputscalc__steps->clusterphase_preferenceOutputsmin_phase2__calc__steps\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Outputscalc__total_displacements\n", - "\n", - "calc__total_displacements\n", + "\n", + "calc__total_displacements\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Outputscalc__total_displacements->clusterphase_preferenceOutputsmin_phase2__calc__total_displacements\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Outputscalc__unwrapped_positions\n", - "\n", - "calc__unwrapped_positions\n", + "\n", + "calc__unwrapped_positions\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Outputscalc__unwrapped_positions->clusterphase_preferenceOutputsmin_phase2__calc__unwrapped_positions\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Outputscalc__volume\n", - "\n", - "calc__volume\n", + "\n", + "calc__volume\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencemin_phase2Outputscalc__volume->clusterphase_preferenceOutputsmin_phase2__calc__volume\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "clusterphase_preferencee1Inputsrun\n", + "\n", + "run\n", + "\n", + "\n", + "\n", + "clusterphase_preferencee1Outputsran\n", + "\n", + "ran\n", + "\n", + "\n", + "\n", + "\n", + "clusterphase_preferencee1Inputsaccumulate_and_run\n", + "\n", + "accumulate_and_run\n", + "\n", + "\n", + "\n", + "clusterphase_preferencee1Outputsgetitem\n", + "\n", + "getitem\n", + "\n", + "\n", + "\n", + "clusterphase_preferencee1__getitem_Divide_n1__lenInputsobj\n", + "\n", + "obj\n", + "\n", + "\n", + "\n", + "clusterphase_preferencee1Outputsgetitem->clusterphase_preferencee1__getitem_Divide_n1__lenInputsobj\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "clusterphase_preferencen1Inputsrun\n", + "\n", + "run\n", + "\n", + "\n", + "\n", + "clusterphase_preferencen1Outputsran\n", + "\n", + "ran\n", + "\n", + "\n", + "\n", + "\n", + "clusterphase_preferencen1Inputsaccumulate_and_run\n", + "\n", + "accumulate_and_run\n", + "\n", + "\n", + "\n", + "clusterphase_preferencen1Outputslen\n", + "\n", + "len\n", + "\n", + "\n", + "\n", + "clusterphase_preferencee1__getitem_Divide_n1__lenInputsother\n", + "\n", + "other\n", + "\n", + "\n", + "\n", + "clusterphase_preferencen1Outputslen->clusterphase_preferencee1__getitem_Divide_n1__lenInputsother\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "clusterphase_preferencee2Inputsrun\n", + "\n", + "run\n", + "\n", + "\n", + "\n", + "clusterphase_preferencee2Outputsran\n", + "\n", + "ran\n", + "\n", + "\n", + "\n", + "\n", + "clusterphase_preferencee2Inputsaccumulate_and_run\n", + "\n", + "accumulate_and_run\n", + "\n", + "\n", + "\n", + "clusterphase_preferencee2Outputsgetitem\n", + "\n", + "getitem\n", + "\n", + "\n", + "\n", + "clusterphase_preferencee2__getitem_Divide_n2__lenInputsobj\n", + "\n", + "obj\n", + "\n", + "\n", + "\n", + "clusterphase_preferencee2Outputsgetitem->clusterphase_preferencee2__getitem_Divide_n2__lenInputsobj\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "clusterphase_preferencen2Inputsrun\n", + "\n", + "run\n", + "\n", + "\n", + "\n", + "clusterphase_preferencen2Outputsran\n", + "\n", + "ran\n", + "\n", + "\n", + "\n", + "\n", + "clusterphase_preferencen2Inputsaccumulate_and_run\n", + "\n", + "accumulate_and_run\n", + "\n", + "\n", + "\n", + "clusterphase_preferencen2Outputslen\n", + "\n", + "len\n", + "\n", + "\n", + "\n", + "clusterphase_preferencee2__getitem_Divide_n2__lenInputsother\n", + "\n", + "other\n", + "\n", + "\n", + "\n", + "clusterphase_preferencen2Outputslen->clusterphase_preferencee2__getitem_Divide_n2__lenInputsother\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "clusterphase_preferencee2__getitem_Divide_n2__lenInputsrun\n", + "\n", + "run\n", + "\n", + "\n", + "\n", + "clusterphase_preferencee2__getitem_Divide_n2__lenOutputsran\n", + "\n", + "ran\n", + "\n", + "\n", + "\n", + "\n", + "clusterphase_preferencee2__getitem_Divide_n2__lenInputsaccumulate_and_run\n", + "\n", + "accumulate_and_run\n", + "\n", + "\n", + "\n", + "clusterphase_preferencee2__getitem_Divide_n2__lenOutputstruediv\n", + "\n", + "truediv\n", + "\n", + "\n", + "\n", + "clusterphase_preferencecompareInputsobj\n", + "\n", + "obj\n", + "\n", + "\n", + "\n", + "clusterphase_preferencee2__getitem_Divide_n2__lenOutputstruediv->clusterphase_preferencecompareInputsobj\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "clusterphase_preferencee1__getitem_Divide_n1__lenInputsrun\n", + "\n", + "run\n", + "\n", + "\n", + "\n", + "clusterphase_preferencee1__getitem_Divide_n1__lenOutputsran\n", + "\n", + "ran\n", + "\n", + "\n", + "\n", + "\n", + "clusterphase_preferencee1__getitem_Divide_n1__lenInputsaccumulate_and_run\n", + "\n", + "accumulate_and_run\n", + "\n", + "\n", + "\n", + "clusterphase_preferencee1__getitem_Divide_n1__lenOutputstruediv\n", + "\n", + "truediv\n", + "\n", + "\n", + "\n", + "clusterphase_preferencecompareInputsother\n", + "\n", + "other\n", + "\n", + "\n", + "\n", + "clusterphase_preferencee1__getitem_Divide_n1__lenOutputstruediv->clusterphase_preferencecompareInputsother\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencecompareInputsrun\n", - "\n", - "run\n", + "\n", + "run\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencecompareOutputsran\n", - "\n", - "ran\n", + "\n", + "ran\n", "\n", "\n", "\n", - "\n", + "\n", "clusterphase_preferencecompareInputsaccumulate_and_run\n", - "\n", - "accumulate_and_run\n", + "\n", + "accumulate_and_run\n", "\n", - "\n", - "\n", - "clusterphase_preferencecompareOutputsde\n", - "\n", - "de\n", + "\n", + "\n", + "clusterphase_preferencecompareOutputssub\n", + "\n", + "sub\n", "\n", - "\n", - "\n", - "clusterphase_preferencecompareOutputsde->clusterphase_preferenceOutputscompare__de\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "clusterphase_preferencecompareOutputssub->clusterphase_preferenceOutputscompare__sub\n", + "\n", + "\n", + "\n", "\n", "\n", "\n" ], "text/plain": [ - "" + "" ] }, - "execution_count": 40, + "execution_count": 49, "metadata": {}, "output_type": "execute_result" } @@ -3154,7 +3859,7 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": 50, "id": "b51bef25-86c5-4d57-80c1-ab733e703caf", "metadata": {}, "outputs": [ @@ -3170,12 +3875,12 @@ ], "source": [ "out = wf(element=\"Al\", phase1=\"fcc\", phase2=\"hcp\", lattice_guess1=4, lattice_guess2=4)\n", - "print(f\"{wf.inputs.element.value}: E({wf.inputs.phase2.value}) - E({wf.inputs.phase1.value}) = {out.compare__de:.2f} eV/atom\")" + "print(f\"{wf.inputs.element.value}: E({wf.inputs.phase2.value}) - E({wf.inputs.phase1.value}) = {out.compare__sub:.2f} eV/atom\")" ] }, { "cell_type": "code", - "execution_count": 42, + "execution_count": 51, "id": "091e2386-0081-436c-a736-23d019bd9b91", "metadata": {}, "outputs": [ @@ -3199,7 +3904,7 @@ ], "source": [ "out = wf(element=\"Mg\", phase1=\"fcc\", phase2=\"hcp\", lattice_guess1=3, lattice_guess2=3)\n", - "print(f\"{wf.inputs.element.value}: E({wf.inputs.phase2.value}) - E({wf.inputs.phase1.value}) = {out.compare__de:.2f} eV/atom\")" + "print(f\"{wf.inputs.element.value}: E({wf.inputs.phase2.value}) - E({wf.inputs.phase1.value}) = {out.compare__sub:.2f} eV/atom\")" ] }, { @@ -3216,7 +3921,7 @@ }, { "cell_type": "code", - "execution_count": 43, + "execution_count": 52, "id": "4cdffdca-48d3-4486-9045-48102c7e5f31", "metadata": {}, "outputs": [ @@ -3230,9 +3935,9 @@ " warn(\n", "/Users/huber/work/pyiron/pyiron_workflow/pyiron_workflow/channels.py:164: UserWarning: The channel element was not connected to user_input, andthus could not disconnect from it.\n", " warn(\n", - "/Users/huber/work/pyiron/pyiron_workflow/pyiron_workflow/channels.py:164: UserWarning: The channel structure was not connected to structure1, andthus could not disconnect from it.\n", + "/Users/huber/work/pyiron/pyiron_workflow/pyiron_workflow/channels.py:164: UserWarning: The channel structure was not connected to obj, andthus could not disconnect from it.\n", " warn(\n", - "/Users/huber/work/pyiron/pyiron_workflow/pyiron_workflow/channels.py:164: UserWarning: The channel energy was not connected to energy1, andthus could not disconnect from it.\n", + "/Users/huber/work/pyiron/pyiron_workflow/pyiron_workflow/channels.py:164: UserWarning: The channel energy was not connected to obj, andthus could not disconnect from it.\n", " warn(\n" ] } @@ -3254,7 +3959,7 @@ }, { "cell_type": "code", - "execution_count": 44, + "execution_count": 53, "id": "ed4a3a22-fc3a-44c9-9d4f-c65bc1288889", "metadata": {}, "outputs": [ @@ -3279,12 +3984,12 @@ "source": [ "# Bad guess\n", "out = wf(element=\"Al\", phase1=\"fcc\", phase2=\"hcp\", lattice_guess1=3, lattice_guess2=3.1)\n", - "print(f\"{wf.inputs.element.value}: E({wf.inputs.phase2.value}) - E({wf.inputs.phase1.value}) = {out.compare__de:.2f} eV/atom\")" + "print(f\"{wf.inputs.element.value}: E({wf.inputs.phase2.value}) - E({wf.inputs.phase1.value}) = {out.compare__sub:.2f} eV/atom\")" ] }, { "cell_type": "code", - "execution_count": 45, + "execution_count": 54, "id": "5a985cbf-c308-4369-9223-b8a37edb8ab1", "metadata": {}, "outputs": [ @@ -3309,7 +4014,7 @@ "source": [ "# Good guess\n", "out = wf(element=\"Al\", phase1=\"fcc\", phase2=\"hcp\", lattice_guess1=4.05, lattice_guess2=3.2)\n", - "print(f\"{wf.inputs.element.value}: E({wf.inputs.phase2.value}) - E({wf.inputs.phase1.value}) = {out.compare__de:.2f} eV/atom\")" + "print(f\"{wf.inputs.element.value}: E({wf.inputs.phase2.value}) - E({wf.inputs.phase1.value}) = {out.compare__sub:.2f} eV/atom\")" ] }, { @@ -3352,7 +4057,7 @@ }, { "cell_type": "code", - "execution_count": 46, + "execution_count": 55, "id": "aa575249-b209-4e0c-9ea6-a82bc69dc833", "metadata": {}, "outputs": [ @@ -3361,25 +4066,21 @@ "output_type": "stream", "text": [ "None 1\n", - " \n" + " \n" ] } ], "source": [ - "@Workflow.wrap_as.single_value_node(\"sum\")\n", - "def Add(x, y):\n", - " return x + y\n", - "\n", "wf = Workflow(\"with_executor\")\n", - "wf.a1 = Add(0, 1)\n", - "wf.a2 = Add(2, 3)\n", - "wf.b = Add(wf.a1, wf.a2)\n", + "wf.a1 = wf.create.standard.Add(0, 1)\n", + "wf.a2 = wf.create.standard.Add(2, 3)\n", + "wf.b = wf.a1 + wf.a2\n", "\n", "wf.a2.executor = wf.create.Executor()\n", "wf()\n", "\n", - "print(wf.a1.future, wf.a1.outputs.sum.value)\n", - "print(wf.a2.future, wf.a2.outputs.sum.value)" + "print(wf.a1.future, wf.a1.outputs.add.value)\n", + "print(wf.a2.future, wf.a2.outputs.add.value)" ] }, { @@ -3392,7 +4093,7 @@ }, { "cell_type": "code", - "execution_count": 47, + "execution_count": 56, "id": "c1b7b4e9-1c76-470c-ba6e-a58ea3f611f6", "metadata": {}, "outputs": [ @@ -3420,7 +4121,7 @@ }, { "cell_type": "code", - "execution_count": 48, + "execution_count": 57, "id": "7e98058b-a791-4cb1-ae2c-864ad7e56cee", "metadata": {}, "outputs": [], @@ -3438,7 +4139,7 @@ }, { "cell_type": "code", - "execution_count": 49, + "execution_count": 58, "id": "0d1b4005-488e-492f-adcb-8ad7235e4fe3", "metadata": {}, "outputs": [ @@ -3447,7 +4148,7 @@ "output_type": "stream", "text": [ "None 1\n", - " \n", + " \n", "Finally 5\n", "b (Add) output single-value: 6\n" ] @@ -3456,15 +4157,15 @@ "source": [ "with Workflow.create.Executor() as executor:\n", " wf = Workflow(\"with_executor\")\n", - " wf.a1 = Add(0, 1)\n", - " wf.a2 = Add(2, 3)\n", - " wf.b = Add(wf.a1, wf.a2)\n", + " wf.a1 = wf.create.standard.Add(0, 1)\n", + " wf.a2 = wf.create.standard.Add(2, 3)\n", + " wf.b = wf.a1 + wf.a2\n", "\n", " wf.a2.executor = executor\n", " wf()\n", " \n", - " print(wf.a1.future, wf.a1.outputs.sum.value)\n", - " print(wf.a2.future, wf.a2.outputs.sum.value)\n", + " print(wf.a1.future, wf.a1.outputs.add.value)\n", + " print(wf.a2.future, wf.a2.outputs.add.value)\n", " \n", " print(\"Finally\", wf.a2.future.result())\n", " print(wf.b)" @@ -3482,7 +4183,7 @@ }, { "cell_type": "code", - "execution_count": 50, + "execution_count": 59, "id": "d03ca074-35a0-4e0d-9377-d4eaa5521f85", "metadata": {}, "outputs": [], @@ -3501,7 +4202,7 @@ }, { "cell_type": "code", - "execution_count": 51, + "execution_count": 60, "id": "a7c07aa0-84fc-4f43-aa4f-6498c0837d76", "metadata": {}, "outputs": [ @@ -3509,7 +4210,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "6.029127317946404\n" + "6.018927805998828\n" ] } ], @@ -3533,7 +4234,7 @@ }, { "cell_type": "code", - "execution_count": 52, + "execution_count": 61, "id": "b062ab5f-9b98-4843-8925-b93bf4c173f8", "metadata": {}, "outputs": [ @@ -3541,7 +4242,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "2.678937633987516\n" + "3.0853979130042717\n" ] } ], @@ -3615,7 +4316,7 @@ }, { "cell_type": "code", - "execution_count": 53, + "execution_count": 62, "id": "0b373764-b389-4c24-8086-f3d33a4f7fd7", "metadata": {}, "outputs": [ @@ -3629,7 +4330,7 @@ " 17.230249999999995]" ] }, - "execution_count": 53, + "execution_count": 62, "metadata": {}, "output_type": "execute_result" } @@ -3666,7 +4367,7 @@ }, { "cell_type": "code", - "execution_count": 54, + "execution_count": 63, "id": "0dd04b4c-e3e7-4072-ad34-58f2c1e4f596", "metadata": {}, "outputs": [ @@ -3725,7 +4426,7 @@ }, { "cell_type": "code", - "execution_count": 55, + "execution_count": 64, "id": "2dfb967b-41ac-4463-b606-3e315e617f2a", "metadata": {}, "outputs": [ @@ -3749,7 +4450,7 @@ }, { "cell_type": "code", - "execution_count": 56, + "execution_count": 65, "id": "2e87f858-b327-4f6b-9237-c8a557f29aeb", "metadata": {}, "outputs": [ @@ -3757,8 +4458,13 @@ "name": "stdout", "output_type": "stream", "text": [ - "0.189 <= 0.2\n", - "Finally 0.189\n" + "0.676 > 0.2\n", + "0.208 > 0.2\n", + "0.919 > 0.2\n", + "0.834 > 0.2\n", + "0.952 > 0.2\n", + "0.031 <= 0.2\n", + "Finally 0.031\n" ] } ], diff --git a/notebooks/quickstart.ipynb b/notebooks/quickstart.ipynb index 38eda8dfb..344a454ee 100644 --- a/notebooks/quickstart.ipynb +++ b/notebooks/quickstart.ipynb @@ -189,7 +189,9 @@ "\n", "We can work with nodes all by themselves, but since the whole point is to connect them together to make a computation graph, we can get extra tools by intentionally making these children of a `Workflow` node.\n", "\n", - "The `Workflow` class not only gives us access to the decorators for defining new nodes, but also lets us register modules of existing nodes and use them. Let's put together a workflow that uses both an existing node from a package, and a `Function` node that is more general than we used above in that it allows us to have multiple return values. This function node will also exploit our ability to name outputs and give type hints:" + "The `Workflow` class not only gives us access to the decorators for defining new nodes, but also lets us register modules of existing nodes and use them. Let's put together a workflow that uses both an existing node from a package, and a `Function` node that is more general than we used above in that it allows us to have multiple return values. This function node will also exploit our ability to name outputs and give type hints. \n", + "\n", + "We can also take output channels (or single value nodes) and perform many (but not all...) python operations on them to dynamically create new output nodes! Below see how we do math and indexing right on the output channels:" ] }, { @@ -207,238 +209,611 @@ "\n", "\n", - "\n", - "\n", + "\n", + "\n", "clustermy_workflow\n", - "\n", - "my_workflow: Workflow\n", + "\n", + "my_workflow: Workflow\n", "\n", "clustermy_workflowInputs\n", "\n", - "\n", + "\n", "\n", "\n", "\n", "\n", - "\n", - "Inputs\n", + "\n", + "Inputs\n", "\n", "\n", "clustermy_workflowOutputs\n", "\n", - "\n", + "\n", "\n", "\n", "\n", "\n", - "\n", - "Outputs\n", + "\n", + "Outputs\n", "\n", "\n", - "clustermy_workflowarrays\n", + "clustermy_workflowarange\n", "\n", - "\n", + "\n", "\n", "\n", "\n", "\n", - "\n", - "arrays: SquareRange\n", + "\n", + "arange: Arange\n", "\n", "\n", - "clustermy_workflowarraysInputs\n", + "clustermy_workflowarangeInputs\n", "\n", - "\n", + "\n", "\n", "\n", "\n", "\n", - "\n", - "Inputs\n", + "\n", + "Inputs\n", "\n", "\n", - "clustermy_workflowarraysOutputs\n", + "clustermy_workflowarangeOutputs\n", "\n", - "\n", + "\n", "\n", "\n", "\n", "\n", - "\n", - "Outputs\n", + "\n", + "Outputs\n", "\n", "\n", - "clustermy_workflowplot\n", + "clustermy_workflowarange__len_Subtract_1\n", "\n", - "\n", + "\n", "\n", "\n", "\n", "\n", - "\n", - "plot: Scatter\n", + "\n", + "arange__len_Subtract_1: Subtract\n", "\n", "\n", - "clustermy_workflowplotInputs\n", + "clustermy_workflowarange__len_Subtract_1Inputs\n", "\n", - "\n", + "\n", "\n", "\n", "\n", "\n", - "\n", - "Inputs\n", + "\n", + "Inputs\n", "\n", "\n", + "clustermy_workflowarange__len_Subtract_1Outputs\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "Outputs\n", + "\n", + "\n", + "clustermy_workflowarange__arange_Slice_None_arange__len_Subtract_1__sub_None\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "arange__arange_Slice_None_arange__len_Subtract_1__sub_None: Slice\n", + "\n", + "\n", + "clustermy_workflowarange__arange_Slice_None_arange__len_Subtract_1__sub_NoneInputs\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "Inputs\n", + "\n", + "\n", + "clustermy_workflowarange__arange_Slice_None_arange__len_Subtract_1__sub_NoneOutputs\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "Outputs\n", + "\n", + "\n", + "clustermy_workflowarange__arange_GetItem_arange__arange_Slice_None_arange__len_Subtract_1__sub_None__slice\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "arange__arange_GetItem_arange__arange_Slice_None_arange__len_Subtract_1__sub_None__slice: GetItem\n", + "\n", + "\n", + "clustermy_workflowarange__arange_GetItem_arange__arange_Slice_None_arange__len_Subtract_1__sub_None__sliceInputs\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "Inputs\n", + "\n", + "\n", + "clustermy_workflowarange__arange_GetItem_arange__arange_Slice_None_arange__len_Subtract_1__sub_None__sliceOutputs\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "Outputs\n", + "\n", + "\n", + "clustermy_workflowarange__arange_GetItem_arange__arange_Slice_None_arange__len_Subtract_1__sub_None__slice__getitem_Power_2\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "arange__arange_GetItem_arange__arange_Slice_None_arange__len_Subtract_1__sub_None__slice__getitem_Power_2: Power\n", + "\n", + "\n", + "clustermy_workflowarange__arange_GetItem_arange__arange_Slice_None_arange__len_Subtract_1__sub_None__slice__getitem_Power_2Inputs\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "Inputs\n", + "\n", + "\n", + "clustermy_workflowarange__arange_GetItem_arange__arange_Slice_None_arange__len_Subtract_1__sub_None__slice__getitem_Power_2Outputs\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "Outputs\n", + "\n", + "\n", + "clustermy_workflowplot\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "plot: Scatter\n", + "\n", + "\n", + "clustermy_workflowplotInputs\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "Inputs\n", + "\n", + "\n", "clustermy_workflowplotOutputs\n", "\n", - "\n", + "\n", "\n", "\n", "\n", "\n", - "\n", - "Outputs\n", + "\n", + "Outputs\n", "\n", "\n", "\n", "clustermy_workflowInputsrun\n", - "\n", - "run\n", + "\n", + "run\n", "\n", "\n", - "\n", + "\n", "clustermy_workflowOutputsran\n", - "\n", - "ran\n", + "\n", + "ran\n", "\n", "\n", "\n", "\n", "clustermy_workflowInputsaccumulate_and_run\n", - "\n", - "accumulate_and_run\n", + "\n", + "accumulate_and_run\n", "\n", - "\n", + "\n", "\n", - "clustermy_workflowInputsarrays__x\n", - "\n", - "arrays__x: int\n", + "clustermy_workflowInputsarange__n\n", + "\n", + "arange__n: int\n", "\n", - "\n", - "\n", - "clustermy_workflowarraysInputsx\n", - "\n", - "x: int\n", + "\n", + "\n", + "clustermy_workflowarangeInputsn\n", + "\n", + "n: int\n", "\n", - "\n", - "\n", - "clustermy_workflowInputsarrays__x->clustermy_workflowarraysInputsx\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "clustermy_workflowInputsarange__n->clustermy_workflowarangeInputsn\n", + "\n", + "\n", + "\n", "\n", - "\n", + "\n", + "\n", + "clustermy_workflowInputsarange__len_Subtract_1__other\n", + "\n", + "arange__len_Subtract_1__other\n", + "\n", + "\n", + "\n", + "clustermy_workflowarange__len_Subtract_1Inputsother\n", + "\n", + "other\n", + "\n", + "\n", + "\n", + "clustermy_workflowInputsarange__len_Subtract_1__other->clustermy_workflowarange__len_Subtract_1Inputsother\n", + "\n", + "\n", + "\n", + "\n", + "\n", "\n", - "clustermy_workflowOutputsplot__fig\n", - "\n", - "plot__fig\n", + "clustermy_workflowInputsarange__arange_Slice_None_arange__len_Subtract_1__sub_None__start\n", + "\n", + "arange__arange_Slice_None_arange__len_Subtract_1__sub_None__start\n", "\n", - "\n", + "\n", + "\n", + "clustermy_workflowarange__arange_Slice_None_arange__len_Subtract_1__sub_NoneInputsstart\n", + "\n", + "start\n", + "\n", + "\n", + "\n", + "clustermy_workflowInputsarange__arange_Slice_None_arange__len_Subtract_1__sub_None__start->clustermy_workflowarange__arange_Slice_None_arange__len_Subtract_1__sub_NoneInputsstart\n", + "\n", + "\n", + "\n", + "\n", + "\n", "\n", - "clustermy_workflowarraysInputsrun\n", - "\n", - "run\n", + "clustermy_workflowInputsarange__arange_Slice_None_arange__len_Subtract_1__sub_None__step\n", + "\n", + "arange__arange_Slice_None_arange__len_Subtract_1__sub_None__step\n", "\n", - "\n", - "\n", - "clustermy_workflowarraysOutputsran\n", - "\n", - "ran\n", + "\n", + "\n", + "clustermy_workflowarange__arange_Slice_None_arange__len_Subtract_1__sub_NoneInputsstep\n", + "\n", + "step\n", + "\n", + "\n", + "\n", + "clustermy_workflowInputsarange__arange_Slice_None_arange__len_Subtract_1__sub_None__step->clustermy_workflowarange__arange_Slice_None_arange__len_Subtract_1__sub_NoneInputsstep\n", + "\n", + "\n", + "\n", "\n", - "\n", - "\n", + "\n", "\n", - "clustermy_workflowarraysInputsaccumulate_and_run\n", - "\n", - "accumulate_and_run\n", + "clustermy_workflowInputsarange__arange_GetItem_arange__arange_Slice_None_arange__len_Subtract_1__sub_None__slice__getitem_Power_2__other\n", + "\n", + "arange__arange_GetItem_arange__arange_Slice_None_arange__len_Subtract_1__sub_None__slice__getitem_Power_2__other\n", "\n", - "\n", + "\n", + "\n", + "clustermy_workflowarange__arange_GetItem_arange__arange_Slice_None_arange__len_Subtract_1__sub_None__slice__getitem_Power_2Inputsother\n", + "\n", + "other\n", + "\n", + "\n", + "\n", + "clustermy_workflowInputsarange__arange_GetItem_arange__arange_Slice_None_arange__len_Subtract_1__sub_None__slice__getitem_Power_2__other->clustermy_workflowarange__arange_GetItem_arange__arange_Slice_None_arange__len_Subtract_1__sub_None__slice__getitem_Power_2Inputsother\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "clustermy_workflowOutputsplot__fig\n", + "\n", + "plot__fig\n", + "\n", + "\n", "\n", - "clustermy_workflowarraysOutputsx\n", - "\n", - "x: ndarray\n", + "clustermy_workflowarangeInputsrun\n", + "\n", + "run\n", "\n", - "\n", + "\n", + "\n", + "clustermy_workflowarangeOutputsran\n", + "\n", + "ran\n", + "\n", + "\n", + "\n", + "\n", + "clustermy_workflowarangeInputsaccumulate_and_run\n", + "\n", + "accumulate_and_run\n", + "\n", + "\n", "\n", + "clustermy_workflowarangeOutputsarange\n", + "\n", + "arange: ndarray\n", + "\n", + "\n", + "\n", + "clustermy_workflowarange__arange_GetItem_arange__arange_Slice_None_arange__len_Subtract_1__sub_None__sliceInputsobj\n", + "\n", + "obj\n", + "\n", + "\n", + "\n", + "clustermy_workflowarangeOutputsarange->clustermy_workflowarange__arange_GetItem_arange__arange_Slice_None_arange__len_Subtract_1__sub_None__sliceInputsobj\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "clustermy_workflowarangeOutputslen\n", + "\n", + "len: int\n", + "\n", + "\n", + "\n", + "clustermy_workflowarange__len_Subtract_1Inputsobj\n", + "\n", + "obj\n", + "\n", + "\n", + "\n", + "clustermy_workflowarangeOutputslen->clustermy_workflowarange__len_Subtract_1Inputsobj\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "clustermy_workflowarange__len_Subtract_1Inputsrun\n", + "\n", + "run\n", + "\n", + "\n", + "\n", + "clustermy_workflowarange__len_Subtract_1Outputsran\n", + "\n", + "ran\n", + "\n", + "\n", + "\n", + "\n", + "clustermy_workflowarange__len_Subtract_1Inputsaccumulate_and_run\n", + "\n", + "accumulate_and_run\n", + "\n", + "\n", + "\n", + "clustermy_workflowarange__len_Subtract_1Outputssub\n", + "\n", + "sub\n", + "\n", + "\n", + "\n", + "clustermy_workflowarange__arange_Slice_None_arange__len_Subtract_1__sub_NoneInputsstop\n", + "\n", + "stop\n", + "\n", + "\n", + "\n", + "clustermy_workflowarange__len_Subtract_1Outputssub->clustermy_workflowarange__arange_Slice_None_arange__len_Subtract_1__sub_NoneInputsstop\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "clustermy_workflowarange__arange_Slice_None_arange__len_Subtract_1__sub_NoneInputsrun\n", + "\n", + "run\n", + "\n", + "\n", + "\n", + "clustermy_workflowarange__arange_Slice_None_arange__len_Subtract_1__sub_NoneOutputsran\n", + "\n", + "ran\n", + "\n", + "\n", + "\n", + "\n", + "clustermy_workflowarange__arange_Slice_None_arange__len_Subtract_1__sub_NoneInputsaccumulate_and_run\n", + "\n", + "accumulate_and_run\n", + "\n", + "\n", + "\n", + "clustermy_workflowarange__arange_Slice_None_arange__len_Subtract_1__sub_NoneOutputsslice\n", + "\n", + "slice\n", + "\n", + "\n", + "\n", + "clustermy_workflowarange__arange_GetItem_arange__arange_Slice_None_arange__len_Subtract_1__sub_None__sliceInputsitem\n", + "\n", + "item\n", + "\n", + "\n", + "\n", + "clustermy_workflowarange__arange_Slice_None_arange__len_Subtract_1__sub_NoneOutputsslice->clustermy_workflowarange__arange_GetItem_arange__arange_Slice_None_arange__len_Subtract_1__sub_None__sliceInputsitem\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "clustermy_workflowarange__arange_GetItem_arange__arange_Slice_None_arange__len_Subtract_1__sub_None__sliceInputsrun\n", + "\n", + "run\n", + "\n", + "\n", + "\n", + "clustermy_workflowarange__arange_GetItem_arange__arange_Slice_None_arange__len_Subtract_1__sub_None__sliceOutputsran\n", + "\n", + "ran\n", + "\n", + "\n", + "\n", + "\n", + "clustermy_workflowarange__arange_GetItem_arange__arange_Slice_None_arange__len_Subtract_1__sub_None__sliceInputsaccumulate_and_run\n", + "\n", + "accumulate_and_run\n", + "\n", + "\n", + "\n", + "clustermy_workflowarange__arange_GetItem_arange__arange_Slice_None_arange__len_Subtract_1__sub_None__sliceOutputsgetitem\n", + "\n", + "getitem\n", + "\n", + "\n", + "\n", + "clustermy_workflowarange__arange_GetItem_arange__arange_Slice_None_arange__len_Subtract_1__sub_None__slice__getitem_Power_2Inputsobj\n", + "\n", + "obj\n", + "\n", + "\n", + "\n", + "clustermy_workflowarange__arange_GetItem_arange__arange_Slice_None_arange__len_Subtract_1__sub_None__sliceOutputsgetitem->clustermy_workflowarange__arange_GetItem_arange__arange_Slice_None_arange__len_Subtract_1__sub_None__slice__getitem_Power_2Inputsobj\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", "clustermy_workflowplotInputsx\n", - "\n", - "x: Union\n", + "\n", + "x: Union\n", "\n", - "\n", - "\n", - "clustermy_workflowarraysOutputsx->clustermy_workflowplotInputsx\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "clustermy_workflowarange__arange_GetItem_arange__arange_Slice_None_arange__len_Subtract_1__sub_None__sliceOutputsgetitem->clustermy_workflowplotInputsx\n", + "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "clustermy_workflowarraysOutputsx_sq\n", - "\n", - "x_sq: ndarray\n", + "\n", + "\n", + "clustermy_workflowarange__arange_GetItem_arange__arange_Slice_None_arange__len_Subtract_1__sub_None__slice__getitem_Power_2Inputsrun\n", + "\n", + "run\n", + "\n", + "\n", + "\n", + "clustermy_workflowarange__arange_GetItem_arange__arange_Slice_None_arange__len_Subtract_1__sub_None__slice__getitem_Power_2Outputsran\n", + "\n", + "ran\n", + "\n", + "\n", + "\n", + "\n", + "clustermy_workflowarange__arange_GetItem_arange__arange_Slice_None_arange__len_Subtract_1__sub_None__slice__getitem_Power_2Inputsaccumulate_and_run\n", + "\n", + "accumulate_and_run\n", + "\n", + "\n", + "\n", + "clustermy_workflowarange__arange_GetItem_arange__arange_Slice_None_arange__len_Subtract_1__sub_None__slice__getitem_Power_2Outputspow\n", + "\n", + "pow\n", "\n", "\n", - "\n", + "\n", "clustermy_workflowplotInputsy\n", - "\n", - "y: Union\n", + "\n", + "y: Union\n", "\n", - "\n", - "\n", - "clustermy_workflowarraysOutputsx_sq->clustermy_workflowplotInputsy\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "clustermy_workflowarange__arange_GetItem_arange__arange_Slice_None_arange__len_Subtract_1__sub_None__slice__getitem_Power_2Outputspow->clustermy_workflowplotInputsy\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "clustermy_workflowplotInputsrun\n", - "\n", - "run\n", + "\n", + "run\n", "\n", "\n", - "\n", + "\n", "clustermy_workflowplotOutputsran\n", - "\n", - "ran\n", + "\n", + "ran\n", "\n", "\n", "\n", - "\n", + "\n", "clustermy_workflowplotInputsaccumulate_and_run\n", - "\n", - "accumulate_and_run\n", + "\n", + "accumulate_and_run\n", "\n", "\n", - "\n", + "\n", "clustermy_workflowplotOutputsfig\n", - "\n", - "fig\n", + "\n", + "fig\n", "\n", "\n", - "\n", + "\n", "clustermy_workflowplotOutputsfig->clustermy_workflowOutputsplot__fig\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", "\n" ], "text/plain": [ - "" + "" ] }, "execution_count": 7, @@ -451,17 +826,19 @@ "\n", "wf = Workflow(\"my_workflow\")\n", "\n", - "@Workflow.wrap_as.function_node(\"x\", \"x_sq\")\n", - "def SquareRange(x: int) -> tuple[np.ndarray, np.ndarray]:\n", - " x = np.arange(x)\n", - " return x, (x**2)\n", + "@Workflow.wrap_as.function_node(\"arange\", \"len\")\n", + "def Arange(n: int) -> tuple[np.ndarray, int]:\n", + " \"\"\"\n", + " Two outputs is silly overkill, but just to demonstrate how Function nodes work\n", + " \"\"\"\n", + " return np.arange(n), n\n", "\n", "wf.register(\"plotting\", \"pyiron_workflow.node_library.plotting\")\n", "\n", - "wf.arrays = SquareRange()\n", + "wf.arange = Arange(10)\n", "wf.plot = wf.create.plotting.Scatter(\n", - " x=wf.arrays.outputs.x,\n", - " y=wf.arrays.outputs.x_sq\n", + " x=wf.arange.outputs.arange[:wf.arange.outputs.len -1],\n", + " y=wf.arange.outputs.arange[:wf.arange.outputs.len -1]**2\n", ")\n", "\n", "wf.draw()" @@ -472,7 +849,7 @@ "id": "ffc897e4-0f12-4231-8ebe-82862c890de5", "metadata": {}, "source": [ - "We can see that the workflow automatically exposes unconnected IO of its children and gives them a name based on the child node's name and that node's IO name.\n", + "We can see that the workflow automatically exposes unconnected IO of its children and gives them a name based on the child node's name and that node's IO name. Further, the math and indexing we do automatically injects new nodes after the output. Note that the slicing nodes get re-used in both occurrences for computational efficiency.\n", "\n", "Let's run our workflow and look at the result:" ] @@ -483,10 +860,18 @@ "id": "c499c0ed-7af5-491a-b340-2d2f4f48529c", "metadata": {}, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/huber/work/pyiron/pyiron_workflow/pyiron_workflow/node.py:613: UserWarning: The keyword 'arrays__x' was not found among input labels. If you are trying to update a node keyword, please use attribute assignment directly instead of calling\n", + " warnings.warn(\n" + ] + }, { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 8, @@ -495,7 +880,7 @@ }, { "data": { - "image/png": "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hmNZloLBYNjvnDZ/XelujOHE8/xNnjxZb7/9tmpqakLb6NGjNWvWLNXU1Cg5ObnTPjGZx6hdyhoDGzdutPr162c9++yz1sGDB61FixZZ55xzjvXRRx9ZlmVZS5cutebMmRPq/+GHH1pnn322tXjxYuvgwYPWs88+a/Xr18/6y1/+EqshdCvS8f3+97+3SktLrcOHD1sHDhywli5dakmyNm3aFKshdKupqcmqrq62qqurLUnWihUrrOrqauvjjz+2LMv582dZkY/RSXM4f/58y+PxWOXl5VZ9fX1o+/zzz0N9nD6HfRmjk+awuLjYqqystGpra6233nrLuv/++62kpCRr27ZtlmU5f/4sK/IxOmn+uvL1u13iYR4TKnxYlmX98Y9/tAYPHmylpqZal112WYdb4ObOnWtdc801HfqXl5dbl156qZWammoNGTLEWr16teGKIxPJ+JYvX25deOGFVlpamnXeeedZ48ePt1555ZUYVN077be0fX2bO3euZVmJMX+RjtFJcxhuXJKs559/PtTH6XPYlzE6aQ7vuOOO0P8v3/zmN63JkyeHfpQty/nzZ1mRj9FJ89eVr4ePeJhHl2X9/1UlAAAABiTMNR8AAMAZCB8AAMAowgcAADCK8AEAAIwifAAAAKMIHwAAwCjCBwAAMIrwAQAAjCJ8AAAAowgfAADAKMIHAAAwivABAACM+j9THZLTIiRtrwAAAABJRU5ErkJggg==", + "image/png": "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", "text/plain": [ "
" ] @@ -527,13 +912,13 @@ "name": "stdout", "output_type": "stream", "text": [ - "The channel x cannot take the value `5.5` because it is not compliant with the type hint \n" + "Can only set Channel object or connect to existing channels, but the attribute x got assigned 5.5 of type \n" ] } ], "source": [ "try:\n", - " wf.arrays.inputs.x = 5.5\n", + " wf.arange.inputs.x = 5.5\n", "except TypeError as e:\n", " message = e.args[0]\n", " print(message)" @@ -560,15 +945,15 @@ "source": [ "@Workflow.wrap_as.macro_node()\n", "def MySquarePlot(macro):\n", - " macro.arrays = SquareRange()\n", + " macro.arange = Arange()\n", " macro.plot = macro.create.plotting.Scatter(\n", - " x=macro.arrays.outputs.x,\n", - " y=macro.arrays.outputs.x_sq\n", + " x=macro.arange.outputs.arange,\n", + " y=macro.arange.outputs.arange**2\n", " )\n", - " macro.inputs_map = {\"arrays__x\": \"n\"}\n", + " macro.inputs_map = {\"arange__n\": \"n\"}\n", " macro.outputs_map = {\n", - " \"arrays__x\": \"x\",\n", - " \"arrays__x_sq\": \"y\",\n", + " \"arange__arange\": \"x\",\n", + " \"arange__len\": \"n\",\n", " \"plot__fig\": \"fig\"\n", " }\n", " # Note that we also forced regularly hidden IO to be exposed!\n", @@ -584,8 +969,9 @@ { "data": { "text/plain": [ - "{'square_plot__fig': ,\n", - " 'shifted_square_plot__fig': }" + "{'square_plot__n': 10,\n", + " 'square_plot__fig': ,\n", + " 'plus_one_square_plot__fig': }" ] }, "execution_count": 11, @@ -594,7 +980,7 @@ }, { "data": { - "image/png": "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", + "image/png": "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7lYg/h6m4e9hFv4e5uFvkj8F+SVZAAAwvbGDAgAAjENAAQAAxiGgAAAA4xBQAACAcQgon/DCCy8oEonI4/FowYIFeuONN+xuacZqbGzUXXfdJa/Xq+LiYj300EN677337G4L5zU2NsrhcKi2ttbuVmas48ePa/Xq1Zo7d65mzZqlO++8UwcPHrS7rRnp3Llz+s53vqNIJKKioiLdcssteuaZZ5ROp+1uraARUM579dVXVVtbq23btuntt9/WkiVL9MUvflHHjh2zu7UZqaOjQxs2bNBbb72l9vZ2nTt3TlVVVfrggw/sbm3G6+7u1p49e/S5z33O7lZmrNOnT+uee+7R1VdfrZ///OeKxWL63ve+p+uuu87u1makHTt26Pvf/76ampr07rvvaufOnfrud7+r559/3u7WChrHjM9bvHixKioq1NzcnF277bbb9NBDD6mxsdHGziBJf/jDH1RcXKyOjg59/vOft7udGWtoaEgVFRV64YUX9E//9E+68847tXv3brvbmnG2bNmiX//61+zyGuLBBx9UIBDQv/3bv2XX/uIv/kKzZs3Sj370Ixs7K2zsoEg6e/asDh48qKqqqpz1qqoqdXZ22tQVPimRSEiS5syZY3MnM9uGDRv0wAMP6P7777e7lRmtpaVFCxcu1Fe/+lUVFxdr/vz5evHFF+1ua8a699579ctf/lLvv/++JOm3v/2t3nzzTX3pS1+yubPCVpA3C8y3P/7xj0qlUgoEAjnrgUBA/f39NnWFCyzL0saNG3XvvfeqvLzc7nZmrFdeeUWHDh1Sd3e33a3MeL///e/V3NysjRs36u///u/V1dWlb33rW3K73VqzZo3d7c04mzdvViKR0Lx58+RyuZRKpfTss8/q4Ycftru1gkZA+QSHw5Hz3LKsUWuYek888YR+97vf6c0337S7lRmrr69PTz31lPbv3y+Px2N3OzNeOp3WwoUL1dDQIEmaP3++jhw5oubmZgKKDV599VXt3btX+/bt0+23367Dhw+rtrZW4XBYjz76qN3tFSwCiqQbbrhBLpdr1G7JwMDAqF0VTK0nn3xSLS0tOnDggG666Sa725mxDh48qIGBAS1YsCC7lkqldODAATU1NWlkZEQul8vGDmeWUCikaDSas3bbbbfpxz/+sU0dzWzf/va3tWXLFn3961+XJN1xxx06evSoGhsbCShXgO+gSLrmmmu0YMECtbe356y3t7ersrLSpq5mNsuy9MQTT+gnP/mJfvWrXykSidjd0ox233336Z133tHhw4ezj4ULF+qRRx7R4cOHCSdT7J577hl17P79999XaWmpTR3NbB9++KGcztyPU5fLxTHjK8QOynkbN27UN77xDS1cuFB333239uzZo2PHjunxxx+3u7UZacOGDdq3b59++tOfyuv1Zne3/H6/ioqKbO5u5vF6vaO+/3Pttddq7ty5fC/IBk8//bQqKyvV0NCglStXqqurS3v27NGePXvsbm1Gqqmp0bPPPqubb75Zt99+u95++23t2rVL3/zmN+1urbBZyPqXf/kXq7S01LrmmmusiooKq6Ojw+6WZixJl3z84Ac/sLs1nLd06VLrqaeesruNGau1tdUqLy+33G63NW/ePGvPnj12tzRjJZNJ66mnnrJuvvlmy+PxWLfccou1bds2a2RkxO7WChpzUAAAgHH4DgoAADAOAQUAABiHgAIAAIxDQAEAAMYhoAAAAOMQUAAAgHEIKAAAwDgEFAAAYBwCCgAAMA4BBQAAGIeAAgAAjENAAQAAxvn/lASCsr1Dz/AAAAAASUVORK5CYII=", "text/plain": [ "
" ] @@ -607,10 +993,10 @@ "wf2 = Workflow(\"my_composed_workflow\")\n", "\n", "wf2.square_plot = MySquarePlot(n=10)\n", - "wf2.shift = AddOne(wf2.square_plot.outputs.x)\n", - "wf2.shifted_square_plot = wf2.create.plotting.Scatter(\n", - " x=wf2.shift,\n", - " y=wf2.square_plot.outputs.y,\n", + "wf2.plus_one = wf2.square_plot.outputs.x + 1\n", + "wf2.plus_one_square_plot = wf2.create.plotting.Scatter(\n", + " x=wf2.square_plot.outputs.x,\n", + " y=wf2.plus_one**2,\n", ")\n", "wf2()" ] diff --git a/pyiron_workflow/channels.py b/pyiron_workflow/channels.py index 63f4561c3..6065691db 100644 --- a/pyiron_workflow/channels.py +++ b/pyiron_workflow/channels.py @@ -183,9 +183,6 @@ def connected(self) -> bool: def __iter__(self): return self.connections.__iter__() - def __len__(self): - return len(self.connections) - @property def channel(self) -> Channel: return self @@ -264,6 +261,17 @@ class DataChannel(Channel, ABC): which is to say it is data (not `NotData`) and that it conforms to the type hint (if one is provided and checking is active). + Output data facilitates many (but not all) python operators by injecting a new + node to perform that operation. Where the operator is not supported, we try to + support using the operator's dunder name as a method, e.g. `==` gives us trouble + with hashing, but this exploits the dunder method `.__eq__(other)`, so you can call + `.eq(other)` on output data. + These new nodes are instructed to run at the end of instantiation, but this fails + cleanly in case they are not ready. This is intended to accommodate two likely + scenarios: if you're injecting a node on top of an existing result you probably + want the injection result to also be immediately available, but if you're injecting + it at the end of something that hasn't run yet you don't want to see an error. + TODO: - Storage (including priority and history) - Ontological hinting @@ -491,6 +499,221 @@ class OutputData(DataChannel): def connection_partner_type(self): return InputData + @staticmethod + def _other_label(other): + return ( + other.channel.scoped_label if isinstance(other, HasChannel) else str(other) + ) + + def get_injected_label(self, injection_class, other=None): + suffix = f"_{self._other_label(other)}" if other is not None else "" + return f"{self.scoped_label}_{injection_class.__name__}{suffix}" + + def _get_injection_label(self, injection_class, *args): + other_labels = "_".join(self._other_label(other) for other in args) + suffix = f"_{other_labels}" if len(args) > 0 else "" + return f"{self.scoped_label}_{injection_class.__name__}{suffix}" + + def _node_injection(self, injection_class, *args, inject_self=True): + """ + Create a new node with the same parent as this channel's node, and feed it + arguments, or load such a node if it already exists on the parent (based on a + name dynamically generated from the injected node class and arguments). + + Args: + injection_class (type[Node]): The new node class to instantiate + *args: Any arguments for that function node + inject_self (bool): Whether to pre-pend the args with self. (Default is + True.) + + Returns: + (Node): The instantiated or loaded node. + """ + label = self._get_injection_label(injection_class, *args) + try: + # First check if the node already exists + return self.node.parent.nodes[label] + except (AttributeError, KeyError): + # Fall back on creating a new node in case parent is None or node nexists + node_args = (self, *args) if inject_self else args + return injection_class( + *node_args, parent=self.node.parent, label=label, run_after_init=True + ) + + # We don't wrap __all__ the operators, because you might really want the string or + # hash or whatever of the actual channel. But we do wrap all the dunder methods + # that should be unambiguously referring to an operation on values + + def __getattr__(self, name): + from pyiron_workflow.node_library.standard import GetAttr + + return self._node_injection(GetAttr, name) + + def __getitem__(self, item): + # Break slices into deeper injections, if any slice arguments are channel-like + if isinstance(item, slice) and any( + isinstance(slice_input, HasChannel) + for slice_input in [item.start, item.stop, item.step] + ): + from pyiron_workflow.node_library.standard import Slice + + item = self._node_injection( + Slice, item.start, item.stop, item.step, inject_self=False + ) + + from pyiron_workflow.node_library.standard import GetItem + + return self._node_injection(GetItem, item) + + def __lt__(self, other): + from pyiron_workflow.node_library.standard import LessThan + + return self._node_injection(LessThan, other) + + def __le__(self, other): + from pyiron_workflow.node_library.standard import LessThanEquals + + return self._node_injection(LessThanEquals, other) + + def eq(self, other): + from pyiron_workflow.node_library.standard import Equals + + return self._node_injection(Equals, other) + + def __ne__(self, other): + from pyiron_workflow.node_library.standard import NotEquals + + return self._node_injection(NotEquals, other) + + def __gt__(self, other): + from pyiron_workflow.node_library.standard import GreaterThan + + return self._node_injection(GreaterThan, other) + + def __ge__(self, other): + from pyiron_workflow.node_library.standard import GreaterThanEquals + + return self._node_injection(GreaterThanEquals, other) + + def bool(self): + from pyiron_workflow.node_library.standard import Bool + + return self._node_injection(Bool) + + def len(self): + from pyiron_workflow.node_library.standard import Length + + return self._node_injection(Length) + + def contains(self, other): + from pyiron_workflow.node_library.standard import Contains + + return self._node_injection(Contains, other) + + def __add__(self, other): + from pyiron_workflow.node_library.standard import Add + + return self._node_injection(Add, other) + + def __sub__(self, other): + from pyiron_workflow.node_library.standard import Subtract + + return self._node_injection(Subtract, other) + + def __mul__(self, other): + from pyiron_workflow.node_library.standard import Multiply + + return self._node_injection(Multiply, other) + + def __rmul__(self, other): + from pyiron_workflow.node_library.standard import RightMultiply + + return self._node_injection(RightMultiply, other) + + def __matmul__(self, other): + from pyiron_workflow.node_library.standard import MatrixMultiply + + return self._node_injection(MatrixMultiply, other) + + def __truediv__(self, other): + from pyiron_workflow.node_library.standard import Divide + + return self._node_injection(Divide, other) + + def __floordiv__(self, other): + from pyiron_workflow.node_library.standard import FloorDivide + + return self._node_injection(FloorDivide, other) + + def __mod__(self, other): + from pyiron_workflow.node_library.standard import Modulo + + return self._node_injection(Modulo, other) + + def __pow__(self, other): + from pyiron_workflow.node_library.standard import Power + + return self._node_injection(Power, other) + + def __and__(self, other): + from pyiron_workflow.node_library.standard import And + + return self._node_injection(And, other) + + def __xor__(self, other): + from pyiron_workflow.node_library.standard import XOr + + return self._node_injection(XOr, other) + + def __or__(self, other): + from pyiron_workflow.node_library.standard import Or + + return self._node_injection(Or, other) + + def __neg__(self): + from pyiron_workflow.node_library.standard import Negative + + return self._node_injection(Negative) + + def __pos__(self): + from pyiron_workflow.node_library.standard import Positive + + return self._node_injection(Positive) + + def __abs__(self): + from pyiron_workflow.node_library.standard import Absolute + + return self._node_injection(Absolute) + + def __invert__(self): + from pyiron_workflow.node_library.standard import Invert + + return self._node_injection(Invert) + + def int(self): + from pyiron_workflow.node_library.standard import Int + + return self._node_injection(Int) + + def float(self): + from pyiron_workflow.node_library.standard import Float + + return self._node_injection(Float) + + def __round__(self): + from pyiron_workflow.node_library.standard import Round + + return self._node_injection(Round) + + # Because we override __getattr__ we need to get and set state for serialization + def __getstate__(self): + return self.__dict__ + + def __setstate__(self, state): + # Update instead of overriding in case some other attributes were added on the + # main process while a remote process was working away + self.__dict__.update(**state) + class SignalChannel(Channel, ABC): """ diff --git a/pyiron_workflow/function.py b/pyiron_workflow/function.py index 42f8aafc6..82e6498c4 100644 --- a/pyiron_workflow/function.py +++ b/pyiron_workflow/function.py @@ -582,13 +582,15 @@ class SingleValue(Function, HasChannel): """ A node that _must_ return only a single value. - Attribute and item access is modified to finally attempt access on the output value. - Note that this means any attributes/method available on the output value become - available directly at the node level (at least those which don't conflict with the - existing node namespace). + Attribute and item access is modified to finally attempt access on the output + channel, and other operations (those supported by the output channel) are also + passed there automatically. + This means that the node itself can be used in place of its output channel, + and that the `value` attribtue directly accesses the output value. Promises (in addition parent class promises): - - Attribute and item access will finally attempt to access the output value + - Attribute and item access will finally attempt to access the output + - Other operators supported by the output channel operate there immediately. - The entire node can be used in place of its output value for connections, e.g. `some_node.input.some_channel = my_svn_instance`. """ @@ -602,40 +604,114 @@ def _get_output_labels(self, output_labels: str | list[str] | tuple[str] | None) ) return output_labels - @property - def single_value(self): - return self.outputs[self.outputs.labels[0]].value - @property def channel(self) -> OutputData: """The channel for the single output""" - return list(self.outputs.channel_dict.values())[0] + return self.outputs[self.outputs.labels[0]] @property def color(self) -> str: """For drawing the graph""" return SeabornColors.cyan - def __getitem__(self, item): - return self.single_value.__getitem__(item) - - def __getattr__(self, item): - try: - return getattr(self.single_value, item) - except Exception as e: - raise AttributeError( - f"Could not find {item} as an attribute of the single value " - f"{self.single_value}" - ) from e - def __repr__(self): - return self.single_value.__repr__() + return self.channel.value.__repr__() def __str__(self): return f"{self.label} ({self.__class__.__name__}) output single-value: " + str( - self.single_value + self.channel.value ) + def __getattr__(self, item): + return getattr(self.channel, item) + + def __getitem__(self, item): + return self.channel.__getitem__(item) + + def __lt__(self, other): + return self.channel.__lt__(other) + + def __le__(self, other): + return self.channel.__le__(other) + + def eq(self, other): + return self.channel.eq(other) + + def __ne__(self, other): + return self.channel.__ne__(other) + + def __gt__(self, other): + return self.channel.__gt__(other) + + def __ge__(self, other): + return self.channel.__ge__(other) + + def bool(self): + return self.channel.bool() + + def len(self): + return self.channel.len() + + def contains(self, other): + return self.channel.contains(other) + + def __add__(self, other): + return self.channel.__add__(other) + + def __sub__(self, other): + return self.channel.__sub__(other) + + def __mul__(self, other): + return self.channel.__mul__(other) + + def __rmul__(self, other): + return self.channel.__rmul__(other) + + def __matmul__(self, other): + return self.channel.__matmul__(other) + + def __truediv__(self, other): + return self.channel.__truediv__(other) + + def __floordiv__(self, other): + return self.channel.__floordiv__(other) + + def __mod__(self, other): + return self.channel.__mod__(other) + + def __pow__(self, other): + return self.channel.__pow__(other) + + def __and__(self, other): + return self.channel.__and__(other) + + def __xor__(self, other): + return self.channel.__xor__(other) + + def __or__(self, other): + return self.channel.__or__(other) + + def __neg__(self): + return self.channel.__neg__() + + def __pos__(self): + return self.channel.__pos__() + + def __abs__(self): + return self.channel.__abs__() + + def __invert__(self): + return self.channel.__invert__() + + def int(self): + return self.channel.int() + + def float(self): + return self.channel.float() + + def __round__(self): + return self.channel.__round__() + def _wrapper_factory( parent_class: type[Function], output_labels: Optional[list[str] | tuple[str]] diff --git a/pyiron_workflow/meta.py b/pyiron_workflow/meta.py index 570ac4dc8..1e221e7fd 100644 --- a/pyiron_workflow/meta.py +++ b/pyiron_workflow/meta.py @@ -216,17 +216,17 @@ def while_loop( >>> >>> AddWhile = Workflow.create.meta.while_loop( ... loop_body_class=Add, - ... condition_class=LessThanTen, + ... condition_class=Workflow.create.standard.LessThan, ... internal_connection_map=[ - ... ("Add", "a + b", "LessThanTen", "value"), + ... ("Add", "a + b", "LessThan", "obj"), ... ("Add", "a + b", "Add", "a") ... ], - ... inputs_map={"Add__a": "a", "Add__b": "b"}, + ... inputs_map={"Add__a": "a", "Add__b": "b", "LessThan__other": "cap"}, ... outputs_map={"Add__a + b": "total"} ... ) >>> >>> wf = Workflow("do_while") - >>> wf.add_while = AddWhile() + >>> wf.add_while = AddWhile(cap=10) >>> >>> wf.inputs_map = { ... "add_while__a": "a", diff --git a/pyiron_workflow/node.py b/pyiron_workflow/node.py index 2026c0afd..125c3717b 100644 --- a/pyiron_workflow/node.py +++ b/pyiron_workflow/node.py @@ -71,6 +71,10 @@ def wrapped_method(node: Node, *args, **kwargs): # rather node:Node return wrapped_method +class ReadinessError(ValueError): + pass + + class Node(HasToDict, ABC, metaclass=AbstractHasPost): """ Nodes are elements of a computational graph. @@ -120,6 +124,8 @@ class Node(HasToDict, ABC, metaclass=AbstractHasPost): held by the output channels - If an error is encountered _after_ reaching the state of actually computing the node's task, the status will get set to failure + - Nodes can be instructed to run at the end of their initialization, but will exit + cleanly if they get to checking their readiness and find they are not ready - Nodes have a label by which they are identified - Nodes may open a working directory related to their label, their parent(age) and the python process working directory @@ -247,7 +253,10 @@ def __init__( def __post__(self, *args, run_after_init: bool = False, **kwargs): if run_after_init: - self.run() + try: + self.run() + except ReadinessError: + pass @property @abstractmethod @@ -376,7 +385,7 @@ def run( self.inputs.fetch() if check_readiness and not self.ready: - raise ValueError( + raise ReadinessError( f"{self.label} received a run command but is not ready. The node " f"should be neither running nor failed, and all input values should" f" conform to type hints.\n" + self.readiness_report diff --git a/pyiron_workflow/node_library/standard.py b/pyiron_workflow/node_library/standard.py index 2783aa08d..1e7820df3 100644 --- a/pyiron_workflow/node_library/standard.py +++ b/pyiron_workflow/node_library/standard.py @@ -17,7 +17,7 @@ def UserInput(user_input): class If(SingleValue): """ - Has two extra signal channels: true and false. Evaluates the input as a boolean and + Has two extra signal channels: true and false. Evaluates the input as obj otheroolean and fires the corresponding output signal after running. """ @@ -29,7 +29,9 @@ def __init__(self, **kwargs): @staticmethod def if_(condition): if isclass(condition) and issubclass(condition, NotData): - raise TypeError(f"Logic 'If' node expected data but got NotData as input.") + raise TypeError( + f"Logic 'If' node expected data otherut got NotData as input." + ) return bool(condition) def process_run_result(self, function_output): @@ -44,7 +46,247 @@ def process_run_result(self, function_output): self.signals.output.false() +@single_value_node("slice") +def Slice(start=None, stop=NotData, step=None): + if start is None: + if stop is None: + raise ValueError( + "Slice must define at least start or stop, but both are None" + ) + elif step is not None: + raise ValueError("If step is provided, start _must_ be provided") + else: + s = slice(stop) + elif stop is None: + raise ValueError("If start is provided, stop _must_ be provided") + else: + s = slice(start, stop, step) + return s + + +# A bunch of (but not all) standard operators +# Return values based on dunder methods, where available + + +@single_value_node("str") +def String(obj): + return str(obj) + + +@single_value_node("bytes") +def Bytes(obj): + return bytes(obj) + + +@single_value_node("lt") +def LessThan(obj, other): + return obj < other + + +@single_value_node("le") +def LessThanEquals(obj, other): + return obj <= other + + +@single_value_node("eq") +def Equals(obj, other): + return obj == other + + +@single_value_node("neq") +def NotEquals(obj, other): + return obj != other + + +@single_value_node("gt") +def GreaterThan(obj, other): + return obj > other + + +@single_value_node("ge") +def GreaterThanEquals(obj, other): + return obj >= other + + +@single_value_node("hash") +def Hash(obj): + return hash(obj) + + +@single_value_node("bool") +def Bool(obj): + return bool(obj) + + +@single_value_node("getattr") +def GetAttr(obj, name): + return getattr(obj, name) + + +# These are not idempotent and thus not encouraged +# @single_value_node("none") +# def SetAttr(obj, name, value): +# setattr(obj, name, value) +# return None +# +# +# @single_value_node("none") +# def DelAttr(obj, name): +# delattr(obj, name) +# return None + + +@single_value_node("getitem") +def GetItem(obj, item): + return obj[item] + + +@single_value_node("dir") +def Dir(obj): + return dir(obj) + + +@single_value_node("len") +def Length(obj): + return len(obj) + + +@single_value_node("in") +def Contains(obj, other): + return other in obj + + +@single_value_node("add") +def Add(obj, other): + return obj + other + + +@single_value_node("sub") +def Subtract(obj, other): + return obj - other + + +@single_value_node("mul") +def Multiply(obj, other): + return obj * other + + +@single_value_node("rmul") +def RightMultiply(obj, other): + return other * obj + + +@single_value_node("matmul") +def MatrixMultiply(obj, other): + return obj @ other + + +@single_value_node("truediv") +def Divide(obj, other): + return obj / other + + +@single_value_node("floordiv") +def FloorDivide(obj, other): + return obj // other + + +@single_value_node("mod") +def Modulo(obj, other): + return obj % other + + +@single_value_node("pow") +def Power(obj, other): + return obj**other + + +@single_value_node("and") +def And(obj, other): + return obj & other + + +@single_value_node("xor") +def XOr(obj, other): + return obj ^ other + + +@single_value_node("or") +def Or(obj, other): + return obj ^ other + + +@single_value_node("neg") +def Negative(obj): + return -obj + + +@single_value_node("pos") +def Positive(obj): + return +obj + + +@single_value_node("abs") +def Absolute(obj): + return abs(obj) + + +@single_value_node("invert") +def Invert(obj): + return ~obj + + +@single_value_node("int") +def Int(obj): + return int(obj) + + +@single_value_node("float") +def Float(obj): + return float(obj) + + +@single_value_node("round") +def Round(obj): + return round(obj) + + nodes = [ - UserInput, + Absolute, + Add, + And, + Bool, + Bytes, + Contains, + Dir, + Divide, + Equals, + Float, + FloorDivide, + GetAttr, + GetItem, + GreaterThan, + GreaterThanEquals, + Hash, If, + Int, + Invert, + Length, + LessThan, + LessThanEquals, + MatrixMultiply, + Modulo, + Multiply, + Negative, + NotEquals, + Or, + Positive, + Power, + RightMultiply, + Round, + Slice, + String, + Subtract, + UserInput, + XOr, ] diff --git a/tests/integration/test_output_injection.py b/tests/integration/test_output_injection.py new file mode 100644 index 000000000..3fc550434 --- /dev/null +++ b/tests/integration/test_output_injection.py @@ -0,0 +1,205 @@ +import unittest + +from pyiron_workflow import Workflow +from pyiron_workflow.node import Node + + +class TestOutputInjection(unittest.TestCase): + """ + I.e. the process of inserting new nodes on-the-fly by modifying output channels" + """ + def setUp(self) -> None: + self.wf = Workflow("injection") + self.int = Workflow.create.standard.UserInput(42, run_after_init=True) + self.list = Workflow.create.standard.UserInput( + list(range(10)), run_after_init=True + ) + + def test_equality(self): + with self.subTest("True expressions"): + for expression in [ + self.int < 100, + 0 < self.int, + self.int <= 100, + self.int <= 42, + 0 <= self.int, + self.int.eq(42), + self.int != 43, + self.int > 0, + 100 > self.int, + self.int >= 0, + 100 >= self.int, + self.int >= 42, + ]: + with self.subTest(expression.label): + self.assertTrue(expression.value) + + with self.subTest("False expressions"): + for expression in [ + self.int > 100, + 0 > self.int, + self.int >= 100, + 0 >= self.int, + self.int != 42, + self.int.eq(43), + self.int < 0, + 100 < self.int, + self.int <= 0, + 100 <= self.int, + ]: + with self.subTest(expression.label): + self.assertFalse(expression.value) + + def test_bool(self): + b = self.int.bool() + self.assertTrue(b.value) + self.int.inputs.user_input = False + self.assertFalse(b()) + + def test_len(self): + self.assertEqual(10, self.list.len().value) + + def test_contains(self): + self.assertTrue(self.list.contains(1).value) + self.assertFalse(self.list.contains(-1).value) + + def test_algebra(self): + x = self.int # 42 + for lhs, rhs in [ + (x + x, 2 * x), + (2 * x, x * 2), + (x * x, x**2), + (x - x, 0 * x), + (x + x - x, x), + (x / 42, x / x), + (x // 2, x / 2), + (x // 43, 0 * x), + ((x + 1) % x, x + 1 - x), + (-x, -1 * x), + (+x, (-x)**2 / x), + (x, abs(-x)), + ]: + with self.subTest(f"{lhs.label} == {rhs.label}"): + self.assertEqual(lhs.value, rhs.value) + + # This passes fine, but requires numpy so don't include it + # def test_matmul(self): + # import numpy as np + # + # a = np.random.rand(2, 2) + # b = np.random.rand(2, 2) + # self.wf.a = Workflow.create.standard.UserInput(a, run_after_init=True) + # self.wf.b = Workflow.create.standard.UserInput(b, run_after_init=True) + # self.assertListEqual( + # (self.wf.a @ self.wf.b).value.tolist(), + # (a @ b).tolist() + # ) + + def test_logic(self): + # Note: We can't invert with not etc. because overloading __bool__ does not work + self.true = Workflow.create.standard.UserInput(True, run_after_init=True) + self.false = Workflow.create.standard.UserInput(False, run_after_init=True) + + with self.subTest("True expressions"): + for expression in [ + self.true & True, + # True & self.true, # There's no __land__ etc. + self.true & self.true, + self.true ^ False, + # False ^ self.true, + self.true ^ self.false, + self.false ^ self.true, + self.true | False, + self.true | self.false, + self.false | self.true, + self.false | False | self.true, + # False | self.true, + ]: + with self.subTest(expression.label): + self.assertTrue(expression.value) + + with self.subTest("False expressions"): + for expression in [ + self.true & False, + self.false & self.false, + self.false & self.true, + self.true & self.false, + self.true ^ self.true, + self.false ^ self.false, + self.false | self.false, + self.false | False, + ]: + with self.subTest(expression.label): + self.assertFalse(expression.value) + + def test_casts(self): + self.float = Workflow.create.standard.UserInput(42.2, run_after_init=True) + + self.assertIsInstance(self.int.float().value, float) + self.assertIsInstance(self.float.int().value, int) + self.assertEqual(self.int.value, round(self.float).value) + + def test_access(self): + + self.dict = Workflow.create.standard.UserInput( + {"foo": 42}, run_after_init=True + ) + + class Something: + myattr = 1 + + self.obj = Workflow.create.standard.UserInput( + Something(), run_after_init=True + ) + + self.assertIsInstance(self.list[0].value, int) + self.assertEqual(5, self.list[:5].len().value) + self.assertEqual(4, self.list[1:5].len().value) + self.assertEqual(3, self.list[-3:].len().value) + self.assertEqual(2, self.list[1:5:2].len().value) + + self.assertEqual(42, self.dict["foo"].value) + self.assertEqual(1, self.obj.myattr.value) + + def test_chaining(self): + self.assertFalse((self.list[:self.int//42][0] != 0).value) + + def test_repeated_access_in_parent_scope(self): + wf = Workflow("output_manipulation") + wf.list = Workflow.create.standard.UserInput(list(range(10))) + + a = wf.list[:4] + b = wf.list[:4] + c = wf.list[1:] + + self.assertIs( + a, + b, + msg="The same operation should re-access an existing node in the parent" + ) + self.assertIsNot( + a, + c, + msg="Unique operations should yield unique nodes" + ) + + def test_without_parent(self): + d1 = self.list[5] + d2 = self.list[5] + + self.assertIsInstance(d1, Node) + self.assertIsNot( + d1, + d2, + msg="Outside the scope of a parent, we can't expect to re-access an " + "equivalent node" + ) + self.assertEqual( + d1.label, + d2.label, + msg="Equivalent operations should nonetheless generate equal labels" + ) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/integration/test_workflow.py b/tests/integration/test_workflow.py index 464b0d560..128ca00d7 100644 --- a/tests/integration/test_workflow.py +++ b/tests/integration/test_workflow.py @@ -147,23 +147,19 @@ def GreaterThan(x: float, threshold: float): with self.subTest("Self-data-loop"): - @Workflow.wrap_as.single_value_node() - def Add(a, b): - return a + b - - @Workflow.wrap_as.single_value_node() - def LessThanTen(value): - return value < 10 - AddWhile = Workflow.create.meta.while_loop( - loop_body_class=Add, - condition_class=LessThanTen, + loop_body_class=Workflow.create.standard.Add, + condition_class=Workflow.create.standard.LessThan, internal_connection_map=[ - ("Add", "a + b", "LessThanTen", "value"), - ("Add", "a + b", "Add", "a") + ("Add", "add", "LessThan", "obj"), + ("Add", "add", "Add", "obj") ], - inputs_map={"Add__a": "a", "Add__b": "b"}, - outputs_map={"Add__a + b": "total"} + inputs_map={ + "Add__obj": "a", + "Add__other": "b", + "LessThan__other": "cap", + }, + outputs_map={"Add__add": "total"} ) wf = Workflow("do_while") @@ -171,11 +167,12 @@ def LessThanTen(value): wf.inputs_map = { "add_while__a": "a", - "add_while__b": "b" + "add_while__b": "b", + "add_while__cap": "cap" } wf.outputs_map = {"add_while__total": "total"} - out = wf(a=1, b=2) + out = wf(a=1, b=2, cap=10) self.assertEqual(out.total, 11) def test_executor_and_creator_interaction(self): diff --git a/tests/unit/test_channels.py b/tests/unit/test_channels.py index 66ab99ec8..b501875b6 100644 --- a/tests/unit/test_channels.py +++ b/tests/unit/test_channels.py @@ -59,20 +59,6 @@ def test_connection_validity(self): self.inp.connect(self.out) # A conjugate pair should work fine - def test_length(self): - self.inp.connect(self.out) - self.out2.connect(self.inp) - self.assertEqual( - 2, - len(self.inp), - msg="Promised that channel length was number of connections" - ) - self.assertEqual( - 1, - len(self.out), - msg="Promised that channel length was number of connections" - ) - def test_connection_reflexivity(self): self.inp.connect(self.out) @@ -359,13 +345,13 @@ def test_connections(self): with self.subTest("Ignore repeated connection"): self.out.connect(self.inp) - self.assertEqual(len(self.inp), 1) - self.assertEqual(len(self.out), 1) + self.assertEqual(len(self.inp.connections), 1) + self.assertEqual(len(self.out.connections), 1) with self.subTest("Check disconnection"): self.out.disconnect_all() - self.assertEqual(len(self.inp), 0) - self.assertEqual(len(self.out), 0) + self.assertEqual(len(self.inp.connections), 0) + self.assertEqual(len(self.out.connections), 0) with self.subTest("No connections to non-SignalChannels"): bad = InputData(label="numeric", node=DummyNode(), default=1, type_hint=int) diff --git a/tests/unit/test_function.py b/tests/unit/test_function.py index 5a993c18d..285aa586c 100644 --- a/tests/unit/test_function.py +++ b/tests/unit/test_function.py @@ -480,31 +480,42 @@ def returns_foo() -> Foo: return Foo() svn = SingleValue(returns_foo, output_labels="foo") + + self.assertEqual( + svn.connected, + False, + msg="Should return the _node_ attribute, not acting on the output channel" + ) + + injection = svn[0] # Should pass cleanly, even though it tries to run svn.run() self.assertEqual( - svn.some_attribute, + svn.some_attribute.value, # The call runs the dynamic node "exists", - msg="Should fall back to looking on the single value" + msg="Should fall back to acting on the output channel and creating a node" ) self.assertEqual( svn.connected, - False, - msg="Should return the _node_ attribute, not the single value attribute" + True, + msg="Should now be connected to the dynamically created nodes" ) - with self.assertRaises(AttributeError): + with self.assertRaises( + AttributeError, + msg="Aggressive running hits the problem that no such attribute exists" + ): svn.doesnt_exists_anywhere self.assertEqual( - svn[0], + injection(), True, - msg="Should fall back to looking on the single value" + msg="Should be able to query injection later" ) self.assertEqual( - svn["some other key"], + svn["some other key"].value, False, msg="Should fall back to looking on the single value" ) @@ -531,7 +542,7 @@ def test_str(self): svn = SingleValue(plus_one) svn.run() self.assertTrue( - str(svn).endswith(str(svn.single_value)), + str(svn).endswith(str(svn.value)), msg="SingleValueNodes should have their output as a string in their string " "representation (e.g., perhaps with a reminder note that this is " "actually still a Function and not just the value you're seeing.)"