Пример #1
0
def slope_error_hist(thickness_cropped,
                     fitted,
                     pixelSize,
                     delta=1,
                     sourcedistance=1.0,
                     saveFigFlag=True,
                     str4title=''):

    errorThickness = thickness_cropped - fitted

    plt.figure(figsize=(15, 8))
    plt.subplot(121)

    slope_error_h = np.diff(errorThickness, axis=0) / pixelSize[0] * delta
    argNotNAN = np.isfinite(slope_error_h)
    factor_seh, unit_seh = wpu.choose_unit(slope_error_h[argNotNAN])
    sigma_seh = np.std(slope_error_h[argNotNAN].flatten())

    plt.hist(slope_error_h[argNotNAN].flatten() * factor_seh,
             100,
             histtype='stepfilled')
    plt.xlabel(r'Slope Error [$  ' + unit_seh + ' rad$ ]')
    plt.title('Horizontal, SDV = ' + '{:.2f}'.format(sigma_seh * factor_seh) +
              ' $' + unit_seh + ' rad$')

    plt.subplot(122)

    slope_error_v = np.diff(errorThickness, axis=1) / pixelSize[1] * delta
    argNotNAN = np.isfinite(slope_error_v)
    factor_sev, unit_sev = wpu.choose_unit(slope_error_v[argNotNAN])
    sigma_sev = np.std(slope_error_v[argNotNAN].flatten())

    plt.hist(slope_error_v[argNotNAN].flatten() * factor_sev,
             100,
             histtype='stepfilled')
    plt.xlabel(r'Slope Error [$  ' + unit_sev + ' rad$ ]')
    plt.title('Vertical, SDV = ' + '{:.2f}'.format(sigma_sev * factor_sev) +
              ' $' + unit_sev + ' rad$')

    if delta != 1:
        str4title += ' WF slope error'
    else:
        str4title += ' Thickness slope error'
    plt.suptitle(str4title, fontsize=18, weight='bold')

    if saveFigFlag:
        wpu.save_figs_with_idx(fname2save, extension='png')

    wpu.log_this('Slope Error Hor SDV = ' +
                 '{:.3f}'.format(sigma_seh * factor_seh) + unit_seh + ' rad')
    wpu.log_this('Slope Error Ver SDV = ' +
                 '{:.3f}'.format(sigma_sev * factor_sev) + unit_sev + ' rad')

    plt.show(block=True)

    return sigma_seh, sigma_sev
Пример #2
0
(period_harm_Vert,
 _) = wgi.exp_harm_period(img, [period_harm_Vert, period_harm_Horz],
                          harmonic_ij=['1', '0'],
                          searchRegion=40,
                          isFFT=False,
                          verbose=True)

(_,
 period_harm_Horz) = wgi.exp_harm_period(img,
                                         [period_harm_Vert, period_harm_Horz],
                                         harmonic_ij=['0', '1'],
                                         searchRegion=40,
                                         isFFT=False,
                                         verbose=True)

wpu.log_this('Input files: ' + samplefileName.rsplit('_', 1)[0] + '*.tif',
             preffname=fname2save)
wpu.log_this('\nNumber of files : ' + str(nfiles))
wpu.log_this('Stride : ' + str(strideFile))
wpu.log_this('Z distances is ' + zvec_from)

if zvec_from == 'Calculated':
    wpu.log_this('Step zscan [mm] : {:.4g}'.format(step_z_scan * 1e3))
    wpu.log_this('Start point zscan [mm] : {:.4g}'.format(startDist * 1e3))

wpu.log_this('Pixel Size [um] : {:.4g}'.format(pixelSize * 1e6))
wpu.log_this('Grating Period [um] : {:.4g}'.format(gratingPeriod * 1e6))
wpu.log_this('Grating Pattern : ' + pattern)
wpu.log_this('Crop idxs : ' + str(idx4crop))
wpu.log_this('Dark idxs : ' + str(idx4cropDark))

