Getting started#

Ontology based atomic structure creation, manipulation, querying.

Imports

from pyscal_rdf import StructureGraph

First we create a graph

g = StructureGraph()

Creation of structures#

We will create three structures for the demonstration.

First a BCC Iron structure

struct_Fe = g.create.element.Fe()

Note that when the structure is created, it is also added to the Graph automatically. We can visualise the graph.

g.visualise(backend='graphviz')
../_images/7974556dfd3f3b4b4981b335f7d92bae17743aa70936dba739545917ad308f56.svg

Now a Si diamond structure

struct_Si = g.create.element.Si()

Finally, an L12 \(Ni_3 Al\) structure

struct_l12 = g.create.lattice.l12(element=['Al', 'Ni'], 
                         lattice_constant=3.57)
g.visualise(backend='graphviz')
../_images/435d578e96547b3d99814dade18de98047744aae8f2179590fa58305cd279e4d.svg

We can save the graph and reload it as needed

Querying the graph#

An example question would be, what are the space group of all structures with 4 atoms?

The corresponding SPARQL query looks like this:

query = """
PREFIX cmso: <http://purls.helmholtz-metadaten.de/cmso/>
SELECT DISTINCT ?symbol
WHERE {
    ?sample cmso:hasNumberOfAtoms ?number .
    ?sample cmso:hasMaterial ?material .
    ?material cmso:hasStructure ?structure .
    ?structure cmso:hasSpaceGroupSymbol ?symbol .
FILTER (?number="4"^^xsd:integer)
}"""
res = g.query(query)

And print the results

res
symbol

The query system can also be used without experience in SPARQL, or deep knowledge about the ontology terms. For example, What are all the samples with Bravais lattice bcc?

First how this looks like:

res = g.query_sample(g.ontology.terms.cmso.hasAltName, 
             condition=(g.ontology.terms.cmso.hasAltName=='bcc'))
res
---------------------------------------------------------------------------
UnboundLocalError                         Traceback (most recent call last)
Cell In[11], line 1
----> 1 res = g.query_sample(g.ontology.terms.cmso.hasAltName, 
      2              condition=(g.ontology.terms.cmso.hasAltName=='bcc'))
      3 res

File ~/checkouts/readthedocs.org/user_builds/pyscal-rdf/conda/latest/lib/python3.12/site-packages/pyscal_rdf/graph.py:930, in RDFGraph.query_sample(self, destination, condition, return_query, enforce_types)
    929 def query_sample(self, destination, condition=None, return_query=False, enforce_types=True):
--> 930     return self.auto_query(self.ontology.terms.cmso.AtomicScaleSample, destination,
    931         condition=condition, return_query=return_query, enforce_types=enforce_types)

File ~/checkouts/readthedocs.org/user_builds/pyscal-rdf/conda/latest/lib/python3.12/site-packages/pyscal_rdf/graph.py:919, in RDFGraph.auto_query(self, source, destination, condition, return_query, enforce_types)
    916             return res
    917 else:
    918     query = self.ontology.create_query(source, destination, 
--> 919         condition=condition, enforce_types=val)
    920     if return_query:
    921         return query

UnboundLocalError: cannot access local variable 'val' where it is not associated with a value

As expected, there is only one sample, since Fe is the only bcc structure we added. We can extract the sample

sample = res.AtomicScaleSample[0]

We can write this sample to a file, for example, a LAMMPS data format, to use it for further simulations

g.to_file(sample, 'bcc.data', format="lammps-data")
! more bcc.data
bcc.data (written by ASE) 

2 	 atoms 
1  atom types
0.0      2.8700000000000001  xlo xhi
0.0      2.8700000000000001  ylo yhi
0.0      2.8700000000000001  zlo zhi


Atoms 

     1   1                       0                       0                      
 0
     2   1      1.4350000000000001      1.4350000000000001      1.43500000000000
01

We can also export as an ASE object

aseobj = g.to_file(sample, format="ase")
aseobj
Atoms(symbols='Fe2', pbc=True, cell=[2.87, 2.87, 2.87])