Coverage for model_workflow/analyses/lipid_interactions.py: 100%
35 statements
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-23 10:54 +0000
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-23 10:54 +0000
1from model_workflow.tools.get_reduced_trajectory import calculate_frame_step
2from model_workflow.utils.mda_spells import to_MDAnalysis_topology
3from model_workflow.utils.auxiliar import save_json
4from model_workflow.utils.constants import OUTPUT_LIPID_INTERACTIONS_FILENAME
5from model_workflow.utils.type_hints import *
6from collections import Counter
7import numpy as np
8import MDAnalysis
10def lipid_interactions (
11 trajectory_file : 'File',
12 standard_topology_file : 'File',
13 output_directory : str,
14 membrane_map: dict,
15 lipid_map: dict,
16 snapshots : int,
17 frames_limit: int = 100):
18 """
19 Lipid-protein interactions analysis.
20 """
21 if membrane_map is None or membrane_map['n_mems'] == 0:
22 print('-> Skipping lipid-protein interactions analysis')
23 return
25 # Set the main output filepath
26 output_analysis_filepath = f'{output_directory}/{OUTPUT_LIPID_INTERACTIONS_FILENAME}'
28 mda_top = to_MDAnalysis_topology(standard_topology_file)
29 u = MDAnalysis.Universe(mda_top, trajectory_file.path)
30 frame_step, frame_count = calculate_frame_step(snapshots, frames_limit)
31 lipids = set([ lipid['resname'] for lipid in lipid_map])
32 lipids_str = " ".join(lipids)
33 resids = np.unique(u.select_atoms('protein').resindices)
34 ocupancy = {resid: Counter() for resid in resids}
36 # Only iterate through the frames you need
37 for ts in u.trajectory[0:snapshots:frame_step]:
38 # Select non-protein atoms near the protein once
39 non_protein_near = u.select_atoms(f'(around 6 protein) and (resname {lipids_str}) and not protein')
40 # Make residue selections only once
41 for resid in resids:
42 residue_atoms = u.select_atoms(f'resid {resid}')
43 # Find non-protein atoms near this specific residue
44 nearby = non_protein_near.select_atoms(f'around 6 global group residuegroup',
45 residuegroup=residue_atoms)
46 # Count residue names
47 ocupancy[resid].update(Counter(nearby.residues.resnames))
49 ocupancy_arrs = {lipid: np.zeros(len(ocupancy)) for lipid in lipids}
50 for resid, counter in ocupancy.items():
51 for lipid, count in counter.items():
52 ocupancy_arrs[lipid][resid] = count
54 # Normalize the occupancy arrays by dividing by the number of frames
55 for lipid in lipids:
56 ocupancy_arrs[lipid] /= frame_count
57 ocupancy_arrs[lipid] = ocupancy_arrs[lipid].tolist()
58 # Save the data
59 data = { 'data': ocupancy_arrs}
60 save_json(data, output_analysis_filepath)