Coverage for mddb_workflow/analyses/thickness.py: 62%
53 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-10-29 15:48 +0000
« prev ^ index » next coverage.py v7.11.0, created at 2025-10-29 15:48 +0000
1from biobb_mem.lipyphilic_biobb.lpp_zpositions import lpp_zpositions, frame_df
2from mddb_workflow.utils.pyt_spells import get_reduced_pytraj_trajectory
3from mddb_workflow.utils.auxiliar import save_json, load_json
4from mddb_workflow.utils.constants import OUTPUT_THICKNESS_FILENAME
5from mddb_workflow.utils.type_hints import *
6from contextlib import redirect_stdout
7import os
10def thickness (
11 structure_file : 'File',
12 trajectory_file : 'File',
13 output_directory : str,
14 membrane_map: dict,
15 snapshots : int,
16 frames_limit: int = 100):
17 """Membrane thickness analysis."""
19 if membrane_map is None or membrane_map['n_mems'] == 0:
20 print('-> Skipping thickness analysis')
21 return
23 # Set the main output filepath
24 output_analysis_filepath = f'{output_directory}/{OUTPUT_THICKNESS_FILENAME}'
26 tj, frame_step, frames_count = get_reduced_pytraj_trajectory(
27 structure_file.path, trajectory_file.path, snapshots, frames_limit)
28 head_sel = []
29 for n in range(membrane_map['n_mems']):
30 head_sel.extend(membrane_map['mems'][str(n)]['polar_atoms']['top'])
31 head_sel.extend(membrane_map['mems'][str(n)]['polar_atoms']['bot'])
32 head_sel_mda = 'index ' + " ".join(map(str,(head_sel)))
33 # Run the analysis on the whole membrane
34 prop = {
35 'lipid_sel': head_sel_mda,
36 'steps': frame_step,
37 'height_sel': head_sel_mda,
38 'ignore_no_box': True,
39 'disable_logs': True,
40 'disable_sandbox': True,
41 }
42 print(' Running BioBB LiPyphilic ZPositions')
43 with redirect_stdout(None):
44 lpp_zpositions(input_top_path=structure_file.path,
45 input_traj_path=trajectory_file.path,
46 output_positions_path='.zpositions.csv',
47 properties=prop)
48 df = frame_df('.zpositions.csv') # Per frame data
49 os.remove('.zpositions.csv')
51 # Calculate the mean z position of midplane wrt the box axis using pytraj
52 midplane_z = []
53 for i in range(0, frames_count):
54 frame = tj[i]
55 selected_atoms = frame[head_sel]
56 mean_z = selected_atoms.mean(axis=0)[2]
57 midplane_z.append(float(mean_z))
58 # Save the data
59 data = { 'data':{
60 'frame': df.index.tolist(),
61 'mean_positive': df['mean_positive'].tolist(),
62 'mean_negative': df['mean_negative'].tolist(),
63 'std_positive': df['std_positive'].tolist(),
64 'std_negative': df['std_negative'].tolist(),
65 'thickness': df['thickness'].tolist(),
66 'std_thickness': df['std_thickness'].tolist(),
67 'midplane_z': midplane_z,
68 'step': frame_step
69 }
70 }
71 save_json(data, output_analysis_filepath)
74def plot_thickness(output_analysis_filepath):
75 import matplotlib.pyplot as plt
77 data = load_json(output_analysis_filepath)["data"]
79 # Extract data for plotting
80 frames = data['frame']
81 thickness = data['thickness']
82 std_thickness = data['std_thickness']
83 midplane_z = data['midplane_z']
84 mean_positive = data['mean_positive']
85 mean_negative = data['mean_negative']
86 std_positive = data['std_positive']
87 std_negative = data['std_negative']
89 # Create the plot
90 plt.figure(figsize=(12, 8))
92 # Plot thickness with error bars
93 plt.errorbar(frames, thickness, yerr=std_thickness, label='Thickness', fmt='-o', capsize=3)
95 # Plot midplane z position
96 plt.plot(frames, midplane_z, label='Midplane Z', linestyle='--', color='orange')
98 # Plot mean positive and mean negative with error bars
99 eb1= plt.errorbar(frames, mean_positive, yerr=std_positive, label='Mean Positive', fmt='-o', color='green', capsize=3)
100 eb1[-1][0].set_linestyle('--')
101 eb2 = plt.errorbar(frames, mean_negative, yerr=std_negative, label='Mean Negative', fmt='-o', color='red', capsize=3)
102 eb2[-1][0].set_linestyle('--')
104 # Add labels, legend, and title
105 plt.xlabel('Frame'); plt.ylabel('Value')
106 plt.title('Membrane Thickness, Midplane Z Position, and Mean Positive/Negative with Errors')
107 plt.legend(); plt.grid(); plt.show()