Skip to content

Commit

Permalink
Merge pull request #10 from LaurentRDC/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
LaurentRDC committed Jun 18, 2017
2 parents 8992c91 + c3aac04 commit b0e1a05
Show file tree
Hide file tree
Showing 22 changed files with 379 additions and 457 deletions.
13 changes: 0 additions & 13 deletions .coveragerc

This file was deleted.

25 changes: 19 additions & 6 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,39 @@ scikit-ued
.. image:: https://img.shields.io/appveyor/ci/LaurentRDC/scikit-ued/master.svg
:target: https://ci.appveyor.com/project/LaurentRDC/scikit-ued
:alt: Windows Build Status
.. image:: https://img.shields.io/codecov/c/github/LaurentRDC/scikit-ued/master.svg
:target: https://codecov.io/gh/LaurentRDC/scikit-ued
:alt: Test Suite Coverage
.. image:: https://readthedocs.org/projects/scikit-ued/badge/?version=latest
:target: http://scikit-ued.readthedocs.io
:alt: Documentation Build Status
.. image:: https://img.shields.io/pypi/v/scikit-ued.svg
:target: https://pypi.python.org/pypi/scikit-ued
:alt: PyPI Version

Collection of algorithms and functions for ultrafast electron diffraction.

Getting Started with scikit-ued
----------------------------
-------------------------------

scikit-ued is available on PyPI can be installed with `pip <https://pip.pypa.io>`_.::

$ python -m pip install scikit-ued

To install the latest development version from `Github <https://github.com/LaurentRDC/scikit-ued>`_::

$ python -m pip install git+git://github.com/LaurentRDC/scikit-ued.git

Each version is tested against Python 3.5 and 3.6. If you are using a different version, tests can be run
using the standard library's `unittest` module.

After installing scikit-ued you can use it like any other Python module as :code:`skued`.

Citations
---------

If you are using the :code:`skued.baseline` subpackage, consider citing the following publication:

.. [#] L. P. René de Cotret and B. J. Siwick, A general method for baseline-removal in ultrafast
electron powder diffraction data using the dual-tree complex wavelet transform, Struct. Dyn. 4 (2017) DOI: 10.1063/1.4972518.
API Reference
-------------

Expand All @@ -32,8 +47,6 @@ Support / Report Issues

All support requests and issue reports should be
`filed on Github as an issue <https://github.com/LaurentRDC/scikit-ued/issues>`_.
Make sure to follow the template so your request may be as handled as quickly as possible.
Please respect contributors by not using personal contacts for support requests.

License
-------
Expand Down
8 changes: 0 additions & 8 deletions codecov.yml

This file was deleted.

14 changes: 12 additions & 2 deletions docs/source/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,21 @@ Plot Utilities
==============
.. automodule:: skued.plot_utils

Array Utilities
===============
.. automodule:: skued.array_utils

Quantities
==========
.. automodule:: skued.quantities

Voigt Profile
=============
.. automodule:: skued.voigt

Affine Transforms
=================
.. automodule:: skued.transformations
.. automodule:: skued.affine

Structure
=========
Expand All @@ -36,14 +44,16 @@ Structure

Simulation
==========
.. automodule:: skued.simulation.powdersim
.. autofunction:: skued.simulation.powdersim

Baseline-determination
======================
.. autofunction:: skued.baseline.baseline_dt

.. autofunction:: skued.baseline.baseline_dwt

.. autofunction:: skued.baseline.dtcwt

Image Analysis
==============
.. automodule:: skued.image_analysis.powder
Expand Down
4 changes: 3 additions & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'
# needs_sphinx = '1.5'
from datetime import datetime
import alabaster

Expand All @@ -43,6 +43,8 @@

intersphinx_mapping = {'numpy': ('http://docs.scipy.org/doc/numpy/', None)}

napoleon_google_docstring = False

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

Expand Down
53 changes: 43 additions & 10 deletions docs/source/tutorials/structure.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ To create an atom, simply provide its element and coordinates::

copper = Atom(element = 'Cu', coords = [0,0,0])

:code:`Atom` objects are hashable; this means that they can be stored in a :code:`set`. Therefore,
a list of atoms can be reduced into unique atoms using a :code:`set`.

One important feature of the :code:`Atom` class is the possibility to compute the electrostatic
potential across meshes::

Expand Down Expand Up @@ -64,7 +67,7 @@ After plot formatting:
The :code:`Crystal` Class
=========================
Diffraction experiments relying on the redundancy of crystals to get good experimental signals;
hence, handling crystal models is the main feature of the :code:`skued.structure` package.
hence, handling crystal models is the main feature of the :code:`skued.structure` subpackage.

Constructing a :code:`Crystal` object from a file
-------------------------------------------------
Expand Down Expand Up @@ -93,7 +96,7 @@ or the asymmetric unit cell;
2. three lattice vectors;
3. Symmetry operators (optional). These symmetry operators will be applied to the atoms to generate
the full unit cell. Hence, if your iterable of atoms contains the entire unit cell, symmetry operators do
not need to be provided.
not need to be provided. The symmetry operators must be expressed in the reduced (or fractional) basis.

As an example, let's create the simplest crystal structure known:
`alpha-Polonium (simple cubic)<https://en.wikipedia.org/wiki/Polonium#Solid_state_form>`::
Expand All @@ -115,14 +118,10 @@ The :code:`Crystal` object provides some interfaces for easy structure manipulat
from skued.structure import graphite

for atm in graphite: #Loops over atoms in the unit cell
print(atm)

for atm in graphite.unitcell: #equivalent
print(atm)
print(atm.element, atm.coords)

Note that :code:`iter(graphite)` is a generator, whereas :code:`graphite.unitcell` is a list; this
distinction is important when handling large crystals. Also note that iterating over the :code:`crystal.atoms`
attribute may or may not be equivalent to :code:`crystal.unitcell`, due to the way crystals are defined.
Note that iterating over the :code:`crystal.atoms` attribute may or may not be equivalent to
:code:`iter(crystal)`, due to the way crystals are defined.

:code:`Crystal` objects also provide interoperability with :code:`spglib`::

Expand All @@ -142,7 +141,41 @@ super-class. Let's use the built-in example of graphite::

The standard `three lengths and angles` description of a lattice is also accessible::

a, b, c, alpha, beta, gamma = graphite.parameters
a, b, c, alpha, beta, gamma = graphite.lattice_parameters

The unit cell volume (and by extensions, density) is also accessible:

vol = graphite.volume
density = vol/len(graphite)

Scattering utilities
--------------------
:code:`Crystal` objects have a few methods that make life easier when dealing with scattering data and modeling.

The conversion between Miller indices and scattering vectors is available::

from skued.structure import graphite

G = graphite.scattering_vector(1,0,0)
h, k, l = graphite.miller_indices(G) #1, 0, 0

Arrays of Miller indices can be generated for all Miller indices that fall below a bound::

h, k, l = graphite.bounded_reflections(12) # All reflections below 12 Angs^-1

In this example, :code:`h`, :code:`k`, and :code:`l` are arrays of integers; each combined row is a reflection.

Static structure factor calculation is also possible, both for a single reflection and arrays of reflections::

import numpy as np

# For a single reflection
SF = graphite.structure_factor_miller(1, 0, 0)

# For an array of reflections: vectorized calculation
h, k, l = graphite.bounded_reflections(12)
SF = graphite.structure_factor_miller(h, k, l)
SF.shape == h.shape # True

Atomic potential
----------------
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ exclude=./tests/*
max-line-length=120

[bdist_wheel]
universal = 1
universal = 0
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
with open('requirements.txt') as f:
requirements = [line for line in f.read().split('\n') if len(line.strip())]

packages = [BASE_PACKAGE + '.' + x for x in find_packages(os.path.join(base_path, BASE_PACKAGE))]
exclude = {'exclude': ['cif2cell*', 'pdb_cache', 'docs']}
packages = [BASE_PACKAGE + '.' + x for x in find_packages(os.path.join(base_path, BASE_PACKAGE), **exclude)]
if BASE_PACKAGE not in packages:
packages.append(BASE_PACKAGE)

Expand Down
8 changes: 4 additions & 4 deletions skued/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
__author__ = 'Laurent P. René de Cotret'
__email__ = 'laurent.renedecotret@mail.mcgill.ca'
__license__ = 'MIT'
__version__ = '0.4.2' # TODO: automatic versioning
__version__ = '0.4.4' # TODO: automatic versioning?

from .array_utils import repeated_array
from .parallel import pmap, preduce
from .plot_utils import spectrum_colors
from .quantities import lorentz, electron_wavelength, interaction_parameter
from .transformations import (affine_map, transform, change_of_basis, is_basis, translation_matrix,
is_rotation_matrix, rotation_matrix, translation_rotation_matrix,
change_basis_mesh, minimum_image_distance)
from .affine import (affine_map, transform, change_of_basis, is_basis, translation_matrix,
is_rotation_matrix, rotation_matrix, translation_rotation_matrix,
change_basis_mesh, minimum_image_distance)
from .voigt import gaussian, lorentzian, pseudo_voigt
18 changes: 8 additions & 10 deletions skued/transformations.py → skued/affine.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
Inspired by Christoph Gohlke's transformation.py <http://www.lfd.uci.edu/~gohlke/>
"""

import math
import numpy as np

#standard basis
Expand Down Expand Up @@ -64,18 +65,15 @@ def transform(matrix, array):
if matrix.shape not in [(3,3), (4,4)]:
raise ValueError('Input matrix is neither a 3x3 or 4x4 matrix, but \
rather of shape {}.'.format(matrix.shape))


matrix = affine_map(matrix)
# Case of a vector (e.g. position vector):
if array.ndim == 1:

if matrix.shape == (3,3):
matrix = affine_map(matrix)
extended_vector = np.array([0,0,0,1], dtype = array.dtype)
extended_vector[:3] = array
return np.dot(matrix, extended_vector)[:3]

# Transformation matrix is either 3x3 or 4x4. Extend everything to 4x4
matrix, array = affine_map(matrix), affine_map(array)
else:
array = affine_map(array)
return np.dot(matrix, array)

def translation_matrix(direction):
Expand Down Expand Up @@ -134,7 +132,7 @@ def is_basis(basis):

def is_rotation_matrix(matrix):
"""
Checks whether a matrix is orthogonal with unit determinant, properties
Checks whether a matrix is orthogonal with unit determinant (1 or -1), properties
of rotation matrices.
Parameters
Expand All @@ -154,7 +152,7 @@ def is_rotation_matrix(matrix):
# matrix = matrix[:3,:3]

is_orthogonal = np.allclose(np.linalg.inv(matrix), np.transpose(matrix))
unit_determinant = np.allclose(np.linalg.det(matrix), 1)
unit_determinant = np.allclose(abs(np.linalg.det(matrix)), 1)
return is_orthogonal and unit_determinant

def rotation_matrix(angle, axis = [0,0,1]):
Expand All @@ -178,7 +176,7 @@ def rotation_matrix(angle, axis = [0,0,1]):
--------
translation_rotation_matrix
"""
sina, cosa = np.sin(angle), np.cos(angle)
sina, cosa = math.sin(angle), math.cos(angle)

# Make sure direction is a numpy vector of unit length
direction = np.asarray(axis)
Expand Down

0 comments on commit b0e1a05

Please sign in to comment.