Example #1
0
def enthalpy_dH(request, cid, db_type=None, mdb=None):
    try:
        pars, _, _, response, payload, x_val = init_isographs(request=request, db_type=db_type, cid=cid, mdb=mdb)
        resiso, resiso_theo = [], []

        if pars['experimental_data_available']:     # only execute this if experimental data is available
            for xv in x_val:                # calculate experimental data
                try:
                    s_th = s_th_o(payload['iso'])
                    args = (payload['iso'], xv, pars, s_th)
                    solutioniso = dh_ds(xv, args[-1], args[-2])[0] / 1000
                    resiso.append(solutioniso)
                except ValueError:          # if brentq function finds no zero point due to plot out of range
                    resiso.append(None)

            res_interp, res_fit = [], []
            for delta_val, res_i in zip(x_val, resiso):    # show interpolation
                if pars['delta_min'] < delta_val < pars['delta_max']:   # result within experimentally covered delta range
                    res_fit.append(res_i)
                    res_interp.append(None)
                else:                                   # result outside this range
                    res_fit.append(None)
                    res_interp.append(res_i)
        else:
            res_fit, res_interp = None, None    # don't plot any experimental data if it is not available

        try:                                # calculate theoretical data
            for xv in x_val[::4]: # use less data points for theoretical graphs to improve speed
                args_theo = (payload['iso'], xv, pars, pars['td_perov'], pars['td_brownm'], \
                pars["dh_min"], pars["dh_max"], pars["act_mat"])
                solutioniso_theo = d_h_num_dev_calc(delta=xv, dh_1=pars["dh_min"], dh_2=pars["dh_max"],
                                temp=payload['iso'], act=pars["act_mat"]) / 1000
                resiso_theo.append(solutioniso_theo)
        except ValueError: # if brentq function finds no zero point due to plot out of range
            resiso_theo.append(None)

        x = list(x_val)
        x_theo = x[::4]
        x_exp = None
        if pars['experimental_data_available']:
            x_exp = x
        if max(pd.np.append(resiso, resiso_theo)) > (pars['dh_max'] * 0.0015):    # limiting values for the plot
            y_max = pars['dh_max'] * 0.0015
        else:
            y_max = max(pd.np.append(resiso, resiso_theo))*1.2
        if min(pd.np.append(resiso, resiso_theo)) < -10:
            y_min = -10
        else:
            y_min = min(pd.np.append(resiso, resiso_theo)) * 0.8
        response = [{'x': x_exp, 'y': res_fit, 'name': "exp_fit", 'line': { 'color': 'rgb(5,103,166)', 'width': 2.5 }},
                        {'x': x_exp, 'y': res_interp, 'name': "exp_interp", \
                        'line': { 'color': 'rgb(5,103,166)', 'width': 2.5, 'dash': 'dot' }},
                        {'x': x_theo, 'y': resiso_theo, 'name': "theo", \
                        'line': { 'color': 'rgb(217,64,41)', 'width': 2.5}}, [y_min,y_max],
                        [pars['compstr_disp'], pars['compstr_exp'], pars['tens_avail'], pars["last_updated"]]]

    except Exception as ex:
        raise ValueError('"REST Error: "{}"'.format(str(ex)))
    return {"valid_response": True, 'response': response}
