Skip to content

Commit

Permalink
Remove librascal_atomic_environments
Browse files Browse the repository at this point in the history
  • Loading branch information
Luthaf committed Sep 26, 2024
1 parent 01fca13 commit 39b41be
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 164 deletions.
2 changes: 0 additions & 2 deletions docs/src/python/reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@

.. autofunction:: chemiscope.all_atomic_environments

.. autofunction:: chemiscope.librascal_atomic_environments

.. autofunction:: chemiscope.ellipsoid_from_tensor

.. autofunction:: chemiscope.arrow_from_vector
Expand Down
1 change: 0 additions & 1 deletion python/chemiscope/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
center_shape,
ellipsoid_from_tensor,
extract_properties,
librascal_atomic_environments,
)
from .explore import explore # noqa: F401
from .version import __version__ # noqa: F401
Expand Down
121 changes: 45 additions & 76 deletions python/chemiscope/input.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ def create_input(
:param list environments: optional list of ``(structure id, atom id, cutoff)``
specifying which atoms have properties attached and how far out atom-centered
environments should be drawn by default. Functions like
:py:func:`all_atomic_environments` or :py:func:`librascal_atomic_environments`
can be used to generate the list of environments in simple cases.
:py:func:`all_atomic_environments` can be used to generate the list of
environments in simple cases.
:param dict shapes: optional dictionary of shapes to have available for display,
see below.
:param dict shapes: optional dictionary of shapes to have available for display, see
below.
:param dict settings: optional dictionary of settings to use when displaying the
data. Possible entries for the ``settings`` dictionary are documented in the
Expand All @@ -62,16 +62,10 @@ def create_input(
.. code-block:: python
meta = {
# str, dataset name
"name": "...",
# str, dataset description
"description": "...",
# list of str, dataset authors, OPTIONAL
"authors": [
# str, dataset name "name": "...", # str, dataset description "description":
"...", # list of str, dataset authors, OPTIONAL "authors": [
"...",
],
# list of str, references for this dataset, OPTIONAL
"references": [
], # list of str, references for this dataset, OPTIONAL "references": [
"...",
],
}
Expand All @@ -93,11 +87,8 @@ def create_input(
properties = {
"cheese": {
"target": "atom",
"values": np.zeros((300, 4)),
# optional: property unit
"units": "random / fs",
# optional: property description
"target": "atom", "values": np.zeros((300, 4)), # optional: property
unit "units": "random / fs", # optional: property description
"description": "a random property for example",
}
}
Expand Down Expand Up @@ -129,13 +120,10 @@ def create_input(
properties = {
"cheese": {
"target": "atom",
"values": np.zeros((300, 4)),
# optional: property unit
"units": "random / fs",
# optional: property description
"description": "a random property for examples",
"parameters": ["origin"],
"target": "atom", "values": np.zeros((300, 4)), # optional: property
unit "units": "random / fs", # optional: property description
"description": "a random property for examples", "parameters":
["origin"],
}
}
Expand All @@ -147,13 +135,11 @@ def create_input(
parameters = {
"origin": {
# an array of numbers containing the values of the parameter
# the size should correspond to the second dimension
# of the corresponding multidimensional property
"values": [0, 1, 2, 3],
# optional free-form description of the parameter as a string
"name": "a short description of this parameter",
# optional units of the values in the values array
# an array of numbers containing the values of the parameter # the size
should correspond to the second dimension # of the corresponding
multidimensional property "values": [0, 1, 2, 3], # optional free-form
description of the parameter as a string "name": "a short description of
this parameter", # optional units of the values in the values array
"units": "eV",
}
}
Expand All @@ -169,8 +155,7 @@ def create_input(
shapes = {
"shape name": {
"kind": "sphere",
"parameters": shape_parameters,
"kind": "sphere", "parameters": shape_parameters,
}
}
Expand All @@ -179,17 +164,16 @@ def create_input(
.. code-block:: python
parameters = {
"global": global_parameters,
"structure": [structure_1, structure_2, ...],
"global": global_parameters, "structure": [structure_1, structure_2, ...],
"atom": [atom_1, atom_2, ...],
}
Each of these can contain some or all of the parameters associated with each shape,
and the parameters for each shape are obtained by combining the parameters from the
most general to the most specific, i.e., if there is a duplicate key in the
`global` and `atom` fields, the value within the `atom` field will supersede the
`global` field for that atom. The parameters for atom `k` that is part of structure
`j` are obtained as
most general to the most specific, i.e., if there is a duplicate key in the `global`
and `atom` fields, the value within the `atom` field will supersede the `global`
field for that atom. The parameters for atom `k` that is part of structure `j` are
obtained as
.. code-block:: python
Expand All @@ -202,57 +186,42 @@ def create_input(
.. code-block:: python
# general parameters
{
# general parameters {
# centering (defaults to origin for structure, atom position for atom)
"position": [float, float, float],
# scaling of the size of the shape
"scale": float,
# optional, given as quaternion in (x, y, z, w) format
"orientation": [float, float, float, float],
"color": string | hex_code, # e.g. 0xFF0000
"position": [float, float, float], # scaling of the size of the shape
"scale": float, # optional, given as quaternion in (x, y, z, w) format
"orientation": [float, float, float, float], "color": string | hex_code, #
e.g. 0xFF0000
}
# "kind" : "sphere"
{
# "kind" : "sphere" {
"radius": float,
}
# "kind" : "ellipsoid"
{
# "kind" : "ellipsoid" {
"semiaxes": [float, float, float],
}
# "kind" : "cylinder"
{
# "orientation" is redundant and hence ignored
"vector": [float, float, float], # orientation and shape of the cylinder
# the tip of the cylinder is at the end of the segment.
"radius": float,
# "kind" : "cylinder" {
# "orientation" is redundant and hence ignored "vector": [float, float,
float], # orientation and shape of the cylinder # the tip of the cylinder
is at the end of the segment. "radius": float,
}
# "kind" : "arrow"
{
# "orientation" is redundant and hence ignored
"vector": [float, float, float], # orientation and shape of the arrow
"baseRadius": float,
"headRadius": float,
# the tip of the arrow is at the end of the segment.
# It will extend past the base point if the arrow is not long enough
# "kind" : "arrow" {
# "orientation" is redundant and hence ignored "vector": [float, float,
float], # orientation and shape of the arrow "baseRadius": float,
"headRadius": float, # the tip of the arrow is at the end of the segment. #
It will extend past the base point if the arrow is not long enough
"headLength": float,
}
# "kind" : "custom"
{
# "kind" : "custom" {
"vertices": [ # list of vertices
[float, float, float],
...,
],
# mesh triangulation (optional); computed via convex triangulation
# where omitted
"simplices": [
[int, int, int], # indices refer to the list of vertices
...,
[float, float, float], ...,
], # mesh triangulation (optional); computed via convex triangulation #
where omitted "simplices": [
[int, int, int], # indices refer to the list of vertices ...,
],
}
Expand Down
23 changes: 0 additions & 23 deletions python/chemiscope/structures/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
from ._ase import (
_ase_all_atomic_environments,
_ase_extract_properties,
_ase_librascal_atomic_environments,
_ase_list_atom_properties,
_ase_list_structure_properties,
_ase_to_json,
Expand Down Expand Up @@ -115,25 +114,3 @@ def all_atomic_environments(frames, cutoff=3.5):
return _ase_all_atomic_environments(frames, cutoff)
else:
raise Exception("reached unreachable code")


def librascal_atomic_environments(frames, cutoff=3.5):
"""
Generate the list of environments for the given ``frames``, matching the
behavior used by librascal when computing descriptors for only a subset of
the atomic centers. The optional spherical ``cutoff`` radius is used to
display the environments in chemiscope.
Only ``ase.Atoms`` are supported for the ``frames`` since that's what
librascal uses.
:param frames: iterable over ``ase.Atoms``
:param float cutoff: spherical cutoff radius used when displaying the
environments
"""
frames, adapter = _guess_adapter(frames)

if adapter != "ASE":
raise Exception("librascal_atomic_environments only supports ASE frames")

return _ase_librascal_atomic_environments(frames, cutoff)
19 changes: 0 additions & 19 deletions python/chemiscope/structures/_ase.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,25 +182,6 @@ def _ase_all_atomic_environments(frames, cutoff):
return environments


def _ase_librascal_atomic_environments(frames, cutoff):
"""
Extract atomic environments out of a set of ASE Atoms objects,
using the same convention as librascal
"""
environments = []
for structure_i, frame in enumerate(frames):
if "center_atoms_mask" in frame.arrays:
atoms_iter = np.where(frame.arrays["center_atoms_mask"])[0]
else:
# use all atoms
atoms_iter = range(len(frame))

for atom_i in atoms_iter:
environments.append((structure_i, atom_i, cutoff))

return environments


def _ase_to_json(frame):
"""Implementation of frame_to_json for ase.Atoms"""
data = {}
Expand Down
35 changes: 16 additions & 19 deletions python/examples/2-structure_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,28 +26,27 @@

# %%
#
# Load the SOAP-PCA descriptors. chemiscope does not provide
# analysis routines (yet), but you can look up for instance
# scikit-matter as a package to do dimensionality reduction
# Load the SOAP-PCA descriptors. chemiscope does not provide analysis routines, but you
# can look up for instance scikit-matter as a package to do dimensionality reduction
# analyses.

pca_atom = np.loadtxt("data/trajectory-pca_atom.dat")
pca_struc = np.loadtxt("data/trajectory-pca_structure.dat")
pca_structure = np.loadtxt("data/trajectory-pca_structure.dat")

# %%
#
# When both environments and structure property are present
# only environment properties are shown. Still they can be stored,
# and future versions of chemiscope may allow switching between
# the two modes.
# When both environments and structure property are present, a toggle allows you to
# switch between both modes.
#
# NB: if there are properties stored in the ASE frames, you can extract
# them with chemiscope.extract_properties(frames)
# .. info::
#
# if there are properties stored in the ASE frames, you can extract them with
# chemiscope.extract_properties(frames)

properties = {
# concise definition of a property, with just an array and the type
# inferred by the size
"structure PCA": pca_struc,
"structure PCA": pca_structure,
"atom PCA": pca_atom,
# an example of the verbose definition
"energy": {
Expand All @@ -61,14 +60,12 @@
# %%
#
# Environment descriptors have only been computed for C and O atoms.
# we use a mask and then a utility function to generate the proper
# list of environments
for frame in frames:
frame_mask = np.zeros(len(frame))
frame_mask[np.where((frame.numbers == 6) | (frame.numbers == 8))[0]] = 1
frame.arrays["center_atoms_mask"] = frame_mask

environments = chemiscope.librascal_atomic_environments(frames, cutoff=4.0)
environments = []
cutoff = 4.0
for frame_i, frame in enumerate(frames):
for atom_i, atom in frame.numbers:
if atom == 6 or atom == 8:
environments.append((frame_i, atom_i, cutoff))


# %%
Expand Down
24 changes: 0 additions & 24 deletions python/tests/ase_structures.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,29 +145,5 @@ def test_wrong_property_type(self):
self.assertEqual(len(properties.keys()), 0)


class TestEnvironments(unittest.TestCase):
"""Generate the list of environments"""

def test_librascal_environments(self):
frames = [ase.Atoms("CO2"), ase.Atoms("NH3")]
for frame in frames:
frame.arrays["atomic number"] = frame.numbers

# center_atoms_mask is used by librascal to specify which atoms to consider
frames[1].arrays["center_atoms_mask"] = [True, False, False, False]

environments = chemiscope.librascal_atomic_environments(frames)
self.assertEqual(len(environments), 4)

properties = chemiscope.extract_properties(frames, environments=environments)
atomic_number = properties["atomic number"]
self.assertEqual(atomic_number["target"], "atom")
self.assertEqual(len(atomic_number["values"]), 4)
self.assertEqual(atomic_number["values"][0], 6) # C in CO2
self.assertEqual(atomic_number["values"][1], 8) # O1 in CO2
self.assertEqual(atomic_number["values"][2], 8) # O2 in CO2
self.assertEqual(atomic_number["values"][3], 7) # N in NH3


if __name__ == "__main__":
unittest.main()

0 comments on commit 39b41be

Please sign in to comment.