Esempio n. 1
0
    def test_chained_quad(self):
        pvs = ['V:3-BSR-MG{QL3G2C29A_T1:3694}Fld:I', 
               'V:3-BSR-MG{QL3G2C29A_T2:7304}Fld:I', 
               'V:3-BSR-MG{QL3G2C29A_T3:10914}Fld:I']
        qs = ap.getElements('ql3g2c29a')
        self.assertEqual(len(qs), 1)
        k1 = ap.caget(pvs)
        self.assertLess(k1[1]/k1[0] - 1.0, 0.005)
        self.assertLess(k1[2]/k1[0] - 1.0, 0.005)

        qs[0].k1 = k1[0] * (1+0.01)
        k1b = ap.caget(pvs)
        self.assertGreater(qs[0].k1 / k1[0] - 1, 0.005)
        self.assertLess(k1b[1]/k1b[0] - 1.0, 0.005)
        self.assertLess(k1b[2]/k1b[0] - 1.0, 0.005)
Esempio n. 2
0
    def test_chained_quad(self):
        pvs = [
            "V:3-BSR-MG{QL3G2C29A_T1:3694}Fld:I",
            "V:3-BSR-MG{QL3G2C29A_T2:7304}Fld:I",
            "V:3-BSR-MG{QL3G2C29A_T3:10914}Fld:I",
        ]
        qs = ap.getElements("ql3g2c29a")
        self.assertEqual(len(qs), 1)
        k1 = ap.caget(pvs)
        self.assertLess(k1[1] / k1[0] - 1.0, 0.005)
        self.assertLess(k1[2] / k1[0] - 1.0, 0.005)

        qs[0].k1 = k1[0] * (1 + 0.01)
        k1b = ap.caget(pvs)
        self.assertGreater(qs[0].k1 / k1[0] - 1, 0.005)
        self.assertLess(k1b[1] / k1b[0] - 1.0, 0.005)
        self.assertLess(k1b[2] / k1b[0] - 1.0, 0.005)
Esempio n. 3
0
def run_single_bumps(pvmaps):
    for pvm in pvmaps:
        if ap.caget(pvm["cmd"]) == 0: continue
        ap.caput(pvm["cmddone"], 0)
        ename = pvm["idname"]
        if not ename: continue
        if ap.caget(pvm["op"]) == 0: continue
        xc, xangle = ap.caget([pvm["offset"], pvm["angle"]])
        plane = pvm["XY"].lower()
        print ename, xc, xangle, plane
        norm0, norm1, norm2, corvals = ap.setIdBump(
            ename, xc, xangle, plane=plane, check=False, ncor=6, dImax=0.5)
        print "Norm:", norm0, norm1, norm2
        print corvals
        ap.caput(pvm["cmddone"], 1)
        ap.caput(pvm["cmd"], 0)
        cothread.Yield(0.1)
Esempio n. 4
0
def run_single_bumps(pvmaps):
    for pvm in pvmaps:
        if ap.caget(pvm["cmd"]) == 0: continue
        ap.caput(pvm["cmddone"], 0)
        ename = pvm["idname"]
        if not ename: continue
        if ap.caget(pvm["op"]) == 0: continue
        xc, xangle = ap.caget([pvm["offset"], pvm["angle"]])
        plane = pvm["XY"].lower()
        print ename, xc, xangle, plane
        dImax = ap.caget("SR:APHLA:SOFB{BUMP:ALL}Single-dImax-I")
        norm0, norm1, norm2, corvals = ap.setIdBump(
            ename, xc, xangle, plane=plane, check=False, ncor=4, dImax=dImax,
            bbpms=[pvm["bpm1"], pvm["bpm2"]])
        #norm0, norm1, norm2, corvals = ap.setIdBump(
        #    ename, xc, xangle, plane=plane, check=False, ncor=6, dImax=0.5)
        print "Norm:", norm0, norm1, norm2
        print corvals
        ap.caput(pvm["cmddone"], 1)
        ap.caput(pvm["cmd"], 0)
        cothread.Yield(0.1)
