def main(args=None):
    if isinstance(args, str):
        import shlex
        args = shlex.split(args)

    import argparse

    parser = argparse.ArgumentParser('calibrateMotorFrequencies',
                                     add_help=True)
    parser.add_argument(
        'moduleName',
        type=str,
        help='the name of the module (e.g. "SC03", "Spare1", or "PFI")')

    parser.add_argument(
        '--initOntimes',
        action='store_true',
        help='set the model ontimes to some sane initial value.')
    parser.add_argument(
        '--fpgaHost',
        type=str,
        default='localhost',
        help='connect to the given FPGA host instead of the simulator.')
    parser.add_argument('--modelVersion',
                        type=str,
                        default='init',
                        help='specify the version of the input model.')
    parser.add_argument('--saveModelFile',
                        type=pathlib.Path,
                        default=None,
                        help='save the updated model in the given file.')
    opts = parser.parse_args(args)
    print(opts)

    output = butler.RunTree()

    pfi = pfiModule.PFI(fpgaHost=opts.fpgaHost,
                        logDir=output.logDir,
                        doLoadModel=False)
    mapPath = butler.mapPathForModule(opts.moduleName, opts.modelVersion)
    print(mapPath)
    pfi.loadModel(mapPath)

    pfi = calibrateMotorFrequencies(pfi=pfi, updateModel=True)
    if opts.initOntimes:
        thetaOntimes = np.full(57, 0.065)
        phiOntimes = np.full(57, 0.045)

        pfi.calibModel.updateOntimes(thtFwd=thetaOntimes,
                                     thtRev=thetaOntimes,
                                     phiFwd=phiOntimes,
                                     phiRev=phiOntimes)

    if opts.saveModelFile is not None:
        if opts.saveModelFile.is_absolute():
            outputPath = opts.saveModelFile
        else:
            outputPath = output.outputDir / opts.saveModelFile
        pfi.calibModel.createCalibrationFile(outputPath)
        print(f"wrote updated map file to {outputPath}")
Пример #2
0
def makeTablefromXML(XML, filename):

    XMLfile = XML
    tablename = filename

    pfi = pfiControl.PFI(fpgaHost='localhost',
                         doConnect=False)  #'fpga' for real device.
    pfi.loadModel(XMLfile)

    model = pfi.calibModel
    pid = np.arange(1, 58, 1)

    # Formaing XY from complex number to string
    centers = []
    for num in pfi.calibModel.centers:
        cen = f'({num.real:.2f} {num.imag:.2f})'
        centers.append(cen)

    #centerX = pfi.calibModel.centers.real
    #centerY = pfi.calibModel.centers.imag

    t = Table([
        pid, centers, model.L1,
        np.rad2deg(model.tht0),
        np.rad2deg(model.tht1), model.motorOntimeFwd1, model.motorOntimeRev1,
        model.L2,
        np.rad2deg(model.phiIn + np.pi),
        np.rad2deg(model.phiOut + np.pi), model.motorOntimeFwd2,
        model.motorOntimeRev2
    ],
              names=('Fiber No.', 'Center', 'L1', 'ThetaCCWLimit',
                     'ThetaCWLimit', 'ThetaOntimeFwd', 'ThetaOntimeRev', 'L2',
                     'PhiCCWLimit', 'PhiCWLimit', 'PhiOntimeFwd',
                     'PhiOntimeRev'))

    t.write(tablename,
            format='ascii.ecsv',
            overwrite=True,
            formats={
                'Fiber No.': '%i',
                'Center': '%s',
                'L1': '%f',
                'ThetaCCWLimit': '%f',
                'ThetaCWLimit': '%f',
                'ThetaOntimeFwd': '%f',
                'ThetaOntimeRev': '%f',
                'L2': '%f',
                'PhiCCWLimit': '%f',
                'PhiCWLimit': '%f',
                'PhiOntimeFwd': '%f',
                'PhiOntimeRev': '%f'
            })
