emdbva 0.0.1.dev140__tar.gz → 0.0.1.dev143__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. {emdbva-0.0.1.dev140/emdbva.egg-info → emdbva-0.0.1.dev143}/PKG-INFO +1 -1
  2. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143/emdbva.egg-info}/PKG-INFO +1 -1
  3. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/emdbva.egg-info/SOURCES.txt +1 -0
  4. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/setup.py +1 -1
  5. emdbva-0.0.1.dev143/va/PATHS_codon_airflow.py +80 -0
  6. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/va/mainva.py +11 -3
  7. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/va/metrics/bars.py +40 -0
  8. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/va/metrics/connected_percentage.py +30 -0
  9. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/va/metrics/contour_level_predicator.py +38 -1
  10. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/va/metrics/phaserandomization.py +30 -2
  11. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/va/metrics/phenix_cc.py +18 -11
  12. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/va/metrics/phenix_mm.py +14 -5
  13. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/va/metrics/projections.py +72 -0
  14. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/va/metrics/qscore.py +13 -5
  15. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/va/metrics/resmap.py +33 -8
  16. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/va/metrics/smoc.py +11 -4
  17. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/va/metrics/strudel.py +1 -0
  18. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/va/preparation.py +44 -22
  19. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/va/prepareandrun_codon_airflow.py +115 -201
  20. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/va/utils/Checker.py +56 -1
  21. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/va/utils/ChimeraxViews.py +8 -1
  22. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/va/utils/MapProcessor.py +16 -4
  23. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/va/utils/Model.py +5 -1
  24. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/va/utils/misc.py +16 -13
  25. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/va/utils/rescolor.py +17 -1
  26. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/va/utils/stars.py +4 -1
  27. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/va/validationanalysis.py +113 -25
  28. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/va/version.py +1 -1
  29. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/LICENSE +0 -0
  30. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/MANIFEST.in +0 -0
  31. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/README.rst +0 -0
  32. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/emdbva.egg-info/dependency_links.txt +0 -0
  33. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/emdbva.egg-info/entry_points.txt +0 -0
  34. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/emdbva.egg-info/requires.txt +0 -0
  35. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/emdbva.egg-info/top_level.txt +0 -0
  36. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/setup.cfg +0 -0
  37. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/va/__init__.py +0 -0
  38. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/va/metrics/__init__.py +0 -0
  39. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/va/metrics/emda_mmcc.py +0 -0
  40. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/va/metrics/emringer.py +0 -0
  41. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/va/metrics/inclusion.py +0 -0
  42. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/va/metrics/map_data_validation.py +0 -0
  43. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/va/metrics/overlap_percentage.py +0 -0
  44. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/va/metrics/residue_locres.py +0 -0
  45. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/va/metrics/surfaces.py +0 -0
  46. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/va/metrics/threedfsc.py +0 -0
  47. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/va/qscores.csv +0 -0
  48. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/va/utils/__init__.py +0 -0
  49. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/va/utils/cl_weights.pth +0 -0
  50. {emdbva-0.0.1.dev140 → emdbva-0.0.1.dev143}/va/utils/log_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: emdbva
3
- Version: 0.0.1.dev140
3
+ Version: 0.0.1.dev143
4
4
  Summary: CryoEM validation toolkit
5
5
  Home-page: https://test.pypi.org/project/va/
6
6
  Author: Zhe Wang
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: emdbva
3
- Version: 0.0.1.dev140
3
+ Version: 0.0.1.dev143
4
4
  Summary: CryoEM validation toolkit
5
5
  Home-page: https://test.pypi.org/project/va/
6
6
  Author: Zhe Wang
@@ -8,6 +8,7 @@ emdbva.egg-info/dependency_links.txt
8
8
  emdbva.egg-info/entry_points.txt
9
9
  emdbva.egg-info/requires.txt
10
10
  emdbva.egg-info/top_level.txt
11
+ va/PATHS_codon_airflow.py
11
12
  va/__init__.py
12
13
  va/mainva.py
13
14
  va/preparation.py