Esempio n. 5
0
def saveState(idobj, output, iiter,
              parnames=None, background=None, extdata={}):
    """
    parnames - list of extra fields of idobj to be saved.
    background - the group name for its last background.
    extdata - extra data dictionary.

    returns data group name
    """
    t1 = datetime.now()
    prefix = "background" if background is None else "iter"

    # create background subgroup with index
    fid = h5py.File(output, 'a')
    iterindex = max([int(g[len(prefix)+1:]) for g in list(fid[idobj.name])
                     if g.startswith(prefix)] + [-1]) + 1
    groupName = "{0}_{1:04d}".format(prefix, iterindex)
    grp = fid[idobj.name].create_group(groupName)
    orb0 = ap.getOrbit(spos=True)
    grp["orbit"] = orb0
    tau, I = ap.getLifetimeCurrent()
    grp["lifetime"] = tau
    grp["current"] = I
    if parnames is None:
        parnames = ['gap', 'phase', 'mode']
    else:
        parnames = ['gap', 'phase', 'mode'] + list(parnames)
    parnames = np.unique(parnames).tolist()
    fields = idobj.fields()
    for par in parnames:
        if par in fields:
            grp[par] = idobj.get(par, unitsys=None)
            grp[par].attrs['unitsymb'] = idobj.getUnit(par, unitsys=None)
    for k,v in extdata.items():
        grp[k] = v
    grp.attrs["iter"] = iiter
    if background:
        grp.attrs["background"] = background
    else:
        # Save current ID trim setpoints
        elemflds = createCorrectorField(idobj)
        _, flds = zip(*elemflds)
        trim_sps = [idobj.get(ch, unitsys=None, handle='setpoint') for ch in flds]
        grp['trim_sp'] = trim_sps
        grp['trim_sp'].attrs['fields'] = flds

        # Save current BPM offsets
        try:
            bpm_offset_pvs         = saveState.bpm_offset_pvs
            bpm_offset_pv_suffixes = saveState.bpm_offset_pv_suffixes
            bpm_offset_fields      = saveState.bpm_offset_fields
            bpm_names              = saveState.bpm_names
        except AttributeError:
            bpms = ap.getElements('p[uhlm]*')
            bpm_names = [b.name for b in bpms]
            bpm_pv_prefixes = [b.pv(field='xbba')[0].replace('BbaXOff-SP', '')
                               for b in bpms]
            bpm_offset_fields = ['xbba', 'ybba', 'xref1', 'yref1', 'xref2', 'yref2']
            bpm_offset_pv_suffixes = [
                bpms[0].pv(field=f)[0].replace(bpm_pv_prefixes[0], '')
                for f in bpm_offset_fields]
            bpm_offset_pvs = []
            for suf in bpm_offset_pv_suffixes:
                bpm_offset_pvs += [prefix+suf for prefix in bpm_pv_prefixes]
            saveState.bpm_offset_pvs         = bpm_offset_pvs
            saveState.bpm_offset_pv_suffixes = bpm_offset_pv_suffixes
            saveState.bpm_offset_fields      = bpm_offset_fields
            saveState.bpm_names              = bpm_names
        bpm_offsets = np.array(
            [d.real if d.ok else np.nan
             for d in ap.caget(bpm_offset_pvs, throw=False)]).reshape(
                 (len(bpm_offset_pv_suffixes), -1)).T
        grp.create_dataset('bpm_offsets', data=bpm_offsets, compression='gzip')
        grp['bpm_offsets'].attrs['fields']      = bpm_offset_fields
        grp['bpm_offsets'].attrs['pv_suffixes'] = bpm_offset_pv_suffixes
        grp['bpm_offsets'].attrs['bpm_names']   = bpm_names

    grp.attrs["state_saved"] = t1.strftime("%Y-%m-%d %H:%M:%S.%f")
    fid.close()
    return groupName
