#! /usr/bin/env python
# -*- coding: iso-8859-15 -*-
"""
Created on Mon May 25 13:51:41 2015

@author: kervella
"""

# ATTENTION: it is necessary to install pdfrw library (sudo port install py27-pdfrw)

import matplotlib as mpl
mpl.use('Agg') # necessary to be able to generate the reports even without X server
import matplotlib.pyplot as plt

#import sys
#import bootstrap as boot
import datetime
import numpy as np
from . import binary
#import pdb
from . import gravi_astrometry_fit
from . import gravi_astrometry_class
from . import gravi_astrometry_lib as gl
#import warnings
#import math
#from scipy.interpolate import interp1d

#try:
#    from scipy.signal import welch
#    welchpresent = True
#except ImportError, e:
#    welchpresent = False
#    pass # module doesn't exist, deal with it.


#==============================================================================
# Preparation of the report using reportlab
#==============================================================================
def produce_astrometry_report(dualseries,filename):
    from reportlab.platypus import SimpleDocTemplate, Spacer, Table, TableStyle, PageBreak
    from reportlab.lib import colors
    from reportlab.rl_config import defaultPageSize
    from reportlab.lib.units import inch, cm, mm
    import io

    PAGE_HEIGHT=defaultPageSize[1]
    PAGE_WIDTH=defaultPageSize[0]

    print ("Start produce_astrometry_report")
    
    if (dualseries is None):
        print ("Input data is NULL")
        return None

    Title = "GRAVITY ASTROMETRY Quality Control Report"
    pageinfo = "First dual mode file: "+filename+".fits"

    def myFirstPage(canvas, doc):
        canvas.saveState()
        canvas.setFont('Helvetica',16)
        canvas.drawCentredString(PAGE_WIDTH/2.0, PAGE_HEIGHT-60, Title)
        canvas.setFont('Helvetica',9)
        canvas.drawString(inch, 0.75 * inch,"Page 1 / %s" % pageinfo)
        canvas.restoreState()

    def myLaterPages(canvas, doc):
        canvas.saveState()
        canvas.setFont('Helvetica', 9)
        canvas.drawString(inch, 0.75 * inch,"Page %d / %s" % (doc.page, pageinfo))
        canvas.restoreState()

    reportname = filename+'-ASTROMETRY.pdf'
    doc = SimpleDocTemplate(reportname)

    nbase = 6 # number of bases


    #==============================================================================
    # First page
    #==============================================================================

    Story = [Spacer(1,1*mm)]
    Story.append(Spacer(1,2*mm))

    gl.plotSubtitle(Story,"Report on SWAP sequence from the ASTROREDUCED files.")
    gl.plotSubtitle(Story,"Header info from 1st file in series.")

    # FIXME: VLTI baseline correction (from Julien Woillez)
    if True:
        dualseries.ucoord *= 0.99888521339323
        dualseries.vcoord *= 0.99888521339323
        gl.plotSubtitle(Story,"0.998885 SCALING FACTOR ON UCOORD and VCOORD.")
    if False:
        gl.plotSubtitle(Story,"NO SCALING FACTOR ON UCOORD and VCOORD.")

    obj1name =  gl.get_key_withdefault(dualseries.headers[0],'HIERARCH ESO FT ROBJ NAME','')
    obj1alpha = gl.get_key_withdefault(dualseries.headers[0],'HIERARCH ESO FT ROBJ ALPHA','')
    obj1delta = gl.get_key_withdefault(dualseries.headers[0],'HIERARCH ESO FT ROBJ DELTA','')
    obj1mag = str(gl.get_key_withdefault(dualseries.headers[0],'HIERARCH ESO FT ROBJ MAG',''))

    obj2name =  gl.get_key_withdefault(dualseries.headers[0],'HIERARCH ESO INS SOBJ NAME','')
    obj2dalpha = gl.get_key_withdefault(dualseries.headers[0],'HIERARCH ESO INS SOBJ X',0)/1000. # in arcseconds
    obj2ddelta = gl.get_key_withdefault(dualseries.headers[0],'HIERARCH ESO INS SOBJ Y',0)/1000.
    obj2mag = str(gl.get_key_withdefault(dualseries.headers[0],'HIERARCH ESO INS SOBJ MAG',''))

    now = datetime.datetime.now()

    keywords = ["First file name:  ",
                "Last file name:  ",
#                "OB start date:",
                "First observing date:",
                "Last observing date:",
                "Processing date:",
                "Report date",
                "Data type:",
                "SC & Polar setup:",
                "SC NDIT per file x DIT:",
                "FT DIT:",
                "Number of files:",
                "1st object name",
                "1st object RA Dec Kmag",
                "2nd object name",
                "2nd object dRA, dDec, Kmag",
                "Swap status of 1st file",
                "Telescopes",
                "Pipeline version: "
                ]

    nfiles = dualseries.nfiles
    nfiles_swapped = 0
    for i in range(0,dualseries.nfiles):
        if dualseries.headers[i]['HIERARCH ESO INS SOBJ SWAP']=='YES': nfiles_swapped += 1

    keyvals  = [dualseries.filename[0]+'.fits',
                dualseries.filename[nfiles-1]+'.fits',
#                dualseries.headers[0]['HIERARCH ESO OBS START']+ " (UT time)",
                dualseries.headers[0]['DATE-OBS']+ " (UT time)",
                dualseries.headers[nfiles-1]['DATE-OBS']+ " (UT time)",
                dualseries.headers[0]['DATE']+ " (local time)",
                now.strftime("%Y-%m-%dT%H:%M:%S")+ " (local time)",
                'ASTROREDUCED',
                #tech,
                dualseries.headers[0]['HIERARCH ESO INS SPEC RES']+', '+
                dualseries.headers[0]['HIERARCH ESO FT POLA MODE']
                ,
                str(dualseries.headers[0]['HIERARCH ESO DET2 NDIT'])+' x '+str(dualseries.headers[0]['HIERARCH ESO DET2 SEQ1 DIT'])+' s',
                str(dualseries.headers[0]['HIERARCH ESO DET3 SEQ1 DIT'])+' s',
                str(dualseries.nfiles)+',   Swap NO='+str(nfiles-nfiles_swapped)+\
                    ',   Swap YES='+str(nfiles_swapped),
                obj1name,
                obj1alpha +'  '+ obj1delta +'  K='+ obj1mag ,
                obj2name,
                '%(val).3f'%{"val":obj2dalpha} +'"  '+ '%(val).3f'%{"val":obj2ddelta} +'"  K='+ obj2mag,
                dualseries.headers[0]['HIERARCH ESO INS SOBJ SWAP'],
                'T1='+gl.get_key_withdefault(dualseries.headers[0],'HIERARCH ESO ISS CONF STATION1','S1')+' '+
                'T2='+gl.get_key_withdefault(dualseries.headers[0],'HIERARCH ESO ISS CONF STATION2','S2')+' '+
                'T3='+gl.get_key_withdefault(dualseries.headers[0],'HIERARCH ESO ISS CONF STATION3','S3')+' '+
                'T4='+gl.get_key_withdefault(dualseries.headers[0],'HIERARCH ESO ISS CONF STATION4','S4'),
                #str(oifits.exptime_sc)+' s',
                dualseries.headers[0]['HIERARCH ESO PRO REC1 PIPE ID'],
                ]


    hsize = [5*cm, 10*cm]
    vsize = 5*mm
    textmatrix = list(zip(keywords,keyvals))
    t = Table(textmatrix,colWidths=hsize,rowHeights=vsize)
    t.setStyle(TableStyle([('INNERGRID', (0,0), (-1,-1), 0.25, colors.black),
                           ('BOX', (0,0), (-1,-1), 2, colors.black),]))
    Story.append(t)

    Story.append(PageBreak())


    # Get all files
    Story.append(Spacer(1,5*mm))
    gl.plotTitle(Story,"Files in this report with swap state")
    Story.append(Spacer(1,5*mm))

    keyvals = []
    keywords = dualseries.filename
    for i in range(len(keywords)):
        keyvals.append(dualseries.headers[i]['HIERARCH ESO INS SOBJ SWAP'])

    hsize = [11.5*cm,3*cm]
    vsize = 5*mm
    textmatrix = list(zip(keywords,keyvals))
    t = Table(textmatrix,colWidths=hsize,rowHeights=vsize)
    t.setStyle(TableStyle([('INNERGRID', (0,0), (-1,-1), 0.25, colors.black),
                           ('BOX', (0,0), (-1,-1), 2, colors.black),]))
    Story.append(t)

    #plotSubtitle(Story,"GD ad hoc scaling factor = ", dualseries.GDscale)

    Story.append(PageBreak())


    # Time scale in decimal hours
    timemjd = dualseries.mjd - np.nanmin(dualseries.mjd)
    timescale = timemjd*24.0
    timescale0 = timescale[np.where(dualseries.swapstate==0)][::nbase]
    timescale1 = timescale[np.where(dualseries.swapstate==1)][::nbase]

    #==============================================================================
    # User parameters
    #==============================================================================

    # horizontal axis limits
    xmaxval = np.max(timescale)
    xminval = np.min(timescale)

    # Limits for the GD residual plots (in microns)
    yminval = -10
    ymaxval = +10

    # Limits for the phase residual plots
    phaseminval = -1.25
    phasemaxval = 1.25
    
    # Limits for the TEL-FC met plots
    metminval = -1.0
    metmaxval = 1.0


    PlotTELfit = True # Plot TEL diode astrometry if True

    PlotWaterfall = True # Plot the waterfall charts of the phase vs time and wavelength

    #==============================================================================
    # Astrometric model fits
    #==============================================================================
    # First guess for Mu Vel
    # dualseries.relposx = -1911.
    # dualseries.relposy = -1242.

    #dualseries.relposx = 143.
    #dualseries.relposy = -2200.

    # WITH 3 PARAMETERS
    dopdFits = gravi_astrometry_fit.dopdFit(dualseries,nZP=3)
    # WITH 6 PARAMETERS
    # dopdFits = gravi_astrometry_fit.dopdFit(dualseries,nZP=6)

    fitG_GDonly = dopdFits['GD'] # GD only, FC only at first step
    mod_GDonly = fitG_GDonly['model']
    fitG_GDPD2 = dopdFits['phase2'] # GD+PD
