Files
dev/script/__Lib/diffcalc-snapshot/diffcalc/hkl/calcbase.py
2019-03-20 13:52:00 +01:00

156 lines
6.0 KiB
Python

###
# 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
from diffcalc.util import DiffcalcException, differ
TORAD = pi / 180
TODEG = 180 / pi
class HklCalculatorBase(object):
def __init__(self, ubcalc, geometry, hardware,
raiseExceptionsIfAnglesDoNotMapBackToHkl=False):
self._ubcalc = ubcalc # to get the UBMatrix, tau and sigma
self._geometry = geometry # to access information about the
# diffractometer geometry and mode_selector
self._hardware = hardware # Used for tracking parameters only
self.raiseExceptionsIfAnglesDoNotMapBackToHkl = \
raiseExceptionsIfAnglesDoNotMapBackToHkl
def anglesToHkl(self, pos, wavelength):
"""
Return hkl tuple and dictionary of all virtual angles in degrees from
Position in degrees and wavelength in Angstroms.
"""
h, k, l = self._anglesToHkl(pos.inRadians(), wavelength)
paramDict = self.anglesToVirtualAngles(pos, wavelength)
return ((h, k, l), paramDict)
def anglesToVirtualAngles(self, pos, wavelength):
"""
Return dictionary of all virtual angles in degrees from Position object
in degrees and wavelength in Angstroms.
"""
anglesDict = self._anglesToVirtualAngles(pos.inRadians(), wavelength)
for name in anglesDict:
anglesDict[name] = anglesDict[name] * TODEG
return anglesDict
def hklToAngles(self, h, k, l, wavelength):
"""
Return verified Position and all virtual angles in degrees from
h, k & l and wavelength in Angstroms.
The calculated Position is verified by checking that it maps back using
anglesToHkl() to the requested hkl value.
Those virtual angles fixed or generated while calculating the position
are verified by by checking that they map back using
anglesToVirtualAngles to the virtual angles for the given position.
Throws a DiffcalcException if either check fails and
raiseExceptionsIfAnglesDoNotMapBackToHkl is True, otherwise displays a
warning.
"""
# Update tracked parameters. During this calculation parameter values
# will be read directly from self._parameters instead of via
# self.getParameter which would trigger another potentially time-costly
# position update.
self.parameter_manager.update_tracked()
pos, virtualAngles = self._hklToAngles(h, k, l, wavelength) # in rad
# to degrees:
pos.changeToDegrees()
for key, val in virtualAngles.items():
if val is not None:
virtualAngles[key] = val * TODEG
self._verify_pos_map_to_hkl(h, k, l, wavelength, pos)
virtualAnglesReadback = self._verify_virtual_angles(h, k, l, wavelength, pos, virtualAngles)
return pos, virtualAnglesReadback
def _verify_pos_map_to_hkl(self, h, k, l, wavelength, pos):
hkl, _ = self.anglesToHkl(pos, wavelength)
e = 0.001
if ((abs(hkl[0] - h) > e) or (abs(hkl[1] - k) > e) or
(abs(hkl[2] - l) > e)):
s = "ERROR: The angles calculated for hkl=(%f,%f,%f) were %s.\n" % (h, k, l, str(pos))
s += "Converting these angles back to hkl resulted in hkl="\
"(%f,%f,%f)" % (hkl[0], hkl[1], hkl[2])
if self.raiseExceptionsIfAnglesDoNotMapBackToHkl:
raise DiffcalcException(s)
else:
print s
def _verify_virtual_angles(self, h, k, l, wavelength, pos, virtualAngles):
# Check that the virtual angles calculated/fixed during the hklToAngles
# those read back from pos using anglesToVirtualAngles
virtualAnglesReadback = self.anglesToVirtualAngles(pos, wavelength)
for key, val in virtualAngles.items():
if val != None: # Some values calculated in some mode_selector
r = virtualAnglesReadback[key]
if ((differ(val, r, .00001) and differ(val, r + 360, .00001) and differ(val, r - 360, .00001))):
s = "ERROR: The angles calculated for hkl=(%f,%f,%f) with"\
" mode=%s were %s.\n" % (h, k, l, self.repr_mode(), str(pos))
s += "During verification the virtual angle %s resulting "\
"from (or set for) this calculation of %f" % (key, val)
s += "did not match that calculated by "\
"anglesToVirtualAngles of %f" % virtualAnglesReadback[key]
if self.raiseExceptionsIfAnglesDoNotMapBackToHkl:
raise DiffcalcException(s)
else:
print s
return virtualAnglesReadback
def repr_mode(self):
pass
### Collect all math access to context here
def _getUBMatrix(self):
return self._ubcalc.UB
def _getMode(self):
return self.mode_selector.getMode()
def _getSigma(self):
return self._ubcalc.sigma
def _getTau(self):
return self._ubcalc.tau
def _getParameter(self, name):
# Does not use context.getParameter as this will trigger a costly
# parameter collection
pm = self.parameter_manager
return pm.getParameterWithoutUpdatingTrackedParemeters(name)
def _getGammaParameterName(self):
return self._gammaParameterName