"""MD scoring module.
This module will perform a short MD simulation on the input models and
score them. No restraints are applied during this step.
"""
from pathlib import Path
from haddock.core.defaults import MODULE_DEFAULT_YAML
from haddock.core.typing import FilePath
from haddock.gear.haddockmodel import HaddockModel
from haddock.libs.libcns import prepare_cns_input, prepare_expected_pdb
from haddock.libs.libontology import PDBFile
from haddock.libs.libsubprocess import CNSJob
from haddock.modules import get_engine
from haddock.modules.scoring import CNSScoringModule
RECIPE_PATH = Path(__file__).resolve().parent
DEFAULT_CONFIG = Path(RECIPE_PATH, MODULE_DEFAULT_YAML)
[docs]
class HaddockModule(CNSScoringModule):
    """HADDOCK3 module to perform energy minimization scoring."""
    name = RECIPE_PATH.name
    def __init__(
        self, order: int, path: Path, initial_params: FilePath = DEFAULT_CONFIG
    ) -> None:
        cns_script = Path(RECIPE_PATH, "cns", f"{self.name}.cns")
        super().__init__(order, path, initial_params, cns_script=cns_script)
[docs]
    @classmethod
    def confirm_installation(cls) -> None:
        """Confirm module is installed."""
        return 
    def _run(self) -> None:
        """Execute module."""
        # Pool of jobs to be executed by the CNS engine
        jobs: list[CNSJob] = []
        try:
            models_to_score = self.previous_io.retrieve_models(individualize=True)
        except Exception as e:
            self.finish_with_error(e)
        # Here we pop the parameter as not supported by CNS and only used
        # at the python level for downstream analysis
        interface_combinations = self.extract_interface_combinations()
        # Prepare all CNS runs
        self.output_models = []
        for model_num, model in enumerate(models_to_score, start=1):
            scoring_inpyt = prepare_cns_input(
                model_num,
                model,
                self.path,
                self.recipe_str,
                self.params,
                self.name,
                native_segid=True,
                debug=self.params["debug"],
                seed=model.seed if isinstance(model, PDBFile) else None,
            )
            scoring_out = f"{self.name}_{model_num}.out"
            err_fname = f"{self.name}_{model_num}.cnserr"
            # create the expected PDBobject
            expected_pdb = prepare_expected_pdb(model, model_num, ".", self.name)
            # fill the ori_name field of expected_pdb
            expected_pdb.ori_name = model.file_name
            expected_pdb.md5 = model.md5
            expected_pdb.restr_fname = model.restr_fname
            self.output_models.append(expected_pdb)
            job = CNSJob(scoring_inpyt, scoring_out, err_fname, envvars=self.envvars)
            jobs.append(job)
        # Run CNS Jobs
        self.log(f"Running CNS Jobs n={len(jobs)}")
        Engine = get_engine(self.params["mode"], self.params)
        engine = Engine(jobs)
        engine.run()
        self.log("CNS jobs have finished")
        # Update the score attributes for each output pdb
        output_haddock_models = self.update_pdb_scores(interface_combinations)
        # Set output filename
        output_fname = f"{self.name}.tsv"
        # Process per-interface analysis
        self.per_interface_output(output_fname, output_haddock_models)
        # Make final output file
        self.log(f"Saving output to {output_fname}")
        self.output(output_fname)
        # Export models
        self.export_io_models(faulty_tolerance=self.params["tolerance"])