예제 #1
0
def test_getspacegroup():
    # Good cases
    assert spacegroups.get_spacegroup(1) == \
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    assert spacegroups.get_spacegroup('Pbca') == \
        [3, 2, 2, 1, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0]
    # Error cases
    assert raises(NicosError, spacegroups.get_spacegroup, 'Pbbb')
    assert raises(NicosError, spacegroups.get_spacegroup, 300)
예제 #2
0
def test_canreflect():
    # P1 all reflection types are allowed
    sg = spacegroups.get_spacegroup('P1')
    assert spacegroups.can_reflect(sg, 0, 0, 0)
    assert spacegroups.can_reflect(sg, 1, 0, 0)
    assert spacegroups.can_reflect(sg, 0, 1, 0)
    assert spacegroups.can_reflect(sg, 0, 0, 1)
    assert spacegroups.can_reflect(sg, 1, 1, 1)
예제 #3
0
 def generate_hkls(self, offset=None, origin=False, sgroup=True):
     if offset is None:
         offset = array([0, 0, 0])
     else:
         offset = array(offset)
     o1 = array(self.cell._orient1)
     o2 = array(self.cell._orient2)
     hkls = []
     sg = None
     if sgroup:
         sg = get_spacegroup(self.tasinfo['spacegroup'])
     for i in range(-10, 11):
         for j in range(-10, 11):
             base = i * o1 + j * o2
             if i == j == 0:
                 if not origin:
                     continue
             elif sg and not can_reflect(sg, *base):
                 continue
             hkls.append(base + offset)
     return self.check_hkls(hkls)