wpu.log_this('Vertical Source Distance: ' + str(sourceDistanceV))
Пример #3
0
    # %% initial pars

    (fname, str4title, nominalRadius, diameter4fit_list,
     lensGeometry) = _load_experimental_pars(sys.argv)

    fname2save = fname.split('.')[0].split('/')[-1] + '_fit'

    data_dir = fname.rsplit('/', 1)[0]
    print(fname)
    print(data_dir)
    os.chdir(data_dir)
    os.makedirs('residuals', exist_ok=True)
    os.chdir('residuals')

    wpu.log_this(preffname=fname.split('.')[0].split('/')[-1] + '_fit',
                 inifname=inifname)

    # %% Load Input File

    if fname.split('.')[-1] == 'sdf':
        thickness, pixelSize, headerdic = wpu.load_sdf_file(fname)
        xx, yy = wpu.realcoordmatrix(thickness.shape[1], pixelSize[1],
                                     thickness.shape[0], pixelSize[0])

    elif fname.split('.')[-1] == 'pickle':

        thickness, xx, yy = load_pickle_surf(fname, False)

        thickness *= 1e-6
        #            thickness *= -1.0 # minus1 here
        xx *= 1e-6
def dpc_profile_analysis(fnameH,
                         fnameV,
                         phenergy,
                         grazing_angle=0.0,
                         projectionFromDiv=1.0,
                         nprofiles=1,
                         remove2ndOrder=False,
                         filter_width=0):

    wavelength = wpu.hc / phenergy

    if fnameH is not None:
        diffPhaseH, virtual_pixelsize, _ = wpu.load_sdf_file(fnameH)

    if fnameV is not None:
        diffPhaseV, virtual_pixelsize, _ = wpu.load_sdf_file(fnameV)

    if fnameH is None:
        diffPhaseH = diffPhaseV * np.nan

    if fnameV is None:
        diffPhaseV = diffPhaseH * np.nan
        saveFileSuf = fnameH.rsplit('/', 1)[0] + '/profiles/' +\
                      fnameH.rsplit('/', 1)[1]
        saveFileSuf = saveFileSuf.rsplit('_X')[0] + '_profiles'
    else:
        saveFileSuf = fnameV.rsplit('/', 1)[0] + '/profiles/' +\
                      fnameV.rsplit('/', 1)[1]
        saveFileSuf = saveFileSuf.rsplit('_Y')[0] + '_profiles'

    if not os.path.exists(saveFileSuf.rsplit('/', 1)[0]):
        os.makedirs(saveFileSuf.rsplit('/', 1)[0])

    (dataH, dataV, labels_H, labels_V,
     fit_coefs) = _n_profiles_H_V(diffPhaseH,
                                  diffPhaseV,
                                  virtual_pixelsize,
                                  'DPC [rad/m]',
                                  titleH='WF DPC Horz',
                                  titleV='WF DPC Vert',
                                  saveFileSuf=saveFileSuf,
                                  nprofiles=nprofiles,
                                  remove2ndOrder=remove2ndOrder,
                                  filter_width=filter_width)

    fit_coefsH = np.array(fit_coefs[0])
    fit_coefsV = np.array(fit_coefs[1])

    print(fit_coefsH)
    print(fit_coefsV)

    if __name__ == '__main__':
        wpu.log_this(preffname=saveFileSuf, inifname=inifname)

    if fnameH is not None:

        radii_fit_H = (2 * np.pi / wavelength / fit_coefsH[:][0])

        wpu.print_blue('MESSAGE: Radius H from fit profiles: ')
        print(radii_fit_H)
        wpu.log_this('radius fit Hor = ' + str(radii_fit_H))

        integratedH = integrate_DPC_cumsum(
            dataH,
            wavelength,
            #grazing_angle=grazing_angle,
            xlabel='x',
            labels=labels_H,
            titleStr='Horizontal, ',
            saveFileSuf=saveFileSuf + '_X')

        curv_H = curv_from_height(
            integratedH,
            virtual_pixelsize[0],
            #grazing_angle=grazing_angle,
            #projectionFromDiv=projectionFromDiv,
            xlabel='x',
            labels=labels_H,
            titleStr='Horizontal, ',
            saveFileSuf=saveFileSuf + '_X')

    if fnameV is not None:

        radii_fit_V = (2 * np.pi / wavelength / fit_coefsV[:][0])

        wpu.print_blue('MESSAGE: Radius V from fit profiles: ')
        print(radii_fit_V)
        wpu.log_this('radius fit Vert = ' + str(radii_fit_V))

        integratedV = integrate_DPC_cumsum(dataV,
                                           wavelength,
                                           grazing_angle=grazing_angle,
                                           projectionFromDiv=projectionFromDiv,
                                           xlabel='y',
                                           labels=labels_V,
                                           titleStr='Vertical, ',
                                           saveFileSuf=saveFileSuf + '_Y')

        curv_V = curv_from_height(integratedV,
                                  virtual_pixelsize[1],
                                  grazing_angle=grazing_angle,
                                  projectionFromDiv=projectionFromDiv,
                                  xlabel='y',
                                  labels=labels_V,
                                  titleStr='Vertical, ',
                                  saveFileSuf=saveFileSuf + '_Y')
