Skip to content

Commit 0530c27

Browse files
committed
Initial workflow defs
1 parent 0c0caad commit 0530c27

File tree

8 files changed

+236
-48
lines changed

8 files changed

+236
-48
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import numpy as np
2+
from nomad.datamodel.data import ArchiveSection
3+
from nomad.datamodel.metainfo.annotations import ELNAnnotation
4+
from nomad.metainfo import Datetime, Quantity
5+
6+
7+
class Time(ArchiveSection):
8+
"""
9+
Contains time-related quantities.
10+
"""
11+
12+
datetime_end = Quantity(
13+
type=Datetime,
14+
description="""
15+
The date and time when this computation ended.
16+
""",
17+
a_eln=ELNAnnotation(component='DateTimeEditQuantity'),
18+
)
19+
20+
cpu1_start = Quantity(
21+
type=np.float64,
22+
unit='second',
23+
description="""
24+
The starting time of the computation on the (first) CPU 1.
25+
""",
26+
a_eln=ELNAnnotation(component='NumberEditQuantity'),
27+
)
28+
29+
cpu1_end = Quantity(
30+
type=np.float64,
31+
unit='second',
32+
description="""
33+
The end time of the computation on the (first) CPU 1.
34+
""",
35+
a_eln=ELNAnnotation(component='NumberEditQuantity'),
36+
)
37+
38+
wall_start = Quantity(
39+
type=np.float64,
40+
unit='second',
41+
description="""
42+
The internal wall-clock time from the starting of the computation.
43+
""",
44+
a_eln=ELNAnnotation(component='NumberEditQuantity'),
45+
)
46+
47+
wall_end = Quantity(
48+
type=np.float64,
49+
unit='second',
50+
description="""
51+
The internal wall-clock time from the end of the computation.
52+
""",
53+
a_eln=ELNAnnotation(component='NumberEditQuantity'),
54+
)

src/nomad_simulations/schema_packages/general.py

Lines changed: 4 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from nomad.datamodel.data import Schema
1212
from nomad.datamodel.metainfo.annotations import ELNAnnotation
1313
from nomad.datamodel.metainfo.basesections import Activity, Entity
14-
from nomad.metainfo import Datetime, Quantity, SchemaPackage, Section, SubSection
14+
from nomad.metainfo import Quantity, SchemaPackage, Section, SubSection
1515

1616
from nomad_simulations.schema_packages.model_method import ModelMethod
1717
from nomad_simulations.schema_packages.model_system import ModelSystem
@@ -21,6 +21,8 @@
2121
is_not_representative,
2222
)
2323

24+
from .common import Time
25+
2426
configuration = config.get_plugin_entry_point(
2527
'nomad_simulations.schema_packages:nomad_simulations_plugin'
2628
)
@@ -121,7 +123,7 @@ def normalize(self, archive: 'EntryArchive', logger: 'BoundLogger') -> None:
121123
pass
122124

123125

