Beispiel #1
0
def make_reactions(reactions, mol_energies):
    def energy_sum(keys):
        return {
            field: sum([getattr(mol_energies[k], field) for k in keys])
            for field in GFIELDS
        }

    rx_energies = dict()
    all_rx_energies = list()
    for rx_name, reagents in reactions.items():
        print(f"Calculating energies for reaction '{rx_name}'")
        pprint(reagents)
        educts = to_list(reagents["educts"])
        ts = [
            reagents["ts"],
        ]
        assert len(ts) == 1
        products = to_list(reagents["products"])
        add = reagents.get("add", [])
        add = [
            add,
        ] if isinstance(add, str) else list(add)

        educt_ens = energy_sum(educts + add)
        ts_ens = energy_sum(ts + add)
        product_ens = energy_sum(products + add)

        energies = {}
        for field in GFIELDS:
            ens = np.array(
                [dct[field] for dct in (educt_ens, ts_ens, product_ens)])
            energies[field] = ens

        rx_energies[rx_name] = energies
    return rx_energies
Beispiel #2
0
def get_reactants(rx):
    reactants = list()
    for key in ("educts", "ts", "products"):
        reactants.append(to_list(rx[key]))
    # 'add' may not be present so we have to handle it separately
    reactants.append(to_list(rx.get("add", [])))
    return reactants
Beispiel #3
0
 def __init__(self, name, educts, ts, products, energies=None, k=None,
              add=None, label=None):
     self.name = name
     self.educts = to_list(educts)
     self.ts = to_list(ts)
     self.products = to_list(products)
     self.energies = energies
     self.k = k
Beispiel #4
0
def make_dash_data(reactions, thermos, thermochem_df):

    unique_Ts = thermochem_df["T"].unique()

    def sum_(keys, field):
        return sum([getattr(thermos[k], field) for k in keys])

    df_cols = "name reactant single_point single_point_alt dG_solv T dG".split(
    )
    rows = list()
    for rx_name, reagents in reactions.items():
        add = reagents.get("add", [])
        add = [
            add,
        ] if isinstance(add, str) else list(add)
        for reactant in ("educts", "ts", "products"):
            reactants = to_list(reagents[reactant])
            if isinstance(reactants, str):
                reactants = [
                    reactants,
                ]
            reactants = reactants + add
            sp = sum_(reactants, "single_point")

            reactant_thermo = thermochem_df[thermochem_df["name"].isin(
                reactants)]
            dGs = reactant_thermo.groupby("T").dG.sum().to_list()

            sp_alt = sum_(reactants, "single_point_alt")
            dG_solv = sum_(reactants, "dG_solv")
            for T, dG in zip(unique_Ts, dGs):
                row = [rx_name, reactant, sp, sp_alt, dG_solv, T, dG]
                rows.append(row)
    df = pd.DataFrame(rows, columns=df_cols)
    return df