Пример #5
0
def dpc_profile_analysis(fnameH, fnameV,
                         phenergy,
                         grazing_angle=0.0, projectionFromDiv=1.0,
                         nprofiles=1,
                         remove1stOrderDPC=False,
                         remove2ndOrder=False,
                         filter_width=0):

    wavelength = wpu.hc/phenergy

    if fnameH is not None:
        diffPhaseH, virtual_pixelsize, _ = wpu.load_sdf_file(fnameH)

    if fnameV is not None:
        diffPhaseV, virtual_pixelsize, _ = wpu.load_sdf_file(fnameV)

    if fnameH is None:
        diffPhaseH = diffPhaseV*np.nan

    if fnameV is None:
        diffPhaseV = diffPhaseH*np.nan
        saveFileSuf = fnameH.rsplit('/', 1)[0] + '/profiles/' +\
                      fnameH.rsplit('/', 1)[1]
        saveFileSuf = saveFileSuf.rsplit('_X')[0] + '_profiles'
    else:
        saveFileSuf = fnameV.rsplit('/', 1)[0] + '/profiles/' +\
                      fnameV.rsplit('/', 1)[1]
        saveFileSuf = saveFileSuf.rsplit('_Y')[0] + '_profiles'

    if not os.path.exists(saveFileSuf.rsplit('/', 1)[0]):
        os.makedirs(saveFileSuf.rsplit('/', 1)[0])

    (dataH, dataV,
     labels_H, labels_V,
     fit_coefs) = _n_profiles_H_V(diffPhaseH,
                                  diffPhaseV,
                                  virtual_pixelsize,
                                  'DPC [rad/m]',
                                  titleH='WF DPC Horz',
                                  titleV='WF DPC Vert',
                                  saveFileSuf=saveFileSuf,
                                  nprofiles=nprofiles,
                                  remove1stOrderDPC=remove1stOrderDPC,
                                  filter_width=filter_width)

    fit_coefsH = np.array(fit_coefs[0])
    fit_coefsV = np.array(fit_coefs[1])

    print(fit_coefsH)
    print(fit_coefsV)

    if __name__ == '__main__':
        wpu.log_this(preffname=saveFileSuf, inifname=inifname)

    if fnameH is not None:

        radii_fit_H = (2*np.pi/wavelength/fit_coefsH[:][0])

        wpu.print_blue('MESSAGE: Radius H from fit profiles: ')
        print(radii_fit_H)
        wpu.log_this('radius fit Hor = ' + str(radii_fit_H))

        integratedH = integrate_DPC_cumsum(dataH, wavelength,
                                           #grazing_angle=grazing_angle,
                                           remove2ndOrder=remove2ndOrder,
                                           xlabel='x',
                                           labels=labels_H,
                                           titleStr='Horizontal, ',
                                           saveFileSuf=saveFileSuf + '_X')

        curv_H = curv_from_height(integratedH, virtual_pixelsize[0],
                                  #grazing_angle=grazing_angle,
                                  #projectionFromDiv=projectionFromDiv,
                                  xlabel='x',
                                  labels=labels_H,
                                  titleStr='Horizontal, ',
                                  saveFileSuf=saveFileSuf + '_X')

    if fnameV is not None:

        radii_fit_V = (2*np.pi/wavelength/fit_coefsV[:][0])

        wpu.print_blue('MESSAGE: Radius V from fit profiles: ')
        print(radii_fit_V)
        wpu.log_this('radius fit Vert = ' + str(radii_fit_V))

        integratedV = integrate_DPC_cumsum(dataV, wavelength,
                                           grazing_angle=grazing_angle,
                                           projectionFromDiv=projectionFromDiv,
                                           remove2ndOrder=remove2ndOrder,
                                           xlabel='y',
                                           labels=labels_V,
                                           titleStr='Vertical, ',
                                           saveFileSuf=saveFileSuf + '_Y')

        curv_V = curv_from_height(integratedV, virtual_pixelsize[1],
                                  grazing_angle=grazing_angle,
                                  projectionFromDiv=projectionFromDiv,
                                  xlabel='y',
                                  labels=labels_V,
                                  titleStr='Vertical, ',
                                  saveFileSuf=saveFileSuf + '_Y')
    wgi.plot_DPC(diffPhase01, diffPhase10,
                 virtual_pixelsize, saveFigFlag=True,
                 saveFileSuf=saveFileSuf)

    plt.pause(.5)

    # %% remove linear component of DPC

    removeLinearFromDPC = easyqt.get_yes_or_no('Remove Linear ' +
                                               'component from DPC?')
    plt.close(plt.gcf())

    if removeLinearFromDPC:

        wpu.log_this('%%% COMMENT: Removed Linear Component from DPC',
                     saveFileSuf)

        def _fit_lin_surface(zz, pixelsize):

            from numpy.polynomial import polynomial

            xx, yy = wpu.grid_coord(zz, pixelsize)

            f = zz.flatten()
            deg = np.array([1, 1])
            vander = polynomial.polyvander2d(xx.flatten(), yy.flatten(), deg)
            vander = vander.reshape((-1, vander.shape[-1]))
            f = f.reshape((vander.shape[0],))
            c = np.linalg.lstsq(vander, f)[0]

            print(c)