Example #2
0
def isotherm(request, cid, db_type=None, mdb=None):
    try:
        pars, a, b, response, payload, x_val = init_isographs(request=request,
                                                              db_type=db_type,
                                                              cid=cid,
                                                              mdb=mdb)
        resiso, resiso_theo = [], []

        if pars['experimental_data_available']:  # only execute this if experimental data is available
            for xv in x_val:  # calculate experimental data
                try:
                    s_th = s_th_o(payload['iso'])
                    args = (xv, payload['iso'], pars, s_th)
                    solutioniso = rootfind(a, b, args, funciso)
                    resiso.append(solutioniso)
                except ValueError:  # if brentq function finds no zero point due to plot out of range
                    resiso.append(None)

            res_interp, res_fit = [], []
            for delta_val, res_i in zip(x_val, resiso):  # show interpolation
                if pars['delta_min'] < delta_val < pars[
                        'delta_max']:  # result within experimentally covered delta range
                    res_fit.append(res_i)
                    res_interp.append(None)
                else:  # result outside this range
                    res_fit.append(None)
                    res_interp.append(res_i)
        else:
            res_fit, res_interp = None, None  # don't plot any experimental data if it is not available

        try:  # calculate theoretical data
            for xv in x_val[::
                            4]:  # use less data points for theoretical graphs to improve speed
                args_theo = (xv, payload['iso'], pars, pars['td_perov'], pars['td_brownm'], \
                pars["dh_min"], pars["dh_max"], pars["act_mat"])
                solutioniso_theo = rootfind(a, b, args_theo, funciso_theo)
                resiso_theo.append(solutioniso_theo)
        except ValueError:  # if brentq function finds no zero point due to plot out of range
            resiso_theo.append(None)

        x = list(pd.np.exp(x_val))
        x_theo = x[::4]
        x_exp = None
        if pars['experimental_data_available']:
            x_exp = x
        response = [{'x': x_exp, 'y': res_fit, 'name': "exp_fit", 'line': { 'color': 'rgb(5,103,166)', 'width': 2.5 }},
                        {'x': x_exp, 'y': res_interp, 'name': "exp_interp", \
                        'line': { 'color': 'rgb(5,103,166)', 'width': 2.5, 'dash': 'dot' }},
                        {'x': x_theo, 'y': resiso_theo, 'name': "theo", 'line': { 'color': 'rgb(217,64,41)', 'width': 2.5}}, [0,0],\
                        [pars['compstr_disp'], pars['compstr_exp'], pars['tens_avail'], pars["last_updated"]]]

    except Exception as ex:
        raise ValueError('"REST Error: "{}"'.format(str(ex)))
    return {"valid_response": True, 'response': response}
Example #3
0
def isoredox(request, cid, db_type=None, mdb=None):
    try:
        pars, a, b, response, payload, x_val = init_isographs(request=request, db_type=db_type, cid=cid, mdb=mdb)
        resiso, resiso_theo = [], []

        if pars['experimental_data_available']:     # only execute this if experimental data is available
            for xv in x_val:                # calculate experimental data
                try:
                    s_th = s_th_o(xv)
                    args = (payload['iso'], xv, pars, s_th)
                    solutioniso = brentq(funciso_redox, -300, 300, args=args)
                    resiso.append(pd.np.exp(solutioniso))
                except ValueError:          # if brentq function finds no zero point due to plot out of range
                    resiso.append(None)

            res_interp, res_fit = [], []
            for delta_val, res_i in zip(x_val, resiso):    # show interpolation
                if pars['delta_min'] < delta_val < pars['delta_max']:   # result within experimentally covered delta range
                    res_fit.append(res_i)
                    res_interp.append(None)
                else:                                   # result outside this range
                    res_fit.append(None)
                    res_interp.append(res_i)
        else:
            res_fit, res_interp = None, None    # don't plot any experimental data if it is not available

        try:                                # calculate theoretical data
            for xv in x_val[::4]: # use less data points for theoretical graphs to improve speed
                args_theo = (payload['iso'], xv, pars, pars['td_perov'], pars['td_brownm'], \
                pars["dh_min"], pars["dh_max"], pars["act_mat"])
                try:
                    solutioniso_theo = brentq(funciso_redox_theo, -300, 300, args=args_theo)
                except ValueError:
                    solutioniso_theo = brentq(funciso_redox_theo, -100, 100, args=args_theo)
                resiso_theo.append(pd.np.exp(solutioniso_theo))
        except ValueError: # if brentq function finds no zero point due to plot out of range
            resiso_theo.append(None)

        x = list(x_val)
        x_theo = x[::4]
        x_exp = None
        if pars['experimental_data_available']:
            x_exp = x
        response = [{'x': x_exp, 'y': res_fit, 'name': "exp_fit", 'line': { 'color': 'rgb(5,103,166)', 'width': 2.5 }},
                        {'x': x_exp, 'y': res_interp, 'name': "exp_interp", \
                        'line': { 'color': 'rgb(5,103,166)', 'width': 2.5, 'dash': 'dot' }},
                        {'x': x_theo, 'y': resiso_theo, 'name': "theo", 'line': { 'color': 'rgb(217,64,41)', 'width': 2.5}}, [0,0],\
                        [pars['compstr_disp'], pars['compstr_exp'], pars['tens_avail'], pars["last_updated"]]]

    except Exception as ex:
        raise ValueError('"REST Error: "{}"'.format(str(ex)))
    return {"valid_response": True, 'response': response}
