Skip to content

Commit 275e9f2

Browse files
committed
Merge remote-tracking branch 'upstream/main' into aiida-pythonjob
2 parents a6e9045 + 3acbc98 commit 275e9f2

17 files changed

+776
-116
lines changed

.github/workflows/executorlib.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: executorlib
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
8+
jobs:
9+
build:
10+
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- uses: actions/checkout@v4
15+
- uses: conda-incubator/setup-miniconda@v3
16+
with:
17+
auto-update-conda: true
18+
python-version: "3.12"
19+
environment-file: environment.yml
20+
auto-activate-base: false
21+
- name: Tests
22+
shell: bash -l {0}
23+
run: |
24+
pip install -e adis_tools
25+
pip install -e python_workflow_definition
26+
conda install -c conda-forge jupyter papermill
27+
export ESPRESSO_PSEUDO=$(pwd)/espresso/pseudo
28+
papermill universal_simple_to_executorlib.ipynb universal_simple_to_executorlib_out.ipynb -k "python3"
29+
papermill universal_qe_to_executorlib.ipynb universal_qe_to_executorlib_out.ipynb -k "python3"

.github/workflows/python.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: python
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
8+
jobs:
9+
build:
10+
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- uses: actions/checkout@v4
15+
- uses: conda-incubator/setup-miniconda@v3
16+
with:
17+
auto-update-conda: true
18+
python-version: "3.12"
19+
environment-file: environment.yml
20+
auto-activate-base: false
21+
- name: Tests
22+
shell: bash -l {0}
23+
run: |
24+
pip install -e adis_tools
25+
pip install -e python_workflow_definition
26+
conda install -c conda-forge jupyter papermill
27+
export ESPRESSO_PSEUDO=$(pwd)/espresso/pseudo
28+
papermill universal_simple_to_python.ipynb universal_simple_to_python_out.ipynb -k "python3"
29+
papermill universal_qe_to_python.ipynb universal_qe_to_python_out.ipynb -k "python3"

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ The corresponding Jupyter notebooks demonstrate this functionality:
6262
|--------------------------------------------------------------------------------|------------------------------------------------------------------------------|
6363
| [universal_simple_to_jobflow.ipynb](universal_simple_to_jobflow.ipynb) | Execute workflow defined in the Python Workflow Definition with jobflow. |
6464
| [universal_simple_to_pyiron_base.ipynb](universal_simple_to_pyiron_base.ipynb) | Execute workflow defined in the Python Workflow Definition with pyrion_base. |
65+
| [universal_simple_to_python.ipynb](universal_simple_to_python.ipynb) | Execute workflow defined in the Python Workflow Definition with Python. |
66+
| [universal_simple_to_executorlib.ipynb](universal_simple_to_executorlib.ipynb) | Execute workflow defined in the Python Workflow Definition with executorlib. |
6567
| [jobflow_to_pyiron_base_simple.ipynb](jobflow_to_pyiron_base_simple.ipynb) | Define Workflow with jobflow and execute it with pyiron_base. |
6668
| [pyiron_base_to_jobflow_simple.ipynb](pyiron_base_to_jobflow_simple.ipynb) | Define Workflow with pyiron_base and execute it with jobflow. |
6769

@@ -76,5 +78,7 @@ initial structure is relaxed, afterwards it is strained and the total energy is
7678
|------------------------------------------------------------------------|------------------------------------------------------------------------------|
7779
| [universal_qe_to_jobflow.ipynb](universal_qe_to_jobflow.ipynb) | Execute workflow defined in the Python Workflow Definition with jobflow. |
7880
| [universal_qe_to_pyiron_base.ipynb](universal_qe_to_pyiron_base.ipynb) | Execute workflow defined in the Python Workflow Definition with pyrion_base. |
81+
| [universal_qe_to_python.ipynb](universal_qe_to_python.ipynb) | Execute workflow defined in the Python Workflow Definition with Python. |
82+
| [universal_qe_to_executorlib.ipynb](universal_qe_to_executorlib.ipynb) | Execute workflow defined in the Python Workflow Definition with executorlib. |
7983
| [jobflow_to_pyiron_base_qe.ipynb](jobflow_to_pyiron_base_qe.ipynb) | Define Workflow with jobflow and execute it with pyiron_base. |
8084
| [pyiron_base_to_jobflow_qe.ipynb](pyiron_base_to_jobflow_qe.ipynb) | Define Workflow with pyiron_base and execute it with jobflow. |