@@ -20,7 +20,7 @@ setup(
20
20
  version=__version__,
21
21
  packages=find_packages(),
22
22
  exclude_package_data={
23
- 'va': ['test/*', 'va/onedepva.py', 'core/*', 'proc/*', 'validation/*', 'test_data/*'],
23
+ 'va': ['test/*', 'core/*', 'proc/*', 'validation/*', 'test_data/*'],
24
24
  },
25
25
  include_package_data=True,
26
26
  author="Zhe Wang",
@@ -0,0 +1,80 @@
1
+ """
2
+ PATHS.py
3
+
4
+
5
+ PATHS is used to input and output directories of validation
6
+ analysis.
7
+
8
+ Copyright [2013] EMBL - European Bioinformatics Institute
9
+ Licensed under the Apache License, Version 2.0 (the
10
+ "License"); you may not use this file except in
11
+ compliance with the License. You may obtain a copy of
12
+ the License at
13
+ http://www.apache.org/licenses/LICENSE-2.0
14
+ Unless required by applicable law or agreed to in writing,
15
+ software distributed under the License is distributed on
16
+ an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17
+ KIND, either express or implied. See the License for the
18
+ specific language governing permissions and limitations
19
+ under the License.
20
+
21
+ """
22
+
23
+ __author__ = 'Zhe Wang'
24
+ __email__ = 'zhe@ebi.ac.uk'
25
+ __date__ = '2022-06-14'
26
+
27
+ # ENT file source path
28
+ ENTSOURCE = '/nfs/msd/work2/ftp/pdb/data/structures/all/pdb/'
29
+
30
+ # VTP file source path
31
+ VTPSOURCE = '/nfs/pdbe_staging/pdbe_data/development/staging/em/'
32
+
33
+ # CIF file source path
34
+ # CIFSOURCE = '/nfs/production/gerard/pdbe/prerelease/current/ftp/pdb/data/structures/divided/mmCIF/'
35
+ # CIFSOURCE = '/nfs/ftp/public/.staging/pdbe-G79Bblrm/projects/pdb/staging/data/structures/all/mmCIF/'
36
+ # CIFSOURCE = '/hps/nobackup/pdbe/nfs_prod/ftp/data/structures/all/mmCIF/'
37
+ CIFSOURCE = '/nfs/production/gerard/pdbe/ftp/pdb/data/structures/all/mmCIF/'
38
+
39
+ MAP_SERVER_PATH = '/hps/nobackup/gerard/emdb/va/entry_results/'
40
+
41
+ # Chimera path
42
+ # CHIMERA = '/hps/nobackup/gerard/emdb/va/external/chimerax/usr/libexec/UCSF-ChimeraX/bin/ChimeraX'
43
+ CHIMERA = '/hps/nobackup/gerard/emdb/va/external/chimera110/usr/libexec/UCSF-ChimeraX/bin/ChimeraX'
44
+
45
+ # Original or old Chimera
46
+ OCHIMERA = '/hps/nobackup/gerard/emdb/va/external/chimera/bin/chimera'
47
+
48
+ # For ebi server to copy data for VA
49
+ # VASOURCE = '/nfs/msd/em/ftp_rsync/staging/structures/'
50
+ # VASOURCE = '/nfs/production/gerard/emdb/archive/staging/structures/'
51
+ # VASOURCE = '/hps/nobackup/gerard/emdb/archive/local/structures/'
52
+ VASOURCE = '/nfs/production/gerard/emdb/archive2/local/structures/'
53
+
54
+ # VAPATH
55
+ VAPATH = '/hps/nobackup/gerard/emdb/va_airflow/Validation-Analysis/va/'
56
+
57
+ # Jsons and images are copied to here for display purpose
58
+ FORDISPLAY = '/nfs/nobackup/msd/em_va/development/'
59
+
60
+ # Proshade path
61
+ PROSHADEPATH = '/hps/software/users/gerard/emdb/va/external/ccpem/ccpem-1.6.0/bin/proshade'
62
+
63
+ # Meshmaker path
64
+ MESHMAKERPATH = '/nfs/msd/em/software/meshmakertest/meshmaker/build/meshmaker'
65
+
66
+ # VA production path
67
+ VA_PROD_PATH = '/nfs/public/rw/pdbe/httpd-em/sessions-prod/validation_analysis'
68
+
69
+ # VA staging path
70
+ VA_STAG_PATH = '/nfs/public/rw/pdbe/httpd-em/sessions/validation_analysis'
71
+
72
+ # Strudel lib
73
+ LIB_STRUDEL_ROOT = '/hps/nobackup/gerard/emdb/va/external/strudel_motiflib/strudel-lib.4_0.5px'
74
+
75
+ # 3DFSC fake to take positions
76
+ THREEDFSC_ROOT = '/Users/zhe/Downloads/Anisotropy/ThreeDFSC/ThreeDFSC_Start.py'
77
+
78
+ # ResMap
79
+ # RESMAP = '/hps/nobackup/gerard/emdb/va/external/resmap/ResMap_project/ResMap.py'
80
+ RESMAP = '/hps/software/users/gerard/emdb/va/external/ccpem/ccpem-1.6.0/bin/relion_postprocess'
@@ -3,8 +3,10 @@
3
3
  """
4
4
  mainva.py
5
5
 
6
- mainva class used to run the main function of validation
7
- analysis
6
+ Entry points and orchestration helpers for the main VA pipeline.
7
+
8
+ This module wires together preparation, validation analysis, and
9
+ logging for the standard package-level VA workflow.
8
10
 
9
11
  Copyright [2013] EMBL - European Bioinformatics Institute
10
12
  Licensed under the Apache License, Version 2.0 (the
@@ -170,6 +172,7 @@ def inallruns(validationobj, runs):
170
172
  """
171
173
 
172
174
  def without_strudel():
175
+ """Run the selected validation steps other than Strudel."""
173
176
  # Projections
174
177
  if 'projection' in runs:
175
178
  validationobj.orthogonal_projections()
@@ -255,6 +258,7 @@ def inallruns(validationobj, runs):
255
258
  return None
256
259
 
257
260
  def strudel_only():
261
+ """Run the selected Strudel validation step."""
258
262
  # Strudel
259
263
  if 'strudel' in runs:
260
264
  validationobj.strudel()
@@ -333,6 +337,11 @@ def reconfigure_logging(temp_logger, buffer, log_file):
333
337
 
334
338
  # @profile
335
339
  def main():
340
+ """Run the main VA command-line entry point.
341
+
342
+ This function parses the CLI arguments, builds the preparation and
343
+ validation objects, and drives the configured validation runs.
344
+ """
336
345
 
337
346
  start_first = timeit.default_timer()
338
347
 
@@ -443,4 +452,3 @@ def main():
443
452
 
444
453
  if __name__ == '__main__':
445
454
  main()
446
-
@@ -1,3 +1,5 @@
1
+ """Calculate score percentiles and generate metric comparison plots."""
2
+
1
3
  import os.path
2
4
  import json
3
5
  import pandas as pd
@@ -317,6 +319,22 @@ def plot_bar_mat(a, b, qmin, qmax, qscore, work_dir, plot_name, score_type, resb
317
319
 
318
320
 
319
321
  def bar(new_entry_dict, score_type, work_dir, score_dir, plot_name, update_bin_file=None):
322
+ """Calculate whole-dataset and resolution-relative score percentiles.
323
+
324
+ Args:
325
+ new_entry_dict: Score entry containing the selected score and resolution.
326
+ score_type: Score column to process.
327
+ work_dir: Directory for generated plot output.
328
+ score_dir: Directory containing the default score CSV.
329
+ plot_name: Plot filename used when a bar plot is generated.
330
+ update_bin_file: Optional CSV used to update the resolution-bin size.
331
+
332
+ Returns:
333
+ tuple: Whole-dataset statistics, relative-resolution statistics, and bin size.
334
+
335
+ Raises:
336
+ ValueError: If no usable score CSV is available.
337
+ """
320
338
  if update_bin_file and os.path.isfile(update_bin_file):
321
339
  input_file = update_bin_file
322
340
  else:
@@ -391,6 +409,11 @@ def score_whole(new_entry, df, score_type='qscore'):
391
409
 
392
410
 
393
411
  def score_relative(new_entry, df, score_type='qscore', column='resolution', bin=0.5):
412
+ """Calculate a score percentile within a resolution range.
413
+
414
+ Returns:
415
+ tuple: Relative percentile and number of rows in the selected range.
416
+ """
394
417
  df_relative = get_resolution_range(new_entry, df, score_type, column, bin)
395
418
  if df_relative.empty: # Handle case where df_relative is empty
396
419
  return 0., 0. # Return NaN for q_relative and an empty list for row_indices
@@ -401,10 +424,16 @@ def score_relative(new_entry, df, score_type='qscore', column='resolution', bin=
401
424
  return q_relative, rows
402
425
 
403
426
  def score_relative_wrapper(args):
427
+ """Unpack arguments for parallel relative-score calculation."""
404
428
  x, df, score_type, column, bin = args
405
429
  return score_relative(x, df, score_type, column, bin)
406
430
 
407
431
  def fast_qscore_resolution_bin(df_resolution_sorted, score_type='qscore'):
432
+ """Add relative-score columns for a series of resolution-bin sizes.
433
+
434
+ Returns:
435
+ pandas.DataFrame: The input DataFrame with calculated relative-score columns.
436
+ """
408
437
  values = [round(x, 1) for x in np.arange(0.1, 1.6, 0.1)]
409
438
  for value in values:
410
439
  args_list = [
@@ -417,6 +446,11 @@ def fast_qscore_resolution_bin(df_resolution_sorted, score_type='qscore'):
417
446
  return df_resolution_sorted
418
447
 
419
448
  def find_optimal_correlation_index(arr):
449
+ """Return the index of the value closest to -0.3 among eligible values.
450
+
451
+ Returns:
452
+ int or None: Selected index, or ``None`` if no value exceeds -0.3.
453
+ """
420
454
  arr = np.asarray(arr)
421
455
  mask = arr > -0.3
422
456
  if not np.any(mask):
@@ -426,6 +460,11 @@ def find_optimal_correlation_index(arr):
426
460
  return np.where(arr == closest_value)[0][0]
427
461
 
428
462
  def resolution_qrelative_correlation(df_resolution_sorted, values, score_type='qscore'):
463
+ """Calculate correlations between resolution and relative-score columns.
464
+
465
+ Returns:
466
+ tuple: Correlations below 5, correlations above 5, and column names.
467
+ """
429
468
  correlation_below_5 = []
430
469
  correlation_above_5 = []
431
470
  col_names = []
@@ -463,6 +502,7 @@ def resolution_qrelative_correlation(df_resolution_sorted, values, score_type='q
463
502
  return correlation_below_5, correlation_above_5, col_names
464
503
 
465
504
  def get_resolution_bin_size_fromva(score_file):
505
+ """Read a score CSV and return its recorded resolution-bin mode."""
466
506
  df = pd.read_csv(score_file, dtype={'id': str, 'resolution': float, 'name': str, 'qscore': float}, usecols=[0, 1, 2, 3])
467
507
  df = df.dropna()
468
508
  df_resolution_sorted = df.sort_values(by='resolution')
@@ -1,12 +1,34 @@
1
+ """Measure connected and removed regions in thresholded MRC volumes."""
2
+
1
3
  import numpy as np
2
4
  import mrcfile
3
5
  from scipy.ndimage import label, find_objects
4
6
 
5
7
 
6
8
  def estimate_diameter_bbox(coords_physical):
9
+ """Estimate a point set's diameter from its axis-aligned bounding box.
10
+
11
+ Args:
12
+ coords_physical: Array of physical-space coordinates.
13
+
14
+ Returns:
15
+ float: Euclidean distance between opposite bounding-box corners.
16
+ """
7
17
  return np.linalg.norm(coords_physical.max(axis=0) - coords_physical.min(axis=0))
8
18
 
9
19
  def detect_small_blobs(volume, threshold, min_diameter, voxel_size=1.0, connectivity=2):
20
+ """Keep thresholded connected regions whose bounding-box diameter is large enough.
21
+
22
+ Args:
23
+ volume: Three-dimensional volume array.
24
+ threshold: Value used to create the binary foreground mask.
25
+ min_diameter: Minimum physical diameter to retain.
26
+ voxel_size: Physical size of one voxel.
27
+ connectivity: Connectivity mode used for labeling.
28
+
29
+ Returns:
30
+ tuple: Cleaned boolean mask and the number of removed voxels.
31
+ """
10
32
  binary = volume > threshold
11
33
  structure = np.ones((3, 3, 3)) if connectivity == 3 else None
12
34
  labeled, _ = label(binary, structure=structure)
@@ -26,6 +48,14 @@ def detect_small_blobs(volume, threshold, min_diameter, voxel_size=1.0, connecti
26
48
  return cleaned, total_removed_voxels
27
49
 
28
50
  def compute_connected_metrics(mrc_path, threshold, min_diameter=5.0, voxel_size=None, connectivity=2):
51
+ """Calculate connected and disconnected volume percentages from an MRC file.
52
+
53
+ The MRC volume is read from ``mrc_path``; the returned metrics are calculated
54
+ after removing regions below the requested diameter.
55
+
56
+ Returns:
57
+ dict: Connected and disconnected percentages and volumes.
58
+ """
29
59
  with mrcfile.open(mrc_path, permissive=True) as mrc:
30
60
  volume = mrc.data.copy()
31
61
  if voxel_size is None:
@@ -1,3 +1,5 @@
1
+ """Predict contour levels from normalized three-dimensional map volumes."""
2
+
1
3
  import os
2
4
  os.environ['KMP_DUPLICATE_LIB_OK'] = 'True'
3
5
  import torch
@@ -14,7 +16,10 @@ warnings.filterwarnings("ignore", message="User provided device_type of 'cuda',
14
16
 
15
17
  # Convolutional layers adapted from https://www.nature.com/articles/s41598-022-19212-6
16
18
  class CNNModel(nn.Module):
19
+ """Three-dimensional convolutional model used for contour prediction."""
20
+
17
21
  def __init__(self):
22
+ """Initialize the convolutional and fully connected layers."""
18
23
  super(CNNModel, self).__init__()
19
24
  self.conv = nn.Sequential(
20
25
  nn.Conv3d(1, 32, 7, 1, padding_mode='replicate'),
@@ -42,6 +47,7 @@ class CNNModel(nn.Module):
42
47
  nn.Linear(in_features=64, out_features=1))
43
48
 
44
49
  def forward(self, x):
50
+ """Run a forward pass on a batch of 64-by-64-by-64 volumes."""
45
51
  x = x.view(-1, 1, 64, 64, 64)
46
52
  x = self.conv(x)
47
53
  x = x.view(x.size(0), -1)
@@ -50,10 +56,19 @@ class CNNModel(nn.Module):
50
56
 
51
57
 
52
58
  def check_boxsize(vol):
59
+ """Return the first dimension of a volume array."""
53
60
  return vol.shape[0]
54
61
 
55
62
 
56
63
  def load_data(vol_d_norm):
64
+ """Wrap a normalized volume in a single-item PyTorch data loader.
65
+
66
+ Args:
67
+ vol_d_norm: Normalized three-dimensional volume.
68
+
69
+ Returns:
70
+ DataLoader: Single-item loader for model prediction.
71
+ """
57
72
  vol_array = np.empty(shape=(1, 64, 64, 64), dtype=np.float32)
58
73
  vol_array[:] = vol_d_norm
59
74
  data_generator = torch.utils.data.DataLoader(vol_array, batch_size=1, shuffle=False)
@@ -61,6 +76,7 @@ def load_data(vol_d_norm):
61
76
 
62
77
 
63
78
  def downsample(vol):
79
+ """Downsample a volume to 64 cubed voxels in Fourier space."""
64
80
  boxsize = check_boxsize(vol)
65
81
  vol_ft = np.fft.fftshift(np.fft.fftn(np.fft.fftshift(vol)))
66
82
  start = boxsize // 2 - 64 // 2
@@ -75,6 +91,7 @@ def downsample(vol):
75
91
 
76
92
  def upsample(
77
93
  vol): # through interpolation of maps in Fourier space; based on https://www.sciencedirect.com/science/article/pii/S001046551400335X
94
+ """Pad a volume in Fourier space to the model's 64 cubed input size."""
78
95
  boxsize = check_boxsize(vol)
79
96
  new_box_size = 64
80
97
  vol_ft = np.fft.fftshift(np.fft.fftn(np.fft.fftshift(vol)))
@@ -87,6 +104,11 @@ def upsample(
87
104
 
88
105
 
89
106
  def normalize(vol_data):
107
+ """Clip and normalize positive volume values for model input.
108
+
109
+ Returns:
110
+ tuple: Normalized volume and the lower and upper scaling values.
111
+ """
90
112
  d_upper = np.percentile(vol_data, 99.999)
91
113
  d_lower = np.percentile(vol_data, 0.001)
92
114
  vol_data = np.where(vol_data > d_upper, d_upper, vol_data)
@@ -109,6 +131,14 @@ model.load_state_dict(checkpoint['model_state_dict'])
109
131
 
110
132
 
111
133
  def model_pred(data_generator):
134
+ """Run the loaded model over a data loader without gradient tracking.
135
+
136
+ Args:
137
+ data_generator: Data loader containing normalized volume batches.
138
+
139
+ Returns:
140
+ list: Model prediction tensors collected for each batch.
141
+ """
112
142
  model.eval()
113
143
  pred_list = []
114
144
  with torch.no_grad():
@@ -122,6 +152,14 @@ def model_pred(data_generator):
122
152
 
123
153
 
124
154
  def calc_level_dev(vol_data):
155
+ """Predict contour levels after resizing the volume to model dimensions.
156
+
157
+ Args:
158
+ vol_data: Three-dimensional volume array.
159
+
160
+ Returns:
161
+ numpy.ndarray: Predicted contour-level values rescaled to input units.
162
+ """
125
163
  boxsize = check_boxsize(vol_data)
126
164
 
127
165
  if boxsize > 64:
@@ -154,4 +192,3 @@ def calc_level_dev(vol_data):
154
192
 
155
193
 
156
194
 
157
-
@@ -1,3 +1,5 @@
1
+ """Create RELION masks and FSC inputs from map volumes."""
2
+
1
3
  from va.utils.ChimeraxViews import *
2
4
  from va.utils.misc import find_rawmap_file
3
5
  import numpy as np
@@ -57,6 +59,14 @@ def check_mrc(input_map):
57
59
 
58
60
  @profile_peak_memory()
59
61
  def relion_mask(raw_map, out_dir, mapname=None):
62
+ """Create a RELION mask and a locally generated comparison mask.
63
+
64
+ The function invokes the RELION mask executable when available and writes
65
+ the resulting mask into ``out_dir``.
66
+
67
+ Returns:
68
+ str or None: Generated mask path when successful.
69
+ """
60
70
  relion_mask_executable_name = 'relion_mask_create'
61
71
  relion_mask_executable = find_executable(relion_mask_executable_name)
62
72
  if relion_mask_executable:
@@ -140,7 +150,9 @@ def relion_fsc(mapone, maptwo, mask_file=None, out_dir=None):
140
150
  def relion_fsc_calculation(mapone, maptwo, root, mapname=None):
141
151
  """
142
152
  Calculates FSc using Relion
143
- return: data dictionary of fsc
153
+
154
+ Returns:
155
+ dict: Data dictionary containing the FSC result.
144
156
  """
145
157
 
146
158
  result_type = 'fsc'
@@ -166,6 +178,7 @@ def relion_fsc_calculation(mapone, maptwo, root, mapname=None):
166
178
  return None
167
179
 
168
180
  def get_voxel_size(input_map):
181
+ """Return the x-axis voxel size read from an MRC map."""
169
182
 
170
183
  try:
171
184
  with mrcfile.open(input_map, permissive=True) as mrc:
@@ -193,6 +206,18 @@ def calculate_pixels(angpix):
193
206
 
194
207
  # following is the Python version of Relion auto masking
195
208
  def relion_auto_mask_fast(data, threshold, extend_pixels, edge_width, verbose=True):
209
+ """Build a soft-edged binary mask from an in-memory volume array.
210
+
211
+ Args:
212
+ data: Volume array to threshold.
213
+ threshold: Initial density threshold.
214
+ extend_pixels: Number of pixels to extend or shrink the mask.
215
+ edge_width: Width of the soft edge in pixels.
216
+ verbose: Whether to display progress messages.
217
+
218
+ Returns:
219
+ numpy.ndarray: Floating-point mask array.
220
+ """
196
221
  steps = []
197
222
  if verbose:
198
223
  steps = tqdm(total=3, desc="Masking Steps", unit="step")
@@ -239,6 +264,10 @@ def relion_auto_mask_fast(data, threshold, extend_pixels, edge_width, verbose=Tr
239
264
 
240
265
  @profile_peak_memory()
241
266
  def relion_auto_mask(input_file, output_file, threshold, extend_pixels, edge_width, verbose=True):
267
+ """Create an MRC mask file from an input MRC volume.
268
+
269
+ The input voxel size is copied to the output file.
270
+ """
242
271
  with mrcfile.open(input_file) as mrc:
243
272
  data = mrc.data.copy()
244
273
  voxel_size = mrc.voxel_size.copy()
@@ -251,4 +280,3 @@ def relion_auto_mask(input_file, output_file, threshold, extend_pixels, edge_wid
251
280
 
252
281
  if verbose:
253
282
  print(f"== Mask saved to {output_file} ==")
254
-
@@ -146,8 +146,13 @@ def run_phenixcc(full_modelpath, full_mappath, resolution, output_path, echo=Tru
146
146
  def read_cc(cc_per_residue_log, errlist):
147
147
  """
148
148
  Read the residue-wise CCC from the output of Phenix results
149
- :param: cc_per_residue_log input file cc_per_residue.log file(full path name) from Phenix CC calculation
150
- :return:
149
+
150
+ Args:
151
+ cc_per_residue_log: Full path to the Phenix residue-wise CCC log.
152
+ errlist: Errors collected during the Phenix calculation.
153
+
154
+ Returns:
155
+ pandas.DataFrame or None: Parsed residue-wise CCC data when available.
151
156
  """
152
157
 
153
158
  if not errlist and os.path.isfile(cc_per_residue_log):
@@ -176,8 +181,12 @@ def _floatohex(numlist):
176
181
  def ccdf_todict(ccdf):
177
182
  """
178
183
  Given the Phenix CC result in dataframe and output the dict to be save in json
179
- :param ccdf: phenix cc_per_residue.log result into dataframe
180
- :return: dict which contain CC per residue results
184
+
185
+ Args:
186
+ ccdf: Phenix residue-wise CCC results in a dataframe.
187
+
188
+ Returns:
189
+ dict: Residue-wise and chain-level CC results.
181
190
  """
182
191
 
183
192
  finaldict = {}
@@ -208,13 +217,11 @@ def _safe_float(x):
208
217
 
209
218
  def parse_phenix_map_model_cc_output(stdout_text):
210
219
  """
211
- Parse phenix.map_model_cc stdout and extract:
212
- - overall CCs: CC_mask, CC_volume, CC_peaks, CC_box
213
- - per-chain local CC table
214
- - (optional) main-chain / side-chain summaries
215
- - (optional) map resolution
216
- - paths to logs that Phenix says it saved
217
- Returns a dict; missing fields will be None or empty lists.
220
+ Parse phenix.map_model_cc stdout and extract overall CCs, per-chain local
221
+ CC values, optional chain summaries, map resolution, and reported log paths.
222
+
223
+ Returns:
224
+ dict: Parsed values; missing fields are ``None`` or empty lists.
218
225
  """
219
226
  result = {
220
227
  "resolution": None,
@@ -55,8 +55,13 @@ def run_phenixmmfsc(full_modelpath, full_mappath, output_path):
55
55
  def read_mmfsc(mmfsc_log, errlist):
56
56
  """
57
57
  Read the residue-wise CCC from the output of Phenix results
58
- :param: cc_per_residue_log input file cc_per_residue.log file(full path name) from Phenix CC calculation
59
- :return:
58
+
59
+ Args:
60
+ mmfsc_log: Full path to the Phenix map-model FSC log.
61
+ errlist: Errors collected during the Phenix calculation.
62
+
63
+ Returns:
64
+ pandas.DataFrame or None: Parsed data when available.
60
65
  """
61
66
 
62
67
  if not errlist and os.path.isfile(mmfsc_log):
@@ -145,8 +150,13 @@ def all_intersection(allcurves):
145
150
  def mmfscdf_todict(mmfscdf, nyquist):
146
151
  """
147
152
  Given the Phenix CC result in dataframe and output the dict to be save in json
148
- :param ccdf: phenix cc_per_residue.log result into dataframe
149
- :return: dict which contain CC per residue results
153
+
154
+ Args:
155
+ mmfscdf: Phenix map-model FSC results in a dataframe.
156
+ nyquist: Maximum frequency value to retain.
157
+
158
+ Returns:
159
+ dict: FSC curves and their intersections.
150
160
  """
151
161
 
152
162
  real_mmfscdf = mmfscdf[mmfscdf[0] <= nyquist].round(3).drop_duplicates()
@@ -168,4 +178,3 @@ def mmfscdf_todict(mmfscdf, nyquist):
168
178
  finaldict = {'curves': curves, 'intersections': intersections}
169
179
 
170
180
  return finaldict
171
-