Esempio n. 6
0
def createParList(ID, parScale):
    """
    create parameter list based on the paraneter range, spaced type
     parRange: 2d parameter range in the format of
     [[name, spacedType, start, end, step, tolerance],...]
     example:[['gap','log',150,15,21,0.1]]
     scan table will cover 15~150 with 21 steps, tolerance is 0.1,
     spacedType: log or linear

    return parameter list for communicating with hardware, table for data
    archive
    """
    # Make sure that "gap" specification (if exists) comes at the end.
    # This is important since, for example, adjusting the gap first and then
    # adjusting the phase would may well result in an unintentional gap change
    # due to the associated magnetic force change.
    fields = [fld for fld, _ in parScale]
    if 'gap' in fields:
        gap_index = fields.index('gap')
        gap_scale = parScale.pop(gap_index)
        parScale.append(gap_scale)
    nlist,vlist,tlist = [],[],[] #name, value and tolerance list
    for fld, scale in parScale:
        if not _params[ID.name].get(fld, None): continue
        nlist.append(fld)
        vmin, vmax, vstep, vtol = _params[ID.name][fld]

        # Make sure that the scan vector and background values stay within
        # the minimum and maximum gap/phase allowed.
        raw2phy = ID.convertUnit(fld, 1.0, None, 'phy', handle='setpoint')
        field_pvsp = ID.pv(field=fld, handle='setpoint')[0]
        try:
            LLim_pv = field_pvsp + '.DRVL'
            LLim_mm = ap.caget(LLim_pv)*raw2phy
            print('Lower Limit for {0} = {1:.3g} mm'.format(fld, LLim_mm))
            if vmin < LLim_mm:
                vmin = LLim_mm
                temp_list = list(_params[ID.name][fld])
                temp_list[0] = LLim_mm
                _params[ID.name][fld] = tuple(temp_list)
        except:
            raise
            print('# WARNING # Lower limit for {0} could not be retrieved.'.format(fld))
            LLim_mm = None
        #
        try:
            HLim_pv = field_pvsp + '.DRVH'
            HLim_mm = ap.caget(HLim_pv)*raw2phy
            print('Upper Limit for {0} = {1:.3g} mm'.format(fld, HLim_mm))
            if vmax < HLim_mm:
                vmax = HLim_mm
                temp_list = list(_params[ID.name][fld])
                temp_list[1] = HLim_mm
                _params[ID.name][fld] = tuple(temp_list)
        except:
            print('# WARNING # Upper limit for {0} could not be retrieved.'.format(fld))
            HLim_mm = None

        if scale == 'linear':
            vlist.append(list(np.linspace(vmin, vmax, int(vstep))))
        elif scale == 'log':
            if vmin<=0 or vmax<=0:
                raise RuntimeError('negative boundary can not be spaced Logarithmically')
            else:
                vlist.append(list(np.logspace(np.log10(vmin),np.log10(vmax),int(vstep))))
        elif not isinstance(scale, string_types):
            # "scale" is a user-specified array for the parameter
            vmin = np.min(scale)
            vmax = np.max(scale)
            if (LLim_mm is not None) and (vmin < LLim_mm):
                raise ValueError(
                    ('Specified array for {0} contains a value smaller than '
                     'the lower limit ({1:.3g} mm)').format(fld, LLim_mm))
            if (HLim_mm is not None) and (vmax > HLim_mm):
                raise ValueError(
                    ('Specified array for {0} contains a value larger than '
                     'the upper limit ({1:.3g} mm)').format(fld, HLim_mm))
            vlist.append(list(scale))
            if fld == 'gap':
                print('Resetting the background "gap" to be the max of user-specified gap array')
                _params[ID.name]['background'][fld] = vmax
            # Reset the "gap" or "phase" tuples in _params
            temp_tup = (vmin, vmax,
                        _params[ID.name][fld][2], _params[ID.name][fld][3])
            _params[ID.name][fld] = temp_tup
        else:
            raise RuntimeError('unknown spaced pattern: %s'%p[1])

        if (HLim_mm is not None) and (_params[ID.name]['background'][fld] > HLim_mm):
            _params[ID.name]['background'][fld] = HLim_mm
            print(('Background value of {0} cannot be larger than the '
                   'upper limit ({1:.3g} mm)').format(fld, HLim_mm))
        if (LLim_mm is not None) and (_params[ID.name]['background'][fld] < LLim_mm):
            raise ValueError(
                ('Background value of {0} cannot be smaller than the '
                 'lower limit ({1:.3g} mm)').format(fld, LLim_mm))

        tlist.append(vtol)

    valueList = itertools.product(*vlist)
    parList = []
    for v in valueList:
        tmp = []
        for i,n in enumerate(nlist):
            tmp.append([n,v[i],tlist[i]])
        parList.append(tmp)
    valueList = itertools.product(*vlist)
    table = [vi for vi in valueList]
    return parList, nlist, table