Example #4
0
def ellingham(request, cid, db_type=None, mdb=None):
    try:
        pars, _, _, response, payload, x_val = init_isographs(request=request,
                                                              db_type=db_type,
                                                              cid=cid,
                                                              mdb=mdb)
        iso = pd.np.log(10**payload['iso'])
        delt = float(payload['del'])

        resiso, resiso_theo, ellingiso = [], [], []
        if pars['experimental_data_available']:  # only execute this if experimental data is available
            for xv in x_val:  # calculate experimental data
                try:
                    s_th = s_th_o(xv)
                    args = (iso, xv, pars, s_th)
                    solutioniso = (
                        dh_ds(delt, args[-1], args[-2])[0] -
                        dh_ds(delt, args[-1], args[-2])[1] * xv) / 1000
                    resiso.append(solutioniso)
                    ellingiso_i = isobar_line_elling(args[0], xv) / 1000
                    ellingiso.append(ellingiso_i)
                except ValueError:  # if brentq function finds no zero point due to plot out of range
                    resiso.append(None)

            res_interp, res_fit = [], []
            for delta_val, res_i in zip(x_val, resiso):  # show interpolation
                if pars['delta_min'] < delta_val < pars[
                        'delta_max']:  # result within experimentally covered delta range
                    res_fit.append(res_i)
                    res_interp.append(None)
                else:  # result outside this range
                    res_fit.append(None)
                    res_interp.append(res_i)
        else:
            res_fit, res_interp = None, None  # don't plot any experimental data if it is not available

        try:  # calculate theoretical data
            for xv in x_val[::
                            4]:  # use less data points for theoretical graphs to improve speed
                dh = d_h_num_dev_calc(delta=delt,
                                      dh_1=pars['dh_min'],
                                      dh_2=pars['dh_max'],
                                      temp=xv,
                                      act=pars["act_mat"])
                ds = d_s_fundamental(delta=delt,
                                     dh_1=pars['dh_min'],
                                     dh_2=pars['dh_max'],
                                     temp=xv,
                                     act=pars["act_mat"],
                                     t_d_perov=pars['td_perov'],
                                     t_d_brownm=pars['td_brownm'])
                solutioniso_theo = (dh - ds * xv) / 1000
                resiso_theo.append(solutioniso_theo)
        except ValueError:  # if brentq function finds no zero point due to plot out of range
            resiso_theo.append(None)

        x = list(x_val)
        x_theo = x[::4]
        if pars['experimental_data_available']:
            x_exp = x
            response = [{'x': x_exp, 'y': res_fit, 'name': 'exp_fit', 'line': { 'color': 'rgb(5,103,166)', 'width': 2.5 }},
                    {'x': x_exp, 'y': res_interp, 'name': 'exp_interp', \
                    'line': { 'color': 'rgb(5,103,166)', 'width': 2.5, 'dash': 'dot' }},
                    {'x': x_theo, 'y': resiso_theo, 'name': 'theo', 'line': { 'color': 'rgb(217,64,41)', 'width': 2.5}},
                    {'x': x_exp, 'y': ellingiso, 'name': 'isobar line', 'line': { 'color': 'rgb(100,100,100)', 'width': 2.5}},\
                    [pars['compstr_disp'], pars['compstr_exp'], pars['tens_avail'], pars["last_updated"]]]

        else:
            x_exp = None
            for xv in x_theo:
                ellingiso_i = isobar_line_elling(iso, xv) / 1000
                ellingiso.append(ellingiso_i)
            response = [{'x': x_exp, 'y': res_fit, 'name': 'exp_fit', 'line': { 'color': 'rgb(5,103,166)', 'width': 2.5 }},
            {'x': x_exp, 'y': res_interp, 'name': 'exp_interp', \
            'line': { 'color': 'rgb(5,103,166)', 'width': 2.5, 'dash': 'dot' }},
            {'x': x_theo, 'y': resiso_theo, 'name': 'theo', 'line': { 'color': 'rgb(217,64,41)', 'width': 2.5}},
            {'x': x_theo, 'y': ellingiso, 'name': 'isobar line', 'line': { 'color': 'rgb(100,100,100)', 'width': 2.5}},\
            [pars['compstr_disp'], pars['compstr_exp'], pars['tens_avail'], pars["last_updated"]]]

    except Exception as ex:
        raise ValueError('"REST Error: "{}"'.format(str(ex)))
    return {"valid_response": True, 'response': response}
