Skip to content

Commit a7719b1

Browse files
committed
more updates for workflow
1 parent ca587e2 commit a7719b1

File tree

3 files changed

+161
-9
lines changed

3 files changed

+161
-9
lines changed

atomrdf/datamodels/workflow/method.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,13 @@
2626

2727

2828
class Method(BaseModel, TemplateMixin):
29+
basename: str
2930
pid: Optional[str] = Field(default=None, description="PID of the method")
3031
label: Optional[str] = Field(default=None, description="Label of the method")
3132

3233

3334
class MolecularStatics(Method):
34-
35+
basename = "MolecularStatics"
3536
pid: str = ASMO.MolecularStatics.uri
3637

3738
def to_graph(self, graph, main_id):
@@ -46,6 +47,7 @@ def from_graph(cls, graph, id):
4647

4748

4849
class MolecularDynamics(Method):
50+
basename = "MolecularDynamics"
4951
pid: str = ASMO.MolecularDynamics.uri
5052

5153
def to_graph(self, graph, main_id):
@@ -60,6 +62,7 @@ def from_graph(cls, graph, id):
6062

6163

6264
class DensityFunctionalTheory(Method):
65+
basename = "DensityFunctionalTheory"
6366
pid: str = ASMO.DensityFunctionalTheory.uri
6467

6568
def to_graph(self, graph, main_id):
@@ -74,6 +77,7 @@ def from_graph(cls, graph, id):
7477

7578

7679
class EquationOfStateFit(Method):
80+
basename = "EquationOfState"
7781
pid: str = ASMO.EquationOfStateFit.uri
7882

7983
def to_graph(self, graph, main_id):
@@ -88,6 +92,7 @@ def from_graph(cls, graph, id):
8892

8993

9094
class QuasiHarmonicApproximation(Method):
95+
basename = "QuasiHarmonicModel"
9196
pid: str = ASMO.QuasiHarmonicApproximation.uri
9297

9398
def to_graph(self, graph, main_id):
@@ -102,6 +107,7 @@ def from_graph(cls, graph, id):
102107

103108

104109
class ThermodynamicIntegration(Method):
110+
basename = "ThermodynamicIntegration"
105111
pid: str = ASMO.ThermodynamicIntegration.uri
106112

107113
def to_graph(self, graph, main_id):

atomrdf/datamodels/workflow/property.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,15 @@ class OutputParameter(Property):
8585
basename: Optional[str] = Field(
8686
default='OutputParameter', description="Basename of the property"
8787
)
88-
88+
associate_to_sample: Optional[bool] = Field(
89+
default=True, description="Whether to associate the property to the sample"
90+
)
91+
8992
class CalculatedProperty(Property):
9093
basename: Optional[str] = Field(
9194
default='CalculatedProperty', description="Basename of the property"
95+
)
96+
associate_to_sample: Optional[bool] = Field(
97+
default=True, description="Whether to associate the property to the sample"
9298
)
9399

atomrdf/datamodels/workflow/workflow.py

Lines changed: 147 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,11 @@
3131
from atomrdf.datamodels.workflow.method import *
3232
from atomrdf.datamodels.workflow.xcfunctional import *
3333
from atomrdf.utils import get_simulation
34-
from atomrdf.datamodels.workflow.property import Property
34+
from atomrdf.datamodels.workflow.property import *
3535

3636