#    mod_GDPD2 = fitG_GDPD2['model']

    fitG_GDonly_telmet = dopdFits['GD_telmet'] # GD only, FC+TEL
#    mod_GDonly_telmet = fitG_GDonly_telmet['model']
    fitG_GDPD2_telmet = dopdFits['phase2_telmet'] # GD+PD
#    mod_GDPD2_telmet = fitG_GDPD2_telmet['model']

    rmsphasor_res = np.std(np.angle(dualseries.phasor_res))
    rmsphasor_res2 = np.std(np.angle(dualseries.phasor_res2))
    rmsphasor_res2_telmet = np.std(np.angle(dualseries.phasor_res2_telmet))

    #==============================================================================
    # Astrometric model parameters using FC metrology only
    #==============================================================================

    hsize = [5*cm,5*cm,5*cm]
    vsize = 5*mm

    def tableParams(fitpar):
        varnames = list(fitpar['best'].keys()); varnames.sort();
        varvals =[]; varerrs=[];
        for varname in varnames:
            varvals.append(fitpar['best'].get(varname))
            varerrs.append(fitpar['uncer'].get(varname))
        varnames.append('Reduced Chi2')
        varvals.append(fitpar['chi2'])
        varerrs.append('-')
        textmatrix = list(zip(varnames,varvals,varerrs))
        t = Table(textmatrix,colWidths=hsize,rowHeights=vsize)
        t.setStyle(TableStyle([('INNERGRID', (0,0), (-1,-1), 0.25, colors.black),
                               ('BOX', (0,0), (-1,-1), 2, colors.black),]))
        return t

    def polarValues(fitX,errX,fitY,errY):
        fitR = np.sqrt(np.square(fitX)+np.square(fitY))
        fitTheta = np.arctan2(fitX,fitY)
