diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 5038855..bc0fcc1 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 0.5.4 +current_version = 0.5.5 commit = True tag = False diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index d7856d1..7f1627f 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -28,5 +28,11 @@ jobs: pip install -e . pip install pytest pip install pytest-cov - pytest tests/ - #pytest --cov-report=xml --cov=pyscal tests/ + #pytest tests/ + pytest --cov-report=xml --cov=atomrdf tests/ + + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v4.0.1 + with: + token: ${{ secrets.CODECOV_TOKEN }} + slug: pyscal/atomRDF \ No newline at end of file diff --git a/CITATION.cff b/CITATION.cff index a7be805..3da4bc0 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -20,4 +20,4 @@ url: 'https://atomrdf.pyscal.org' license: "MIT" repository-code: https://github.com/pyscal/atomRDF type: software -version: 0.5.4 +version: 0.5.5 diff --git a/atomrdf/data/dft_template.yml b/atomrdf/data/dft_template.yml new file mode 100644 index 0000000..af995ca --- /dev/null +++ b/atomrdf/data/dft_template.yml @@ -0,0 +1,29 @@ +method: DensityFunctionalTheory +temperature: 100 +pressure: 0 +dof: +- AtomicPositions +- CellVolume +id: 2314 +xcfunctional: LDA +workflow_manager: + uri: xxxx + label: pyiron +software: +- uri: xxxx + label: lammps +- uri: xxxx + label: pyscal +outputs: +- label: TotalEnergy + value: 2.301 + unit: EV + associate_to_sample: True +- label: TotalVolume + value: 23.01 + unit: ANGSTROM3 + associate_to_sample: True +inputs: +- label: AnotherInput + value: 0.1 + unit: None diff --git a/atomrdf/data/md_template.yml b/atomrdf/data/md_template.yml new file mode 100644 index 0000000..d938133 --- /dev/null +++ b/atomrdf/data/md_template.yml @@ -0,0 +1,34 @@ +method: MolecularStatics +temperature: 100 +pressure: 0 +dof: +- AtomicPositions +- CellVolume +ensemble: NPT +id: 2314 +potential: + uri: https://doi.org/xxx + type: eam + label: string +workflow_manager: + uri: xxxx + label: pyiron +software: +- uri: xxxx + label: lammps +- uri: xxxx + label: pyscal +outputs: +- label: TotalEnergy + value: 2.301 + unit: EV + associate_to_sample: True +- label: TotalVolume + value: 23.01 + unit: ANGSTROM3 + associate_to_sample: True +inputs: +- label: AnotherInput + value: 0.1 + unit: None + diff --git a/atomrdf/graph.py b/atomrdf/graph.py index 1490b63..e94a4a6 100644 --- a/atomrdf/graph.py +++ b/atomrdf/graph.py @@ -128,6 +128,7 @@ def __init__(self, graph_file=None, self._atom_ids = None self.store = store self._n_triples = 0 + self._initialize_graph() def add_structure(self, structure): @@ -180,19 +181,19 @@ def _check_domain_if_uriref(self, triple): break return found, dm - def _check_domain_if_ontoterm(self, triple): - found = True - domain = triple[0].domain - if len(domain) > 0: - if 'owl:Thing' not in domain: - if triple[1].namespace != triple[0].namespace: - #cross ontology term - self.log(f'ignoring possible cross ontology connection between {triple[1].namespace} and {triple[0].namespace}') - return True, None - found = False - if triple[1].name in domain: - found = True - return found, triple[0].name +# def _check_domain_if_ontoterm(self, triple): +# found = True +# domain = triple[0].domain +# if len(domain) > 0: +# if 'owl:Thing' not in domain: +# if triple[1].namespace != triple[0].namespace: +# #cross ontology term +# self.log(f'ignoring possible cross ontology connection between {triple[1].namespace} and {triple[0].namespace}') +# return True, None +# found = False +# if triple[1].name in domain: +# found = True +# return found, triple[0].name def _check_domain(self, triple): @@ -204,8 +205,8 @@ def _check_domain(self, triple): if type(triple[0]).__name__ == 'URIRef': found, dm = self._check_domain_if_uriref(triple) - elif self._is_ontoterm(triple[0]): - found, dm = self._check_domain_if_ontoterm(triple) + #elif self._is_ontoterm(triple[0]): + # found, dm = self._check_domain_if_ontoterm(triple) if not found: raise ValueError(f'{dm} not in domain of {triple[1].name}') @@ -234,20 +235,20 @@ def _check_range_if_uriref(self, triple): break return found, rn - def _check_range_if_ontoterm(self, triple): - found = True - rang = triple[1].range - if len(rang) > 0: - if 'owl:Thing' not in rang: - if triple[1].namespace != triple[2].namespace: - #cross ontology term - self.log(f'ignoring possible cross ontology connection between {triple[1].namespace} and {triple[2].namespace}') - return True, None - - found = False - if triple[2].name in rang: - found = True - return found, triple[2].name +# def _check_range_if_ontoterm(self, triple): +# found = True +# rang = triple[1].range +# if len(rang) > 0: +# if 'owl:Thing' not in rang: +# if triple[1].namespace != triple[2].namespace: +# #cross ontology term +# self.log(f'ignoring possible cross ontology connection between {triple[1].namespace} and {triple[2].namespace}') +# return True, None +# +# found = False +# if triple[2].name in rang: +# found = True +# return found, triple[2].name def _check_range_if_literal(self, triple): @@ -280,8 +281,8 @@ def _check_range(self, triple): if type(triple[2]).__name__ == 'URIRef': found, dm = self._check_range_if_uriref(triple) - elif self._is_ontoterm(triple[2]): - found, dm = self._check_range_if_ontoterm(triple) + #elif self._is_ontoterm(triple[2]): + # found, dm = self._check_range_if_ontoterm(triple) elif type(triple[2]).__name__ == 'Literal': found, dm = self._check_range_if_literal(triple) @@ -363,7 +364,7 @@ def _initialize_graph(self): self.add((CMSO.LatticeVector, RDFS.subClassOf, CMSO.Vector)) self.add((CMSO.SimulationCellVector, RDFS.subClassOf, CMSO.Vector)) - self.add((CMSO.PositionVector, RDFS.subClassOf, CMSO.Vector)) + #self.add((CMSO.PositionVector, RDFS.subClassOf, CMSO.Vector)) self.add((CMSO.Vector, CMSO.hasUnit, URIRef("http://qudt.org/vocab/unit/ANGSTROM"))) @@ -376,13 +377,14 @@ def add_calculated_quantity(self, sample, propertyname, value, unit=None): self.add((prop, CMSO.hasUnit, URIRef(f'http://qudt.org/vocab/unit/{unit}'))) - def inspect_sample(self): + def inspect_sample(self, sample): natoms = self.value(sample, CMSO.hasNumberOfAtoms).toPython() material = list([k[2] for k in self.triples((sample, CMSO.hasMaterial, None))])[0] defects = list([k[2] for k in self.triples((material, CMSO.hasDefect, None))]) composition = list([k[2].toPython() for k in self.triples((material, CMSO.hasElementRatio, None))]) crystalstructure = self.value(material, CMSO.hasStructure) - spacegroupsymbol = self.value(crystalstructure, CMSO.hasSpaceGroupSymbol).toPython() + spacegroup = self.value(crystalstructure, CMSO.hasSpaceGroup) + spacegroupsymbol = self.value(spacegroup, CMSO.hasSpaceGroupSymbol).toPython() lattice = self.value(sample, CMSO.hasNumberOfAtoms).toPython() defect_types = list([self.value(d, RDF.type).toPython() for d in defects]) @@ -557,7 +559,7 @@ def archive(self, package_name, format='turtle', compress=True): #assign corrected path new_relpath = "/".join(['rdf_structure_store', filepath.split('/')[-1]]) - self.graph.add((URIRef(f'{sample}_{val}'), CMSO.hasPath, Literal(new_relpath, datatype=XSD.string))) + self.add((URIRef(f'{sample}_{val}'), CMSO.hasPath, Literal(new_relpath, datatype=XSD.string))) triple_file = os.path.join(package_name, 'triples') self.write(triple_file, format=format) @@ -731,7 +733,7 @@ def get_system_from_sample(self, sample): sys.atoms = at return sys - def to_file(self, sample, filename=None, format="lammps-dump"): + def to_file(self, sample, filename=None, format="poscar"): """ Save a given sample to a file diff --git a/atomrdf/properties.py b/atomrdf/properties.py index 6d35d94..16c493f 100644 --- a/atomrdf/properties.py +++ b/atomrdf/properties.py @@ -80,19 +80,19 @@ def get_basis_positions(system): return system._structure_dict["positions"] return None -def get_basis_occupancy(system): - if system._structure_dict is None: - return None - - if "species" in system._structure_dict.keys(): - occ_numbers = system._structure_dict['species'] - tdict = system.atoms._type_dict - vals = [val for key, val in tdict.items()] +#def get_basis_occupancy(system): +# if system._structure_dict is None: +# return None + +# if "species" in system._structure_dict.keys(): +# occ_numbers = system._structure_dict['species'] +# tdict = system.atoms._type_dict +# vals = [val for key, val in tdict.items()] - if vals[0] is not None: - occ_numbers = [tdict[x] for x in occ_numbers] - return occ_numbers - return None +# if vals[0] is not None: +# occ_numbers = [tdict[x] for x in occ_numbers] +# return occ_numbers +# return None def get_lattice_vector(system): if system._structure_dict is None: diff --git a/atomrdf/structure.py b/atomrdf/structure.py index 38187de..9a1f72e 100644 --- a/atomrdf/structure.py +++ b/atomrdf/structure.py @@ -598,7 +598,7 @@ def add_interstitial_impurities(self, element, void_type='tetrahedral', lattice_ self.graph.remove((chemical_species, None, None)) self.graph.remove((self.sample, CMSO.hasSpecies, None)) - composition = self.schema.material.element_ratio() + composition = sysn.schema.material.element_ratio() valid = False for e, r in composition.items(): if e in element_indetifiers.keys(): diff --git a/atomrdf/visualize.py b/atomrdf/visualize.py index 281bd1c..881ac40 100644 --- a/atomrdf/visualize.py +++ b/atomrdf/visualize.py @@ -35,11 +35,7 @@ def get_string_from_URI(x): #just a normal url split now rawsplit = raw.split("/") if len(rawsplit) > 1: - return ".".join(rawsplit[-2:]), "URIRef" - - rawsplit = raw.split(':') - if len(rawsplit) == 2: - return "_".join(rawsplit), "BNode" + return ".".join(rawsplit[-2:]), "URIRef" #none of the conditions, worked, which means its a hex string return raw, "BNode" diff --git a/atomrdf/workflow/pyiron.py b/atomrdf/workflow/pyiron.py index 8a01032..fd0b90a 100644 --- a/atomrdf/workflow/pyiron.py +++ b/atomrdf/workflow/pyiron.py @@ -83,13 +83,12 @@ def _identify_method(job): ensemble = 'IsothermalisobaricEnsemble' mdict = {} - mdict['md'] = {} - mdict['md']['method'] = md_method - mdict['md']['temperature'] = temp - mdict['md']['pressure'] = press - mdict['md']['dof'] = dof - mdict['md']['ensemble'] = ensemble - mdict['md']['id'] = job.id + mdict['method'] = md_method + mdict['temperature'] = temp + mdict['pressure'] = press + mdict['dof'] = dof + mdict['ensemble'] = ensemble + mdict['id'] = job.id #now process potential inpdict = job.input.to_dict() @@ -101,47 +100,44 @@ def _identify_method(job): if 'url' in potdict[list(potdict.keys())[0]].keys(): url = potdict[list(potdict.keys())[0]]['url'] - mdict['md']['potential'] = {} - mdict['md']['potential']['type'] = ps - mdict['md']['potential']['label'] = name + mdict['potential'] = {} + mdict['potential']['type'] = ps + mdict['potential']['label'] = name if url is not None: - mdict['md']['potential']['uri'] = url + mdict['potential']['uri'] = url else: - mdict['md']['potential']['uri'] = name + mdict['potential']['uri'] = name - mdict['md']['workflow_manager'] = {} - mdict['md']['workflow_manager']['uri'] = "http://demo.fiz-karlsruhe.de/matwerk/E457491" - mdict['md']['workflow_manager']['label'] = "pyiron" + mdict['workflow_manager'] = {} + mdict['workflow_manager']['uri'] = "http://demo.fiz-karlsruhe.de/matwerk/E457491" + mdict['workflow_manager']['label'] = "pyiron" #and finally code details software = {'uri':"http://demo.fiz-karlsruhe.de/matwerk/E447986", 'label':'LAMMPS'} - mdict['md']['software'] = [software] + mdict['software'] = [software] #finally add calculated quantities quantdict = extract_calculated_quantities(job) - mdict['md']['outputs'] = quantdict + mdict['outputs'] = quantdict return mdict def extract_calculated_quantities(job): aen = np.mean(job.output.energy_tot) avol = np.mean(job.output.volume) - outdict = {} - outdict['TotalEnergy'] = {} - outdict['TotalEnergy']['value'] = np.round(aen, decimals=4) - outdict['TotalEnergy']['unit'] = 'EV' - outdict['TotalEnergy']['associate_to_sample'] = True - - - outdict['TotalVolume'] = {} - outdict['TotalVolume']['value'] = np.round(avol, decimals=4) - outdict['TotalVolume']['unit'] = 'ANGSTROM3' - outdict['TotalVolume']['associate_to_sample'] = True - - return outdict + outputs = [] + outputs.append({'label': 'TotalEnergy', + 'value': np.round(aen, decimals=4), + 'unit': 'EV', + 'associate_to_sample': True}) + outputs.append({'label': 'TotalVolume', + 'value': np.round(avol, decimals=4), + 'unit': 'ANGSTROM3', + 'associate_to_sample': True}) + return outputs diff --git a/atomrdf/workflow/workflow.py b/atomrdf/workflow/workflow.py index ff0b3cc..17014e6 100644 --- a/atomrdf/workflow/workflow.py +++ b/atomrdf/workflow/workflow.py @@ -14,7 +14,7 @@ See atomrdf.workflow.pyiron for more details """ -from rdflib import Graph, Literal, Namespace, XSD, RDF, RDFS, BNode, URIRef, FOAF, SKOS, DCTERMS +from rdflib import Literal, Namespace, XSD, RDF, RDFS, BNode, URIRef import warnings import numpy as np @@ -49,9 +49,10 @@ def __init__(self, kg, if environment == 'pyiron': self.wenv = pi else: - raise ValueError('unknow workflow environment') + raise ValueError('unknown workflow environment') def _prepare_job(self, workflow_object): + self.wenv._check_if_job_is_valid(workflow_object) parent_structure, parent_sample, structure, sample = self.wenv._add_structures(workflow_object) method_dict = self.wenv._identify_method(workflow_object) @@ -67,13 +68,15 @@ def _prepare_job(self, workflow_object): if parent_sample is None: #its not added to graph yet - parent_structure.graph = self.kg - parent_structure.to_graph() - parent_sample = parent_structure.sample + if parent_structure is not None: + parent_structure.graph = self.kg + parent_structure.to_graph() + parent_sample = parent_structure.sample self.structure = structure self.sample = sample self.mdict = method_dict + self.main_id = method_dict['id'] self.parent_sample = parent_sample def _get_lattice_properties(self, ): @@ -122,19 +125,19 @@ def _add_inherited_properties(self, ): for defect in parent_defects: new_defect = URIRef(defect.toPython()) - self.kg.graph.add((material, CMSO.hasDefect, new_defect)) + self.kg.add((material, CMSO.hasDefect, new_defect)) #now fetch all defect based info for triple in self.kg.triples((defect, None, None)): - self.kg.graph.add((new_defect, triple[1], triple[2])) + self.kg.add((new_defect, triple[1], triple[2])) #now add the special props for vacancy parent_simcell = self.kg.value(self.sample, CMSO.hasSimulationCell) simcell = self.kg.value(self.parent_sample, CMSO.hasSimulationCell) for triple in self.kg.triples((parent_simcell, PODO.hasVacancyConcentration, None)): - self.kg.graph.add((simcell, triple[1], triple[2])) + self.kg.add((simcell, triple[1], triple[2])) for triple in self.kg.triples((parent_simcell, PODO.hasNumberOfVacancies, None)): - self.kg.graph.add((simcell, triple[1], triple[2])) + self.kg.add((simcell, triple[1], triple[2])) @@ -152,140 +155,131 @@ def add_method(self, ): mdict ----- md: - method: MolecularStatics - temperature: 100 - pressure: 0 - dof: - - AtomicPositions - - CellVolume - ensemble: NPT - id: 2314 - potential: - uri: https://doi.org/xxx - type: eam - label: string - workflow_manager: - uri: xxxx - label: pyiron - software: - - uri: xxxx - label: lammps - - uri: xxxx - label: pyscal """ if self.mdict is None: return - - if 'md' in self.mdict.keys(): - method_type = 'md' - mdict = self.mdict['md'] - elif 'dft' in self.mdict.keys(): - method_type = 'dft' - mdict = self.mdict['dft'] - else: - raise KeyError('method dict keys should be either md or dft') - #add activity - main_id = mdict['id'] - activity = URIRef(f'activity:{main_id}') + #---------------------------------------------------------- + activity = URIRef(f'activity_{self.main_id}') self.kg.add((activity, RDF.type, PROV.Activity)) - #method, this is specific to dft/md - if method_type == 'md': - method = URIRef(f'method:{main_id}') - if mdict['method'] == 'MolecularStatics': - self.kg.add((method, RDF.type, ASMO.MolecularStatics)) - elif mdict['method'] == 'MolecularDynamics': - self.kg.add((method, RDF.type, ASMO.MolecularDynamics)) - elif method_type == 'dft': - method = URIRef(f'method:{main_id}') - if mdict['method'] == 'DensityFunctionalTheory': - self.kg.add((method, RDF.type, ASMO.DensityFunctionalTheory)) + #add method + #---------------------------------------------------------- + method = URIRef(f'method_{self.main_id}') + if self.mdict['method'] == 'MolecularStatics': + self.kg.add((method, RDF.type, ASMO.MolecularStatics)) + elif self.mdict['method'] == 'MolecularDynamics': + self.kg.add((method, RDF.type, ASMO.MolecularDynamics)) + elif self.mdict['method'] == 'DensityFunctionalTheory': + self.kg.add((method, RDF.type, ASMO.DensityFunctionalTheory)) self.kg.add((activity, ASMO.hasComputationalMethod, method)) - if len(mdict['dof']) == 0: - self.kg.add((activity, RDF.type, ASMO.RigidEnergyCalculation)) + #choose if its rigid energy or structure optimisation + #---------------------------------------------------------- + if len(self.mdict['dof']) == 0: + self.kg.add((activity, RDF.type, Namespace("http://purls.helmholtz-metadaten.de/asmo/").RigidEnergyCalculation)) else: self.kg.add((activity, RDF.type, ASMO.StructureOptimization)) - - for dof in mdict['dof']: + #add DOFs + for dof in self.mdict['dof']: self.kg.add((activity, ASMO.hasRelaxationDOF, getattr(ASMO, dof))) - if method_type == 'md': - self.kg.add((method, ASMO.hasStatisticalEnsemble, getattr(ASMO, mdict['ensemble']))) - - #add temperature if needed - if mdict['temperature'] is not None: - temperature = URIRef(f'temperature:{main_id}') - self.kg.add((temperature, RDF.type, ASMO.InputParameter)) - self.kg.add((temperature, RDFS.label, Literal('temperature', datatype=XSD.string))) - self.kg.add((activity, ASMO.hasInputParameter, temperature)) - self.kg.add((temperature, ASMO.hasValue, Literal(mdict['temperature'], datatype=XSD.float))) - self.kg.add((temperature, ASMO.hasUnit, URIRef('http://qudt.org/vocab/unit/K'))) - - if mdict['pressure'] is not None: - pressure = URIRef(f'pressure:{main_id}') - self.kg.add((pressure, RDF.type, ASMO.InputParameter)) - self.kg.add((pressure, RDFS.label, Literal('pressure', datatype=XSD.string))) - self.kg.add((activity, ASMO.hasInputParameter, pressure)) - self.kg.add((pressure, ASMO.hasValue, Literal(mdict['pressure'], datatype=XSD.float))) - self.kg.add((pressure, ASMO.hasUnit, URIRef('http://qudt.org/vocab/unit/GigaPA'))) - - #potentials need to be mapped - potential = URIRef(f'potential:{main_id}') - if 'meam' in mdict['potential']['type']: - self.kg.add((potential, RDF.type, ASMO.ModifiedEmbeddedAtomModel)) - elif 'eam' in mdict['potential']['type']: - self.kg.add((potential, RDF.type, ASMO.EmbeddedAtomModel)) - elif 'lj' in mdict['potential']['type']: - self.kg.add((potential, RDF.type, ASMO.LennardJonesPotential)) - elif 'ace' in mdict['potential']['type']: - self.kg.add((potential, RDF.type, ASMO.MachineLearningPotential)) - else: - self.kg.add((potential, RDF.type, ASMO.InteratomicPotential)) + #add method specific items + if self.mdict['method'] in ['MolecularStatics', 'MolecularDynamics']: + self._add_md(method, activity) + elif self.mdict['method'] in ['DensityFunctionalTheory']: + self._add_dft(method, activity) - if 'uri' in mdict['potential'].keys(): - self.kg.add((potential, CMSO.hasReference, Literal(mdict['potential']['uri'], datatype=XSD.string))) - if 'label' in mdict['potential'].keys(): - self.kg.add((potential, RDFS.label, Literal(mdict['potential']['label']))) + #add that structure was generated + self.kg.add((self.sample, PROV.wasGeneratedBy, activity)) + self._add_inputs(activity) + self._add_outputs(activity) + self._add_software(method) - self.kg.add((method, ASMO.hasInteratomicPotential, potential)) - self.kg.add((self.sample, PROV.wasGeneratedBy, activity)) + def to_graph(self, workflow_object): + self._prepare_job(workflow_object) + self.add_structural_relation() + self.add_method() + + def _add_outputs(self, activity): + if 'outputs' in self.mdict.keys(): + for out in self.mdict['outputs']: + prop = self.kg.create_node(f'{self.main_id}_{out["label"]}', CMSO.CalculatedProperty) + self.kg.add((prop, RDFS.label, Literal(out['label']))) + self.kg.add((prop, ASMO.hasValue, Literal(out["value"]))) + if "unit" in out.keys(): + unit = out['unit'] + self.kg.add((prop, ASMO.hasUnit, URIRef(f'http://qudt.org/vocab/unit/{unit}'))) + self.kg.add((prop, ASMO.wasCalculatedBy, activity)) + if out['associate_to_sample']: + self.kg.add((self.sample, CMSO.hasCalculatedProperty, prop)) + + def _add_inputs(self, activity): + if 'inputs' in self.mdict.keys(): + for inp in self.mdict['inputs']: + prop = self.kg.create_node(f'{self.main_id}_{inp["label"]}', ASMO.InputParameter) + self.kg.add((prop, RDFS.label, Literal(inp['label']))) + self.kg.add((prop, ASMO.hasValue, Literal(inp["value"]))) + if "unit" in inp.keys(): + unit = inp['unit'] + self.kg.add((prop, ASMO.hasUnit, URIRef(f'http://qudt.org/vocab/unit/{unit}'))) + self.kg.add((activity, ASMO.hasInputParameter, prop)) + + def _add_software(self, method): #finally add software wfagent = None - if 'workflow_manager' in mdict.keys(): - wfagent = URIRef(mdict["workflow_manager"]['uri']) - self.kg.add((wfagent, RDF.type, PROV.SoftwareAgent)) - self.kg.add((wfagent, RDFS.label, Literal(mdict["workflow_manager"]['label']))) + if 'workflow_manager' in self.mdict.keys(): + wfagent = self.kg.create_node(self.mdict["workflow_manager"]['uri'], PROV.SoftwareAgent) + self.kg.add((wfagent, RDFS.label, Literal(self.mdict["workflow_manager"]['label']))) self.kg.add((method, PROV.wasAssociatedWith, wfagent)) - - for software in mdict['software']: - agent = URIRef(software['uri']) - self.kg.add((agent, RDF.type, PROV.SoftwareAgent)) - self.kg.add((agent, RDFS.label, Literal(software['label']))) + for software in self.mdict['software']: + agent = self.kg.create_node(software['uri'], PROV.SoftwareAgent) + self.kg.add((agent, RDFS.label, Literal(software['label']))) if wfagent is not None: self.kg.add((wfagent, PROV.actedOnBehalfOf, agent)) else: self.kg.add((method, PROV.wasAssociatedWith, agent)) - for key, val in mdict['outputs'].items(): - prop = URIRef(f'{main_id}_{key}') - self.kg.add((prop, RDF.type, CMSO.CalculatedProperty)) - self.kg.add((prop, RDFS.label, Literal(key))) - self.kg.add((prop, ASMO.hasValue, Literal(val["value"]))) - if "unit" in val.keys(): - unit = val['unit'] - self.kg.add((prop, ASMO.hasUnit, URIRef(f'http://qudt.org/vocab/unit/{unit}'))) - self.kg.add((prop, ASMO.wasCalculatedBy, activity)) - if val['associate_to_sample']: - self.kg.add((self.sample, CMSO.hasCalculatedProperty, prop)) - def to_graph(self, workflow_object): - self._prepare_job(workflow_object) - self.add_structural_relation() - self.add_method() + def _add_md(self, method, activity): + self.kg.add((method, ASMO.hasStatisticalEnsemble, getattr(ASMO, self.mdict['ensemble']))) + + #add temperature if needed + if self.mdict['temperature'] is not None: + temperature = self.kg.create_node(f'temperature_{self.main_id}', ASMO.InputParameter) + self.kg.add((temperature, RDFS.label, Literal('temperature', datatype=XSD.string))) + self.kg.add((activity, ASMO.hasInputParameter, temperature)) + self.kg.add((temperature, ASMO.hasValue, Literal(self.mdict['temperature'], datatype=XSD.float))) + self.kg.add((temperature, ASMO.hasUnit, URIRef('http://qudt.org/vocab/unit/K'))) + + if self.mdict['pressure'] is not None: + pressure = self.kg.create_node(f'pressure_{self.main_id}', ASMO.InputParameter) + self.kg.add((pressure, RDFS.label, Literal('pressure', datatype=XSD.string))) + self.kg.add((activity, ASMO.hasInputParameter, pressure)) + self.kg.add((pressure, ASMO.hasValue, Literal(self.mdict['pressure'], datatype=XSD.float))) + self.kg.add((pressure, ASMO.hasUnit, URIRef('http://qudt.org/vocab/unit/GigaPA'))) + + #potentials need to be mapped + potential = URIRef(f'potential_{self.main_id}') + if 'meam' in self.mdict['potential']['type']: + self.kg.add((potential, RDF.type, ASMO.ModifiedEmbeddedAtomModel)) + elif 'eam' in self.mdict['potential']['type']: + self.kg.add((potential, RDF.type, ASMO.EmbeddedAtomModel)) + elif 'lj' in self.mdict['potential']['type']: + self.kg.add((potential, RDF.type, ASMO.LennardJonesPotential)) + elif 'ace' in self.mdict['potential']['type']: + self.kg.add((potential, RDF.type, ASMO.MachineLearningPotential)) + else: + self.kg.add((potential, RDF.type, ASMO.InteratomicPotential)) + + if 'uri' in self.mdict['potential'].keys(): + self.kg.add((potential, CMSO.hasReference, Literal(self.mdict['potential']['uri'], datatype=XSD.string))) + if 'label' in self.mdict['potential'].keys(): + self.kg.add((potential, RDFS.label, Literal(self.mdict['potential']['label']))) + + self.kg.add((method, ASMO.hasInteratomicPotential, potential)) diff --git a/examples/06_workflow_pyiron.ipynb b/examples/06_workflow_pyiron.ipynb index 4c9e529..e774ba4 100644 --- a/examples/06_workflow_pyiron.ipynb +++ b/examples/06_workflow_pyiron.ipynb @@ -41,13 +41,13 @@ "/home/menon/miniconda3/envs/workflow-rdf-v0.2/lib/python3.11/site-packages/numpy/core/getlimits.py:542: UserWarning: Signature b'\\x00\\xd0\\xcc\\xcc\\xcc\\xcc\\xcc\\xcc\\xfb\\xbf\\x00\\x00\\x00\\x00\\x00\\x00' for does not match any known type: falling back to type probe function.\n", "This warnings indicates broken support for the dtype!\n", " machar = _get_machar(dtype)\n", - "2024-04-16 18:35:17,228 - pyiron_log - WARNING - pyiron found a 'templates' folder in the /home/menon/pyiron/resources resource directory. These are no longer supported in pyiron_base >=0.7.0. They are replaced by Project.create_job_class() and Project.wrap_python_function().\n" + "2024-04-18 12:54:21,059 - pyiron_log - WARNING - pyiron found a 'templates' folder in the /home/menon/pyiron/resources resource directory. These are no longer supported in pyiron_base >=0.7.0. They are replaced by Project.create_job_class() and Project.wrap_python_function().\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "569131161c9642049116b50ce92ca869", + "model_id": "b3e1540e94144972bc50c9b3fdce538f", "version_major": 2, "version_minor": 0 }, @@ -70,7 +70,7 @@ "metadata": {}, "outputs": [], "source": [ - "pr = Project('wf9')" + "pr = Project('wf1a')" ] }, { @@ -120,93 +120,21 @@ "\n", "\n", - "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "\n", "\n", - "sample_0394fcda-2d6a-470a-a72a-1b98ac5ce1a3\n", - "\n", - "sample_0394fcda-2d6a-470a-a72a-1b98ac5ce1a3\n", - "\n", - "\n", - "\n", - "Entity\n", - "\n", - "Entity\n", - "\n", - "\n", - "\n", - "sample_0394fcda-2d6a-470a-a72a-1b98ac5ce1a3->Entity\n", - "\n", - "\n", - "type\n", - "\n", - "\n", - "\n", - "sample_cc0c55d8-fa4c-43ff-8a18-2e1d9e077ca7\n", - "\n", - "sample_cc0c55d8-fa4c-43ff-8a18-2e1d9e077ca7\n", - "\n", - "\n", - "\n", - "sample_cc0c55d8-fa4c-43ff-8a18-2e1d9e077ca7->sample_0394fcda-2d6a-470a-a72a-1b98ac5ce1a3\n", - "\n", - "\n", - "wasDerivedFrom\n", - "\n", - "\n", - "\n", - "sample_cc0c55d8-fa4c-43ff-8a18-2e1d9e077ca7->Entity\n", - "\n", - "\n", - "type\n", - "\n", - "\n", - "\n", - "sample_2c3e9210-84b2-45dd-a7a2-3569907a9d97\n", - "\n", - "sample_2c3e9210-84b2-45dd-a7a2-3569907a9d97\n", - "\n", - "\n", - "\n", - "sample_2c3e9210-84b2-45dd-a7a2-3569907a9d97->Entity\n", - "\n", - "\n", - "type\n", - "\n", - "\n", - "\n", - "sample_51aeb661-2cb8-4036-8e76-27a97fb0f467\n", - "\n", - "sample_51aeb661-2cb8-4036-8e76-27a97fb0f467\n", - "\n", - "\n", - "\n", - "sample_51aeb661-2cb8-4036-8e76-27a97fb0f467->Entity\n", - "\n", - "\n", - "type\n", - "\n", - "\n", - "\n", - "sample_51aeb661-2cb8-4036-8e76-27a97fb0f467->sample_2c3e9210-84b2-45dd-a7a2-3569907a9d97\n", - "\n", - "\n", - "wasDerivedFrom\n", - "\n", - "\n", - "\n", - "sample_3d96246d-ddc5-449c-9a3e-c76411879498\n", - "\n", - "sample_3d96246d-ddc5-449c-9a3e-c76411879498\n", + "sample_d6ce3789-c330-4dc9-be4c-ad2aa3fee411\n", + "\n", + "sample_d6ce3789-c330-4dc9-be4c-ad2aa3fee411\n", "\n", "\n", "\n" ], "text/plain": [ - "" + "" ] }, "execution_count": 7, @@ -268,7 +196,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "The job j1 was saved and received the ID: 8173\n" + "The job j1 was saved and received the ID: 8176\n" ] } ], @@ -303,437 +231,399 @@ "\n", "\n", - "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "\n", "\n", - "sample_0394fcda-2d6a-470a-a72a-1b98ac5ce1a3\n", - "\n", - "sample_0394fcda-2d6a-470a-a72a-1b98ac5ce1a3\n", + "sample_d6ce3789-c330-4dc9-be4c-ad2aa3fee411\n", + "\n", + "sample_d6ce3789-c330-4dc9-be4c-ad2aa3fee411\n", "\n", - "\n", + "\n", "\n", - "sample_cc0c55d8-fa4c-43ff-8a18-2e1d9e077ca7\n", - "\n", - "sample_cc0c55d8-fa4c-43ff-8a18-2e1d9e077ca7\n", + "sample_7c113ec5-bf1f-4c2c-b863-b7bb5b9091b7\n", + "\n", + "sample_7c113ec5-bf1f-4c2c-b863-b7bb5b9091b7\n", "\n", - "\n", + "\n", "\n", - "sample_cc0c55d8-fa4c-43ff-8a18-2e1d9e077ca7->sample_0394fcda-2d6a-470a-a72a-1b98ac5ce1a3\n", - "\n", - "\n", - "wasDerivedFrom\n", + "sample_7c113ec5-bf1f-4c2c-b863-b7bb5b9091b7->sample_d6ce3789-c330-4dc9-be4c-ad2aa3fee411\n", + "\n", + "\n", + "wasDerivedFrom\n", "\n", - "\n", + "\n", "\n", - "sample_2c3e9210-84b2-45dd-a7a2-3569907a9d97\n", - "\n", - "sample_2c3e9210-84b2-45dd-a7a2-3569907a9d97\n", - "\n", - "\n", - "\n", - "sample_51aeb661-2cb8-4036-8e76-27a97fb0f467\n", - "\n", - "sample_51aeb661-2cb8-4036-8e76-27a97fb0f467\n", - "\n", - "\n", - "\n", - "sample_51aeb661-2cb8-4036-8e76-27a97fb0f467->sample_2c3e9210-84b2-45dd-a7a2-3569907a9d97\n", - "\n", - "\n", - "wasDerivedFrom\n", - "\n", - "\n", - "\n", - "sample_3d96246d-ddc5-449c-9a3e-c76411879498\n", - "\n", - "sample_3d96246d-ddc5-449c-9a3e-c76411879498\n", + "activity_8176\n", + "\n", + "activity_8176\n", "\n", - "\n", - "\n", - "sample_97a194be-0485-4135-817e-7a587adae82c\n", - "\n", - "sample_97a194be-0485-4135-817e-7a587adae82c\n", - "\n", - "\n", - "\n", - "sample_97a194be-0485-4135-817e-7a587adae82c->sample_3d96246d-ddc5-449c-9a3e-c76411879498\n", - "\n", - "\n", - "wasDerivedFrom\n", - "\n", - "\n", - "\n", - "activity_8173\n", - "\n", - "activity_8173\n", - "\n", - "\n", - "\n", - "sample_97a194be-0485-4135-817e-7a587adae82c->activity_8173\n", - "\n", - "\n", - "wasGeneratedBy\n", + "\n", + "\n", + "sample_7c113ec5-bf1f-4c2c-b863-b7bb5b9091b7->activity_8176\n", + "\n", + "\n", + "wasGeneratedBy\n", "\n", - "\n", - "\n", - "8173_TotalEnergy\n", - "\n", - "8173_TotalEnergy\n", + "\n", + "\n", + "8176_TotalEnergy\n", + "\n", + "8176_TotalEnergy\n", "\n", - "\n", - "\n", - "sample_97a194be-0485-4135-817e-7a587adae82c->8173_TotalEnergy\n", - "\n", - "\n", - "cmso.hasCalculatedProperty\n", + "\n", + "\n", + "sample_7c113ec5-bf1f-4c2c-b863-b7bb5b9091b7->8176_TotalEnergy\n", + "\n", + "\n", + "cmso.hasCalculatedProperty\n", "\n", - "\n", - "\n", - "8173_TotalVolume\n", - "\n", - "8173_TotalVolume\n", + "\n", + "\n", + "8176_TotalVolume\n", + "\n", + "8176_TotalVolume\n", "\n", - "\n", - "\n", - "sample_97a194be-0485-4135-817e-7a587adae82c->8173_TotalVolume\n", - "\n", - "\n", - "cmso.hasCalculatedProperty\n", + "\n", + "\n", + "sample_7c113ec5-bf1f-4c2c-b863-b7bb5b9091b7->8176_TotalVolume\n", + "\n", + "\n", + "cmso.hasCalculatedProperty\n", "\n", - "\n", - "\n", - "method_8173\n", - "\n", - "method_8173\n", + "\n", + "\n", + "method_8176\n", + "\n", + "method_8176\n", "\n", - "\n", - "\n", - "activity_8173->method_8173\n", - "\n", - "\n", - "asmo.hasComputationalMethod\n", + "\n", + "\n", + "activity_8176->method_8176\n", + "\n", + "\n", + "asmo.hasComputationalMethod\n", "\n", "\n", - "\n", + "\n", "asmo.AtomicPosition\n", - "\n", - "asmo.AtomicPosition\n", + "\n", + "asmo.AtomicPosition\n", "\n", - "\n", - "\n", - "activity_8173->asmo.AtomicPosition\n", - "\n", - "\n", - "asmo.hasRelaxationDOF\n", + "\n", + "\n", + "activity_8176->asmo.AtomicPosition\n", + "\n", + "\n", + "asmo.hasRelaxationDOF\n", "\n", "\n", - "\n", + "\n", "asmo.CellVolume\n", - "\n", - "asmo.CellVolume\n", + "\n", + "asmo.CellVolume\n", "\n", - "\n", - "\n", - "activity_8173->asmo.CellVolume\n", - "\n", - "\n", - "asmo.hasRelaxationDOF\n", + "\n", + "\n", + "activity_8176->asmo.CellVolume\n", + "\n", + "\n", + "asmo.hasRelaxationDOF\n", "\n", - "\n", - "\n", - "temperature_8173\n", - "\n", - "temperature_8173\n", + "\n", + "\n", + "temperature_8176\n", + "\n", + "temperature_8176\n", "\n", - "\n", - "\n", - "activity_8173->temperature_8173\n", - "\n", - "\n", - "asmo.hasInputParameter\n", + "\n", + "\n", + "activity_8176->temperature_8176\n", + "\n", + "\n", + "asmo.hasInputParameter\n", "\n", - "\n", - "\n", - "pressure_8173\n", - "\n", - "pressure_8173\n", + "\n", + "\n", + "pressure_8176\n", + "\n", + "pressure_8176\n", "\n", - "\n", - "\n", - "activity_8173->pressure_8173\n", - "\n", - "\n", - "asmo.hasInputParameter\n", + "\n", + "\n", + "activity_8176->pressure_8176\n", + "\n", + "\n", + "asmo.hasInputParameter\n", "\n", "\n", - "\n", + "\n", "asmo.Isothermal–isobaricEnsemble\n", - "\n", - "asmo.Isothermal–isobaricEnsemble\n", + "\n", + "asmo.Isothermal–isobaricEnsemble\n", "\n", - "\n", - "\n", - "method_8173->asmo.Isothermal–isobaricEnsemble\n", - "\n", - "\n", - "asmo.hasStatisticalEnsemble\n", + "\n", + "\n", + "method_8176->asmo.Isothermal–isobaricEnsemble\n", + "\n", + "\n", + "asmo.hasStatisticalEnsemble\n", "\n", - "\n", - "\n", - "potential_8173\n", - "\n", - "potential_8173\n", + "\n", + "\n", + "potential_8176\n", + "\n", + "potential_8176\n", "\n", - "\n", - "\n", - "method_8173->potential_8173\n", - "\n", - "\n", - "asmo.hasInteratomicPotential\n", + "\n", + "\n", + "method_8176->potential_8176\n", + "\n", + "\n", + "asmo.hasInteratomicPotential\n", "\n", "\n", "\n", "matwerk.E457491\n", - "\n", - "matwerk.E457491\n", + "\n", + "matwerk.E457491\n", "\n", - "\n", - "\n", - "method_8173->matwerk.E457491\n", - "\n", - "\n", - "wasAssociatedWith\n", + "\n", + "\n", + "method_8176->matwerk.E457491\n", + "\n", + "\n", + "wasAssociatedWith\n", "\n", "\n", - "\n", + "\n", "unit.K\n", - "\n", - "unit.K\n", + "\n", + "unit.K\n", "\n", - "\n", - "\n", - "temperature_8173->unit.K\n", - "\n", - "\n", - "asmo.hasUnit\n", + "\n", + "\n", + "temperature_8176->unit.K\n", + "\n", + "\n", + "asmo.hasUnit\n", "\n", - "\n", - "\n", - "33893be5-082f-457c-a724-2d78ba35c377\n", - "\n", - "Temperature\n", + "\n", + "\n", + "c28634b6-575e-4a85-a1a5-6d75bc798da8\n", + "\n", + "Temperature\n", "\n", - "\n", - "\n", - "temperature_8173->33893be5-082f-457c-a724-2d78ba35c377\n", - "\n", - "\n", - "label\n", + "\n", + "\n", + "temperature_8176->c28634b6-575e-4a85-a1a5-6d75bc798da8\n", + "\n", + "\n", + "label\n", "\n", - "\n", - "\n", - "c7172178-e65a-451d-a26e-78211ce3d9e4\n", - "\n", - "500.0\n", + "\n", + "\n", + "28fd3ec9-1c42-4914-a782-37b30dab9227\n", + "\n", + "500.0\n", "\n", - "\n", - "\n", - "temperature_8173->c7172178-e65a-451d-a26e-78211ce3d9e4\n", - "\n", - "\n", - "asmo.hasValue\n", + "\n", + "\n", + "temperature_8176->28fd3ec9-1c42-4914-a782-37b30dab9227\n", + "\n", + "\n", + "asmo.hasValue\n", "\n", "\n", - "\n", + "\n", "unit.GigaPA\n", - "\n", - "unit.GigaPA\n", + "\n", + "unit.GigaPA\n", "\n", - "\n", - "\n", - "pressure_8173->unit.GigaPA\n", - "\n", - "\n", - "asmo.hasUnit\n", + "\n", + "\n", + "pressure_8176->unit.GigaPA\n", + "\n", + "\n", + "asmo.hasUnit\n", "\n", - "\n", - "\n", - "f230d3cb-7144-414d-8b45-7e3d3d5e1022\n", - "\n", - "Pressure\n", + "\n", + "\n", + "20658bc9-06a9-4003-9c13-509e346d5f41\n", + "\n", + "Pressure\n", "\n", - "\n", + "\n", + "\n", + "pressure_8176->20658bc9-06a9-4003-9c13-509e346d5f41\n", + "\n", + "\n", + "label\n", + "\n", + "\n", + "\n", + "0042105c-fd16-4778-aeeb-6408b322a1b6\n", + "\n", + "0.0\n", + "\n", + "\n", + "\n", + "pressure_8176->0042105c-fd16-4778-aeeb-6408b322a1b6\n", + "\n", + "\n", + "asmo.hasValue\n", + "\n", + "\n", + "\n", + "5a0e55bc-afeb-4d22-b5e1-72b8692a6e6c\n", + "\n", + "2001--Mishin-Y--Cu-1--Lammps--Ipr1\n", + "\n", + "\n", "\n", - "pressure_8173->f230d3cb-7144-414d-8b45-7e3d3d5e1022\n", - "\n", - "\n", - "label\n", + "potential_8176->5a0e55bc-afeb-4d22-b5e1-72b8692a6e6c\n", + "\n", + "\n", + "label\n", "\n", - "\n", - "\n", - "9c649324-bb8c-4b5a-a27c-5992e0af8c39\n", - "\n", - "0.0\n", + "\n", + "\n", + "8176_TotalEnergy->activity_8176\n", + "\n", + "\n", + "asmo.wasCalculatedBy\n", "\n", - "\n", + "\n", + "\n", + "unit.EV\n", + "\n", + "unit.EV\n", + "\n", + "\n", + "\n", + "8176_TotalEnergy->unit.EV\n", + "\n", + "\n", + "asmo.hasUnit\n", + "\n", + "\n", + "\n", + "a919bb29-412b-4b7a-8a9e-67c280ab5cbe\n", + "\n", + "Totalenergy\n", + "\n", + "\n", "\n", - "pressure_8173->9c649324-bb8c-4b5a-a27c-5992e0af8c39\n", - "\n", - "\n", - "asmo.hasValue\n", + "8176_TotalEnergy->a919bb29-412b-4b7a-8a9e-67c280ab5cbe\n", + "\n", + "\n", + "label\n", "\n", - "\n", - "\n", - "e6481ff8-7f93-4aed-9b58-9e7550a74af9\n", - "\n", - "2001--Mishin-Y--Cu-1--Lammps--Ipr1\n", + "\n", + "\n", + "30de06a7-9ca9-4b53-b42a-65230b0aa37d\n", + "\n", + "-13.7346\n", "\n", - "\n", + "\n", "\n", - "potential_8173->e6481ff8-7f93-4aed-9b58-9e7550a74af9\n", - "\n", - "\n", - "label\n", + "8176_TotalEnergy->30de06a7-9ca9-4b53-b42a-65230b0aa37d\n", + "\n", + "\n", + "asmo.hasValue\n", "\n", - "\n", - "\n", - "matwerk.E447986\n", - "\n", - "matwerk.E447986\n", + "\n", + "\n", + "8176_TotalVolume->activity_8176\n", + "\n", + "\n", + "asmo.wasCalculatedBy\n", "\n", - "\n", + "\n", + "\n", + "unit.ANGSTROM3\n", + "\n", + "unit.ANGSTROM3\n", + "\n", + "\n", "\n", - "matwerk.E457491->matwerk.E447986\n", - "\n", - "\n", - "actedOnBehalfOf\n", + "8176_TotalVolume->unit.ANGSTROM3\n", + "\n", + "\n", + "asmo.hasUnit\n", "\n", - "\n", - "\n", - "12548f54-03d7-4501-8c43-9f0ad08fe88d\n", - "\n", - "Pyiron\n", + "\n", + "\n", + "64a38d93-403d-471a-91a1-c52bfb00ef77\n", + "\n", + "Totalvolume\n", "\n", - "\n", + "\n", "\n", - "matwerk.E457491->12548f54-03d7-4501-8c43-9f0ad08fe88d\n", - "\n", - "\n", - "label\n", + "8176_TotalVolume->64a38d93-403d-471a-91a1-c52bfb00ef77\n", + "\n", + "\n", + "label\n", "\n", - "\n", - "\n", - "04b8fe58-e7f8-475a-b86b-eb91a6360617\n", - "\n", - "Lammps\n", + "\n", + "\n", + "0358a436-7878-4e47-86de-053abfece585\n", + "\n", + "48.2558\n", "\n", - "\n", + "\n", "\n", - "matwerk.E447986->04b8fe58-e7f8-475a-b86b-eb91a6360617\n", - "\n", - "\n", - "label\n", + "8176_TotalVolume->0358a436-7878-4e47-86de-053abfece585\n", + "\n", + "\n", + "asmo.hasValue\n", "\n", - "\n", - "\n", - "8173_TotalEnergy->activity_8173\n", - "\n", - "\n", - "asmo.wasCalculatedBy\n", + "\n", + "\n", + "matwerk.E447986\n", + "\n", + "matwerk.E447986\n", "\n", - "\n", - "\n", - "unit.EV\n", - "\n", - "unit.EV\n", + "\n", + "\n", + "matwerk.E457491->matwerk.E447986\n", + "\n", + "\n", + "actedOnBehalfOf\n", "\n", - "\n", - "\n", - "8173_TotalEnergy->unit.EV\n", - "\n", - "\n", - "asmo.hasUnit\n", - "\n", - "\n", - "\n", - "79389594-1584-4763-a243-5d35ca8ccf10\n", - "\n", - "Totalenergy\n", - "\n", - "\n", - "\n", - "8173_TotalEnergy->79389594-1584-4763-a243-5d35ca8ccf10\n", - "\n", - "\n", - "label\n", - "\n", - "\n", - "\n", - "eec92a85-1911-49ce-a483-b3d892942b01\n", - "\n", - "-13.7346\n", - "\n", - "\n", - "\n", - "8173_TotalEnergy->eec92a85-1911-49ce-a483-b3d892942b01\n", - "\n", - "\n", - "asmo.hasValue\n", + "\n", + "\n", + "2785804e-e4e8-415d-860b-62fa830b5dfa\n", + "\n", + "Pyiron\n", "\n", - "\n", - "\n", - "8173_TotalVolume->activity_8173\n", - "\n", - "\n", - "asmo.wasCalculatedBy\n", + "\n", + "\n", + "matwerk.E457491->2785804e-e4e8-415d-860b-62fa830b5dfa\n", + "\n", + "\n", + "label\n", "\n", - "\n", - "\n", - "unit.ANGSTROM3\n", - "\n", - "unit.ANGSTROM3\n", + "\n", + "\n", + "3b64e836-85ed-4e47-b3dd-8bea5e000434\n", + "\n", + "Lammps\n", "\n", - "\n", - "\n", - "8173_TotalVolume->unit.ANGSTROM3\n", - "\n", - "\n", - "asmo.hasUnit\n", - "\n", - "\n", - "\n", - "8a700e67-6e09-4d19-861f-6c423d9c28f7\n", - "\n", - "Totalvolume\n", - "\n", - "\n", - "\n", - "8173_TotalVolume->8a700e67-6e09-4d19-861f-6c423d9c28f7\n", - "\n", - "\n", - "label\n", - "\n", - "\n", - "\n", - "fad73c39-653b-4764-a6ae-43e8e1b051ad\n", - "\n", - "48.2558\n", - "\n", - "\n", - "\n", - "8173_TotalVolume->fad73c39-653b-4764-a6ae-43e8e1b051ad\n", - "\n", - "\n", - "asmo.hasValue\n", + "\n", + "\n", + "matwerk.E447986->3b64e836-85ed-4e47-b3dd-8bea5e000434\n", + "\n", + "\n", + "label\n", "\n", "\n", "\n" ], "text/plain": [ - "" + "" ] }, "execution_count": 14, diff --git a/examples/08_dislocation.ipynb b/examples/08_dislocation.ipynb index c5c14f5..9ceae60 100644 --- a/examples/08_dislocation.ipynb +++ b/examples/08_dislocation.ipynb @@ -23,7 +23,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 6, "id": "6e34870d-4172-49e5-b3bb-dbadf6d15cea", "metadata": {}, "outputs": [], @@ -35,7 +35,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 7, "id": "b293bfc3-8dea-437a-82a7-4cd01bc7a2ae", "metadata": {}, "outputs": [], @@ -45,29 +45,38 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 8, "id": "42017ed4-7ea2-4df6-b939-e011280fe96e", "metadata": {}, + "outputs": [], + "source": [ + "sys = System.create.defect.dislocation(burgers_vector,\n", + " slip_vector,\n", + " dislocation_line,\n", + " elastic_constant_dict,\n", + " element='Cu',\n", + " dislocation_type='periodicarray')" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "db1195bc-f810-45f8-9f81-a266b00c095f", + "metadata": {}, "outputs": [ { "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "4defb7646fa54bf288abf1f9f11f514e", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [] + "text/plain": [ + "96" + ] }, + "execution_count": 9, "metadata": {}, - "output_type": "display_data" + "output_type": "execute_result" } ], "source": [ - "sys = System.create.defect.dislocation(burgers_vector,\n", - " slip_vector,\n", - " dislocation_line,\n", - " elastic_constant_dict,\n", - " element='Cu')" + "sys.natoms" ] }, { diff --git a/setup.py b/setup.py index 4808f78..2f2ffa1 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ setup( name='atomrdf', - version='0.5.4', + version='0.5.5', author='Abril Azocar Guzman, Sarath Menon', author_email='sarath.menon@pyscal.org', description='Ontology based structural manipulation and quering', diff --git a/tests/conf.dump b/tests/conf.dump new file mode 100644 index 0000000..37ab323 --- /dev/null +++ b/tests/conf.dump @@ -0,0 +1,11 @@ +ITEM: TIMESTEP +0 +ITEM: NUMBER OF ATOMS +2 +ITEM: BOX BOUNDS pp pp pp +0.0 2.87 +0.0 2.87 +0.0 2.87 +ITEM: ATOMS x y z type id +0.0 0.0 0.0 1 1 +1.435 1.435 1.435 1 2 diff --git a/tests/test_encoder_and_write.py b/tests/test_encoder_and_write.py index e0b4ba0..ff9e45f 100644 --- a/tests/test_encoder_and_write.py +++ b/tests/test_encoder_and_write.py @@ -11,8 +11,14 @@ def test_encoder(): dumpdata = json.dumps(data, cls=NumpyArrayEncoder) assert(np.abs(float(dumpdata.split(',')[-2]) - arr[-2]) < 1E-5) + enc = NumpyArrayEncoder() + assert type(enc.default(np.float64(23))) == float + assert type(enc.default(np.int64(23))) == int + assert type(enc.default(np.array([23]))) == list + def test_writer(tmp_path): arr = np.linspace(0, 10, 100) data = {"array": arr} write_file("test_json", data) - assert(os.path.exists("test_json.json")) \ No newline at end of file + assert(os.path.exists("test_json.json")) + diff --git a/tests/test_graph.py b/tests/test_graph.py index 39e2dc3..df7c400 100644 --- a/tests/test_graph.py +++ b/tests/test_graph.py @@ -1,5 +1,8 @@ import pytest +import os from atomrdf import KnowledgeGraph, System +from atomrdf.namespace import CMSO, PLDO +import shutil def test_structuregraph(): s = KnowledgeGraph() @@ -21,4 +24,114 @@ def test_structuregraph(): sys = System.create.element.Fe(graph=s) assert s.n_samples == 1 #res = s.query_sample("NumberOfAtoms", 2) - #assert(len(res) == 1) \ No newline at end of file + #assert(len(res) == 1) + + +def test_logger(): + if os.path.exists('tests/atomrdf.log'): + os.remove('tests/atomrdf.log') + s = KnowledgeGraph(enable_log=True) + s.log('testing-logger') + assert str(type(s.log).__name__) == "method" + +def test_add_structure(): + s = KnowledgeGraph() + sys = System.create.element.Fe() + s.add_structure(sys) + assert sys.sample in s.samples + +def test_add_cross_triple(): + + s = KnowledgeGraph(enable_log=True) + sys = System.create.element.Fe(graph=s) + status, _ = s._check_domain_if_uriref((sys.material, CMSO.hasDefect, PLDO.AntiphaseBoundary)) + assert status == True + + +def test_add_quantity(): + s = KnowledgeGraph(enable_log=True) + sys = System.create.element.Fe(graph=s) + s.add_calculated_quantity(sys.sample, + 'Energy', + str(23), + unit='eV') + cp = s.value(sys.sample, CMSO.hasCalculatedProperty) + val = s.value(cp, CMSO.hasValue) + assert val.toPython() == '23' + + insp = s.inspect_sample(sys.sample) + assert 'Im-3m' in insp + assert '23' in insp + +def test_archive(): + s = KnowledgeGraph(enable_log=True) + sys = System.create.element.Fe(graph=s) + sys = System.create.element.Cu(graph=s) + if os.path.exists('test_archive.tar.gz'): + os.remove('test_archive.tar.gz') + if os.path.exists('test_archive'): + shutil.rmtree('test_archive') + s.archive('test_archive') + assert os.path.exists('test_archive.tar.gz') + + s = KnowledgeGraph.unarchive('test_archive.tar.gz') + assert s.n_samples == 2 + os.remove('test_archive.tar.gz') + shutil.rmtree('test_archive') + +def test_sparql_query(): + kg = KnowledgeGraph() + struct_Fe = System.create.element.Fe(graph=kg) + struct_Si = System.create.element.Si(graph=kg) + struct_l12 = System.create.lattice.l12(element=['Al', 'Ni'], + lattice_constant=3.57, graph=kg) + query = """ + PREFIX cmso: + SELECT DISTINCT ?symbol + WHERE { + ?sample cmso:hasNumberOfAtoms ?number . + ?sample cmso:hasMaterial ?material . + ?material cmso:hasStructure ?structure . + ?structure cmso:hasSpaceGroup ?spgroup . + ?spgroup cmso:hasSpaceGroupSymbol ?symbol . + FILTER (?number="4"^^xsd:integer) + }""" + res = kg.query(query) + assert res.symbol.values[0].toPython() == 'Pm-3m' + + res = kg.query_sample(kg.ontology.terms.cmso.hasAltName, + condition=(kg.ontology.terms.cmso.hasAltName=='bcc')) + assert res.hasAltNamevalue.values[0].toPython() == 'bcc' + + res = kg.query_sample(kg.ontology.terms.cmso.hasAltName, + condition=(kg.ontology.terms.cmso.hasAltName=='bcc'), + enforce_types=True) + assert res.hasAltNamevalue.values[0].toPython() == 'bcc' + +def test_extract_sample(): + kg = KnowledgeGraph() + struct_Fe = System.create.element.Fe(graph=kg) + sample_graph, no_atoms = kg.get_sample(struct_Fe.sample, no_atoms=True) + assert no_atoms == 2 + assert sample_graph.samples[0] == struct_Fe.sample + + struct = kg.get_system_from_sample(struct_Fe.sample) + assert len(struct.atoms.positions) == 2 + + kg.to_file(struct_Fe.sample, filename='POSCAR') + assert os.path.exists('POSCAR') + os.remove('POSCAR') + + kg.to_file(struct_Fe.sample, filename='POSCAR', format='cif') + assert os.path.exists('POSCAR') + os.remove('POSCAR') + +#def test_add_domain_ontoterm(): +# from atomrdf.namespace import CMSO, PLDO +# s = KnowledgeGraph() +# sys = System.create.element.Fe(graph=s) +# status, _ = s._check_domain_if_ontoterm((CMSO.Material, CMSO.hasDefect, PLDO.AntiphaseBoundary)) +# assert status == True + + + diff --git a/tests/test_network.py b/tests/test_network.py new file mode 100644 index 0000000..d552d4e --- /dev/null +++ b/tests/test_network.py @@ -0,0 +1,11 @@ +import pytest +import os +from atomrdf import KnowledgeGraph, System +from atomrdf.namespace import CMSO, PLDO +import shutil + + +def test_network_draw(): + s = KnowledgeGraph() + sys = System.create.element.Fe(graph=s) + assert s.ontology.draw() != None \ No newline at end of file diff --git a/tests/test_store.py b/tests/test_store.py new file mode 100644 index 0000000..b3cdb6d --- /dev/null +++ b/tests/test_store.py @@ -0,0 +1,10 @@ +import pytest +import os +from atomrdf import KnowledgeGraph, System +from atomrdf.namespace import CMSO, PLDO +import shutil + + +def test_sqlalchemy(): + s = KnowledgeGraph(store='SQLAlchemy', store_file='aa') + sys = System.create.element.Fe(graph=s) \ No newline at end of file diff --git a/tests/test_structure.py b/tests/test_structure.py new file mode 100644 index 0000000..19795e8 --- /dev/null +++ b/tests/test_structure.py @@ -0,0 +1,82 @@ +import pytest +import os +import numpy as np +from atomrdf import KnowledgeGraph, System +from atomrdf.namespace import CMSO, PLDO +import shutil + +def test_custom(): + kg = KnowledgeGraph() + struct = System.create.lattice.custom([[0. , 0. , 0. ], + [1.435, 1.435, 1.435]], + [1, 1], + [[2.87, 0. , 0. ], + [0. , 2.87, 0. ], + [0. , 0. , 2.87]], + lattice_constant = 2.87, + element='Fe', + graph=kg) + assert kg.value(struct.sample, CMSO.hasNumberOfAtoms).toPython() == 2 + +def test_dislocation(): + burgers_vector = 0.5*np.array([1, 0, -1]) + slip_vector = np.array([1, 1, 1]) + dislocation_line = np.array([1, 0, -1]) + elastic_constant_dict = {'C11': 169, 'C12': 122, 'C44': 75.4} + sys = System.create.defect.dislocation(burgers_vector, + slip_vector, + dislocation_line, + elastic_constant_dict, + element='Cu') + assert sys.natoms == 96 + + sys = System.create.defect.dislocation(burgers_vector, + slip_vector, + dislocation_line, + elastic_constant_dict, + element='Cu', + dislocation_type='periodicarray') + assert sys.natoms == 96 + + +def test_read_in(): + kg = KnowledgeGraph() + struct = System.read.file('tests/conf.dump', graph=kg, lattice='bcc', lattice_constant=2.861) + assert kg.n_samples == 1 + +def test_delete(): + s = KnowledgeGraph() + sys = System.create.element.Fe(graph=s) + sys.delete(indices=[0]) + assert sys.natoms == 1 + ss, n= s.get_sample(sys.sample, no_atoms=True) + assert n==1 + + s = KnowledgeGraph() + sys = System.create.element.Fe(graph=s) + del sys[0] + assert sys.natoms == 1 + ss, n= s.get_sample(sys.sample, no_atoms=True) + assert n==1 + +def test_substitute(): + s = KnowledgeGraph() + sys = System.create.element.Fe(graph=s) + sys.substitute_atoms('Li', indices=[0]) + species = s.value(sys.sample, CMSO.hasSpecies) + elements = [k[2] for k in s.triples((species, CMSO.hasElement, None))] + assert len(elements) == 2 + +def test_interstitials(): + s = KnowledgeGraph() + sys = System.create.element.Fe(graph=s) + sys = sys.add_interstitial_impurities(['Li', 'Au'], void_type='tetrahedral') + species = s.value(sys.sample, CMSO.hasSpecies) + elements = [k[2] for k in s.triples((species, CMSO.hasElement, None))] + assert len(elements) == 3 + + sys = System.create.element.Fe(graph=s) + sys = sys.add_interstitial_impurities(['Li', 'Au'], void_type='octahedral') + species = s.value(sys.sample, CMSO.hasSpecies) + elements = [k[2] for k in s.triples((species, CMSO.hasElement, None))] + assert len(elements) == 3 diff --git a/tests/test_term.py b/tests/test_term.py new file mode 100644 index 0000000..89e7f62 --- /dev/null +++ b/tests/test_term.py @@ -0,0 +1,67 @@ +import pytest +import os +from atomrdf import KnowledgeGraph, System +from atomrdf.namespace import CMSO, PLDO +import shutil + +def test_lt(): + kg = KnowledgeGraph() + struct_Fe = System.create.element.Fe(graph=kg) + + term = kg.ontology.terms.cmso.hasNumberOfAtoms + term < 2 + assert term._condition == '(?hasNumberOfAtomsvalue<"2"^^xsd:int)' + +def test_eq(): + kg = KnowledgeGraph() + struct_Fe = System.create.element.Fe(graph=kg) + + term = kg.ontology.terms.cmso.hasNumberOfAtoms + term == 2 + assert term._condition == '(?hasNumberOfAtomsvalue="2"^^xsd:int)' + +def test_gt(): + kg = KnowledgeGraph() + struct_Fe = System.create.element.Fe(graph=kg) + + term = kg.ontology.terms.cmso.hasNumberOfAtoms + term > 2 + assert term._condition == '(?hasNumberOfAtomsvalue>"2"^^xsd:int)' + +def test_lte(): + kg = KnowledgeGraph() + struct_Fe = System.create.element.Fe(graph=kg) + + term = kg.ontology.terms.cmso.hasNumberOfAtoms + term <= 2 + assert term._condition == '(?hasNumberOfAtomsvalue<="2"^^xsd:int)' + +def test_gte(): + kg = KnowledgeGraph() + struct_Fe = System.create.element.Fe(graph=kg) + + term = kg.ontology.terms.cmso.hasNumberOfAtoms + term >= 2 + assert term._condition == '(?hasNumberOfAtomsvalue>="2"^^xsd:int)' + +def test_ne(): + kg = KnowledgeGraph() + struct_Fe = System.create.element.Fe(graph=kg) + + term = kg.ontology.terms.cmso.hasNumberOfAtoms + term != 2 + assert term._condition == '(?hasNumberOfAtomsvalue!="2"^^xsd:int)' + +def test_and(): + kg = KnowledgeGraph() + struct_Fe = System.create.element.Fe(graph=kg) + + term = (kg.ontology.terms.cmso.hasVolume > 2) & (kg.ontology.terms.cmso.hasVolume < 4) + assert term._condition == '((?hasVolumevalue<"4"^^xsd:float)&&(?hasVolumevalue<"4"^^xsd:float))' + +def test_or(): + kg = KnowledgeGraph() + struct_Fe = System.create.element.Fe(graph=kg) + + term = (kg.ontology.terms.cmso.hasVolume > 2) | (kg.ontology.terms.cmso.hasVolume < 4) + assert term._condition == '((?hasVolumevalue<"4"^^xsd:float)||(?hasVolumevalue<"4"^^xsd:float))' \ No newline at end of file diff --git a/tests/test_visualise.py b/tests/test_visualise.py new file mode 100644 index 0000000..c01770f --- /dev/null +++ b/tests/test_visualise.py @@ -0,0 +1,29 @@ +import pytest +import os +import numpy as np +from atomrdf import KnowledgeGraph, System +from atomrdf.namespace import CMSO, PLDO +import shutil +import atomrdf.visualize as viz + + +def test_switch_box(): + assert viz._switch_box("box") == "rectangle" + +def test_fix_id(): + assert viz._fix_id('hello', 'random') == 'hello' + assert viz._fix_id('hello', 'Literal') != 'hello' + +def test_visualise(): + s = KnowledgeGraph() + sys = System.create.element.Cr(graph=s) + + styledict = {"edgecolor": "#D9D9D9", + "BNode": {"color": "#263238"}} + vis = s.visualise(styledict=styledict) + assert(vis != None) + + s = KnowledgeGraph() + sys = System.create.element.Cr(graph=s) + vis = s.visualise(workflow_view=True, hide_types=True) + assert(vis != None) diff --git a/tests/test_workflow.py b/tests/test_workflow.py new file mode 100644 index 0000000..c0d68bc --- /dev/null +++ b/tests/test_workflow.py @@ -0,0 +1,56 @@ +import pytest +import os +import numpy as np +from atomrdf import KnowledgeGraph, System, Workflow +from atomrdf.namespace import CMSO, PLDO +import shutil + +def test_wf_creation(): + s = KnowledgeGraph() + wf = Workflow(s) + +def test_lattice_props(): + s = KnowledgeGraph() + wf = Workflow(s) + parent_sys = System.create.element.Cr(graph=s) + #add some defects + parent_sys.delete(indices=[0]) + child_sys = System.create.element.Cr(graph=s) + #trick workflow and add info + wf.parent_sample = parent_sys.sample + wf.structure = child_sys + wf.sample = child_sys.sample + wf.add_structural_relation() + + +def test_add_method(): + for pot in ['meam', 'eam', 'lj', 'ace', 'nequip']: + s = KnowledgeGraph() + wf = Workflow(s) + parent_sys = System.create.element.Cr(graph=s) + #add some defects + parent_sys.delete(indices=[0]) + child_sys = System.create.element.Cr(graph=s) + #trick workflow and add info + wf.parent_sample = parent_sys.sample + wf.structure = child_sys + wf.sample = child_sys.sample + wf.add_structural_relation() + wf.main_id = 2314 + wf.mdict = {"method": "MolecularDynamics", + "temperature": 100, + "pressure": 0, + "dof": ["AtomicPosition", "CellVolume"], + "ensemble": "IsothermalisobaricEnsemble", + "id": 2314, + "potential": {"uri": "https://doi.org/xxx", + "type": pot, + "label": "string" }, + "workflow_manager": {"uri": "xxxx", + "label": "pyiron"}, + "software": [ {"uri": "xxxx", "label": "lammps"},], + "outputs": [{"label": "TotalEnergy", "value": 2.301, "unit": "EV", + "associate_to_sample": True}], + "inputs": [ {"label": "AnotherInput", "value": 0.1, "unit": None },] + } + wf.add_method()