Skip to content

Commit

Permalink
Merge branch 'master' into tests-OM-expansion
Browse files Browse the repository at this point in the history
  • Loading branch information
pc494 committed Feb 28, 2018
2 parents adbf90c + f312256 commit 4e7058a
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 52 deletions.
4 changes: 3 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ sudo: false
before_install:
- "pip install sphinx hyperspy pymatgen Cython transforms3d lxml ipywidgets"
- "pip install sphinx_bootstrap_theme"
- "pip install pytest pytest-cov"
- "pip install coveralls"

install:
- "python setup.py install"
Expand All @@ -16,7 +18,7 @@ before_script:
- "sh -e /etc/init.d/xvfb start"
- sleep 3
script:
- pytest tests
- pytest --cov=pyxem tests
- sphinx-apidoc -fo docs/source pyxem
- sphinx-build -b html docs/source docs/build
after_success:
Expand Down
11 changes: 9 additions & 2 deletions pyxem/signals/electron_diffraction.py
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,7 @@ def get_diffraction_variance(self):
def get_direct_beam_position(self,
method='blur',
sigma=30,
half_shape=72,
*args, **kwargs):
"""Estimate the direct beam position in each experimentally acquired
electron diffraction pattern.
Expand All @@ -470,16 +471,20 @@ def get_direct_beam_position(self,
* 'refine_local' - Refine the position of the direct beam and
hence an estimate for the position of the pattern center in
each SED pattern.
* 'subpixel' - Fits a capped gaussian to data that has already
been roughly centered.
sigma : int
Standard deviation for the gaussian convolution (only for
'blur' method).
half_shape: int
The half shape of the SED patterns, only for subpixel
Returns
-------
centers : ndarray
Array containing the shift to be applied to each SED pattern to
center it.
Array containing the centers for each SED pattern.
"""
#TODO: add sub-pixel capabilities and model fitting methods.
Expand All @@ -494,6 +499,8 @@ def get_direct_beam_position(self,
initial_center=initial_center,
radius=radius,
inplace=False)
elif method == 'subpixel':
centers = self.map(subpixel_beam_finder,half_shape=half_shape,inplace=False)