environment.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ channels:
22
- conda-forge
33
dependencies:
44
- python=3.12
5+
- aiida-workgraph=0.4.10
56
- pyiron_base=0.11.7
67
- qe=7.2
78
- qe-tools=2.0.0

jobflow_to_pyiron_base_simple.ipynb

Lines changed: 207 additions & 1 deletion
Large diffs are not rendered by default.

pyiron_base_to_jobflow_qe.ipynb

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,6 @@
4141
"outputs": [],
4242
"execution_count": 2
4343
},
44-
{
45-
"id": "78ca455d-d0b8-4814-81fa-6039f6adb4c4",
46-
"cell_type": "code",
47-
"source": "from python_workflow_definition.jobflow import load_workflow_json",
48-
"metadata": {
49-
"trusted": true
50-
},
51-
"outputs": [],
52-
"execution_count": 3
53-
},
5444
{
5545
"id": "14d87342-706e-4120-99e6-b5363f724601",
5646
"cell_type": "code",
Lines changed: 198 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,198 @@
1-
{"metadata":{"kernelspec":{"display_name":"Python 3 (ipykernel)","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.12.8"}},"nbformat_minor":5,"nbformat":4,"cells":[{"id":"28d69730-d8cb-4174-ae3f-aa70da8a8108","cell_type":"code","source":"import numpy as np","metadata":{"trusted":true},"outputs":[],"execution_count":1},{"id":"cacaa0a8-27c8-44de-9e37-69cd3d13408b","cell_type":"code","source":"from jobflow.managers.local import run_locally","metadata":{"trusted":true},"outputs":[],"execution_count":2},{"id":"78ca455d-d0b8-4814-81fa-6039f6adb4c4","cell_type":"code","source":"from python_workflow_definition.jobflow import load_workflow_json","metadata":{"trusted":true},"outputs":[],"execution_count":3},{"id":"14d87342-706e-4120-99e6-b5363f724601","cell_type":"code","source":"from pyiron_base import Project, job","metadata":{"trusted":true},"outputs":[],"execution_count":4},{"id":"a2ed2608-9e1b-4a81-81cb-5079573ea2d1","cell_type":"code","source":"from python_workflow_definition.pyiron_base import write_workflow_json","metadata":{"trusted":true},"outputs":[],"execution_count":5},{"id":"444347b0-d5ba-4903-b8d4-a9d7fc35d268","cell_type":"code","source":"from python_workflow_definition.jobflow import load_workflow_json","metadata":{"trusted":true},"outputs":[],"execution_count":6},{"id":"b75c2530-9b89-4185-838f-a17e517fa68f","cell_type":"code","source":"from simple_workflow import (\n add_x_and_y as _add_x_and_y, \n add_x_and_y_and_z as _add_x_and_y_and_z,\n)","metadata":{"trusted":true},"outputs":[],"execution_count":7},{"id":"208ddfb8-dfda-4227-aa1f-3dc29e34ea82","cell_type":"code","source":"add_x_and_y = job(_add_x_and_y, output_key_lst=[\"x\", \"y\", \"z\"])\nadd_x_and_y_and_z = job(_add_x_and_y_and_z)","metadata":{"trusted":true},"outputs":[],"execution_count":8},{"id":"13debfcd-362d-4fd0-a91f-5ab33632fceb","cell_type":"code","source":"pr = Project(\"test\")\npr.remove_jobs(recursive=True, silently=True)","metadata":{"trusted":true},"outputs":[{"output_type":"display_data","data":{"text/plain":"0it [00:00, ?it/s]","application/vnd.jupyter.widget-view+json":{"version_major":2,"version_minor":0,"model_id":"1bcb58b981944c688403d1eaca7b3598"}},"metadata":{}}],"execution_count":9},{"id":"1f1cb12f-4001-478d-8ea0-b369f4f2981a","cell_type":"code","source":"obj = add_x_and_y(x=1, y=2, pyiron_project=pr)","metadata":{"trusted":true},"outputs":[],"execution_count":10},{"id":"4140f07b-af54-41ef-be22-df6b5b53bf95","cell_type":"code","source":"w = add_x_and_y_and_z(x=obj.output.x, y=obj.output.y, z=obj.output.z, pyiron_project=pr)","metadata":{"trusted":true},"outputs":[],"execution_count":11},{"id":"52646121-335f-48e6-bd5e-a1d69d00e8bc","cell_type":"code","source":"write_workflow_json(delayed_object=w, file_name=\"workflow_pyiron.json\")","metadata":{"trusted":true},"outputs":[],"execution_count":12},{"id":"72c8e6e6-8e60-4a4f-81f3-968b4b5f36ee","cell_type":"code","source":"!cat workflow_pyiron.json","metadata":{"trusted":true},"outputs":[{"name":"stdout","output_type":"stream","text":"{\"nodes\": {\"0\": \"simple_workflow.add_x_and_y_and_z\", \"1\": \"simple_workflow.add_x_and_y\", \"2\": 1, \"3\": 2}, \"edges\": [{\"target\": 0, \"targetHandle\": \"x\", \"source\": 1, \"sourceHandle\": \"x\"}, {\"target\": 1, \"targetHandle\": \"x\", \"source\": 2, \"sourceHandle\": null}, {\"target\": 1, \"targetHandle\": \"y\", \"source\": 3, \"sourceHandle\": null}, {\"target\": 0, \"targetHandle\": \"y\", \"source\": 1, \"sourceHandle\": \"y\"}, {\"target\": 0, \"targetHandle\": \"z\", \"source\": 1, \"sourceHandle\": \"z\"}]}"}],"execution_count":13},{"id":"32fcd4b2-4f0a-442d-b098-827672823796","cell_type":"code","source":"flow = load_workflow_json(file_name=\"workflow_pyiron.json\")","metadata":{"trusted":true},"outputs":[],"execution_count":14},{"id":"a80b59bd-fe30-49c6-92ca-35ef2d77a6fb","cell_type":"code","source":"result = run_locally(flow)\nresult","metadata":{"trusted":true},"outputs":[{"name":"stdout","output_type":"stream","text":"2025-03-13 06:29:36,854 INFO Started executing jobs locally\n2025-03-13 06:29:37,166 INFO Starting job - add_x_and_y (75f3eb14-326b-46bb-848d-ef501b2d43b4)\n2025-03-13 06:29:37,169 INFO Finished job - add_x_and_y (75f3eb14-326b-46bb-848d-ef501b2d43b4)\n2025-03-13 06:29:37,170 INFO Starting job - add_x_and_y_and_z (609c1659-ec60-4211-8996-670770e4b36c)\n2025-03-13 06:29:37,172 INFO Finished job - add_x_and_y_and_z (609c1659-ec60-4211-8996-670770e4b36c)\n2025-03-13 06:29:37,172 INFO Finished executing jobs locally\n"},{"execution_count":15,"output_type":"execute_result","data":{"text/plain":"{'75f3eb14-326b-46bb-848d-ef501b2d43b4': {1: Response(output={'x': 1, 'y': 2, 'z': 3}, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False, job_dir=PosixPath('/home/jovyan'))},\n '609c1659-ec60-4211-8996-670770e4b36c': {1: Response(output=6, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False, job_dir=PosixPath('/home/jovyan'))}}"},"metadata":{}}],"execution_count":15},{"id":"6a8d1a17-3698-4873-8937-616e9e7dc7ca","cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}
1+
{
2+
"metadata": {
3+
"kernelspec": {
4+
"display_name": "Python 3 (ipykernel)",
5+
"language": "python",
6+
"name": "python3"
7+
},
8+
"language_info": {
9+
"codemirror_mode": {
10+
"name": "ipython",
11+
"version": 3
12+
},
13+
"file_extension": ".py",
14+
"mimetype": "text/x-python",
15+
"name": "python",
16+
"nbconvert_exporter": "python",
17+
"pygments_lexer": "ipython3",
18+
"version": "3.12.8"
19+
}
20+
},
21+
"nbformat_minor": 5,
22+
"nbformat": 4,
23+
"cells": [
24+
{
25+
"id": "cacaa0a8-27c8-44de-9e37-69cd3d13408b",
26+
"cell_type": "code",
27+
"source": "from jobflow.managers.local import run_locally",
28+
"metadata": {
29+
"trusted": true
30+
},
31+
"outputs": [],
32+
"execution_count": 2
33+
},
34+
{
35+
"id": "14d87342-706e-4120-99e6-b5363f724601",
36+
"cell_type": "code",
37+
"source": "from pyiron_base import Project, job",
38+
"metadata": {
39+
"trusted": true
40+
},
41+
"outputs": [],
42+
"execution_count": 4
43+
},
44+
{
45+
"id": "a2ed2608-9e1b-4a81-81cb-5079573ea2d1",
46+
"cell_type": "code",
47+
"source": "from python_workflow_definition.pyiron_base import write_workflow_json",
48+
"metadata": {
49+
"trusted": true
50+
},
51+
"outputs": [],
52+
"execution_count": 5
53+
},
54+
{
55+
"id": "444347b0-d5ba-4903-b8d4-a9d7fc35d268",
56+
"cell_type": "code",
57+
"source": "from python_workflow_definition.jobflow import load_workflow_json",
58+
"metadata": {
59+
"trusted": true
60+
},
61+
"outputs": [],
62+
"execution_count": 6
63+
},
64+
{
65+
"id": "b75c2530-9b89-4185-838f-a17e517fa68f",
66+
"cell_type": "code",
67+
"source": "from simple_workflow import (\n add_x_and_y as _add_x_and_y, \n add_x_and_y_and_z as _add_x_and_y_and_z,\n)",
68+
"metadata": {
69+
"trusted": true
70+
},
71+
"outputs": [],
72+
"execution_count": 7
73+
},
74+
{
75+
"id": "208ddfb8-dfda-4227-aa1f-3dc29e34ea82",
76+
"cell_type": "code",
77+
"source": "add_x_and_y = job(_add_x_and_y, output_key_lst=[\"x\", \"y\", \"z\"])\nadd_x_and_y_and_z = job(_add_x_and_y_and_z)",
78+
"metadata": {
79+
"trusted": true
80+
},
81+
"outputs": [],
82+
"execution_count": 8
83+
},
84+
{
85+
"id": "13debfcd-362d-4fd0-a91f-5ab33632fceb",
86+
"cell_type": "code",
87+
"source": "pr = Project(\"test\")\npr.remove_jobs(recursive=True, silently=True)",
88+
"metadata": {
89+
"trusted": true
90+
},
91+
"outputs": [
92+
{
93+
"output_type": "display_data",
94+
"data": {
95+
"text/plain": "0it [00:00, ?it/s]",
96+
"application/vnd.jupyter.widget-view+json": {
97+
"version_major": 2,
98+
"version_minor": 0,
99+
"model_id": "1bcb58b981944c688403d1eaca7b3598"
100+
}
101+
},
102+
"metadata": {}
103+
}
104+
],
105+
"execution_count": 9
106+
},
107+
{
108+
"id": "1f1cb12f-4001-478d-8ea0-b369f4f2981a",
109+
"cell_type": "code",
110+
"source": "obj = add_x_and_y(x=1, y=2, pyiron_project=pr)",
111+
"metadata": {
112+
"trusted": true
113+
},
114+
"outputs": [],
115+
"execution_count": 10
116+
},
117+
{
118+
"id": "4140f07b-af54-41ef-be22-df6b5b53bf95",
119+
"cell_type": "code",
120+
"source": "w = add_x_and_y_and_z(x=obj.output.x, y=obj.output.y, z=obj.output.z, pyiron_project=pr)",
121+
"metadata": {
122+
"trusted": true
123+
},
124+
"outputs": [],
125+
"execution_count": 11
126+
},
127+
{
128+
"id": "52646121-335f-48e6-bd5e-a1d69d00e8bc",
129+
"cell_type": "code",
130+
"source": "write_workflow_json(delayed_object=w, file_name=\"workflow_pyiron.json\")",
131+
"metadata": {
132+
"trusted": true
133+
},
134+
"outputs": [],
135+
"execution_count": 12
136+
},
137+
{
138+
"id": "72c8e6e6-8e60-4a4f-81f3-968b4b5f36ee",
139+
"cell_type": "code",
140+
"source": "!cat workflow_pyiron.json",
141+
"metadata": {
142+
"trusted": true
143+
},
144+
"outputs": [
145+
{
146+
"name": "stdout",
147+
"output_type": "stream",
148+
"text": "{\"nodes\": {\"0\": \"simple_workflow.add_x_and_y_and_z\", \"1\": \"simple_workflow.add_x_and_y\", \"2\": 1, \"3\": 2}, \"edges\": [{\"target\": 0, \"targetHandle\": \"x\", \"source\": 1, \"sourceHandle\": \"x\"}, {\"target\": 1, \"targetHandle\": \"x\", \"source\": 2, \"sourceHandle\": null}, {\"target\": 1, \"targetHandle\": \"y\", \"source\": 3, \"sourceHandle\": null}, {\"target\": 0, \"targetHandle\": \"y\", \"source\": 1, \"sourceHandle\": \"y\"}, {\"target\": 0, \"targetHandle\": \"z\", \"source\": 1, \"sourceHandle\": \"z\"}]}"
149+
}
150+
],
151+
"execution_count": 13
152+
},
153+
{
154+
"id": "32fcd4b2-4f0a-442d-b098-827672823796",
155+
"cell_type": "code",
156+
"source": "flow = load_workflow_json(file_name=\"workflow_pyiron.json\")",
157+
"metadata": {
158+
"trusted": true
159+
},
160+
"outputs": [],
161+
"execution_count": 14
162+
},
163+
{
164+
"id": "a80b59bd-fe30-49c6-92ca-35ef2d77a6fb",
165+
"cell_type": "code",
166+
"source": "result = run_locally(flow)\nresult",
167+
"metadata": {
168+
"trusted": true
169+
},
170+
"outputs": [
171+
{
172+
"name": "stdout",
173+
"output_type": "stream",
174+
"text": "2025-03-13 06:29:36,854 INFO Started executing jobs locally\n2025-03-13 06:29:37,166 INFO Starting job - add_x_and_y (75f3eb14-326b-46bb-848d-ef501b2d43b4)\n2025-03-13 06:29:37,169 INFO Finished job - add_x_and_y (75f3eb14-326b-46bb-848d-ef501b2d43b4)\n2025-03-13 06:29:37,170 INFO Starting job - add_x_and_y_and_z (609c1659-ec60-4211-8996-670770e4b36c)\n2025-03-13 06:29:37,172 INFO Finished job - add_x_and_y_and_z (609c1659-ec60-4211-8996-670770e4b36c)\n2025-03-13 06:29:37,172 INFO Finished executing jobs locally\n"
175+
},
176+
{
177+
"execution_count": 15,
178+
"output_type": "execute_result",
179+
"data": {
180+
"text/plain": "{'75f3eb14-326b-46bb-848d-ef501b2d43b4': {1: Response(output={'x': 1, 'y': 2, 'z': 3}, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False, job_dir=PosixPath('/home/jovyan'))},\n '609c1659-ec60-4211-8996-670770e4b36c': {1: Response(output=6, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False, job_dir=PosixPath('/home/jovyan'))}}"
181+
},
182+
"metadata": {}
183+
}
184+
],
185+
"execution_count": 15
186+
},
187+
{
188+
"id": "6a8d1a17-3698-4873-8937-616e9e7dc7ca",
189+
"cell_type": "code",
190+
"source": "",
191+
"metadata": {
192+
"trusted": true
193+
},
194+
"outputs": [],
195+
"execution_count": null
196+
}
197+
]
198+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import json
2+
from importlib import import_module
3+
from inspect import isfunction
4+
5+
6+
from python_workflow_definition.shared import get_dict, get_list, get_kwargs, get_source_handles
7+
from python_workflow_definition.purepython import resort_total_lst, group_edges
8+
9+
10+
def get_item(obj, key):
11+
return obj[key]
12+
13+
14+
def _get_value(result_dict, nodes_new_dict, link_dict, exe):
15+
source, source_handle = link_dict["source"], link_dict["sourceHandle"]
16+
if source in result_dict.keys():
17+
result = result_dict[source]
18+
elif source in nodes_new_dict.keys():
19+
result = nodes_new_dict[source]
20+
else:
21+
raise KeyError()
22+
if source_handle is None:
23+
return result
24+
else:
25+
return exe.submit(fn=get_item, obj=result, key=source_handle)
26+
27+
28+
def load_workflow_json(file_name, exe):
29+
with open(file_name, "r") as f:
30+
content = json.load(f)
31+
32+
edges_new_lst = content["edges"]
33+
nodes_new_dict = {}
34+
for k, v in content["nodes"].items():
35+
if isinstance(v, str) and "." in v:
36+
p, m = v.rsplit('.', 1)
37+
mod = import_module(p)
38+
nodes_new_dict[int(k)] = getattr(mod, m)
39+
else:
40+
nodes_new_dict[int(k)] = v
41+
42+
total_lst = group_edges(edges_new_lst)
43+
total_new_lst = resort_total_lst(total_lst=total_lst, nodes_dict=nodes_new_dict)
44+
45+
result_dict = {}
46+
last_key = None
47+
for lst in total_new_lst:
48+
node = nodes_new_dict[lst[0]]
49+
if isfunction(node):
50+
kwargs = {
51+
k: _get_value(result_dict=result_dict, nodes_new_dict=nodes_new_dict, link_dict=v, exe=exe)
52+
for k, v in lst[1].items()
53+
}
54+
result_dict[lst[0]] = exe.submit(node, **kwargs)
55+
last_key = lst[0]
56+
57+
return result_dict[last_key]

0 commit comments

Comments
 (0)