Пример #3
0
    def __init__(self):
        super().__init__()
        self.pfi = pfiControl.PFI(fpgaHost='localhost', doLoadModel=False)

        self.setWindowTitle('Cobra controller')
        self.statusBar().showMessage('Please load XML file')

        block1 = QHBoxLayout()
        self.xml = QLineEdit()
        self.xml.setMinimumWidth(240)
        block1.addWidget(self.xml)
        self.btn_xml = QPushButton('Load XML file')
        self.btn_xml.clicked.connect(self.click_load)
        block1.addWidget(self.btn_xml)
        block1.addWidget(QSplitter(Qt.Vertical), QSizePolicy.Expanding)
        btn = QPushButton('Move Up/Down')
        btn.clicked.connect(self.move_up_down)
        block1.addWidget(btn)

        block2 = QHBoxLayout()
        self.btn_go = QPushButton('Go')
        block2.addWidget(self.btn_go, QSizePolicy.Expanding)
        self.btn_go.clicked.connect(self.click_go)
        onlyInt = QIntValidator()
        block2.addWidget(QLabel('theta:'))
        self.theta = QLineEdit('0')
        self.theta.setValidator(onlyInt)
        block2.addWidget(self.theta)
        block2.addWidget(QLabel('phi:'))
        self.phi = QLineEdit('0')
        self.phi.setValidator(onlyInt)
        block2.addWidget(self.phi)

        block3 = QHBoxLayout()
        btn_odd = QPushButton('Odd')
        btn_odd.setCheckable(True)
        btn_odd.clicked[bool].connect(self.click_odd)
        block3.addWidget(btn_odd)
        block4 = QHBoxLayout()
        btn_even = QPushButton('Even')
        btn_even.setCheckable(True)
        btn_even.clicked[bool].connect(self.click_even)
        block4.addWidget(btn_even)
        self.btn_cobras = []
        for idx in range(57):
            btn_c = CobraButton(idx)
            self.btn_cobras.append(btn_c)
            if idx % 2 == 0:
                block3.addWidget(btn_c, QSizePolicy.Minimum)
            else:
                block4.addWidget(btn_c, QSizePolicy.Minimum)
        btn_c = QPushButton()
        btn_c.setMaximumWidth(20)
        block4.addWidget(btn_c)

        block5 = QHBoxLayout()
        block5.addWidget(QLabel('Right click to mark bad cobras'),
                         QSizePolicy.Expanding)
        self.cb_use_bad = QCheckBox('Use bad cobras')
        block5.addWidget(self.cb_use_bad)
        self.btn_speed = QPushButton('Fast')
        self.btn_speed.setCheckable(True)
        self.btn_speed.clicked[bool].connect(self.click_speed)
        block5.addWidget(self.btn_speed)

        layout = QVBoxLayout()
        layout.addLayout(block1)
        layout.addWidget(QSplitter())
        layout.addLayout(block2)
        layout.addLayout(block5)
        layout.addLayout(block3)
        layout.addLayout(block4)

        cw = QWidget()
        cw.setLayout(layout)
        self.setCentralWidget(cw)