#        errR = np.sqrt(np.square(errX*np.cos(fitTheta))+np.square(errY*np.sin(fitTheta)))
#        errTheta = np.arctan2(np.square(errX*np.sin(fitTheta))+np.square(errY*np.cos(fitTheta)),fitR)
        errR = np.abs((errX*fitX+errY*fitY)/fitR)
        errTheta = np.sqrt( ((fitY*errX)**2 + (fitX*errY)**2)/fitR**4 )
        fitTheta *= 180./np.pi
        errTheta *= 180./np.pi
        return [fitR,errR,fitTheta,errTheta]

    if ("WDS_J10468-4925" in obj1name):
        Story.append(Spacer(1,5*mm))
        gl.plotTitle(Story,"1) NACO measured separation of Mu Vel (epoch 2016):")
        Separ = 2279.36 # mas from NACO
        errSepar = 0.3 # mas
        Thetapos = 56.9177 # deg
        errThetapos = 0.2 # deg
        gl.plotTitle(Story,"R = %(Rval).3f +/- %(Rerr).3f mas, theta = %(Tval).5f +/- %(Terr).5f deg"\
                    %{"Rval":Separ, "Rerr":errSepar, "Tval":Thetapos, "Terr":errThetapos})
    elif ("GJ65" in obj1name):
        Story.append(Spacer(1,5*mm))
        t = np.mean(dualseries.mjd)
        gl.plotTitle(Story,"1) Expected relative position of GJ65AB:")
        param = {'a': 2.05843, 'i': 52.177, 'OMEGA': 145.789, 'e':0.6185,
             'omega':283.266, 'T0': 41359.090, 'P':9600.23}
        xyz = np.array(binary.orbit(t, param, Vrad=False, verbose=True))
        Separ = np.sqrt(xyz[0]**2+xyz[1]**2)*1000 # milliarcsec
        errSepar = 0.0047*Separ # milliarcsec
        Thetapos = np.arctan2(xyz[0],xyz[1])*180./np.pi # deg
        errThetapos = 0.2 # deg
        gl.plotTitle(Story,"R = %(Rval).3f +/- %(Rerr).3f mas, theta = %(Tval).5f +/- %(Terr).5f deg"\
                    %{"Rval":Separ, "Rerr":errSepar, "Tval":Thetapos, "Terr":errThetapos})
        gl.plotSubtitle(Story,"MJD=%.2f, orbit from Kervella et al. (2016, A&A, 593, A127)"%(t))
    elif ("AlfCen" in obj1name) or ("AlphaCen" in obj1name) or ("alfCen" in obj1name) or ("alfCen" in obj1name):
        Story.append(Spacer(1,5*mm))
        t = np.mean(dualseries.mjd)
        gl.plotTitle(Story,"1) Expected relative position of Alpha Cen A wrt. B:")
        
        param = {'a': 17.592, 'i': -100.6803, 'OMEGA': 205.064, 'e':0.5208,
             'omega':232.006, 'T0': 35328.373, 'P':29194.151}
        xyz = np.array(binary.orbit(t, param, Vrad=False, verbose=True))
        Separ = np.sqrt(xyz[0]**2+xyz[1]**2)*1000 # milliarcsec
        errSepar = Separ*0.013/17.592 # milliarcsec, from relative error on semi-major axis
        Thetapos = np.arctan2(xyz[0],xyz[1])*180./np.pi + 180. # deg BEWARE: position of A relative to B !
        errThetapos = 0.2 # deg
        gl.plotTitle(Story,"R = %(Rval).3f +/- %(Rerr).3f mas, theta = %(Tval).5f +/- %(Terr).5f deg"\
                    %{"Rval":Separ, "Rerr":errSepar, "Tval":Thetapos, "Terr":errThetapos})
        gl.plotSubtitle(Story,"MJD=%.2f, orbit from Kervella et al. (2016, A&A, 594, A107)"%(t))
    else:
        Story.append(Spacer(1,5*mm))
        [Separ,errSepar,Thetapos,errThetapos] = polarValues(obj2dalpha*1000., 0.0, obj2ddelta*1000., 0.0)
        gl.plotTitle(Story,"1) Expected astrometry of "+obj1name+" (from header):")
        gl.plotTitle(Story,"R = %(Rval).3f +/- %(Rerr).3f mas, theta = %(Tval).5f +/- %(Terr).5f deg"\
                    %{"Rval":Separ, "Rerr":errSepar, "Tval":Thetapos, "Terr":errThetapos})
    #Story.append(Spacer(1,5*mm))
    
    gl.plotTitle(Story,"2) GD only solution")    
    Story.append(Spacer(1,2*mm))
    t = tableParams(fitG_GDonly)
    Story.append(t)

    fitX = fitG_GDonly['best'].get('X[mas]')
    errX = fitG_GDonly['uncer'].get('X[mas]')
    fitY = fitG_GDonly['best'].get('Y[mas]')
    errY = fitG_GDonly['uncer'].get('Y[mas]')
    [fitR,errR,fitTheta,errTheta] = polarValues(fitX,errX,fitY,errY)
    gl.plotTitle(Story,"R = %(Rval).3f +/- %(Rerr).3f mas, theta = %(Tval).5f +/- %(Terr).5f deg"\
                                        %{"Rval":fitR, "Rerr":errR, "Tval":fitTheta, "Terr":errTheta})

    Rsig = (fitR-Separ)/np.sqrt(np.square(errSepar) + np.square(errR))
    Tsig = (fitTheta-Thetapos)/np.sqrt(np.square(errThetapos) + np.square(errTheta))
    gl.plotSubtitle(Story,"rms phase = %(rms).3f rad, dR = %(Rval).3f mas = %(Rsig).1f sigmas, dtheta = %(Tval).5f deg = %(Tsig).1f sigmas"\
                                            %{"rms":rmsphasor_res, "Rval":fitR-Separ, "Rsig":Rsig, "Tval":fitTheta-Thetapos, "Tsig":Tsig})
    #Story.append(Spacer(1,5*mm))

    gl.plotTitle(Story,"3) Second fit of residual phasor of GD fit with FC MET ONLY")
    Story.append(Spacer(1,2*mm))
    t = tableParams(fitG_GDPD2)
    Story.append(t)

    fitX = fitG_GDonly['best'].get('X[mas]')+fitG_GDPD2['best'].get('X[mas]')
    errX = fitG_GDPD2['uncer'].get('X[mas]')
    fitY = fitG_GDonly['best'].get('Y[mas]')+fitG_GDPD2['best'].get('Y[mas]')
    errY = fitG_GDPD2['uncer'].get('Y[mas]')
    [fitR,errR,fitTheta,errTheta] = polarValues(fitX,errX,fitY,errY)
    gl.plotTitle(Story,"R = %(Rval).3f +/- %(Rerr).3f mas, theta = %(Tval).5f +/- %(Terr).5f deg"\
                                        %{"Rval":fitR, "Rerr":errR, "Tval":fitTheta, "Terr":errTheta})

    Rsig = (fitR-Separ)/np.sqrt(np.square(errSepar) + np.square(errR))
    Tsig = (fitTheta-Thetapos)/np.sqrt(np.square(errThetapos) + np.square(errTheta))
    gl.plotSubtitle(Story,"rms phase = %(rms).3f rad, dR = %(Rval).3f mas = %(Rsig).1f sigmas, dtheta = %(Tval).5f deg = %(Tsig).1f sigmas"\
                                            %{"rms":rmsphasor_res2, "Rval":fitR-Separ, "Rsig":Rsig, "Tval":fitTheta-Thetapos, "Tsig":Tsig})

    hsize = [5*cm,5*cm,5*cm]
    vsize = 5*mm
    
    gl.plotTitle(Story,"4) Second fit of residual phasor of GD fit with FC+TEL MET")
    Story.append(Spacer(1,2*mm))
    t = tableParams(fitG_GDPD2_telmet)
    Story.append(t)

    fitX = fitG_GDonly_telmet['best'].get('X[mas]')+fitG_GDPD2_telmet['best'].get('X[mas]')
    errX = fitG_GDPD2_telmet['uncer'].get('X[mas]')
    fitY = fitG_GDonly_telmet['best'].get('Y[mas]')+fitG_GDPD2_telmet['best'].get('Y[mas]')
    errY = fitG_GDPD2_telmet['uncer'].get('Y[mas]')
    [fitR,errR,fitTheta,errTheta] = polarValues(fitX,errX,fitY,errY)
    
    gl.plotTitle(Story,"R = %(Rval).3f +/- %(Rerr).3f mas, theta = %(Tval).5f +/- %(Terr).5f deg"\
                                        %{"Rval":fitR, "Rerr":errR, "Tval":fitTheta, "Terr":errTheta})

    Rsig = (fitR-Separ)/np.sqrt(np.square(errSepar) + np.square(errR))
    Tsig = (fitTheta-Thetapos)/np.sqrt(np.square(errThetapos) + np.square(errTheta))
    gl.plotSubtitle(Story,"rms phase = %(rms).3f rad, dR = %(Rval).3f mas = %(Rsig).1f sigmas, dtheta = %(Tval).5f deg = %(Tsig).1f sigmas"\
                                            %{"rms":rmsphasor_res2_telmet, "Rval":fitR-Separ, "Rsig":Rsig, "Tval":fitTheta-Thetapos, "Tsig":Tsig})

    Story.append(PageBreak())   


    #==============================================================================
    # Indices of the two swap states and baseline names
    #==============================================================================

    swap0 = np.where(dualseries.swapstate.flatten()==0)
    swap1 = np.where(dualseries.swapstate.flatten()==1)
    basenames = dualseries.base[0,:]

    #==============================================================================
    # Astrometric model fit residuals from Group Delay only
    #==============================================================================

    gl.plotTitle(Story,"(1/2) Group delay + FC MET only dOPD model fit residuals")
    gl.plotSubtitle(Story,"dOPD (microns) vs. time (decimal hours).",spacer=Spacer(1,2*mm))
    gl.plotSubtitle(Story,"Swap WITH disp. corr.: NO=Red, YES=Orange x (-1).")

    hsize=16*cm
    vsize=6.5*cm

    residuals = 1E6*(dualseries.dopd_gd.flatten()-mod_GDonly)
    residuals0 = residuals[swap0]
    residuals1 = (-1)*residuals[swap1]

    for baseline in range(0,3):
        ydata0 = residuals0[baseline::nbase]
        ydata1 = residuals1[baseline::nbase]
        rms = np.std(residuals[baseline::nbase])
        data = []
        data.append( tuple(zip(timescale0, gl.clipdata(ydata0,yminval,ymaxval))) )
        data.append( tuple(zip(timescale1, gl.clipdata(ydata1,yminval,ymaxval))) )
        a = gl.graphscatteraxes (data, xminval, xmaxval,yminval,ymaxval,hsize,vsize,\
            None,None,'Base '+basenames[baseline]+'  RMS = %.3f'%rms+' microns')
        Story.append(a)
        if baseline < nbase-1:
            Story.append(Spacer(1,7*mm))

    Story.append(PageBreak())

    gl.plotTitle(Story,"(2/2) Group delay + FC MET only dOPD model fit residuals")
    gl.plotSubtitle(Story,"dOPD (microns) vs. time (decimal hours).",spacer=Spacer(1,2*mm))
    gl.plotSubtitle(Story,"Swap WITH disp. corr.: NO=Red, YES=Orange x (-1).")
 
    for baseline in range(3,nbase):
        ydata0 = residuals0[baseline::nbase]
        ydata1 = residuals1[baseline::nbase]
        rms = np.std(residuals[baseline::nbase])
        data = []
        data.append( tuple(zip(timescale0, gl.clipdata(ydata0,yminval,ymaxval))) )
        data.append( tuple(zip(timescale1, gl.clipdata(ydata1,yminval,ymaxval))) )
        a = gl.graphscatteraxes (data, xminval, xmaxval,yminval,ymaxval,hsize,vsize,\
            None,None,'Base '+basenames[baseline]+'  RMS = %.3f'%rms+' microns')
        Story.append(a)
        if baseline < nbase-1:
            Story.append(Spacer(1,7*mm))

    Story.append(PageBreak())


    #==============================================================================
    # Phase residual after GD FC only model subtracion
    #==============================================================================

    gl.plotTitle(Story,"(1/2) Residual dOPD from phase after FC ONLY GD fit")
    gl.plotSubtitle(Story,"dOPD (mic) from WRAPPED phase vs. time (h), median over lbd.",spacer=Spacer(1,2*mm))
    gl.plotSubtitle(Story,"Swap with disp. corr.: NO=Red, YES=Orange x (-1).")

    hsize=16*cm
    vsize=6.5*cm
    residuals = 1E6*dualseries.dopd_phasor_res.flatten() * ((-1)**(dualseries.swapstate.flatten())) # in meters
    residuals0 = residuals[swap0]
    residuals1 = (-1)*residuals[swap1]

    # max step to avoid counting wraps in rms
    stepmax = (1E6*dualseries.lambda_mean)/2.0

    for baseline in range(0,3):
        ydata0 = residuals0[baseline::nbase]
        ydata1 = residuals1[baseline::nbase]
        rms0 = np.std(np.abs(ydata0)%stepmax)
        rms1 = np.std(np.abs(ydata1)%stepmax)
        data=[]
        data.append(tuple(zip(timescale0, gl.clipdata(ydata0,phaseminval,phasemaxval))) )
        data.append(tuple(zip(timescale1, gl.clipdata(ydata1,phaseminval,phasemaxval))) )
        a = gl.graphscatteraxes (data, xminval, xmaxval,phaseminval,phasemaxval,hsize,vsize,\
            None,None,'Base %s   RMS(swapNO)= %.3f microns   RMS(swapYES)= %.3f microns'\
            %(basenames[baseline],rms0,rms1))
        Story.append(a)
        if baseline < nbase-1:
            Story.append(Spacer(1,7*mm))

    Story.append(PageBreak())

    gl.plotTitle(Story,"(2/2) Residual dOPD from phase after FC ONLY GD fit")
    gl.plotSubtitle(Story,"dOPD (mic) from WRAPPED phase vs. time (h), median over lbd.",spacer=Spacer(1,2*mm))
    gl.plotSubtitle(Story,"Swap with disp. corr.: NO=Red, YES=Orange x (-1).")

    for baseline in range(3,nbase):
        ydata0 = residuals0[baseline::nbase]
        ydata1 = residuals1[baseline::nbase]
        rms0 = np.std(np.abs(ydata0)%stepmax)
        rms1 = np.std(np.abs(ydata1)%stepmax)
        data=[]
        data.append(tuple(zip(timescale0, gl.clipdata(ydata0,phaseminval,phasemaxval))) )
        data.append(tuple(zip(timescale1, gl.clipdata(ydata1,phaseminval,phasemaxval))) )
        a = gl.graphscatteraxes (data, xminval, xmaxval,phaseminval,phasemaxval,hsize,vsize,\
            None,None,'Base %s   RMS(swapNO)= %.3f microns   RMS(swapYES)= %.3f microns'\
            %(basenames[baseline],rms0,rms1))
        Story.append(a)
        if baseline < nbase-1:
            Story.append(Spacer(1,7*mm))

    Story.append(PageBreak())


    #==============================================================================
    # Phase residual after GD FC+TEL model subtraction 
    #==============================================================================

    if PlotTELfit:
        gl.plotTitle(Story,"(1/2) Residual dOPD from phase after FC+TEL GD fit")
        gl.plotSubtitle(Story,"dOPD (mic) from WRAPPED phase vs. time (h), median over lbd.",spacer=Spacer(1,2*mm))
        gl.plotSubtitle(Story,"Swap with disp. corr.: NO=Red, YES=Orange x (-1).")
    
        hsize=16*cm
        vsize=6.5*cm
        residuals = 1E6 * dualseries.dopd_phasor_res_telmet.flatten() * ((-1)**(dualseries.swapstate.flatten()))
        residuals0 = residuals[swap0]
        residuals1 = (-1)*residuals[swap1]
    
        for baseline in range(0,3):
            ydata0 = residuals0[baseline::nbase]
            ydata1 = residuals1[baseline::nbase]
            rms0 = np.std(np.abs(ydata0)%stepmax)
            rms1 = np.std(np.abs(ydata1)%stepmax)
            data=[]
            data.append(tuple(zip(timescale0, gl.clipdata(ydata0,phaseminval,phasemaxval))) )
            data.append(tuple(zip(timescale1, gl.clipdata(ydata1,phaseminval,phasemaxval))) )
            a = gl.graphscatteraxes (data, xminval, xmaxval,phaseminval,phasemaxval,hsize,vsize,\
                None,None,'Base %s   RMS(swapNO)= %.3f microns   RMS(swapYES)= %.3f microns'\
                %(basenames[baseline],rms0,rms1))
            Story.append(a)
            if baseline < nbase-1:
                Story.append(Spacer(1,7*mm))
    
        Story.append(PageBreak())
    
        gl.plotTitle(Story,"(2/2) Residual dOPD from phase after FC+TEL GD fit")
        gl.plotSubtitle(Story,"dOPD (mic) from WRAPPED phase vs. time (h), median over lbd.",spacer=Spacer(1,2*mm))
        gl.plotSubtitle(Story,"Swap with disp. corr.: NO=Red, YES=Orange x (-1).")
    
        for baseline in range(3,nbase):
            ydata0 = residuals0[baseline::nbase]
            ydata1 = residuals1[baseline::nbase]
            rms0 = np.std(np.abs(residuals0[baseline::nbase])%stepmax)
            rms1 = np.std(np.abs(residuals1[baseline::nbase])%stepmax)
            data=[]
            data.append(tuple(zip(timescale0, gl.clipdata(ydata0,phaseminval,phasemaxval))) )
            data.append(tuple(zip(timescale1, gl.clipdata(ydata1,phaseminval,phasemaxval))) )
            a = gl.graphscatteraxes (data, xminval, xmaxval,phaseminval,phasemaxval,hsize,vsize,\
                None,None,'Base %s   RMS(swapNO)= %.3f microns   RMS(swapYES)= %.3f microns'\
                %(basenames[baseline],rms0,rms1))
            Story.append(a)
            if baseline < nbase-1:
                Story.append(Spacer(1,7*mm))
    
        Story.append(PageBreak())

    #==============================================================================
    # Phase residual after second fit of phase
    #==============================================================================

    if PlotTELfit:
        gl.plotTitle(Story,"(1/2) Residual dOPD from phase (FC+TEL) after second phase fit")
        gl.plotSubtitle(Story,"dOPD (mic) from phase vs. time (h), median over lbd.",spacer=Spacer(1,2*mm))
        gl.plotSubtitle(Story,"Swap with disp. corr.: NO=Red, YES=Orange x (-1).")
    
        hsize=16*cm
        vsize=6.5*cm
        residuals = 1E6 * dualseries.dopd_phasor_res2_telmet.flatten() * ((-1)**(dualseries.swapstate.flatten()))
        residuals0 = residuals[swap0]
        residuals1 = (-1)*residuals[swap1]
    
        for baseline in range(0,3):
            ydata0 = residuals0[baseline::nbase]
            ydata1 = residuals1[baseline::nbase]
            rms0 = np.std(np.abs(ydata0)%stepmax)
            rms1 = np.std(np.abs(ydata1)%stepmax)
            data=[]
            data.append(tuple(zip(timescale0, gl.clipdata(ydata0,phaseminval,phasemaxval))) )
            data.append(tuple(zip(timescale1, gl.clipdata(ydata1,phaseminval,phasemaxval))) )
            a = gl.graphscatteraxes (data, xminval, xmaxval,phaseminval,phasemaxval,hsize,vsize,\
                None,None,'Base %s   RMS(swapNO)= %.3f microns   RMS(swapYES)= %.3f microns'\
                %(basenames[baseline],rms0,rms1))
            Story.append(a)
            if baseline < nbase-1:
                Story.append(Spacer(1,7*mm))
    
        Story.append(PageBreak())
    
        gl.plotTitle(Story,"(2/2) Residual dOPD from phase (FC+TEL) after second phase fit")
        gl.plotSubtitle(Story,"dOPD (mic) from phase vs. time (h), median over lbd.",spacer=Spacer(1,2*mm))
        gl.plotSubtitle(Story,"Swap with disp. corr.: NO=Red, YES=Orange x (-1).")
    
        for baseline in range(3,nbase):
            ydata0 = residuals0[baseline::nbase]
            ydata1 = residuals1[baseline::nbase]
            rms0 = np.std(np.abs(residuals0[baseline::nbase])%stepmax)
            rms1 = np.std(np.abs(residuals1[baseline::nbase])%stepmax)
            data=[]
            data.append(tuple(zip(timescale0, gl.clipdata(ydata0,phaseminval,phasemaxval))) )
            data.append(tuple(zip(timescale1, gl.clipdata(ydata1,phaseminval,phasemaxval))) )
            a = gl.graphscatteraxes (data, xminval, xmaxval,phaseminval,phasemaxval,hsize,vsize,\
                None,None,'Base %s   RMS(swapNO)= %.3f microns   RMS(swapYES)= %.3f microns'\
                %(basenames[baseline],rms0,rms1))
            Story.append(a)
            if baseline < nbase-1:
                Story.append(Spacer(1,7*mm))
    
        Story.append(PageBreak())

 
    #==============================================================================
    # Difference between TEL and FC metrology
    #==============================================================================

    gl.plotTitle(Story,"Difference between TEL and FC metrology signals")
    gl.plotSubtitle(Story,"dOPD (microns) vs. time (decimal hours).",spacer=Spacer(1,2*mm))
    gl.plotSubtitle(Story,"Swap: NO=Red, YES=Orange.")

    hsize=16*cm
    vsize=3*cm
    residuals = 1E6*(dualseries.met_delta.flatten())
    residuals0 = (residuals[swap0])
    residuals1 = (-1)*(residuals[swap1])

    for baseline in range(0,nbase):
        ydata0 = residuals0[baseline::nbase]
        ydata1 = residuals1[baseline::nbase]
        #yminval = np.min(residuals[baseline::nbase])
        #ymaxval = np.max(residuals[baseline::nbase])
        rms = np.std(residuals[baseline::nbase])
        data = []
        data.append( tuple(zip(timescale0, gl.clipdata(ydata0,metminval,metmaxval))) )
        data.append( tuple(zip(timescale1, gl.clipdata(ydata1,metminval,metmaxval))) )
        a = gl.graphscatteraxes (data, xminval, xmaxval,metminval,metmaxval,hsize,vsize,\
            None,None,'Base '+basenames[baseline]+'  RMS = %.3f'%rms+' microns')
        Story.append(a)
        if baseline < nbase-1:
            Story.append(Spacer(1,7*mm))

    Story.append(PageBreak())

 
    #==============================================================================
    # Waterfall display of second fit phasor residuals GD+TEL+FC
    #==============================================================================
    if PlotWaterfall:  


        gl.plotTitle(Story,"Waterfall of residual phasor of GD+FC only fit")
        gl.plotSubtitle(Story,"RMS = %.3f rad, wavelength in horizontal axis, time in vertical axis."%(rmsphasor_res))
    
        valmin = -np.pi
        valmax = np.pi
        imgdata = io.StringIO()
        plt.close('all')
        plt.rc('xtick', labelsize='x-small')
        plt.rc('ytick', labelsize='x-small')
        fig, axarr = plt.subplots(nrows=nbase, ncols=1, sharex=True, sharey=True, figsize=(5,8))
        for baseline in range(0,nbase):
            im = axarr[baseline].imshow(np.angle(dualseries.phasor_res[:,baseline,:]),\
                    vmin=valmin,vmax=valmax,cmap='bwr', interpolation='nearest', aspect='auto')
            axarr[baseline].set_title('Baseline '+basenames[baseline], fontsize=7)
        fig.subplots_adjust(hspace=.2)
        # Color bar plot
        fig.subplots_adjust(right=0.8)
        cbar_ax = fig.add_axes([0.85, 0.15, 0.05, 0.7])
        fig.colorbar(im, cax=cbar_ax)
        widthfig = 20 * cm
        heightfig= 22 * cm
        plt.savefig(imgdata, format='PDF', dpi=72, bbox_inches='tight')
        pi1 = gl.PdfImage(imgdata, width=widthfig, height=heightfig, kind='bound')
        plt.close('all')
        Story.append(pi1)

        Story.append(PageBreak())

        gl.plotTitle(Story,"Waterfall of residual phasor of second fit with FC only")
        gl.plotSubtitle(Story,"RMS = %.3f rad, wavelength in horizontal axis, time in vertical axis."%(rmsphasor_res2))
    
        valmin = -np.pi
        valmax = np.pi
        imgdata = io.StringIO()
        plt.close('all')
        plt.rc('xtick', labelsize='x-small')
        plt.rc('ytick', labelsize='x-small')
        fig, axarr = plt.subplots(nrows=nbase, ncols=1, sharex=True, sharey=True, figsize=(5,8))
        for baseline in range(0,nbase):
            im = axarr[baseline].imshow(np.angle(dualseries.phasor_res2[:,baseline,:]),\
                    vmin=valmin,vmax=valmax,cmap='bwr', interpolation='nearest', aspect='auto')
            axarr[baseline].set_title('Baseline '+basenames[baseline], fontsize=7)
        fig.subplots_adjust(hspace=.2)
        # Color bar plot
        fig.subplots_adjust(right=0.8)
        cbar_ax = fig.add_axes([0.85, 0.15, 0.05, 0.7])
        fig.colorbar(im, cax=cbar_ax)
        widthfig = 20 * cm
        heightfig= 22 * cm
        plt.savefig(imgdata, format='PDF', dpi=72, bbox_inches='tight')
        pi1 = gl.PdfImage(imgdata, width=widthfig, height=heightfig, kind='bound')
        plt.close('all')
        Story.append(pi1)

        Story.append(PageBreak())


        gl.plotTitle(Story,"Waterfall of residual phasor of second fit with FC+TEL")
        gl.plotSubtitle(Story,"RMS = %.3f rad, wavelength in horizontal axis, time in vertical axis."%(rmsphasor_res2_telmet))
    
        valmin = -np.pi
        valmax = np.pi
        imgdata = io.StringIO()
        plt.close('all')
        plt.rc('xtick', labelsize='x-small')
        plt.rc('ytick', labelsize='x-small')
        fig, axarr = plt.subplots(nrows=nbase, ncols=1, sharex=True, sharey=True, figsize=(5,8))
        for baseline in range(0,nbase):
            im = axarr[baseline].imshow(np.angle(dualseries.phasor_res2_telmet[:,baseline,:]),\
                    vmin=valmin,vmax=valmax,cmap='bwr', interpolation='nearest', aspect='auto')
            axarr[baseline].set_title('Baseline '+basenames[baseline], fontsize=7)
        fig.subplots_adjust(hspace=.2)
        # Color bar plot
        fig.subplots_adjust(right=0.8)
        cbar_ax = fig.add_axes([0.85, 0.15, 0.05, 0.7])
        fig.colorbar(im, cax=cbar_ax)
        widthfig = 20 * cm
        heightfig= 22 * cm
        plt.savefig(imgdata, format='PDF', dpi=72, bbox_inches='tight')
        pi1 = gl.PdfImage(imgdata, width=widthfig, height=heightfig, kind='bound')
        plt.close('all')
        Story.append(pi1)

        Story.append(PageBreak())

    if True:
        #==============================================================================
        # GDELAY versus time
        #==============================================================================
        gl.plotTitle(Story,"GDELAY_SC and GDELAY_FT versus time")
        gl.plotSubtitle(Story,"Group delay (microns) vs. time (decimal hours), Red = SC, Orange = FT.")

        hsize=16*cm
        vsize=3*cm
    
        ydata0 = np.array(dualseries.gd_sc * 1E6)
        ydata1 = np.array(dualseries.gd_ft * 1E6)
        gdminval = np.nanmin([ydata0,ydata1])
        gdmaxval = np.nanmax([ydata0,ydata1])

        for baseline in range(0,nbase):
            data = []
            data.append( tuple(zip(timescale[:,baseline], gl.clipdata(ydata0[:,baseline],gdminval,gdmaxval))) )
            data.append( tuple(zip(timescale[:,baseline], gl.clipdata(ydata1[:,baseline],gdminval,gdmaxval))) )
            a = gl.graphscatteraxes (data, xminval, xmaxval,gdminval,gdmaxval,hsize,vsize,\
                None,None,'Base '+basenames[baseline])
            Story.append(a)
            if baseline < nbase-1:
                Story.append(Spacer(1,7*mm))
    
        Story.append(PageBreak())
    

        #==============================================================================
        # GDELAY difference versus time
        #==============================================================================
        gl.plotTitle(Story,"GDELAY_SC - GDELAY_FT versus time")
        gl.plotSubtitle(Story,"Group delay (microns) vs. time (decimal hours). Swap NO=Red, YES=Orange.")
    
        hsize=16*cm
        vsize=3*cm
        residuals = 1E6*(dualseries.gd_sc - dualseries.gd_ft)
        residuals0 = 1E6*(dualseries.gd_sc[np.where(dualseries.swapstate==0)]-dualseries.gd_ft[np.where(dualseries.swapstate==0)])
        residuals1 = 1E6*(dualseries.gd_sc[np.where(dualseries.swapstate==1)]-dualseries.gd_ft[np.where(dualseries.swapstate==1)])

        gddiffminval = np.nanmin(residuals)
        gddiffmaxval = np.nanmax(residuals)
    
        for baseline in range(0,nbase):
            ydata0 = residuals0[baseline::nbase]
            ydata1 = residuals1[baseline::nbase]
            rms = np.std(residuals[baseline::nbase])
            data=[]
            data.append(tuple(zip(timescale0, gl.clipdata(ydata0,gddiffminval,gddiffmaxval))) )
            data.append(tuple(zip(timescale1, gl.clipdata(ydata1,gddiffminval,gddiffmaxval))) )
            a = gl.graphscatteraxes (data, xminval, xmaxval,gddiffminval,gddiffmaxval,hsize,vsize,\
                None,None,'Base '+basenames[baseline]+'  RMS = %.3f'%rms+' microns')
            Story.append(a)
            Story.append(Spacer(1,7*mm))
    
        Story.append(PageBreak())
    
        #==============================================================================
        # GD_DISP - GD model versus time
        #==============================================================================
        gl.plotTitle(Story,"GD_DISP - GD model versus time")
        gl.plotSubtitle(Story,"dOPD (microns) vs. time (decimal hours)")
    
        hsize=16*cm
        vsize=3*cm
    
        ydata1 = (dualseries.gd_disp.flatten() - mod_GDonly) * 1e6
        gdresminval = np.nanmin(ydata1)
        gdresmaxval = np.nanmax(ydata1)
    
        for baseline in range(0,nbase):
            data = [tuple(zip(timescale[:,baseline], gl.clipdata(ydata1[baseline::nbase],gdresminval,gdresmaxval)))]
            a = gl.graphscatteraxes (data, xminval, xmaxval,gdresminval,gdresmaxval,hsize,vsize,None,None,'Base '+basenames[baseline])
            Story.append(a)
            Story.append(Spacer(1,7*mm))
    
        Story.append(PageBreak())


    #==============================================================================
    # Create the PDF
    #==============================================================================

    print("Creating ASTROMETRY PDF report:")
    doc.build(Story, onFirstPage=myFirstPage, onLaterPages=myLaterPages)
    print((" "+reportname))