Beispiel #5
0
def run():
    args = parse_args(sys.argv[1:])

    no_alt = args.no_alt
    show_rxs = not args.norxs
    show_paths = not args.nopaths
    temperature = args.T

    if args.quick:
        show_paths = False
        educts, ts, products = [
            reactants.split(",") for reactants in args.quick.split(";")
        ]
        assert len(ts) == 1
        ed_keys = [f"ed{i}" for i in range(len(educts))]
        prod_keys = [f"prod{i}" for i in range(len(products))]

        inp_dict = {
            "molecules": dict(),
            "program": "orca",
        }

        def add_mols(keys, fns):
            for key, fn in zip(keys, fns):
                inp_dict["molecules"][key] = {
                    "freq": fn,
                }

        add_mols(ed_keys, educts)
        add_mols([
            "ts",
        ], ts)
        add_mols(prod_keys, products)

        # Dummy reaction
        inp_dict["reactions"] = {
            "quick": {
                "educts": ed_keys,
                "ts": "ts",
                "products": prod_keys,
            }
        }
    elif args.yaml:
        with open(args.yaml) as handle:
            inp_dict = yaml.load(handle)
    else:
        print(
            "Specify either a YAML file or use --quick! See also 'plotprofile --help'"
        )
        sys.exit()

    reactions = inp_dict["reactions"]

    if args.interactive:
        rx_keys = list(reactions.keys())
        for i, rx in enumerate(rx_keys):
            print(f"{i:02d}: {rx}")
        ind = int(input("Show reaction: ", ))
        rx_key = rx_keys[ind]
        reaction = reactions[rx_key]
        reactions = {
            rx_key: reaction,
        }
        # Modify molecules so only the ones actually needed are loaded
        rx_molecules = list(
            it.chain(*[to_list(mols) for mols in reaction.values()]))
        inp_dict["molecules"] = {
            key: val
            for key, val in inp_dict["molecules"].items()
            if key in rx_molecules
        }

    molecules = inp_dict["molecules"]
    thermos = load_thermos(molecules, inp_dict["program"])
    mol_energies = load_molecule_energies(thermos, no_alt=no_alt)

    rx_strs = {rx_name: rx_to_string(rx) for rx_name, rx in reactions.items()}

    if args.parsedash:
        freq_logs = {k: v["freq"] for k, v in inp_dict["molecules"].items()}
        qc_datas = {k: QCData(v) for k, v in freq_logs.items()}
        temps = np.arange(298.00, 373.00, 5)
        rows = list()
        for mol_name, temp in it.product(qc_datas, temps):
            qc = qc_datas[mol_name]
            tc = thermochemistry(qc, temp)
            row = [
                mol_name,
            ] + list(tc)
            rows.append(row)
        cols = [
            "name",
        ] + list(tc._fields)
        df = pd.DataFrame(rows, columns=cols)
        df.to_pickle("thermochem_data")
        thermochem_df = pd.read_pickle("thermochem_data")
        df = make_dash_data(inp_dict["reactions"], thermos, thermochem_df)
        df.to_pickle("dash_data")

    print()
    print("Using these G-values:")
    for key, val in mol_energies.items():
        print(key)
        pprint(val._asdict())
    print()

    rx_energies = make_reactions(reactions, mol_energies)

    paths = inp_dict.get("paths", None)
    if paths is None:
        print("Found no defined paths in .yaml file. Using all defined "
              "reactions instead.")
        paths = {"autogenerated": list(reactions.keys())}
    if args.interactive:
        paths = dict()

    print_path_rx_energies(paths, rx_energies, rx_strs, temperature)
    dump_energies(rx_energies)

    mol_labels = {
        # Use molecule key as fallback if no label is defined
        mol: values.get("label", mol)
        for mol, values in molecules.items()
    }
    rx_labels = {}
    rx_titles = {}
    # Create label strings for plotting
    for rx_name in reactions:
        labels = [
            v for k, v in reactions[rx_name].items()
            if k in ("educts", "ts", "products")
        ]

        pretty_labels = list()
        for lbl in labels:
            if isinstance(lbl, str):
                lbl = [
                    lbl,
                ]
            # Replace with pretty labels
            lbl = [mol_labels[mol] for mol in lbl]
            lbl = ",\n".join(lbl)
            pretty_labels.append(lbl)
        rx_labels[rx_name] = pretty_labels

        rx_title = reactions[rx_name].get("label", rx_name)
        rx_titles[rx_name] = rx_title

    # Try to use the 'best' energies for plotting. That is with alternative
    # single point and solvation.
    best_rx_energies = {
        rx_name: rx_energies[rx_name]["G_solv_alt"]
        for rx_name in rx_labels
    }

    if show_rxs:
        plot_reactions(best_rx_energies, rx_labels, rx_titles, temperature)
    else:
        print("Skipped plotting of reactions!")

    if show_paths and not args.interactive and (len(best_rx_energies) > 1):
        plot_paths(best_rx_energies, paths, rx_labels, rx_titles)
    else:
        print("Skipped plotting of reaction paths!")

    path_reactions = set(list(it.chain(*paths.values())))
    all_reactions = set(list(reactions.keys()))
    remainder = all_reactions - path_reactions
    if len(remainder) > 0:
        print()
        print("Warning!".upper())
        print("Not all defined reactions appeared in (defined) paths!")
        for i, rx in enumerate(remainder):
            print(f"\t{i:02d}: {rx}")
        print("Warning!".upper())
        print()

        remainder_path = {
            "remainder": remainder,
        }
        print_path_rx_energies(remainder_path, rx_energies, rx_strs,
                               temperature)

    to_compare = inp_dict.get("compare", dict())
    compare_molecules(to_compare, mol_energies)
    # compare_molecules(to_compare, mol_energies, attr="G_gas_alt")

    # Kinetics
    if "kinetics" in inp_dict:
        kin_dict = inp_dict["kinetics"]
        kin_reactions = kin_dict.get("only", reactions.keys())

        reaction_objs = list()
        for rx_name in kin_reactions:
            reactants = reactions[rx_name]
            educts = reactants["educts"]
            ts = reactants["ts"]
            products = reactants["products"]
            energies = rx_energies[rx_name]
            frx = Reaction(rx_name, educts, ts, products, energies)
            brx = frx.get_back_reaction()
            reaction_objs.extend((frx, brx))
        c0s = kin_dict["c0s"]
        t_span = kin_dict["t_span"]

        mols, res = kinetics(reaction_objs, c0s, t_span=t_span)
        plot_kinetics(mols, res)