| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| import copy |
| import json |
| import os |
| from pathlib import Path |
|
|
| import numpy as np |
| import torch |
| from biotite.structure import AtomArray |
| from protenix.data.utils import save_atoms_to_cif |
| from protenix.utils.file_io import save_json |
| from protenix.utils.torch_utils import round_values |
|
|
|
|
| def get_clean_full_confidence(full_confidence_dict: dict) -> dict: |
| """ |
| Clean and format the full confidence dictionary by removing unnecessary keys and rounding values. |
| |
| Args: |
| full_confidence_dict (dict): The dictionary containing full confidence data. |
| |
| Returns: |
| dict: The cleaned and formatted dictionary. |
| """ |
| |
| full_confidence_dict.pop("atom_coordinate") |
| |
| full_confidence_dict.pop("atom_is_polymer") |
| |
| full_confidence_dict = round_values(full_confidence_dict) |
| return full_confidence_dict |
|
|
|
|
| class DataDumper: |
| def __init__(self, base_dir) -> None: |
| self.base_dir = base_dir |
|
|
| def dump( |
| self, |
| dataset_name: str, |
| pdb_id: str, |
| seed: int, |
| pred_dict: dict, |
| atom_array: AtomArray, |
| entity_poly_type: dict[str, str], |
| ): |
| """ |
| Dump the predictions and related data to the specified directory. |
| |
| Args: |
| dataset_name (str): The name of the dataset. |
| pdb_id (str): The PDB ID of the sample. |
| seed (int): The seed used for randomization. |
| pred_dict (dict): The dictionary containing the predictions. |
| atom_array (AtomArray): The AtomArray object containing the structure data. |
| entity_poly_type (dict[str, str]): The entity poly type information. |
| """ |
| dump_dir = self._get_dump_dir(dataset_name, pdb_id, seed) |
| Path(dump_dir).mkdir(parents=True, exist_ok=True) |
|
|
| self.dump_predictions( |
| pred_dict=pred_dict, |
| dump_dir=dump_dir, |
| pdb_id=pdb_id, |
| atom_array=atom_array, |
| entity_poly_type=entity_poly_type, |
| ) |
|
|
| def _get_dump_dir(self, dataset_name: str, sample_name: str, seed: int) -> str: |
| """ |
| Generate the directory path for dumping data based on the dataset name, sample name, and seed. |
| """ |
| dump_dir = os.path.join( |
| self.base_dir, dataset_name, sample_name, f"seed_{seed}" |
| ) |
| return dump_dir |
|
|
| def dump_predictions( |
| self, |
| pred_dict: dict, |
| dump_dir: str, |
| pdb_id: str, |
| atom_array: AtomArray, |
| entity_poly_type: dict[str, str], |
| ): |
| """ |
| Dump raw predictions from the model: |
| structure: Save the predicted coordinates as CIF files. |
| confidence: Save the confidence data as JSON files. |
| """ |
| prediction_save_dir = os.path.join(dump_dir, "predictions") |
| os.makedirs(prediction_save_dir, exist_ok=True) |
|
|
| self._save_structure( |
| pred_dict["coordinate"], |
| prediction_save_dir, |
| pdb_id, |
| atom_array, |
| entity_poly_type, |
| ) |
| self._save_confidence( |
| data=pred_dict, prediction_save_dir=prediction_save_dir, sample_name=pdb_id |
| ) |
| self._mark_task_complete(dump_dir) |
|
|
| def _mark_task_complete(self, dump_dir): |
| success_file_path = os.path.join(dump_dir, f"SUCCESS_FILE") |
| success_data = {"prediction": True} |
| with open(success_file_path, "w") as f: |
| json.dump(success_data, f) |
|
|
| def check_completion(self, dataset_name, sample_name, seed): |
| dump_dir = self._get_dump_dir(dataset_name, sample_name, seed) |
| success_file_path = os.path.join(dump_dir, f"SUCCESS_FILE") |
| return os.path.exists(success_file_path) |
|
|
| def _save_structure( |
| self, |
| pred_coordinates, |
| prediction_save_dir, |
| sample_name, |
| atom_array, |
| entity_poly_type=None, |
| ): |
| N_sample = pred_coordinates.shape[0] |
| for sample_idx in range(N_sample): |
| output_fpath = os.path.join( |
| prediction_save_dir, f"{sample_name}_sample_{sample_idx}.cif" |
| ) |
| |
| atom_array.set_annotation( |
| "b_factor", np.round(np.zeros(len(atom_array)).astype(float), 2) |
| ) |
| if "occupancy" not in atom_array._annot: |
| |
| atom_array.set_annotation( |
| "occupancy", np.round(np.ones(len(atom_array)), 2) |
| ) |
| save_structure_cif( |
| atom_array, |
| pred_coordinates[sample_idx], |
| output_fpath, |
| entity_poly_type, |
| sample_name, |
| |
| ) |
|
|
| def _save_confidence( |
| self, |
| data: dict, |
| prediction_save_dir: str, |
| sample_name: str, |
| ): |
| N_sample = ( |
| len(data["summary_confidence"]) if "summary_confidence" in data else 0 |
| ) |
| if N_sample <= 0: |
| return |
|
|
| for idx, rank in enumerate(range(N_sample)): |
| output_fpath = os.path.join( |
| prediction_save_dir, |
| f"{sample_name}_summary_confidence_sample_{rank}.json", |
| ) |
| save_json(data["summary_confidence"][idx], output_fpath, indent=4) |
|
|
|
|
| def save_structure_cif( |
| atom_array: AtomArray, |
| pred_coordinate: torch.Tensor, |
| output_fpath: str, |
| entity_poly_type: dict[str, str], |
| pdb_id: str, |
| ): |
| """ |
| Save the predicted structure to a CIF file. |
| |
| Args: |
| atom_array (AtomArray): The original AtomArray containing the structure. |
| pred_coordinate (torch.Tensor): The predicted coordinates for the structure. |
| output_fpath (str): The output file path for saving the CIF file. |
| entity_poly_type (dict[str, str]): The entity poly type information. |
| pdb_id (str): The PDB ID for the entry. |
| """ |
| pred_atom_array = copy.deepcopy(atom_array) |
| pred_pose = pred_coordinate.cpu().numpy() |
| pred_atom_array.coord = pred_pose |
| save_atoms_to_cif( |
| output_fpath, |
| pred_atom_array, |
| entity_poly_type, |
| pdb_id, |
| ) |
|
|