Startup
This commit is contained in:
292
script/__Lib/diffcalc_old/diffcalc/hkl/willmott/calc.py
Normal file
292
script/__Lib/diffcalc_old/diffcalc/hkl/willmott/calc.py
Normal file
@@ -0,0 +1,292 @@
|
||||
###
|
||||
# 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, asin, acos, atan2, sin, cos, sqrt
|
||||
|
||||
try:
|
||||
from numpy import matrix
|
||||
except ImportError:
|
||||
from numjy import matrix
|
||||
|
||||
from diffcalc.log import logging
|
||||
from diffcalc.util import bound, AbstractPosition, DiffcalcException,\
|
||||
x_rotation, z_rotation
|
||||
from diffcalc.hkl.vlieg.geometry import VliegGeometry
|
||||
from diffcalc.ub.calc import PaperSpecificUbCalcStrategy
|
||||
from diffcalc.hkl.calcbase import HklCalculatorBase
|
||||
from diffcalc.hkl.common import DummyParameterManager
|
||||
|
||||
logger = logging.getLogger("diffcalc.hkl.willmot.calcwill")
|
||||
|
||||
CHOOSE_POSITIVE_GAMMA = True
|
||||
|
||||
TORAD = pi / 180
|
||||
TODEG = 180 / pi
|
||||
I = matrix('1 0 0; 0 1 0; 0 0 1')
|
||||
SMALL = 1e-10
|
||||
|
||||
TEMPORARY_CONSTRAINTS_DICT_RAD = {'betain': 2 * TORAD}
|
||||
|
||||
|
||||
def create_matrices(delta, gamma, omegah, phi):
|
||||
return (calc_DELTA(delta), calc_GAMMA(gamma), calc_OMEGAH(omegah),
|
||||
calc_PHI(phi))
|
||||
|
||||
|
||||
def calc_DELTA(delta):
|
||||
return x_rotation(delta) # (39)
|
||||
|
||||
|
||||
def calc_GAMMA(gamma):
|
||||
return z_rotation(gamma) # (40)
|
||||
|
||||
|
||||
def calc_OMEGAH(omegah):
|
||||
return x_rotation(omegah) # (41)
|
||||
|
||||
|
||||
def calc_PHI(phi):
|
||||
return z_rotation(phi) # (42)
|
||||
|
||||
|
||||
def angles_to_hkl_phi(delta, gamma, omegah, phi):
|
||||
"""Calculate hkl matrix in phi frame in units of 2*pi/lambda
|
||||
"""
|
||||
DELTA, GAMMA, OMEGAH, PHI = create_matrices(delta, gamma, omegah, phi)
|
||||
H_lab = (GAMMA * DELTA - I) * matrix([[0], [1], [0]]) # (43)
|
||||
H_phi = PHI.I * OMEGAH.I * H_lab # (44)
|
||||
return H_phi
|
||||
|
||||
|
||||
def angles_to_hkl(delta, gamma, omegah, phi, wavelength, UB):
|
||||
"""Calculate hkl matrix in reprical lattice space in units of 1/Angstrom
|
||||
"""
|
||||
H_phi = angles_to_hkl_phi(delta, gamma, omegah, phi) * 2 * pi / wavelength
|
||||
hkl = UB.I * H_phi # (5)
|
||||
return hkl
|
||||
|
||||
|
||||
class WillmottHorizontalPosition(AbstractPosition):
|
||||
|
||||
def __init__(self, delta=None, gamma=None, omegah=None, phi=None):
|
||||
self.delta = delta
|
||||
self.gamma = gamma
|
||||
self.omegah = omegah
|
||||
self.phi = phi
|
||||
|
||||
def clone(self):
|
||||
return WillmottHorizontalPosition(self.delta, self.gamma, self.omegah,
|
||||
self.phi)
|
||||
|
||||
def changeToRadians(self):
|
||||
self.delta *= TORAD
|
||||
self.gamma *= TORAD
|
||||
self.omegah *= TORAD
|
||||
self.phi *= TORAD
|
||||
|
||||
def changeToDegrees(self):
|
||||
self.delta *= TODEG
|
||||
self.gamma *= TODEG
|
||||
self.omegah *= TODEG
|
||||
self.phi *= TODEG
|
||||
|
||||
def totuple(self):
|
||||
return (self.delta, self.gamma, self.omegah, self.phi)
|
||||
|
||||
def __str__(self):
|
||||
return ('WillmottHorizontalPosition('
|
||||
'delta: %.4f gamma: %.4f omegah: %.4f phi: %.4f)' %
|
||||
(self.delta, self.gamma, self.omegah, self.phi))
|
||||
|
||||
|
||||
class WillmottHorizontalGeometry(object):
|
||||
|
||||
def __init__(self):
|
||||
self.name = 'willmott_horizontal'
|
||||
|
||||
def physical_angles_to_internal_position(self, physicalAngles):
|
||||
return WillmottHorizontalPosition(*physicalAngles)
|
||||
|
||||
def internal_position_to_physical_angles(self, internalPosition):
|
||||
return internalPosition.totuple()
|
||||
|
||||
def create_position(self, delta, gamma, omegah, phi):
|
||||
return WillmottHorizontalPosition(delta, gamma, omegah, phi)
|
||||
|
||||
|
||||
class WillmottHorizontalUbCalcStrategy(PaperSpecificUbCalcStrategy):
|
||||
|
||||
def calculate_q_phi(self, pos):
|
||||
H_phi = angles_to_hkl_phi(*pos.totuple())
|
||||
return matrix(H_phi.tolist())
|
||||
|
||||
|
||||
class DummyConstraints(object):
|
||||
|
||||
@property
|
||||
def reference(self):
|
||||
"""dictionary of constrained reference circles"""
|
||||
return TEMPORARY_CONSTRAINTS_DICT_RAD
|
||||
|
||||
|
||||
class ConstraintAdapter(object):
|
||||
|
||||
def __init__(self, constraints):
|
||||
self._constraints = constraints
|
||||
|
||||
def getParameterDict(self):
|
||||
names = self._constraints.available
|
||||
return dict(zip(names, [None] * len(names)))
|
||||
|
||||
def setParameter(self, name, value):
|
||||
self._constraints.set_constraint(name, value)
|
||||
|
||||
def get(self, name):
|
||||
if name in self._constraints.all:
|
||||
val = self._constraints.get_value(name)
|
||||
return 999 if val is None else val
|
||||
else:
|
||||
return 999
|
||||
|
||||
def update_tracked(self):
|
||||
pass
|
||||
|
||||
|
||||
class WillmottHorizontalCalculator(HklCalculatorBase):
|
||||
|
||||
def __init__(self, ubcalc, geometry, hardware, constraints,
|
||||
raiseExceptionsIfAnglesDoNotMapBackToHkl=True):
|
||||
""""
|
||||
Where constraints.reference is a one element dict with the key either
|
||||
('betain', 'betaout' or 'equal') and the value a number or None for
|
||||
'betain_eq_betaout'
|
||||
"""
|
||||
|
||||
HklCalculatorBase.__init__(self, ubcalc, geometry, hardware,
|
||||
raiseExceptionsIfAnglesDoNotMapBackToHkl)
|
||||
|
||||
if constraints is not None:
|
||||
self.constraints = constraints
|
||||
self.parameter_manager = ConstraintAdapter(constraints)
|
||||
else:
|
||||
self.constraints = DummyConstraints()
|
||||
self.parameter_manager = DummyParameterManager()
|
||||
|
||||
@property
|
||||
def _UB(self):
|
||||
return self._ubcalc.UB
|
||||
|
||||
def _anglesToHkl(self, pos, wavelength):
|
||||
"""
|
||||
Calculate miller indices from position in radians.
|
||||
"""
|
||||
hkl_matrix = angles_to_hkl(pos.delta, pos.gamma, pos.omegah, pos.phi,
|
||||
wavelength, self._UB)
|
||||
return hkl_matrix[0, 0], hkl_matrix[1, 0], hkl_matrix[2, 0],
|
||||
|
||||
def _anglesToVirtualAngles(self, pos, wavelength):
|
||||
"""
|
||||
Calculate virtual-angles in radians from position in radians.
|
||||
|
||||
Return theta, alpha, and beta in a dictionary.
|
||||
"""
|
||||
|
||||
betain = pos.omegah # (52)
|
||||
|
||||
hkl = angles_to_hkl(pos.delta, pos.gamma, pos.omegah, pos.phi,
|
||||
wavelength, self._UB)
|
||||
H_phi = self._UB * hkl
|
||||
H_phi = H_phi / (2 * pi / wavelength)
|
||||
l_phi = H_phi[2, 0]
|
||||
sin_betaout = l_phi - sin(betain)
|
||||
betaout = asin(bound(sin_betaout)) # (54)
|
||||
|
||||
cos_2theta = cos(pos.delta) * cos(pos.gamma)
|
||||
theta = acos(bound(cos_2theta)) / 2.
|
||||
|
||||
return {'theta': theta, 'betain': betain, 'betaout': betaout}
|
||||
|
||||
def _hklToAngles(self, h, k, l, wavelength):
|
||||
"""
|
||||
Calculate position and virtual angles in radians for a given hkl.
|
||||
"""
|
||||
|
||||
H_phi = self._UB * matrix([[h], [k], [l]]) # units: 1/Angstrom
|
||||
H_phi = H_phi / (2 * pi / wavelength) # units: 2*pi/wavelength
|
||||
h_phi = H_phi[0, 0]
|
||||
k_phi = H_phi[1, 0]
|
||||
l_phi = H_phi[2, 0] # (5)
|
||||
|
||||
### determine betain (omegah) and betaout ###
|
||||
|
||||
if not self.constraints.reference:
|
||||
raise ValueError("No reference constraint has been constrained.")
|
||||
|
||||
ref_name, ref_value = self.constraints.reference.items()[0]
|
||||
if ref_value is not None:
|
||||
ref_value *= TORAD
|
||||
if ref_name == 'betain':
|
||||
betain = ref_value
|
||||
betaout = asin(bound(l_phi - sin(betain))) # (53)
|
||||
elif ref_name == 'betaout':
|
||||
betaout = ref_value
|
||||
betain = asin(bound(l_phi - sin(betaout))) # (54)
|
||||
elif ref_name == 'bin_eq_bout':
|
||||
betain = betaout = asin(bound(l_phi / 2)) # (55)
|
||||
else:
|
||||
raise ValueError("Unexpected constraint name'%s'." % ref_name)
|
||||
|
||||
if abs(betain) < SMALL:
|
||||
raise DiffcalcException('required betain was 0 degrees (requested '
|
||||
'q is perpendicular to surface normal)')
|
||||
if betain < -SMALL:
|
||||
raise DiffcalcException("betain was -ve (%.4f)" % betain)
|
||||
# logger.info('betain = %.4f, betaout = %.4f',
|
||||
# betain * TODEG, betaout * TODEG)
|
||||
omegah = betain # (52)
|
||||
|
||||
### determine H_lab (X, Y and Z) ###
|
||||
|
||||
Y = -(h_phi ** 2 + k_phi ** 2 + l_phi ** 2) / 2 # (45)
|
||||
|
||||
Z = (sin(betaout) + sin(betain) * (Y + 1)) / cos(omegah) # (47)
|
||||
|
||||
X_squared = (h_phi ** 2 + k_phi ** 2 -
|
||||
((cos(betain) * Y + sin(betain) * Z) ** 2)) # (48)
|
||||
if (X_squared < 0) and (abs(X_squared) < SMALL):
|
||||
X_squared = 0
|
||||
Xpositive = sqrt(X_squared)
|
||||
if CHOOSE_POSITIVE_GAMMA:
|
||||
X = -Xpositive
|
||||
else:
|
||||
X = Xpositive
|
||||
# logger.info('H_lab (X,Y,Z) = [%.4f, %.4f, %.4f]', X, Y, Z)
|
||||
### determine diffractometer angles ###
|
||||
|
||||
gamma = atan2(-X, Y + 1) # (49)
|
||||
if (abs(gamma) < SMALL):
|
||||
# degenerate case, only occurs when q || z
|
||||
delta = 2 * omegah
|
||||
else:
|
||||
delta = atan2(Z * sin(gamma), -X) # (50)
|
||||
M = cos(betain) * Y + sin(betain) * Z
|
||||
phi = atan2(h_phi * M - k_phi * X, h_phi * X + k_phi * M) # (51)
|
||||
|
||||
pos = WillmottHorizontalPosition(delta, gamma, omegah, phi)
|
||||
virtual_angles = {'betain': betain, 'betaout': betaout}
|
||||
return pos, virtual_angles
|
||||
58
script/__Lib/diffcalc_old/diffcalc/hkl/willmott/commands.py
Normal file
58
script/__Lib/diffcalc_old/diffcalc/hkl/willmott/commands.py
Normal file
@@ -0,0 +1,58 @@
|
||||
###
|
||||
# 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.hkl.common import getNameFromScannableOrString
|
||||
from diffcalc.util import command
|
||||
|
||||
|
||||
class WillmottHklCommands(object):
|
||||
|
||||
def __init__(self, hklcalc):
|
||||
self._hklcalc = hklcalc
|
||||
self.commands = [self.con,
|
||||
self.uncon,
|
||||
self.cons]
|
||||
|
||||
def __str__(self):
|
||||
return self._hklcalc.__str__()
|
||||
|
||||
@command
|
||||
def con(self, scn_or_string):
|
||||
"""con <constraint> -- constrains constraint
|
||||
"""
|
||||
name = getNameFromScannableOrString(scn_or_string)
|
||||
self._hklcalc.constraints.constrain(name)
|
||||
print self._report_constraints()
|
||||
|
||||
@command
|
||||
def uncon(self, scn_or_string):
|
||||
"""uncon <constraint> -- unconstrains constraint
|
||||
"""
|
||||
name = getNameFromScannableOrString(scn_or_string)
|
||||
self._hklcalc.constraints.unconstrain(name)
|
||||
print self._report_constraints()
|
||||
|
||||
@command
|
||||
def cons(self):
|
||||
"""cons -- list available constraints and values
|
||||
"""
|
||||
print self._report_constraints()
|
||||
|
||||
def _report_constraints(self):
|
||||
return (self._hklcalc.constraints.build_display_table_lines() + '\n\n' +
|
||||
self._hklcalc.constraints._report_constraints())
|
||||
156
script/__Lib/diffcalc_old/diffcalc/hkl/willmott/constraints.py
Normal file
156
script/__Lib/diffcalc_old/diffcalc/hkl/willmott/constraints.py
Normal file
@@ -0,0 +1,156 @@
|
||||
###
|
||||
# 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.util import DiffcalcException
|
||||
|
||||
|
||||
def filter_dict(d, keys):
|
||||
"""Return a copy of d containing only keys that are in keys"""
|
||||
##return {k: d[k] for k in keys} # requires Python 2.6
|
||||
return dict((k, d[k]) for k in keys if k in d.keys())
|
||||
|
||||
|
||||
ref_constraints = ('betain', 'betaout', 'bin_eq_bout')
|
||||
valueless_constraints = ('bin_eq_bout')
|
||||
all_constraints = ref_constraints
|
||||
|
||||
|
||||
class WillmottConstraintManager(object):
|
||||
"""Constraints in degrees.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self._constrained = {'bin_eq_bout': None}
|
||||
|
||||
@property
|
||||
def available_constraint_names(self):
|
||||
"""list of all available constraints"""
|
||||
return all_constraints
|
||||
|
||||
@property
|
||||
def all(self): # @ReservedAssignment
|
||||
"""dictionary of all constrained values"""
|
||||
return self._constrained.copy()
|
||||
|
||||
@property
|
||||
def reference(self):
|
||||
"""dictionary of constrained reference circles"""
|
||||
return filter_dict(self.all, ref_constraints)
|
||||
|
||||
@property
|
||||
def constrained_names(self):
|
||||
"""ordered tuple of constained circles"""
|
||||
names = self.all.keys()
|
||||
names.sort(key=lambda name: list(all_constraints).index(name))
|
||||
return tuple(names)
|
||||
|
||||
def is_constrained(self, name):
|
||||
return name in self._constrained
|
||||
|
||||
def get_value(self, name):
|
||||
return self._constrained[name]
|
||||
|
||||
def _build_display_table(self):
|
||||
constraint_types = (ref_constraints,)
|
||||
num_rows = max([len(col) for col in constraint_types])
|
||||
max_name_width = max(
|
||||
[len(name) for name in sum(constraint_types[:2], ())])
|
||||
# headings
|
||||
lines = [' ' + 'REF'.ljust(max_name_width)]
|
||||
lines.append(' ' + '=' * max_name_width + ' ')
|
||||
|
||||
# constraint rows
|
||||
for n_row in range(num_rows):
|
||||
cells = []
|
||||
for col in constraint_types:
|
||||
name = col[n_row] if n_row < len(col) else ''
|
||||
cells.append(self._label_constraint(name))
|
||||
cells.append(('%-' + str(max_name_width) + 's ') % name)
|
||||
lines.append(''.join(cells))
|
||||
lines.append
|
||||
return '\n'.join(lines)
|
||||
|
||||
def _report_constraints(self):
|
||||
if not self.reference:
|
||||
return "!!! No reference constraint set"
|
||||
name, val = self.reference.items()[0]
|
||||
if name in valueless_constraints:
|
||||
return " %s" % name
|
||||
else:
|
||||
if val is None:
|
||||
return "!!! %s: ---" % name
|
||||
else:
|
||||
return " %s: %.4f" % (name, val)
|
||||
|
||||
def _label_constraint(self, name):
|
||||
if name == '':
|
||||
label = ' '
|
||||
elif (self.is_constrained(name) and (self.get_value(name) is None) and
|
||||
name not in valueless_constraints):
|
||||
label = 'o-> '
|
||||
elif self.is_constrained(name):
|
||||
label = '--> '
|
||||
else:
|
||||
label = ' '
|
||||
return label
|
||||
|
||||
def constrain(self, name):
|
||||
if name in self.all:
|
||||
return "%s is already constrained." % name.capitalize()
|
||||
elif name in ref_constraints:
|
||||
return self._constrain_reference(name)
|
||||
else:
|
||||
raise DiffcalcException('%s is not a valid constraint name')
|
||||
|
||||
def _constrain_reference(self, name):
|
||||
if self.reference:
|
||||
constrained_name = self.reference.keys()[0]
|
||||
del self._constrained[constrained_name]
|
||||
self._constrained[name] = None
|
||||
return '%s constraint replaced.' % constrained_name.capitalize()
|
||||
else:
|
||||
self._constrained[name] = None
|
||||
|
||||
def unconstrain(self, name):
|
||||
if name in self._constrained:
|
||||
del self._constrained[name]
|
||||
else:
|
||||
return "%s was not already constrained." % name.capitalize()
|
||||
|
||||
###
|
||||
def _check_constraint_settable(self, name, verb):
|
||||
if name not in all_constraints:
|
||||
raise DiffcalcException(
|
||||
'Could not %(verb)s %(name)s as this is not an available '
|
||||
'constraint.' % locals())
|
||||
elif name not in self.all.keys():
|
||||
raise DiffcalcException(
|
||||
'Could not %(verb)s %(name)s as this is not currently '
|
||||
'constrained.' % locals())
|
||||
elif name in valueless_constraints:
|
||||
raise DiffcalcException(
|
||||
'Could not %(verb)s %(name)s as this constraint takes no '
|
||||
'value.' % locals())
|
||||
|
||||
def set_constraint(self, name, value): # @ReservedAssignment
|
||||
self._check_constraint_settable(name, 'set')
|
||||
old_value = self.all[name]
|
||||
old = str(old_value) if old_value is not None else '---'
|
||||
self._constrained[name] = float(value)
|
||||
new = str(value)
|
||||
return "%(name)s : %(old)s --> %(new)s" % locals()
|
||||
Reference in New Issue
Block a user