View difference between Paste ID: NCyqGiWd and xxDUs1rs
SHOW: | | - or go back to the newest paste.
1
import numpy as np
2
import matplotlib.pyplot as plt
3
from matplotlib import cm
4
from tqdm import tqdm
5
import os
6
from scipy.integrate import solve_ivp
7
8
# Parameters
9
SM = 0.0
10-
INT = 5.0
10+
INT = 10.0
11
PROD = -2.0
12
13
TS1_values = np.linspace(5, 30, 40)
14-
TS2_values = np.linspace(5, 40, 40)
14+
TS2_values = np.linspace(5, 30, 40)
15
16
R = 8.314e-3
17
T = 298.0
18
RT = R * T
19
A = 1.0
20
21
# ODE system
22
def reaction_odes(t, y, k1f, k1r, k2f, k2r):
23
    SM_conc, INT_conc, PROD_conc = y
24
    dSMdt = -k1f * SM_conc + k1r * INT_conc
25
    dINTdt = k1f * SM_conc - k1r * INT_conc - k2f * INT_conc + k2r * PROD_conc
26
    dPRODdt = k2f * INT_conc - k2r * PROD_conc
27
    return [dSMdt, dINTdt, dPRODdt]
28
29
y0 = [1.0, 0.0, 0.0]
30
t_span = (0, 1000.0)
31
t_eval = [1000.0]
32
33
TS1_grid, TS2_grid = np.meshgrid(TS1_values, TS2_values)
34
rate_grid = np.zeros_like(TS1_grid)
35
36
# Calculate rates
37
for i in tqdm(range(len(TS2_values)), desc="Rows"):
38
    for j in range(len(TS1_values)):
39
        TS1_val = TS1_grid[i, j]
40
        TS2_val = TS2_grid[i, j]
41
42-
        if (TS1_val >= 5) and (TS2_val >= 5) and ((TS2_val - INT) < (TS1_val - SM)):
42+
        if (TS1_val >= 10) and (TS2_val >= 10)  and ((TS1_val - SM) > (TS2_val - INT)) and (TS2_val > TS1_val):
43
            k1f = A * np.exp(-(TS1_val - SM) / RT)
44
            k1r = A * np.exp(-(TS1_val - INT) / RT)
45
            k2f = A * np.exp(-(TS2_val - INT) / RT)
46
            k2r = A * np.exp(-(TS2_val - PROD) / RT)
47
48
            sol = solve_ivp(reaction_odes, t_span, y0, t_eval=t_eval, args=(k1f, k1r, k2f, k2r))
49
            if sol.success:
50
                SM_final, INT_final, PROD_final = sol.y[:, -1]
51
                rate = (k2f * INT_final) - (k2r * PROD_final)
52
            else:
53
                rate = np.nan
54
        else:
55
            rate = np.nan
56
57
        rate_grid[i, j] = rate
58
59
# Stats
60
valid_rates = rate_grid[~np.isnan(rate_grid)]
61
mean_rate = np.mean(valid_rates) if valid_rates.size > 0 else np.nan
62
std_rate = np.std(valid_rates) if valid_rates.size > 0 else np.nan
63
max_rate = np.nanmax(rate_grid)
64
min_rate = np.nanmin(rate_grid)
65
66
print("Summary Statistics:")
67
print(f"Mean rate: {mean_rate:.4e}")
68
print(f"Std dev of rate: {std_rate:.4e}")
69
print(f"Max rate: {max_rate:.4e}")
70
print(f"Min rate: {min_rate:.4e}")
71
72
# Calculate intersection line where TS1 = TS2
73
intersection_mask = np.isclose(TS1_grid, TS2_grid)
74
intersection_TS1 = TS1_grid[intersection_mask]
75
intersection_TS2 = TS2_grid[intersection_mask]
76
intersection_rates = rate_grid[intersection_mask]
77
78
# Plot
79
fig = plt.figure(figsize=(10, 7))
80
ax = fig.add_subplot(111, projection='3d')
81
82
masked_rate = np.ma.masked_invalid(rate_grid)
83
84
# Plot the main surface
85
surf = ax.plot_surface(TS1_grid, TS2_grid, masked_rate, cmap=cm.viridis, edgecolor='none')
86
87
# Add color bar
88
fig.colorbar(surf, shrink=0.5, aspect=5)
89
90
# Labels and title
91-
output_path = "3d_rate_plot_odes_reversible.png"
91+
ax.set_zlim(0, max_rate)
92
ax.set_xlabel('TS1 Free Energy')
93
ax.set_ylabel('TS2 Free Energy')
94
ax.set_zlabel('Net Rate')
95
ax.set_title('Rate Dependence (Assuming A=1)')
96
97
# Add legend
98
ax.legend()
99
100
# Invert axes
101
ax.invert_xaxis()
102
ax.invert_yaxis()
103
104
# Set view angle
105
ax.view_init(elev=30, azim=210)
106
107
plt.tight_layout()
108
109
# Save and show plot
110
output_path = "3d_rate_plot_odes_intersection_line.png"
111
plt.savefig(output_path, dpi=300)
112
print(f"Plot saved as {os.path.abspath(output_path)}")
113
114
plt.show()
115