#==============================================================================
# MAIN PROGRAM
#==============================================================================

if __name__ == '__main__':

#    fits_keys = {'HIERARCH ESO PRO CATG': ['P2VMREDUCED'],\
#                 'HIERARCH ESO FT POLA MODE': ['COMBINED','SPLIT']}
    fits_keys = {'HIERARCH ESO PRO CATG': ['ASTROREDUCED'],\
                 'HIERARCH ESO FT POLA MODE': ['COMBINED','SPLIT']}

# Four UTs

## no dispersion:
#    files = [
##'astroreduced/2016-08-14-nodisp/GRAVI.2016-08-14T23:23:16.657_astroreduced', bad
##'astroreduced/2016-08-14-nodisp/GRAVI.2016-08-14T23:30:01.679_astroreduced', bad
##'astroreduced/2016-08-14-nodisp/GRAVI.2016-08-14T23:34:43.695_astroreduced', bad
##'astroreduced/2016-08-14-nodisp/GRAVI.2016-08-15T00:33:25.894_astroreduced', bad
##'astroreduced/2016-08-14-nodisp/GRAVI.2016-08-15T00:39:49.915_astroreduced', bad
#'astroreduced/2016-08-14-nodisp/GRAVI.2016-08-15T01:01:22.988_astroreduced', # 1
#'astroreduced/2016-08-14-nodisp/GRAVI.2016-08-15T01:07:44.010_astroreduced', 
#'astroreduced/2016-08-14-nodisp/GRAVI.2016-08-15T01:16:38.040_astroreduced', # 1
##'astroreduced/2016-08-14-nodisp/GRAVI.2016-08-15T01:22:59.061_astroreduced',
##'astroreduced/2016-08-14-nodisp/GRAVI.2016-08-15T01:32:32.094_astroreduced',
##'astroreduced/2016-08-14-nodisp/GRAVI.2016-08-15T01:38:56.115_astroreduced',
##'astroreduced/2016-08-14-nodisp/GRAVI.2016-08-15T01:47:44.145_astroreduced',
##'astroreduced/2016-08-14-nodisp/GRAVI.2016-08-15T01:54:08.167_astroreduced',
##'astroreduced/2016-08-14-nodisp/GRAVI.2016-08-15T02:07:56.213_astroreduced',
##'astroreduced/2016-08-14-nodisp/GRAVI.2016-08-15T02:14:20.235_astroreduced',
##'astroreduced/2016-08-14-nodisp/GRAVI.2016-08-15T02:22:20.262_astroreduced',
##'astroreduced/2016-08-14-nodisp/GRAVI.2016-08-15T02:28:41.283_astroreduced',# 1
##'astroreduced/2016-08-14-nodisp/GRAVI.2016-08-15T02:52:26.364_astroreduced',
##'astroreduced/2016-08-14-nodisp/GRAVI.2016-08-15T02:59:08.386_astroreduced',
##'astroreduced/2016-08-14-nodisp/GRAVI.2016-08-15T03:09:41.422_astroreduced',
##'astroreduced/2016-08-14-nodisp/GRAVI.2016-08-15T03:16:02.444_astroreduced',
##'astroreduced/2016-08-14-nodisp/GRAVI.2016-08-15T03:24:20.472_astroreduced',
##'astroreduced/2016-08-14-nodisp/GRAVI.2016-08-15T03:30:44.493_astroreduced'
#    ]
    
