|
31 | 31 | from atomrdf.datamodels.workflow.method import * |
32 | 32 | from atomrdf.datamodels.workflow.xcfunctional import * |
33 | 33 | from atomrdf.utils import get_simulation |
34 | | -from atomrdf.datamodels.workflow.property import Property |
| 34 | +from atomrdf.datamodels.workflow.property import * |
35 | 35 |
|
36 | 36 |
|
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") |
40 | 39 | # classes |
41 | 40 | method: Optional[ |
42 | 41 | Union[ |
@@ -90,16 +89,20 @@ class Simulation(BaseModel, TemplateMixin): |
90 | 89 | ) |
91 | 90 |
|
92 | 91 | # list of classes |
93 | | - input_property: Optional[List[Property]] = Field( |
| 92 | + input_paramater: Optional[List[InputParameter]] = Field( |
94 | 93 | default=[], description="Input properties used in the simulation" |
95 | 94 | ) |
96 | | - output_property: Optional[List[Property]] = Field( |
| 95 | + output_parameter: Optional[List[OutputParameter]] = Field( |
97 | 96 | default=[], description="Output properties generated in the simulation" |
98 | 97 | ) |
99 | | - calculated_property: Optional[List[Property]] = Field( |
| 98 | + calculated_property: Optional[List[CalculatedProperty]] = Field( |
100 | 99 | default=[], description="Calculated properties from the simulation" |
101 | 100 | ) |
102 | 101 |
|
| 102 | + path: Optional[str] = Field( |
| 103 | + default=None, description="Path to the simulation directory" |
| 104 | + ) |
| 105 | + |
103 | 106 | @field_validator("method", mode="before") |
104 | 107 | @classmethod |
105 | 108 | def _validate_method(cls, v): |
@@ -171,6 +174,8 @@ def _validate_workflow_manager(cls, v): |
171 | 174 | if isinstance(v, dict): |
172 | 175 | return SoftwareAgent(**v) |
173 | 176 | return v |
| 177 | + |
| 178 | + |
174 | 179 |
|
175 | 180 | def _to_graph_md_details(self, graph, simulation): |
176 | 181 | # add ensemble |
@@ -274,3 +279,138 @@ def _from_graph_software(cls, graph, sim_id): |
274 | 279 | if software: |
275 | 280 | cls.software = [SoftwareAgent.from_graph(graph, s) for s in software] |
276 | 281 | 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