def get_upper_limit(self, name): '''returns upper limit by axis name. Limit may be None if not set ''' try: scn = self.diffhw.getGroupMember(name) except AttributeError: scn = self.diffhw.getFieldScannable(name) try: limit = scn.getUpperInnerLimit() return limit except AttributeError: pass try: limits = scn.getUpperGdaLimits() except AttributeError: raise DiffcalcException( "Cannot read upper limit for scannable {}".format(name)) try: if len(limits) != 1: raise DiffcalcException( "Upper limit for scannable {} has {} limit values".format( name, len(limits))) return limits[0] except TypeError: return limits
def calculate_UB_from_orientation(self): """ Calculate orientation matrix. Uses first two crystal orientations. """ # 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 crystal orientations if self._state.orientlist is None: raise DiffcalcException("Cannot calculate a U matrix until a " "UBCalculation has been started with " "'newub'") try: (h1, x1, _, _) = self._state.orientlist.getOrientation(1) (h2, x2, _, _) = self._state.orientlist.getOrientation(2) except IndexError: raise DiffcalcException( "Two crystal orientations are required to calculate a U matrix" ) h1 = matrix([h1]).T # row->column h2 = matrix([h2]).T u1p = matrix([x1]).T u2p = matrix([x2]).T self._calc_UB(h1, h2, u1p, u2p)
def fit_ub_matrix(self, *args): if args is None: raise DiffcalcException( "Please specify list of reference reflection indices.") if len(args) < 3: raise DiffcalcException( "Need at least 3 reference reflections to fit UB matrix.") if len(self._state.crystal.get_lattice_params()[1]) == 6: new_u, uc_params = self._fit_ub_matrix_uncon(*args) else: refl_list = [] for idx in args: try: hkl_vals, pos, en, _, _ = self.get_reflection(idx) pos.changeToRadians() refl_list.append(( hkl_vals, pos, en, )) except IndexError: raise DiffcalcException( "Cannot read reflection data for index %s" % str(idx)) print "Fitting crystal lattice parameters..." new_lattice = fit_crystal(self._state.crystal, refl_list) print "Fitting orientation matrix..." new_u = fit_u_matrix(self._U, new_lattice, refl_list) uc_params = (self._state.crystal.getLattice()[0], ) + new_lattice.getLattice()[1:] return new_u, uc_params
def __conic_th_to_hkl(self, params): from diffcalc.dc import dcyou as _dc from diffcalc.util import norm3, solve_h_fixed_q, solve_k_fixed_q import __main__ try: r, th, h0, k0 = params except TypeError: raise DiffcalcException("Invalid number of input parameters.") if not (th >= 0 and th < 180): raise DiffcalcException("Value of th should be n [0, 180) range") sin_th = sin(th * TORAD) cos_th = cos(th * TORAD) a = sin_th b = -cos_th c = 0 d = h0 * sin_th - k0 * cos_th h, k, l = __main__.hkl.getPosition()[:3] hkl_nphi = _dc._ub.ubcalc._UB * matrix([[h], [k], [l]]) qval = norm3(hkl_nphi)**2 if th > 45.: k = k0 + r * sin_th hkl = solve_k_fixed_q(k, qval, _dc._ub.ubcalc._UB, (a, b, c, d)) else: h = h0 + r * cos_th hkl = solve_h_fixed_q(h, qval, _dc._ub.ubcalc._UB, (a, b, c, d)) return hkl
def asynchronousMoveTo(self, newpos): pos = self.diffhw.getPosition() # a tuple (hkl_pos , _) = self._diffcalc.angles_to_hkl(pos) nref_hkl = [i[0] for i in self._diffcalc._ub.ubcalc.n_hkl.tolist()] pol, az_nref, sc = self._diffcalc._ub.ubcalc.calc_offset_for_hkl(hkl_pos, nref_hkl) if pol < SMALL: az_nref = 0 sc_nref_hkl = [sc * v for v in nref_hkl] _ubm = self._diffcalc._ub.ubcalc._get_UB() qvec = _ubm * matrix(hkl_pos).T qvec_rlu = sqrt(dot3(qvec, qvec)) * self._diffcalc._ub.ubcalc.get_hkl_plane_distance(nref_hkl) / (2.*pi) try: newpol = acos(bound(newpos / qvec_rlu)) except AssertionError: raise DiffcalcException("Scattering vector projection value of %.5f r.l.u. unreachable." % newpos) try: hkl_offset = self._diffcalc._ub.ubcalc.calc_hkl_offset(*sc_nref_hkl, pol=newpol, az=az_nref) (pos, _) = self._diffcalc.hkl_to_angles(*hkl_offset) except DiffcalcException as e: if DEBUG: raise else: raise DiffcalcException(e.message) self.diffhw.asynchronousMoveTo(pos)
def set_constraint(self, name, value): # @ReservedAssignment ext_name = settings.geometry.map_to_external_name(name) if self.is_constraint_fixed(name): raise DiffcalcException('%s constraint cannot be changed' % ext_name) self._check_constraint_settable(name) # if name in self._tracking: # raise DiffcalcException( # "Could not set %s as this constraint is configured to track " # "its associated\nphysical angle. First remove this tracking " # "(use 'untrack %s').""" % (name, name)) old_value = self.get_constraint(name) try: old_str = '---' if old_value is None else str(old_value) except Exception: old_str = '---' try: self._constrained[name] = float(value) * TORAD except Exception: raise DiffcalcException( 'Cannot set %s constraint. Invalid input value.' % ext_name) try: new_str = '---' if value is None else str(value) except Exception: new_str = '---' return "%s : %s --> %s" % (name, old_str, new_str)
def _calc_remaining_detector_angles(self, constraint_name, constraint_value, theta): """Return delta, nu and qaz given one detector angle """ # (section 5.1) # Find qaz using various derivations of 17 and 18 if constraint_name == 'delta': delta = constraint_value sin_2theta = sin(2 * theta) if is_small(sin_2theta): raise DiffcalcException( 'No meaningful scattering vector (Q) can be found when ' 'theta is so small (%.4f).' % theta * TODEG) qaz = asin(bound(sin(delta) / sin_2theta)) # (17 & 18) elif constraint_name == NUNAME: nu = constraint_value # cos_delta = cos(2*theta) / cos(nu)#<--fails when nu = 90 # delta = acos(bound(cos_delta)) # tan sin_2theta = sin(2 * theta) if is_small(sin_2theta): raise DiffcalcException( 'No meaningful scattering vector (Q) can be found when ' 'theta is so small (%.4f).' % theta * TODEG) cos_qaz = tan(nu) / tan(2 * theta) if abs(cos_qaz) > 1 + SMALL: raise DiffcalcException( 'The specified %s=%.4f is greater than the 2theta (%.4f)' % (NUNAME, nu, theta)) qaz = acos(bound(cos_qaz)) elif constraint_name == 'qaz': qaz = constraint_value else: raise ValueError( constraint_name + ' is not an explicit detector angle ' '(naz cannot be handled here)') if constraint_name != NUNAME: nu = atan2(sin(2 * theta) * cos(qaz), cos(2 * theta)) if constraint_name != 'delta': cos_qaz = cos(qaz) if not is_small(cos_qaz): # TODO: switch methods at 45 deg? delta = atan2(sin(qaz) * sin(nu), cos_qaz) else: # qaz is close to 90 (a common place for it) delta = sign(qaz) * acos(bound(cos(2 * theta) / cos(nu))) return delta, nu, qaz
def constrain(self, name): if self.is_constraint_fixed(name): raise DiffcalcException('%s is not a valid constraint name' % name) if name in self.all: return "%s is already constrained." % name.capitalize() elif name in det_constraints: return self._constrain_detector(name) elif name in ref_constraints: return self._constrain_reference(name) elif name in samp_constraints: return self._constrain_sample(name) else: raise DiffcalcException("%s is not a valid constraint name. Type 'con' for a table of constraint name" % name)
def _calc_theta(self, h_phi, wavelength): """Calculate theta using Equation1 """ q_length = norm(h_phi) if q_length == 0: raise DiffcalcException('Reflection is unreachable as |Q| is 0') wavevector = 2 * pi / wavelength try: theta = asin(q_length / (2 * wavevector)) except ValueError: raise DiffcalcException( 'Reflection is unreachable as |Q| is too long') return theta
def _check_constraint_settable(self, name): if name not in all_constraints: raise DiffcalcException( 'Could not set %(name)s. This is not an available ' 'constraint.' % locals()) elif name not in self.all.keys(): raise DiffcalcException( 'Could not set %(name)s. This is not currently ' 'constrained.' % locals()) elif name in valueless_constraints: raise DiffcalcException( 'Could not set %(name)s. This constraint takes no ' 'value.' % locals())
def _check_constraint_settable(self, name): ext_name = settings.geometry.map_to_external_name(name) if name not in all_constraints: raise DiffcalcException( 'Could not set %(ext_name)s. This is not an available ' 'constraint.' % locals()) elif name not in self.all.keys(): raise DiffcalcException( 'Could not set %(ext_name)s. This is not currently ' 'constrained.' % locals()) elif name in valueless_constraints: raise DiffcalcException( 'Could not set %(ext_name)s. This constraint takes no ' 'value.' % locals())
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 simulateMoveTo(self, hkl): if type(hkl) not in (list, tuple): raise ValueError('sr2 device expects four inputs') if len(hkl) != 4: raise ValueError('sr2 device expects four inputs') az = hkl[-1] * TORAD try: _hkl_ref = self._diffcalc._ub.ubcalc.get_reflection(1)[0] except IndexError: raise DiffcalcException("Please add one reference reflection into the reflection list.") pol, _, sc = self._diffcalc._ub.ubcalc.calc_offset_for_hkl(hkl[:3], _hkl_ref) hkl_sc= [sc * val for val in _hkl_ref] hkl_offset = self._diffcalc._ub.ubcalc.calc_hkl_offset(*hkl_sc, pol=pol, az=az) (pos, params) = self._diffcalc.hkl_to_angles(*hkl_offset) width = max(len(k) for k in (params.keys() + list(self.diffhw.getInputNames()))) fmt = ' %' + str(width) + 's : % 9.4f' lines = ['simulated hkl: %9.4f %.4f %.4f' % (hkl_offset[0],hkl_offset[1],hkl_offset[2]), self.diffhw.getName() + ' would move to:'] for idx, name in enumerate(self.diffhw.getInputNames()): lines.append(fmt % (name, pos[idx])) lines[-1] = lines[-1] + '\n' for k in sorted(params): lines.append(fmt % (k, params[k])) return '\n'.join(lines)
def __hkl_to_conic_h(self, hkl): h, _, _ = hkl try: a, b, c, d = self.cached_params except TypeError: raise DiffcalcException("hkl constraint values not set.") return (h, a, b, c, d)
def unconstrain(self, name): if self.is_constraint_fixed(name): raise DiffcalcException('%s is not a valid constraint name') if name in self._constrained: del self._constrained[name] else: return "%s was not already constrained." % name.capitalize()
def _raise_multiple_detector_solutions_found(delta_nu_pairs): assert len(delta_nu_pairs) > 1 delta_nu_pairs_degrees = [[v * TODEG for v in pair] for pair in delta_nu_pairs] raise DiffcalcException( 'Multiple detector solutions were found: delta, %s = %s, ' 'please constrain detector limits' % (NUNAME, delta_nu_pairs_degrees))
def normalise(m): d = norm(m) if d < SMALL: raise DiffcalcException( "Invalid UB reference data. Please check that the specified " "reference reflections/orientations are not parallel.") return m / d
def get_energy(self): """energy = get_energy() -- returns energy in kEv """ if self._wavelength is None: raise DiffcalcException( "Energy or wavelength have not been set") return (12.39842 / (self._wavelength * self.energyScannableMultiplierToGetKeV))
def add_reflection(self, h, k, l, position, energy, tag, time): """Add a reference reflection. Adds a reflection position in degrees and in the systems internal representation. Parameters ---------- h : number h index of the reflection k : number k index of the reflection l : number l index of the reflection position: :obj:`list` or :obj:`tuple` of numbers list of diffractometer angles in internal representation in degrees energy : float energy of the x-ray beam tag : str identifying tag for the reflection time : :obj:`datetime` datetime object """ 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 self.get_reference_count() == 2: self._autocalculateUbAndReport() self.save()
def set_U_manually(self, m, conv=True): """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." if conv: self._U = self._tobj.transform(m) else: self._U = m self._state.configure_calc_type(manual_U=self._U) 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 self.save()
def load(self, name): state = self._persister.load(name) if isinstance(self._persister, UBCalculationJSONPersister): self._state = self._persister.encoder.decode_ubcalcstate( state, settings.geometry, self._get_diffractometer_axes_names(), settings.hardware.energyScannableMultiplierToGetKeV) self._state.reference.get_UB = self._get_UB self._state.surface.get_UB = self._get_UB elif isinstance(self._persister, UBCalculationPersister): self._state = state else: raise DiffcalcException('Unexpected persister type: ' + str(self._persister)) if self._state.manual_U is not None: self._U = self._state.manual_U self._UB = self._U * self._state.crystal.B self.save() elif self._state.manual_UB is not None: self._UB = self._state.manual_UB self.save() elif self._state.is_okay_to_autocalculate_ub: try: self.calculate_UB(self._state.or0, self._state.or1) except Exception, e: print e
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 get_energy(self): """energy = get_energy() -- returns energy in keV (NOT eV!) """ multiplier = self.energyScannableMultiplierToGetKeV energy = self.energyhw.getPosition() * multiplier if energy is None: raise DiffcalcException("Energy has not been set") return energy
def newub(name=None): """newub {'name'} -- start a new ub calculation name """ if name is None: # interactive name = promptForInput('calculation name') while not name: print('Please provide non-empty UB calculation name') name = promptForInput('calculation name') try: ubcalc.start_new(name) except IOError: raise DiffcalcException('Cannot create UB calculation persistence file with name "%s"' % name) setlat() elif isinstance(name, str): if name in ubcalc._persister.list(): print ("No UB calculation started: There is already a calculation " "called: " + name) reply = promptForInput("Load the existing UB calculation '%s'? " % name, 'y') if reply in ('y', 'Y', 'yes'): loadub(name) return else: reply = promptForInput("Overwrite the existing UB calculation '%s'? " % name, 'y') if reply in ('y', 'Y', 'yes'): ubcalc.start_new(name) setlat() else: print ("Aborting") else: # just trying might cause confusion here ubcalc.start_new(name) else: raise TypeError()
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 asynchronousMoveTo(self, new_position): report = self.checkPositionValid([ new_position, ]) if report: raise DiffcalcException(report) self._current_position = float(new_position)
def asynchronousMoveTo(self, newpos): report = self.checkPositionValid([ newpos, ]) if report: raise DiffcalcException(report) ScannableBase.asynchronousMoveTo(self, newpos)
def _fit_ub_matrix_uncon(self, *args): if args is None: raise DiffcalcException( "Please specify list of reference reflection indices.") if len(args) < 3: raise DiffcalcException( "Need at least 3 reference reflections to fit UB matrix.") x = [] y = [] for idx in args: try: hkl_vals, pos, en, _, _ = self.get_reflection(idx) except IndexError: raise DiffcalcException( "Cannot read reflection data for index %s" % str(idx)) pos.changeToRadians() x.append(hkl_vals) wl = 12.3984 / en y_tmp = self._strategy.calculate_q_phi(pos) * 2. * pi / wl y.append(y_tmp.T.tolist()[0]) xm = matrix(x) ym = matrix(y) b = (xm.T * xm).I * xm.T * ym b1, b2, b3 = matrix(b.tolist()[0]), matrix(b.tolist()[1]), matrix( b.tolist()[2]) e1 = b1 / norm(b1) e2 = b2 - e1 * dot3(b2.T, e1.T) e2 = e2 / norm(e2) e3 = b3 - e1 * dot3(b3.T, e1.T) - e2 * dot3(b3.T, e2.T) e3 = e3 / norm(e3) new_umatrix = matrix(e1.tolist() + e2.tolist() + e3.tolist()).T V = dot3(cross3(b1.T, b2.T), b3.T) a1 = cross3(b2.T, b3.T) * 2 * pi / V a2 = cross3(b3.T, b1.T) * 2 * pi / V a3 = cross3(b1.T, b2.T) * 2 * pi / V ax, bx, cx = norm(a1), norm(a2), norm(a3) alpha = acos(dot3(a2, a3) / (bx * cx)) * TODEG beta = acos(dot3(a1, a3) / (ax * cx)) * TODEG gamma = acos(dot3(a1, a2) / (ax * bx)) * TODEG lattice_name = self._state.crystal.getLattice()[0] return new_umatrix, (lattice_name, ax, bx, cx, alpha, beta, gamma)
def checkPositionLength(self, positionArray): if len(positionArray) != len( self.getHostScannable().getInputNames()): raise DiffcalcException( "Expected position of length {} but got position of length {}" .format( len(self.getHostScannable().getInputNames().length), len(positionArray)))
def constrain(self, name): ext_name = settings.geometry.map_to_external_name(name) if self.is_constraint_fixed(name): raise DiffcalcException('%s constraint cannot be changed' % ext_name) if name in self.all: return "%s is already constrained." % ext_name.capitalize() elif name in det_constraints: return self._constrain_detector(name) elif name in ref_constraints: return self._constrain_reference(name) elif name in samp_constraints: return self._constrain_sample(name) else: raise DiffcalcException( "%s is not a valid constraint name. Type 'con' for a table of constraint name" % ext_name)