## with dispersion:
#    files = [
##'astroreduced/GRAVI.2016-08-14T23:23:16.657_astroreduced', bad
##'astroreduced/GRAVI.2016-08-14T23:30:01.679_astroreduced', bad
##'astroreduced/GRAVI.2016-08-14T23:34:43.695_astroreduced', bad
##'astroreduced/GRAVI.2016-08-15T00:33:25.894_astroreduced', bad
##'astroreduced/GRAVI.2016-08-15T00:39:49.915_astroreduced', bad
#'astroreduced/GRAVI.2016-08-15T01:01:22.988_astroreduced', # 1
#'astroreduced/GRAVI.2016-08-15T01:07:44.010_astroreduced', # 1
#'astroreduced/GRAVI.2016-08-15T01:16:38.040_astroreduced', # 1
##'astroreduced/GRAVI.2016-08-15T01:22:59.061_astroreduced',
##'astroreduced/GRAVI.2016-08-15T01:32:32.094_astroreduced',
##'astroreduced/GRAVI.2016-08-15T01:38:56.115_astroreduced',
##'astroreduced/GRAVI.2016-08-15T01:47:44.145_astroreduced',
##'astroreduced/GRAVI.2016-08-15T01:54:08.167_astroreduced',
##'astroreduced/GRAVI.2016-08-15T02:07:56.213_astroreduced',
##'astroreduced/GRAVI.2016-08-15T02:14:20.235_astroreduced',
##'astroreduced/GRAVI.2016-08-15T02:22:20.262_astroreduced',
##'astroreduced/GRAVI.2016-08-15T02:28:41.283_astroreduced',
##'astroreduced/GRAVI.2016-08-15T02:52:26.364_astroreduced',
##'astroreduced/GRAVI.2016-08-15T02:59:08.386_astroreduced',
##'astroreduced/GRAVI.2016-08-15T03:09:41.422_astroreduced',
##'astroreduced/GRAVI.2016-08-15T03:16:02.444_astroreduced',
##'astroreduced/GRAVI.2016-08-15T03:24:20.472_astroreduced',
##'astroreduced/GRAVI.2016-08-15T03:30:44.493_astroreduced',
##'astroreduced/GRAVI.2016-08-15T03:30:44.493_astroreduced',
##'astroreduced/GRAVI.2016-08-15T03:37:56.518_astroreduced',
##'astroreduced/GRAVI.2016-08-15T03:44:32.540_astroreduced',
##'astroreduced/GRAVI.2016-08-15T03:51:38.564_astroreduced'
#    ]

