* extract phot from exposure*

    **Key Arguments:**
        - ``expIdIndex`` -- index of the exposure to extract the dophot photometry from. A tuple of expId and integer MJD
        - ``cachePath`` -- path to the cache of ATLAS data

    **Return:**
        - ``dophotRows`` -- the list of matched dophot rows

def _extract_phot_from_exposure(
        expIdIndex,
        log,
        cachePath,
        settings):
    """* extract phot from exposure*

    **Key Arguments:**
        - ``expIdIndex`` -- index of the exposure to extract the dophot photometry from. A tuple of expId and integer MJD
        - ``cachePath`` -- path to the cache of ATLAS data

    **Return:**
        - ``dophotRows`` -- the list of matched dophot rows
    """
    log.info('starting the ``_extract_phot_from_exposure`` method')

    global exposureIds

    expId = exposureIds[expIdIndex]

    # SETUP A DATABASE CONNECTION FOR THE remote database
    host = settings["database settings"]["atlasMovers"]["host"]
    user = settings["database settings"]["atlasMovers"]["user"]
    passwd = settings["database settings"]["atlasMovers"]["password"]
    dbName = settings["database settings"]["atlasMovers"]["db"]
    try:
        sshPort = settings["database settings"][
            "atlasMovers"]["tunnel"]["port"]
    except:
        sshPort = False
    thisConn = ms.connect(
        host=host,
        user=user,
        passwd=passwd,
        db=dbName,
        port=sshPort,
        use_unicode=True,
        charset='utf8',
        client_flag=ms.constants.CLIENT.MULTI_STATEMENTS,
        connect_timeout=3600
    )
    thisConn.autocommit(True)

    matchRadius = float(settings["dophot"]["search radius"])

    dophotFilePath = cachePath + "/" + \
        expId[0][:3] + "/" + str(expId[1]) + "/" + expId[0] + ".dph"

    # TEST THE FILE EXISTS
    exists = os.path.exists(dophotFilePath)
    expId = expId[0]
    if not exists:

        sqlQuery = """update atlas_exposures set dophot_match = 99 where expname = "%(expId)s" """ % locals(
        )
        writequery(
            log=log,
            sqlQuery=sqlQuery,
            dbConn=thisConn,
        )
        log.info(
            'the dophot file %(expId)s.dph is missing from the local ATLAS data cache' % locals())
        return []

    try:
        log.debug("attempting to open the file %s" %
                  (dophotFilePath,))
        dophotFile = codecs.open(
            dophotFilePath, encoding='utf-8', mode='r')
        dophotData = dophotFile.read()
        dophotFile.close()
    except IOError, e:
        message = 'could not open the file %s' % (dophotFilePath,)
        log.critical(message)
        raise IOError(message)

    ra = []
    dec = []
    dophotLines = dophotData.split("\n")[1:]

    # FREE MEMORY
    dophotData = None
    for r in dophotLines:
        r = r.split()
        if len(r):
            ra.append(float(r[0]))
            dec.append(float(r[1]))

    ra = np.array(ra)
    dec = np.array(dec)

    sqlQuery = u"""
        select * from orbfit_positions where expname = "%(expId)s"
    """ % locals()
    try:
        orbFitRows = readquery(
            log=log,
            sqlQuery=sqlQuery,
            dbConn=thisConn,
        )
    except:
        thisConn = ms.connect(
            host=host,
            user=user,
            passwd=passwd,
            db=dbName,
            port=sshPort,
            use_unicode=True,
            charset='utf8',
            client_flag=ms.constants.CLIENT.MULTI_STATEMENTS,
            connect_timeout=3600
        )
        thisConn.autocommit(True)
        orbFitRows = readquery(
            log=log,
            sqlQuery=sqlQuery,
            dbConn=thisConn,
        )

    potSources = len(orbFitRows)

    raOrb = []
    raOrb[:] = [r["ra_deg"] for r in orbFitRows]
    decOrb = []
    decOrb[:] = [r["dec_deg"] for r in orbFitRows]

    raOrb = np.array(raOrb)
    decOrb = np.array(decOrb)

    mesh = HTM(
        depth=12,
        log=log
    )
    matchIndices1, matchIndices2, seps = mesh.match(
        ra1=ra,
        dec1=dec,
        ra2=raOrb,
        dec2=decOrb,
        radius=matchRadius / 3600.,
        convertToArray=False,
        maxmatch=0  # 1 = match closest 1, 0 = match all
    )

    # FREE MEMORY
    raOrb = None
    decOrb = None

    dophotRows = []
    for m1, m2, s in zip(matchIndices1, matchIndices2, seps):
        # print ra[m1], dec[m1], " -> ", s * 3600., " arcsec -> ",
        # raOrb[m2], decOrb[m2]
        dList = dophotLines[m1].split()
        dDict = {
            "ra_deg": dList[0],
            "dec_deg": dList[1],
            "m": dList[2],
            "idx": dList[3],
            "type": dList[4],
            "xtsk": dList[5],
            "ytsk": dList[6],
            "fitmag": dList[7],
            "dfitmag": dList[8],
            "sky": dList[9],
            "major": dList[10],
            "minor": dList[11],
            "phi": dList[12],
            "probgal": dList[13],
            "apmag": dList[14],
            "dapmag": dList[15],
            "apsky": dList[16],
            "ap_fit": dList[17],
            "orbfit_separation_arcsec": s * 3600.,
            "orbfit_postions_id": orbFitRows[m2]["primaryId"],
            "expname": expId
        }
        dophotRows.append(dDict)

    # FREE MEMORY
    dophotLines = None
    orbFitRows = None

    log.info('completed the ``_extract_phot_from_exposure`` method')
    return dophotRows