else:
raise NotImplementedError("The method specified is not implemented. "
Expand Down
38 changes: 38 additions & 0 deletions pyxem/utils/expt_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,16 @@ def _polar2cart(r, theta):
x = r * np.sin(theta)
return x, y

def _capped_gaussian(x,prefactor,sigma,center):
"""
Worker functions for : subpixel_beam_finder()
Creates a 1D Gaussian model, and then truncates all values
greate than 1 to unity. There is no discretisation here.
"""
model_value = prefactor*np.exp(-(x-center)**2/(2*sigma**2))
model_value[np.greater(model_value,np.ones_like(model_value))] = 1 #finite dynamic range
return np.ravel(model_value) #convert this to 1D

def radial_average(z, center,cython=True):
"""Calculate the radial profile by azimuthal averaging about a specified
center.
Expand Down Expand Up @@ -459,6 +469,34 @@ def refine_beam_position(z, start, radius):

return c

def subpixel_beam_finder(single_pattern,half_shape):
"""
This routine is designed to find, to sub-pixel accuracy, the
center of a pattern that has saturated a detector. The noise
model is Gaussian. The input dp should be approximately (within about 3
pixels) centered. Use one of the other centering methods to achieve this.
single_pattern : numpy array : A dp (for .map purposes)
half_shape : int : An int for the approx center of the pattern
"""

# Set up
hs = half_shape #readability
size = np.int(half_shape/7) #this prevents fitting to the far out noise
pattern = single_pattern[hs-size:hs+size,hs-size:hs+size]

if np.max(pattern) > 1:
raise ValueError('Patterns should be normalised to max intensity')

#fitting
from scipy.optimize import curve_fit as cf
i_array = np.array([np.arange(hs-size,hs+size),np.arange(hs-size,hs+size),np.arange(hs-size,hs+size)])
x_center = cf(_capped_gaussian,i_array,np.ravel(pattern[size:size+3,:].T),p0=[2,5,hs])[0][2]
y_center = cf(_capped_gaussian,i_array,np.ravel(pattern[:,size:size+3].T),p0=[2,5,hs])[0][2]

return np.asarray([x_center,y_center])


def enhance_gauss_sauvola(z, sigma_blur, sigma_enhance, k, window_size, threshold, morph_opening=True):
z = z.astype(np.float64)
im1 = ndi.gaussian_filter(z, sigma=sigma_blur, mode='mirror')
Expand Down
68 changes: 22 additions & 46 deletions pyxem_examples/marker_attachment_testbook.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "code",
"execution_count": 43,
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -13,34 +13,25 @@
"import pymatgen as pmg\n",
"from matplotlib import pyplot as plt\n",
"from pymatgen.transformations.standard_transformations import RotationTransformation\n",
"from pyxem.indexation_generator import IndexationGenerator\n",
"from pyxem.generators.indexation_generator import IndexationGenerator\n",
"from pyxem.utils.sim_utils import peaks_from_best_template\n",
"from pyxem.utils.plot import generate_marker_inputs_from_peaks\n",
"from scipy.constants import pi"
]
},
{
"cell_type": "code",
"execution_count": 44,
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"The autoreload extension is already loaded. To reload it, use:\n",
" %reload_ext autoreload\n"
]
}
],
"outputs": [],
"source": [
"%load_ext autoreload\n",
"%autoreload 2"
]
},
{
"cell_type": "code",
"execution_count": 45,
"execution_count": 4,
"metadata": {
"collapsed": true
},
Expand All @@ -57,15 +48,13 @@
},
{
"cell_type": "code",
"execution_count": 46,
"metadata": {
"collapsed": true
},
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"size = 256\n",
"radius=1.5\n",
"ediff = pxm.ElectronDiffractionCalculator(300., 0.025)\n",
"ediff = pxm.DiffractionGenerator(300., 0.025)\n",
"\n",
"rotaxis = [0, 0, 1]\n",
"thetas = np.arange(0, 46, 45)\n",
Expand All @@ -87,7 +76,7 @@
},
{
"cell_type": "code",
"execution_count": 47,
"execution_count": 7,
"metadata": {
"collapsed": true
},
Expand All @@ -102,38 +91,39 @@
},
{
"cell_type": "code",
"execution_count": 48,
"execution_count": 24,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
" \r"
" \r"
]
}
],
"source": [
"edc = pxm.ElectronDiffractionCalculator(300, 0.025)\n",
"diff_gen = pxm.DiffractionLibraryGenerator(edc)\n",
"diff_gen = pxm.DiffractionLibraryGenerator(ediff)\n",
"struc_lib = dict()\n",
"struc_lib['si'] = (silicon, rot_list)\n",
"struc_lib['ga'] = (gall,rot_list)\n",
"library = diff_gen.get_diffraction_library(struc_lib,\n",
" calibration=1.2/128,\n",
" reciprocal_radius=1.5,\n",
" representation='euler')"
" reciprocal_radius=1.1,\n",
" representation='euler',\n",
" half_shape=(256/2,256/2),\n",
" with_direct_beam=False)"
]
},
{
"cell_type": "code",
"execution_count": 49,
"execution_count": 25,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "675d0008b8d348db87981eb4292e9051",
"model_id": "80070396142b40ae945fe0344323e56e",
"version_major": 2,
"version_minor": 0
},
Expand All @@ -143,13 +133,6 @@
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n"
]
}
],
"source": [
Expand All @@ -160,13 +143,13 @@
},
{
"cell_type": "code",
"execution_count": 50,
"execution_count": 26,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "69d040b131d74bbd8c103ce0370d1f12",
"model_id": "b6d864e1bad44b5b9b500d113e72c927",
"version_major": 2,
"version_minor": 0
},
Expand All @@ -176,13 +159,6 @@
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n"
]
}
],
"source": [
Expand All @@ -191,7 +167,7 @@
},
{
"cell_type": "code",
"execution_count": 51,
"execution_count": 27,
"metadata": {
"collapsed": true
},
Expand Down Expand Up @@ -222,7 +198,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.2"
"version": "3.6.3"
}
},
"nbformat": 4,
Expand Down
57 changes: 57 additions & 0 deletions tests/Orientation_mapping/OM_fixtures.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# -*- coding: utf-8 -*-
# Copyright 2018 The pyXem developers
#
# This file is part of pyXem.
#
# pyXem is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# pyXem is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with pyXem. If not, see <http://www.gnu.org/licenses/>.

import pymatgen as pmg
import numpy as np
import pyxem as pxm
from transforms3d.euler import euler2axangle
from pymatgen.transformations.standard_transformations import RotationTransformation

half_side_length = 72

def create_GaAs():
Ga = pmg.Element("Ga")
As = pmg.Element("As")
lattice = pmg.Lattice.cubic(5.6535)
return pmg.Structure.from_spacegroup("F23",lattice, [Ga,As], [[0, 0, 0],[0.25,0.25,0.25]])

def create_pair(angle_start,angle_change):
""" Lists for angles """
angle_2 = np.add(angle_start,angle_change)
return [angle_start,angle_start,angle_2,angle_2]

def build_linear_grid_in_euler(alpha_max,beta_max,gamma_max,resolution):
a = np.arange(0,alpha_max,step=resolution)
b = np.arange(0,beta_max,step=resolution)
c = np.arange(0,gamma_max,step=resolution)
from itertools import product
return list(product(a,b,c))

def create_sample(edc,structure,angle_start,angle_change):
dps = []
for orientation in create_pair(angle_start,angle_change):
axis, angle = euler2axangle(orientation[0], orientation[1],orientation[2], 'rzxz')
rotation = RotationTransformation(axis, angle,angle_in_radians=True)
rotated_structure = rotation.apply_transformation(structure)
data = edc.calculate_ed_data(rotated_structure,
reciprocal_radius=0.9, #avoiding a reflection issue
with_direct_beam=False)
dps.append(data.as_signal(2*half_side_length,0.025,1).data)
dp = pxm.ElectronDiffraction([dps[0:2],dps[2:]])
dp.set_calibration(1/half_side_length)
return dp
2 changes: 1 addition & 1 deletion tests/Orientation_mapping/test_orientation_mapping_phys.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,4 +181,4 @@ def test_match_results_caseC(structure,rot_list,edc):
## THERE IS A GOTCHA HERE DUE TO WEAK REFLECTION
m = hs.markers.point(x=mx,y=my,color='red',marker='x') #see visual test
dp.add_marker(m,plot_marker=True,permanent=True)
"""
"""
4 changes: 2 additions & 2 deletions tests/test_diffraction_simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,15 +84,15 @@ def check_pattern_equivilance(p1,p2,coords_only=False):
fake_pattern = get_pattern(Mscope,fake_cubic_I)
larger_pattern = get_pattern(Mscope,larger_cubic_I)


def test_casual_formal():
# Checks that Pymatgen understands that these are the same structure
assert formal_cubic_I == casual_cubic_I

def test_casual_formal_in_simulation():
## Checks that are simulations also realise that
check_pattern_equivilance(formal_pattern,casual_pattern)

def test_systematic_absence():
## Cubic I thus each peak must have indicies that sum to an even number
assert np.all(np.sum(formal_pattern.indices,axis=1) % 2 == 0)
Expand Down

0 comments on commit 4e7058a

Please sign in to comment.