From 3bdb7c22f5324302772436c74e83b978730adb3c Mon Sep 17 00:00:00 2001 From: Sarath Date: Thu, 11 Jul 2024 14:29:10 +0200 Subject: [PATCH 01/15] add sim length params as values --- atomrdf/workflow/pyiron/lammps.py | 30 +++++++++++++++++++++++++++ atomrdf/workflow/pyiron/murnaghan.py | 31 ++++++++++++++++++++++++++++ atomrdf/workflow/pyiron/vasp.py | 29 ++++++++++++++++++++++++++ 3 files changed, 90 insertions(+) diff --git a/atomrdf/workflow/pyiron/lammps.py b/atomrdf/workflow/pyiron/lammps.py index 19bd507..2008b2a 100644 --- a/atomrdf/workflow/pyiron/lammps.py +++ b/atomrdf/workflow/pyiron/lammps.py @@ -162,4 +162,34 @@ def extract_calculated_quantities(job, method_dict): "associate_to_sample": True, } ) + + structure = job.get_structure(frame=-1) + lx = np.linalg.norm(structure.cell[0]) + ly = np.linalg.norm(structure.cell[1]) + lz = np.linalg.norm(structure.cell[2]) + + outputs.append( + { + "label": "SimulationCellLength_x", + "value": np.round(lx, decimals=4), + "unit": "ANGSTROM", + "associate_to_sample": True, + } + ) + outputs.append( + { + "label": "SimulationCellLength_y", + "value": np.round(ly, decimals=4), + "unit": "ANGSTROM", + "associate_to_sample": True, + } + ) + outputs.append( + { + "label": "SimulationCellLength_z", + "value": np.round(lz, decimals=4), + "unit": "ANGSTROM", + "associate_to_sample": True, + } + ) method_dict['outputs'] = outputs \ No newline at end of file diff --git a/atomrdf/workflow/pyiron/murnaghan.py b/atomrdf/workflow/pyiron/murnaghan.py index 2c43bad..0bd8a26 100644 --- a/atomrdf/workflow/pyiron/murnaghan.py +++ b/atomrdf/workflow/pyiron/murnaghan.py @@ -48,6 +48,37 @@ def process_job(job): "associate_to_sample": True, } ) + + structure = job.get_structure(frame=-1) + lx = np.linalg.norm(structure.cell[0]) + ly = np.linalg.norm(structure.cell[1]) + lz = np.linalg.norm(structure.cell[2]) + + outputs.append( + { + "label": "SimulationCellLength_x", + "value": np.round(lx, decimals=4), + "unit": "ANGSTROM", + "associate_to_sample": True, + } + ) + outputs.append( + { + "label": "SimulationCellLength_y", + "value": np.round(ly, decimals=4), + "unit": "ANGSTROM", + "associate_to_sample": True, + } + ) + outputs.append( + { + "label": "SimulationCellLength_z", + "value": np.round(lz, decimals=4), + "unit": "ANGSTROM", + "associate_to_sample": True, + } + ) + murnaghan_dict['outputs'] = outputs lammps.add_software(murnaghan_dict) job_dicts.append(murnaghan_dict) diff --git a/atomrdf/workflow/pyiron/vasp.py b/atomrdf/workflow/pyiron/vasp.py index 298bfd2..4b795ff 100644 --- a/atomrdf/workflow/pyiron/vasp.py +++ b/atomrdf/workflow/pyiron/vasp.py @@ -159,4 +159,33 @@ def extract_calculated_quantities(job, method_dict): "associate_to_sample": True, } ) + structure = job.get_structure(frame=-1) + lx = np.linalg.norm(structure.cell[0]) + ly = np.linalg.norm(structure.cell[1]) + lz = np.linalg.norm(structure.cell[2]) + + outputs.append( + { + "label": "SimulationCellLength_x", + "value": np.round(lx, decimals=4), + "unit": "ANGSTROM", + "associate_to_sample": True, + } + ) + outputs.append( + { + "label": "SimulationCellLength_y", + "value": np.round(ly, decimals=4), + "unit": "ANGSTROM", + "associate_to_sample": True, + } + ) + outputs.append( + { + "label": "SimulationCellLength_z", + "value": np.round(lz, decimals=4), + "unit": "ANGSTROM", + "associate_to_sample": True, + } + ) method_dict['outputs'] = outputs \ No newline at end of file From 5f6ef94d4e9eac537b58ec6ca18fd68b754ef88e Mon Sep 17 00:00:00 2001 From: Sarath Date: Mon, 15 Jul 2024 17:00:03 +0200 Subject: [PATCH 02/15] add declassing --- atomrdf/structure.py | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/atomrdf/structure.py b/atomrdf/structure.py index 16535dd..5d231f1 100644 --- a/atomrdf/structure.py +++ b/atomrdf/structure.py @@ -30,6 +30,7 @@ import atomrdf.json_io as json_io import atomrdf.properties as prp +from atomrdf.sample import Property from rdflib import Graph, Namespace, XSD, RDF, RDFS, BNode, URIRef from atomrdf.namespace import CMSO, LDO, PLDO, PODO, UNSAFEASMO, UNSAFECMSO, PROV, Literal @@ -41,6 +42,13 @@ with open(file_location, "r") as fin: element_indetifiers = yaml.safe_load(fin) +#declassing special variables +def _declass(item): + if isinstance(item, Property): + return item.value + else: + return item + def _make_crystal( structure, lattice_constant=1.00, @@ -85,9 +93,9 @@ def _make_crystal( """ atoms, box, sdict = pcs.make_crystal( structure, - lattice_constant=lattice_constant, + lattice_constant = _declass(lattice_constant), repetitions=repetitions, - ca_ratio=ca_ratio, + ca_ratio = _declass(ca_ratio), noise=noise, element=element, return_structure_dict=True, @@ -98,7 +106,7 @@ def _make_crystal( s.box = box s.atoms = atoms s.atoms._lattice = structure - s.atoms._lattice_constant = lattice_constant + s.atoms._lattice_constant = _declass(lattice_constant) s._structure_dict = sdict s.label = label s.to_graph() @@ -152,7 +160,7 @@ def _make_general_lattice( positions, types, box, - lattice_constant=lattice_constant, + lattice_constant=_declass(lattice_constant), repetitions=repetitions, noise=noise, element=element, @@ -162,7 +170,7 @@ def _make_general_lattice( s.box = box s.atoms = atoms s.atoms._lattice = "custom" - s.atoms._lattice_constant = lattice_constant + s.atoms._lattice_constant = _declass(lattice_constant) s._structure_dict = sdict s.label = label s.to_graph() @@ -273,9 +281,9 @@ def _make_dislocation( # create a structure with the info input_structure = _make_crystal( structure, - lattice_constant=lattice_constant, + lattice_constant=_declass(lattice_constant), repetitions=repetitions, - ca_ratio=ca_ratio, + ca_ratio=_declass(ca_ratio), noise=noise, element=element, primitive=primitive, @@ -288,9 +296,9 @@ def _make_dislocation( raise ValueError("Please provide structure") input_structure = _make_crystal( structure, - lattice_constant=lattice_constant, + lattice_constant=_declass(lattice_constant), repetitions=repetitions, - ca_ratio=ca_ratio, + ca_ratio=_declass(ca_ratio), noise=noise, element=element, primitive=primitive, @@ -423,7 +431,7 @@ def _make_grain_boundary( atoms, box, sdict = gb.populate_grain_boundary( structure, repetitions=repetitions, - lattice_parameter=lattice_constant, + lattice_parameter=_declass(lattice_constant), overlap=overlap, ) elif element is not None: @@ -434,7 +442,7 @@ def _make_grain_boundary( s.box = box s.atoms = atoms s.atoms._lattice = structure - s.atoms._lattice_constant = lattice_constant + s.atoms._lattice_constant = _declass(lattice_constant) s._structure_dict = sdict s.label = label s.to_graph() @@ -506,7 +514,7 @@ def _read_structure( datadict = structure_dict[lattice]["conventional"] datadict["lattice"] = lattice if lattice_constant is not None: - datadict["lattice_constant"] = lattice_constant + datadict["lattice_constant"] = _declass(lattice_constant) if basis_box is not None: datadict["box"] = basis_box if basis_positions is not None: From db10cfeb04cd66fb6a22f44b8fb7658249fac0c6 Mon Sep 17 00:00:00 2001 From: Sarath Date: Mon, 15 Jul 2024 17:26:10 +0200 Subject: [PATCH 03/15] add initial draft of property mappings --- atomrdf/structure.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/atomrdf/structure.py b/atomrdf/structure.py index 5d231f1..1f5532d 100644 --- a/atomrdf/structure.py +++ b/atomrdf/structure.py @@ -110,6 +110,10 @@ def _make_crystal( s._structure_dict = sdict s.label = label s.to_graph() + s.add_property_mappings(lattice_constant) + + + return s @@ -848,6 +852,19 @@ def delete(self, ids=None, indices=None, condition=None, selection=False, copy_s return sys + + def add_property_mappings(self, output_property): + if self.graph is None: + return + if not isinstance(output_property, Property): + return + + #add mappings to the graph + parent_samples = list([x[0] for x in self.graph.triples((None, CMSO.hasCalculatedProperty, output_property._parent))]) + for parent_sample in parent_samples: + self.graph.add((self.sample, PROV.wasDerivedFrom, parent_sample)) + + def add_vacancy(self, concentration, number=None): """ Add Vacancy details which will be annotated by PODO From ca96badac75c063fef1664692a7fee95999c8ed7 Mon Sep 17 00:00:00 2001 From: Sarath Date: Mon, 15 Jul 2024 18:17:11 +0200 Subject: [PATCH 04/15] add mapping quantity --- atomrdf/structure.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/atomrdf/structure.py b/atomrdf/structure.py index 1f5532d..d088d5f 100644 --- a/atomrdf/structure.py +++ b/atomrdf/structure.py @@ -33,7 +33,7 @@ from atomrdf.sample import Property from rdflib import Graph, Namespace, XSD, RDF, RDFS, BNode, URIRef -from atomrdf.namespace import CMSO, LDO, PLDO, PODO, UNSAFEASMO, UNSAFECMSO, PROV, Literal +from atomrdf.namespace import CMSO, LDO, PLDO, PODO, UNSAFEASMO, UNSAFECMSO, PROV, Literal, ASMO # read element data file file_location = os.path.dirname(__file__).split("/") @@ -110,10 +110,7 @@ def _make_crystal( s._structure_dict = sdict s.label = label s.to_graph() - s.add_property_mappings(lattice_constant) - - - + s.add_property_mappings(lattice_constant, mapping_quantity='lattice_constant') return s @@ -853,7 +850,7 @@ def delete(self, ids=None, indices=None, condition=None, selection=False, copy_s return sys - def add_property_mappings(self, output_property): + def add_property_mappings(self, output_property, mapping_quantity=None): if self.graph is None: return if not isinstance(output_property, Property): @@ -863,6 +860,17 @@ def add_property_mappings(self, output_property): parent_samples = list([x[0] for x in self.graph.triples((None, CMSO.hasCalculatedProperty, output_property._parent))]) for parent_sample in parent_samples: self.graph.add((self.sample, PROV.wasDerivedFrom, parent_sample)) + + if mapping_quantity=='lattice_constant': + #add lattice constant mapping + material = self.graph.value(self.sample, CMSO.hasMaterial) + crystal_structure = self.graph.value(material, CMSO.hasStructure) + unit_cell = self.graph.value(crystal_structure, CMSO.hasUnitCell) + lattice_parameter = self.graph.value(unit_cell, CMSO.hasLatticeParameter) + + #also get activity + activity = self.graph.value(output_property._parent, ASMO.wasCalculatedBy) + self.graph.add((lattice_parameter, ASMO.wasCalculatedBy, activity)) def add_vacancy(self, concentration, number=None): From fcd090da150f066bdd51aad4faf271532b67cc08 Mon Sep 17 00:00:00 2001 From: Sarath Date: Tue, 16 Jul 2024 10:23:51 +0200 Subject: [PATCH 05/15] add lattice constant mapping everywherer --- atomrdf/structure.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/atomrdf/structure.py b/atomrdf/structure.py index d088d5f..c76f64d 100644 --- a/atomrdf/structure.py +++ b/atomrdf/structure.py @@ -110,7 +110,8 @@ def _make_crystal( s._structure_dict = sdict s.label = label s.to_graph() - s.add_property_mappings(lattice_constant, mapping_quantity='lattice_constant') + s.add_property_mappings(lattice_constant, mapping_quantity='lattice_constant') + s.add_property_mappings(ca_ratio, mapping_quantity='lattice_constant') return s @@ -175,7 +176,8 @@ def _make_general_lattice( s._structure_dict = sdict s.label = label s.to_graph() - + s.add_property_mappings(lattice_constant, mapping_quantity='lattice_constant') + return s @@ -373,6 +375,8 @@ def _make_dislocation( output_structure.graph = graph output_structure.to_graph() output_structure.add_dislocation(disl_dict) + output_structure.add_property_mappings(lattice_constant, mapping_quantity='lattice_constant') + output_structure.add_property_mappings(ca_ratio, mapping_quantity='lattice_constant') if return_atomman_dislocation: return output_structure, disc @@ -447,6 +451,8 @@ def _make_grain_boundary( s._structure_dict = sdict s.label = label s.to_graph() + s.add_property_mappings(lattice_constant, mapping_quantity='lattice_constant') + gb_dict = { "GBPlane": " ".join(np.array(gb_plane).astype(str)), "RotationAxis": axis, @@ -532,6 +538,7 @@ def _read_structure( s.lattice_properties = datadict s.label = label s.to_graph() + s.add_property_mappings(lattice_constant, mapping_quantity='lattice_constant') return s From 88d4e7acfd402c8ce58f102c0bf9e6012f6989d9 Mon Sep 17 00:00:00 2001 From: Sarath Date: Tue, 16 Jul 2024 10:52:31 +0200 Subject: [PATCH 06/15] add path for lattice constant --- atomrdf/network/ontology.py | 1 + 1 file changed, 1 insertion(+) diff --git a/atomrdf/network/ontology.py b/atomrdf/network/ontology.py index 30bd71c..30df473 100644 --- a/atomrdf/network/ontology.py +++ b/atomrdf/network/ontology.py @@ -82,6 +82,7 @@ def read_ontology(): # General fixes combo.add_path(("cmso:CrystalStructure", "cmso:hasAltName", "string")) + combo.add_path(("cmso:LatticeParameter", "asmo:wasCalculatedBy", "prov:Activity")) # interontology paths #CMSO -> PODO VACANCY From 5d71b90daa84defc11029e0e5f359296b72e74a2 Mon Sep 17 00:00:00 2001 From: Sarath Date: Tue, 16 Jul 2024 11:09:58 +0200 Subject: [PATCH 07/15] map calculation for operations --- atomrdf/sample.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/atomrdf/sample.py b/atomrdf/sample.py index 9e1abf3..589cce1 100644 --- a/atomrdf/sample.py +++ b/atomrdf/sample.py @@ -194,9 +194,11 @@ def __add__(self, value): if self._graph is not None: operation = URIRef(f'operation:{uuid.uuid4()}') self._graph.add((operation, RDF.type, MATH.Addition)) + self._graph.add((operation, RDF.type, PROV.Activity)) self._graph.add((operation, MATH.hasAddend, self._wrap(value))) self._graph.add((operation, MATH.hasAddend, self._wrap(self))) self._graph.add((operation, MATH.hasSum, self._wrap(res_prop))) + self._graph.add((parent, ASMO.wasCaclulatedBy, operation)) return res_prop def __sub__(self, value): @@ -207,9 +209,11 @@ def __sub__(self, value): if self._graph is not None: operation = URIRef(f'operation:{uuid.uuid4()}') self._graph.add((operation, RDF.type, MATH.Subtraction)) + self._graph.add((operation, RDF.type, PROV.Activity)) self._graph.add((operation, MATH.hasMinuend, self._wrap(self))) self._graph.add((operation, MATH.hasSubtrahend, self._wrap(value))) self._graph.add((operation, MATH.hasDifference, self._wrap(res_prop))) + self._graph.add((parent, ASMO.wasCaclulatedBy, operation)) return res_prop def __mul__(self, value): @@ -220,9 +224,11 @@ def __mul__(self, value): if self._graph is not None: operation = URIRef(f'operation:{uuid.uuid4()}') self._graph.add((operation, RDF.type, MATH.Multiplication)) + self._graph.add((operation, RDF.type, PROV.Activity)) self._graph.add((operation, MATH.hasFactor, self._wrap(self))) self._graph.add((operation, MATH.hasFactor, self._wrap(value))) self._graph.add((operation, MATH.hasProduct, self._wrap(res_prop))) + self._graph.add((parent, ASMO.wasCaclulatedBy, operation)) return res_prop def __truediv__(self, value): @@ -233,9 +239,11 @@ def __truediv__(self, value): if self._graph is not None: operation = URIRef(f'operation:{uuid.uuid4()}') self._graph.add((operation, RDF.type, MATH.Division)) + self._graph.add((operation, RDF.type, PROV.Activity)) self._graph.add((operation, MATH.hasDivisor, self._wrap(self))) self._graph.add((operation, MATH.hasDividend, self._wrap(value))) self._graph.add((operation, MATH.hasQuotient, self._wrap(res_prop))) + self._graph.add((parent, ASMO.wasCaclulatedBy, operation)) return res_prop From 43235a66fc9b967c6e74902f261c4edd6f4999be Mon Sep 17 00:00:00 2001 From: Sarath Date: Tue, 16 Jul 2024 11:11:23 +0200 Subject: [PATCH 08/15] bug fix in name --- atomrdf/sample.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomrdf/sample.py b/atomrdf/sample.py index 589cce1..2a74181 100644 --- a/atomrdf/sample.py +++ b/atomrdf/sample.py @@ -243,7 +243,7 @@ def __truediv__(self, value): self._graph.add((operation, MATH.hasDivisor, self._wrap(self))) self._graph.add((operation, MATH.hasDividend, self._wrap(value))) self._graph.add((operation, MATH.hasQuotient, self._wrap(res_prop))) - self._graph.add((parent, ASMO.wasCaclulatedBy, operation)) + self._graph.add((parent, ASMO.wasCalculatedBy, operation)) return res_prop From 65304bd891a3ce5fa48435010e1d407dde1ac8fa Mon Sep 17 00:00:00 2001 From: Sarath Date: Tue, 16 Jul 2024 11:13:28 +0200 Subject: [PATCH 09/15] rename onto to unsafe one --- atomrdf/sample.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/atomrdf/sample.py b/atomrdf/sample.py index 2a74181..f482787 100644 --- a/atomrdf/sample.py +++ b/atomrdf/sample.py @@ -198,7 +198,7 @@ def __add__(self, value): self._graph.add((operation, MATH.hasAddend, self._wrap(value))) self._graph.add((operation, MATH.hasAddend, self._wrap(self))) self._graph.add((operation, MATH.hasSum, self._wrap(res_prop))) - self._graph.add((parent, ASMO.wasCaclulatedBy, operation)) + self._graph.add((parent, MATH.wasCalculatedBy, operation)) return res_prop def __sub__(self, value): @@ -213,7 +213,7 @@ def __sub__(self, value): self._graph.add((operation, MATH.hasMinuend, self._wrap(self))) self._graph.add((operation, MATH.hasSubtrahend, self._wrap(value))) self._graph.add((operation, MATH.hasDifference, self._wrap(res_prop))) - self._graph.add((parent, ASMO.wasCaclulatedBy, operation)) + self._graph.add((parent, MATH.wasCalculatedBy, operation)) return res_prop def __mul__(self, value): @@ -228,7 +228,7 @@ def __mul__(self, value): self._graph.add((operation, MATH.hasFactor, self._wrap(self))) self._graph.add((operation, MATH.hasFactor, self._wrap(value))) self._graph.add((operation, MATH.hasProduct, self._wrap(res_prop))) - self._graph.add((parent, ASMO.wasCaclulatedBy, operation)) + self._graph.add((parent, MATH.wasCalculatedBy, operation)) return res_prop def __truediv__(self, value): @@ -243,7 +243,7 @@ def __truediv__(self, value): self._graph.add((operation, MATH.hasDivisor, self._wrap(self))) self._graph.add((operation, MATH.hasDividend, self._wrap(value))) self._graph.add((operation, MATH.hasQuotient, self._wrap(res_prop))) - self._graph.add((parent, ASMO.wasCalculatedBy, operation)) + self._graph.add((parent, MATH.wasCalculatedBy, operation)) return res_prop From abe7cdf119dba01453cfa4677cd6cc85607b73b0 Mon Sep 17 00:00:00 2001 From: Sarath Date: Tue, 16 Jul 2024 11:19:16 +0200 Subject: [PATCH 10/15] rename onto to unsafe one --- atomrdf/sample.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/atomrdf/sample.py b/atomrdf/sample.py index f482787..c57e613 100644 --- a/atomrdf/sample.py +++ b/atomrdf/sample.py @@ -198,7 +198,7 @@ def __add__(self, value): self._graph.add((operation, MATH.hasAddend, self._wrap(value))) self._graph.add((operation, MATH.hasAddend, self._wrap(self))) self._graph.add((operation, MATH.hasSum, self._wrap(res_prop))) - self._graph.add((parent, MATH.wasCalculatedBy, operation)) + self._graph.add((parent, MATH.wasCalculatedBy, operation), validate=False) return res_prop def __sub__(self, value): @@ -213,7 +213,7 @@ def __sub__(self, value): self._graph.add((operation, MATH.hasMinuend, self._wrap(self))) self._graph.add((operation, MATH.hasSubtrahend, self._wrap(value))) self._graph.add((operation, MATH.hasDifference, self._wrap(res_prop))) - self._graph.add((parent, MATH.wasCalculatedBy, operation)) + self._graph.add((parent, MATH.wasCalculatedBy, operation), validate=False) return res_prop def __mul__(self, value): @@ -228,7 +228,7 @@ def __mul__(self, value): self._graph.add((operation, MATH.hasFactor, self._wrap(self))) self._graph.add((operation, MATH.hasFactor, self._wrap(value))) self._graph.add((operation, MATH.hasProduct, self._wrap(res_prop))) - self._graph.add((parent, MATH.wasCalculatedBy, operation)) + self._graph.add((parent, MATH.wasCalculatedBy, operation), validate=False) return res_prop def __truediv__(self, value): @@ -243,7 +243,7 @@ def __truediv__(self, value): self._graph.add((operation, MATH.hasDivisor, self._wrap(self))) self._graph.add((operation, MATH.hasDividend, self._wrap(value))) self._graph.add((operation, MATH.hasQuotient, self._wrap(res_prop))) - self._graph.add((parent, MATH.wasCalculatedBy, operation)) + self._graph.add((parent, MATH.wasCalculatedBy, operation), validate=False) return res_prop From 13a0db3140fff8a6b9eb6d344873b5032aee2910 Mon Sep 17 00:00:00 2001 From: Sarath Date: Tue, 16 Jul 2024 11:21:38 +0200 Subject: [PATCH 11/15] fix asmo in structure --- atomrdf/sample.py | 8 ++++---- atomrdf/structure.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/atomrdf/sample.py b/atomrdf/sample.py index c57e613..f482787 100644 --- a/atomrdf/sample.py +++ b/atomrdf/sample.py @@ -198,7 +198,7 @@ def __add__(self, value): self._graph.add((operation, MATH.hasAddend, self._wrap(value))) self._graph.add((operation, MATH.hasAddend, self._wrap(self))) self._graph.add((operation, MATH.hasSum, self._wrap(res_prop))) - self._graph.add((parent, MATH.wasCalculatedBy, operation), validate=False) + self._graph.add((parent, MATH.wasCalculatedBy, operation)) return res_prop def __sub__(self, value): @@ -213,7 +213,7 @@ def __sub__(self, value): self._graph.add((operation, MATH.hasMinuend, self._wrap(self))) self._graph.add((operation, MATH.hasSubtrahend, self._wrap(value))) self._graph.add((operation, MATH.hasDifference, self._wrap(res_prop))) - self._graph.add((parent, MATH.wasCalculatedBy, operation), validate=False) + self._graph.add((parent, MATH.wasCalculatedBy, operation)) return res_prop def __mul__(self, value): @@ -228,7 +228,7 @@ def __mul__(self, value): self._graph.add((operation, MATH.hasFactor, self._wrap(self))) self._graph.add((operation, MATH.hasFactor, self._wrap(value))) self._graph.add((operation, MATH.hasProduct, self._wrap(res_prop))) - self._graph.add((parent, MATH.wasCalculatedBy, operation), validate=False) + self._graph.add((parent, MATH.wasCalculatedBy, operation)) return res_prop def __truediv__(self, value): @@ -243,7 +243,7 @@ def __truediv__(self, value): self._graph.add((operation, MATH.hasDivisor, self._wrap(self))) self._graph.add((operation, MATH.hasDividend, self._wrap(value))) self._graph.add((operation, MATH.hasQuotient, self._wrap(res_prop))) - self._graph.add((parent, MATH.wasCalculatedBy, operation), validate=False) + self._graph.add((parent, MATH.wasCalculatedBy, operation)) return res_prop diff --git a/atomrdf/structure.py b/atomrdf/structure.py index c76f64d..46df2c0 100644 --- a/atomrdf/structure.py +++ b/atomrdf/structure.py @@ -877,7 +877,7 @@ def add_property_mappings(self, output_property, mapping_quantity=None): #also get activity activity = self.graph.value(output_property._parent, ASMO.wasCalculatedBy) - self.graph.add((lattice_parameter, ASMO.wasCalculatedBy, activity)) + self.graph.add((lattice_parameter, UNSAFEASMO.wasCalculatedBy, activity)) def add_vacancy(self, concentration, number=None): From c52f73118aa4082b02de3f25503b2288fb2b51ee Mon Sep 17 00:00:00 2001 From: Sarath Date: Tue, 16 Jul 2024 11:58:03 +0200 Subject: [PATCH 12/15] add sample parents --- atomrdf/sample.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/atomrdf/sample.py b/atomrdf/sample.py index f482787..893dd0e 100644 --- a/atomrdf/sample.py +++ b/atomrdf/sample.py @@ -69,7 +69,7 @@ def _volume(self): self._graph.add((parent, ASMO.hasUnit, URIRef(f"http://qudt.org/vocab/unit/ANGSTROM3"))) else: parent = inps[labels.index("Volume")] - return Property(volume.toPython(), graph=self._graph, parent=parent, unit='ANGSTROM3') + return Property(volume.toPython(), graph=self._graph, parent=parent, unit='ANGSTROM3', sample_parent=self._sample_id) @property def _no_of_atoms(self): @@ -83,7 +83,7 @@ def _no_of_atoms(self): self._graph.add((self._sample_id, CMSO.hasCalculatedProperty, parent)) else: parent = inps[labels.index("NumberOfAtoms")] - return Property(no_atoms.toPython(), graph=self._graph, parent=parent) + return Property(no_atoms.toPython(), graph=self._graph, parent=parent, sample_parent=self._sample_id) @property @@ -98,7 +98,7 @@ def _input_properties(self): units = [unit if unit is None else unit.toPython().split('/')[-1] for unit in units] props = [] for count, value in enumerate(values): - props.append(Property(value.toPython(), unit=units[count], graph=self._graph, parent=inps[count])) + props.append(Property(value.toPython(), unit=units[count], graph=self._graph, parent=inps[count], sample_parent=self._sample_id)) return labels, props return [], [] @@ -112,16 +112,17 @@ def _output_properties(self): units = [unit if unit is None else unit.toPython().split('/')[-1] for unit in units] props = [] for count, value in enumerate(values): - props.append(Property(value.toPython(), unit=units[count], graph=self._graph, parent=inps[count])) + props.append(Property(value.toPython(), unit=units[count], graph=self._graph, parent=inps[count], sample_parent=self._sample_id)) return labels, props class Property: - def __init__(self, value, unit=None, graph=None, parent=None): + def __init__(self, value, unit=None, graph=None, parent=None, sample_parent=None): self._value = self._clean_value(value) self._unit = unit self._graph = graph self._parent = parent self._label = None + self._sample_parent = sample_parent def _clean_value(self, value): if isinstance(value, str): @@ -191,6 +192,7 @@ def __add__(self, value): parent = self._create_node(res) res_prop = Property(res, unit=self._unit, graph=self._graph, parent=parent) res_prop.label = self._create_label(self, value, '+') + res_prop._sample_parent = self._sample_parent if self._graph is not None: operation = URIRef(f'operation:{uuid.uuid4()}') self._graph.add((operation, RDF.type, MATH.Addition)) @@ -206,6 +208,7 @@ def __sub__(self, value): parent = self._create_node(res) res_prop = Property(res, unit=self._unit, graph=self._graph, parent=parent) res_prop.label = self._create_label(self, value, '-') + res_prop._sample_parent = self._sample_parent if self._graph is not None: operation = URIRef(f'operation:{uuid.uuid4()}') self._graph.add((operation, RDF.type, MATH.Subtraction)) @@ -221,6 +224,7 @@ def __mul__(self, value): parent = self._create_node(res) res_prop = Property(res, unit=self._unit, graph=self._graph, parent=parent) res_prop.label = self._create_label(self, value, '*') + res_prop._sample_parent = self._sample_parent if self._graph is not None: operation = URIRef(f'operation:{uuid.uuid4()}') self._graph.add((operation, RDF.type, MATH.Multiplication)) @@ -236,6 +240,7 @@ def __truediv__(self, value): parent = self._create_node(res) res_prop = Property(res, unit=self._unit, graph=self._graph, parent=parent) res_prop.label = self._create_label(self, value, '/') + res_prop._sample_parent = self._sample_parent if self._graph is not None: operation = URIRef(f'operation:{uuid.uuid4()}') self._graph.add((operation, RDF.type, MATH.Division)) From 240e0d97b1b8b6f64f2b48f7e8be130017eebba2 Mon Sep 17 00:00:00 2001 From: Sarath Date: Tue, 16 Jul 2024 12:00:13 +0200 Subject: [PATCH 13/15] add sample parent mapping --- atomrdf/structure.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/atomrdf/structure.py b/atomrdf/structure.py index 46df2c0..2fa0a86 100644 --- a/atomrdf/structure.py +++ b/atomrdf/structure.py @@ -863,11 +863,16 @@ def add_property_mappings(self, output_property, mapping_quantity=None): if not isinstance(output_property, Property): return - #add mappings to the graph + #if the property is a directly calculated value parent_samples = list([x[0] for x in self.graph.triples((None, CMSO.hasCalculatedProperty, output_property._parent))]) - for parent_sample in parent_samples: - self.graph.add((self.sample, PROV.wasDerivedFrom, parent_sample)) - + if len(parent_samples)>0: + for parent_sample in parent_samples: + self.graph.add((self.sample, PROV.wasDerivedFrom, parent_sample)) + else: + #this is quantity that is derived -> for example volume/3 -> it has only sample parent, but no direct connection + if output_property._sample_parent is not None: + self.graph.add((self.sample, PROV.wasDerivedFrom, output_property._sample_parent)) + if mapping_quantity=='lattice_constant': #add lattice constant mapping material = self.graph.value(self.sample, CMSO.hasMaterial) From f1f3d6d202bdf9d24937fe44d26ce1d43625152b Mon Sep 17 00:00:00 2001 From: Sarath Date: Tue, 16 Jul 2024 12:06:56 +0200 Subject: [PATCH 14/15] add workflow linking example --- .../06_linking_calculations.ipynb | 407 ++++++++++++++++++ 1 file changed, 407 insertions(+) create mode 100644 examples/workflow_examples/06_linking_calculations.ipynb diff --git a/examples/workflow_examples/06_linking_calculations.ipynb b/examples/workflow_examples/06_linking_calculations.ipynb new file mode 100644 index 0000000..c7120a0 --- /dev/null +++ b/examples/workflow_examples/06_linking_calculations.ipynb @@ -0,0 +1,407 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Linking calculations" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "%config IPCompleter.evaluation='unsafe'" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "10ca3afd28c24e45935e4673526b8e2c", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from pyiron_atomistics import Project\n", + "from atomrdf import KnowledgeGraph\n", + "import numpy as np" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "project = 'wf9d52b'\n", + "pr = Project(project)\n", + "kg = KnowledgeGraph(store='db', store_file=f'{project}.db')\n", + "kg.enable_workflow(pr, workflow_environment='pyiron')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Run a MD simulation; and get the relaxed structure" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The job j1 was saved and received the ID: 1148\n" + ] + } + ], + "source": [ + "structure = pr.create.structure.annotated_structure.bulk('Cu', cubic=True, label='cu_min', repetitions=(3,3,3))\n", + "job = pr.create.job.Lammps('j1', delete_existing_job=True, delete_aborted_job=True)\n", + "job.structure = structure\n", + "job.potential = '2001--Mishin-Y--Cu-1--LAMMPS--ipr1'\n", + "job.calc_minimize(pressure=0)\n", + "job.run()\n", + "kg.add_workflow(job, workflow_environment='pyiron')" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[cu_min, sample:a7f6ce8a-ce7d-4609-9aa3-56d7ddf21947_from_cu_min]" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "kg.samples" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "sample = kg.samples[-1]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The relaxed structure values are also calculation outputs" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "TotalEnergy, TotalVolume, SimulationCellLength_x, SimulationCellLength_y, SimulationCellLength_z, Volume, NumberOfAtoms" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sample.outputs" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "a = sample.outputs.SimulationCellLength_x/3" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3.615 ANGSTROM" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "a" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now create a new structure with this and run a MD simulation" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "rel_struct = pr.create.structure.annotated_structure.bulk('Cu', cubic=True, label='cu_new',\n", + " a=a, repetitions=(3,3,3))" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The job j1 was saved and received the ID: 1148\n" + ] + } + ], + "source": [ + "job = pr.create.job.Lammps('j1', delete_existing_job=True, delete_aborted_job=True)\n", + "job.structure = rel_struct\n", + "job.potential = '2001--Mishin-Y--Cu-1--LAMMPS--ipr1'\n", + "job.calc_md(pressure=0, temperature=300)\n", + "job.run()\n", + "kg.add_workflow(job, workflow_environment='pyiron')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Check the KG" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sample_a7f6ce8a-ce7d-4609-9aa3-56d7ddf21947\n", + "\n", + "sample_a7f6ce8a-ce7d-4609-9aa3-56d7ddf21947\n", + "\n", + "\n", + "\n", + "sample_ef711752-603e-4b84-8f77-7b9e03132d48\n", + "\n", + "sample_ef711752-603e-4b84-8f77-7b9e03132d48\n", + "\n", + "\n", + "\n", + "sample_a7f6ce8a-ce7d-4609-9aa3-56d7ddf21947->sample_ef711752-603e-4b84-8f77-7b9e03132d48\n", + "\n", + "\n", + "wasDerivedFrom\n", + "\n", + "\n", + "\n", + "activity_4f1b4767-6502-4f00-b35b-c6bb613d26de\n", + "\n", + "activity_4f1b4767-6502-4f00-b35b-c6bb613d26de\n", + "\n", + "\n", + "\n", + "sample_a7f6ce8a-ce7d-4609-9aa3-56d7ddf21947->activity_4f1b4767-6502-4f00-b35b-c6bb613d26de\n", + "\n", + "\n", + "wasGeneratedBy\n", + "\n", + "\n", + "\n", + "sample_60996d0a-82b3-4812-a61f-9029e9e57ca8\n", + "\n", + "sample_60996d0a-82b3-4812-a61f-9029e9e57ca8\n", + "\n", + "\n", + "\n", + "sample_60996d0a-82b3-4812-a61f-9029e9e57ca8->sample_a7f6ce8a-ce7d-4609-9aa3-56d7ddf21947\n", + "\n", + "\n", + "wasDerivedFrom\n", + "\n", + "\n", + "\n", + "sample_536d4ce9-8b97-4f0e-a7d0-4d82beee4fe9\n", + "\n", + "sample_536d4ce9-8b97-4f0e-a7d0-4d82beee4fe9\n", + "\n", + "\n", + "\n", + "sample_536d4ce9-8b97-4f0e-a7d0-4d82beee4fe9->sample_60996d0a-82b3-4812-a61f-9029e9e57ca8\n", + "\n", + "\n", + "wasDerivedFrom\n", + "\n", + "\n", + "\n", + "activity_c2b6577c-a338-4276-90ca-f372f3085c00\n", + "\n", + "activity_c2b6577c-a338-4276-90ca-f372f3085c00\n", + "\n", + "\n", + "\n", + "sample_536d4ce9-8b97-4f0e-a7d0-4d82beee4fe9->activity_c2b6577c-a338-4276-90ca-f372f3085c00\n", + "\n", + "\n", + "wasGeneratedBy\n", + "\n", + "\n", + "\n" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "kg.visualise(sample_view=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can also query and see the lattice parameter was calculated by an activity" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
LatticeParameterwasCalculatedBy
0sample:60996d0a-82b3-4812-a61f-9029e9e57ca8_La...operation:04fc5b80-11c0-4b7f-9125-0e04516807c6
\n", + "
" + ], + "text/plain": [ + " LatticeParameter \\\n", + "0 sample:60996d0a-82b3-4812-a61f-9029e9e57ca8_La... \n", + "\n", + " wasCalculatedBy \n", + "0 operation:04fc5b80-11c0-4b7f-9125-0e04516807c6 " + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "kg.auto_query(kg.terms.cmso.LatticeParameter, [kg.terms.asmo.wasCalculatedBy])" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "workflow-rdf", + "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.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From ac6765e985f37d070b6723fe7bdcccc71c925866 Mon Sep 17 00:00:00 2001 From: Sarath Date: Tue, 16 Jul 2024 12:10:17 +0200 Subject: [PATCH 15/15] =?UTF-8?q?Bump=20version:=200.9.4=20=E2=86=92=200.9?= =?UTF-8?q?.5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .bumpversion.cfg | 2 +- CITATION.cff | 2 +- setup.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index cd03bf6..b5f1cbb 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 0.9.4 +current_version = 0.9.5 commit = True tag = False diff --git a/CITATION.cff b/CITATION.cff index 3c3d542..987bab5 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -19,4 +19,4 @@ url: 'https://atomrdf.pyscal.org' license: "MIT" repository-code: https://github.com/pyscal/atomRDF type: software -version: 0.9.4 +version: 0.9.5 diff --git a/setup.py b/setup.py index f7246b1..ddf1700 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ setup( name='atomrdf', - version='0.9.4', + version='0.9.5', author='Abril Azocar Guzman, Sarath Menon', author_email='sarath.menon@pyscal.org', description='Ontology based structural manipulation and quering',