Coverage for biobb_mem/ambertools/cpptraj_density.py: 89%
65 statements
« prev ^ index » next coverage.py v7.14.1, created at 2026-05-28 14:30 +0000
« prev ^ index » next coverage.py v7.14.1, created at 2026-05-28 14:30 +0000
1#!/usr/bin/env python3
3"""Module containing the Cpptraj Density class and the command line interface."""
4from pathlib import Path, PurePath
5from biobb_common.generic.biobb_object import BiobbObject
6from biobb_common.tools.file_utils import launchlogger
9class CpptrajDensity(BiobbObject):
10 """
11 | biobb_mem CpptrajDensity
12 | Wrapper of the Ambertools Cpptraj module for calculating density profile along an axis of a given cpptraj compatible trajectory.
13 | Cpptraj (the successor to ptraj) is the main program in Ambertools for processing coordinate trajectories and data files. The parameter names and defaults are the same as the ones in the official `Cpptraj manual <https://raw.githubusercontent.com/Amber-MD/cpptraj/master/doc/CpptrajManual.pdf>`_.
15 Args:
16 input_top_path (str): Path to the input structure or topology file. File type: input. `Sample file <https://github.com/bioexcel/biobb_mem/raw/main/biobb_mem/test/data/ambertools/topology.pdb>`_. Accepted formats: top (edam:format_3881), pdb (edam:format_1476), prmtop (edam:format_3881), parmtop (edam:format_3881), zip (edam:format_3987).
17 input_traj_path (str): Path to the input trajectory to be processed. File type: input. `Sample file <https://github.com/bioexcel/biobb_mem/raw/main/biobb_mem/test/data/ambertools/trajectory.xtc>`_. Accepted formats: mdcrd (edam:format_3878), crd (edam:format_3878), cdf (edam:format_3650), netcdf (edam:format_3650), nc (edam:format_3650), restart (edam:format_3886), ncrestart (edam:format_3886), restartnc (edam:format_3886), dcd (edam:format_3878), charmm (edam:format_3887), cor (edam:format_2033), pdb (edam:format_1476), mol2 (edam:format_3816), trr (edam:format_3910), gro (edam:format_2033), binpos (edam:format_3885), xtc (edam:format_3875), cif (edam:format_1477), arc (edam:format_2333), sqm (edam:format_2033), sdf (edam:format_3814), conflib (edam:format_2033).
18 output_cpptraj_path (str): Path to the output processed density analysis. File type: output. `Sample file <https://github.com/bioexcel/biobb_mem/raw/main/biobb_mem/test/reference/ambertools/density_default.dat>`_. Accepted formats: dat (edam:format_1637), agr (edam:format_2033), xmgr (edam:format_2033), gnu (edam:format_2033).
19 output_traj_path (str) (Optional): Path to the output processed trajectory. File type: output. `Sample file <https://github.com/bioexcel/biobb_mem/raw/main/biobb_mem/test/reference/ambertools/trajectory_out.dcd>`_. Accepted formats: mdcrd (edam:format_3878), crd (edam:format_3878), cdf (edam:format_3650), netcdf (edam:format_3650), nc (edam:format_3650), restart (edam:format_3886), ncrestart (edam:format_3886), restartnc (edam:format_3886), dcd (edam:format_3878), charmm (edam:format_3887), cor (edam:format_2033), pdb (edam:format_1476), mol2 (edam:format_3816), trr (edam:format_3910), gro (edam:format_2033), binpos (edam:format_3885), xtc (edam:format_3875), cif (edam:format_1477), arc (edam:format_2333), sqm (edam:format_2033), sdf (edam:format_3814), conflib (edam:format_2033).
20 properties (dic - Python dictionary object containing the tool parameters, not input/output files):
21 * **start** (*int*) - (1) [1~100000|1] Starting frame for slicing
22 * **end** (*int*) - (-1) [-1~100000|1] Ending frame for slicing
23 * **steps** (*int*) - (1) [1~100000|1] Step for slicing
24 * **density_type** (*str*) - ("number") Number, mass, partial charge (q) or electron (Ne - q) density. Electron density will be converted to e-/Å3 by dividing the average area spanned by the other two dimensions.
25 * **mask** (*str*) - ("*") Arbitrary number of masks for atom selection; a dataset is created and the output will contain entries for each mask.. Default: all atoms.
26 * **delta** (*float*) - (0.25) Resolution, i.e. determines number of slices (i.e. histogram bins).
27 * **axis** (*str*) - ("z") Coordinate (axis) for density calculation. Vales: x, y, z.
28 * **bintype** (*str*) - ("bincenter") Determine whether histogram bin coordinates will be based on bin center (default) or bin edges. Values: bicenter, binedge.
29 * **restrict** (*str*) - (None) If specified, only calculate the density within a cylinder or square shape from the specified axis as defined by a distance cutoff. Values: cylinder, square.
30 * **cutoff** (*float*) - (None) The distance cutoff for 'restrict'. Required if 'restrict' is specified.
31 * **binary_path** (*str*) - ("cpptraj") Path to the cpptraj executable binary.
32 * **remove_tmp** (*bool*) - (True) [WF property] Remove temporal files.
33 * **restart** (*bool*) - (False) [WF property] Do not execute if output files exist.
34 * **sandbox_path** (*str*) - ("./") [WF property] Parent path to the sandbox directory.
35 * **container_path** (*str*) - (None) Container path definition.
36 * **container_image** (*str*) - ('afandiadib/ambertools:serial') Container image definition.
37 * **container_volume_path** (*str*) - ('/tmp') Container volume path definition.
38 * **container_working_dir** (*str*) - (None) Container working directory definition.
39 * **container_user_id** (*str*) - (None) Container user_id definition.
40 * **container_shell_path** (*str*) - ('/bin/bash') Path to default shell inside the container.
42 Examples:
43 This is a use example of how to use the building block from Python::
45 from biobb_mem.ambertools.cpptraj_density import cpptraj_density
46 prop = {
47 'density_type': 'number'
48 }
49 cpptraj_density(input_top_path='/path/to/myTopology.top',
50 input_traj_path='/path/to/myTrajectory.xtc',
51 output_cpptraj_path='/path/to/newAnalysis.dat',
52 properties=prop)
54 Info:
55 * wrapped_software:
56 * name: Ambertools Cpptraj
57 * version: >=22.5
58 * license: GNU
59 * ontology:
60 * name: EDAM
61 * schema: http://edamontology.org/EDAM.owl
63 """
65 def __init__(self, input_top_path, input_traj_path, output_cpptraj_path,
66 output_traj_path=None, properties=None, **kwargs) -> None:
67 properties = properties or {}
69 # Call parent class constructor
70 super().__init__(properties)
71 self.locals_var_dict = locals().copy()
73 # Input/Output files
74 self.io_dict = {
75 "in": {"input_top_path": input_top_path, "input_traj_path": input_traj_path},
76 "out": {"output_cpptraj_path": output_cpptraj_path, "output_traj_path": output_traj_path}
77 }
79 # Properties specific for BB
80 self.instructions_file = 'instructions.in'
81 self.start = properties.get('start', 1)
82 self.end = properties.get('end', -1)
83 self.steps = properties.get('steps', 1)
84 self.slice = f' {self.start} {self.end} {self.steps}'
85 self.density_type = properties.get('density_type', 'number')
86 self.mask = properties.get('mask', '*')
87 self.delta = properties.get('delta', 0.25)
88 self.axis = properties.get('axis', 'z')
89 self.bintype = properties.get('bintype', 'bincenter')
90 self.restrict = properties.get('restrict', None)
91 self.cutoff = properties.get('cutoff', None)
92 self.binary_path = properties.get('binary_path', 'cpptraj')
93 self.properties = properties
95 # Check the properties
96 self.check_properties(properties)
97 self.check_arguments()
99 def create_instructions_file(self, stage_io_dict, out_log, err_log):
100 """Creates an input file using the properties file settings."""
101 instructions_list = []
102 instructions_file_name = PurePath(self.instructions_file).name
103 # Always create the instructions file in the host staged sandbox.
104 # In container mode, this directory is mounted to container_volume_path.
105 unique_dir = stage_io_dict.get("unique_dir", "")
106 self.instructions_file = str(Path(unique_dir).joinpath(instructions_file_name))
108 instructions_list.append('parm ' + PurePath(stage_io_dict["in"]["input_top_path"]).name)
109 instructions_list.append('trajin ' + PurePath(stage_io_dict["in"]["input_traj_path"]).name + self.slice)
110 density_command = f'density {self.density_type} out {PurePath(stage_io_dict["out"]["output_cpptraj_path"]).name} {self.mask} delta {self.delta} {self.axis} {self.bintype}'
111 if self.restrict:
112 density_command += f' restrict {self.restrict}'
113 if self.cutoff:
114 density_command += f' cutoff {self.cutoff}'
115 instructions_list.append(density_command)
117 # trajout
118 if stage_io_dict["out"].get("output_traj_path"):
119 instructions_list.append('trajout ' + PurePath(stage_io_dict["out"]["output_traj_path"]).name)
121 # Create .in file
122 with open(self.instructions_file, 'w') as mdp:
123 for line in instructions_list:
124 mdp.write(line.strip() + '\n')
126 return self.instructions_file
128 @launchlogger
129 def launch(self) -> int:
130 """Execute the :class:`CpptrajDensity <ambertools.cpptraj_density.CpptrajDensity>` object."""
132 # Setup Biobb
133 if self.check_restart():
134 return 0
135 self.stage_files()
137 if self.container_path:
138 working_dir = self.container_volume_path if self.container_volume_path else "/data"
139 else:
140 working_dir = self.stage_io_dict.get("unique_dir", "")
142 # create instructions file
143 self.create_instructions_file(self.stage_io_dict, self.out_log, self.err_log)
144 # create cmd and launch execution
145 self.cmd = ["cd", working_dir, ";", self.binary_path, '-i', PurePath(self.instructions_file).name]
146 # Run Biobb block
147 self.run_biobb()
148 # Copy files to host
149 self.copy_to_host()
150 # remove temporary folder(s)
151 self.remove_tmp_files()
152 self.check_arguments(output_files_created=True, raise_exception=False)
153 return self.return_code
156def cpptraj_density(input_top_path: str,
157 input_traj_path: str,
158 output_cpptraj_path: str,
159 output_traj_path: str = None,
160 properties: dict = None,
161 **kwargs) -> int:
162 """Execute the :class:`CpptrajDensity <ambertools.cpptraj_density.CpptrajDensity>` class and
163 execute the :meth:`launch() <ambertools.cpptraj_density.CpptrajDensity.launch>` method."""
164 return CpptrajDensity(**dict(locals())).launch()
167cpptraj_density.__doc__ = CpptrajDensity.__doc__
168main = CpptrajDensity.get_main(cpptraj_density, "Calculates the density along an axis of a given cpptraj compatible trajectory.")
170if __name__ == '__main__':
171 main()