124-
class BaseSimulation(Activity):
126+
class BaseSimulation(Activity, Time):
125127
"""
126128
A computational simulation that produces output data from a given input model system
127129
and input methodological parameters.
@@ -135,50 +137,6 @@ class BaseSimulation(Activity):
135137
links=['https://liusemweb.github.io/mdo/core/1.1/index.html#Calculation']
136138
)
137139

138-
datetime_end = Quantity(
139-
type=Datetime,
140-
description="""
141-
The date and time when this computation ended.
142-
""",
143-
a_eln=ELNAnnotation(component='DateTimeEditQuantity'),
144-
)
145-
146-
cpu1_start = Quantity(
147-
type=np.float64,
148-
unit='second',
149-
description="""
150-
The starting time of the computation on the (first) CPU 1.
151-
""",
152-
a_eln=ELNAnnotation(component='NumberEditQuantity'),
153-
)
154-
155-
cpu1_end = Quantity(
156-
type=np.float64,
157-
unit='second',
158-
description="""
159-
The end time of the computation on the (first) CPU 1.
160-
""",
161-
a_eln=ELNAnnotation(component='NumberEditQuantity'),
162-
)
163-
164-
wall_start = Quantity(
165-
type=np.float64,
166-
unit='second',
167-
description="""
168-
The internal wall-clock time from the starting of the computation.
169-
""",
170-
a_eln=ELNAnnotation(component='NumberEditQuantity'),
171-
)
172-
173-
wall_end = Quantity(
174-
type=np.float64,
175-
unit='second',
176-
description="""
177-
The internal wall-clock time from the end of the computation.
178-
""",
179-
a_eln=ELNAnnotation(component='NumberEditQuantity'),
180-
)
181-
182140
program = SubSection(sub_section=Program.m_def, repeats=False)
183141

184142
def normalize(self, archive: 'EntryArchive', logger: 'BoundLogger') -> None:

src/nomad_simulations/schema_packages/outputs.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from typing import TYPE_CHECKING, Optional
22

33
import numpy as np
4-
from nomad.datamodel.data import ArchiveSection
54
from nomad.datamodel.metainfo.annotations import ELNAnnotation
65
from nomad.metainfo import Quantity, SubSection
76

@@ -38,8 +37,10 @@
3837
XASSpectrum,
3938
)
4039

40+
from .common import Time
4141

42-
class Outputs(ArchiveSection):
42+
43+
class Outputs(Time):
4344
"""
4445
Output properties of a simulation. This base class can be used for inheritance in any of the output properties
4546
defined in this schema.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from .general import SimulationWorkflow
2+
from .geometry_optimization import GeometryOptimization
3+
from .gw import DFTGWWorkflow
4+
from .single_point import SinglePoint
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
from nomad.datamodel import EntryArchive
2+
from nomad.datamodel.metainfo.workflow import Link, Task, Workflow
3+
from structlog.stdlib import BoundLogger
4+
5+
INCORRECT_N_TASKS = 'Incorrect number of tasks found.'
6+
7+
8+
class SimulationWorkflow(Workflow):
9+
"""
10+
Base class for simulation workflows.
11+
"""
12+
13+
def normalize(self, archive: EntryArchive, logger: BoundLogger):
14+
"""
15+
Generate tasks from the archive data outputs.
16+
"""
17+
if not archive.data or not archive.data.outputs:
18+
return
19+
20+
# generate tasks from outputs
21+
if not self.tasks:
22+
# default should to serial execution
23+
times: list[tuple[float, float]] = list(
24+
[
25+
(o.wall_start or n, o.wall_end or n)
26+
for n, o in enumerate(archive.data.outputs)
27+
]
28+
)
29+
times.sort(key=lambda x: x[0])
30+
# current parent task
31+
parent_n = 0
32+
parent_outputs: list[Link] = []
33+
for n, time in enumerate(times):
34+
task = Task(
35+
outputs=[
36+
Link(
37+
name='Output',
38+
section=archive.data.outputs[n],
39+
)
40+
],
41+
)
42+
self.tasks.append(task)
43+
# link tasks based on overlap in execution time
44+
if time[0] >= times[parent_n][1]:
45+
# if no overlap, assign outputs of parent as input to next task
46+
task.inputs = [
47+
Link(name='Input', section=output.section)
48+
for output in parent_outputs or task.outputs
49+
]
50+
# assign first parent outputs as workflow inputs
51+
if not self.inputs:
52+
self.inputs = task.inputs
53+
# assign as new parent
54+
parent_n = n
55+
# reset outputs
56+
parent_outputs = task.outputs
57+
else:
58+
parent_outputs.extend(task.outputs)
59+
# if overlap, assign parent outputs to task inputs
60+
task.inputs = [
61+
Link(name='Input', section=output.section)
62+
for output in self.tasks[parent_n or n].outputs
63+
]
64+
if not self.outputs:
65+
# assign parent outputs as workflow outputs
66+
self.outputs = parent_outputs
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from nomad.datamodel import EntryArchive
2+
from nomad.datamodel.metainfo.workflow import Link, Task
3+
from structlog.stdlib import BoundLogger
4+
5+
from .general import SimulationWorkflow
6+
7+
8+
class GeometryOptimization(SimulationWorkflow):
9+
"""
10+
Definitions for geometry optimization workflow.
11+
"""
12+
13+
def normalize(self, archive: EntryArchive, logger: BoundLogger) -> None:
14+
"""
15+
Specify the inputs and outputs of the tasks as the model system.
16+
"""
17+
super().normalize(archive, logger)
18+
19+
def to_system_links(task: Task) -> None:
20+
task.inputs = [
21+
Link(name='Input system', section=link.section.model_system_ref)
22+
for link in task.inputs
23+
if link.section and link.section.model_system_ref
24+
]
25+
task.outputs = [
26+
Link(name='Output system', section=link.section.model_system_ref)
27+
for link in task.inputs
28+
if link.section and link.section.model_system_ref
29+
]
30+
31+
to_system_links(self)
32+
for task in self.tasks:
33+
to_system_links(task)
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
from nomad.datamodel import EntryArchive
2+
from structlog.stdlib import BoundLogger
3+
4+
from .general import INCORRECT_N_TASKS, SimulationWorkflow
5+
6+
7+
class DFTGWWorkflow(SimulationWorkflow):
8+
"""
9+
Definitions for GW calculation based on DFT workflow.
10+
"""
11+
12+
def normalize(self, archive: EntryArchive, logger: BoundLogger) -> None:
13+
"""
14+
Link the DFT and GW single point workflows in the DFT-GW workflow.
15+
"""
16+
super().normalize(archive, logger)
17+
18+
if not self.name:
19+
self.name = 'DFT+GW'
20+
21+
if len(self.tasks) != 2:
22+
logger.error(INCORRECT_N_TASKS)
23+
return
24+
25+
if not self.inputs:
26+
# set inputs to inputs of DFT
27+
self.inputs = self.tasks[0].task.inputs
28+
29+
if not self.outputs:
30+
# set ouputs to outputs of GW
31+
self.outputs = self.tasks[1].task.outputs
32+
33+
# link dft and gw workflows
34+
self.tasks[0].inputs = self.inputs
35+
self.tasks[0].outputs = self.tasks[0].task.outputs
36+
self.tasks[1].inputs = self.tasks[0].outputs
37+
self.tasks[1].outputs = self.outputs
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
from nomad.datamodel import EntryArchive
2+
from nomad.datamodel.metainfo.workflow import Link
3+
from structlog.stdlib import BoundLogger
4+
5+
from .general import INCORRECT_N_TASKS, SimulationWorkflow
6+
7+
8+
class SinglePoint(SimulationWorkflow):
9+
"""
10+
Definitions for single point workflow.
11+
"""
12+
13+
def normalize(self, archive: EntryArchive, logger: BoundLogger) -> None:
14+
"""
15+
Specify the method and system as inputs.
16+
"""
17+
super().normalize(archive, logger)
18+
if len(self.tasks) != 1:
19+
logger.error(INCORRECT_N_TASKS)
20+
return
21+
22+
if not self.inputs:
23+
self.inputs = self.tasks[0].inputs
24+
25+
inps: list[Link] = []
26+
for inp in self.inputs:
27+
if inp.section and inp.section.model_system_ref:
28+
inps.append(
29+
Link(name='Input system', section=inp.section.model_system_ref)
30+
)
31+
if inp.section and inp.section.model_method_ref:
32+
inps.append(
33+
Link(name='Input method', section=inp.section.model_method_ref)
34+
)
35+
self.inputs = inps

0 commit comments

Comments
 (0)