Esempio n. 7
0
        for k,v in _tmpl.items():
            pv = v.format(**mac)
            pvls.append((k, pv))
        pvdict = dict(pvls)
        #print k, pv, caget(pv)
        bpm = ap.getElements(pvdict["bpm1"])[0]
        if mac["HV"] == "H" and pvdict["hv1"] != bpm.pv(field="xref1")[0]:
            print bpm.name, mac["HV"], pvdict["hv1"], bpm.pv(field="xref1")[0]
        pvmaps.append(pvdict)

    #for b in ap.getElements("UBPM"):
    #    print b.name, b.pv(field="x")
    print "Start checking IDLocalBump command ..."
    while True:
        run_single_bumps(pvmaps)
        if ap.caget(_pvcmd) == 0:
            time.sleep(1)
            continue
        #obt = ap.getOrbit(spos=True)
        #print "BPMS:", len(ap.getElements("BPM")),
        #print np.average(obt[:,0]), np.std(obt[:,0])
        for pvm in pvmaps:
            ap.caput(pvm["cmddone"], 0)
        for pvm in pvmaps:
            ename = pvm["idname"]
            if not ename: continue
            if ap.caget(pvm["op"]) == 0: continue
            xc, xangle = ap.caget([pvm["offset"], pvm["angle"]])
            plane = pvm["XY"].lower()
            print ename, xc, xangle, plane
            dImax = ap.caget("SR:APHLA:SOFB{BUMP:ALL}dImax-I")
Esempio n. 8
0
def saveState(idobj, output, iiter, parnames=None, background=None, extdata={}):
    """
    parnames - list of extra fields of idobj to be saved.
    background - the group name for its last background.
    extdata - extra data dictionary.

    returns data group name
    """
    t1 = datetime.now()
    prefix = "background" if background is None else "iter"

    # create background subgroup with index
    fid = h5py.File(output)
    iterindex = max([int(g[len(prefix) + 1 :]) for g in fid[idobj.name].keys() if g.startswith(prefix)] + [-1]) + 1
    groupName = "{0}_{1:04d}".format(prefix, iterindex)
    grp = fid[idobj.name].create_group(groupName)
    orb0 = ap.getOrbit(spos=True)
    grp["orbit"] = orb0
    tau, I = ap.getLifetimeCurrent()
    grp["lifetime"] = tau
    grp["current"] = I
    if parnames is None:
        parnames = ["gap", "phase", "mode"]
    else:
        parnames = ["gap", "phase", "mode"] + list(parnames)
    parnames = np.unique(parnames).tolist()
    fields = idobj.fields()
    for par in parnames:
        if par in fields:
            grp[par] = idobj.get(par, unitsys=None)
            grp[par].attrs["unitsymb"] = idobj.getUnit(par, unitsys=None)
    for k, v in extdata.items():
        grp[k] = v
    grp.attrs["iter"] = iiter
    if background:
        grp.attrs["background"] = background
    else:
        # Save current ID trim setpoints
        elemflds = createCorrectorField(idobj)
        _, flds = zip(*elemflds)
        trim_sps = [idobj.get(ch, unitsys=None, handle="setpoint") for ch in flds]
        grp["trim_sp"] = trim_sps
        grp["trim_sp"].attrs["fields"] = flds

        # Save current BPM offsets
        try:
            bpm_offset_pvs = saveState.bpm_offset_pvs
            bpm_offset_pv_suffixes = saveState.bpm_offset_pv_suffixes
            bpm_offset_fields = saveState.bpm_offset_fields
            bpm_names = saveState.bpm_names
        except AttributeError:
            bpms = ap.getElements("p[uhlm]*")
            bpm_names = [b.name for b in bpms]
            bpm_pv_prefixes = [b.pv(field="xbba")[0].replace("BbaXOff-SP", "") for b in bpms]
            bpm_offset_fields = ["xbba", "ybba", "xref1", "yref1", "xref2", "yref2"]
            bpm_offset_pv_suffixes = [bpms[0].pv(field=f)[0].replace(bpm_pv_prefixes[0], "") for f in bpm_offset_fields]
            bpm_offset_pvs = []
            for suf in bpm_offset_pv_suffixes:
                bpm_offset_pvs += [prefix + suf for prefix in bpm_pv_prefixes]
            saveState.bpm_offset_pvs = bpm_offset_pvs
            saveState.bpm_offset_pv_suffixes = bpm_offset_pv_suffixes
            saveState.bpm_offset_fields = bpm_offset_fields
            saveState.bpm_names = bpm_names
        bpm_offsets = (
            np.array([d.real if d.ok else np.nan for d in ap.caget(bpm_offset_pvs, throw=False)])
            .reshape((len(bpm_offset_pv_suffixes), -1))
            .T
        )
        grp.create_dataset("bpm_offsets", data=bpm_offsets, compression="gzip")
        grp["bpm_offsets"].attrs["fields"] = bpm_offset_fields
        grp["bpm_offsets"].attrs["pv_suffixes"] = bpm_offset_pv_suffixes
        grp["bpm_offsets"].attrs["bpm_names"] = bpm_names

    grp.attrs["state_saved"] = t1.strftime("%Y-%m-%d %H:%M:%S.%f")
    fid.close()
    return groupName