37-
class Simulation(BaseModel, TemplateMixin):
38-
pid: Optional[str] = Field(default=None, description="PID of the method")
39-
label: Optional[str] = Field(default=None, description="Label of the method")
37+
class Simulation(Activity):
38+
label: Optional[str] = Field(default=None, description="Label of the simulation")
4039
# classes
4140
method: Optional[
4241
Union[
@@ -90,16 +89,20 @@ class Simulation(BaseModel, TemplateMixin):
9089
)
9190

9291
# list of classes
93-
input_property: Optional[List[Property]] = Field(
92+
input_paramater: Optional[List[InputParameter]] = Field(
9493
default=[], description="Input properties used in the simulation"
9594
)
96-
output_property: Optional[List[Property]] = Field(
95+
output_parameter: Optional[List[OutputParameter]] = Field(
9796
default=[], description="Output properties generated in the simulation"
9897
)
99-
calculated_property: Optional[List[Property]] = Field(
98+
calculated_property: Optional[List[CalculatedProperty]] = Field(
10099
default=[], description="Calculated properties from the simulation"
101100
)
102101

102+
path: Optional[str] = Field(
103+
default=None, description="Path to the simulation directory"
104+
)
105+
103106
@field_validator("method", mode="before")
104107
@classmethod
105108
def _validate_method(cls, v):
@@ -171,6 +174,8 @@ def _validate_workflow_manager(cls, v):
171174
if isinstance(v, dict):
172175
return SoftwareAgent(**v)
173176
return v
177+
178+
174179

175180
def _to_graph_md_details(self, graph, simulation):
176181
# add ensemble
@@ -274,3 +279,138 @@ def _from_graph_software(cls, graph, sim_id):
274279
if software:
275280
cls.software = [SoftwareAgent.from_graph(graph, s) for s in software]
276281
return cls
282+
283+
def to_graph_input_parameters(self, graph, simulation):
284+
if self.input_paramater:
285+
for param in self.input_paramater:
286+
param_uri = param.to_graph(graph)
287+
graph.add((simulation, ASMO.hasInputParameter, param_uri))
288+
289+
@classmethod
290+
def from_graph_input_parameters(cls, graph, sim_id):
291+
sim = get_simulation(graph, sim_id)
292+
input_params = [x[2] for x in graph.triples((sim, ASMO.hasInputParameter, None))]
293+
if input_params:
294+
cls.input_paramater = [InputParameter.from_graph(graph, p) for p in input_params]
295+
return cls
296+
297+
def to_graph_output_parameters(self, graph, simulation):
298+
if self.output_parameter:
299+
for param in self.output_parameter:
300+
param_uri = param.to_graph(graph)
301+
graph.add((simulation, ASMO.hasOutputParameter, param_uri))
302+
if param.associate_to_sample:
303+
if self.final_sample:
304+
graph.add((self.final_sample, ASMO.hasCalculatedProperty, param_uri))
305+
306+
@classmethod
307+
def from_graph_output_parameters(cls, graph, sim_id):
308+
sim = get_simulation(graph, sim_id)
309+
output_params = [x[2] for x in graph.triples((sim, ASMO.hasOutputParameter, None))]
310+
if output_params:
311+
cls.output_parameter = [OutputParameter.from_graph(graph, p) for p in output_params]
312+
return cls
313+
314+
@classmethod
315+
def from_graph_calculated_properties(cls, graph, sim_id):
316+
sim = get_simulation(graph, sim_id)
317+
calc_props = [x[2] for x in graph.triples((sim, ASMO.wasCalculatedBy, None))]
318+
if calc_props:
319+
cls.calculated_property = [CalculatedProperty.from_graph(graph, p) for p in calc_props]
320+
return cls
321+
322+
def to_graph_calculated_properties(self, graph, simulation):
323+
if self.calculated_property:
324+
for param in self.calculated_property:
325+
param_uri = param.to_graph(graph)
326+
graph.add((param_uri, ASMO.wasCalculatedBy, simulation))
327+
if param.associate_to_sample:
328+
if self.final_sample:
329+
graph.add((self.final_sample, ASMO.hasCalculatedProperty, param_uri))
330+
331+
def to_graph(self, graph):
332+
# create main simulation id
333+
main_id = uuid.uuid4()
334+
main_id = f'simulation:{main_id}'
335+
336+
#add method
337+
method = self.method.to_graph(graph, main_id)
338+
339+
# create simulation node based on method
340+
if self.method.basename in ["MolecularStatics", "MolecularDynamics"]:
341+
simulation = self.kg.create_node(main_id, ASMO.EnergyCalculation)
342+
graph.add((simulation, ASMO.hasComputationalMethod, method))
343+
self._to_graph_dof(graph, simulation)
344+
self._to_graph_md_details(graph, simulation)
345+
346+
elif self.method.basename == "DensityFunctionalTheory":
347+
simulation = self.kg.create_node(main_id, ASMO.EnergyCalculation)
348+
graph.add((simulation, ASMO.hasComputationalMethod, method))
349+
self._to_graph_dof(graph, simulation)
350+
self._to_graph_dft_details(graph, simulation)
351+
352+
elif self.method.basename in ["EquationOfStateFit",
353+
"QuasiHarmonicApproximation",]:
354+
simulation = self.kg.create_node(main_id, ASMO.Simulation)
355+
graph.add((simulation, ASMO.usesSimulationAlgorithm, method))
356+
357+
elif self.method.basename == 'ThermodynamicIntegration':
358+
simulation = self.kg.create_node(main_id, ASMO.Simulation)
359+
graph.add((simulation, ASMO.usesSimulationAlgorithm, method))
360+
self._to_graph_dof(graph, simulation)
361+
self._to_graph_md_details(graph, simulation)
362+
363+
#now add software
364+
self._to_graph_software(graph, simulation)
365+
366+
#add structure layers
367+
if self.final_sample:
368+
graph.add((self.final_sample, PROV.wasGeneratedBy, simulation))
369+
if self.initial_sample:
370+
graph.add((self.final_sample, PROV.wasDerivedFrom, self.initial_sample))
371+
372+
if self.path:
373+
graph.add((simulation, CMSO.hasPath, Literal(self.path, datatype=XSD.string)))
374+
375+
376+
if self.input_paramater:
377+
self.to_graph_input_parameters(graph, simulation)
378+
if self.output_parameter:
379+
self.to_graph_output_parameters(graph, simulation)
380+
if self.calculated_property:
381+
self.to_graph_calculated_properties(graph, simulation)
382+
383+
return simulation
384+
385+
@classmethod
386+
def from_graph(cls, graph, sim_id):
387+
cls = cls._from_graph_md_details(graph, sim_id)
388+
cls = cls._from_graph_dft_details(graph, sim_id)
389+
cls = cls._from_graph_dof(graph, sim_id)
390+
cls = cls._from_graph_software(graph, sim_id)
391+
cls = cls.from_graph_input_parameters(graph, sim_id)
392+
cls = cls.from_graph_output_parameters(graph, sim_id)
393+
cls = cls.from_graph_calculated_properties(graph, sim_id)
394+
395+
sim = get_simulation(graph, sim_id)
396+
label = graph.get_label(sim)
397+
if label:
398+
cls.label = label
399+
400+
initial_sample = graph.value(sim, PROV.wasDerivedFrom)
401+
if initial_sample:
402+
cls.initial_sample = str(initial_sample)
403+
404+
final_sample = graph.value(sim, PROV.wasGeneratedBy)
405+
if final_sample:
406+
cls.final_sample = str(final_sample)
407+
408+
path = graph.value(sim, CMSO.hasPath)
409+
if path:
410+
cls.path = str(path)
411+
412+
return cls
413+
414+
415+
416+

0 commit comments

Comments
 (0)