-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathaggregate_results.py
More file actions
161 lines (145 loc) · 6.37 KB
/
Copy pathaggregate_results.py
File metadata and controls
161 lines (145 loc) · 6.37 KB
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#!/usr/bin/env python3
"""
aggregate_results.py
This script navigates the LIGANDS directory structure, locates each run's results.txt file,
and extracts the following metrics from the block starting with:
Processing column 3: Eproj (average overall electric field)
The metrics extracted are:
Error enhancement factor (Gamma2) = <number>
Mean = <number>
Standard deviation = <number>
Estimated error = <number>
For each ligand and solvent pair, the script writes one row per run
(with columns: Ligand, Solvent, Run, Gamma2, Mean, Std, EstError)
and then appends an additional row labeled "Average" that averages the three runs.
The aggregated data is saved as "aggregated_results.csv" in the current working directory.
Usage:
python aggregate_results.py
"""
import os
import re
import csv
import statistics
# Define regex patterns for the markers
proc_pattern = re.compile(r"Processing column\s+(\d+):\s+(.+)")
gamma_pattern = re.compile(r"Error enhancement factor \(Gamma2\)\s*=\s*([\d\.eE\+\-]+)")
mean_pattern = re.compile(r"Mean\s*=\s*([\d\.eE\+\-]+)")
std_pattern = re.compile(r"Standard deviation\s*=\s*([\d\.eE\+\-]+)")
est_pattern = re.compile(r"Estimated error\s*=\s*([\d\.eE\+\-]+)")
# We want to parse the block for column 3 with the following label:
desired_label = "Eproj (average overall electric field)"
# Dictionary to store results:
# results[ligand][solvent] = list of dicts, each dict holds metrics for a run with key "run"
results = {}
# Assume LIGANDS is in the current working directory
ligands_dir = os.path.join(os.getcwd(), "LIGANDS")
if not os.path.isdir(ligands_dir):
print(f"ERROR: LIGANDS directory not found at {ligands_dir}")
exit(1)
print(f"Scanning results under: {ligands_dir}")
# Traverse each ligand directory
for ligand in os.listdir(ligands_dir):
ligand_path = os.path.join(ligands_dir, ligand)
if not os.path.isdir(ligand_path):
continue
results.setdefault(ligand, {})
# Solvent folders end with _md
for folder in os.listdir(ligand_path):
if not folder.endswith("_md"):
continue
solvent = folder[:-3] # remove the trailing "_md"
solvent_path = os.path.join(ligand_path, folder)
if not os.path.isdir(solvent_path):
continue
results[ligand].setdefault(solvent, [])
# Process each run folder (e.g., run1, run2, run3)
for run in os.listdir(solvent_path):
run_path = os.path.join(solvent_path, run)
if not os.path.isdir(run_path):
continue
results_file = os.path.join(run_path, "results.txt")
if not os.path.isfile(results_file):
print(f"WARNING: results.txt not found in {run_path}. Skipping.")
continue
# Read and parse results.txt
with open(results_file, "r") as f:
lines = f.readlines()
in_block = False
metrics = {}
for line in lines:
line_strip = line.strip()
proc_match = proc_pattern.match(line_strip)
if proc_match:
col_num, label = proc_match.groups()
# If we are already in the desired block and encounter a new block, stop parsing
if in_block:
break
if desired_label in label:
in_block = True
continue
if in_block:
if "gamma2" not in metrics:
gamma_match = gamma_pattern.search(line_strip)
if gamma_match:
metrics["gamma2"] = float(gamma_match.group(1))
if "mean" not in metrics:
mean_match = mean_pattern.search(line_strip)
if mean_match:
metrics["mean"] = float(mean_match.group(1))
if "std" not in metrics:
std_match = std_pattern.search(line_strip)
if std_match:
metrics["std"] = float(std_match.group(1))
if "est_error" not in metrics:
est_match = est_pattern.search(line_strip)
if est_match:
metrics["est_error"] = float(est_match.group(1))
if in_block and len(metrics) == 4:
print(f"Parsed {results_file} for ligand '{ligand}', solvent '{solvent}', run '{run}'.")
# Store the run name along with metrics
metrics["run"] = run
results[ligand][solvent].append(metrics)
else:
print(f"WARNING: Desired metrics not found in {results_file}. Skipping this run.")
# Build rows for CSV output.
# Each row: Ligand, Solvent, Run, Gamma2, Mean, Std, EstError
rows = []
for ligand, solvent_dict in results.items():
for solvent, runs in solvent_dict.items():
# Add one row per run
for run_data in runs:
row = {
"Ligand": ligand,
"Solvent": solvent,
"Run": run_data["run"],
"Gamma2": run_data["gamma2"],
"Mean": run_data["mean"],
"Std": run_data["std"],
"EstError": run_data["est_error"],
}
rows.append(row)
# Add a row for the average across runs
if runs:
gamma2_avg = statistics.mean([r["gamma2"] for r in runs])
mean_avg = statistics.mean([r["mean"] for r in runs])
std_avg = statistics.mean([r["std"] for r in runs])
est_avg = statistics.mean([r["est_error"] for r in runs])
avg_row = {
"Ligand": ligand,
"Solvent": solvent,
"Run": "Average",
"Gamma2": gamma2_avg,
"Mean": mean_avg,
"Std": std_avg,
"EstError": est_avg,
}
rows.append(avg_row)
# Write aggregated data to CSV file
csv_filename = "aggregated_results.csv"
csv_fields = ["Ligand", "Solvent", "Run", "Gamma2", "Mean", "Std", "EstError"]
with open(csv_filename, "w", newline="") as csvfile:
writer = csv.DictWriter(csvfile, fieldnames=csv_fields)
writer.writeheader()
for row in rows:
writer.writerow(row)
print(f"Aggregation complete. Results saved to {csv_filename}.")