#    # WDS_J20452-3120 B and C series
#    files = [
#        'astroreduced/GRAVITY.2016-07-12T04-56-13_astroreduced',
#        'astroreduced/GRAVITY.2016-07-12T05-02-28_astroreduced',
#        'astroreduced/GRAVITY.2016-07-12T05-09-55_astroreduced',
#        'astroreduced/GRAVITY.2016-07-12T05-16-07_astroreduced',
#        'astroreduced/GRAVITY.2016-07-12T06-22-37_astroreduced',
#        'astroreduced/GRAVITY.2016-07-12T06-29-40_astroreduced',
#        'astroreduced/GRAVITY.2016-07-12T06-36-52_astroreduced',
#        'astroreduced/GRAVITY.2016-07-12T06-43-04_astroreduced',
#        'astroreduced/GRAVITY.2016-07-12T07-44-22_astroreduced',
#        'astroreduced/GRAVITY.2016-07-12T07-50-31_astroreduced',
#        'astroreduced/GRAVITY.2016-07-12T07-57-22_astroreduced',
#        'astroreduced/GRAVITY.2016-07-12T08-03-31_astroreduced'
#        ]

#    files = [
#        'astroreduced/GRAVITY.2016-07-12T05-41-37_astroreduced',
#        'astroreduced/GRAVITY.2016-07-12T05-47-46_astroreduced',
#        'astroreduced/GRAVITY.2016-07-12T05-58-10_astroreduced',
#        'astroreduced/GRAVITY.2016-07-12T06-04-34_astroreduced',
#        'astroreduced/GRAVITY.2016-07-12T07-03-01_astroreduced',
#        'astroreduced/GRAVITY.2016-07-12T07-09-10_astroreduced',
#        'astroreduced/GRAVITY.2016-07-12T07-20-16_astroreduced',
#        'astroreduced/GRAVITY.2016-07-12T07-26-43_astroreduced',
#        'astroreduced/GRAVITY.2016-07-12T08-24-22_astroreduced',
#        'astroreduced/GRAVITY.2016-07-12T08-32-40_astroreduced',
#        'astroreduced/GRAVITY.2016-07-12T08-46-55_astroreduced',
#        'astroreduced/GRAVITY.2016-07-12T08-50-41_astroreduced',
#        'astroreduced/GRAVITY.2016-07-12T08-59-32_astroreduced',
#        'astroreduced/GRAVITY.2016-07-12T09-13-38_astroreduced',
#        'astroreduced/GRAVITY.2016-07-12T09-20-44_astroreduced'
#        ]


    if False:
        #    # Mu Vel series
        
        #    files = [
        #    #'astroreduced/GRAVITY.2016-03-23T05-31-27_astroreduced', # bad met
        #    #'astroreduced/GRAVITY.2016-03-23T05-51-09_astroreduced', # bad met
        #    #'astroreduced/GRAVITY.2016-03-23T06-00-45_astroreduced', # bad met
        #    'astroreduced/GRAVITY.2016-03-23T06-08-30_astroreduced',
        #    'astroreduced/GRAVITY.2016-03-23T06-19-48_astroreduced',
        #    'astroreduced/GRAVITY.2016-03-23T06-30-28_astroreduced',
        #    'astroreduced/GRAVITY.2016-03-23T06-42-06_astroreduced',
        #    'astroreduced/GRAVITY.2016-03-23T06-51-18_astroreduced']
        
        files = [
        #'astroreduced/GRAVI.2016-04-10T01:45:11.406_astroreduced',
        #'astroreduced/GRAVI.2016-04-10T02:02:14.463_astroreduced',
        'astroreduced/GRAVI.2016-04-10T02:22:02.530_astroreduced',
        'astroreduced/GRAVI.2016-04-10T02:29:53.557_astroreduced',
        #    'astroreduced/GRAVI.2016-04-10T02:33:20.568_astroreduced', # bad synchro
        'astroreduced/GRAVI.2016-04-10T02:36:32.579_astroreduced',
        'astroreduced/GRAVI.2016-04-10T02:42:41.600_astroreduced',
        'astroreduced/GRAVI.2016-04-10T02:50:29.626_astroreduced',
        'astroreduced/GRAVI.2016-04-10T02:54:26.639_astroreduced',
        'astroreduced/GRAVI.2016-04-10T02:59:02.655_astroreduced',
        'astroreduced/GRAVI.2016-04-10T03:06:08.679_astroreduced',
        'astroreduced/GRAVI.2016-04-10T03:14:44.708_astroreduced',
        'astroreduced/GRAVI.2016-04-10T03:18:44.722_astroreduced',
        'astroreduced/GRAVI.2016-04-10T03:21:53.732_astroreduced',
        'astroreduced/GRAVI.2016-04-10T03:28:02.753_astroreduced',
        'astroreduced/GRAVI.2016-04-10T03:46:41.815_astroreduced',
        'astroreduced/GRAVI.2016-04-10T03:49:56.826_astroreduced',
        #'astroreduced/GRAVI.2016-04-10T03:53:08.837_astroreduced',
        #'astroreduced/GRAVI.2016-04-10T04:00:29.862_astroreduced',
        #'astroreduced/GRAVI.2016-04-10T04:09:11.892_astroreduced',
        #'astroreduced/GRAVI.2016-04-10T04:13:44.907_astroreduced',
        #'astroreduced/GRAVI.2016-04-10T04:17:08.918_astroreduced',
        'astroreduced/GRAVI.2016-04-10T04:24:08.942_astroreduced',
        'astroreduced/GRAVI.2016-04-10T04:32:35.970_astroreduced',
        'astroreduced/GRAVI.2016-04-10T04:35:44.981_astroreduced',
        'astroreduced/GRAVI.2016-04-10T04:40:08.996_astroreduced',
        'astroreduced/GRAVI.2016-04-10T04:46:45.019_astroreduced',
        'astroreduced/GRAVI.2016-04-10T04:53:57.043_astroreduced',
        'astroreduced/GRAVI.2016-04-10T04:57:12.054_astroreduced',
        'astroreduced/GRAVI.2016-04-10T05:00:18.064_astroreduced',
        'astroreduced/GRAVI.2016-04-10T05:07:18.087_astroreduced',
        'astroreduced/GRAVI.2016-04-10T05:14:48.113_astroreduced',
        'astroreduced/GRAVI.2016-04-10T05:18:00.124_astroreduced',
        'astroreduced/GRAVI.2016-04-10T05:21:09.134_astroreduced',
        'astroreduced/GRAVI.2016-04-10T05:29:18.162_astroreduced',
        'astroreduced/GRAVI.2016-04-10T05:36:15.185_astroreduced',
        'astroreduced/GRAVI.2016-04-10T05:39:27.196_astroreduced',
        'astroreduced/GRAVI.2016-04-10T05:42:36.207_astroreduced'
        ]
        
