Beispiel #1
0
def getNorm(normType, argsOfList, arg):
    if normType == 'variablePrivate': norm = None
    else:
        if normType == 'variableCommon': norm = value(argsOfList, 'norm')
        else:
            norm = value(
                arg, 'norm'
            )  # normType == 'fixed' => норма должна сидеть в параметрах по умолчанию
            assert norm is not None, 'When norm is fixed it must be included in deafaul smooth parameters'
    return norm
Beispiel #2
0
def deconvolve(e, xanes, smooth_params):
    xanes = utils.simpleSmooth(e, xanes, 1)
    Gamma_hole = value(smooth_params, 'Gamma_hole')
    Ecent = value(smooth_params, 'Ecent')
    Elarg = value(smooth_params, 'Elarg')
    Gamma_max = value(smooth_params, 'Gamma_max')
    Efermi = value(smooth_params, 'Efermi')
    n = e.size
    A = np.zeros([n, n])
    for i in range(n):
        #sigma = superWidth(e[i], Gamma_hole, Ecent, Elarg, Gamma_max, Efermi)
        sigma = 5
        kern = kernel(e, e[i], sigma)
        A[i] = kern / utils.integral(e, kern)
    res, _, _, s = np.linalg.lstsq(A, xanes, rcond=0.001)
    return res
Beispiel #3
0
def funcFitSmoothHelper(args, xanes, smoothType, exp, norm=None):
    shift = value(args, 'shift')
    # t1 = time.time()
    if smoothType == 'fdmnes':
        if xanes.folder is None:
            xanes.folder = tempfile.mkdtemp(dir='./tmp', prefix='smooth_')
        if not os.path.exists(xanes.folder + '/out.txt'):
            xanes.save(xanes.folder + '/out.txt',
                       exp.defaultSmoothParams.fdmnesSmoothHeader)
        Gamma_hole, Ecent, Elarg, Gamma_max, Efermi = getSmoothParams(
            args, ['Gamma_hole', 'Ecent', 'Elarg', 'Gamma_max', 'Efermi'])
        fdmnes_en1, res = smooth_fdmnes(xanes.energy,
                                        xanes.absorb,
                                        Gamma_hole,
                                        Ecent,
                                        Elarg,
                                        Gamma_max,
                                        Efermi,
                                        folder=xanes.folder)
    elif smoothType == 'my_fdmnes':
        Gamma_hole, Ecent, Elarg, Gamma_max, Efermi = getSmoothParams(
            args, ['Gamma_hole', 'Ecent', 'Elarg', 'Gamma_max', 'Efermi'])
        fdmnes_en1, res = smooth_my_fdmnes(xanes.energy, xanes.absorb,
                                           Gamma_hole, Ecent, Elarg, Gamma_max,
                                           Efermi)
    elif smoothType == 'linear':
        Gamma_hole, Gamma_max, Efermi = getSmoothParams(
            args, ['Gamma_hole', 'Gamma_max', 'Efermi'])
        fdmnes_en1, res = smooth_linear_conv(xanes.energy, xanes.absorb,
                                             Gamma_hole, Gamma_max, Efermi)
    elif smoothType == 'Muller':
        group, Efermi, Gamma_hole, alpha1, alpha2, alpha3 = getSmoothParams(
            args,
            ['group', 'Efermi', 'Gamma_hole', 'alpha1', 'alpha2', 'alpha3'])
        fdmnes_en1, res = smooth_Muller(xanes.energy, xanes.absorb, group,
                                        Gamma_hole, Efermi, alpha1, alpha2,
                                        alpha3)
    elif smoothType == 'piecewise':
        Gamma_hole, Gamma_max, Ecent = getSmoothParams(
            args, ['Gamma_hole', 'Gamma_max', 'Ecent'])
        fdmnes_en1, res = smooth_piecewise(xanes.energy, xanes.absorb,
                                           Gamma_hole, Gamma_max, Ecent)
    elif smoothType == 'multi_piecewise':
        sigma = getSmoothWidth(smoothType, xanes.energy, args)
        fdmnes_en1, res = generalSmooth(xanes.energy, xanes.absorb, sigma)
    elif smoothType == 'spline':
        sigma = getSmoothWidth(smoothType, xanes.energy, args)
        fdmnes_en1, res = generalSmooth(xanes.energy, xanes.absorb, sigma)
    else:
        error('Unknown smooth type ' + smoothType)
    # t2 = time.time()
    # print("Smooth time=", t2 - t1)
    res, norm = utils.fit_to_experiment_by_norm_or_regression_mult_only(
        exp.xanes.energy, exp.xanes.absorb, exp.fit_intervals['norm'],
        fdmnes_en1, res, shift, norm)
    return utils.Xanes(exp.xanes.energy, res, xanes.folder), norm