Пример #4
0
def geometryStat(XMLarray, tablename, skipfiber=False):

    Xarray = []
    Yarray = []

    L1array = []
    L2array = []
    tht0array = []
    tht1array = []

    phiInarray = []
    phiOutarray = []

    for count, file in enumerate(XMLarray):
        print(file)
        pfi = pfiControl.PFI(fpgaHost='localhost',
                             doConnect=False)  #'fpga' for real device.
        pfi.loadModel(file)
        model = pfi.calibModel
        if count == 0:
            L1array = model.L1
            L2array = model.L2
            tht0array = np.rad2deg(model.tht0)
            tht1array = np.rad2deg(model.tht1)

            phiInarray = np.rad2deg(model.phiIn + np.pi)
            phiOutarray = np.rad2deg(model.phiOut + np.pi)

            Xarray = pfi.calibModel.centers.real
            Yarray = pfi.calibModel.centers.imag

        else:
            L1array = np.vstack((L1array, model.L1))
            L2array = np.vstack((L2array, model.L2))
            tht0array = np.vstack((tht0array, np.rad2deg(model.tht0)))
            tht1array = np.vstack((tht1array, np.rad2deg(model.tht1)))

            phiInarray = np.vstack(
                (phiInarray, np.rad2deg(model.phiIn + np.pi)))
            phiOutarray = np.vstack(
                (phiOutarray, np.rad2deg(model.phiOut + np.pi)))

            Xarray = np.vstack((Xarray, pfi.calibModel.centers.real))
            Yarray = np.vstack((Yarray, pfi.calibModel.centers.imag))

    L1mean = np.mean(L1array, axis=0)
    L1std = np.std(L1array, axis=0)

    L2mean = np.mean(L2array, axis=0)
    L2std = np.std(L2array, axis=0)

    tht0mean = np.mean(tht0array, axis=0)
    tht0std = np.std(tht0array, axis=0)

    tht1mean = np.mean(tht1array, axis=0)
    tht1std = np.std(tht1array, axis=0)

    phiInmean = np.mean(phiInarray, axis=0)
    PhiInstd = np.std(phiInarray, axis=0)

    phiOutmean = np.mean(phiOutarray, axis=0)
    PhiOutstd = np.std(phiOutarray, axis=0)

    Xmean = np.mean(Xarray, axis=0)
    Xstd = np.std(Xarray, axis=0)

    Ymean = np.mean(Yarray, axis=0)
    Ystd = np.std(Yarray, axis=0)

    print(tht0std)
    print(tht1std)

    pid = np.arange(1, 58, 1)

    t = Table([
        pid, Xmean, Xstd, Ymean, Ystd, L1mean, L1std, L2mean, L2std, tht0mean,
        tht0std, tht1mean, tht1std, phiInmean, PhiInstd, phiOutmean, PhiOutstd
    ],
              names=('Fiber No.', 'X', 'Xstd', 'Y', 'Ystd', 'L1mean', 'L1std',
                     'L2mean', 'L2std', 'ThetaCCWLimitMean',
                     'ThetaCCWLimitStd', 'ThetaCWLimitMean', 'ThetaCWLimitStd',
                     'PhiCCWLimitMean', 'PhiCCWLimitStd', 'PhiCWLimitMean',
                     'PhiCWLimitStd'))

    if skipfiber is not False:
        t.remove_rows(skipfiber)

    t.write(tablename,
            format='ascii.ecsv',
            overwrite=True,
            formats={
                'Fiber No.': '%i',
                'X': '%f',
                'Xstd': '%f',
                'Y': '%f',
                'Ystd': '%f',
                'L1mean': '%f',
                'L1std': '%f',
                'L2mean': '%f',
                'L2std': '%f',
                'ThetaCCWLimitMean': '%f',
                'ThetaCCWLimitStd': '%f',
                'ThetaCWLimitMean': '%f',
                'ThetaCWLimitStd': '%f',
                'PhiCCWLimitMean': '%f',
                'PhiCCWLimitStd': '%f',
                'PhiCWLimitMean': '%f',
                'PhiCWLimitStd': '%f'
            })
