Skip to content

Commit

Permalink
Get atom radius from raw
Browse files Browse the repository at this point in the history
  • Loading branch information
jvsguerra committed Oct 24, 2024
1 parent 06c451c commit 78e8b8b
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 156 deletions.
8 changes: 8 additions & 0 deletions AtomPacker/structure/Cage.py
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,14 @@ def _build_cluster(
# Translate the cluster to the center
cluster.positions += center

# Get radii for nanocluster
distances = cluster.get_all_distances()
radii = (distances[distances > 0] / 2).min()
cluster.info.update({"radii": radii})

# Get lattice constants for nanocluster
cluster.info.update({"lattice_constants": lattice_constants})

if optimize:
# Create rotation angles and translations for the cluster
if angles is None:
Expand Down
60 changes: 6 additions & 54 deletions AtomPacker/structure/Cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,11 @@
"""

import os
from typing import Any, Dict, Tuple
from typing import Any, Dict

import ase
import numpy
import pandas
from ase.data import atomic_numbers, covalent_radii
from MDAnalysis import Universe
from plotly.express import scatter_3d

Expand Down Expand Up @@ -53,7 +52,8 @@ def __init__(
# Cluster information
self.atom_type = cluster.get_chemical_symbols()[0]
self.lattice_type = cluster.symmetry
self.lattice_constants = self._get_lattice_constants()
self.lattice_constants = cluster.info.get("lattice_constants")
self.radii = cluster.info.get("radii")

# Atomic information: MDAnalysis Universe
self.universe = self._get_universe()
Expand Down Expand Up @@ -214,7 +214,7 @@ def summary(self) -> pandas.DataFrame:
return pandas.DataFrame.from_dict(
{
"Atom Type": self.atom_type,
"Atom Radius": self._get_radii(),
"Atom Radius": self.radii,
"Cavity Volume (ų)": self._cavity.volume,
"Diameter (maximum)": self.diameter(method="maximum"),
"Diameter (shape)": self.diameter(method="shape"),
Expand All @@ -239,55 +239,7 @@ def _get_distances(self) -> numpy.ndarray:
cluster.
"""
# Calculate distances between atoms
distances = numpy.linalg.norm(
self._cluster.positions[:, numpy.newaxis, :]
- self._cluster.positions[numpy.newaxis, :, :],
axis=-1,
)

return distances

def _get_lattice_constants(
self,
) -> Tuple[float, float, float] | Tuple[float, float] | float:
"""
Get the lattice constants of the cluster.
Returns
-------
Tuple[float, float, float] | Tuple[float, float] | float
The lattice constants of the cluster.
"""
if self.lattice_type == "hcp":
return (
self._cluster.lattice_basis[0, 0],
self._cluster.lattice_basis[2, 2],
)
elif self.lattice_type == "fcc":
return self._cluster.lattice_basis[0, 0]
elif self.lattice_type == "bcc":
return self._cluster.lattice_basis[0, 0]
elif self.lattice_type == "sc":
return self._cluster.lattice_basis[0, 0]

def _get_radii(self) -> float:
"""
Get the radius of the atoms in the cluster.
Returns
-------
float
The radius of the atoms in the cluster.
"""
if len(self._cluster) > 1:
# Calculate distances between atoms
distances = self._get_distances()
# Calculate radii, ignoring self-distances
radii = (distances[distances > 0] / 2).min()
else:
radii = covalent_radii[atomic_numbers[self._cluster.get_chemical_formula()]]

return radii
return self._cluster.get_all_distances()

def _get_universe(self) -> Universe:
"""
Expand Down Expand Up @@ -322,7 +274,7 @@ def _get_universe(self) -> Universe:
) # atom type
universe.add_TopologyAttr(
"radii",
[self._get_radii()] * universe.atoms.n_atoms, # atom radius
[self.radii] * universe.atoms.n_atoms, # atom radius
)
universe.add_TopologyAttr("resids", [1]) # resids
universe.add_TopologyAttr("resnums", [1]) # resnums
Expand Down
6 changes: 2 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ Packing nanoparticle atoms, based on ASE nanocluster, and filter atoms inside a
# Uncomment to preview the cage structure.
>>> # cage.preview()
# 2: Detect cavity
>>> cage.detect_cavity(step=0.25, probe_in=1.4, probe_out=10.0, removal_distance=1.0, volume_cutoff=5.0)
>>> cage.detect_cavity(step=0.6, probe_in=1.4, probe_out=10.0, removal_distance=1.0, volume_cutoff=5.0)
# Uncomment to preview the cavity structure for detection quality control.
>>> # cage.cavity.preview()
# Show volume
Expand Down Expand Up @@ -123,13 +123,11 @@ class Cluster {
+ Universe universe
+ numpy.ndarray volume
# Cavity cavity
# ase.cluster.Cluster cluster
# ase.cluster.Cluster _cluster
+ diameter(str method) float
+ preview(str renderer, float opacity, Dict~str,Any~ **kwargs) void
+ save(str filename) void
# _get_distances() numpy.ndarray
# _get_lattice_constants() Tuple~float~
# _get_radii() float
# _get_universe() Universe
}
}
Expand Down
116 changes: 18 additions & 98 deletions tests/test_cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

from AtomPacker import Cage, Cavity, Cluster
from ase.cluster import FaceCenteredCubic
from ase.data import atomic_numbers, covalent_radii

DATADIR = os.path.join(os.path.abspath(os.path.dirname(__file__)), "data")

Expand Down Expand Up @@ -46,41 +45,24 @@ def cavity(grid, vertices):
)


@pytest.fixture # 1 atom
def atom():
return FaceCenteredCubic(
symbols="Au",
surfaces=[(1, 0, 0), (0, 1, 0), (0, 0, 1)],
layers=[0, 0, 0],
latticeconstant=4.08,
)


@pytest.fixture # 13 atoms
def cluster():
return FaceCenteredCubic(
_cluster = FaceCenteredCubic(
symbols="Au",
surfaces=[(1, 0, 0), (0, 1, 0), (0, 0, 1)],
layers=[1, 1, 1],
latticeconstant=4.08,
)
# Add radius to ase.cluster
distances = _cluster.get_all_distances()
radii = (distances[distances > 0] / 2).min()
_cluster.info.update({"radii": radii})
# Add lattice_constants to ase.cluster
_cluster.info.update({"lattice_constants": 4.08})
return _cluster


def test_one_atom_cluster_distances(pdb, cavity, atom):
cage = Cage()
cage.load(pdb)

# Dummy Cavity
cage.cavity = cavity

# Dummy Cluster
cage.cluster = Cluster(atom, cavity)

# Check distances for one-atom cluster
assert cage.cluster._get_distances() == numpy.array([0])


def test_multi_atom_cluster_distances(pdb, cavity, cluster):
def test_cluster_distances(pdb, cavity, cluster):
cage = Cage()
cage.load(pdb)

Expand All @@ -92,25 +74,11 @@ def test_multi_atom_cluster_distances(pdb, cavity, cluster):

# Check distances for multi-atom cluster
assert (
cage.cluster._cluster.get_all_distances() == cage.cluster._get_distances()
cage.cluster._get_distances() == cage.cluster._cluster.get_all_distances()
).all()


def test_one_atom_cluster_radii(pdb, cavity, atom):
cage = Cage()
cage.load(pdb)

# Dummy Cavity
cage.cavity = cavity

# Dummy Cluster
cage.cluster = Cluster(atom, cavity)

# Check radii for one-atom cluster
assert cage.cluster._get_radii() == [covalent_radii[atomic_numbers["Au"]]]


def test_multi_atom_cluster_radii(pdb, cavity, cluster):
def test_cluster_radii(pdb, cavity, cluster):
cage = Cage()
cage.load(pdb)

Expand All @@ -125,24 +93,10 @@ def test_multi_atom_cluster_radii(pdb, cavity, cluster):
radii = distances[distances > 0].min() / 2

# Check radii for multi-atom cluster
assert cage.cluster._get_radii() == radii
assert cage.cluster.radii == radii


def test_one_atom_cluster_coordinates(pdb, cavity, atom):
cage = Cage()
cage.load(pdb)

# Dummy Cavity
cage.cavity = cavity

# Dummy Cluster
cage.cluster = Cluster(atom, cavity)

# Check coordinates
assert (cage.cluster.coordinates == numpy.array([0, 0, 0])).all()


def test_multi_atom_cluster_coordinates(pdb, cavity, cluster):
def test_cluster_coordinates(pdb, cavity, cluster):
cage = Cage()
cage.load(pdb)

Expand All @@ -165,26 +119,13 @@ def test_cluster_lattice_constants(pdb, cavity, cluster):

# Dummy Cluster
cage.cluster = Cluster(cluster, cavity)
print(cage.cluster.lattice_constants)

# Check lattice constants
assert (cage.cluster.lattice_constants == 4.08).all()


def test_one_atom_cluster_number_of_atoms(pdb, cavity, atom):
cage = Cage()
cage.load(pdb)
assert cage.cluster.lattice_constants == 4.08

# Dummy Cavity
cage.cavity = cavity

# Dummy Cluster
cage.cluster = Cluster(atom, cavity)

# Check number of atoms
assert cage.cluster.number_of_atoms == 1


def test_multi_atom_cluster_number_of_atoms(pdb, cavity, cluster):
def test_cluster_number_of_atoms(pdb, cavity, cluster):
cage = Cage()
cage.load(pdb)

Expand All @@ -198,28 +139,7 @@ def test_multi_atom_cluster_number_of_atoms(pdb, cavity, cluster):
assert cage.cluster.number_of_atoms == 13


def test_one_atom_cluster_maximum_number_of_atoms(pdb, cavity, atom):
cage = Cage()
cage.load(pdb)

# Dummy Cavity
cage.cavity = cavity

# Dummy Cluster
cage.cluster = Cluster(atom, cavity)

# Get maximum number of atoms
maximum_number_of_atoms = numpy.ceil(
numpy.prod(cage.cavity.grid.shape)
* 0.6**3
/ (4 / 3 * numpy.pi * (cage.cluster._get_radii() ** 3)),
).astype(int)

# Check maximum number of atoms
assert cage.cluster.maximum_number_of_atoms == maximum_number_of_atoms


def test_multi_atom_cluster_maximum_number_of_atoms(pdb, cavity, cluster):
def test_cluster_maximum_number_of_atoms(pdb, cavity, cluster):
cage = Cage()
cage.load(pdb)

Expand All @@ -233,7 +153,7 @@ def test_multi_atom_cluster_maximum_number_of_atoms(pdb, cavity, cluster):
maximum_number_of_atoms = numpy.ceil(
numpy.prod(cage.cavity.grid.shape)
* 0.6**3
/ (4 / 3 * numpy.pi * (cage.cluster._get_radii() ** 3)),
/ (4 / 3 * numpy.pi * (cage.cluster.radii**3)),
).astype(int)

# Check maximum number of atoms
Expand Down

0 comments on commit 78e8b8b

Please sign in to comment.