Example #5
0
def enthalpy_dH(request, cid, db_type=None, mdb=None):
    try:
        pars, _, _, response, payload, x_val = init_isographs(request=request,
                                                              db_type=db_type,
                                                              cid=cid,
                                                              mdb=mdb)
        resiso, resiso_theo = [], []

        if pars['experimental_data_available']:  # only execute this if experimental data is available
            for xv in x_val:  # calculate experimental data
                try:
                    s_th = s_th_o(payload['iso'])
                    args = (payload['iso'], xv, pars, s_th)
                    solutioniso = dh_ds(xv, args[-1], args[-2])[0] / 1000
                    resiso.append(solutioniso)
                except ValueError:  # if brentq function finds no zero point due to plot out of range
                    resiso.append(None)

            res_interp, res_fit = [], []
            for delta_val, res_i in zip(x_val, resiso):  # show interpolation
                if pars['delta_min'] < delta_val < pars[
                        'delta_max']:  # result within experimentally covered delta range
                    res_fit.append(res_i)
                    res_interp.append(None)
                else:  # result outside this range
                    res_fit.append(None)
                    res_interp.append(res_i)
        else:
            res_fit, res_interp = None, None  # don't plot any experimental data if it is not available

        try:  # calculate theoretical data
            for xv in x_val[::
                            4]:  # use less data points for theoretical graphs to improve speed
                args_theo = (payload['iso'], xv, pars, pars['td_perov'], pars['td_brownm'], \
                pars["dh_min"], pars["dh_max"], pars["act_mat"])
                solutioniso_theo = d_h_num_dev_calc(delta=xv,
                                                    dh_1=pars["dh_min"],
                                                    dh_2=pars["dh_max"],
                                                    temp=payload['iso'],
                                                    act=pars["act_mat"]) / 1000
                resiso_theo.append(solutioniso_theo)
        except ValueError:  # if brentq function finds no zero point due to plot out of range
            resiso_theo.append(None)

        x = list(x_val)
        x_theo = x[::4]
        x_exp = None
        if pars['experimental_data_available']:
            x_exp = x
        if max(pd.np.append(resiso, resiso_theo)) > (
                pars['dh_max'] * 0.0015):  # limiting values for the plot
            y_max = pars['dh_max'] * 0.0015
        else:
            y_max = max(pd.np.append(resiso, resiso_theo)) * 1.2
        if min(pd.np.append(resiso, resiso_theo)) < -10:
            y_min = -10
        else:
            y_min = min(pd.np.append(resiso, resiso_theo)) * 0.8
        response = [{'x': x_exp, 'y': res_fit, 'name': "exp_fit", 'line': { 'color': 'rgb(5,103,166)', 'width': 2.5 }},
                        {'x': x_exp, 'y': res_interp, 'name': "exp_interp", \
                        'line': { 'color': 'rgb(5,103,166)', 'width': 2.5, 'dash': 'dot' }},
                        {'x': x_theo, 'y': resiso_theo, 'name': "theo", \
                        'line': { 'color': 'rgb(217,64,41)', 'width': 2.5}}, [y_min,y_max],
                        [pars['compstr_disp'], pars['compstr_exp'], pars['tens_avail'], pars["last_updated"]]]

    except Exception as ex:
        raise ValueError('"REST Error: "{}"'.format(str(ex)))
    return {"valid_response": True, 'response': response}
    def calc(self, p_ox, p_red, t_ox, t_red, data_origin="Exp", data_use="combined",
             enth_steps=30, sample_ident=-1, celsius=True, from_file=True,
             heat_cap=True,
             heat_cap_approx=True
             ):

        """
        Performs an energy analysis using experimental data.

        :param p_ox:    Oxidation partial pressure of oxygen (in bar) or ratio p(H2)/p(H2O) / p(CO)/p(CO2)
        :param p_red:   Oxygen partial pressure for reduction (in bar)
        :param t_ox:    Oxidation temperature
        :param t_red:   Reduction temperature

        :param data_origin:     "Exp":  experimental data
                                "Theo": theoretical data

            ***only relevant if 'data_origin' = "Theo"
            :param data_use:
                                "endmembers": uses redox members of solid solution endmembers to estimate redox
                                              enthalpies of solid solutions
                                "combined":   corrects above-mentioned data by the actual redox enthalpies for the solid
                                              solutions calcualted via DFT

            :param enth_steps:      number of enthalpy values which are calculated for each material in order to
                                    reach a good approximation of the integral over dH vs. delta

        :param sample_ident:   Sample number(s) (experimental data) or composition (theoretical data),
                               default value '-1'-> analyze all samples

        :param pump_ener:   allows to consider the pumping energy required to pump from p_o_2_1 to p_o_2_2
                            input in kJ per kg of redox material in the oxidized state + the losses
                            This depends on many factors, such as the type of pumps used, the volume of the
                            reaction chamber, the reactor type etc., so the user needs to calculate this
                            value beforehand depending on the individual process conditions
                            In case some of the pumping energy can be recovered, this share needs to be
                            subtracted beforehand, as it is not considered herein.

        :param celsius:             if True, assumes all input temperatures are in °C instead of K

        :param from_file:           if True, takes the enthalpies, Debye temperatures, and materials lists from
                                    the file "theo_redenth_debye.json". Much faster than using the MPRester
                                    Only works if sample_ident = -1

        :param heat_cap:            if True, sensible energy to heat the samples is considered
        :param heat_cap_approx:     if True, uses values for SrFeOx in case of missing heat capacity data

        :return:    dict_result: dictonary with results for different materials
        """
        si_first = sample_ident
        # correct temperature values for Kelvin/Celsius
        if celsius:
            temp_1_corr = t_ox + 273.15
            temp_2_corr = t_red + 273.15
        else:
            temp_1_corr = t_ox
            temp_2_corr = t_red

        if data_origin == "Exp": # currently not in use for updates of existing data
            # load experimental sample data from file
            path = os.path.abspath("")
            filepath = os.path.join(path, "exp_data.json")
            with open(filepath) as handle:
                expdata = json.loads(handle.read())

        # use equivalent partial pressures for Water Splitting and CO2 splitting
        if self.process == "Water Splitting":
            p_ox = WaterSplitting().get_po2(temp=temp_1_corr, h2_h2o=p_ox)
        elif self.process == "CO2 Splitting":
            p_ox = CO2Splitting().get_po2(temp=temp_1_corr, co_co2=p_ox)

        # iterate over samples
        if isinstance(sample_ident, collections.Sized) and not isinstance(sample_ident, str):
            no_range = range(len(sample_ident))
            sample = None
        else:
            no_range = range(1)
            if data_origin == "Exp":
                sample = int(sample_ident)
            else:
                sample = str(sample_ident)
            # iterate over all available samples
            if sample_ident == -1:
                sample = None
                if data_origin == "Exp":
                    no_range = range(0, 150)
                    sample_ident = no_range
                else:
                    if not from_file:
                        filename = os.path.join(os.path.abspath('..'), "datafiles", "perovskite_theo_list.csv")
                        if not os.path.exists(filename):
                            raise ImportError("File 'perovskite_theo_list.csv' not found.")
                        fo = open(filename, "rb")
                        sample_ident = pd.np.genfromtxt(fo, dtype='str', delimiter=",", skip_header=1)
                        fo.close()
                    else:
                        sampledata = views.get_theo_data()
                        sample_ident = sampledata["compstr"]
                    no_range = range(len(sample_ident))

        sample_l, chemical_energy_l, sensible_energy_l, mol_mass_ox_l, prodstr_alt_l = [], [], [], [], []
        mol_prod_mol_red_l, t_ox_l, t_red_l, p_ox_l, p_red_l, compstr_l = [], [], [], [], [], []
        delta_1_l, delta_2_l, mass_redox_l, prodstr_l, l_prod_kg_red_l, g_prod_kg_red_l = [], [], [], [], [], []
        for i in no_range:
            if not sample:
                sample = sample_ident[i]
            # this only works if the sample number/data exists
            try:
                if data_origin == "Exp":
                    exp_index = -1
                    for k in range(len(expdata)):
                        if int(expdata["Sample number"][k]) == sample:
                            exp_index = k
                    if exp_index == -1:
                        raise ValueError("Experimental data for this sample not found.")
                    compstr = expdata["theo_compstr"][exp_index]
                    compstr_x = compstr.split("Ox")[0]

                    # this formats the parameters the same way we have them in views.py
                    fit_param_enth = {"a": float(expdata["dH_max"][exp_index]),
                                      "b": float(expdata["dH_min"][exp_index]),
                                      "c": float(expdata["t"][exp_index]),
                                      "d": float(expdata["s"][exp_index])}
                    fit_type_entr = str(expdata["fit type entropy"][exp_index])
                    if fit_type_entr == "Dilute_Species":
                        fit_par_ent = {"a": float(expdata["entr_dil_s_v"][exp_index]),
                                          "b": float(expdata["entr_dil_a"][exp_index]),
                                          "c": float(expdata["delta_0"][exp_index])}
                    else:
                        fit_par_ent = {"a": float(expdata["entr_solid_sol_s"][exp_index]),
                                          "b": float(expdata["entr_solid_sol_shift"][exp_index]),
                                          "c": float(expdata["delta_0"][exp_index])}
                    theo_compstr = compstr
                    splitcomp = split_comp(compstr)
                    delta_0 = float(expdata["delta_0"][exp_index])
                    actf = find_active(mat_comp=splitcomp)[1]
                    act_mat = {"Material": float(actf)}
                    fit_param_fe = {"a": 231.062,
                                      "b": -24.3338,
                                      "c": 0.839785,
                                      "d": 0.219157}
                    pars = { "fit_par_ent": fit_par_ent,
                            "fit_param_enth": fit_param_enth,
                            "fit_type_entr": fit_type_entr,
                            "delta_0": delta_0,
                            "fit_param_fe": fit_param_fe,
                            "act_mat": act_mat
                            }

                    args_1 = (pd.np.log(p_ox), temp_1_corr, pars, s_th_o(temp_1_corr))
                    args_2 = (pd.np.log(p_red), temp_2_corr, pars, s_th_o(temp_2_corr))
                    delta_1 = rootfind(1e-10, 0.5-1e-10, args_1, funciso)
                    delta_2 = rootfind(1e-10, 0.5-1e-10, args_2, funciso)

                    # use theoretical elastic tensors
                    sampledata = views.get_theo_data()
                    for z in range(len(sampledata["compstr"])):
                        if (sampledata["compstr"][z]).split("O3")[0] == compstr.split("Ox")[0]:
                            index_debye = z
                    t_d_perov = float(sampledata["Debye temp perovskite"][index_debye])
                    t_d_brownm = float(sampledata["Debye temp brownmillerite"][index_debye])
                else:
                    # if composition does not contain ones as stoichiometries, add them
                    sample = add_comp_one(compstr=sample)
                    if not from_file or si_first != -1:
                        try:
                            red_active = redenth_act(sample)
                        except TypeError:
                            raise ValueError("Enthalpy data not available for this material.")
                        h_min = red_active[1]
                        h_max = red_active[2]
                        act = red_active[3]
                    else:
                        h_min = float(sampledata["dH_min"][i])
                        h_max = float(sampledata["dH_max"][i])
                        act = float(sampledata["act"][i])
                    compstr = sample
                    compstr_x = compstr.split("O")[0]

                    if not from_file or si_first != -1:
                        try: # get Debye temperatures for vibrational entropy
                            mp_ids = get_mpids_comps_perov_brownm(compstr=compstr)
                            t_d_perov = get_debye_temp(mp_ids[0])
                            t_d_brownm = get_debye_temp(mp_ids[1])
                        except Exception as e: # if no elastic tensors or no data for this material is available
                            mp_ids = ("mp-510624", "mp-561589") # using data for SrFeOx if no data is available (close approximation)
                            t_d_perov = get_debye_temp(mp_ids[0])
                            t_d_brownm = get_debye_temp(mp_ids[1])
                    else:
                        t_d_perov = float(sampledata["Debye temp perovskite"][i])
                        t_d_brownm = float(sampledata["Debye temp brownmillerite"][i])

                    args_theo_1 = (pd.np.log(p_ox), temp_1_corr, None, t_d_perov, t_d_brownm, h_min, h_max, act)
                    delta_1 = rootfind(1e-10, 0.5-1e-10, args_theo_1, funciso_theo)
                    args_theo_2 = (pd.np.log(p_red), temp_2_corr, None, t_d_perov, t_d_brownm, h_min, h_max, act)
                    delta_2 = rootfind(1e-10, 0.5-1e-10, args_theo_2, funciso_theo)

                # calculate the mass change in %
                comp_ox = compstr_x + "O" + str(float(3 - delta_1))
                comp_red = compstr_x + "O" + str(float(3 - delta_2))
                mol_mass_ox = float(Composition(comp_ox).weight)
                mol_mass_red = float(Composition(comp_red).weight)
                mass_redox_i = ((mol_mass_ox - mol_mass_red) / mol_mass_ox) * 100

                # define reaction products
                if self.process == "Air Separation":
                    prodstr = "O2"
                    prodstr_alt = "O"
                elif self.process == "Water Splitting":
                    prodstr = "H2"
                    prodstr_alt = prodstr
                elif self.process == "CO2 Splitting":
                    prodstr = "CO"
                    prodstr_alt = prodstr
                else:
                    raise ValueError("Process must be either Air Separation, Water Splitting, or CO2 Splitting!")

                # only continue if the user-designated reduction step actually leads to reduction
                # if not, set result to infinite
                if delta_2 < delta_1:
                    ener_i = pd.np.ones(5) * float('inf')
                    per_kg_redox = pd.np.ones(5) * float('inf')
                    per_kg_wh_redox = pd.np.ones(5) * float('inf')
                    kj_mol_prod = pd.np.ones(5) * float('inf')
                    energy_l = pd.np.ones(5) * float('inf')
                    energy_l_wh = pd.np.ones(5) * float('inf')
                    efficiency = float('inf')
                    mol_prod_mol_red = float('inf')
                    l_prod_kg_red = float('inf')
                    g_prod_kg_red = float('inf')

                else:
                    # mol product per mol of redox material
                    mol_prod_mol_red = delta_2 - delta_1
                    # L product per kg of redox material (SATP)
                    l_prod_kg_red = mol_prod_mol_red * (24.465 / (0.001 * mol_mass_ox))
                    # convert mol O to mol O2
                    if self.process == "Air Separation":
                        l_prod_kg_red = l_prod_kg_red * 0.5
                    # g product per kg redox material
                    g_prod_kg_red = float(Composition(prodstr).weight) * (l_prod_kg_red / 24.465)

                    if data_origin == "Exp":
                        d_delta = delta_0
                    else:
                        d_delta = 0.0
                    # correct for d_delta
                    d_delta_1 = delta_1 - d_delta
                    d_delta_2 = delta_2 - d_delta

                    # chemical energy
                    if data_origin == "Exp":
                        s_th_mean = (s_th_o(temp_1_corr) + s_th_o(temp_1_corr)) / 2
                        def dh_func_exp(d_delta_func):
                            return dh_ds(d_delta_func, s_th_mean, pars)[0]
                        energy_integral_dh = quad(dh_func_exp, d_delta_1, d_delta_2)[0]
                        if energy_integral_dh < 0:
                            raise ValueError("negative chemical energy due to insuffiencent experimental data...skipping this sample")
                    else:
                        energy_integral_dh = EnergyAnalysis(process=self.process).energy_integral_theo(
                             celsius=celsius, compstr=compstr, dh_max=h_max,
                            dh_min=h_min, enth_steps=enth_steps, p_o_2_1=p_ox, p_o_2_2=p_red, temp_1=t_ox, temp_2=t_red,
                            t_d_perov=t_d_perov, t_d_brownm = t_d_brownm)

                    # sensible energy
                    energy_sensible = 0
                    if heat_cap:
                        energy_sensible = EnergyAnalysis().heat_input_linear(temp_1=temp_1_corr, temp_2=temp_2_corr, delta_1=delta_1,
                            delta_2=delta_2, t_d_perov=t_d_perov, t_d_brownm=t_d_brownm, num=40) / 1000

                chemical_energy_l.append(energy_integral_dh)
                sensible_energy_l.append(energy_sensible)
                mol_mass_ox_l.append(mol_mass_ox)
                mol_prod_mol_red_l.append(mol_prod_mol_red)
                t_ox_l.append(temp_1_corr)
                t_red_l.append(temp_2_corr)
                p_ox_l.append(p_ox)
                p_red_l.append(p_red)
                compstr_l.append(compstr)
                delta_1_l.append(delta_1)
                delta_2_l.append(delta_2)
                mass_redox_l.append(mass_redox_i)
                prodstr_l.append(prodstr)
                prodstr_alt_l.append(prodstr_alt)
                l_prod_kg_red_l.append(l_prod_kg_red)
                g_prod_kg_red_l.append(g_prod_kg_red)

            # skip this sample if the sample number does not exist
            except Exception as e:
                pass
                #print("No data for sample " + str(sample) + " found!" + str(e))
            sample = None

        resdict = { "Chemical Energy": chemical_energy_l,
                    "Sensible Energy": sensible_energy_l,
                    "mol_mass_ox": mol_mass_ox_l,
                    "mol_prod_mol_red": mol_prod_mol_red_l,
                    "T_ox": t_ox_l,
                    "T_red": t_red_l,
                    "p_ox": p_ox_l,
                    "p_red": p_red_l,
                    "compstr": compstr_l,
                    "delta_1": delta_1_l,
                    "delta_2": delta_2_l,
                    "mass_redox": mass_redox_l,
                    "prodstr": prodstr_l,
                    "prodstr_alt": prodstr_alt_l,
                    "l_prod_kg_red": l_prod_kg_red_l,
                    "g_prod_kg_red": g_prod_kg_red_l}
        return resdict