Beispiel #4
0
def plotToFolder(folder, exp, xanes0, smoothed_xanes, append=None):
    exp_e = exp.xanes.energy
    exp_xanes = exp.xanes.absorb
    shiftIsAbsolute = exp.defaultSmoothParams.shiftIsAbsolute
    search_shift_level = exp.defaultSmoothParams.search_shift_level
    fit_interval = exp.fit_intervals['norm']
    fig, ax = plt.subplots()
    fdmnes_en = smoothed_xanes.energy
    fdmnes_xan = smoothed_xanes.absorb
    with open(folder + '/args_smooth.txt', 'r') as f:
        smooth_params = json.load(f)
    shift = optimize.value(smooth_params, 'shift')
    if not shiftIsAbsolute:
        shift += utils.getInitialShift(exp_e, exp_xanes, fdmnes_en, fdmnes_xan,
                                       search_shift_level)
    fdmnes_xan0 = utils.fit_arg_to_experiment(xanes0.energy,
                                              exp_e,
                                              xanes0.absorb,
                                              shift,
                                              lastValueNorm=True)
    ax.plot(exp_e - shift, fdmnes_xan0, label='initial')
    ax.plot(exp_e - shift, fdmnes_xan, label='convolution')
    ax.plot(exp_e - shift, exp_xanes, c='k', label="Experiment")
    if append is not None:
        e_fdmnes = exp_e - shift
        ax2 = ax.twinx()
        ax2.plot(e_fdmnes, append, c='r', label='Smooth width')
        ax2.legend()
        # ax3 = ax.twinx()
        # ax3.plot(e_fdmnes[1:], (append[1:]-append[:-1])/(e_fdmnes[1:]-e_fdmnes[:-1]), c='g', label='Diff smooth width')
        # ax3.legend()
    ax.set_xlim([fit_interval[0] - shift, fit_interval[1] - shift])
    ax.set_ylim([0, np.max(exp_xanes) * 1.2])
    ax.set_xlabel("Energy")
    ax.set_ylabel("XANES")
    ax.legend()
    fig.set_size_inches((16 / 3 * 2, 9 / 3 * 2))
    fig.savefig(folder + '/xanes.png')
    plt.close(fig)
