File size: 6,002 Bytes
ef53368
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
"""SI Figure S2: literature Diels-Alder barriers for ethylene + butadiene.

Published quantum-chemistry predictions span ~15-45 kcal/mol (experiment ~23.3). The barriers are a
literature compilation (paper reference 26); the table below is the data (no dataset/reader). This
file holds the table and its method-family grouping; the bar chart is drawn inline in the notebook.
"""
# experimental activation barrier for the ethylene + butadiene Diels-Alder reaction, kcal/mol
EXPERIMENTAL_BARRIER = 23.3

# (method // geometry, predicted barrier in kcal/mol), compiled from the literature (reference 26).
# The label before "//" is the energy method; it sets the bar's group and label.
DATA = [
    ("HF/3-21G//HF/3-21G", 35.9),
    ("HF/6-31G*//HF/6-31G*", 45.0),
    ("HF/6-31G**//HF/6-31G**", 45.9),
    ("CASSCF(6,6)/3-21G// CASSCF(6,6)/3-21G", 37.3),
    ("CASSCF(6,6)/6-31G*//B3LYP/6-31G*", 43.8),
    ("MRMP2-CAS(6,6)/6-31G*//B3LYP/6-31G*", 28.6),
    ("CASSCF(6,6)/6-31G*// CASSCF(6,6)/6-31G*", 43.8),
    ("CASSCF(6,6)/6-31G(d,p)//CASSCF(6,6)/6-31(d,p)", 44.5),
    ("CASSCF(6,6)-MP2/6-31G(d,p)//CASSCF(6,6)/6-31(d,p)", 39.4),
    ("CASSCF(6,6)/6-311+G(d,p)//CASSCF(6,6)/6-31(d,p)", 37.0),
    ("CASSCF(6,6)-MP2/6-311+G(d,p)//CASSCF(6,6)/6-31(d,p)", 40.9),
    ("CASSCF(6,6)/6-31G*//CASSCF(6,6)/6-31G*", 25.0),
    ("CASSCF(6,6)/6-31G*//CASSCF(6,6)/6-31G*", 43.6),
    ("MR-AQCC/6-31G*//MR-AQCC/6-31G*", 25.7),
    ("MR-AQCC/6-31G**//MR-AQCC/6-31G**", 25.3),
    ("MR-AQCC/6-31G**//MR-AQCC/6-31G**", 24.2),
    ("MR-AQCC/6-311G(2d,p)//MR-AQCC/6-311G(2d,p)", 23.7),
    ("MP2/6-31G*//HF/6-31G*", 16.6),
    ("MP2/6-31G*//MP2/6-31G*", 18.5),
    ("MP2/6-31G*//B3LYP/6-31G*", 20.4),
    ("MP2/6-31G**//MP2/6-31G**", 15.9),
    ("MP2/6-311G(d,p)//B3LYP/6-31G", 17.5),
    ("MP3/6-31G*//HF/6-31G*", 26.9),
    ("MP3/6-311G(d,p)//B3LYP/6-31G", 28.2),
    ("MP4(SDQ)/6-31G*//HF/6-31G*", 29.0),
    ("MP4(SDTQ)/6-31G*//HF/6-31G*", 21.9),
    ("MP4(SDTQ)/6-31G*//MP2/6-31G*", 22.4),
    ("MP4(SDTQ)/6-311G(d,p)//B3LYP/6-31G", 22.8),
    ("B3LYP/6-31G*//B3LYP/6-31G*", 23.1),
    ("B3LYP/6-31G*//B3LYP/6-31G*", 24.9),
    ("B3LYP/6-31G**//B3LYP/6-31G**", 22.4),
    ("B3LYP/6-311+G(2d,p)//B3LYP/6-311+G(2d,p)", 27.2),
    ("BPW91/6-31G*//BPW91/6-31G*", 26.2),
    ("MPW1K/6-31+G**//MPW1K/6-31+G*", 24.4),
    ("KMLYP/6-31G*//KMLYP/6-31G*", 21.1),
    ("KMLYP/6-311G//KMLYP/6-31G", 22.4),
    ("OLYP/6-31G(d)//OLYP/6-31G(d)", 26.7),
    ("OLYP/6-311+G(2d,p)//OLYP/6-311+G(2d,p)", 30.1),
    ("OLYP/6-311G(2df,2pd)// OLYP/6-311G(2df,2pd)", 29.2),
    ("O3LYP/6-31G(d)//OLYP/6-31G(d)", 26.8),
    ("O3LYP/6-311+G(2d,p)//OLYP/6-311+G(2d,p)", 30.1),
    ("O3LYP/6-311G(2df,2pd)// OLYP/6-311G(2df,2pd)", 29.3),
    ("M06-2x/6-31G(d)", 20.4),
    ("M06-2x/cc-pVTZ", 23.2),
    ("ωB97X-D/6-31G(d)", 21.7),
    ("ωB97X-D/cc-pVTZ", 25.1),
    ("B2PLYP/cc-pVDZ", 24.0),
    ("QCISD(T)/6-31G*//CASSCF(6,6)/6-31G*", 25.5),
    ("QCISD(T)/6-31G*//B3LYP/6-31G*", 25.0),
    ("CCSD/6-311G(d,p)//B3LYP/6-31G", 30.8),
    ("CCSD(T)/6-311G(d,p)//B3LYP/6-31G", 25.7),
    ("CCSD(T)/6-31G**//B3LYP/6-31G**", 27.6),
    ("G2MP2/6-311+G(3df,2p)", 24.6),
    ("G2MS/6-311+G(2df,2p)", 23.9),
    ("CBS-QB3", 22.9),
]