Esempio n. 9
0
def createParList(ID, parScale):
    """
    create parameter list based on the paraneter range, spaced type
     parRange: 2d parameter range in the format of
     [[name, spacedType, start, end, step, tolerance],...]
     example:[['gap','log',150,15,21,0.1]]
     scan table will cover 15~150 with 21 steps, tolerance is 0.1,
     spacedType: log or linear

    return parameter list for communicating with hardware, table for data
    archive
    """
    # Make sure that "gap" specification (if exists) comes at the end.
    # This is important since, for example, adjusting the gap first and then
    # adjusting the phase would may well result in an unintentional gap change
    # due to the associated magnetic force change.
    fields = [fld for fld, _ in parScale]
    if "gap" in fields:
        gap_index = fields.index("gap")
        gap_scale = parScale.pop(gap_index)
        parScale.append(gap_scale)
    nlist, vlist, tlist = [], [], []  # name, value and tolerance list
    for fld, scale in parScale:
        if not _params[ID.name].get(fld, None):
            continue
        nlist.append(fld)
        vmin, vmax, vstep, vtol = _params[ID.name][fld]

        # Make sure that the scan vector and background values stay within
        # the minimum and maximum gap/phase allowed.
        raw2phy = ID.convertUnit(fld, 1.0, None, "phy", handle="setpoint")
        field_pvsp = ID.pv(field=fld, handle="setpoint")[0]
        try:
            LLim_pv = field_pvsp + ".DRVL"
            LLim_mm = ap.caget(LLim_pv) * raw2phy
            print "Lower Limit for {0} = {1:.3g} mm".format(fld, LLim_mm)
            if vmin < LLim_mm:
                vmin = LLim_mm
                temp_list = list(_params[ID.name][fld])
                temp_list[0] = LLim_mm
                _params[ID.name][fld] = tuple(temp_list)
        except:
            raise
            print "# WARNING # Lower limit for {0} could not be retrieved.".format(fld)
            LLim_mm = None
        #
        try:
            HLim_pv = field_pvsp + ".DRVH"
            HLim_mm = ap.caget(HLim_pv) * raw2phy
            print "Upper Limit for {0} = {1:.3g} mm".format(fld, HLim_mm)
            if vmax < HLim_mm:
                vmax = HLim_mm
                temp_list = list(_params[ID.name][fld])
                temp_list[1] = HLim_mm
                _params[ID.name][fld] = tuple(temp_list)
        except:
            print "# WARNING # Upper limit for {0} could not be retrieved.".format(fld)
            HLim_mm = None

        if scale == "linear":
            vlist.append(list(np.linspace(vmin, vmax, int(vstep))))
        elif scale == "log":
            if vmin <= 0 or vmax <= 0:
                raise RuntimeError("negative boundary can not be spaced Logarithmically")
            else:
                vlist.append(list(np.logspace(np.log10(vmin), np.log10(vmax), int(vstep))))
        elif not isinstance(scale, (str, unicode)):
            # "scale" is a user-specified array for the parameter
            vmin = np.min(scale)
            vmax = np.max(scale)
            if (LLim_mm is not None) and (vmin < LLim_mm):
                raise ValueError(
                    ("Specified array for {0} contains a value smaller than " "the lower limit ({1:.3g} mm)").format(
                        fld, LLim_mm
                    )
                )
            if (HLim_mm is not None) and (vmax > HLim_mm):
                raise ValueError(
                    ("Specified array for {0} contains a value larger than " "the upper limit ({1:.3g} mm)").format(
                        fld, HLim_mm
                    )
                )
            vlist.append(list(scale))
            if fld == "gap":
                print 'Resetting the background "gap" to be the max of user-specified gap array'
                _params[ID.name]["background"][fld] = vmax
            # Reset the "gap" or "phase" tuples in _params
            temp_tup = (vmin, vmax, _params[ID.name][fld][2], _params[ID.name][fld][3])
            _params[ID.name][fld] = temp_tup
        else:
            raise RuntimeError("unknown spaced pattern: %s" % p[1])

        if (HLim_mm is not None) and (_params[ID.name]["background"][fld] > HLim_mm):
            _params[ID.name]["background"][fld] = HLim_mm
            print ("Background value of {0} cannot be larger than the " "upper limit ({1:.3g} mm)").format(fld, HLim_mm)
        if (LLim_mm is not None) and (_params[ID.name]["background"][fld] < LLim_mm):
            raise ValueError(
                ("Background value of {0} cannot be smaller than the " "lower limit ({1:.3g} mm)").format(fld, LLim_mm)
            )

        tlist.append(vtol)

    valueList = itertools.product(*vlist)
    parList = []
    for v in valueList:
        tmp = []
        for i, n in enumerate(nlist):
            tmp.append([n, v[i], tlist[i]])
        parList.append(tmp)
    valueList = itertools.product(*vlist)
    table = [vi for vi in valueList]
    return parList, nlist, table
