Startup
This commit is contained in:
0
script/__Lib/diffcalc_old/diffcalc/ub/__init__.py
Normal file
0
script/__Lib/diffcalc_old/diffcalc/ub/__init__.py
Normal file
637
script/__Lib/diffcalc_old/diffcalc/ub/calc.py
Normal file
637
script/__Lib/diffcalc_old/diffcalc/ub/calc.py
Normal file
@@ -0,0 +1,637 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# Diffcalc 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 Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from diffcalc.ub.calcstate import decode_ubcalcstate
|
||||
from diffcalc.ub.calcstate import UBCalcState
|
||||
from diffcalc.ub.crystal import CrystalUnderTest
|
||||
from diffcalc.ub.reflections import ReflectionList
|
||||
from diffcalc.ub.persistence import UBCalculationJSONPersister, UBCalculationPersister
|
||||
from diffcalc.util import DiffcalcException, cross3, dot3, bold
|
||||
from math import acos, cos, sin, pi
|
||||
from diffcalc.ub.reference import YouReference
|
||||
|
||||
try:
|
||||
from numpy import matrix, hstack
|
||||
from numpy.linalg import norm
|
||||
except ImportError:
|
||||
from numjy import matrix, hstack
|
||||
from numjy.linalg import norm
|
||||
|
||||
from diffcalc.ub.crystal import CrystalUnderTest
|
||||
from diffcalc.ub.reflections import ReflectionList
|
||||
from diffcalc.util import DiffcalcException, cross3, dot3
|
||||
|
||||
SMALL = 1e-7
|
||||
TODEG = 180 / pi
|
||||
|
||||
WIDTH = 13
|
||||
|
||||
def z(num):
|
||||
"""Round to zero if small. This is useful to get rid of erroneous
|
||||
minus signs resulting from float representation close to zero.
|
||||
"""
|
||||
if abs(num) < SMALL:
|
||||
num = 0
|
||||
return num
|
||||
|
||||
#The UB matrix is used to find or set the orientation of a set of
|
||||
#planes described by an hkl vector. The U matrix can be used to find
|
||||
#or set the orientation of the crystal lattices' y axis. If there is
|
||||
#crystal miscut the crystal lattices y axis is not parallel to the
|
||||
#crystals optical surface normal. For surface diffraction experiments,
|
||||
#where not only the crystal lattice must be oriented appropriately but
|
||||
#so must the crystal's optical surface, two angles tau and sigma are
|
||||
#used to describe the difference between the two. Sigma is (minus) the
|
||||
#ammount of chi axis rotation and tau (minus) the ammount of phi axis
|
||||
#rotation needed to move the surface normal into the direction of the
|
||||
|
||||
|
||||
class PaperSpecificUbCalcStrategy(object):
|
||||
|
||||
def calculate_q_phi(self, pos):
|
||||
"""Calculate hkl in the phi frame in units of 2 * pi / lambda from
|
||||
pos object in radians"""
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class UBCalculation:
|
||||
"""A UB matrix calculation for an experiment.
|
||||
|
||||
Contains the parameters for the _crystal under test, a list of measured
|
||||
reflections and, if its been calculated, a UB matrix to be used by the rest
|
||||
of the code.
|
||||
"""
|
||||
|
||||
def __init__(self, hardware, diffractometerPluginObject,
|
||||
persister, strategy, include_sigtau=True, include_reference=True):
|
||||
|
||||
# The diffractometer geometry is required to map the internal angles
|
||||
# into those used by this diffractometer (for display only)
|
||||
|
||||
self._hardware = hardware
|
||||
self._geometry = diffractometerPluginObject
|
||||
self._persister = persister
|
||||
self._strategy = strategy
|
||||
self.include_sigtau = include_sigtau
|
||||
self.include_reference = include_reference
|
||||
self._clear()
|
||||
|
||||
def _get_diffractometer_axes_names(self):
|
||||
return self._hardware.get_axes_names()
|
||||
|
||||
def _clear(self, name=None):
|
||||
# NOTE the Diffraction calculator is expecting this object to exist in
|
||||
# the long run. We can't remove this entire object, and recreate it.
|
||||
# It also contains a required link to the angle calculator.
|
||||
reflist = ReflectionList(self._geometry, self._get_diffractometer_axes_names())
|
||||
reference = YouReference(self._get_UB)
|
||||
self._state = UBCalcState(name=name, reflist=reflist, reference=reference)
|
||||
self._U = None
|
||||
self._UB = None
|
||||
self._state.configure_calc_type()
|
||||
|
||||
### State ###
|
||||
def start_new(self, name):
|
||||
"""start_new(name) --- creates a new blank ub calculation"""
|
||||
# Create storage object if name does not exist (TODO)
|
||||
if name in self._persister.list():
|
||||
print ("No UBCalculation started: There is already a calculation "
|
||||
"called: " + name)
|
||||
print "Saved calculations: " + repr(self._persister.list())
|
||||
return
|
||||
self._clear(name)
|
||||
self.save()
|
||||
|
||||
def load(self, name):
|
||||
state = self._persister.load(name)
|
||||
if isinstance(self._persister, UBCalculationJSONPersister):
|
||||
self._state = decode_ubcalcstate(state, self._geometry, self._get_diffractometer_axes_names())
|
||||
self._state.reference.get_UB = self._get_UB
|
||||
elif isinstance(self._persister, UBCalculationPersister):
|
||||
self._state = state
|
||||
else:
|
||||
raise Exception('Unexpected persister type: ' + str(self._persister))
|
||||
if self._state.manual_U is not None:
|
||||
self.set_U_manually(self._state.manual_U)
|
||||
elif self._state.manual_UB is not None:
|
||||
self.set_UB_manually(self._state.manual_UB)
|
||||
elif self._state.or0 is not None:
|
||||
if self._state.or1 is None:
|
||||
self.calculate_UB_from_primary_only()
|
||||
else:
|
||||
self.calculate_UB()
|
||||
else:
|
||||
pass
|
||||
|
||||
def save(self):
|
||||
self.saveas(self._state.name)
|
||||
|
||||
def saveas(self, name):
|
||||
self._state.name = name
|
||||
self._persister.save(self._state, name)
|
||||
|
||||
def listub(self):
|
||||
return self._persister.list()
|
||||
|
||||
def listub_metadata(self):
|
||||
return self._persister.list_metadata()
|
||||
|
||||
def remove(self, name):
|
||||
self._persister.remove(name)
|
||||
if self._state == name:
|
||||
self._clear(name)
|
||||
|
||||
def getState(self):
|
||||
return self._state.getState()
|
||||
|
||||
def __str__(self):
|
||||
|
||||
if self._state.name is None:
|
||||
return "<<< No UB calculation started >>>"
|
||||
lines = []
|
||||
lines.append(bold("UBCALC"))
|
||||
lines.append("")
|
||||
lines.append(
|
||||
" name:".ljust(WIDTH) + self._state.name.rjust(9))
|
||||
|
||||
if self.include_sigtau:
|
||||
lines.append("")
|
||||
lines.append(
|
||||
" sigma:".ljust(WIDTH) + ("% 9.5f" % self._state.sigma).rjust(9))
|
||||
lines.append(
|
||||
" tau:".ljust(WIDTH) + ("% 9.5f" % self._state.tau).rjust(9))
|
||||
|
||||
if self.include_reference:
|
||||
lines.append("")
|
||||
ub_calculated = self._UB is not None
|
||||
lines.extend(self._state.reference.repr_lines(ub_calculated, WIDTH))
|
||||
|
||||
lines.append("")
|
||||
lines.append(bold("CRYSTAL"))
|
||||
lines.append("")
|
||||
|
||||
if self._state.crystal is None:
|
||||
lines.append(" <<< none specified >>>")
|
||||
else:
|
||||
lines.extend(self._state.crystal.str_lines())
|
||||
|
||||
lines.append("")
|
||||
lines.append(bold("UB MATRIX"))
|
||||
lines.append("")
|
||||
|
||||
if self._UB is None:
|
||||
lines.append(" <<< none calculated >>>")
|
||||
else:
|
||||
lines.extend(self.str_lines_u())
|
||||
lines.append("")
|
||||
lines.extend(self.str_lines_u_angle_and_axis())
|
||||
lines.append("")
|
||||
lines.extend(self.str_lines_ub())
|
||||
|
||||
lines.append("")
|
||||
lines.append(bold("REFLECTIONS"))
|
||||
lines.append("")
|
||||
|
||||
lines.extend(self._state.reflist.str_lines())
|
||||
|
||||
return '\n'.join(lines)
|
||||
|
||||
def str_lines_u(self):
|
||||
lines = []
|
||||
fmt = "% 9.5f % 9.5f % 9.5f"
|
||||
U = self.U
|
||||
lines.append(" U matrix:".ljust(WIDTH) +
|
||||
fmt % (z(U[0, 0]), z(U[0, 1]), z(U[0, 2])))
|
||||
lines.append(' ' * WIDTH + fmt % (z(U[1, 0]), z(U[1, 1]), z(U[1, 2])))
|
||||
lines.append(' ' * WIDTH + fmt % (z(U[2, 0]), z(U[2, 1]), z(U[2, 2])))
|
||||
return lines
|
||||
|
||||
def str_lines_u_angle_and_axis(self):
|
||||
lines = []
|
||||
fmt = "% 9.5f % 9.5f % 9.5f"
|
||||
y = matrix('0; 0; 1')
|
||||
rotation_axis = cross3(y, self.U * y)
|
||||
if abs(norm(rotation_axis)) < SMALL:
|
||||
lines.append(" U angle:".ljust(WIDTH) + " 0")
|
||||
else:
|
||||
rotation_axis = rotation_axis * (1 / norm(rotation_axis))
|
||||
cos_rotation_angle = dot3(y, self.U * y)
|
||||
rotation_angle = acos(cos_rotation_angle)
|
||||
|
||||
lines.append(" angle:".ljust(WIDTH) + "% 9.5f" % (rotation_angle * TODEG))
|
||||
lines.append(" axis:".ljust(WIDTH) + fmt % tuple((rotation_axis.T).tolist()[0]))
|
||||
|
||||
return lines
|
||||
|
||||
def str_lines_ub(self):
|
||||
lines = []
|
||||
fmt = "% 9.5f % 9.5f % 9.5f"
|
||||
UB = self.UB
|
||||
lines.append(" UB matrix:".ljust(WIDTH) +
|
||||
fmt % (z(UB[0, 0]), z(UB[0, 1]), z(UB[0, 2])))
|
||||
lines.append(' ' * WIDTH + fmt % (z(UB[1, 0]), z(UB[1, 1]), z(UB[1, 2])))
|
||||
lines.append(' ' * WIDTH + fmt % (z(UB[2, 0]), z(UB[2, 1]), z(UB[2, 2])))
|
||||
return lines
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._state.name
|
||||
### Lattice ###
|
||||
|
||||
def set_lattice(self, name, *shortform):
|
||||
"""
|
||||
Converts a list shortform crystal parameter specification to a six-long
|
||||
tuple returned as . Returns None if wrong number of input args. See
|
||||
set_lattice() for a description of the shortforms supported.
|
||||
|
||||
shortformLattice -- a tuple as follows:
|
||||
[a] - assumes cubic
|
||||
[a,b]) - assumes tetragonal
|
||||
[a,b,c]) - assumes ortho
|
||||
[a,b,c,gam]) - assumes mon/hex gam different from 90.
|
||||
[a,b,c,alp,bet,gam]) - for arbitrary
|
||||
where all measurements in angstroms and angles in degrees
|
||||
"""
|
||||
self._set_lattice_without_saving(name, *shortform)
|
||||
self.save()
|
||||
|
||||
def _set_lattice_without_saving(self, name, *shortform):
|
||||
sf = shortform
|
||||
if len(sf) == 1:
|
||||
fullform = (sf[0], sf[0], sf[0], 90., 90., 90.) # cubic
|
||||
elif len(sf) == 2:
|
||||
fullform = (sf[0], sf[0], sf[1], 90., 90., 90.) # tetragonal
|
||||
elif len(sf) == 3:
|
||||
fullform = (sf[0], sf[1], sf[2], 90., 90., 90.) # ortho
|
||||
elif len(sf) == 4:
|
||||
fullform = (sf[0], sf[1], sf[2], 90., 90., sf[3]) # mon/hex gam
|
||||
# not 90
|
||||
elif len(sf) == 5:
|
||||
raise ValueError("wrong length input to set_lattice")
|
||||
elif len(sf) == 6:
|
||||
fullform = sf # triclinic/arbitrary
|
||||
else:
|
||||
raise ValueError("wrong length input to set_lattice")
|
||||
self._set_lattice(name, *fullform)
|
||||
|
||||
def _set_lattice(self, name, a, b, c, alpha, beta, gamma):
|
||||
"""set lattice parameters in degrees"""
|
||||
if self._state.name is None:
|
||||
raise DiffcalcException(
|
||||
"Cannot set lattice until a UBCalcaluation has been started "
|
||||
"with newubcalc")
|
||||
self._state.crystal = CrystalUnderTest(name, a, b, c, alpha, beta, gamma)
|
||||
# Clear U and UB if these exist
|
||||
if self._U is not None: # (UB will also exist)
|
||||
print "Warning: the old UB calculation has been cleared."
|
||||
print " Use 'calcub' to recalculate with old reflections."
|
||||
|
||||
### Surface normal stuff ###
|
||||
|
||||
def _gettau(self):
|
||||
"""
|
||||
Returns tau (in degrees): the (minus) ammount of phi axis rotation ,
|
||||
that together with some chi axis rotation (minus sigma) brings the
|
||||
optical surface normal parallelto the omega axis.
|
||||
"""
|
||||
return self._state.tau
|
||||
|
||||
def _settau(self, tau):
|
||||
self._state.tau = tau
|
||||
self.save()
|
||||
|
||||
tau = property(_gettau, _settau)
|
||||
|
||||
def _getsigma(self):
|
||||
"""
|
||||
Returns sigma (in degrees): the (minus) ammount of phi axis rotation ,
|
||||
that together with some phi axis rotation (minus tau) brings the
|
||||
optical surface normal parallel to the omega axis.
|
||||
"""
|
||||
return self._state.sigma
|
||||
|
||||
def _setsigma(self, sigma):
|
||||
self.state._sigma = sigma
|
||||
self.save()
|
||||
|
||||
sigma = property(_getsigma, _setsigma)
|
||||
|
||||
|
||||
### Reference vector ###
|
||||
|
||||
def _get_n_phi(self):
|
||||
return self._state.reference.n_phi
|
||||
|
||||
n_phi = property(_get_n_phi)
|
||||
|
||||
def set_n_phi_configured(self, n_phi):
|
||||
self._state.reference.n_phi_configured = n_phi
|
||||
self.save()
|
||||
|
||||
def set_n_hkl_configured(self, n_hkl):
|
||||
self._state.reference.n_hkl_configured = n_hkl
|
||||
self.save()
|
||||
|
||||
def print_reference(self):
|
||||
print '\n'.join(self._state.reference.repr_lines(self.is_ub_calculated()))
|
||||
|
||||
### Reflections ###
|
||||
|
||||
def add_reflection(self, h, k, l, position, energy, tag, time):
|
||||
"""add_reflection(h, k, l, position, tag=None) -- adds a reflection
|
||||
|
||||
position is in degrees and in the systems internal representation.
|
||||
"""
|
||||
if self._state.reflist is None:
|
||||
raise DiffcalcException("No UBCalculation loaded")
|
||||
self._state.reflist.add_reflection(h, k, l, position, energy, tag, time)
|
||||
self.save() # incase autocalculateUbAndReport fails
|
||||
|
||||
# If second reflection has just been added then calculateUB
|
||||
if len(self._state.reflist) == 2:
|
||||
self._autocalculateUbAndReport()
|
||||
self.save()
|
||||
|
||||
def edit_reflection(self, num, h, k, l, position, energy, tag, time):
|
||||
"""
|
||||
edit_reflection(num, h, k, l, position, tag=None) -- adds a reflection
|
||||
|
||||
position is in degrees and in the systems internal representation.
|
||||
"""
|
||||
if self._state.reflist is None:
|
||||
raise DiffcalcException("No UBCalculation loaded")
|
||||
self._state.reflist.edit_reflection(num, h, k, l, position, energy, tag, time)
|
||||
|
||||
# If first or second reflection has been changed and there are at least
|
||||
# two reflections then recalculate UB
|
||||
if (num == 1 or num == 2) and len(self._state.reflist) >= 2:
|
||||
self._autocalculateUbAndReport()
|
||||
self.save()
|
||||
|
||||
def get_reflection(self, num):
|
||||
"""--> ( [h, k, l], position, energy, tag, time
|
||||
num starts at 1, position in degrees"""
|
||||
return self._state.reflist.getReflection(num)
|
||||
|
||||
def get_reflection_in_external_angles(self, num):
|
||||
"""--> ( [h, k, l], position, energy, tag, time
|
||||
num starts at 1, position in degrees"""
|
||||
return self._state.reflist.get_reflection_in_external_angles(num)
|
||||
|
||||
def get_number_reflections(self):
|
||||
return 0 if self._state.reflist is None else len(self._state.reflist)
|
||||
|
||||
def del_reflection(self, reflectionNumber):
|
||||
self._state.reflist.removeReflection(reflectionNumber)
|
||||
if ((reflectionNumber == 1 or reflectionNumber == 2) and
|
||||
(self._U != None)):
|
||||
self._autocalculateUbAndReport()
|
||||
self.save()
|
||||
|
||||
def swap_reflections(self, num1, num2):
|
||||
self._state.reflist.swap_reflections(num1, num2)
|
||||
if ((num1 == 1 or num1 == 2 or num2 == 1 or num2 == 2) and
|
||||
(self._U != None)):
|
||||
self._autocalculateUbAndReport()
|
||||
self.save()
|
||||
|
||||
def _autocalculateUbAndReport(self):
|
||||
if len(self._state.reflist) < 2:
|
||||
pass
|
||||
elif self._state.crystal is None:
|
||||
print ("Not calculating UB matrix as no lattice parameters have "
|
||||
"been specified.")
|
||||
elif not self._state.is_okay_to_autocalculate_ub:
|
||||
print ("Not calculating UB matrix as it has been manually set. "
|
||||
"Use 'calcub' to explicitly recalculate it.")
|
||||
else: # okay to autocalculate
|
||||
if self._UB is None:
|
||||
print "Calculating UB matrix."
|
||||
else:
|
||||
print "Recalculating UB matrix."
|
||||
self.calculate_UB()
|
||||
|
||||
# @property
|
||||
# def reflist(self):
|
||||
# return self._state.reflist
|
||||
### Calculations ###
|
||||
|
||||
def set_U_manually(self, m):
|
||||
"""Manually sets U. matrix must be 3*3 Jama or python matrix.
|
||||
Turns off aution UB calcualtion."""
|
||||
|
||||
# Check matrix is a 3*3 Jama matrix
|
||||
if m.__class__ != matrix:
|
||||
m = matrix(m) # assume its a python matrix
|
||||
if m.shape[0] != 3 or m.shape[1] != 3:
|
||||
raise ValueError("Expects 3*3 matrix")
|
||||
|
||||
if self._UB is None:
|
||||
print "Calculating UB matrix."
|
||||
else:
|
||||
print "Recalculating UB matrix."
|
||||
|
||||
self._state.configure_calc_type(manual_U=m)
|
||||
self._U = m
|
||||
if self._state.crystal is None:
|
||||
raise DiffcalcException(
|
||||
"A crystal must be specified before manually setting U")
|
||||
self._UB = self._U * self._state.crystal.B
|
||||
print ("NOTE: A new UB matrix will not be automatically calculated "
|
||||
"when the orientation reflections are modified.")
|
||||
self.save()
|
||||
|
||||
def set_UB_manually(self, m):
|
||||
"""Manually sets UB. matrix must be 3*3 Jama or python matrix.
|
||||
Turns off aution UB calcualtion."""
|
||||
|
||||
# Check matrix is a 3*3 Jama matrix
|
||||
if m.__class__ != matrix:
|
||||
m = matrix(m) # assume its a python matrix
|
||||
if m.shape[0] != 3 or m.shape[1] != 3:
|
||||
raise ValueError("Expects 3*3 matrix")
|
||||
|
||||
self._state.configure_calc_type(manual_UB=m)
|
||||
self._UB = m
|
||||
self.save()
|
||||
|
||||
@property
|
||||
def U(self):
|
||||
if self._U is None:
|
||||
raise DiffcalcException(
|
||||
"No U matrix has been calculated during this ub calculation")
|
||||
return self._U
|
||||
|
||||
@property
|
||||
def UB(self):
|
||||
return self._get_UB()
|
||||
|
||||
def is_ub_calculated(self):
|
||||
return self._UB is not None
|
||||
|
||||
def _get_UB(self):
|
||||
if not self.is_ub_calculated():
|
||||
raise DiffcalcException(
|
||||
"No UB matrix has been calculated during this ub calculation")
|
||||
else:
|
||||
return self._UB
|
||||
|
||||
def calculate_UB(self):
|
||||
"""
|
||||
Calculate orientation matrix. Uses first two orientation reflections
|
||||
as in Busang and Levy, but for the diffractometer in Lohmeier and
|
||||
Vlieg.
|
||||
"""
|
||||
|
||||
# Major variables:
|
||||
# h1, h2: user input reciprical lattice vectors of the two reflections
|
||||
# h1c, h2c: user input vectors in cartesian crystal plane
|
||||
# pos1, pos2: measured diffractometer positions of the two reflections
|
||||
# u1a, u2a: measured reflection vectors in alpha frame
|
||||
# u1p, u2p: measured reflection vectors in phi frame
|
||||
|
||||
|
||||
# Get hkl and angle values for the first two refelctions
|
||||
if self._state.reflist is None:
|
||||
raise DiffcalcException("Cannot calculate a U matrix until a "
|
||||
"UBCalculation has been started with "
|
||||
"'newub'")
|
||||
try:
|
||||
(h1, pos1, _, _, _) = self._state.reflist.getReflection(1)
|
||||
(h2, pos2, _, _, _) = self._state.reflist.getReflection(2)
|
||||
except IndexError:
|
||||
raise DiffcalcException(
|
||||
"Two reflections are required to calculate a u matrix")
|
||||
h1 = matrix([h1]).T # row->column
|
||||
h2 = matrix([h2]).T
|
||||
pos1.changeToRadians()
|
||||
pos2.changeToRadians()
|
||||
|
||||
# Compute the two reflections' reciprical lattice vectors in the
|
||||
# cartesian crystal frame
|
||||
B = self._state.crystal.B
|
||||
h1c = B * h1
|
||||
h2c = B * h2
|
||||
|
||||
u1p = self._strategy.calculate_q_phi(pos1)
|
||||
u2p = self._strategy.calculate_q_phi(pos2)
|
||||
|
||||
# Create modified unit vectors t1, t2 and t3 in crystal and phi systems
|
||||
t1c = h1c
|
||||
t3c = cross3(h1c, h2c)
|
||||
t2c = cross3(t3c, t1c)
|
||||
|
||||
t1p = u1p # FIXED from h1c 9July08
|
||||
t3p = cross3(u1p, u2p)
|
||||
t2p = cross3(t3p, t1p)
|
||||
|
||||
# ...and nornmalise and check that the reflections used are appropriate
|
||||
SMALL = 1e-4 # Taken from Vlieg's code
|
||||
e = DiffcalcException("Invalid orientation reflection(s)")
|
||||
|
||||
def normalise(m):
|
||||
d = norm(m)
|
||||
if d < SMALL:
|
||||
raise e
|
||||
return m / d
|
||||
|
||||
t1c = normalise(t1c)
|
||||
t2c = normalise(t2c)
|
||||
t3c = normalise(t3c)
|
||||
|
||||
t1p = normalise(t1p)
|
||||
t2p = normalise(t2p)
|
||||
t3p = normalise(t3p)
|
||||
|
||||
Tc = hstack([t1c, t2c, t3c])
|
||||
Tp = hstack([t1p, t2p, t3p])
|
||||
self._state.configure_calc_type(or0=1, or1=2)
|
||||
self._U = Tp * Tc.I
|
||||
self._UB = self._U * B
|
||||
self.save()
|
||||
|
||||
def calculate_UB_from_primary_only(self):
|
||||
"""
|
||||
Calculate orientation matrix with the shortest absolute angle change.
|
||||
Uses first orientation reflection
|
||||
"""
|
||||
|
||||
# Algorithm from http://www.j3d.org/matrix_faq/matrfaq_latest.html
|
||||
|
||||
# Get hkl and angle values for the first two refelctions
|
||||
if self._state.reflist is None:
|
||||
raise DiffcalcException(
|
||||
"Cannot calculate a u matrix until a UBCalcaluation has been "
|
||||
"started with newub")
|
||||
try:
|
||||
(h, pos, _, _, _) = self._state.reflist.getReflection(1)
|
||||
except IndexError:
|
||||
raise DiffcalcException(
|
||||
"One reflection is required to calculate a u matrix")
|
||||
|
||||
h = matrix([h]).T # row->column
|
||||
pos.changeToRadians()
|
||||
B = self._state.crystal.B
|
||||
h_crystal = B * h
|
||||
h_crystal = h_crystal * (1 / norm(h_crystal))
|
||||
|
||||
q_measured_phi = self._strategy.calculate_q_phi(pos)
|
||||
q_measured_phi = q_measured_phi * (1 / norm(q_measured_phi))
|
||||
|
||||
rotation_axis = cross3(h_crystal, q_measured_phi)
|
||||
rotation_axis = rotation_axis * (1 / norm(rotation_axis))
|
||||
|
||||
cos_rotation_angle = dot3(h_crystal, q_measured_phi)
|
||||
rotation_angle = acos(cos_rotation_angle)
|
||||
|
||||
uvw = rotation_axis.T.tolist()[0] # TODO: cleanup
|
||||
print "resulting U angle: %.5f deg" % (rotation_angle * TODEG)
|
||||
u_repr = (', '.join(['% .5f' % el for el in uvw]))
|
||||
print "resulting U axis direction: [%s]" % u_repr
|
||||
|
||||
u, v, w = uvw
|
||||
rcos = cos(rotation_angle)
|
||||
rsin = sin(rotation_angle)
|
||||
m = [[0, 0, 0], [0, 0, 0], [0, 0, 0]] # TODO: tidy
|
||||
m[0][0] = rcos + u * u * (1 - rcos)
|
||||
m[1][0] = w * rsin + v * u * (1 - rcos)
|
||||
m[2][0] = -v * rsin + w * u * (1 - rcos)
|
||||
m[0][1] = -w * rsin + u * v * (1 - rcos)
|
||||
m[1][1] = rcos + v * v * (1 - rcos)
|
||||
m[2][1] = u * rsin + w * v * (1 - rcos)
|
||||
m[0][2] = v * rsin + u * w * (1 - rcos)
|
||||
m[1][2] = -u * rsin + v * w * (1 - rcos)
|
||||
m[2][2] = rcos + w * w * (1 - rcos)
|
||||
|
||||
if self._UB is None:
|
||||
print "Calculating UB matrix from the first reflection only."
|
||||
else:
|
||||
print "Recalculating UB matrix from the first reflection only."
|
||||
print ("NOTE: A new UB matrix will not be automatically calculated "
|
||||
"when the orientation reflections are modified.")
|
||||
|
||||
self._state.configure_calc_type(or0=1)
|
||||
|
||||
self._U = matrix(m)
|
||||
self._UB = self._U * B
|
||||
|
||||
self.save()
|
||||
|
||||
def get_hkl_plane_distance(self, hkl):
|
||||
"""Calculates and returns the distance between planes"""
|
||||
return self._state.crystal.get_hkl_plane_distance(hkl)
|
||||
180
script/__Lib/diffcalc_old/diffcalc/ub/calcstate.py
Normal file
180
script/__Lib/diffcalc_old/diffcalc/ub/calcstate.py
Normal file
@@ -0,0 +1,180 @@
|
||||
from diffcalc.hkl.vlieg.geometry import VliegPosition
|
||||
from diffcalc.ub.crystal import CrystalUnderTest
|
||||
from diffcalc.ub.reflections import ReflectionList, _Reflection
|
||||
from math import pi
|
||||
import datetime # @UnusedImport For crazy time eval code!
|
||||
from diffcalc.ub.reference import YouReference
|
||||
|
||||
try:
|
||||
from collection import OrderedDict
|
||||
except ImportError:
|
||||
from simplejson import OrderedDict
|
||||
|
||||
try:
|
||||
import json
|
||||
except ImportError:
|
||||
import simplejson as json
|
||||
|
||||
try:
|
||||
from numpy import matrix
|
||||
except ImportError:
|
||||
from numjy import matrix
|
||||
|
||||
|
||||
TODEG = 180 / pi
|
||||
|
||||
|
||||
class UBCalcState():
|
||||
|
||||
def __init__(self, name=None, crystal=None, reflist=None, tau=0, sigma=0,
|
||||
manual_U=None, manual_UB=None, or0=None, or1=None, reference=None):
|
||||
|
||||
assert reflist is not None
|
||||
self.name = name
|
||||
self.crystal = crystal
|
||||
self.reflist = reflist
|
||||
self.tau = tau # degrees
|
||||
self.sigma = sigma # degrees
|
||||
self.manual_U = manual_U
|
||||
self.manual_UB = manual_UB
|
||||
self.or0 = or0
|
||||
self.or1 = or1
|
||||
self.reference = reference
|
||||
|
||||
@property
|
||||
def is_okay_to_autocalculate_ub(self):
|
||||
nothing_set = ((self.manual_U is None) and
|
||||
(self.manual_UB is None) and
|
||||
(self.or0 is None) and
|
||||
(self.or1 is None))
|
||||
or0_and_or1_used = (self.or0 is not None) and (self.or1 is not None)
|
||||
return nothing_set or or0_and_or1_used
|
||||
|
||||
|
||||
def configure_calc_type(self,
|
||||
manual_U=None,
|
||||
manual_UB=None,
|
||||
or0=None,
|
||||
or1=None):
|
||||
self.manual_U = manual_U
|
||||
self.manual_UB = manual_UB
|
||||
self.or0 = or0
|
||||
self.or1 = or1
|
||||
|
||||
|
||||
class UBCalcStateEncoder(json.JSONEncoder):
|
||||
|
||||
def default(self, obj):
|
||||
|
||||
if isinstance(obj, UBCalcState):
|
||||
d = OrderedDict()
|
||||
d['name'] = obj.name
|
||||
d['crystal'] = obj.crystal
|
||||
d['reflist'] = obj.reflist
|
||||
d['tau'] = obj.tau
|
||||
d['sigma'] = obj.sigma
|
||||
d['reference'] = obj.reference
|
||||
d['u'] = obj.manual_U
|
||||
d['ub'] = obj.manual_UB
|
||||
d['or0'] = obj.or0
|
||||
d['or1'] = obj.or1
|
||||
|
||||
return d
|
||||
|
||||
if isinstance(obj, CrystalUnderTest):
|
||||
return repr([obj._name, obj._a1, obj._a2, obj._a3, obj._alpha1 * TODEG,
|
||||
obj._alpha2 * TODEG, obj._alpha3 * TODEG])
|
||||
|
||||
if isinstance(obj, matrix):
|
||||
l = [', '.join((repr(e) for e in row)) for row in obj.tolist()]
|
||||
return l
|
||||
|
||||
if isinstance(obj, ReflectionList):
|
||||
d = OrderedDict()
|
||||
for n, ref in enumerate(obj._reflist):
|
||||
d[str(n+1)] = ref
|
||||
return d
|
||||
|
||||
if isinstance(obj, _Reflection):
|
||||
d = OrderedDict()
|
||||
d['tag'] = obj.tag
|
||||
d['hkl'] = repr([obj.h, obj.k, obj.l])
|
||||
d['pos'] = repr(list(obj.pos.totuple()))
|
||||
d['energy'] = obj.energy
|
||||
dt = eval(obj.time) # e.g. --> datetime.datetime(2013, 8, 5, 15, 47, 7, 962432)
|
||||
d['time'] = None if dt is None else dt.isoformat()
|
||||
return d
|
||||
|
||||
if isinstance(obj, YouReference):
|
||||
d = OrderedDict()
|
||||
if obj.n_hkl_configured is not None:
|
||||
d['n_hkl_configured'] = repr(obj.n_hkl_configured.T.tolist()[0])
|
||||
else:
|
||||
d['n_hkl_configured'] = None
|
||||
if obj.n_phi_configured is not None:
|
||||
d['n_phi_configured'] = repr(obj.n_phi_configured.T.tolist()[0])
|
||||
else:
|
||||
d['n_phi_configured'] = None
|
||||
return d
|
||||
|
||||
|
||||
return json.JSONEncoder.default(self, obj)
|
||||
|
||||
|
||||
def decode_ubcalcstate(state, geometry, diffractometer_axes_names):
|
||||
|
||||
return UBCalcState(
|
||||
name=state['name'],
|
||||
crystal=state['crystal'] and CrystalUnderTest(*eval(state['crystal'])),
|
||||
reflist=decode_reflist(state['reflist'], geometry, diffractometer_axes_names),
|
||||
tau=state['tau'],
|
||||
sigma=state['sigma'],
|
||||
manual_U=state['u'] and decode_matrix(state['u']),
|
||||
manual_UB=state['ub'] and decode_matrix(state['ub']),
|
||||
or0=state['or0'],
|
||||
or1=state['or1'],
|
||||
reference=decode_reference(state.get('reference', None))
|
||||
)
|
||||
|
||||
|
||||
def decode_matrix(rows):
|
||||
return matrix([[eval(e) for e in row.split(', ')] for row in rows])
|
||||
|
||||
|
||||
def decode_reflist(reflist_dict, geometry, diffractometer_axes_names):
|
||||
reflections = []
|
||||
for key in sorted(reflist_dict.keys()):
|
||||
reflections.append(decode_reflection(reflist_dict[key], geometry))
|
||||
|
||||
return ReflectionList(geometry, diffractometer_axes_names, reflections)
|
||||
|
||||
|
||||
def decode_reflection(ref_dict, geometry):
|
||||
h, k, l = eval(ref_dict['hkl'])
|
||||
time = ref_dict['time'] and gt(ref_dict['time'])
|
||||
pos_tuple = eval(ref_dict['pos'])
|
||||
try:
|
||||
position = geometry.create_position(*pos_tuple)
|
||||
except AttributeError:
|
||||
position = VliegPosition(*pos_tuple)
|
||||
return _Reflection(h, k, l, position, ref_dict['energy'], str(ref_dict['tag']), repr(time))
|
||||
|
||||
|
||||
def decode_reference(ref_dict):
|
||||
|
||||
reference = YouReference(None) # TODO: We can't set get_ub method yet (tangles!)
|
||||
if ref_dict:
|
||||
nhkl = ref_dict.get('n_hkl_configured', None)
|
||||
nphi = ref_dict.get('n_phi_configured', None)
|
||||
if nhkl:
|
||||
reference.n_hkl_configured = matrix([eval(nhkl)]).T
|
||||
if nphi:
|
||||
reference.n_phi_configured = matrix([eval(nphi)]).T
|
||||
return reference
|
||||
|
||||
# From: http://stackoverflow.com/questions/127803/how-to-parse-iso-formatted-date-in-python
|
||||
def gt(dt_str):
|
||||
dt, _, us= dt_str.partition(".")
|
||||
dt= datetime.datetime.strptime(dt, "%Y-%m-%dT%H:%M:%S")
|
||||
us= int(us.rstrip("Z"), 10)
|
||||
return dt + datetime.timedelta(microseconds=us)
|
||||
137
script/__Lib/diffcalc_old/diffcalc/ub/crystal.py
Normal file
137
script/__Lib/diffcalc_old/diffcalc/ub/crystal.py
Normal file
@@ -0,0 +1,137 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# Diffcalc 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 Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from math import pi, cos, sin, acos, sqrt
|
||||
|
||||
|
||||
try:
|
||||
from numpy import matrix
|
||||
except ImportError:
|
||||
from numjy import matrix
|
||||
|
||||
TORAD = pi / 180
|
||||
TODEG = 180 / pi
|
||||
SMALL = 1e-7
|
||||
|
||||
def z(num):
|
||||
"""Round to zero if small. This is useful to get rid of erroneous
|
||||
minus signs resulting from float representation close to zero.
|
||||
"""
|
||||
if abs(num) < SMALL:
|
||||
num = 0
|
||||
return num
|
||||
|
||||
|
||||
class CrystalUnderTest(object):
|
||||
"""
|
||||
Contains the lattice parameters and calculated B matrix for the crytsal
|
||||
under test. Also Calculates the distance between planes at a given hkl
|
||||
value.
|
||||
|
||||
The lattice paraemters can be specified and then if desired saved to a
|
||||
__library to be loaded later. The parameters are persisted across restarts.
|
||||
Lattices stored in config/var/crystals.xml .
|
||||
"""
|
||||
|
||||
def __init__(self, name, a, b, c, alpha, beta, gamma):
|
||||
'''Creates a new lattice and calculates related values.
|
||||
|
||||
Keyword arguments:
|
||||
name -- a string
|
||||
a,b,c,alpha,beta,gamma -- lengths and angles (in degrees)
|
||||
'''
|
||||
|
||||
self._name = name
|
||||
|
||||
# Set the direct lattice parameters
|
||||
self._a1 = a1 = a
|
||||
self._a2 = a2 = b
|
||||
self._a3 = a3 = c
|
||||
self._alpha1 = alpha1 = alpha * TORAD
|
||||
self._alpha2 = alpha2 = beta * TORAD
|
||||
self._alpha3 = alpha3 = gamma * TORAD
|
||||
|
||||
# Calculate the reciprocal lattice parameters
|
||||
self._beta1 = acos((cos(alpha2) * cos(alpha3) - cos(alpha1)) /
|
||||
(sin(alpha2) * sin(alpha3)))
|
||||
|
||||
self._beta2 = beta2 = acos((cos(alpha1) * cos(alpha3) - cos(alpha2)) /
|
||||
(sin(alpha1) * sin(alpha3)))
|
||||
|
||||
self._beta3 = beta3 = acos((cos(alpha1) * cos(alpha2) - cos(alpha3)) /
|
||||
(sin(alpha1) * sin(alpha2)))
|
||||
|
||||
volume = (a1 * a2 * a3 *
|
||||
sqrt(1 + 2 * cos(alpha1) * cos(alpha2) * cos(alpha3) -
|
||||
cos(alpha1) ** 2 - cos(alpha2) ** 2 - cos(alpha3) ** 2))
|
||||
|
||||
self._b1 = b1 = 2 * pi * a2 * a3 * sin(alpha1) / volume
|
||||
self._b2 = b2 = 2 * pi * a1 * a3 * sin(alpha2) / volume
|
||||
self._b3 = b3 = 2 * pi * a1 * a2 * sin(alpha3) / volume
|
||||
|
||||
# Calculate the BMatrix from the direct and reciprical parameters.
|
||||
# Reference: Busang and Levy (1967)
|
||||
self._bMatrix = matrix([
|
||||
[b1, b2 * cos(beta3), b3 * cos(beta2)],
|
||||
[0.0, b2 * sin(beta3), -b3 * sin(beta2) * cos(alpha1)],
|
||||
[0.0, 0.0, 2 * pi / a3]])
|
||||
|
||||
@property
|
||||
def B(self):
|
||||
'''
|
||||
Returns the B matrix, may be null if crystal is not set, or if there
|
||||
was a problem calculating this'''
|
||||
return self._bMatrix
|
||||
|
||||
def get_hkl_plane_distance(self, hkl):
|
||||
'''Calculates and returns the distance between planes'''
|
||||
hkl = matrix([hkl])
|
||||
bReduced = self._bMatrix / (2 * pi)
|
||||
bMT = bReduced.I * bReduced.T.I
|
||||
return 1.0 / sqrt((hkl * bMT.I * hkl.T)[0,0])
|
||||
|
||||
def __str__(self):
|
||||
''' Returns lattice name and all set and calculated parameters'''
|
||||
return '\n'.join(self.str_lines())
|
||||
|
||||
def str_lines(self):
|
||||
WIDTH = 13
|
||||
if self._name is None:
|
||||
return [" none specified"]
|
||||
|
||||
b = self._bMatrix
|
||||
lines = []
|
||||
lines.append(" name:".ljust(WIDTH) + self._name.rjust(9))
|
||||
lines.append("")
|
||||
lines.append(" a, b, c:".ljust(WIDTH) +
|
||||
"% 9.5f % 9.5f % 9.5f" % (self.getLattice()[1:4]))
|
||||
lines.append(" " * WIDTH +
|
||||
"% 9.5f % 9.5f % 9.5f" % (self.getLattice()[4:]))
|
||||
lines.append("")
|
||||
|
||||
fmt = "% 9.5f % 9.5f % 9.5f"
|
||||
lines.append(" B matrix:".ljust(WIDTH) +
|
||||
fmt % (z(b[0, 0]), z(b[0, 1]), z(b[0, 2])))
|
||||
lines.append(' ' * WIDTH + fmt % (z(b[1, 0]), z(b[1, 1]), z(b[1, 2])))
|
||||
lines.append(' ' * WIDTH + fmt % (z(b[2, 0]), z(b[2, 1]), z(b[2, 2])))
|
||||
return lines
|
||||
|
||||
def getLattice(self):
|
||||
return(self._name, self._a1, self._a2, self._a3, self._alpha1 * TODEG,
|
||||
self._alpha2 * TODEG, self._alpha3 * TODEG)
|
||||
|
||||
151
script/__Lib/diffcalc_old/diffcalc/ub/persistence.py
Normal file
151
script/__Lib/diffcalc_old/diffcalc/ub/persistence.py
Normal file
@@ -0,0 +1,151 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# Diffcalc 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 Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from __future__ import with_statement
|
||||
|
||||
import os, glob
|
||||
from diffcalc.ub.calcstate import UBCalcStateEncoder
|
||||
import datetime
|
||||
|
||||
try:
|
||||
import json
|
||||
except ImportError:
|
||||
import simplejson as json
|
||||
|
||||
|
||||
def is_writable(directory):
|
||||
"""Return true if the file is writable from the current user
|
||||
"""
|
||||
probe = os.path.join(directory, "probe")
|
||||
try:
|
||||
open(probe, 'w')
|
||||
except IOError:
|
||||
return False
|
||||
else:
|
||||
os.remove(probe)
|
||||
return True
|
||||
|
||||
def check_directory_appropriate(directory):
|
||||
|
||||
if not os.path.exists(directory):
|
||||
raise IOError("'%s' does not exist")
|
||||
|
||||
if not os.path.isdir(directory):
|
||||
raise IOError("'%s' is not a directory")
|
||||
|
||||
if not is_writable(directory):
|
||||
raise IOError("'%s' is not writable")
|
||||
|
||||
|
||||
class UBCalculationJSONPersister(object):
|
||||
|
||||
def __init__(self, directory):
|
||||
check_directory_appropriate(directory)
|
||||
self.directory = directory
|
||||
self.description = directory
|
||||
|
||||
def filepath(self, name):
|
||||
return os.path.join(self.directory, name + '.json')
|
||||
|
||||
def save(self, state, name):
|
||||
# FORMAT = '%Y-%m-%d %H:%M:%S'
|
||||
# time_string = datetime.datetime.strftime(datetime.datetime.now(), FORMAT)
|
||||
with open(self.filepath(name), 'w') as f:
|
||||
json.dump(state, f, indent=4, cls=UBCalcStateEncoder)
|
||||
|
||||
def load(self, name):
|
||||
with open(self.filepath(name), 'r') as f:
|
||||
return json.load(f)
|
||||
|
||||
def list(self): # @ReservedAssignment
|
||||
files = self._get_save_files()
|
||||
return [os.path.basename(f + '.json').split('.json')[0] for f in files]
|
||||
|
||||
def list_metadata(self):
|
||||
metadata = []
|
||||
for f in self._get_save_files():
|
||||
dt = datetime.datetime.fromtimestamp(os.path.getmtime(f))
|
||||
metadata.append(dt.strftime('%d %b %Y (%H:%M)'))
|
||||
return metadata
|
||||
|
||||
def _get_save_files(self):
|
||||
files = filter(os.path.isfile, glob.glob(os.path.join(self.directory, '*.json')))
|
||||
files.sort(key=lambda x: os.path.getmtime(x))
|
||||
files.reverse()
|
||||
return files
|
||||
|
||||
def remove(self, name):
|
||||
os.remove(self.filepath(name))
|
||||
|
||||
|
||||
|
||||
class UBCalculationPersister(object):
|
||||
"""Attempts to the use the gda's database to store ub calculation state
|
||||
"""
|
||||
def __init__(self):
|
||||
try:
|
||||
from uk.ac.diamond.daq.persistence.jythonshelf import LocalJythonShelfManager
|
||||
from uk.ac.diamond.daq.persistence.jythonshelf.LocalDatabase import \
|
||||
LocalDatabaseException
|
||||
self.shelf = LocalJythonShelfManager.getLocalObjectShelf(
|
||||
'diffcalc.ub')
|
||||
except ImportError, e:
|
||||
print ("!!! UBCalculationPersister could not import the gda database "
|
||||
"code: " + repr(e))
|
||||
self.shelf = None
|
||||
except LocalDatabaseException, e:
|
||||
print ("UBCalculationPersister could not connect to the gda "
|
||||
"database: " + repr(e))
|
||||
self.shelf = None
|
||||
self.description = 'GDA sql database'
|
||||
|
||||
def save(self, state, key):
|
||||
if self.shelf is not None:
|
||||
self.shelf[key] = state
|
||||
else:
|
||||
print "<<<no database available to save UB calculation>>>"
|
||||
|
||||
def load(self, name):
|
||||
if self.shelf is not None:
|
||||
return self.shelf[name]
|
||||
else:
|
||||
raise IOError("Could not load UB calculation: no database available")
|
||||
|
||||
def list(self): # @ReservedAssignment
|
||||
if self.shelf is not None:
|
||||
names = list(self.shelf.keys())
|
||||
names.sort()
|
||||
return names
|
||||
else:
|
||||
return []
|
||||
|
||||
def remove(self, name):
|
||||
if self.shelf is not None:
|
||||
del self.shelf[name]
|
||||
else:
|
||||
raise IOError("Could not remove UB calculation: no database available")
|
||||
|
||||
|
||||
class UbCalculationNonPersister(UBCalculationPersister):
|
||||
"""
|
||||
A version of UBCalculationPersister that simply stores to a local dict
|
||||
rather than a database. Useful for testing.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.shelf = dict()
|
||||
self.description = 'memory only'
|
||||
99
script/__Lib/diffcalc_old/diffcalc/ub/reference.py
Normal file
99
script/__Lib/diffcalc_old/diffcalc/ub/reference.py
Normal file
@@ -0,0 +1,99 @@
|
||||
from math import pi
|
||||
|
||||
try:
|
||||
from numpy import matrix, hstack
|
||||
from numpy.linalg import norm
|
||||
except ImportError:
|
||||
from numjy import matrix, hstack
|
||||
from numjy.linalg import norm
|
||||
|
||||
|
||||
from math import pi, sin, cos, tan, acos, atan2, asin, sqrt, atan
|
||||
|
||||
from diffcalc.util import DiffcalcException, bound, angle_between_vectors
|
||||
from diffcalc.util import cross3, z_rotation, x_rotation, dot3
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
SMALL = 1e-7
|
||||
TODEG = 180 / pi
|
||||
|
||||
|
||||
|
||||
class YouReference(object):
|
||||
|
||||
def __init__(self, get_UB):
|
||||
self.get_UB = get_UB # callable
|
||||
self._n_phi_configured = None
|
||||
self._n_hkl_configured = None
|
||||
self._set_n_phi_configured(matrix('0; 0; 1'))
|
||||
|
||||
def _set_n_phi_configured(self, n_phi):
|
||||
self._n_phi_configured = n_phi
|
||||
self._n_hkl_configured = None
|
||||
|
||||
def _get_n_phi_configured(self):
|
||||
return self._n_phi_configured
|
||||
|
||||
n_phi_configured = property(_get_n_phi_configured, _set_n_phi_configured)
|
||||
|
||||
def _set_n_hkl_configured(self, n_hkl):
|
||||
self._n_phi_configured = None
|
||||
self._n_hkl_configured = n_hkl
|
||||
|
||||
def _get_n_hkl_configured(self):
|
||||
return self._n_hkl_configured
|
||||
|
||||
n_hkl_configured = property(_get_n_hkl_configured, _set_n_hkl_configured)
|
||||
|
||||
@property
|
||||
def n_phi(self):
|
||||
n_phi = (self.get_UB() * self._n_hkl_configured if self._n_phi_configured is None
|
||||
else self._n_phi_configured)
|
||||
return n_phi / norm(n_phi)
|
||||
|
||||
@property
|
||||
def n_hkl(self):
|
||||
n_hkl = (self.get_UB().I * self._n_phi_configured if self._n_hkl_configured is None
|
||||
else self._n_hkl_configured)
|
||||
return n_hkl / norm(n_hkl)
|
||||
|
||||
def _pretty_vector(self, m):
|
||||
return ' '.join([('% 9.5f' % e).rjust(9) for e in m.T.tolist()[0]])
|
||||
|
||||
def repr_lines(self, ub_calculated, WIDTH=9):
|
||||
SET_LABEL = ' <- set'
|
||||
lines = []
|
||||
if self._n_phi_configured is not None:
|
||||
nphi_label = SET_LABEL
|
||||
nhkl_label = ''
|
||||
elif self._n_hkl_configured is not None:
|
||||
nphi_label = ''
|
||||
nhkl_label = SET_LABEL
|
||||
else:
|
||||
raise AssertionError("Neither a manual n_phi nor n_hkl is configured")
|
||||
|
||||
if ub_calculated:
|
||||
lines.append(" n_phi:".ljust(WIDTH) + self._pretty_vector(self.n_phi) + nphi_label)
|
||||
lines.append(" n_hkl:".ljust(WIDTH) + self._pretty_vector(self.n_hkl) + nhkl_label)
|
||||
rotation_axis = cross3(matrix('0; 0; 1'), self.n_phi)
|
||||
if abs(norm(rotation_axis)) < SMALL:
|
||||
lines.append(" miscut:".ljust(WIDTH) + " None")
|
||||
else:
|
||||
rotation_axis = rotation_axis * (1 / norm(rotation_axis))
|
||||
cos_rotation_angle = dot3(matrix('0; 0; 1'), self.n_phi)
|
||||
rotation_angle = acos(cos_rotation_angle)
|
||||
lines.append(" miscut:")
|
||||
lines.append(" angle:".ljust(WIDTH) + "% 9.5f" % (rotation_angle * TODEG))
|
||||
lines.append(" axis:".ljust(WIDTH) + self._pretty_vector(rotation_axis))
|
||||
|
||||
else: # no ub calculated
|
||||
if self._n_phi_configured is not None:
|
||||
lines.append(" n_phi:".ljust(WIDTH) + self._pretty_vector(self._n_phi_configured) + SET_LABEL)
|
||||
elif self._n_hkl_configured is not None:
|
||||
lines.append(" n_hkl:".ljust(WIDTH) + self._pretty_vector(self._n_hkl_configured) + SET_LABEL)
|
||||
|
||||
return lines
|
||||
|
||||
126
script/__Lib/diffcalc_old/diffcalc/ub/reflections.py
Normal file
126
script/__Lib/diffcalc_old/diffcalc/ub/reflections.py
Normal file
@@ -0,0 +1,126 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# Diffcalc 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 Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from copy import deepcopy
|
||||
import datetime # @UnusedImport for the eval below
|
||||
from diffcalc.util import DiffcalcException, bold
|
||||
from diffcalc.hkl.vlieg.geometry import VliegPosition
|
||||
|
||||
|
||||
class _Reflection:
|
||||
"""A reflection"""
|
||||
def __init__(self, h, k, l, position, energy, tag, time):
|
||||
|
||||
self.h = float(h)
|
||||
self.k = float(k)
|
||||
self.l = float(l)
|
||||
self.pos = position
|
||||
self.tag = tag
|
||||
self.energy = float(energy) # energy=12.39842/lambda
|
||||
self.wavelength = 12.3984 / self.energy
|
||||
self.time = time # Saved as e.g. repr(datetime.now())
|
||||
|
||||
def __str__(self):
|
||||
return ("energy=%-6.3f h=%-4.2f k=%-4.2f l=%-4.2f alpha=%-8.4f "
|
||||
"delta=%-8.4f gamma=%-8.4f omega=%-8.4f chi=%-8.4f "
|
||||
"phi=%-8.4f %-s %s" % (self.energy, self.h, self.k, self.l,
|
||||
self.pos.alpha, self.pos.delta, self.pos.gamma, self.pos.omega,
|
||||
self.pos.chi, self.pos.phi, self.tag, self.time))
|
||||
|
||||
|
||||
class ReflectionList:
|
||||
|
||||
def __init__(self, diffractometerPluginObject, externalAngleNames, reflections=None):
|
||||
self._geometry = diffractometerPluginObject
|
||||
self._externalAngleNames = externalAngleNames
|
||||
self._reflist = reflections if reflections else []
|
||||
|
||||
|
||||
def add_reflection(self, h, k, l, position, energy, tag, time):
|
||||
"""adds a reflection, position in degrees
|
||||
"""
|
||||
if type(position) in (list, tuple):
|
||||
try:
|
||||
position = self._geometry.create_position(*position)
|
||||
except AttributeError:
|
||||
position = VliegPosition(*position)
|
||||
self._reflist += [_Reflection(h, k, l, position, energy, tag,
|
||||
time.__repr__())]
|
||||
|
||||
def edit_reflection(self, num, h, k, l, position, energy, tag, time):
|
||||
"""num starts at 1"""
|
||||
if type(position) in (list, tuple):
|
||||
position = VliegPosition(*position)
|
||||
try:
|
||||
self._reflist[num - 1] = _Reflection(h, k, l, position, energy, tag,
|
||||
time.__repr__())
|
||||
except IndexError:
|
||||
raise DiffcalcException("There is no reflection " + repr(num)
|
||||
+ " to edit.")
|
||||
|
||||
def getReflection(self, num):
|
||||
"""
|
||||
getReflection(num) --> ( [h, k, l], position, energy, tag, time ) --
|
||||
num starts at 1 position in degrees
|
||||
"""
|
||||
r = deepcopy(self._reflist[num - 1]) # for convenience
|
||||
return [r.h, r.k, r.l], deepcopy(r.pos), r.energy, r.tag, eval(r.time)
|
||||
|
||||
def get_reflection_in_external_angles(self, num):
|
||||
"""getReflection(num) --> ( [h, k, l], (angle1...angleN), energy, tag )
|
||||
-- num starts at 1 position in degrees"""
|
||||
r = deepcopy(self._reflist[num - 1]) # for convenience
|
||||
externalAngles = self._geometry.internal_position_to_physical_angles(r.pos)
|
||||
result = [r.h, r.k, r.l], externalAngles, r.energy, r.tag, eval(r.time)
|
||||
return result
|
||||
|
||||
def removeReflection(self, num):
|
||||
del self._reflist[num - 1]
|
||||
|
||||
def swap_reflections(self, num1, num2):
|
||||
orig1 = self._reflist[num1 - 1]
|
||||
self._reflist[num1 - 1] = self._reflist[num2 - 1]
|
||||
self._reflist[num2 - 1] = orig1
|
||||
|
||||
def __len__(self):
|
||||
return len(self._reflist)
|
||||
|
||||
def __str__(self):
|
||||
return '\n'.join(self.str_lines())
|
||||
|
||||
def str_lines(self):
|
||||
axes = tuple(s.upper() for s in self._externalAngleNames)
|
||||
if not self._reflist:
|
||||
return [" <<< none specified >>>"]
|
||||
|
||||
lines = []
|
||||
|
||||
format = (" %6s %5s %5s %5s " + "%8s " * len(axes) + " TAG")
|
||||
values = ('ENERGY', 'H', 'K', 'L') + axes
|
||||
lines.append(bold(format % values))
|
||||
|
||||
for n in range(len(self._reflist)):
|
||||
ref_tuple = self.get_reflection_in_external_angles(n + 1)
|
||||
[h, k, l], externalAngles, energy, tag, _ = ref_tuple
|
||||
if tag is None:
|
||||
tag = ""
|
||||
format = (" %2d %6.3f % 4.2f % 4.2f % 4.2f " +
|
||||
"% 8.4f " * len(axes) + " %s")
|
||||
values = (n + 1, energy, h, k, l) + externalAngles + (tag,)
|
||||
lines.append(format % values)
|
||||
return lines
|
||||
532
script/__Lib/diffcalc_old/diffcalc/ub/ub.py
Normal file
532
script/__Lib/diffcalc_old/diffcalc/ub/ub.py
Normal file
@@ -0,0 +1,532 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# Diffcalc 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 Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from diffcalc import settings
|
||||
from diffcalc.ub.calc import UBCalculation
|
||||
|
||||
from math import asin, pi
|
||||
from datetime import datetime
|
||||
|
||||
try:
|
||||
from numpy import matrix
|
||||
except ImportError:
|
||||
from numjy import matrix
|
||||
|
||||
|
||||
from diffcalc.util import getInputWithDefault as promptForInput, \
|
||||
promptForNumber, promptForList, allnum, isnum, bold
|
||||
from diffcalc.util import command
|
||||
|
||||
TORAD = pi / 180
|
||||
TODEG = 180 / pi
|
||||
|
||||
|
||||
# When using ipython magic, these functions must not be imported to the top
|
||||
# level namespace. Doing so will stop them from being called with magic.
|
||||
|
||||
__all__ = ['addref', 'c2th', 'calcub', 'delref', 'editref', 'listub', 'loadub',
|
||||
'newub', 'saveubas', 'setlat', 'setu', 'setub', 'showref', 'swapref',
|
||||
'trialub', 'checkub', 'ub', 'ubcalc', 'rmub', 'clearref', 'lastub']
|
||||
|
||||
if settings.include_sigtau:
|
||||
__all__.append('sigtau')
|
||||
|
||||
if settings.include_reference:
|
||||
__all__.append('setnphi')
|
||||
__all__.append('setnhkl')
|
||||
|
||||
|
||||
ubcalc = UBCalculation(settings.hardware,
|
||||
settings.geometry,
|
||||
settings.ubcalc_persister,
|
||||
settings.ubcalc_strategy,
|
||||
settings.include_sigtau,
|
||||
settings.include_reference)
|
||||
|
||||
|
||||
|
||||
### UB state ###
|
||||
|
||||
@command
|
||||
def newub(name=None):
|
||||
"""newub {'name'} -- start a new ub calculation name
|
||||
"""
|
||||
if name is None:
|
||||
# interactive
|
||||
name = promptForInput('calculation name')
|
||||
ubcalc.start_new(name)
|
||||
setlat()
|
||||
elif isinstance(name, str):
|
||||
# just trying might cause confusion here
|
||||
ubcalc.start_new(name)
|
||||
else:
|
||||
raise TypeError()
|
||||
|
||||
@command
|
||||
def loadub(name_or_num):
|
||||
"""loadub 'name' | num -- load an existing ub calculation
|
||||
"""
|
||||
if isinstance(name_or_num, str):
|
||||
ubcalc.load(name_or_num)
|
||||
else:
|
||||
ubcalc.load(ubcalc.listub()[int(name_or_num)])
|
||||
|
||||
@command
|
||||
def lastub():
|
||||
"""lastub -- load the last used ub calculation
|
||||
"""
|
||||
try:
|
||||
lastub_name = ubcalc.listub()[0]
|
||||
print "Loading ub calculation: '%s'" % lastub_name
|
||||
loadub(0)
|
||||
except IndexError:
|
||||
print "WARNING: There is no record of the last ub calculation used"
|
||||
|
||||
@command
|
||||
def rmub(name_or_num):
|
||||
"""rmub 'name'|num -- remove existing ub calculation
|
||||
"""
|
||||
if isinstance(name_or_num, str):
|
||||
ubcalc.remove(name_or_num)
|
||||
else:
|
||||
ubcalc.remove(ubcalc.listub()[int(name_or_num)])
|
||||
|
||||
@command
|
||||
def listub():
|
||||
"""listub -- list the ub calculations available to load.
|
||||
"""
|
||||
if hasattr(ubcalc._persister, 'description'):
|
||||
print "UB calculations in: " + ubcalc._persister.description
|
||||
else:
|
||||
print "UB calculations:"
|
||||
print
|
||||
ubnames = ubcalc.listub()
|
||||
# TODO: whole mechanism of making two calls is messy
|
||||
try:
|
||||
ub_metadata = ubcalc.listub_metadata()
|
||||
except AttributeError:
|
||||
ub_metadata = [''] * len(ubnames)
|
||||
|
||||
for n, name, data in zip(range(len(ubnames)), ubnames, ub_metadata):
|
||||
print "%2i) %-15s %s" % (n, name, data)
|
||||
|
||||
@command
|
||||
def saveubas(name):
|
||||
"""saveubas 'name' -- save the ub calculation with a new name
|
||||
"""
|
||||
if isinstance(name, str):
|
||||
# just trying might cause confusion here
|
||||
ubcalc.saveas(name)
|
||||
else:
|
||||
raise TypeError()
|
||||
|
||||
@command
|
||||
def ub():
|
||||
"""ub -- show the complete state of the ub calculation
|
||||
"""
|
||||
#wavelength = float(hardware.get_wavelength())
|
||||
#energy = float(hardware.get_energy())
|
||||
print ubcalc.__str__()
|
||||
|
||||
### UB lattice ###
|
||||
|
||||
@command
|
||||
def setlat(name=None, *args):
|
||||
"""
|
||||
setlat -- interactively enter lattice parameters (Angstroms and Deg)
|
||||
setlat name a -- assumes cubic
|
||||
setlat name a b -- assumes tetragonal
|
||||
setlat name a b c -- assumes ortho
|
||||
setlat name a b c gamma -- assumes mon/hex with gam not equal to 90
|
||||
setlat name a b c alpha beta gamma -- arbitrary
|
||||
"""
|
||||
|
||||
if name is None: # Interactive
|
||||
name = promptForInput("crystal name")
|
||||
a = promptForNumber(' a', 1)
|
||||
b = promptForNumber(' b', a)
|
||||
c = promptForNumber(' c', a)
|
||||
alpha = promptForNumber('alpha', 90)
|
||||
beta = promptForNumber('beta', 90)
|
||||
gamma = promptForNumber('gamma', 90)
|
||||
ubcalc.set_lattice(name, a, b, c, alpha, beta, gamma)
|
||||
|
||||
elif (isinstance(name, str) and
|
||||
len(args) in (1, 2, 3, 4, 6) and
|
||||
allnum(args)):
|
||||
# first arg is string and rest are numbers
|
||||
ubcalc.set_lattice(name, *args)
|
||||
else:
|
||||
raise TypeError()
|
||||
|
||||
@command
|
||||
def c2th(hkl, en=None):
|
||||
"""
|
||||
c2th [h k l] -- calculate two-theta angle for reflection
|
||||
"""
|
||||
if en is None:
|
||||
wl = settings.hardware.get_wavelength() # @UndefinedVariable
|
||||
else:
|
||||
wl = 12.39842 / en
|
||||
d = ubcalc.get_hkl_plane_distance(hkl)
|
||||
if wl > (2 * d):
|
||||
raise ValueError(
|
||||
'Reflection un-reachable as wavelength (%f) is more than twice\n'
|
||||
'the plane distance (%f)' % (wl, d))
|
||||
try:
|
||||
return 2.0 * asin(wl / (d * 2)) * TODEG
|
||||
except ValueError as e:
|
||||
raise ValueError('asin(wl / (d * 2) with wl=%f and d=%f: ' %(wl, d) + e.args[0])
|
||||
|
||||
|
||||
### Surface and reference vector stuff ###
|
||||
|
||||
@command
|
||||
def sigtau(sigma=None, tau=None):
|
||||
"""sigtau {sigma tau} -- sets or displays sigma and tau"""
|
||||
if sigma is None and tau is None:
|
||||
chi = settings.hardware.get_position_by_name('chi') # @UndefinedVariable
|
||||
phi = settings.hardware.get_position_by_name('phi') # @UndefinedVariable
|
||||
_sigma, _tau = ubcalc.sigma, ubcalc.tau
|
||||
print "sigma, tau = %f, %f" % (_sigma, _tau)
|
||||
print " chi, phi = %f, %f" % (chi, phi)
|
||||
sigma = promptForInput("sigma", -chi)
|
||||
tau = promptForInput(" tau", -phi)
|
||||
ubcalc.sigma = sigma
|
||||
ubcalc.tau = tau
|
||||
else:
|
||||
ubcalc.sigma = float(sigma)
|
||||
ubcalc.tau = float(tau)
|
||||
|
||||
|
||||
@command
|
||||
def setnphi(xyz = None):
|
||||
"""setnphi {[x y z]} -- sets or displays n_phi reference"""
|
||||
if xyz is None:
|
||||
ubcalc.print_reference()
|
||||
else:
|
||||
ubcalc.set_n_phi_configured(_to_column_vector_triple(xyz))
|
||||
ubcalc.print_reference()
|
||||
|
||||
@command
|
||||
def setnhkl(hkl):
|
||||
"""setnhkl {[h k l]} -- sets or displays n_hkl reference"""
|
||||
if hkl is None:
|
||||
ubcalc.print_reference()
|
||||
else:
|
||||
ubcalc.set_n_hkl_configured(_to_column_vector_triple(hkl))
|
||||
ubcalc.print_reference()
|
||||
|
||||
|
||||
def _to_column_vector_triple(o):
|
||||
m = matrix(o)
|
||||
if m.shape == (1, 3):
|
||||
return m.T
|
||||
elif m.shape == (3, 1):
|
||||
return m
|
||||
else:
|
||||
raise ValueError("Unexpected shape matrix: " + m)
|
||||
|
||||
### UB refelections ###
|
||||
|
||||
@command
|
||||
def showref():
|
||||
"""showref -- shows full reflection list"""
|
||||
if ubcalc._state.reflist:
|
||||
print '\n'.join(ubcalc._state.reflist.str_lines())
|
||||
else:
|
||||
print "<<< No reflections stored >>>"
|
||||
|
||||
@command
|
||||
def addref(*args):
|
||||
"""
|
||||
addref -- add reflection interactively
|
||||
addref [h k l] {'tag'} -- add reflection with current position and energy
|
||||
addref [h k l] (p1, .., pN) energy {'tag'} -- add arbitrary reflection
|
||||
"""
|
||||
|
||||
if len(args) == 0:
|
||||
h = promptForNumber('h', 0.)
|
||||
k = promptForNumber('k', 0.)
|
||||
l = promptForNumber('l', 0.)
|
||||
if None in (h, k, l):
|
||||
_handleInputError("h,k and l must all be numbers")
|
||||
reply = promptForInput('current pos', 'y')
|
||||
if reply in ('y', 'Y', 'yes'):
|
||||
positionList = settings.hardware.get_position() # @UndefinedVariable
|
||||
energy = settings.hardware.get_energy() # @UndefinedVariable
|
||||
else:
|
||||
currentPos = settings.hardware.get_position() # @UndefinedVariable
|
||||
positionList = []
|
||||
names = settings.hardware.get_axes_names() # @UndefinedVariable
|
||||
for i, angleName in enumerate(names):
|
||||
val = promptForNumber(angleName.rjust(7), currentPos[i])
|
||||
if val is None:
|
||||
_handleInputError("Please enter a number, or press"
|
||||
" Return to accept default!")
|
||||
return
|
||||
positionList.append(val)
|
||||
energy = promptForNumber('energy', settings.hardware.get_energy()) # @UndefinedVariable
|
||||
if val is None:
|
||||
_handleInputError("Please enter a number, or press "
|
||||
"Return to accept default!")
|
||||
return
|
||||
muliplier = settings.hardware.energyScannableMultiplierToGetKeV # @UndefinedVariable
|
||||
energy = energy * muliplier
|
||||
tag = promptForInput("tag")
|
||||
if tag == '':
|
||||
tag = None
|
||||
pos = settings.geometry.physical_angles_to_internal_position(positionList) # @UndefinedVariable
|
||||
ubcalc.add_reflection(h, k, l, pos, energy, tag,
|
||||
datetime.now())
|
||||
elif len(args) in (1, 2, 3, 4):
|
||||
args = list(args)
|
||||
h, k, l = args.pop(0)
|
||||
if not (isnum(h) and isnum(k) and isnum(l)):
|
||||
raise TypeError()
|
||||
if len(args) >= 2:
|
||||
pos = settings.geometry.physical_angles_to_internal_position( # @UndefinedVariable
|
||||
args.pop(0))
|
||||
energy = args.pop(0)
|
||||
if not isnum(energy):
|
||||
raise TypeError()
|
||||
else:
|
||||
pos = settings.geometry.physical_angles_to_internal_position( # @UndefinedVariable
|
||||
settings.hardware.get_position()) # @UndefinedVariable
|
||||
energy = settings.hardware.get_energy() # @UndefinedVariable
|
||||
if len(args) == 1:
|
||||
tag = args.pop(0)
|
||||
if not isinstance(tag, str):
|
||||
raise TypeError()
|
||||
else:
|
||||
tag = None
|
||||
ubcalc.add_reflection(h, k, l, pos, energy, tag,
|
||||
datetime.now())
|
||||
else:
|
||||
raise TypeError()
|
||||
|
||||
@command
|
||||
def editref(num):
|
||||
"""editref num -- interactively edit a reflection.
|
||||
"""
|
||||
num = int(num)
|
||||
|
||||
# Get old reflection values
|
||||
[oldh, oldk, oldl], oldExternalAngles, oldEnergy, oldTag, oldT = \
|
||||
ubcalc.get_reflection_in_external_angles(num)
|
||||
del oldT # current time will be used.
|
||||
|
||||
h = promptForNumber('h', oldh)
|
||||
k = promptForNumber('k', oldk)
|
||||
l = promptForNumber('l', oldl)
|
||||
if None in (h, k, l):
|
||||
_handleInputError("h,k and l must all be numbers")
|
||||
reply = promptForInput('update position with current hardware setting',
|
||||
'n')
|
||||
if reply in ('y', 'Y', 'yes'):
|
||||
positionList = settings.hardware.get_position() # @UndefinedVariable
|
||||
energy = settings.hardware.get_energy() # @UndefinedVariable
|
||||
else:
|
||||
positionList = []
|
||||
names = settings.hardware.get_axes_names() # @UndefinedVariable
|
||||
for i, angleName in enumerate(names):
|
||||
val = promptForNumber(angleName.rjust(7), oldExternalAngles[i])
|
||||
if val is None:
|
||||
_handleInputError("Please enter a number, or press "
|
||||
"Return to accept default!")
|
||||
return
|
||||
positionList.append(val)
|
||||
energy = promptForNumber('energy', oldEnergy)
|
||||
if val is None:
|
||||
_handleInputError("Please enter a number, or press Return "
|
||||
"to accept default!")
|
||||
return
|
||||
energy = energy * settings.hardware.energyScannableMultiplierToGetKeV # @UndefinedVariable
|
||||
tag = promptForInput("tag", oldTag)
|
||||
if tag == '':
|
||||
tag = None
|
||||
pos = settings.geometry.physical_angles_to_internal_position(positionList) # @UndefinedVariable
|
||||
ubcalc.edit_reflection(num, h, k, l, pos, energy, tag,
|
||||
datetime.now())
|
||||
|
||||
@command
|
||||
def delref(num):
|
||||
"""delref num -- deletes a reflection (numbered from 1)
|
||||
"""
|
||||
ubcalc.del_reflection(int(num))
|
||||
|
||||
@command
|
||||
def clearref():
|
||||
"""clearref -- deletes all the reflections
|
||||
"""
|
||||
while ubcalc.get_number_reflections():
|
||||
ubcalc.del_reflection(1)
|
||||
|
||||
@command
|
||||
def swapref(num1=None, num2=None):
|
||||
"""
|
||||
swapref -- swaps first two reflections used for calulating U matrix
|
||||
swapref num1 num2 -- swaps two reflections (numbered from 1)
|
||||
"""
|
||||
if num1 is None and num2 is None:
|
||||
ubcalc.swap_reflections(1, 2)
|
||||
elif isinstance(num1, int) and isinstance(num2, int):
|
||||
ubcalc.swap_reflections(num1, num2)
|
||||
else:
|
||||
raise TypeError()
|
||||
|
||||
### UB calculations ###
|
||||
|
||||
@command
|
||||
def setu(U=None):
|
||||
"""setu {[[..][..][..]]} -- manually set u matrix
|
||||
"""
|
||||
if U is None:
|
||||
U = _promptFor3x3MatrixDefaultingToIdentity()
|
||||
if U is None:
|
||||
return # an error will have been printed or thrown
|
||||
if _is3x3TupleOrList(U) or _is3x3Matrix(U):
|
||||
ubcalc.set_U_manually(U)
|
||||
else:
|
||||
raise TypeError("U must be given as 3x3 list or tuple")
|
||||
|
||||
@command
|
||||
def setub(UB=None):
|
||||
"""setub {[[..][..][..]]} -- manually set ub matrix"""
|
||||
if UB is None:
|
||||
UB = _promptFor3x3MatrixDefaultingToIdentity()
|
||||
if UB is None:
|
||||
return # an error will have been printed or thrown
|
||||
if _is3x3TupleOrList(UB):
|
||||
ubcalc.set_UB_manually(UB)
|
||||
else:
|
||||
raise TypeError("UB must be given as 3x3 list or tuple")
|
||||
|
||||
def _promptFor3x3MatrixDefaultingToIdentity():
|
||||
estring = "Please enter a number, or press Return to accept default!"
|
||||
row1 = promptForList("row1", (1, 0, 0))
|
||||
if row1 is None:
|
||||
_handleInputError(estring)
|
||||
return None
|
||||
row2 = promptForList("row2", (0, 1, 0))
|
||||
if row2 is None:
|
||||
_handleInputError(estring)
|
||||
return None
|
||||
row3 = promptForList("row3", (0, 0, 1))
|
||||
if row3 is None:
|
||||
_handleInputError(estring)
|
||||
return None
|
||||
return [row1, row2, row3]
|
||||
|
||||
@command
|
||||
def calcub():
|
||||
"""calcub -- (re)calculate u matrix from ref1 and ref2.
|
||||
"""
|
||||
ubcalc.calculate_UB()
|
||||
|
||||
@command
|
||||
def trialub():
|
||||
"""trialub -- (re)calculate u matrix from ref1 only (check carefully).
|
||||
"""
|
||||
ubcalc.calculate_UB_from_primary_only()
|
||||
|
||||
|
||||
# This command requires the ubcalc
|
||||
|
||||
def checkub():
|
||||
"""checkub -- show calculated and entered hkl values for reflections.
|
||||
"""
|
||||
|
||||
s = "\n %7s %4s %4s %4s %6s %6s %6s TAG\n" % \
|
||||
('ENERGY', 'H', 'K', 'L', 'H_COMP', 'K_COMP', 'L_COMP')
|
||||
s = bold(s)
|
||||
nref = ubcalc.get_number_reflections()
|
||||
if not nref:
|
||||
s += "<<empty>>"
|
||||
for n in range(nref):
|
||||
hklguess, pos, energy, tag, _ = ubcalc.get_reflection(n + 1)
|
||||
wavelength = 12.39842 / energy
|
||||
hkl = settings.angles_to_hkl_function(pos.inRadians(), wavelength, ubcalc.UB)
|
||||
h, k, l = hkl
|
||||
if tag is None:
|
||||
tag = ""
|
||||
s += ("% 2d % 6.4f % 4.2f % 4.2f % 4.2f % 6.4f % 6.4f "
|
||||
"% 6.4f %6s\n" % (n + 1, energy, hklguess[0],
|
||||
hklguess[1], hklguess[2], h, k, l, tag))
|
||||
print s
|
||||
|
||||
|
||||
commands_for_help = ['State',
|
||||
newub,
|
||||
loadub,
|
||||
lastub,
|
||||
listub,
|
||||
rmub,
|
||||
saveubas,
|
||||
ub,
|
||||
'Lattice',
|
||||
setlat,
|
||||
c2th]
|
||||
|
||||
if ubcalc.include_reference:
|
||||
commands_for_help.extend([
|
||||
'Reference (surface)',
|
||||
setnphi,
|
||||
setnhkl])
|
||||
|
||||
if ubcalc.include_sigtau:
|
||||
commands_for_help.extend([
|
||||
'Surface',
|
||||
sigtau])
|
||||
|
||||
commands_for_help.extend([
|
||||
'Reflections',
|
||||
showref,
|
||||
addref,
|
||||
editref,
|
||||
delref,
|
||||
clearref,
|
||||
swapref,
|
||||
'ub matrix',
|
||||
checkub,
|
||||
setu,
|
||||
setub,
|
||||
calcub,
|
||||
trialub])
|
||||
|
||||
|
||||
|
||||
def _is3x3TupleOrList(m):
|
||||
if type(m) not in (list, tuple):
|
||||
return False
|
||||
if len(m) != 3:
|
||||
return False
|
||||
for mrow in m:
|
||||
if type(mrow) not in (list, tuple):
|
||||
return False
|
||||
if len(mrow) != 3:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def _is3x3Matrix(m):
|
||||
return isinstance(m, matrix) and tuple(m.shape) == (3, 3)
|
||||
|
||||
|
||||
def _handleInputError(msg):
|
||||
raise TypeError(msg)
|
||||
Reference in New Issue
Block a user