Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Track lattice constant #143

Merged
merged 15 commits into from
Jul 16, 2024
2 changes: 1 addition & 1 deletion .bumpversion.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 0.9.4
current_version = 0.9.5
commit = True
tag = False

Expand Down
2 changes: 1 addition & 1 deletion CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -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
1 change: 1 addition & 0 deletions atomrdf/network/ontology.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
23 changes: 18 additions & 5 deletions atomrdf/sample.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand All @@ -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
Expand All @@ -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 [], []

Expand All @@ -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):
Expand Down Expand Up @@ -191,51 +192,63 @@ 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))
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, MATH.wasCalculatedBy, operation))
return res_prop

def __sub__(self, value):
res = self._value - self._declass(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))
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, MATH.wasCalculatedBy, operation))
return res_prop

def __mul__(self, value):
res = self._value * self._declass(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))
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, MATH.wasCalculatedBy, operation))
return res_prop

def __truediv__(self, value):
res = self._value / self._declass(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))
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, MATH.wasCalculatedBy, operation))
return res_prop


Expand Down
73 changes: 59 additions & 14 deletions atomrdf/structure.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@

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
from atomrdf.namespace import CMSO, LDO, PLDO, PODO, UNSAFEASMO, UNSAFECMSO, PROV, Literal, ASMO

# read element data file
file_location = os.path.dirname(__file__).split("/")
Expand All @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -98,10 +106,12 @@ 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()
s.add_property_mappings(lattice_constant, mapping_quantity='lattice_constant')
s.add_property_mappings(ca_ratio, mapping_quantity='lattice_constant')
return s


Expand Down Expand Up @@ -152,7 +162,7 @@ def _make_general_lattice(
positions,
types,
box,
lattice_constant=lattice_constant,
lattice_constant=_declass(lattice_constant),
repetitions=repetitions,
noise=noise,
element=element,
Expand All @@ -162,11 +172,12 @@ 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()

s.add_property_mappings(lattice_constant, mapping_quantity='lattice_constant')

return s


Expand Down Expand Up @@ -273,9 +284,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,
Expand All @@ -288,9 +299,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,
Expand Down Expand Up @@ -364,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
Expand Down Expand Up @@ -423,7 +436,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:
Expand All @@ -434,10 +447,12 @@ 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()
s.add_property_mappings(lattice_constant, mapping_quantity='lattice_constant')

gb_dict = {
"GBPlane": " ".join(np.array(gb_plane).astype(str)),
"RotationAxis": axis,
Expand Down Expand Up @@ -506,7 +521,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:
Expand All @@ -523,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


Expand Down Expand Up @@ -840,6 +856,35 @@ def delete(self, ids=None, indices=None, condition=None, selection=False, copy_s

return sys


def add_property_mappings(self, output_property, mapping_quantity=None):
if self.graph is None:
return
if not isinstance(output_property, Property):
return

#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))])
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)
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, UNSAFEASMO.wasCalculatedBy, activity))


def add_vacancy(self, concentration, number=None):
"""
Add Vacancy details which will be annotated by PODO
Expand Down
30 changes: 30 additions & 0 deletions atomrdf/workflow/pyiron/lammps.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
31 changes: 31 additions & 0 deletions atomrdf/workflow/pyiron/murnaghan.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Loading
Loading