diff --git a/src/pdbdepo/pdb_deposition.py b/src/pdbdepo/pdb_deposition.py index a2a33c7..e0e7c3b 100644 --- a/src/pdbdepo/pdb_deposition.py +++ b/src/pdbdepo/pdb_deposition.py @@ -13,6 +13,7 @@ import argparse import bz2 +import csv import datetime import glob import re @@ -101,6 +102,7 @@ def process_input( mmcifgen_block, output_dir: Path, cmpd_codes_dict: dict = {}, + pose_ids_dict: dict = {}, debug=False, ): software_templates = read_software_templates() @@ -276,6 +278,10 @@ def process_input( mmcifgen_refine_values, ) + # build the comma-separated pose ID string for this crystal + pose_ids = pose_ids_dict.get(xtal_name, []) + pose_id_str = ', '.join(pose_ids) + # add in the common metadata (generated by mmcif-gen) for item in mmcifgen_block: to_add = True @@ -287,6 +293,7 @@ def process_input( template = item.loop.values[1] template = template.replace('$CompoundCode', cmpd_code) template = template.replace('$CrystalName', xtal_name) + template = template.replace('$PoseID', pose_id_str) cmpd_codes = cmpd_codes_dict.get(xtal_name) if cmpd_codes: for i, cmpd_code in enumerate(cmpd_codes): @@ -296,6 +303,19 @@ def process_input( template = template.replace('$ExternalCode' + str(i), '') new_loop = structure_cif_block0.init_loop('', item.loop.tags) new_loop.add_row([item.loop.values[0], template]) + elif any('$PoseID' in v for v in item.loop.values): + to_add = False + ncols = len(item.loop.tags) + nrows = len(item.loop.values) // ncols + new_loop = structure_cif_block0.init_loop('', item.loop.tags) + for r in range(nrows): + loop_row = [ + item.loop.values[r * ncols + c].replace('$PoseID', pose_id_str) for c in range(ncols) + ] + new_loop.add_row(loop_row) + elif item.pair is not None and '$PoseID' in item.pair[1]: + structure_cif_block0.set_pair(item.pair[0], item.pair[1].replace('$PoseID', pose_id_str)) + to_add = False if to_add: # otherwise add the item as it is added_item = structure_cif_block0.add_item(item) @@ -1060,12 +1080,34 @@ def read_cmpd_codes(filename): return d +def read_fragalysis_csv(filename): + """Read Fragalysis metadata CSV and return a dict mapping crystal name -> list of pose codes. + + The CSV has pose code in column 1 (index 0) and crystal/experiment code in column 3 (index 2). + """ + d = {} + if filename: + with open(filename, 'rt', newline='') as f: + reader = csv.reader(f) + next(reader) # skip header + for tokens in reader: + if len(tokens) >= 3: + pose_code = tokens[0].strip() + crystal_name = tokens[2].strip() + if crystal_name not in d: + d[crystal_name] = [] + d[crystal_name].append(pose_code) + info('read pose IDs for', len(d), 'crystals') + return d + + def run(collator_path, metadata_csv, compound_codes_csv=None, fragalysis_csv=None, debug=False): info('run on ' + str(datetime.datetime.now())) info('using RDKit version ' + rdBase.rdkitVersion) # info('using InCHI version ' + Chem.GetInchiVersion()) cmpd_codes_dict = read_cmpd_codes(compound_codes_csv) + pose_ids_dict = read_fragalysis_csv(fragalysis_csv) output_dir_p = collator_path / 'pdb_depo_files' @@ -1101,6 +1143,7 @@ def run(collator_path, metadata_csv, compound_codes_csv=None, fragalysis_csv=Non meta_mmcifgen, output_dir_p, cmpd_codes_dict=cmpd_codes_dict, + pose_ids_dict=pose_ids_dict, debug=debug, )