#    files = [
#    'astroreduced/GRAVI.2016-06-03T00:37:14.206_astroreduced',
#    'astroreduced/GRAVI.2016-06-03T00:44:20.230_astroreduced'
#    ]
    
#    files = [
#    'astroreduced/GRAVI.2016-06-03T02:56:35.676_astroreduced',
#    'astroreduced/GRAVI.2016-06-03T03:03:20.699_astroreduced',
#    'astroreduced/GRAVI.2016-06-03T03:09:53.722_astroreduced',
#    'astroreduced/GRAVI.2016-06-03T03:17:35.748_astroreduced',
#    'astroreduced/GRAVI.2016-06-03T03:23:53.768_astroreduced',
#    'astroreduced/GRAVI.2016-06-03T03:30:17.790_astroreduced',
#    'astroreduced/GRAVI.2016-06-03T03:36:35.812_astroreduced',
#    'astroreduced/GRAVI.2016-06-03T03:43:05.834_astroreduced',
#    'astroreduced/GRAVI.2016-06-03T03:49:23.854_astroreduced',
#    'astroreduced/GRAVI.2016-06-03T03:56:56.881_astroreduced',
#    'astroreduced/GRAVI.2016-06-03T04:03:26.902_astroreduced',
#    'astroreduced/GRAVI.2016-06-03T04:09:26.923_astroreduced',
#    'astroreduced/GRAVI.2016-06-03T04:15:44.944_astroreduced',
#    'astroreduced/GRAVI.2016-06-03T04:24:14.973_astroreduced',
#    'astroreduced/GRAVI.2016-06-03T04:30:32.994_astroreduced',
#    'astroreduced/GRAVI.2016-06-03T04:36:54.015_astroreduced'
#    ] 
    
    
    # GJ65 2017-01-04
    if False:
        files = [
        '/Volumes/GRAVITY-1TB/2017-01-04/astroreduced/GRAVITY.2017-01-04T01-46-25_astroreduced',
        '/Volumes/GRAVITY-1TB/2017-01-04/astroreduced/GRAVITY.2017-01-04T01-53-51_astroreduced',
        '/Volumes/GRAVITY-1TB/2017-01-04/astroreduced/GRAVITY.2017-01-04T02-04-15_astroreduced',
        '/Volumes/GRAVITY-1TB/2017-01-04/astroreduced/GRAVITY.2017-01-04T02-11-11_astroreduced'
        ]

    # GJ65 2017-01-05
    if False:    
        files = [
        '/Volumes/GRAVITY-1TB/2017-01-05/astroreduced/GRAVITY.2017-01-05T01-09-28_astroreduced',
        '/Volumes/GRAVITY-1TB/2017-01-05/astroreduced/GRAVITY.2017-01-05T01-25-11_astroreduced',
        '/Volumes/GRAVITY-1TB/2017-01-05/astroreduced/GRAVITY.2017-01-05T01-32-13_astroreduced',
        '/Volumes/GRAVITY-1TB/2017-01-05/astroreduced/GRAVITY.2017-01-05T01-59-54_astroreduced',
        '/Volumes/GRAVITY-1TB/2017-01-05/astroreduced/GRAVITY.2017-01-05T02-25-46_astroreduced',
        '/Volumes/GRAVITY-1TB/2017-01-05/astroreduced/GRAVITY.2017-01-05T02-38-42_astroreduced',
        #'/Volumes/GRAVITY-1TB/2017-01-05/astroreduced/GRAVITY.2017-01-05T02-46-17_astroreduced'
        ]
    
