-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit edfb07c
Showing
963 changed files
with
182,475 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
/.tox/ | ||
/build/ | ||
/dist/ | ||
*.egg-info | ||
__pycache__/ | ||
|
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# Sphinx build info version 1 | ||
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. | ||
config: 86d260a3fe4cd9f79d6a9487e7db2411 | ||
tags: 645f666f9bcd5a90fca523b33c5a78b7 |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added
BIN
+50.7 KB
docs/build/html/.doctrees/references/potentials/inversepowerlaw.doctree
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added
BIN
+3.61 KB
...baf011e8813032544797131a62636ea6cfb5a6ddc6f4e9b593100f7385a-fig_4-kspace-demo_001.json.gz
Binary file not shown.
Binary file added
BIN
+769 Bytes
...4615fd1197d8da8378f97a68eed9983f9bffce2bfb97175314-fig_2-neighbor-lists-usage_001.json.gz
Binary file not shown.
Binary file added
BIN
+164 KB
...4b132c5b2c9a08f9d4b77057dd9457a0cc9975e0f29ed1446363f8e-fig_9-atomistic-model_004.json.gz
Binary file not shown.
Binary file added
BIN
+635 Bytes
...71319c5e6360de2ae7f5082ec3b4f3006b360241ded9d38de274-fig_8-combined-potential_002.json.gz
Binary file not shown.
Binary file added
BIN
+8.64 KB
...bf026993cc7a60cdcecd9189e42acfd83c3f40c9aa4705d646fbd14cf1e71-fig_7-lode-demo_007.json.gz
Binary file not shown.
Binary file added
BIN
+1.15 KB
...bef78e21c5dd05ebaac6f264a72efd460f4d516bcb6dec6b467e53b7efbe0-fig_3-mesh-demo_003.json.gz
Binary file not shown.
Binary file added
BIN
+523 Bytes
...fda4747e22e99aeeb3632208f8cedaa6f446b99e291e50e4055184d3f28e4-fig_3-mesh-demo_002.json.gz
Binary file not shown.
Binary file added
BIN
+3.61 KB
...df7322c295b41254c85629fe042ad24951bcd95ce16d2eec635696bb0db-fig_4-kspace-demo_001.json.gz
Binary file not shown.
Binary file added
BIN
+23.2 KB
...86a0f2a0403870254008b37f71da2f1f80b6157d482a524a043aaa0edd949-fig_7-lode-demo_008.json.gz
Binary file not shown.
Binary file added
BIN
+630 Bytes
...3be26800058eaded4448d2ce81552e3880e5d9da0ee2cf269a4eca4-fig_9-atomistic-model_003.json.gz
Binary file not shown.
Binary file added
BIN
+164 KB
...af114687e3cd838c43c0da6a22c87b1a2b5ee5a3ec6c3b50036af1e-fig_9-atomistic-model_003.json.gz
Binary file not shown.
Binary file added
BIN
+635 Bytes
...4e23e9b1d1db0cd3ad8fc3275c1cd9e138b08897f3d32642c86f-fig_8-combined-potential_002.json.gz
Binary file not shown.
Binary file added
BIN
+4.49 KB
...a82567cb57464c74247cb65701392b87e840f61b4cb8a2035d9b8720832a6-fig_3-mesh-demo_004.json.gz
Binary file not shown.
Binary file added
BIN
+2.62 KB
...d488a3b28116c7dbe748b0657965d0ca8650f5973c2cdfb530f0a67a56bb0-fig_3-mesh-demo_005.json.gz
Binary file not shown.
353 changes: 353 additions & 0 deletions
353
docs/build/html/_downloads/089ecdba78a2a7b2567f668a56b474d2/3-mesh-demo.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,353 @@ | ||
""" | ||
.. _example-mesh-demo: | ||
Examples of the ``MeshInterpolator`` class | ||
========================================== | ||
.. currentmodule:: torchpme | ||
:Authors: Michele Ceriotti `@ceriottm <https://github.com/ceriottm/>`_ | ||
This notebook showcases the functionality of ``torch-pme`` by going | ||
step-by-step through the process of projecting an atom density onto a | ||
grid, and interpolating the grid values on (possibly different) points. | ||
""" | ||
|
||
import ase | ||
import chemiscope | ||
import numpy as np | ||
import torch | ||
from matplotlib import pyplot as plt | ||
|
||
import torchpme | ||
|
||
device = "cpu" | ||
dtype = torch.float64 | ||
rng = torch.Generator() | ||
rng.manual_seed(32) | ||
|
||
# %% | ||
# | ||
# Compute the atom density projection on a mesh | ||
# --------------------------------------------- | ||
# | ||
# Create a rocksalt structure with a regular array of atoms, that we | ||
# will use as example | ||
|
||
structure = ase.Atoms( | ||
positions=[ | ||
[0, 0, 0], | ||
[3, 0, 0], | ||
[0, 3, 0], | ||
[3, 3, 0], | ||
[0, 0, 3], | ||
[3, 0, 3], | ||
[0, 3, 3], | ||
[3, 3, 3], | ||
], | ||
cell=[6, 6, 6], | ||
symbols="NaClClNaClNaNaCl", | ||
) | ||
|
||
# %% | ||
# | ||
# We now slightly displace the atoms from their initial positions randomly based on a | ||
# Gaussian distribution. | ||
|
||
displacement = torch.normal( | ||
mean=0.0, std=2.5e-1, size=(len(structure), 3), generator=rng | ||
) | ||
structure.positions += displacement.numpy() | ||
|
||
chemiscope.show( | ||
frames=[structure], | ||
mode="structure", | ||
settings=chemiscope.quick_settings(structure_settings={"unitCell": True}), | ||
) | ||
|
||
# %% | ||
# | ||
# We also define the charges, with a bit of noise for good measure. (NB: the structure | ||
# won't be charge neutral but it does not matter for this example). | ||
# Also load positions and cells into torch tensors | ||
|
||
charges = torch.tensor( | ||
[[1.0], [-1.0], [-1.0], [1.0], [-1.0], [1.0], [1.0], [-1.0]], | ||
dtype=dtype, | ||
device=device, | ||
) | ||
charges += torch.normal(mean=0.0, std=1e-1, size=(len(charges), 1), generator=rng) | ||
positions = torch.from_numpy(structure.positions).to(device=device, dtype=dtype) | ||
cell = torch.from_numpy(structure.cell.array).to(device=device, dtype=dtype) | ||
|
||
# %% | ||
# | ||
# We now use :class:`MeshInterpolator <lib.MeshInterpolator>` to project | ||
# atomic positions on a grid. Note that ideally the interpolation represents a sharp | ||
# density peaked at atomic positions, so the degree of smoothening depends on the grid | ||
# resolution (as well as on the interpolation nodes) | ||
# | ||
# We demonstrate this by computing a projection on two grids with 3 and 7 mesh points. | ||
|
||
interpolator = torchpme.lib.MeshInterpolator( | ||
cell=cell, ns_mesh=torch.tensor([3, 3, 3]), interpolation_nodes=3, method="P3M" | ||
) | ||
interpolator_fine = torchpme.lib.MeshInterpolator( | ||
cell=cell, ns_mesh=torch.tensor([7, 7, 7]), interpolation_nodes=3, method="P3M" | ||
) | ||
interpolator.compute_weights(positions) | ||
interpolator_fine.compute_weights(positions) | ||
|
||
rho_mesh = interpolator.points_to_mesh(charges) | ||
rho_mesh_fine = interpolator_fine.points_to_mesh(charges) | ||
|
||
# %% | ||
# | ||
# Note that the meshing can be also used for multiple "pseudo-charge" values per atom | ||
# simultaneously. In that case, :func:`points_to_mesh | ||
# <torchpme.lib.MeshInterpolator.points_to_mesh>` will return multiple mesh values. | ||
|
||
pseudo_charges = torch.normal(mean=0, std=1, size=(len(structure), 4)) | ||
pseudo_mesh = interpolator.points_to_mesh(pseudo_charges) | ||
|
||
print(tuple(pseudo_mesh.shape)) | ||
|
||
|
||
# %% | ||
# | ||
# Visualizing the mesh | ||
# -------------------- | ||
# | ||
# One can extract the mesh to visualize the values of the atom density. The grid is | ||
# periodic, so we need some manipulations just for the purpose of visualization. | ||
# It is clear that the finer mesh leads to sharper densities, centered around the | ||
# atom positions. | ||
|
||
fig, ax = plt.subplots( | ||
1, 2, figsize=(8, 4), sharey=True, sharex=True, constrained_layout=True | ||
) | ||
mesh_extent = [ | ||
0, | ||
interpolator.cell[0, 0], | ||
0, | ||
interpolator.cell[1, 1], | ||
] | ||
|
||
z_plot = rho_mesh[0, :, :, 0].detach().numpy() | ||
z_plot = np.vstack([z_plot, z_plot[0, :]]) # Add first row at the bottom | ||
z_plot = np.hstack( | ||
[z_plot, z_plot[:, 0].reshape(-1, 1)] | ||
) # Add first column at the right | ||
|
||
z_min, z_max = (z_plot.min(), z_plot.max()) | ||
|
||
cf = ax[0].imshow( | ||
z_plot, | ||
extent=mesh_extent, | ||
vmin=z_min, | ||
vmax=z_max, | ||
origin="lower", | ||
interpolation="bilinear", | ||
) | ||
|
||
z_plot = rho_mesh_fine[0, :, :, 0].detach().numpy() | ||
z_plot = np.vstack([z_plot, z_plot[0, :]]) # Add first row at the bottom | ||
z_plot = np.hstack( | ||
[z_plot, z_plot[:, 0].reshape(-1, 1)] | ||
) # Add first column at the right | ||
|
||
cf_fine = ax[1].imshow( | ||
z_plot, | ||
extent=mesh_extent, | ||
vmin=z_min, | ||
vmax=z_max, | ||
origin="lower", | ||
interpolation="bilinear", | ||
) | ||
ax[0].set_xlabel("x / Å") | ||
ax[1].set_xlabel("x / Å") | ||
ax[0].set_ylabel("y / Å") | ||
ax[0].set_title(r"$n_{\mathrm{grid}}=3$") | ||
ax[1].set_title(r"$n_{\mathrm{grid}}=7$") | ||
fig.colorbar(cf_fine, label=r"density / e/Å$^3$") | ||
fig.show() | ||
|
||
|
||
# %% | ||
# | ||
# Mesh visualization in chemiscope | ||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
# | ||
# We can also plot the points explicitly together with the structure, adding some | ||
# dummy atoms with a "charge" property | ||
|
||
xyz_mesh = interpolator.get_mesh_xyz().detach().numpy() | ||
dummy = ase.Atoms( | ||
positions=xyz_mesh.reshape(-1, 3), symbols="H" * len(xyz_mesh.reshape(-1, 3)) | ||
) | ||
chemiscope.show( | ||
frames=[structure + dummy], | ||
properties={ | ||
"charge": { | ||
"target": "atom", | ||
"values": np.concatenate([charges.flatten(), rho_mesh[0].flatten()]), | ||
} | ||
}, | ||
mode="structure", | ||
settings=chemiscope.quick_settings( | ||
structure_settings={ | ||
"unitCell": True, | ||
"bonds": False, | ||
"environments": {"activated": False}, | ||
"color": { | ||
"property": "charge", | ||
"min": -0.3, | ||
"max": 0.3, | ||
"transform": "linear", | ||
"palette": "seismic", | ||
}, | ||
} | ||
), | ||
environments=chemiscope.all_atomic_environments([structure + dummy]), | ||
) | ||
|
||
# %% | ||
# | ||
# and for the fine mesh (that again shows clearly how the charge is distributed | ||
# over the neighboring points, and how the mesh size determines the smearing). | ||
|
||
xyz_mesh = interpolator_fine.get_mesh_xyz().detach().numpy() | ||
dummy = ase.Atoms( | ||
positions=xyz_mesh.reshape(-1, 3), symbols="H" * len(xyz_mesh.reshape(-1, 3)) | ||
) | ||
chemiscope.show( | ||
frames=[structure + dummy], | ||
properties={ | ||
"charge": { | ||
"target": "atom", | ||
"values": np.concatenate([charges.flatten(), rho_mesh_fine[0].flatten()]), | ||
} | ||
}, | ||
mode="structure", | ||
settings=chemiscope.quick_settings( | ||
structure_settings={ | ||
"unitCell": True, | ||
"bonds": False, | ||
"environments": {"activated": False}, | ||
"color": { | ||
"property": "charge", | ||
"min": -0.3, | ||
"max": 0.3, | ||
"transform": "linear", | ||
"palette": "seismic", | ||
}, | ||
} | ||
), | ||
environments=chemiscope.all_atomic_environments([structure + dummy]), | ||
) | ||
|
||
# %% | ||
# | ||
# Mesh interpolation | ||
# ------------------ | ||
# | ||
# Once a mesh has been defined, it is possible to use the :class:`MeshInterpolator | ||
# <lib.MeshInterpolator>` object to compute an interpolation of the field on | ||
# the points for which the weights have been computed. | ||
# | ||
# A very important point to grasp is that the charge mapping on the grid is designed to | ||
# conserve the total charge, and so interpolating it back does not (and is not meant | ||
# to!) yield the initial value of the atomic "pseudo-charges". | ||
# | ||
# This is also very clear from the mesh plots above, in which the charge assigned to the | ||
# grid points is much smaller than the atomic charges (that are around ±1). | ||
|
||
mesh_charges = interpolator_fine.mesh_to_points(rho_mesh_fine) | ||
fig, ax = plt.subplots(1, 1, figsize=(6, 4), constrained_layout=True) | ||
|
||
ax.scatter(charges.flatten(), mesh_charges.flatten()) | ||
ax.set_xlabel("pseudo-charges") | ||
ax.set_ylabel("interpolated values") | ||
fig.show() | ||
|
||
# %% | ||
# | ||
# Even though it is not specifically designed for that, :func:`points_to_mesh | ||
# <lib.MeshInterpolator.mesh_to_points>` can interpolate arbitrary functions | ||
# defined on the grid. For instance, here we define a product of sine functions along | ||
# the three Cartesian directions, :math:`\cos(2\pi x/L)\cos(2\pi y/L)\cos(2\pi z/L)` | ||
|
||
xyz_mesh = interpolator_fine.get_mesh_xyz() | ||
mesh_2pil = xyz_mesh * np.pi * 2 / interpolator_fine.cell[0, 0] | ||
f_mesh = ( | ||
torch.cos(mesh_2pil[..., 0]) | ||
* torch.cos(mesh_2pil[..., 1]) | ||
* torch.cos(mesh_2pil[..., 2]) | ||
).reshape(1, *mesh_2pil.shape[:-1]) | ||
|
||
f_points = interpolator_fine.mesh_to_points(f_mesh) | ||
|
||
dummy = ase.Atoms( | ||
positions=xyz_mesh.reshape(-1, 3), symbols="H" * len(xyz_mesh.reshape(-1, 3)) | ||
) | ||
chemiscope.show( | ||
frames=[structure + dummy], | ||
properties={ | ||
"f": { | ||
"target": "atom", | ||
"values": np.concatenate([f_points.flatten(), f_mesh.flatten()]), | ||
} | ||
}, | ||
mode="structure", | ||
settings=chemiscope.quick_settings( | ||
structure_settings={ | ||
"unitCell": True, | ||
"bonds": False, | ||
"environments": {"activated": False}, | ||
"color": { | ||
"property": "f", | ||
"min": -1, | ||
"max": 1, | ||
"transform": "linear", | ||
"palette": "seismic", | ||
}, | ||
} | ||
), | ||
environments=chemiscope.all_atomic_environments([structure + dummy]), | ||
) | ||
|
||
|
||
# %% | ||
# | ||
# Interpolating on different points | ||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
# | ||
# If you want to interpolate on a different set of points than the ones a | ||
# :class:`MeshInterpolator <lib.MeshInterpolator>` object was initialized | ||
# on, it is easy to do by either creating a new one or simply calling again | ||
# :func:`compute_weights | ||
# <torchpme.lib.MeshInterpolator.compute_weights>` for the new set of | ||
# points. | ||
|
||
new_points = torch.normal(mean=3, std=1, size=(10, 3), dtype=dtype, device=device) | ||
interpolator_fine.compute_weights(new_points) | ||
new_f = interpolator_fine.mesh_to_points(f_mesh) | ||
new_ref = ( | ||
torch.cos(new_points[..., 0]) | ||
* torch.cos(new_points[..., 1]) | ||
* torch.cos(new_points[..., 2]) | ||
).reshape(1, *new_points.shape[:-1]) | ||
|
||
|
||
# %% | ||
# Even though the interpolated values are not accurate (this is a pretty | ||
# coarse grid for this function resolution) it is clear that the class can | ||
# interpolate on arbitrary positions of the target points. | ||
|
||
fig, ax = plt.subplots(1, 1, figsize=(6, 4), constrained_layout=True) | ||
|
||
ax.scatter(new_ref.flatten(), new_f.flatten()) | ||
ax.plot([-0.7, 0.7], [-0.7, 0.7], "k--") | ||
ax.set_xlabel(r"$f$ value") | ||
ax.set_ylabel(r"$f$ interpolated") | ||
fig.show() |
Oops, something went wrong.