Coverage for biobb_mem/fatslim/fatslim_apl.py: 92%
75 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 FATSLiM Area per Lipid class and the command line interface."""
4from pathlib import Path, PurePath
5import sys
6from biobb_common.generic.biobb_object import BiobbObject
7from biobb_common.tools.file_utils import launchlogger
8from biobb_mem.fatslim.common import ignore_no_box, move_output_file
9import MDAnalysis as mda
12class FatslimAPL(BiobbObject):
13 """
14 | biobb_mem FatslimAPL
15 | Wrapper of the `FATSLiM area per lipid <https://pythonhosted.org/fatslim/documentation/apl.html>`_ module for area per lipid calculation.
16 | FATSLiM is designed to provide efficient and robust analysis of physical parameters from MD trajectories, with a focus on processing large trajectory files quickly.
18 Args:
19 input_top_path (str): Path to the input topology file. File type: input. `Sample file <https://github.com/bioexcel/biobb_mem/raw/main/biobb_mem/test/data/A01JD/A01JD.pdb>`_. Accepted formats: tpr (edam:format_2333), gro (edam:format_2033), g96 (edam:format_2033), pdb (edam:format_1476), brk (edam:format_2033), ent (edam:format_1476).
20 input_traj_path (str) (Optional): Path to the GROMACS trajectory file. File type: input. `Sample file <https://github.com/bioexcel/biobb_mem/raw/main/biobb_mem/test/data/A01JD/A01JD.xtc>`_. Accepted formats: xtc (edam:format_3875), trr (edam:format_3910), cpt (edam:format_2333), gro (edam:format_2033), g96 (edam:format_2033), pdb (edam:format_1476), tng (edam:format_3876).
21 input_ndx_path (str) (Optional): Path to the input index NDX file for lipid headgroups and the interacting group. File type: input. `Sample file <https://github.com/bioexcel/biobb_mem/raw/main/biobb_mem/test/data/A01JD/headgroups.ndx>`_. Accepted formats: ndx (edam:format_2033).
22 output_csv_path (str): Path to the output CSV file. File type: output. `Sample file <https://github.com/bioexcel/biobb_mem/raw/main/biobb_mem/test/reference/fatslim/apl.csv>`_. Accepted formats: csv (edam:format_3752).
23 properties (dic - Python dictionary object containing the tool parameters, not input/output files):
24 * **lipid_selection** (*str*) - ("not protein and element P") Headgroups MDAnalysis `selection <https://docs.mdanalysis.org/stable/documentation_pages/selections.html>`_.
25 * **protein_selection** (*str*) - ("protein and not element H") Protein selection interacting with the membrane.
26 * **cutoff** (*float*) - (3) This option allows user to specify the cutoff distance (in nm) to be used when performing the neighbor search needed by the APL calculation algorithm
27 * **limit** (*float*) - (10) This option allows user to specify the upper limit (in nm2) for a valid area per lipid value.
28 * **begin_frame** (*int*) - (-1) First frame index to be used for analysis.
29 * **end_frame** (*int*) - (-1) Last frame index to be used for analysis.
30 * **ignore_no_box** (*bool*) - (False) Ignore the absence of box information in the topology. If the topology does not contain box information, the box will be set to the minimum and maximum positions of the atoms.
31 * **return_hydrogen** (*bool*) - (False) Include hydrogen atoms in the output index file.
32 * **binary_path** (*str*) - ("fatslim") Path to the fatslim executable binary.
33 * **remove_tmp** (*bool*) - (True) [WF property] Remove temporal files.
34 * **restart** (*bool*) - (False) [WF property] Do not execute if output files exist.
35 * **sandbox_path** (*str*) - ("./") [WF property] Parent path to the sandbox directory.
36 * **container_path** (*str*) - (None) Container path definition.
37 * **container_image** (*str*) - ('afandiadib/ambertools:serial') Container image definition.
38 * **container_volume_path** (*str*) - ('/tmp') Container volume path definition.
39 * **container_working_dir** (*str*) - (None) Container working directory definition.
40 * **container_user_id** (*str*) - (None) Container user_id definition.
41 * **container_shell_path** (*str*) - ('/bin/bash') Path to default shell inside the container.
43 Examples:
44 This is a use example of how to use the building block from Python::
46 from biobb_mem.fatslim.fatslim_apl import fatslim_apl
47 prop = {
48 'lipid_selection': '(resname DPPC and name P8)',
49 'cutoff': 3
50 }
51 fatslim_apl(input_top_path='/path/to/myTopology.tpr',
52 input_traj_path='/path/to/myTrajectory.xtc',
53 output_csv_path='/path/to/newIndex.ndx',
54 properties=prop)
56 Info:
57 * wrapped_software:
58 * name: FATSLiM
59 * version: 0.2.2
60 * license: GNU
61 * ontology:
62 * name: EDAM
63 * schema: http://edamontology.org/EDAM.owl
65 """
67 def __init__(self, input_top_path, output_csv_path, input_traj_path=None, input_ndx_path=None, properties=None, **kwargs) -> None:
68 properties = properties or {}
70 # Call parent class constructor
71 super().__init__(properties)
72 self.locals_var_dict = locals().copy()
74 # Input/Output files
75 self.io_dict = {
76 "in": {"input_top_path": input_top_path,
77 "input_traj_path": input_traj_path,
78 "input_ndx_path": input_ndx_path},
79 "out": {"output_csv_path": output_csv_path}
80 }
82 # Properties specific for BB
83 self.lipid_selection = properties.get('lipid_selection', "not protein and element P")
84 self.protein_selection = properties.get('protein_selection', "protein and not element H")
85 self.cutoff = properties.get('cutoff', 3)
86 self.limit = properties.get('cutoff', 10)
87 self.begin_frame = properties.get('begin_frame', -1)
88 self.end_frame = properties.get('end_frame', -1)
89 self.ignore_no_box = properties.get('ignore_no_box', False)
90 self.binary_path = properties.get('binary_path', 'fatslim')
91 self.properties = properties
93 # Check the properties
94 self.check_properties(properties)
95 self.check_arguments()
97 @launchlogger
98 def launch(self) -> int:
99 """Execute the :class:`FatslimAPL <fatslim.fatslim_apl.FatslimAPL>` object."""
101 # Setup Biobb
102 if self.check_restart():
103 return 0
104 self.stage_files()
106 unique_dir = self.stage_io_dict.get("unique_dir", "")
107 if self.container_path:
108 working_dir = self.container_volume_path if self.container_volume_path else "/data"
109 else:
110 working_dir = unique_dir
112 host_top_path = str(Path(unique_dir).joinpath(PurePath(self.io_dict["in"]["input_top_path"]).name))
113 host_traj_path = None
114 if self.io_dict["in"].get("input_traj_path"):
115 host_traj_path = str(Path(unique_dir).joinpath(PurePath(self.io_dict["in"]["input_traj_path"]).name))
117 # Create index file using MDAnalysis
118 u = mda.Universe(topology=host_top_path, coordinates=host_traj_path)
119 ignore_no_box(u, self.ignore_no_box, self.out_log, self.global_log)
121 # Build the index to select the atoms from the membrane
122 if self.stage_io_dict["in"].get('input_ndx_path', None):
123 tmp_ndx = self.stage_io_dict["in"]["input_ndx_path"]
124 else:
125 tmp_ndx = str(Path(unique_dir).joinpath('_apl_inp.ndx'))
126 with mda.selections.gromacs.SelectionWriter(tmp_ndx, mode='w') as ndx:
127 ndx.write(u.select_atoms(self.lipid_selection), name='headgroups')
128 ndx.write(u.select_atoms(self.protein_selection), name='protein')
130 if self.stage_io_dict["in"]["input_top_path"].endswith('gro'):
131 cfg = self.stage_io_dict["in"]["input_top_path"]
133 else:
134 # Convert topology .gro and add box dimensions if not available in the topology
135 cfg = str(Path(unique_dir).joinpath('_output.gro'))
136 # Save as GRO file with box information
137 u.atoms.write(cfg)
139 tmp_csv = str(Path(unique_dir).joinpath('_out.csv'))
141 cmd_prefix = ["cd", working_dir, ";"]
142 if not self.container_path and PurePath(self.binary_path).name == "fatslim":
143 # FATSLiM 0.2.2 uses deprecated NumPy aliases removed in modern NumPy versions.
144 fatslim_compat = Path(unique_dir).joinpath('fatslim_numpy_compat.py')
145 with open(fatslim_compat, 'w') as compat_script:
146 compat_script.write('import sys\n')
147 compat_script.write('import numpy as np\n')
148 compat_script.write('if not hasattr(np, "int"):\n')
149 compat_script.write(' np.int = int\n')
150 compat_script.write('from fatslimlib import main\n')
151 compat_script.write('sys.exit(main(sys.argv[1:]))\n')
152 binary_cmd = [sys.executable, PurePath(fatslim_compat).name]
153 else:
154 binary_cmd = [self.binary_path]
156 # Build command
157 self.cmd = cmd_prefix + binary_cmd + [
158 "apl",
159 "-n", PurePath(tmp_ndx).name,
160 "-c", PurePath(cfg).name,
161 "--export-apl-raw", PurePath(tmp_csv).name,
162 "--apl-cutoff", str(self.cutoff),
163 "--apl-limit", str(self.limit),
164 "--begin-frame", str(self.begin_frame),
165 "--end-frame", str(self.end_frame)
166 ]
168 # Run Biobb block
169 self.run_biobb()
170 staged_output_csv = str(Path(unique_dir).joinpath(PurePath(self.stage_io_dict["out"]["output_csv_path"]).name))
171 move_output_file(tmp_csv, staged_output_csv,
172 self.out_log, self.global_log)
173 # Copy files to host
174 self.copy_to_host()
175 # Remove temporary files
176 self.remove_tmp_files()
177 self.check_arguments(output_files_created=True, raise_exception=False)
179 return self.return_code
182def fatslim_apl(input_top_path: str,
183 output_csv_path: str,
184 input_traj_path: str = None,
185 input_ndx_path: str = None,
186 properties: dict = None,
187 **kwargs) -> int:
188 """Execute the :class:`FatslimAPL <fatslim.fatslim_apl.FatslimAPL>` class and
189 execute the :meth:`launch() <fatslim.fatslim_apl.FatslimAPL.launch>` method."""
190 return FatslimAPL(**dict(locals())).launch()
193fatslim_apl.__doc__ = FatslimAPL.__doc__
194main = FatslimAPL.get_main(fatslim_apl, 'Calculate the area per lipid.')
196if __name__ == '__main__':
197 main()