Skip to content

Commit 285b88a

Browse files
authored
Merge pull request #96 from sgbaird:ll-extraction
ll extraction
2 parents aaa9807 + 1f325ef commit 285b88a

File tree

1 file changed

+243
-0
lines changed

1 file changed

+243
-0
lines changed
Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
# Solvent Extraction Optimization Script
2+
# %pip install ax-platform matplotlib
3+
import matplotlib.pyplot as plt
4+
import pandas as pd
5+
from ax.service.ax_client import AxClient, ObjectiveProperties
6+
7+
# Define the training data with proper solvent extraction parameters and results
8+
# fmt: off
9+
training_data = [
10+
# Example 1
11+
{
12+
"parameters": {
13+
"aqueous_composition": 0.6,
14+
"organic_composition": 0.4,
15+
"stirring_speed": 300,
16+
"stirring_time": 60,
17+
"temperature": 25,
18+
},
19+
"results": {
20+
"recovery": 75.2,
21+
"purity": 92.5,
22+
"separation": 85.3,
23+
"emulsion": 12.4,
24+
"total_time": 850,
25+
},
26+
},
27+
# Example 2
28+
{
29+
"parameters": {
30+
"aqueous_composition": 0.3,
31+
"organic_composition": 0.7,
32+
"stirring_speed": 400,
33+
"stirring_time": 90,
34+
"temperature": 30,
35+
},
36+
"results": {
37+
"recovery": 82.1,
38+
"purity": 88.7,
39+
"separation": 76.8,
40+
"emulsion": 25.3,
41+
"total_time": 1050,
42+
},
43+
},
44+
# Example 3
45+
{
46+
"parameters": {
47+
"aqueous_composition": 0.8,
48+
"organic_composition": 0.2,
49+
"stirring_speed": 250,
50+
"stirring_time": 45,
51+
"temperature": 15,
52+
},
53+
"results": {
54+
"recovery": 65.8,
55+
"purity": 95.2,
56+
"separation": 93.1,
57+
"emulsion": 8.5,
58+
"total_time": 720,
59+
},
60+
},
61+
# Example 4
62+
{
63+
"parameters": {
64+
"aqueous_composition": 0.5,
65+
"organic_composition": 0.5,
66+
"stirring_speed": 350,
67+
"stirring_time": 75,
68+
"temperature": 20,
69+
},
70+
"results": {
71+
"recovery": 78.4,
72+
"purity": 91.8,
73+
"separation": 81.5,
74+
"emulsion": 15.2,
75+
"total_time": 920,
76+
},
77+
},
78+
# Example 5
79+
{
80+
"parameters": {
81+
"aqueous_composition": 0.7,
82+
"organic_composition": 0.3,
83+
"stirring_speed": 200,
84+
"stirring_time": 30,
85+
"temperature": 10,
86+
},
87+
"results": {
88+
"recovery": 69.3,
89+
"purity": 93.6,
90+
"separation": 88.7,
91+
"emulsion": 10.8,
92+
"total_time": 780,
93+
},
94+
},
95+
]
96+
# fmt: on
97+
98+
# Extract X_train and y_train from the combined training data
99+
X_train = pd.DataFrame([example["parameters"] for example in training_data])
100+
y_train = [example["results"] for example in training_data]
101+
102+
# Define the number of training examples
103+
n_train = len(X_train)
104+
105+
assert n_train == len(y_train), "Mismatch between X_train and y_train lengths"
106+
107+
# Initialize Ax client for multi-objective optimization
108+
ax_client = AxClient()
109+
110+
# Define parameters and objectives
111+
ax_client.create_experiment(
112+
parameters=[
113+
{"name": "aqueous_composition", "type": "range", "bounds": [0.0, 1.0]},
114+
{"name": "stirring_speed", "type": "range", "bounds": [100, 500]},
115+
{"name": "stirring_time", "type": "range", "bounds": [10, 120]},
116+
{"name": "temperature", "type": "range", "bounds": [4, 40]},
117+
],
118+
objectives={
119+
"recovery": ObjectiveProperties(minimize=False, threshold=50.0),
120+
"purity": ObjectiveProperties(minimize=False, threshold=90.0),
121+
"separation": ObjectiveProperties(minimize=False),
122+
"emulsion": ObjectiveProperties(minimize=True),
123+
"total_time": ObjectiveProperties(minimize=True, threshold=1200.0),
124+
},
125+
parameter_constraints=[
126+
# No need for an explicit constraint on aqueous + organic since organic
127+
# is derived
128+
],
129+
)
130+
131+
# Add existing data to the AxClient
132+
for i in range(n_train):
133+
parameterization = X_train.iloc[i].to_dict()
134+
135+
# remove organic, since it's hidden from search space due to composition constraint
136+
parameterization.pop("organic_composition")
137+
138+
ax_client.attach_trial(parameterization)
139+
ax_client.complete_trial(trial_index=i, raw_data=y_train[i])
140+
141+
142+
parameterization, trial_index = ax_client.get_next_trial()
143+
144+
# Extract parameters
145+
aqueous_composition = parameterization["aqueous_composition"]
146+
organic_composition = 1.0 - aqueous_composition # Enforce composition constraint
147+
stirring_speed = parameterization["stirring_speed"]
148+
stirring_time = parameterization["stirring_time"]
149+
temperature = parameterization["temperature"]
150+
151+
print(f"Trial {trial_index}:")
152+
print(f"Aqueous Composition: {aqueous_composition}")
153+
print(f"Organic Composition: {organic_composition}")
154+
print(f"Stirring Speed: {stirring_speed}")
155+
print(f"Stirring Time: {stirring_time}")
156+
print(f"Temperature: {temperature}")
157+
158+
# # Run evaluation
159+
# results = evaluate_extraction(
160+
# aqueous_composition,
161+
# organic_composition,
162+
# stirring_speed,
163+
# stirring_time,
164+
# temperature,
165+
# )
166+
167+
# # Report results
168+
# ax_client.complete_trial(trial_index=trial_index, raw_data=results)
169+
170+
if n_train > 0:
171+
172+
# Get results
173+
df = ax_client.get_trials_data_frame()
174+
print("\nResults summary:")
175+
print(df)
176+
177+
# Plot results
178+
objectives = ax_client.objective_names
179+
180+
pareto = ax_client.get_pareto_optimal_parameters(use_model_predictions=False)
181+
pareto_data = [p[1][0] for p in pareto.values()]
182+
pareto = pd.DataFrame(pareto_data).sort_values(objectives[0])
183+
184+
# Plot recovery vs purity
185+
plt.figure(figsize=(10, 8))
186+
187+
# Recovery vs Purity
188+
plt.subplot(2, 2, 1)
189+
plt.scatter(df["recovery"], df["purity"], c=df["total_time"], cmap="viridis")
190+
plt.colorbar(label="Total Time (s)")
191+
plt.xlabel("Recovery (%)")
192+
plt.ylabel("Purity (%)")
193+
plt.axhline(y=90, color="r", linestyle="--", alpha=0.5) # Purity threshold
194+
plt.axvline(x=50, color="r", linestyle="--", alpha=0.5) # Recovery threshold
195+
196+
# Separation vs Emulsion
197+
plt.subplot(2, 2, 2)
198+
plt.scatter(df["separation"], df["emulsion"], c=df["total_time"], cmap="viridis")
199+
plt.colorbar(label="Total Time (s)")
200+
plt.xlabel("Separation (%)")
201+
plt.ylabel("Emulsion (%)")
202+
203+
# Temperature vs Stirring Speed
204+
plt.subplot(2, 2, 3)
205+
sc = plt.scatter(
206+
df["temperature"], df["stirring_speed"], c=df["recovery"], cmap="plasma"
207+
)
208+
plt.colorbar(sc, label="Recovery (%)")
209+
plt.xlabel("Temperature (°C)")
210+
plt.ylabel("Stirring Speed (rpm)")
211+
212+
# Aqueous Composition vs Stirring Time
213+
plt.subplot(2, 2, 4)
214+
sc = plt.scatter(
215+
df["aqueous_composition"], df["stirring_time"], c=df["purity"], cmap="plasma"
216+
)
217+
plt.colorbar(sc, label="Purity (%)")
218+
plt.xlabel("Aqueous Composition")
219+
plt.ylabel("Stirring Time (s)")
220+
221+
plt.tight_layout()
222+
plt.show()
223+
224+
# Generate 3D plot for key parameters
225+
fig = plt.figure(figsize=(10, 8))
226+
ax = fig.add_subplot(111, projection="3d")
227+
228+
sc = ax.scatter(
229+
df["aqueous_composition"],
230+
df["stirring_speed"],
231+
df["temperature"],
232+
c=df["recovery"],
233+
cmap="viridis",
234+
s=50,
235+
)
236+
237+
ax.set_xlabel("Aqueous Composition")
238+
ax.set_ylabel("Stirring Speed (rpm)")
239+
ax.set_zlabel("Temperature (°C)")
240+
plt.colorbar(sc, label="Recovery (%)")
241+
242+
plt.tight_layout()
243+
plt.show()

0 commit comments

Comments
 (0)