#    # GJ65 2017-01-06
#        files = [
#        '/Volumes/GRAVITY-1TB/2017-01-06/astroreduced/GRAVITY.2017-01-06T01-26-29_astroreduced',
#        '/Volumes/GRAVITY-1TB/2017-01-06/astroreduced/GRAVITY.2017-01-06T01-41-08_astroreduced',
#        '/Volumes/GRAVITY-1TB/2017-01-06/astroreduced/GRAVITY.2017-01-06T01-47-39_astroreduced',
#        '/Volumes/GRAVITY-1TB/2017-01-06/astroreduced/GRAVITY.2017-01-06T01-56-29_astroreduced',
#        #'/Volumes/GRAVITY-1TB/2017-01-06/astroreduced/GRAVITY.2017-01-06T02-03-05_astroreduced',
#        '/Volumes/GRAVITY-1TB/2017-01-06/astroreduced/GRAVITY.2017-01-06T02-15-34_astroreduced',
#        '/Volumes/GRAVITY-1TB/2017-01-06/astroreduced/GRAVITY.2017-01-06T02-22-25_astroreduced',
#        #'/Volumes/GRAVITY-1TB/2017-01-06/astroreduced/GRAVITY.2017-01-06T02-29-21_astroreduced',
#        '/Volumes/GRAVITY-1TB/2017-01-06/astroreduced/GRAVITY.2017-01-06T02-35-53_astroreduced',
#        ]

    if True:
        directory = '/Users/kervella/Pipelines/python_tools/gravi_astrometry/2017-01-06/'
        files = [
        directory+'GRAVITY.2017-01-06T01-26-29_astroreduced',
        directory+'GRAVITY.2017-01-06T01-41-08_astroreduced',
        directory+'GRAVITY.2017-01-06T01-47-39_astroreduced',
        directory+'GRAVITY.2017-01-06T01-56-29_astroreduced',
        directory+'GRAVITY.2017-01-06T02-03-05_astroreduced',
        directory+'GRAVITY.2017-01-06T02-15-34_astroreduced',
        directory+'GRAVITY.2017-01-06T02-22-25_astroreduced',
        directory+'GRAVITY.2017-01-06T02-35-53_astroreduced'
        ]

    files.sort()
    filename = files[0] # name of the first file in the series for the report

    plt.close('all')
    astroreduced = gravi_astrometry_class.Astroreduced(files,fits_keys)
    produce_astrometry_report(astroreduced,filename)

