Skip to content

Commit

Permalink
Merge pull request #143 from pyscal/track_lattice_constant
Browse files Browse the repository at this point in the history
Track lattice constant
  • Loading branch information
srmnitc authored Jul 16, 2024
2 parents 690b8c6 + ac6765e commit 497519e
Show file tree
Hide file tree
Showing 10 changed files with 578 additions and 22 deletions.
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

0 comments on commit 497519e

Please sign in to comment.