Skip to content

Commit 79c18d9

Browse files
authored
Add wrapper for xia2.overload (#354)
1 parent b982e66 commit 79c18d9

2 files changed

Lines changed: 139 additions & 0 deletions

File tree

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@
9393
"topaz3 = dlstbx.wrapper.topaz3_wrapper:Topaz3Wrapper",
9494
"xia2 = dlstbx.wrapper.xia2:Xia2Wrapper",
9595
"xia2.multiplex = dlstbx.wrapper.xia2_multiplex:Xia2MultiplexWrapper",
96+
"xia2.overload = dlstbx.wrapper.xia2_overload:Xia2OverloadWrapper",
9697
"xia2.strategy = dlstbx.wrapper.xia2_strategy:Xia2StrategyWrapper",
9798
"xia2.to_shelxcde = dlstbx.wrapper.xia2_to_shelxcde:Xia2toShelxcdeWrapper",
9899
"xia2.ssx = dlstbx.wrapper.xia2_ssx:Xia2SsxWrapper",
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
from __future__ import annotations
2+
3+
import json
4+
import math
5+
import subprocess
6+
7+
from pathlib import Path
8+
import shutil
9+
10+
from dlstbx.wrapper import Wrapper
11+
12+
13+
class Xia2OverloadWrapper(Wrapper):
14+
_logger_name = "dlstbx.wrap.xia2_overload"
15+
16+
def send_to_ispyb(self, transmission):
17+
ispyb_command_list = []
18+
19+
d = {
20+
"program": "xia2.overload",
21+
"ispyb_command": "insert_screening_output",
22+
"screening_id": "$ispyb_screening_id",
23+
"store_result": "ispyb_screening_output_id",
24+
}
25+
ispyb_command_list.append(d)
26+
27+
d = {
28+
"ispyb_command": "insert_screening_strategy",
29+
"transmission": transmission,
30+
"screening_output_id": "$ispyb_screening_output_id",
31+
"store_result": "ispyb_screening_strategy_id",
32+
}
33+
ispyb_command_list.append(d)
34+
35+
d = {
36+
"ispyb_command": "insert_screening_strategy_wedge",
37+
"screening_strategy_id": "$ispyb_screening_strategy_id",
38+
"store_result": "ispyb_screening_strategy_wedge_id",
39+
}
40+
ispyb_command_list.append(d)
41+
42+
d = {
43+
"ispyb_command": "insert_screening_strategy_sub_wedge",
44+
"transmission": transmission,
45+
"screening_strategy_wedge_id": "$ispyb_screening_strategy_wedge_id",
46+
"store_result": "ispyb_screening_strategy_sub_wedge_id",
47+
}
48+
ispyb_command_list.append(d)
49+
50+
d = {
51+
"ispyb_command": "update_processing_status",
52+
"program_id": "$ispyb_autoprocprogram_id",
53+
"message": "Processing successful",
54+
"status": "success",
55+
}
56+
ispyb_command_list.append(d)
57+
58+
self.recwrap.send_to("ispyb", {"ispyb_command_list": ispyb_command_list})
59+
self.log.info("Sent %d commands to ISPyB", len(ispyb_command_list))
60+
self.log.debug("Sending %s", json.dumps(ispyb_command_list, indent=2))
61+
62+
def run(self):
63+
assert hasattr(self, "recwrap"), "No recipewrapper object found"
64+
65+
params = self.recwrap.recipe_step["job_parameters"]
66+
working_directory = Path(params["working_directory"])
67+
results_directory = Path(params["results_directory"])
68+
69+
target_countrate_pct = float(params["target_countrate_pct"])
70+
oscillation = float(params["oscillation"])
71+
transmission = float(params["transmission"])
72+
73+
file = params["input_file"]
74+
75+
command = [f"xia2.overload {file}"]
76+
77+
result = subprocess.run(
78+
command, shell=True, cwd=working_directory, capture_output=True
79+
)
80+
81+
if result.returncode:
82+
self.log.info(f"xia2.overload failed with return code {result.returncode}")
83+
self.log.info(result.stderr)
84+
self.log.debug(f"Command output:\n{result.stdout}")
85+
return False
86+
87+
results_directory.mkdir(parents=True, exist_ok=True)
88+
output_file_name = "overload.json"
89+
90+
source_file = working_directory / output_file_name
91+
destination = results_directory / output_file_name
92+
93+
if not source_file.exists():
94+
return False
95+
96+
self.log.debug(f"Copying {str(source_file)} to {str(destination)}")
97+
shutil.copy2(source_file, destination)
98+
99+
self.record_result_individual_file(
100+
{
101+
"file_path": str(destination.parent),
102+
"file_name": destination.name,
103+
"file_type": "result",
104+
}
105+
)
106+
107+
with source_file.open("r") as f:
108+
data = json.load(f)
109+
counts = data["counts"]
110+
overload_limit = float(data["overload_limit"])
111+
112+
max_count = float(list(counts)[-1])
113+
114+
mosaicity_corr = params.get("mosaicity_correction", False)
115+
average_to_peak = (
116+
self.mosaicity_correction(mosaicity_corr, oscillation)
117+
if mosaicity_corr
118+
else 1
119+
)
120+
121+
saturation = (max_count / overload_limit) * average_to_peak
122+
scale_factor = target_countrate_pct / saturation
123+
124+
scaled_transmission = transmission * scale_factor
125+
self.send_to_ispyb(min(100, scaled_transmission))
126+
127+
self.log.info("Done.")
128+
return True
129+
130+
def mosaicity_correction(self, moscaicity_coefficent: float, oscillation: float):
131+
delta_z = oscillation / (moscaicity_coefficent) * math.sqrt(2)
132+
average_to_peak = (
133+
math.sqrt(math.pi) * delta_z * math.erf(delta_z)
134+
+ math.exp(-(delta_z * delta_z))
135+
- 1
136+
) / (delta_z * delta_z)
137+
self.log.info("Average-to-peak intensity ratio: %f", average_to_peak)
138+
return average_to_peak

0 commit comments

Comments
 (0)