Files
dev/script/__Lib/diffcalc-2.1/diffcalc/hkl/vlieg/constraints.py
2019-03-20 13:52:00 +01:00

337 lines
12 KiB
Python
Executable File

###
# 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 copy
from diffcalc.util import DiffcalcException
class Mode(object):
def __init__(self, index, name, group, description, parameterNames,
implemented=True):
self.index = index
self.group = group
self.name = name
self.description = description
self.parameterNames = parameterNames
self.implemented = implemented
def __repr__(self):
return "%i) %s" % (self.index, self.description)
def __str__(self):
return self.__repr__()
def usesParameter(self, name):
return name in self.parameterNames
class ModeSelector(object):
def __init__(self, geometry, parameterManager=None,
gammaParameterName='gamma'):
self.parameter_manager = parameterManager
self._geometry = geometry
self._gammaParameterName = gammaParameterName
self._modelist = {} # indexed by non-contiguous mode number
self._configureAvailableModes()
self._selectedIndex = 1
def setParameterManager(self, manager):
"""
Required as a ParameterManager and ModelSelector are mutually tied
together in practice
"""
self.parameter_manager = manager
def _configureAvailableModes(self):
gammaName = self._gammaParameterName
ml = self._modelist
ml[0] = Mode(0, '4cFixedw', 'fourc', 'fourc fixed-bandlw',
['alpha', gammaName, 'blw'], False)
ml[1] = Mode(1, '4cBeq', 'fourc', 'fourc bisecting',
['alpha', gammaName])
ml[2] = Mode(2, '4cBin', 'fourc', 'fourc incoming',
['alpha', gammaName, 'betain'])
ml[3] = Mode(3, '4cBout', 'fourc', 'fourc outgoing',
['alpha', gammaName, 'betaout'])
ml[4] = Mode(4, '4cAzimuth', 'fourc', 'fourc azimuth',
['alpha', gammaName, 'azimuth'], False)
ml[5] = Mode(5, '4cPhi', 'fourc', 'fourc fixed-phi',
['alpha', gammaName, 'phi'])
ml[10] = Mode(10, '5cgBeq', 'fivecFixedGamma', 'fivec bisecting',
[gammaName])
ml[11] = Mode(11, '5cgBin', 'fivecFixedGamma', 'fivec incoming',
[gammaName, 'betain'])
ml[12] = Mode(12, '5cgBout', 'fivecFixedGamma', 'fivec outgoing',
[gammaName, 'betaout'])
ml[13] = Mode(13, '5caBeq', 'fivecFixedAlpha', 'fivec bisecting',
['alpha'])
ml[14] = Mode(14, '5caBin', 'fivecFixedAlpha', 'fivec incoming',
['alpha', 'betain'])
ml[15] = Mode(15, '5caBout', 'fivecFixedAlpha', 'fivec outgoing',
['alpha', 'betaout'])
ml[20] = Mode(20, '6czBeq', 'zaxis', 'zaxis bisecting',
[])
ml[21] = Mode(21, '6czBin', 'zaxis', 'zaxis incoming',
['betain'])
ml[22] = Mode(22, '6czBout', 'zaxis', 'zaxiz outgoing',
['betaout'])
def setModeByIndex(self, index):
if index in self._modelist:
self._selectedIndex = index
else:
raise DiffcalcException("mode %r is not defined" % index)
def setModeByName(self, name):
def findModeWithName(name):
for index, mode in self._modelist.items():
if mode.name == name:
return index, mode
raise ValueError
try:
index, mode = findModeWithName(name)
except ValueError:
raise DiffcalcException(
'Unknown mode. The diffraction calculator supports these '
'modeSelector: %s' % self._supportedModes.keys())
if self._geometry.supports_mode_group(mode.group):
self._selectedIndex = index
else:
raise DiffcalcException(
"Mode %s not supported for this diffractometer (%s)." %
(name, self._geometry.name))
def getMode(self):
return self._modelist[self._selectedIndex]
def reportCurrentMode(self):
return self.getMode().__str__()
def reportAvailableModes(self):
result = ''
indecis = self._modelist.keys()
indecis.sort()
for index in indecis:
mode = self._modelist[index]
if self._geometry.supports_mode_group(mode.group):
paramString = ''
flags = ''
pm = self.parameter_manager
for paramName in pm.getUserChangableParametersForMode(mode):
paramString += paramName + ", "
if paramString:
paramString = paramString[:-2] # remove trailing commas
if not mode.implemented:
flags += "(Not impl.)"
result += ('%2i) %-15s (%s) %s\n' % (mode.index,
mode.description, paramString, flags))
return result
class VliegParameterManager(object):
def __init__(self, geometry, hardware, modeSelector,
gammaParameterName='gamma'):
self._geometry = geometry
self._hardware = hardware
self._modeSelector = modeSelector
self._gammaParameterName = gammaParameterName
self._parameters = {}
self._defineParameters()
def _defineParameters(self):
# Set default fixed values (In degrees if angles)
self._parameters = {}
self._parameters['alpha'] = 0
self._parameters[self._gammaParameterName] = 0
self._parameters['blw'] = None # Busing and Levi omega!
self._parameters['betain'] = None
self._parameters['betaout'] = None
self._parameters['azimuth'] = None
self._parameters['phi'] = None
self._parameterDisplayOrder = (
'alpha', self._gammaParameterName, 'betain', 'betaout', 'azimuth',
'phi', 'blw')
self._trackableParameters = ('alpha', self._gammaParameterName, 'phi')
self._trackedParameters = []
# Overide parameters that are unchangable for this diffractometer
for (name, value) in self._geometry.fixed_parameters.items():
if name not in self._parameters:
raise RuntimeError(
"The %s diffractometer geometry specifies a fixed "
"parameter %s that is not used by the diffractometer "
"calculator" % (self._geometry.getName, name))
self._parameters[name] = value
def reportAllParameters(self):
self.update_tracked()
result = ''
for name in self._parameterDisplayOrder:
flags = ""
if not self._modeSelector.getMode().usesParameter(name):
flags += '(not relevant in this mode)'
if self._geometry.parameter_fixed(name):
flags += ' (fixed by this diffractometer)'
if self.isParameterTracked(name):
flags += ' (tracking hardware)'
value = self._parameters[name]
if value is None:
value = '---'
else:
value = float(value)
result += '%s: %s %s\n' % (name.rjust(8), value, flags)
return result
def reportParametersUsedInCurrentMode(self):
self.update_tracked()
result = ''
for name in self.getUserChangableParametersForMode(
self._modeSelector.getMode()):
flags = ""
value = self._parameters[name]
if value is None:
value = '---'
else:
value = float(value)
if self.isParameterTracked(name):
flags += ' (tracking hardware)'
result += '%s: %s %s\n' % (name.rjust(8), value, flags)
return result
def getUserChangableParametersForMode(self, mode=None):
"""
(p1,p2...p3) = getUserChangableParametersForMode(mode) returns a list
of parameters names used in this mode for this diffractometer geometry.
Checks current mode if no mode specified.
"""
if mode is None:
mode = self._mode
result = []
for name in self._parameterDisplayOrder:
if self._isParameterChangeable(name, mode):
result += [name]
return result
### Fixed parameters stuff ###
def set_constraint(self, name, value):
if not name in self._parameters:
raise DiffcalcException("No fixed parameter %s is used by the "
"diffraction calculator" % name)
if self._geometry.parameter_fixed(name):
raise DiffcalcException(
"The parameter %s cannot be changed: It has been fixed by the "
"%s diffractometer geometry"
% (name, self._geometry.name))
if self.isParameterTracked(name):
# for safety and to avoid confusion:
raise DiffcalcException(
"Cannot change parameter %s as it is set to track an axis.\n"
"To turn this off use a command like 'trackalpha 0'." % name)
if not self.isParameterUsedInSelectedMode(name):
print ("WARNING: The parameter %s is not used in mode %i" %
(name, self._modeSelector.getMode().index))
self._parameters[name] = value
def isParameterUsedInSelectedMode(self, name):
return self._modeSelector.getMode().usesParameter(name)
def getParameterWithoutUpdatingTrackedParemeters(self, name):
try:
return self._parameters[name]
except KeyError:
raise DiffcalcException("No fixed parameter %s is used by the "
"diffraction calculator" % name)
def get_constraint(self, name):
self.update_tracked()
return self.getParameterWithoutUpdatingTrackedParemeters(name)
def getParameterDict(self):
self.update_tracked()
return copy(self._parameters)
@property
def settable_constraint_names(self):
"""list of all available constraints that have settable values"""
return sorted(self.getParameterDict().keys())
def setTrackParameter(self, name, switch):
if not name in self._parameters.keys():
raise DiffcalcException("No fixed parameter %s is used by the "
"diffraction calculator" % name)
if not name in self._trackableParameters:
raise DiffcalcException("Parameter %s is not trackable" % name)
if not self._isParameterChangeable(name):
print ("WARNING: Parameter %s is not used in mode %i" %
(name, self._mode.index))
if switch:
if name not in self._trackedParameters:
self._trackedParameters.append(name)
else:
if name in self._trackedParameters:
self._trackedParameters.remove(name)
def isParameterTracked(self, name):
return (name in self._trackedParameters)
def update_tracked(self):
"""Note that the name of a tracked parameter MUST map into the name of
an external diffractometer angle
"""
if self._trackedParameters:
externalAnglePositionArray = self._hardware.get_position()
externalAngleNames = list(self._hardware.get_axes_names())
for name in self._trackedParameters:
self._parameters[name] = \
externalAnglePositionArray[externalAngleNames.index(name)]
def _isParameterChangeable(self, name, mode=None):
"""
Returns true if parameter is used in a mode (current mode if none
specified), AND if it is not locked by the diffractometer geometry
"""
if mode is None:
mode = self._modeSelector.getMode()
return (mode.usesParameter(name) and
not self._geometry.parameter_fixed(name))