Source code for reforge.martini.martini_tools

"""
Module for Martini simulation tools.

This module provides tools for preparing Martini simulations, such as topology file generation,
linking itp files, processing PDB files with GROMACS, and running various martinize2 routines.
Note that this module is intended for internal use.
"""

import logging
import os
import shutil
import warnings
from pathlib import Path
from MDAnalysis import Universe
from MDAnalysis.analysis.dssp import translate, DSSP
from reforge import cli
from reforge.martini import martinize_rna
from reforge.martini.martinize_rna import martinize_rna
from reforge.utils import cd

logger = logging.getLogger(__name__)
warnings.filterwarnings("ignore", message="Reader has no dt information, set to 1.0 ps")


[docs] def dssp(in_file): """Compute the DSSP secondary structure for the given PDB file. Parameters ---------- in_file : str or Path Path to the PDB file. Returns ------- str Secondary structure string with '-' replaced by 'C'. """ logger.info("Doing DSSP") u = Universe(in_file) run = DSSP(u).run() mean_secondary_structure = translate(run.results.dssp_ndarray.mean(axis=0)) ss = "".join(mean_secondary_structure).replace("-", "C") return ss
[docs] def append_to(in_file, out_file): """Append the contents of in_file (excluding the first line) to out_file. Parameters ---------- in_file : str or Path Path to the source file. out_file : str or Path Path to the destination file. """ # Convert to Path objects in_path = Path(in_file) out_path = Path(out_file) logger.debug(f"Appending {in_path} to {out_path} (excluding first line)") # Check if input file exists if not in_path.exists(): logger.warning(f"Source file does not exist: {in_path}") return # Create parent directory for output file if it doesn't exist out_path.parent.mkdir(parents=True, exist_ok=True) with open(in_path, "r", encoding="utf-8") as src: lines = src.readlines() lines_appended = len(lines) - 1 if len(lines) > 1 else 0 with open(out_path, "a", encoding="utf-8") as dest: dest.writelines(lines[1:]) logger.debug(f"Appended {lines_appended} lines from {in_path} to {out_path}")
[docs] def fix_go_map(wdir, in_map, out_map="go.map"): """Fix the Go-map file by removing the last column from lines that start with 'R '. Parameters ---------- wdir : str or Path Working directory. in_map : str or Path Input map filename. out_map : str or Path, optional Output map filename. Default is "go.map". """ wdir_path = Path(wdir) in_map_path = wdir_path / in_map out_map_path = wdir_path / out_map logger.info(f"Fixing Go-map file: {in_map_path} -> {out_map_path}") if not in_map_path.exists(): logger.error(f"Input map file does not exist: {in_map_path}") raise FileNotFoundError(f"Input map file does not exist: {in_map_path}") lines_processed = 0 lines_modified = 0 with open(in_map_path, "r", encoding="utf-8") as in_file: with open(out_map_path, "w", encoding="utf-8") as out_file: for line in in_file: lines_processed += 1 if line.startswith("R "): new_line = " ".join(line.split()[:-1]) out_file.write(new_line + "\n") lines_modified += 1 else: out_file.write(line) logger.info(f"Go-map fix completed: {lines_processed} lines processed, {lines_modified} lines modified") logger.info(f"Output written to: {out_map_path}")
[docs] @cli.from_wdir def run_martinize_go(wdir, topdir, aapdb, cgpdb, name="protein", go_eps=9.414, go_low=0.3, go_up=1.1, go_res_dist=3, from_ff='amber', **kwargs): """Run virtual site-based GoMartini via martinize2. Parameters ---------- wdir : str Working directory. topdir : str Topology directory. aapdb : str Input all-atom PDB file. cgpdb : str Coarse-grained PDB file. name : str, optional Protein name. Default is "protein". go_eps : float, optional Strength of the Go-model bias. Default is 9.414. go_low : float, optional Lower distance cutoff (nm). Default is 0.3. go_up : float, optional Upper distance cutoff (nm). Default is 1.1. go_res_dist : int, optional Minimum residue distance below which contacts are removed. Default is 3. **kwargs : Additional keyword arguments. """ kwargs.setdefault("f", aapdb) kwargs.setdefault("x", cgpdb) kwargs.setdefault("go", "") kwargs.setdefault("o", "protein.top") kwargs.setdefault("cys", 0.3) kwargs.setdefault("p", "all") kwargs.setdefault("pf", 1000) kwargs.setdefault("sep", " ") kwargs.setdefault("resid", "input") kwargs.setdefault("ff", "martini3001") kwargs.setdefault("maxwarn", "1000") kwargs.setdefault("from", from_ff) # Convert paths to Path objects wdir_path = Path(wdir) topdir_path = Path(topdir) logger.info(f"Starting martinize_go for protein '{name}'") logger.info(f"Working directory: {wdir_path}") logger.info(f"Topology directory: {topdir_path}") logger.info(f"Input AA PDB: {aapdb}") logger.info(f"Input CG PDB: {cgpdb}") with cd(wdir): go_write_path = wdir_path / "maps" / f"{name}.map" logger.info(f"Go-map will be written to: {go_write_path}") go_write_path.parent.mkdir(parents=True, exist_ok=True) logger.info(f"Created directory: {go_write_path.parent}") relative_go_path = go_write_path.relative_to(wdir_path) line = ("-name {} -go-eps {} -go-low {} -go-up {} -go-res-dis {} " "-go-write-file {} -dssp").format( name, go_eps, go_low, go_up, go_res_dist, relative_go_path) logger.info(f"Running martinize2 with command: {line}") cli.run("martinize2", line, **kwargs) logger.info("martinize2 execution completed") go_atomtypes_src = Path("go_atomtypes.itp") go_atomtypes_dst = topdir_path / "go_atomtypes.itp" go_nbparams_src = Path("go_nbparams.itp") go_nbparams_dst = topdir_path / "go_nbparams.itp" protein_itp_src = Path(f"{name}.itp") protein_itp_dst = topdir_path / f"{name}.itp" logger.info(f"Moving files to topology directory: {topdir_path}") append_to(go_atomtypes_src, go_atomtypes_dst) logger.info(f"Appended {go_atomtypes_src} to {go_atomtypes_dst}") append_to(go_nbparams_src, go_nbparams_dst) logger.info(f"Appended {go_nbparams_src} to {go_nbparams_dst}") shutil.move(protein_itp_src, protein_itp_dst) logger.info(f"Moved {protein_itp_src} to {protein_itp_dst}") logger.info(f"martinize_go completed successfully for protein '{name}'")
[docs] @cli.from_wdir def run_martinize_en(wdir, aapdb, cgpdb, ef=700, el=0.0, eu=0.9, from_ff='amber', **kwargs): """Run protein elastic network generation via martinize2. Parameters ---------- wdir : str Working directory. aapdb : str Input all-atom PDB file. cgpdb : str Coarse-grained PDB file. ef : float, optional Force constant. Default is 700. el : float, optional Lower cutoff. Default is 0.0. eu : float, optional Upper cutoff. Default is 0.9. **kwargs : Additional keyword arguments. """ kwargs.setdefault("f", aapdb) kwargs.setdefault("x", cgpdb) kwargs.setdefault("o", "protein.top") kwargs.setdefault("cys", 0.3) kwargs.setdefault("p", "all") kwargs.setdefault("pf", 1000) kwargs.setdefault("sep", "") kwargs.setdefault("resid", "input") kwargs.setdefault("ff", "martini3001") kwargs.setdefault("maxwarn", "1000") kwargs.setdefault("elastic", "") kwargs.setdefault("from", from_ff) ss = dssp(aapdb) line = ("-ef {} -el {} -eu {} -ss {}").format(ef, el, eu, ss) with cd(wdir): cli.run("martinize2", line, **kwargs)
[docs] def run_martinize_nucleotide(wdir, aapdb, cgpdb, **kwargs): """Run nucleotide coarse-graining using martinize_nucleotides. Parameters ---------- wdir : str Working directory. aapdb : str Input all-atom PDB file. cgpdb : str Coarse-grained PDB file. **kwargs : Additional parameters. """ kwargs.setdefault("f", aapdb) kwargs.setdefault("x", cgpdb) kwargs.setdefault("sys", "RNA") kwargs.setdefault("type", "ss") kwargs.setdefault("o", "topol.top") kwargs.setdefault("p", "bb") kwargs.setdefault("pf", 1000) with cd(wdir): script = "reforge.martini.martinize_nucleotides" cli.run("python3 -m", script, **kwargs)
[docs] def run_martinize_rna(wdir, **kwargs): """Run RNA coarse-graining using martinize_rna. Parameters ---------- wdir : str Working directory. **kwargs : Additional parameters. """ with cd(wdir): martinize_rna(**kwargs)
[docs] def insert_membrane(**kwargs): """Insert a membrane using the insane tool. """ script = "reforge.martini.insane3" cli.run("python3 -m", script, **kwargs)