예제 #4
0
def powderfit(powder,
              scans=None,
              peaks=None,
              ki=None,
              dmono=3.355,
              spacegroup=1):
    """Fit powder peaks of a powder sample to calibrate instrument wavelength.

    First argument is either a string that names a known material (currently
    only ``'YIG'`` is available) or a cubic lattice parameter.  Then you need
    to give either scan numbers (*scans*) or peak positions (*peaks*) and a
    neutron wavevector (*ki*).  Examples:

    >>> powderfit('YIG', scans=[1382, 1383, 1384, ...])

    >>> powderfit(12.377932, peaks=[45.396, 61.344, 66.096, ...], ki=1.4)

    As a further argument, *dmono* is the lattice constant of the monochromator
    (only used to calculate monochromator 2-theta offsets), it defaults to PG
    (3.355 A).
    """
    maxhkl = 10  # max H/K/L to consider when looking for d-values
    maxdd = 0.2  # max distance in d-value when looking for peak indices
    ksteps = 50  # steps with different ki
    dki = 0.002  # relative ki stepsize

    if powder == 'YIG':
        a = 12.377932
        spacegroup = 230
        session.log.info('YIG: using cubic lattice constant of %.6f A', a)
        session.log.info('')
    else:
        if not isinstance(powder, float):
            raise UsageError('first argument must be either "YIG" or a '
                             'lattice constant')
        a = powder

    sg = get_spacegroup(spacegroup)
    # calculate (possible) d-values
    # loop through some hkl-sets, also consider higher harmonics...
    dhkls = {}
    for h in range(maxhkl):
        for k in range(maxhkl):
            for l in range(maxhkl):
                if h + k + l > 0:  # assume all reflections are possible
                    if not can_reflect(sg, h, k, l):
                        continue
                    G = sqrt(h * h + k * k + l * l)
                    dhkls[a / G] = '(%d %d %d)' % (h, k, l)
                    dhkls[a / (2 * G)] = '(%d %d %d)/2' % (h, k, l)
                    dhkls[a / (3 * G)] = '(%d %d %d)/3' % (h, k, l)
                    dhkls[a / (4 * G)] = '(%d %d %d)/4' % (h, k, l)
                    dhkls[a / (5 * G)] = '(%d %d %d)/5' % (h, k, l)
    # generate list from dict
    dvals = sorted(dhkls)

    # fit and helper functions

    def dk2tt(d, k):
        return 2.0 * degrees(arcsin(pi / (d * k)))

    def model(x, k, stt0):
        return stt0 + dk2tt(x, k)

    data = {}
    if not peaks:
        if not scans:
            raise UsageError('please give either scans or peaks argument')

        for dataset in session.experiment.data.getLastScans():
            num = dataset.counter
            if num not in scans:
                continue
            res = _extract_powder_data(num, dataset)
            session.log.debug('powder_data from %d: %s', num, res)
            if res:
                ki, peaks = res
                data.setdefault(ki, []).extend(
                    [None, p, dp, '#%d ' % num] for (p, dp) in peaks)
        if not data:
            session.log.warning('no data found, check the scan numbers!')
            return
    else:
        if scans:
            raise UsageError('please give either scans or peaks argument')
        if not ki:
            raise UsageError('please give ki argument together with peaks')
        data[float(ki)] = [[None, p, 0.1, ''] for p in peaks]

    beststt0s = []
    bestmtt0s = []
    bestrms = 1.0
    bestlines = []
    orig_data = data
    for j in [0] + [i * s for i in range(1, ksteps) for s in (-1, 1)]:
        out = []
        p = out.append
        data = deepcopy(orig_data)

        # now iterate through data (for all ki and for all peaks) and try to
        # assign a d-value assuming the ki not to be completely off!
        for ki1 in sorted(data):
            new_ki = ki1 + j * dki * ki1
            # iterate over ki specific list, start at last element
            for el in reversed(data[ki1]):
                tdval = pi / new_ki / sin(abs(radians(
                    el[1] / 2.)))  # dvalue from scan
                distances = [(abs(d - tdval), i)
                             for (i, d) in enumerate(dvals)]
                mindist = min(distances)
                if mindist[0] > maxdd:
                    p('%speak at %7.3f -> no hkl found' % (el[3], el[1]))
                    data[ki1].remove(el)
                else:
                    el[0] = dvals[mindist[1]]
                    if el[1] < 0:
                        el[0] *= -1
                    p('%speak at %7.3f could be %s at d = %-7.4f' %
                      (el[3], el[1], dhkls[abs(el[0])], el[0]))
        p('')

        restxt = []
        restxt.append('___final_results___')
        restxt.append('ki_exp  #peaks | ki_fit   dki_fit  mtt_0    lambda   | '
                      'stt_0    dstt_0   | chisqr')
        stt0s = []
        mtt0s = []
        rms = 0
        for ki1 in sorted(data):
            new_ki = ki1 + j * dki * ki1
            peaks = data[ki1]
            failed = True
            if len(peaks) > 2:
                fit = Fit('ki', model, ['ki', 'stt0'], [new_ki, 0])
                res = fit.run([el[0] for el in peaks], [el[1] for el in peaks],
                              [el[2] for el in peaks])
                failed = res._failed
            if failed:
                restxt.append('%4.3f   %-6d | No fit!' % (ki1, len(peaks)))
                rms += 1e6
                continue
            mtt0 = dk2tt(dmono, res.ki) - dk2tt(dmono, ki1)
            restxt.append('%5.3f   %-6d | %-7.4f  %-7.4f  %-7.4f  %-7.4f  | '
                          '%-7.4f  %-7.4f  | %.2f' %
                          (ki1, len(peaks), res.ki, res.dki, mtt0,
                           2 * pi / res.ki, res.stt0, res.dstt0, res.chi2))
            stt0s.append(res.stt0)
            mtt0s.append(mtt0)
            peaks_fit = [model(el[0], res.ki, res.stt0) for el in peaks]
            p('___fitted_peaks_for_ki=%.3f___' % ki1)
            p('peak          dval measured   fitpos    delta')
            for i, el in enumerate(peaks):
                p('%-10s %7.3f  %7.3f  %7.3f  %7.3f%s' %
                  (dhkls[abs(el[0])], el[0], el[1], peaks_fit[i], peaks_fit[i]
                   - el[1], '' if abs(peaks_fit[i] - el[1]) < 0.10 else " **"))
            p('')
            rms += sum(
                (pobs - pfit)**2
                for (pobs,
                     pfit) in zip([el[1]
                                   for el in peaks], peaks_fit)) / len(peaks)

        out.extend(restxt)
        session.log.debug('')
        session.log.debug('-' * 80)
        session.log.debug('result from run with j=%d (RMS = %g):', j, rms)
        for line in out:
            session.log.debug(line)

        if rms < bestrms:
            beststt0s = stt0s
            bestmtt0s = mtt0s
            bestrms = rms
            bestlines = out
            session.log.debug('')
            session.log.debug('*** new best result: RMS = %g', rms)

    if not beststt0s:
        session.log.warning('No successful fit results!')
        if ki is not None:
            session.log.warning('Is the initial guess for ki too far off?')
        return

    for line in bestlines:
        session.log.info(line)

    meanstt0 = sum(beststt0s) / len(beststt0s)
    meanmtt0 = sum(bestmtt0s) / len(bestmtt0s)

    session.log.info('Check errors (dki, dstt0)!  RMS = %.3g', bestrms)
    session.log.info('')
    session.log.info('Adjust using:')
    # TODO: fix suggestions using adjust()
    session.log.info('mtt.offset += %.4f', meanmtt0)
    session.log.info('mth.offset += %.4f', meanmtt0 / 2)
    session.log.info('stt.offset += %.4f', meanstt0)

    return CommandLineFitResult((meanmtt0, meanstt0))
예제 #5
0
 def doWriteSpacegroup(self, val):
     try:
         get_spacegroup(val)
     except NicosError as err:
         self.log.warning('%s; new value will be ignored', err)
예제 #6
0
 def __init__(self, spgr):
     self.spgr = get_spacegroup(spgr)