Beispiel #5
0
def fitBySliders(geometryParams, xanes, exp):
    # normalize params
    geometryParamsMin = np.min(geometryParams.values, axis=0)
    geometryParamsMax = np.max(geometryParams.values, axis=0)
    geometryParams = 2 * (geometryParams - geometryParamsMin) / (
        geometryParamsMax - geometryParamsMin) - 1
    # machine learning estimator training
    estimator = makeQuadric(RidgeCV(alphas=[0.01, 0.1, 1, 10, 100]))
    estimator.fit(geometryParams.values, xanes.values)
    # need for smoothing by fdmnes
    xanesFolder = tempfile.mkdtemp(prefix='smooth_')
    e_names = xanes.columns
    xanes_energy = np.array(
        [float(e_names[i][2:]) for i in range(e_names.size)])
    fig, ax = plt.subplots()
    ax2 = ax.twinx()
    fig.set_size_inches((16 * 0.6, 9 * 0.8))

    def plotXanes(**params):
        geomArg = np.array([params[pName] for pName in geometryParams.columns
                            ]).reshape([1, geometryParams.shape[1]])
        geomArg = 2 * (geomArg - geometryParamsMin) / (geometryParamsMax -
                                                       geometryParamsMin) - 1
        # prediction
        absorbPrediction = estimator.predict(geomArg)[0]
        # smoothing
        xanesPrediction = utils.Xanes(xanes_energy, absorbPrediction, None,
                                      None)
        xanesPrediction.save(xanesFolder + '/out.txt',
                             exp.defaultSmoothParams.fdmnesSmoothHeader)
        _, smoothedXanes = smoothLib.smooth_fdmnes(
            None, None, params['Gamma_hole'], params['Ecent'], params['Elarg'],
            params['Gamma_max'], params['Efermi'], xanesFolder)
        #plotting
        shift = params['shift']
        exp_e = exp.xanes.energy
        exp_xanes = exp.xanes.absorb
        e_fdmnes = exp_e - shift
        absorbPredictionNormalized = utils.fit_arg_to_experiment(
            xanesPrediction.energy,
            exp_e,
            xanesPrediction.absorb,
            shift,
            lastValueNorm=True)
        smoothedPredictionNormalized = utils.fit_arg_to_experiment(
            xanesPrediction.energy,
            exp_e,
            smoothedXanes,
            shift,
            lastValueNorm=True)
        if params['notConvoluted']:
            ax.plot(e_fdmnes, absorbPredictionNormalized, label='initial')
        ax.clear()
        ax.plot(e_fdmnes, smoothedPredictionNormalized, label='convolution')
        ax.plot(e_fdmnes, exp_xanes, c='k', label="Experiment")
        if params['smoothWidth']:
            smoothWidth = smoothLib.YvesWidth(e_fdmnes, params['Gamma_hole'],
                                              params['Ecent'], params['Elarg'],
                                              params['Gamma_max'],
                                              params['Efermi'])
            ax2.clear()
            ax2.plot(e_fdmnes, smoothWidth, c='r', label='Smooth width')
            ax2.legend()
        ax.set_xlim([params['energyRange'][0], params['energyRange'][1]])
        ax.set_ylim([0, np.max(exp_xanes) * 1.2])
        ax.set_xlabel("Energy")
        ax.set_ylabel("Absorb")
        ax.legend()
        # plt.show()

    controls = []
    o = 'vertical'
    for pName in exp.geometryParamRanges:
        p0 = exp.geometryParamRanges[pName][0]
        p1 = exp.geometryParamRanges[pName][1]
        controls.append(
            widgets.FloatSlider(description=pName,
                                min=p0,
                                max=p1,
                                step=(p1 - p0) / 30,
                                value=(p0 + p1) / 2,
                                orientation=o))
    shift = optimize.value(exp.defaultSmoothParams['fdmnes'], 'shift')
    controls.append(
        widgets.FloatSlider(description='shift',
                            min=shift - 10.0,
                            max=shift + 10.0,
                            step=0.3,
                            value=shift,
                            orientation=o))
    controls.append(
        widgets.FloatSlider(description='Gamma_hole',
                            min=0.1,
                            max=10,
                            step=0.2,
                            value=2,
                            orientation=o))
    controls.append(
        widgets.FloatSlider(description='Ecent',
                            min=0,
                            max=100,
                            step=1,
                            value=50,
                            orientation=o))
    controls.append(
        widgets.FloatSlider(description='Elarg',
                            min=0,
                            max=100,
                            step=1,
                            value=50,
                            orientation=o))
    controls.append(
        widgets.FloatSlider(description='Gamma_max',
                            min=1,
                            max=100,
                            step=1,
                            value=15,
                            orientation=o))
    controls.append(
        widgets.FloatSlider(description='Efermi',
                            min=-30,
                            max=30,
                            step=1,
                            value=0,
                            orientation=o))
    controls.append(widgets.Checkbox(description='smoothWidth', value=True))
    controls.append(widgets.Checkbox(description='notConvoluted', value=True))
    e0 = xanes_energy[0]
    e1 = xanes_energy[-1]
    controls.append(
        widgets.FloatRangeSlider(description='energyRange',
                                 min=e0,
                                 max=e1,
                                 step=(e1 - e0) / 30,
                                 value=[e0, e1],
                                 orientation='horizontal'))
    ui = widgets.HBox(tuple(controls))
    ui.layout.flex_flow = 'row wrap'
    ui.layout.justify_content = 'space-between'
    ui.layout.align_items = 'flex-start'
    ui.layout.align_content = 'flex-start'
    controlsDict = {}
    for c in controls:
        controlsDict[c.description] = c
    out = widgets.interactive_output(plotXanes, controlsDict)
    # out.layout.min_height = '400px'
    display(ui, out)
