-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #20 from LaurentRDC/develop
Develop
- Loading branch information
Showing
16 changed files
with
464 additions
and
164 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
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
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
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
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
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,104 @@ | ||
# -*- coding: utf-8 -*- | ||
""" | ||
Electrostatic potential simulation | ||
================================== | ||
""" | ||
from functools import partial | ||
from .. import chunked, minimum_image_distance, repeated_array | ||
from scipy.special import k0 as bessel | ||
import numpy as np | ||
from numpy import pi | ||
|
||
m = 9.109*10**(-31) #in kg | ||
a0 = 0.5291 #in Angs | ||
e = 14.4 #Volt*Angstrom | ||
|
||
def electrostatic(crystal, x, y, z): | ||
""" | ||
Electrostatic potential from a crystal calculated on a real-space mesh, | ||
assuming an infinite crystal. | ||
Parameters | ||
---------- | ||
crystal : skued.Crystal | ||
x, y, z : `~numpy.ndarray` | ||
Real space coordinates mesh. | ||
Returns | ||
------- | ||
potential : `~numpy.ndarray`, dtype float | ||
Linear superposition of atomic potential [V*Angs] | ||
See also | ||
-------- | ||
pelectrostatic | ||
Projected electrostatic potential from a crystal | ||
""" | ||
# TODO: split xx and yy into smalled non-repeating unit | ||
# TODO: multicore | ||
# TODO: pre-load scattering params _a, _b, _c, and _d into an appropriate shape | ||
|
||
potential = np.zeros_like(x, dtype = np.float) | ||
r = np.zeros_like(x, dtype = np.float) | ||
for atom in crystal: | ||
ax, ay, az = atom.xyz(crystal) | ||
r[:] = minimum_image_distance(x - ax, y - ay, z - az, | ||
lattice = crystal.lattice_vectors) | ||
potential += atom.potential(r) | ||
|
||
# Due to sampling, x,y, and z might pass through the center of atoms | ||
# Replace np.inf by the next largest value | ||
m = potential[np.isfinite(potential)].max() | ||
potential[np.isinf(potential)] = m | ||
return potential | ||
|
||
def pelectrostatic(crystal, xx, yy, bounds = None): | ||
""" | ||
Projected electrostatic potential from a crystal calculated on a real-space mesh, | ||
assuming an infinite crystal. Projection axis is defined as the z-axis. To project the potential | ||
along a different axis, the crystal can be rotated with ``Crystal.transform``. | ||
Parameters | ||
---------- | ||
crystal : skued.Crystal | ||
xx, yy: `~numpy.ndarray` | ||
Real space coordinates mesh. | ||
Returns | ||
------- | ||
potential : `~numpy.ndarray`, dtype float | ||
Linear superposition of atomic potential [V*Angs] | ||
""" | ||
# TODO: split xx and yy into smalled non-repeating unit | ||
# TODO: multicore | ||
# TODO: pre-load scattering params _a, _b, _c, and _d into an appropriate shape | ||
|
||
if bounds: | ||
min_z, max_z = min(bounds), max(bounds) | ||
atoms = (atom for atom in iter(crystal) if min_z <= atom.xyz(crystal)[2] < max_z) | ||
else: | ||
atoms = iter(crystal) | ||
|
||
potential = np.zeros_like(xx) | ||
zz = np.zeros_like(xx) | ||
for atom in atoms: | ||
xa, ya, _ = atom.xyz(crystal) | ||
r = minimum_image_distance(xx - xa, yy - ya, zz, lattice = np.array(crystal.lattice_vectors)).reshape(-1,1) | ||
potential += np.sum( 2*atom._a*bessel(2*pi*r*np.sqrt(atom._b)) + (atom._c/atom._d) * np.exp( -(r*pi)**2 / atom._d), axis = -1).reshape(xx.shape) | ||
potential *= 2 * a0 * e * (pi**2) | ||
|
||
# Due to sampling, x,y, and z might pass through the center of atoms | ||
# Replace n.inf by the next largest value | ||
potential[np.isinf(potential)] = np.nan | ||
potential[np.isnan(potential)] = np.nanmax(potential) | ||
return potential | ||
|
||
def _proj_elec_atm(atom, xx, yy, lattice): | ||
potential = np.zeros_like(xx, dtype = np.float)[:,:,None] | ||
xa, ya, _ = tuple(atom.xyz(lattice)) | ||
r = np.zeros_like(xx)[:,:,None, None] | ||
r[:,:, 0, 0] = minimum_image_distance(xx - xa, yy - ya, np.zeros_like(xx), lattice) | ||
potential = np.sum( 2*atom._a*bessel(2*pi*r*np.sqrt(atom._b)) + (atom._c/atom._d) * np.exp( -(r*pi)**2 / atom._d), axis = -1) | ||
return 2*a0*e*(pi**2)*np.squeeze(potential) |
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,56 @@ | ||
# -*- coding: utf-8 -*- | ||
from .. import electrostatic, pelectrostatic | ||
from ...structure import graphite | ||
from copy import deepcopy | ||
import numpy as np | ||
import unittest | ||
|
||
class TestElectrostatic(unittest.TestCase): | ||
|
||
def setUp(self): | ||
self.crystal = deepcopy(graphite) | ||
|
||
def test_return_shape(self): | ||
""" Test that the return shape of pelectrostatic is the same as input arrays """ | ||
xx, yy, zz = np.meshgrid(np.linspace(-10, 10, 16), np.linspace(-10, 10, 16), np.linspace(-10, 10, 16)) | ||
potential = electrostatic(graphite, xx, yy, zz) | ||
|
||
self.assertSequenceEqual(xx.shape, potential.shape) | ||
|
||
def test_side_effects(self): | ||
""" Test that mesh arrays are not written to in pelectrostatic """ | ||
xx, yy, zz = np.meshgrid(np.linspace(-10, 10, 16), np.linspace(-10, 10, 16), np.linspace(-10, 10, 16)) | ||
|
||
xx.setflags(write = False) | ||
yy.setflags(write = False) | ||
zz.setflags(write = False) | ||
|
||
potential = electrostatic(graphite, xx, yy, zz) | ||
|
||
class TestPElectrostatic(unittest.TestCase): | ||
|
||
def setUp(self): | ||
self.crystal = deepcopy(graphite) | ||
|
||
def test_return_shape(self): | ||
""" Test that the return shape of pelectrostatic is the same as input arrays """ | ||
xx, yy = np.meshgrid(np.linspace(-10, 10, 32), np.linspace(-10, 10, 32)) | ||
potential = pelectrostatic(graphite, xx, yy) | ||
|
||
self.assertSequenceEqual(xx.shape, potential.shape) | ||
|
||
def test_side_effects(self): | ||
""" Test that mesh arrays are not written to in pelectrostatic """ | ||
xx, yy = np.meshgrid(np.linspace(-10, 10, 32), np.linspace(-10, 10, 32)) | ||
xx.setflags(write = False) | ||
yy.setflags(write = False) | ||
potential = pelectrostatic(graphite, xx, yy) | ||
|
||
def test_trivial(self): | ||
""" Test that the projected electrostatic potential from an empty slice of crystal is zero""" | ||
xx, yy = np.meshgrid(np.linspace(-10, 10, 32), np.linspace(-10, 10, 32)) | ||
potential = pelectrostatic(graphite, xx, yy, bounds = (1,2)) | ||
self.assertTrue(np.allclose(potential, 0)) | ||
|
||
if __name__ == '__main__': | ||
unittest.main() |
Oops, something went wrong.