# the method-family groups, in the left-to-right order the figure lays them out
CATEGORY_ORDER = ["HF", "MP2", "MP3", "MP4", "DFT", "CASSCF",
                  "Multireference", "Coupled Cluster", "Composite"]


def energy_method(method_string):
    """The energy method (the part before '//') of a 'method//geometry' string. This is what the
    bar is labeled with and categorized by; a string with no '//' is returned unchanged."""
    return method_string.split("//")[0].strip() if "//" in method_string else method_string


def categorize_method(method):
    """The method family ('HF', 'MP2', 'DFT', 'CASSCF', ...) of an energy method, by the same rules
    as the original figure. Used to group the bars."""
    m = method.upper()
    if m.startswith("HF"):
        return "HF"
    if m.startswith("MP2"):
        return "MP2"
    if m.startswith("MP3"):
        return "MP3"
    if m.startswith("MP4"):
        return "MP4"
    if any(k in m for k in ("B3LYP", "BPW91", "MPW1K", "KMLYP", "OLYP", "O3LYP", "M06",
                            "ωB97X", "B2PLYP")):
        return "DFT"
    if "CASSCF" in m:
        return "CASSCF"
    if "CCSD" in m or "QCISD" in m:
        return "Coupled Cluster"
    if m.startswith("G2") or "CBS" in m:
        return "Composite"
    if "MR-AQCC" in m or "MRMP2" in m:
        return "Multireference"
    return "Other"


def ordered_layout(data=DATA, group_spacing=2):
    """Lay the bars out grouped by method family and sorted by barrier within each group, with a gap
    of group_spacing between groups. Returns a dict with parallel lists methods (the energy-method
    labels), energies, positions (x of each bar), and group_labels / group_boundaries (the
    (start, end) bar position of each group), in CATEGORY_ORDER.
    """
    grouped = {}
    for method_string, energy in data:
        method = energy_method(method_string)
        grouped.setdefault(categorize_method(method), []).append((method, energy))
    for entries in grouped.values():
        entries.sort(key=lambda me: me[1])

    methods, energies, positions = [], [], []
    group_labels, group_boundaries = [], []
    pos = 0
    for i, category in enumerate(CATEGORY_ORDER):
        if category not in grouped:
            continue
        if i > 0 and methods:   # gap before each group after the first present one
            pos += group_spacing
        start = pos
        for method, energy in grouped[category]:
            methods.append(method)
            energies.append(energy)
            positions.append(pos)
            pos += 1
        group_labels.append(category)
        group_boundaries.append((start, pos - 1))
    return {"methods": methods, "energies": energies, "positions": positions,
            "group_labels": group_labels, "group_boundaries": group_boundaries}