Beispiel #6
0
def fitSmooth(expList,
              xanesList0,
              smoothType='fdmnes',
              fixParamNames=[],
              commonParams0={},
              targetFunc='max(l2)',
              plotTrace=False,
              crossValidationExp=None,
              crossValidationXanes=None,
              minimizeMethodType='seq',
              useGridSearch=True,
              useRefinement=True):
    xanesList = copy.deepcopy(xanesList0)
    if 'norm' in fixParamNames: normType = 'fixed'
    else:
        if 'norm' in commonParams0: normType = 'variableCommon'
        else: normType = 'variablePrivate'
    folder = tempfile.mkdtemp(dir='./tmp', prefix='smooth_')
    for i in range(len(expList)):
        os.makedirs(folder + '/' + expList[i].name)
        if xanesList[i].folder is not None:
            copyfile(xanesList[i].folder + '/out.txt',
                     folder + '/' + expList[i].name + '/out.txt')
        xanesList[i].folder = folder + '/' + expList[i].name
        if xanesList[i].molecula is not None:
            xanesList[i].molecula.export_xyz(xanesList[i].folder +
                                             '/molecula.xyz')
    arg0 = createArg(expList, smoothType, fixParamNames, commonParams0)
    # 0.0001
    fmin, smooth_params, trace = optimize.minimizePokoord(
        funcFitSmoothList,
        arg0,
        minDeltaFunc=1e-4,
        enableOutput=False,
        methodType=minimizeMethodType,
        parallel=False,
        useRefinement=useRefinement,
        useGridSearch=useGridSearch,
        returnTrace=True,
        f_kwargs={
            'expList': expList,
            'xanesList': xanesList,
            'smoothType': smoothType,
            'targetFunc': targetFunc,
            'normType': normType
        })
    with open(folder + '/func_smooth_value.txt', 'w') as f:
        json.dump(fmin, f)
    with open(folder + '/args_smooth.txt', 'w') as f:
        json.dump(smooth_params, f)
    with open(folder + '/args_smooth_human.txt', 'w') as f:
        f.write(arg2string(smooth_params))
    # выдаем предостережение, если достигли границы одного из параметров
    for p in smooth_params:
        d = p['rightBorder'] - p['leftBorder']
        if (abs(p['value'] - p['leftBorder']) <= p['step']) or (
                abs(p['value'] - p['rightBorder']) <= p['step']):
            print('Warning: parameter ' + p['paramName'] + '=' +
                  str(p['value']) + ' is near border of domain [' +
                  str(p['leftBorder']) + '; ' + str(p['rightBorder']) + ']')
    # считаем по отдельности размазку каждого xanes
    smoothed_xanes = []
    argsOfList = copy.deepcopy(smooth_params)
    for j in range(len(expList)):
        exp = expList[j]
        arg = getOneArg(argsOfList, exp, smoothType)
        norm = getNorm(normType, argsOfList, arg)
        fdmnes_xan, _ = funcFitSmoothHelper(arg, xanesList[j], smoothType, exp,
                                            norm)
        smoothed_xanes.append(fdmnes_xan)
        with open(folder + '/' + expList[j].name + '/args_smooth.txt',
                  'w') as f:
            json.dump(arg, f)
        with open(folder + '/' + expList[j].name + '/args_smooth_human.txt',
                  'w') as f:
            f.write(arg2string(arg))
        shift = value(arg, 'shift')
        fdmnes.plotToFolder(folder + '/' + expList[j].name,
                            exp,
                            xanesList[j],
                            fdmnes_xan,
                            append=getSmoothWidth(smoothType,
                                                  exp.xanes.energy - shift,
                                                  arg))
        ind = (exp.fit_intervals['smooth'][0] <= exp.xanes.energy) & (
            exp.xanes.energy <= exp.fit_intervals['smooth'][1])
        partial_fmin = np.sqrt(
            utils.integral(
                exp.xanes.energy[ind],
                abs(fdmnes_xan.absorb[ind] - exp.xanes.absorb[ind])**2))
        with open(
                folder + '/' + expList[j].name +
                '/func_smooth_partial_value.txt', 'w') as f:
            json.dump(partial_fmin, f)
        plotSmoothWidthToFolder(smoothType, exp.xanes.energy[ind] - shift, arg,
                                folder + '/' + expList[j].name)
    if plotTrace:
        privateFuncData = np.zeros([len(expList), len(trace)])
        norms = np.zeros([len(expList), len(trace)])
        for j in range(len(trace)):
            step = trace[j]
            argsOfList = step[0]
            for i in range(len(expList)):
                arg = getOneArg(argsOfList, expList[i], smoothType)
                norm = getNorm(normType, argsOfList, arg)
                privateFuncData[i, j] = funcFitSmooth(arg, xanesList[i],
                                                      smoothType, expList[i],
                                                      norm)
                _, norms[i,
                         j] = funcFitSmoothHelper(arg, xanesList[i],
                                                  smoothType, expList[i], norm)
        fig, ax = plt.subplots()
        steps = np.arange(1, len(trace) + 1)
        targetFuncData = [step[1] for step in trace]
        for i in range(len(expList)):
            ax.plot(steps, privateFuncData[i], label=expList[i].name)
        ax.plot(steps, targetFuncData, label='target')
        if crossValidationExp is not None:
            crossValidationXanes = copy.deepcopy(crossValidationXanes)
            if smoothType == 'fdmnes':
                folder2 = folder + '/CV_' + crossValidationExp.name
                os.makedirs(folder2)
                if crossValidationXanes.folder is not None:
                    copyfile(crossValidationXanes.folder + '/out.txt',
                             folder2 + '/out.txt')
                crossValidationXanes.folder = folder2
            crossValidationData = []
            for step_i in range(len(trace)):
                step = trace[step_i]
                argsOfList = step[0]
                arg = getOneArg(argsOfList, crossValidationExp, smoothType)
                for a in arg:
                    if value(argsOfList, a['paramName']) is None:
                        mean = 0
                        for exp in expList:
                            mean += value(argsOfList,
                                          exp.name + '_' + a['paramName'])
                        mean /= len(expList)
                        print(
                            'Warning: parameter ' + a['paramName'] +
                            ' is not common. Take mean for cross validation: '
                            + str(mean))
                        a['value'] = mean
                fmin1 = funcFitSmooth(arg, crossValidationXanes, smoothType,
                                      crossValidationExp,
                                      np.mean(norms[:, step_i]))
                crossValidationData.append(fmin1)
                if step_i == len(trace) - 1:
                    with open(folder2 + '/func_smooth_check_value.txt',
                              'w') as f:
                        json.dump(fmin1, f)
                    with open(folder2 + '/args_smooth.txt', 'w') as f:
                        json.dump(arg, f)
                    fdmnes_xan, _ = funcFitSmoothHelper(
                        arg, crossValidationXanes, smoothType,
                        crossValidationExp, np.mean(norms[:, step_i]))
                    fdmnes.plotToFolder(folder2, crossValidationExp,
                                        crossValidationXanes, fdmnes_xan)
                    #print(np.mean(norms[:,step_i]))
            ax.plot(steps, crossValidationData, label='check')
        ax.set_xscale('log')
        ax.legend()
        fig.set_size_inches((16 / 3 * 2, 9 / 3 * 2))
        fig.savefig(folder + '/trace.png')
        plt.close(fig)
    return smoothed_xanes, smooth_params, fmin