Example #7
0
def ellingham(request, cid, db_type=None, mdb=None):
    try:
        pars, _, _, response, payload, x_val = init_isographs(request=request, db_type=db_type, cid=cid, mdb=mdb)
        iso = pd.np.log(10**payload['iso'])
        delt =  float(payload['del'])

        resiso, resiso_theo, ellingiso = [], [], []
        if pars['experimental_data_available']:     # only execute this if experimental data is available
            for xv in x_val:                # calculate experimental data
                try:
                    s_th = s_th_o(xv)
                    args = (iso, xv, pars, s_th)
                    solutioniso = (dh_ds(delt, args[-1], args[-2])[0] - dh_ds(delt, args[-1], args[-2])[1]*xv)/1000
                    resiso.append(solutioniso)
                    ellingiso_i = isobar_line_elling(args[0], xv)/1000
                    ellingiso.append(ellingiso_i)
                except ValueError:          # if brentq function finds no zero point due to plot out of range
                    resiso.append(None)

            res_interp, res_fit = [], []
            for delta_val, res_i in zip(x_val, resiso):    # show interpolation
                if pars['delta_min'] < delta_val < pars['delta_max']:   # result within experimentally covered delta range
                    res_fit.append(res_i)
                    res_interp.append(None)
                else:                                   # result outside this range
                    res_fit.append(None)
                    res_interp.append(res_i)
        else:
            res_fit, res_interp = None, None    # don't plot any experimental data if it is not available

        try:                                # calculate theoretical data
            for xv in x_val[::4]: # use less data points for theoretical graphs to improve speed
                dh = d_h_num_dev_calc(delta=delt, dh_1=pars['dh_min'], dh_2=pars['dh_max'], temp=xv, act=pars["act_mat"])
                ds = d_s_fundamental(delta=delt, dh_1=pars['dh_min'], dh_2=pars['dh_max'], temp=xv,
                     act=pars["act_mat"], t_d_perov=pars['td_perov'], t_d_brownm=pars['td_brownm'])
                solutioniso_theo = (dh - ds*xv)/1000
                resiso_theo.append(solutioniso_theo)
        except ValueError: # if brentq function finds no zero point due to plot out of range
            resiso_theo.append(None)

        x = list(x_val)
        x_theo = x[::4]
        if pars['experimental_data_available']:
            x_exp = x
            response = [{'x': x_exp, 'y': res_fit, 'name': 'exp_fit', 'line': { 'color': 'rgb(5,103,166)', 'width': 2.5 }},
                    {'x': x_exp, 'y': res_interp, 'name': 'exp_interp', \
                    'line': { 'color': 'rgb(5,103,166)', 'width': 2.5, 'dash': 'dot' }},
                    {'x': x_theo, 'y': resiso_theo, 'name': 'theo', 'line': { 'color': 'rgb(217,64,41)', 'width': 2.5}},
                    {'x': x_exp, 'y': ellingiso, 'name': 'isobar line', 'line': { 'color': 'rgb(100,100,100)', 'width': 2.5}},\
                    [pars['compstr_disp'], pars['compstr_exp'], pars['tens_avail'], pars["last_updated"]]]

        else:
            x_exp = None
            for xv in x_theo:
                ellingiso_i = isobar_line_elling(iso, xv)/1000
                ellingiso.append(ellingiso_i)
            response = [{'x': x_exp, 'y': res_fit, 'name': 'exp_fit', 'line': { 'color': 'rgb(5,103,166)', 'width': 2.5 }},
            {'x': x_exp, 'y': res_interp, 'name': 'exp_interp', \
            'line': { 'color': 'rgb(5,103,166)', 'width': 2.5, 'dash': 'dot' }},
            {'x': x_theo, 'y': resiso_theo, 'name': 'theo', 'line': { 'color': 'rgb(217,64,41)', 'width': 2.5}},
            {'x': x_theo, 'y': ellingiso, 'name': 'isobar line', 'line': { 'color': 'rgb(100,100,100)', 'width': 2.5}},\
            [pars['compstr_disp'], pars['compstr_exp'], pars['tens_avail'], pars["last_updated"]]]

    except Exception as ex:
        raise ValueError('"REST Error: "{}"'.format(str(ex)))
    return {"valid_response": True, 'response': response}