def bootstrapModule(moduleName, initialXml=None, outputName=None,
                    fpgaHost='fpga',
                    simulationPath=None,
                    setCenters=True,
                    clearGeometry=True,
                    brokenFibers=(),
                    doCalibrate=True,
                    numberCobrasFromRight=False,
                    setModuleId=True):

    run = butler.RunTree()

    if fpgaHost == 'fpga':
        fpgaHost = '128.149.77.24' # See INSTRM-464
    elif fpgaHost == 'None' or fpgaHost == '':
        fpgaHost = None

    if initialXml is None:
        initialXml = butler.mapPathForModule(moduleName, 'init')
    if outputName is None:
        outputName = f"{moduleName}_bootstrap.xml"

    cam = camera.cameraFactory(runManager=run, simulationPath=simulationPath,
                               doClear=True)
    cam.resetStack(doStack=False)
    _ = cam.expose() # Just to record in case calibrartion moves far.

    nCobras = 57
    if fpgaHost is None:
        pfi = None
        pfiModel = pfiDesign.PFIDesign(initialXml)
    else:
        pfi = pfiControl.PFI(fpgaHost=fpgaHost, logDir=run.logDir,
                             doLoadModel=False)
        pfi.loadModel(initialXml)
        pfiModel = pfi.calibModel
        pfi.reset()

        # Override undependable ontimes. We want fast defaults which will drive full range
        pfi.calibModel.updateOntimes(phiFwd=[0.07]*nCobras, phiRev=[0.07]*nCobras, fast=True)
        pfi.calibModel.updateOntimes(phiFwd=[0.05]*nCobras, phiRev=[0.05]*nCobras, fast=False)

        pfi.calibModel.updateOntimes(thetaFwd=[0.08]*nCobras, thetaRev=[0.08]*nCobras, fast=True)
        pfi.calibModel.updateOntimes(thetaFwd=[0.06]*nCobras, thetaRev=[0.06]*nCobras, fast=False)

        # if we need to calibrate motor frequencies , assume the worst
        # (as seen in the assembly station init files): the values
        # would leave the motors not safe to run. So calibrate phi now, so
        # that we can reliably move it to home.
        if doCalibrate:
            calibrateMotorFrequencies.calibrateMotorFrequencies(pfi,
                                                                enabled=(False, True))
            pfi.moveAllSteps(None, 0, -4000)
        else:
            pfi.setFreq()

    if setModuleId:
        moduleId = pfiModel.setModuleId(moduleName)

    cs, im, _ = cam.expose()
    imCenters = np.stack((cs['x'], cs['y']), 1)

    # Needs to come from pfiDesign.nVisibleCobras, etc.
    nspots = len(cs)
    if nspots != nCobras - len(brokenFibers):
        raise RuntimeError(f'expect {nCobras - len(brokenFibers)} spots, got {nspots}')
    visibleIdx = list(pfiModel.findAllCobras())
    for b in brokenFibers:
        pfiModel.setCobraStatus(b, moduleId, invisible=True)
        visibleIdx.remove(pfiModel.findCobraByModuleAndPositioner(moduleId, b))
    visibleIdx = np.array(visibleIdx, 'i4')

    oldCenters = pfiModel.centers[visibleIdx]
    modelCenters = np.stack((np.real(oldCenters), np.imag(oldCenters)), 1)

    # The _only_ point of this step is to match up the fiber
    # numbers with the spots.
    # Forcing the images to have the boards run horizontally is a robust way
    # to do this.
    imIdx, _ = coordinates.laydown(imCenters)
    modelIdx, _ = coordinates.laydown(modelCenters)

    # These are now sorted descending by x, alternating between top
    # and bottom cobras. But the cobras centers in the xml files can
    # have real trash coordinates. For all the existing science
    # modules at CIT, several cobras have the same coordinates.  So do
    # _not_ use the model coordinates by default. Simply assign the
    # cobras by increasing/decreasing X.
    #
    # We want the cobras to be numbered from the left by default.
    #
    if numberCobrasFromRight:
        imIdx = imIdx[::-1]         # The ASRD camera has cobra 1 in the top-right.
    homes = imCenters[imIdx,0] + imCenters[imIdx,1]*(1j)

    # Usually only use scale from this. Only use the reset if we neither assign new centers nor
    # clear the geometry.
    offset1, scale1, tilt1, convert1 = coordinates.makeTransform(oldCenters[modelIdx], homes)

    if setCenters:
        centers = pfiModel.centers[:] * 0
        centers[visibleIdx] = homes
    else:
        centers = convert1(pfiModel.centers)

    if clearGeometry:
        tht0 = pfiModel.tht0[:] * 0.0
        tht1 = pfiModel.tht1[:] * 0.0 + 20.0 * np.pi/180

        phiIn = pfiModel.phiIn[:] * 0.0
        phiOut = pfiModel.phiOut[:] * 0.0 + 180.0 * np.pi/180

    else:
        tht0 = (pfiModel.tht0+tilt1)%(2*np.pi)
        tht1 = (pfiModel.tht1+tilt1)%(2*np.pi)
        phiIn = pfiModel.phiIn
        phiOut = pfiModel.phiOut
    L1 = pfiModel.L1*scale1
    L2 = pfiModel.L2*scale1

    pfiModel.updateGeometry(centers, L1, L2)
    pfiModel.updateThetaHardStops(tht0, tht1)
    pfiModel.updatePhiHardStops(phiIn, phiOut)

    if doCalibrate:
        # Now can calibrate theta motors.
        calibrateMotorFrequencies.calibrateMotorFrequencies(pfi,
                                                            enabled=(True, False))
    xmlDir = run.outputDir
    outPath = xmlDir / outputName
    pfiModel.createCalibrationFile(outPath, name='bootstrap')
    pfiModel.createCalibrationFile(butler.mapPathForModule(moduleName, version='bootstrap'),
                                   name='bootstrap')
    return outPath