Beispiel #7
0
def getSmoothParams(arg, names):
    res = ()
    for name in names:
        res = res + (value(arg, name), )
    return res
Beispiel #8
0
def plotDiffToFolder(folder0,
                     exp_e0,
                     exp_xanes0,
                     folder,
                     exp_e,
                     exp_xanes,
                     fit_interval,
                     shiftIsAbsolute=True,
                     search_shift_level=None,
                     fitBy='RegressionMultOnly'):
    fig, ax = plt.subplots()
    figDiff, axDiff = plt.subplots()
    fdmnes_en_init, fdmnes_xan_init, _ = parse_one_folder(folder)
    fdmnes_en_init0, fdmnes_xan_init0, _ = parse_one_folder(folder0)
    fdmnes_en_conv, fdmnes_xan_conv = parse_convolution(folder)
    fdmnes_en_conv0, fdmnes_xan_conv0 = parse_convolution(folder0)
    with open(folder + '/args_smooth.txt', 'r') as f:
        smooth_params = json.load(f)
    with open(folder0 + '/args_smooth.txt', 'r') as f:
        smooth_params0 = json.load(f)
    shift = optimize.value(smooth_params, 'shift')
    shift0 = optimize.value(smooth_params0, 'shift')
    assert shift == shift0
    if not shiftIsAbsolute:
        shift += utils.getInitialShift(exp_e, exp_xanes, fdmnes_en_conv,
                                       fdmnes_xan_conv, search_shift_level)
        shift0 += utils.getInitialShift(exp_e0, exp_xanes0, fdmnes_en_conv0,
                                        fdmnes_xan_conv0, search_shift_level)
    fdmnes_xan_init = utils.fit_arg_to_experiment(fdmnes_en_init,
                                                  exp_e,
                                                  fdmnes_xan_init,
                                                  shift,
                                                  lastValueNorm=True)
    fdmnes_xan_init0 = utils.fit_arg_to_experiment(fdmnes_en_init0,
                                                   exp_e0,
                                                   fdmnes_xan_init0,
                                                   shift0,
                                                   lastValueNorm=True)
    axDiff.plot(exp_e - shift,
                fdmnes_xan_init - fdmnes_xan_init0,
                label='initDiff')  # здесь важно чтобы shift==shift0
    ax.plot(exp_e - shift, fdmnes_xan_init, label='init')
    ax.plot(exp_e - shift, fdmnes_xan_init0, label='initBare')

    if fitBy == 'RegressionMultOnly':
        fdmnes_xan_conv = utils.fit_arg_to_experiment(fdmnes_en_conv, exp_e,
                                                      fdmnes_xan_conv, shift)
        fdmnes_xan_conv0 = utils.fit_arg_to_experiment(fdmnes_en_conv0, exp_e0,
                                                       fdmnes_xan_conv0,
                                                       shift0)
        fdmnes_xan_conv = utils.fit_by_regression_mult_only(
            exp_e, exp_xanes, fdmnes_xan_conv, fit_interval)
        fdmnes_xan_conv0 = utils.fit_by_regression_mult_only(
            exp_e0, exp_xanes0, fdmnes_xan_conv0, fit_interval)
    elif fitBy == 'Regression':
        fdmnes_xan_conv = utils.fit_arg_to_experiment(fdmnes_en_conv, exp_e,
                                                      fdmnes_xan_conv, shift)
        fdmnes_xan_conv0 = utils.fit_arg_to_experiment(fdmnes_en_conv0, exp_e0,
                                                       fdmnes_xan_conv0,
                                                       shift0)
        fdmnes_xan_conv = utils.fit_by_regression(exp_e, exp_xanes,
                                                  fdmnes_xan_conv,
                                                  fit_interval)
        fdmnes_xan_conv0 = utils.fit_by_regression(exp_e0, exp_xanes0,
                                                   fdmnes_xan_conv0,
                                                   fit_interval)
    elif fitBy == 'FixedNorm':
        norm = optimize.value(smooth_params, 'norm')
        norm0 = optimize.value(smooth_params0, 'norm')
        fdmnes_xan_conv = utils.fit_to_experiment_by_norm_or_regression_mult_only(
            exp_e, exp_xanes, fit_interval, fdmnes_en_conv, fdmnes_xan_conv,
            shift, norm)
        fdmnes_xan_conv0 = utils.fit_to_experiment_by_norm_or_regression_mult_only(
            exp_e0, exp_xanes0, fit_interval, fdmnes_en_conv0,
            fdmnes_xan_conv0, shift0, norm0)
    else:
        assert False, 'Unknown fitBy = ' + fitBy
    axDiff.plot(exp_e - shift,
                fdmnes_xan_conv - fdmnes_xan_conv0,
                label='convDiff')  # здесь важно чтобы shift==shift0
    ax.plot(exp_e - shift, fdmnes_xan_conv, label='conv')
    ax.plot(exp_e - shift, fdmnes_xan_conv0, label='convBare')
    axDiff.plot(exp_e - shift, exp_xanes - exp_xanes0, c='k',
                label="ExpDiff")  # здесь важно чтобы shift==shift0
    ax.plot(exp_e - shift, exp_xanes, label="Exp")
    ax.plot(exp_e - shift, exp_xanes0, label="ExpBare")

    axDiff.set_xlim([fit_interval[0] - shift, fit_interval[1] - shift
                     ])  # здесь важно чтобы shift==shift0
    ax.set_xlim([fit_interval[0] - shift, fit_interval[1] - shift])
    m = np.min(exp_xanes - exp_xanes0)
    M = np.max(exp_xanes - exp_xanes0)
    mM = M - m
    axDiff.set_ylim([m - mM / 5, M + mM / 5])
    ax.set_ylim([0, np.max(exp_xanes) * 1.5])
    axDiff.set_xlabel("Energy")
    ax.set_xlabel("Energy")
    axDiff.set_ylabel("XANES Diff")
    ax.set_ylabel("XANES")
    axDiff.legend()
    ax.legend()
    figDiff.set_size_inches((16 / 3 * 2, 9 / 3 * 2))
    fig.set_size_inches((16 / 3 * 2, 9 / 3 * 2))
    figDiff.savefig(folder + '/xanesDiff.png')
    fig.savefig(folder + '/xanes.png')
    plt.close(figDiff)
    plt.close(fig)