Esempio n. 10
0
def markForStablePv():
    global ref_v0, PV_REF_RB
    ref_v0 = np.array(ap.caget(PV_REF_RB), 'd')
Esempio n. 11
0
PV_SR_DCCT='V:2-SR-BI{DCCT}CUR-I'
PV_REF_RB = [
    "V:2-SR:C15-BI:G2{PL1:1845}SA:X",
    "V:2-SR:C15-BI:G2{PL1:1845}SA:Y",
    "V:2-SR:C15-BI:G2{PL2:1865}SA:X",
    "V:2-SR:C15-BI:G2{PL2:1865}SA:Y",
    "V:2-SR:C15-BI:G4{PM1:1890}SA:X",
    "V:2-SR:C15-BI:G4{PM1:1890}SA:Y",
    "V:2-SR:C15-BI:G4{PM1:1900}SA:X",
    "V:2-SR:C15-BI:G4{PM1:1900}SA:Y",
    "V:2-SR:C15-BI:G6{PH2:1924}SA:X",
    "V:2-SR:C15-BI:G6{PH2:1924}SA:Y",
    "V:2-SR:C15-BI:G6{PH1:1939}SA:X",
    "V:2-SR:C15-BI:G6{PH1:1939}SA:Y"
    ]
ref_v0 = np.array(ap.caget(PV_REF_RB), 'd')

# name of BPMs
BPM1='ph2g2c30a'
BPM2='pm1g4c30a'

# plotting ?
PLOTTING = True
V1LTD1_OFFLINE = False
try:
    catools.caget("LTB:BI{BPM:1}Pos:X-I")
except:
    V1LTD1_OFFLINE = True

logging.info("V1LTD1_OFFLINE={0}".format(V1LTD1_OFFLINE))
Esempio n. 12
0
        for k,v in _tmpl.items():
            pv = v.format(**mac)
            pvls.append((k, pv))
        pvdict = dict(pvls)
        #print k, pv, caget(pv)
        bpm = ap.getElements(pvdict["bpm1"])[0]
        if mac["HV"] == "H" and pvdict["hv1"] != bpm.pv(field="xref1")[0]:
            print bpm.name, mac["HV"], pvdict["hv1"], bpm.pv(field="xref1")[0]
        pvmaps.append(pvdict)

    #for b in ap.getElements("UBPM"):
    #    print b.name, b.pv(field="x")
    print "Start checking IDLocalBump command ..."
    while True:
        run_single_bumps(pvmaps)
        if ap.caget(_pvcmd) == 0:
            time.sleep(1)
            continue
        #obt = ap.getOrbit(spos=True)
        #print "BPMS:", len(ap.getElements("BPM")),
        #print np.average(obt[:,0]), np.std(obt[:,0])
        for pvm in pvmaps:
            ap.caput(pvm["cmddone"], 0)
        for pvm in pvmaps:
            ename = pvm["idname"]
            if not ename: continue
            if ap.caget(pvm["op"]) == 0: continue
            xc, xangle = ap.caget([pvm["offset"], pvm["angle"]])
            plane = pvm["XY"].lower()
            print ename, xc, xangle, plane
            norm0, norm1, norm2, corvals = ap.setIdBump(