Some common tasks you can do with QCrBoxtools¶
This is a short reference of functions that are implemented in the QCrBoxTools library, which is available in the qcrbox
conda environment in every QCrBox container. This is not a complete collection but highlights some functions which might be useful for your own development. If these functions work with an iotbx.cif
it is assumed that they are in unified cif format.
In this first cell, we create ourselves a content manager for temporary files. Make sure you execute the next cell before all others.
from contextlib import contextmanager
from pathlib import Path
from tempfile import NamedTemporaryFile
from textwrap import dedent
@contextmanager
def temp_file_context(suffix: str, file_text: str) -> str:
temp_cif = NamedTemporaryFile(suffix=suffix, delete=False)
temp_cif.write(dedent(file_text).encode("utf-8"))
temp_cif.close()
yield Path(temp_cif.name)
Path(temp_cif.name).unlink()
Load a cif in unified format¶
We create a small temporary file first and then load it from disk as unified cif. This function makes sure that you do not need to handle aliases yourself.
from qcrboxtools.cif.read import read_cif_as_unified
cif_text = dedent("""
data_test
_cell_length_a 10.00(2)
_cell_length_b 11.01(12)
_cell_length_c 12.05(5)
""")
with temp_file_context(".cif", cif_text) as cif_path:
unified_block = read_cif_as_unified(
cif_path=cif_path, # path to the CIF file.
dataset=0, # use an integer to specify dataset by position, a string to specify by name
)
# We now use unified keywords. Standard uncertainties are stored in the "<entry>_su" keys.
# We can now be sure which aliases of the entries are used.
print(unified_block["_cell.length_a"], unified_block["_cell.length_a_su"])
10.0 0.02
Generating an hkl from a cif.¶
from qcrboxtools.cif.file_converter.hkl import cif2hkl4
cif_text = dedent("""
data_test
loop_
_diffrn_refln.index_h
_diffrn_refln.index_k
_diffrn_refln.index_l
_diffrn_refln.intensity_net
_diffrn_refln.intensity_net_su
_diffrn_refln.scale_group_code
0 0 3 93.4022 38.7231 2
0 0 -3 192.939 61.994 2
0 0 -4 144304 1540.24 2
0 0 4 146626 1495.57 2
0 0 -5 485.452 123.618 2
0 0 5 284.703 91.7571 2
""")
with temp_file_context(".cif", cif_text) as cif_path:
with temp_file_context(".hkl", "") as hkl_path:
# Generates an HKL file from the CIF file.
cif2hkl4(cif_path=cif_path, cif_dataset=0, hkl_path=hkl_path)
print(hkl_path.read_text()) # check the content of the generated HKL file
0 0 3 93.4022 38.7231 2 0 0 -3 192.939 61.9940 2 0 0 -4 144304. 1540.24 2 0 0 4 146626. 1495.57 2 0 0 -5 485.452 123.618 2 0 0 5 284.703 91.7571 2
Getting a new cif with non-unified cif entries from a unified cif¶
from qcrboxtools.cif.cif2cif import cif_file_to_specific
cif_text = dedent("""
data_test
_cell.length_a 10.0002
_cell.length_a_su 0.02
_cell.length_b 11.019
_cell.length_b_su 0.12
_cell.length_c 12.05
_cell.length_c_su 0.05
_cell.volume 1331.0
_custom_category.entry testme
""")
with temp_file_context(".cif", cif_text) as cif_path:
with temp_file_context(".cif", "") as new_cif_path:
# Generates a new CIF file with only the specified entries.
cif_file_to_specific(
input_cif_path=cif_path,
output_cif_path=new_cif_path,
required_entries=["_cell_length_a", "_cell_length_b", "_custom_category_entry"],
optional_entries=[
"_cell_length_c",
"_cell_angle_alpha",
], # notice that "_cell_angle_alpha" is not present in the input CIF file
custom_categories=["custom_category"],
merge_su=True,
)
print(new_cif_path.read_text()) # check the content of the generated CIF file
data_test _cell_length_a 10.00(2) _cell_length_b 11.02(12) _cell_length_c 12.05(5) _custom_category_entry testme
Merge two CIF blocks¶
QCrBox has a helper functions to merge cif blocks, including merging loops on specified entries
from qcrboxtools.cif.merge import merge_cif_blocks
from qcrboxtools.cif.read import read_cif_safe
cif_text1 = dedent("""
data_test
_cell.length_a 10.0002
_cell.length_a_su 0.02
_cell.length_b 11.019
_cell.length_b_su 0.12
_cell.length_c 12.05
_cell.length_c_su 0.05
loop_
_refln.index_h
_refln.index_k
_refln.index_l
_refln.f_squared_meas
_refln.f_squared_meas_su
0 0 3 93.4022 38.7231
0 0 -3 192.939 61.994
0 0 -4 144304 1540.24
0 0 4 146626 1495.57
""")
cif_text2 = dedent("""
data_test
_cell.length_c 15.05
_cell.length_c_su 0.05
loop_
_refln.index_h
_refln.index_k
_refln.index_l
_refln.f_calc
_refln.phase_calc
0 0 3 31.4022 0.5
0 0 5 192.939 90.5
""")
with temp_file_context(".cif", cif_text1) as cif_path1:
with temp_file_context(".cif", cif_text2) as cif_path2:
block1 = read_cif_safe(cif_path1)["test"] # read_cif_safe also supports pathlib.Path objects
block2 = read_cif_safe(cif_path2)["test"]
merged_block = merge_cif_blocks(
block1=block1,
block2=block2, # block2 will overwrite block1
possible_markers=["_refln.index_.*"], # markers to merge the loops on h,k,l unique,
# would also work with default value
)
print(merged_block) # note that missing entries in a loop are filled with ?.
# Ensure matching index to avoid
_cell.length_a 10.0002 _cell.length_a_su 0.02 _cell.length_b 11.019 _cell.length_b_su 0.12 _cell.length_c 15.05 _cell.length_c_su 0.05 loop_ _refln.index_h _refln.index_k _refln.index_l _refln.f_squared_meas _refln.f_squared_meas_su _refln.f_calc _refln.phase_calc 0 0 3 93.4022 38.7231 31.4022 0.5 0 0 -3 192.939 61.994 ? ? 0 0 -4 144304 1540.24 ? ? 0 0 4 146626 1495.57 ? ? 0 0 5 ? ? 192.939 90.5