Source code for ligandparam.recipes.lazyligand

from pathlib import Path
from typing import Optional, Union, Any

from typing_extensions import override

from ligandparam.parametrization import Recipe
from ligandparam.stages import (
    StageInitialize,
    StageDisplaceMol,
    StageNormalizeCharge,
    GaussianMinimizeRESP,
    StageLazyResp,
    StageUpdate,
    StageParmChk,
    StageLeap,
)


[docs] class LazyLigand(Recipe): """This is a class for parametrizing a simple ligand using Gaussian and Antechamber. This class is designed to do a quick parametrization of a very standard ligand. If your ligand is weird in any way, you should use a different class. This class does a very simple parametrization using Gaussian and Antechamber. The steps are: 1. Initialize the ligand using the PDB file. 2. Minimize the ligand using Gaussian at a low level of theory. 3. Minimize the ligand using Gaussian at a high level of theory. 4. Calculate the RESP charges using Gaussian at the low level of theory. 5. Check the parameters using ParmChk. 6. Generate the Leap input files. """ @override def __init__(self, in_filename: Union[Path, str], cwd: Union[Path, str], *args, **kwargs): super().__init__(in_filename, cwd, *args, **kwargs) # logger will be passed manually to each stage kwargs.pop("logger", None) # required options for opt in ("net_charge",): try: setattr(self, opt, kwargs[opt]) del kwargs[opt] except KeyError: raise KeyError(f"Missing {opt}") # required options with defaults # TODO: defaults should be a global singleton dict for opt, default_val in zip( ("theory", "leaprc", "force_gaussian_rerun", "nproc", "mem"), ({"low": "HF/6-31G*", "high": "PBE1PBE/6-31G*"}, ["leaprc.gaff2"], False, 1, 1), ): try: setattr(self, opt, kwargs[opt]) del kwargs[opt] except KeyError: setattr(self, opt, default_val) # optional options, without defaults for opt in ("gaussian_root", "gauss_exedir", "gaussian_binary", "gaussian_scratch"): setattr(self, opt, kwargs.pop(opt, None)) self.kwargs = kwargs
[docs] def setup(self): initial_mol2 = self.cwd / f"{self.label}.initial.mol2" centered_mol2 = self.cwd / f"{self.label}.centered.mol2" lowtheory_minimization_gaussian_log = self.cwd / f"{self.label}.lowtheory.minimization.log" hightheory_minimization_gaussian_log = self.cwd / f"{self.label}.hightheory.minimization.log" resp_mol2_low = self.cwd / f"{self.label}.lowtheory.mol2" resp_mol2_high = self.cwd / f"{self.label}.minimized.mol2" resp_mol2 = self.cwd / f"{self.label}.resp.mol2" final_mol2 = self.cwd / f"final_{self.label}.mol2" nonminimized_mol2 = self.cwd / f"{self.label}.mol2" frcmod = self.cwd / f"{self.label}.frcmod" lib = self.cwd / f"{self.label}.lib" self.stages = [ StageInitialize( "Initialize", main_input=self.in_filename, cwd=self.cwd, out_mol2=initial_mol2, net_charge=self.net_charge, logger=self.logger, **self.kwargs, ), StageNormalizeCharge( "Normalize1", main_input=initial_mol2, cwd=self.cwd, net_charge=self.net_charge, out_mol2=initial_mol2, logger=self.logger, **self.kwargs, ), StageDisplaceMol( "Centering", main_input=initial_mol2, cwd=self.cwd, out_mol=centered_mol2, logger=self.logger, ), GaussianMinimizeRESP( "MinimizeLowTheory", main_input=centered_mol2, cwd=self.cwd, nproc=self.nproc, mem=self.mem, gaussian_root=self.gaussian_root, gauss_exedir=self.gauss_exedir, gaussian_binary=self.gaussian_binary, gaussian_scratch=self.gaussian_scratch, net_charge=self.net_charge, opt_theory=self.theory["low"], resp_theory=self.theory["low"], force_gaussian_rerun=self.force_gaussian_rerun, out_gaussian_log=lowtheory_minimization_gaussian_log, logger=self.logger, **self.kwargs, ), StageLazyResp( "LazyRespLow", main_input=lowtheory_minimization_gaussian_log, cwd=self.cwd, net_charge=self.net_charge, out_mol2=resp_mol2_low, logger=self.logger, **self.kwargs, ), GaussianMinimizeRESP( "MinimizeHighTheory", main_input=resp_mol2_low, cwd=self.cwd, nproc=self.nproc, mem=self.mem, gaussian_root=self.gaussian_root, gauss_exedir=self.gauss_exedir, gaussian_binary=self.gaussian_binary, gaussian_scratch=self.gaussian_scratch, net_charge=self.net_charge, opt_theory=self.theory["high"], resp_theory=self.theory["low"], force_gaussian_rerun=self.force_gaussian_rerun, out_gaussian_log=hightheory_minimization_gaussian_log, logger=self.logger, **self.kwargs, ), StageLazyResp( "LazyRespHigh", main_input=hightheory_minimization_gaussian_log, cwd=self.cwd, out_mol2=resp_mol2_high, net_charge=self.net_charge, logger=self.logger, **self.kwargs, ), StageNormalizeCharge( "Normalize2", main_input=resp_mol2_high, cwd=self.cwd, net_charge=self.net_charge, out_mol2=resp_mol2, logger=self.logger, **self.kwargs, ), StageUpdate( "UpdateNames", main_input=resp_mol2, cwd=self.cwd, source_mol2=initial_mol2, out_mol2=final_mol2, net_charge=self.net_charge, update_names=True, update_types=False, update_resname=True, logger=self.logger, **self.kwargs, ), # Create a `nonminimized_mol2` with `initial_mol2` coordinates and `final_mol2` charges StageUpdate( "UpdateCharges", main_input=initial_mol2, cwd=self.cwd, source_mol2=final_mol2, out_mol2=nonminimized_mol2, update_charges=True, net_charge=self.net_charge, logger=self.logger, **self.kwargs, ), StageParmChk("ParmChk", main_input=nonminimized_mol2, cwd=self.cwd, out_frcmod=frcmod, logger=self.logger, **self.kwargs), StageLeap("Leap", main_input=nonminimized_mol2, cwd=self.cwd, in_frcmod=frcmod, out_lib=lib, logger=self.logger, **self.kwargs), ]
[docs] @override def execute(self, dry_run=False, nproc: Optional[int] = None, mem: Optional[int] = None) -> Any: self.logger.info(f"Starting the LazyLigand recipe at {self.cwd}") super().execute(dry_run=dry_run, nproc=nproc, mem=mem) self.logger.info("Done with the LazyLigand recipe")