def main_terminal(data_dir,
                  zvec_from,
                  startDist,
                  step_z_scan,
                  image_per_point,
                  strideFile,
                  pixelSize=0.65e-6,
                  gratingPeriod=4.8e-6,
                  pattern='Diagonal',
                  sourceDistanceV=-1,
                  sourceDistanceH=32,
                  unFilterSize=1,
                  searchRegion=20,
                  idx4crop=[0, -1, 0, -1],
                  darkRegionSelctionFlag=True):
    '''
        *** all unit in [m]
        data_dir:       data folder path
        zvec_from:      distance type:
                        'Calculated'
                        'Tabled'
        startDist:      started distance postion
        step_z_scan:    step size
        image_per_point:    images number for every distance
        strideFile:     Stride (Use only every XX files)

        pixelSize:       Pixel Size
        gratingPeriod:   CB Grating Period
        pattern:         grating pattern
                        'Diagonal' or 'Edge']
        sourceDistanceV:    Distance to Source
                             in the VERTICAL [m]
        sourceDistanceH:    Distance to Source
                            in the Horizontal [m]
        unFilterSize:   Size for Uniform Filter [Pixels]
                        default_value  1
        searchRegion:   Size of Region for Searching
                        the Peak [in Pixels]
                        default_value=20
        idx4crop:       crop area
                        [low_y, high_y, low_x, high_x ]
        darkRegionSelctionFlag:     use dark region [0, 20, 0, 20]?

    '''
    wpu._mpl_settings_4_nice_graphs()

    # =============================================================================
    # %% Load Image
    # =============================================================================

    originalDir = os.getcwd()

    # samplefileName = easyqt.get_file_names("Choose one of the scan files")[0]

    # data_dir = samplefileName.rsplit('/', 1)[0]
    os.chdir(data_dir)

    try:
        os.mkdir(data_dir + '/output/')
    except:
        pass

    fname2save = data_dir + '/output/' + 'zscan'

    # wpu.print_blue('MESSAGE: Loading files ' +
    #                samplefileName.rsplit('_', 1)[0] + '*.tif')
    wpu.print_blue('MESSAGE: Loading files ' + data_dir + '/*.tif')

    # listOfDataFiles = glob.glob(samplefileName.rsplit('_', 2)[0] + '*.tif')
    listOfDataFiles = glob.glob(os.path.join(data_dir, '*.tif'))
    listOfDataFiles.sort()
    nfiles = len(listOfDataFiles)

    # zvec_from = easyqt.get_choice(message='z distances is calculated or from table?',
    #                               title='Title',
    #                               choices=['Calculated', 'Tabled'])

    # %%

    if zvec_from == 'Calculated':

        # startDist = easyqt.get_float('Starting distance scan [mm]',
        #                              title='Title',
        #                              default_value=20)*1e-3

        # step_z_scan = easyqt.get_float('Step size scan [mm]',
        #                                title='Title',
        #                                default_value=5)*1e-3

        # image_per_point = easyqt.get_int('Number of images by step',
        #                                  title='Title',
        #                                  default_value=1)

        zvec = np.linspace(
            startDist,
            startDist + step_z_scan * (nfiles / image_per_point - 1),
            int(nfiles / image_per_point))
        zvec = zvec.repeat(image_per_point)

        # strideFile = easyqt.get_int('Stride (Use only every XX files)',
        #                             title='Title',
        #                             default_value=1)
        listOfDataFiles = listOfDataFiles[0::strideFile]
        zvec = zvec[0::strideFile]
        print(zvec)
    elif zvec_from == 'Tabled':

        zvec = np.loadtxt(
            easyqt.get_file_names("Table with the z distance values in mm")
            [0]) * 1e-3
        step_z_scan = np.mean(np.diff(zvec))

    if step_z_scan > 0:
        pass
    else:
        listOfDataFiles = listOfDataFiles[::-1]
        zvec = zvec[::-1]

    img = dxchange.read_tiff(listOfDataFiles[0])

    # =============================================================================
    # %% Experimental parameters
    # =============================================================================

    # pixelSize = easyqt.get_float("Enter Pixel Size [um]",
    #                              title='Experimental Values',
    #                              default_value=.6500, decimals=5)*1e-6

    # gratingPeriod = easyqt.get_float("Enter CB Grating Period [um]",
    #                                  title='Experimental Values',
    #                                  default_value=4.8)*1e-6

    # pattern = easyqt.get_choice(message='Select CB Grating Pattern',
    #                             title='Title',
    #                             choices=['Diagonal', 'Edge'])
    # #                            choices=['Edge', 'Diagonal'])

    # sourceDistanceV = easyqt.get_float("Enter Distance to Source\n in the VERTICAL [m]",
    #                                    title='Experimental Values',
    #                                    default_value=-0.73)

    # sourceDistanceH = easyqt.get_float("Enter Distance to Source\n in the Horizontal [m]",
    #                                    title='Experimental Values',
    #                                    default_value=34.0)

    # unFilterSize = easyqt.get_int("Enter Size for Uniform Filter [Pixels]\n" +
    #                               "    (Enter 1 to NOT use the filter)",
    #                               title='Experimental Values',
    #                               default_value=1)

    # searchRegion = easyqt.get_int("Enter Size of Region for Searching\n the Peak [in Pixels]",
    #                               title='Experimental Values',
    #                               default_value=20)

    os.chdir(originalDir)

    # =============================================================================
    # %% Crop
    # =============================================================================

    idx4crop = [0, -1, 0, -1]

    # [colorlimit,
    #  cmap] = wpu.plot_slide_colorbar(img,
    #                                  title='SELECT COLOR SCALE,\n' +
    #                                  'Raw Image, No Crop',
    #                                  xlabel=r'x [$\mu m$ ]',
    #                                  ylabel=r'y [$\mu m$ ]',
    #                                  extent=wpu.extent_func(img,
    #                                                         pixelSize)*1e6)

    # idx4crop = wpu.graphical_roi_idx(img, verbose=True,
    #                                  kargs4graph={'cmap': cmap,
    #                                               'vmin': colorlimit[0],
    #                                               'vmax': colorlimit[1]})

    wpu.print_blue("MESSAGE: idx for cropping")
    wpu.print_blue(idx4crop)

    # =============================================================================
    # %% Dark indexes
    # =============================================================================

    # darkRegionSelctionFlag = easyqt.get_yes_or_no('Do you want to select ' +
    #                                               'region for dark calculation?\n' +
    #                                               'Press ESC to use [0, 20, 0, 20]')
    print(darkRegionSelctionFlag)
    if darkRegionSelctionFlag:

        idx4cropDark = wpu.graphical_roi_idx(img,
                                             verbose=True,
                                             kargs4graph={
                                                 'cmap': cmap,
                                                 'vmin': colorlimit[0],
                                                 'vmax': colorlimit[1]
                                             })
    else:
        idx4cropDark = [0, 20, 0, 20]

    # dark_im = dxchange.read_tiff(listOfDataFiles[0])*0.0 + avgDark

    img = wpu.crop_matrix_at_indexes(img, idx4crop)

    # ==============================================================================
    # %% Harmonic Periods
    # ==============================================================================

    if pattern == 'Diagonal':
        period_harm_Vert = np.int(
            np.sqrt(2) * pixelSize / gratingPeriod * img.shape[0])
        period_harm_Horz = np.int(
            np.sqrt(2) * pixelSize / gratingPeriod * img.shape[1])
    elif pattern == 'Edge':
        period_harm_Vert = np.int(2 * pixelSize / gratingPeriod * img.shape[0])
        period_harm_Horz = np.int(2 * pixelSize / gratingPeriod * img.shape[1])

    # Obtain harmonic periods from images

    (period_harm_Vert,
     _) = wgi.exp_harm_period(img, [period_harm_Vert, period_harm_Horz],
                              harmonic_ij=['1', '0'],
                              searchRegion=40,
                              isFFT=False,
                              verbose=True)

    (_, period_harm_Horz) = wgi.exp_harm_period(
        img, [period_harm_Vert, period_harm_Horz],
        harmonic_ij=['0', '1'],
        searchRegion=40,
        isFFT=False,
        verbose=True)

    wpu.log_this('Input folder: ' + data_dir, preffname=fname2save)
    wpu.log_this('\nNumber of files : ' + str(nfiles))
    wpu.log_this('Stride : ' + str(strideFile))
    print(zvec_from)
    wpu.log_this('Z distances is ' + zvec_from)

    if zvec_from == 'Calculated':
        wpu.log_this('Step zscan [mm] : {:.4g}'.format(step_z_scan * 1e3))
        wpu.log_this('Start point zscan [mm] : {:.4g}'.format(startDist * 1e3))

    wpu.log_this('Pixel Size [um] : {:.4g}'.format(pixelSize * 1e6))
    wpu.log_this('Grating Period [um] : {:.4g}'.format(gratingPeriod * 1e6))
    wpu.log_this('Grating Pattern : ' + pattern)
    wpu.log_this('Crop idxs : ' + str(idx4crop))
    wpu.log_this('Dark idxs : ' + str(idx4cropDark))

    wpu.log_this('Vertical Source Distance: ' + str(sourceDistanceV))
    wpu.log_this('Horizontal Source Distance: ' + str(sourceDistanceH))

    wpu.log_this('Uniform Filter Size : {:d}'.format(unFilterSize))

    wpu.log_this('Search Region : {:d}'.format(searchRegion))

    # =============================================================================
    # %% Calculate everything
    # =============================================================================

    # =============================================================================
    # %% multiprocessing
    # =============================================================================

    ncpus = cpu_count()

    wpu.print_blue("MESSAGE: %d cpu's available" % ncpus)

    tzero = time.time()

    p = Pool(ncpus - 2)

    indexes = range(len(listOfDataFiles))
    parameters = []

    for i in indexes:
        parameters.append([
            i, listOfDataFiles, zvec, idx4cropDark, idx4crop, period_harm_Vert,
            sourceDistanceV, period_harm_Horz, sourceDistanceH, searchRegion,
            unFilterSize
        ])

    res = p.map(_func, parameters)
    p.close()

    wpu.print_blue('MESSAGE: Time spent: {0:.3f} s'.format(time.time() -
                                                           tzero))
    '''
    res = []
    for i in range(len(listOfDataFiles)):
        res.append(_func(i))
    print(res)
    '''
    # =============================================================================
    # %% Sorting the data
    # =============================================================================

    contrastV = np.asarray([x[0] for x in res])
    contrastH = np.asarray([x[1] for x in res])

    p0 = np.asarray([x[2] for x in res])
    pv = np.asarray([x[3] for x in res])
    ph = np.asarray([x[4] for x in res])

    pattern_period_Vert_z = pixelSize / (pv[:, 0] - p0[:, 0]) * img.shape[0]
    pattern_period_Horz_z = pixelSize / (ph[:, 1] - p0[:, 1]) * img.shape[1]

    # =============================================================================
    # %% Save csv file
    # =============================================================================

    outputfname = wpu.get_unique_filename(fname2save, 'csv')

    wpu.save_csv_file(np.c_[zvec.T, contrastV.T, contrastH.T,
                            pattern_period_Vert_z.T, pattern_period_Horz_z.T],
                      outputfname,
                      headerList=[
                          'z [m]', 'Vert Contrast', 'Horz Contrast',
                          'Vert Period [m]', 'Horz Period [m]'
                      ])

    wpu.log_this('\nOutput file: ' + outputfname)

    # =============================================================================
    # %% Plot
    # =============================================================================

    # contrast vs z
    fig = plt.figure(figsize=(10, 7))
    plt.plot(zvec * 1e3, contrastV * 100, '-ko', label='Vert')
    plt.plot(zvec * 1e3, contrastH * 100, '-ro', label='Hor')
    plt.xlabel(r'Distance $z$  [mm]', fontsize=14)

    plt.ylabel(r'Visibility $\times$ 100 [%]', fontsize=14)
    plt.title('Visibility vs detector distance', fontsize=14, weight='bold')

    plt.legend(fontsize=14, loc=0)

    wpu.save_figs_with_idx(fname2save)
    plt.show(block=False)

    # =============================================================================
    # %% Plot Harmonic position and calculate source distance
    # =============================================================================
    from wavepytools.diag.coherence.fit_singleGratingCoherence_z_scan import fit_period_vs_z
    #xshi 20190719
    #from fit_singleGratingCoherence_z_scan import fit_period_vs_z
    (sourceDistance_from_fit_V,
     patternPeriodFromData_V) = fit_period_vs_z(zvec,
                                                pattern_period_Vert_z,
                                                contrastV,
                                                direction='Vertical',
                                                threshold=.002,
                                                fname4graphs=fname2save)

    (sourceDistance_from_fit_H,
     patternPeriodFromData_H) = fit_period_vs_z(zvec,
                                                pattern_period_Horz_z,
                                                contrastH,
                                                direction='Horizontal',
                                                threshold=0.0005,
                                                fname4graphs=fname2save)