emdbva 0.0.1.dev127__tar.gz → 0.0.1.dev129__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.
- {emdbva-0.0.1.dev127/emdbva.egg-info → emdbva-0.0.1.dev129}/PKG-INFO +1 -1
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129/emdbva.egg-info}/PKG-INFO +1 -1
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/va/preparation.py +38 -5
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/va/utils/ChimeraxViews.py +10 -3
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/va/utils/stars.py +174 -1
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/va/validationanalysis.py +175 -23
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/va/version.py +1 -1
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/LICENSE +0 -0
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/MANIFEST.in +0 -0
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/README.rst +0 -0
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/emdbva.egg-info/SOURCES.txt +0 -0
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/emdbva.egg-info/dependency_links.txt +0 -0
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/emdbva.egg-info/entry_points.txt +0 -0
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/emdbva.egg-info/requires.txt +0 -0
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/emdbva.egg-info/top_level.txt +0 -0
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/setup.cfg +0 -0
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/setup.py +0 -0
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/va/__init__.py +0 -0
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/va/mainva.py +0 -0
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/va/metrics/__init__.py +0 -0
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/va/metrics/bars.py +0 -0
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/va/metrics/connected_percentage.py +0 -0
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/va/metrics/contour_level_predicator.py +0 -0
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/va/metrics/emda_mmcc.py +0 -0
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/va/metrics/emringer.py +0 -0
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/va/metrics/inclusion.py +0 -0
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/va/metrics/overlap_percentage.py +0 -0
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/va/metrics/phaserandomization.py +0 -0
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/va/metrics/phenix_cc.py +0 -0
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/va/metrics/phenix_mm.py +0 -0
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/va/metrics/projections.py +0 -0
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/va/metrics/qscore.py +0 -0
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/va/metrics/residue_locres.py +0 -0
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/va/metrics/resmap.py +0 -0
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/va/metrics/smoc.py +0 -0
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/va/metrics/strudel.py +0 -0
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/va/metrics/surfaces.py +0 -0
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/va/metrics/threedfsc.py +0 -0
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/va/qscores.csv +0 -0
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/va/utils/Checker.py +0 -0
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/va/utils/MapProcessor.py +0 -0
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/va/utils/Model.py +0 -0
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/va/utils/__init__.py +0 -0
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/va/utils/cl_weights.pth +0 -0
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/va/utils/log_utils.py +0 -0
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/va/utils/misc.py +0 -0
- {emdbva-0.0.1.dev127 → emdbva-0.0.1.dev129}/va/utils/rescolor.py +0 -0
|
@@ -669,12 +669,44 @@ class PreParation:
|
|
|
669
669
|
block = doc.sole_block()
|
|
670
670
|
|
|
671
671
|
# Extract resolution and reconstruction method
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
672
|
+
rm = block.find_value('_em_experiment.reconstruction_method')
|
|
673
|
+
reconstruction_method = (
|
|
674
|
+
str(rm).replace("'", "").strip().lower()
|
|
675
|
+
if rm and str(rm).strip() not in ('?', '.', '')
|
|
676
|
+
else None
|
|
677
|
+
)
|
|
678
|
+
|
|
679
|
+
# Extract resolution (scalar)
|
|
680
|
+
res = block.find_value('_em_3d_reconstruction.resolution')
|
|
681
|
+
resolution = None
|
|
682
|
+
if res and str(res).strip() not in ('?', '.', ''):
|
|
683
|
+
try:
|
|
684
|
+
resolution = float(str(res).strip().strip("'").strip('"'))
|
|
685
|
+
except ValueError:
|
|
686
|
+
resolution = None
|
|
687
|
+
|
|
688
|
+
# Fallback: try loop column *only if it exists*
|
|
675
689
|
if resolution is None and reconstruction_method != 'tomography':
|
|
676
|
-
|
|
677
|
-
|
|
690
|
+
col = block.find_loop('_em_3d_reconstruction.resolution') # returns Column
|
|
691
|
+
|
|
692
|
+
# If the column is nil, get_loop() will either fail or be useless.
|
|
693
|
+
# So we just try to iterate safely:
|
|
694
|
+
value = None
|
|
695
|
+
try:
|
|
696
|
+
for x in col: # iterates over column values if non-nil
|
|
697
|
+
sx = str(x).strip().strip("'").strip('"')
|
|
698
|
+
if sx not in ('?', '.', ''):
|
|
699
|
+
value = sx
|
|
700
|
+
break
|
|
701
|
+
except Exception:
|
|
702
|
+
value = None
|
|
703
|
+
|
|
704
|
+
if value is not None:
|
|
705
|
+
try:
|
|
706
|
+
resolution = float(value)
|
|
707
|
+
except ValueError:
|
|
708
|
+
resolution = None
|
|
709
|
+
|
|
678
710
|
|
|
679
711
|
# Initialize map containers
|
|
680
712
|
map_data = {'primary': {}, 'mask': {}, 'odd': {}, 'even': {}}
|
|
@@ -701,6 +733,7 @@ class PreParation:
|
|
|
701
733
|
map_types = [map_type]
|
|
702
734
|
except Exception as e:
|
|
703
735
|
# fallback or log error
|
|
736
|
+
print(f'Error parsing map information: {e}')
|
|
704
737
|
contour_levels, map_files, map_types = [], [], []
|
|
705
738
|
|
|
706
739
|
# Parse combined map data
|
|
@@ -475,11 +475,17 @@ class ChimeraxViews:
|
|
|
475
475
|
output_json = {}
|
|
476
476
|
raw_map = f'{self.va_dir}/{map_name[:-4] + "_rawmap.map"}'
|
|
477
477
|
mask_map = f'{self.va_dir}/{map_name}_relion/mask/{map_name}_mask.mrc'
|
|
478
|
+
# if mask does not exist, treat as no mask
|
|
479
|
+
if not os.path.isfile(mask_map):
|
|
480
|
+
mask_map = None
|
|
478
481
|
local_resolution_map_glob = glob.glob(f'{self.va_dir}/{map_name}_relion/*_locres.mrc')
|
|
479
482
|
local_resolution_map = local_resolution_map_glob[0] if len(local_resolution_map_glob) > 0 else None
|
|
480
483
|
map_processor = MapProcessor()
|
|
481
|
-
|
|
482
|
-
|
|
484
|
+
if mask_map:
|
|
485
|
+
binarized_mask_map = map_processor.binarized_mask(mask_map, map_name)
|
|
486
|
+
masked_raw_map = map_processor.mask_map(raw_map, binarized_mask_map)
|
|
487
|
+
else:
|
|
488
|
+
masked_raw_map = raw_map
|
|
483
489
|
map_min, map_max = map_processor.map_minmax(masked_raw_map, local_resolution_map)
|
|
484
490
|
real_min = map_min if map_min < all_models_min_value else all_models_min_value
|
|
485
491
|
real_max = map_max if map_max > all_models_max_value else all_models_max_value
|
|
@@ -487,7 +493,8 @@ class ChimeraxViews:
|
|
|
487
493
|
new_max = scale_value(map_max, real_min, real_max, 0, 1)
|
|
488
494
|
num_elements = 50
|
|
489
495
|
palette_colours = self.generate_palette(new_min, new_max, map_min, map_max, num_elements)
|
|
490
|
-
chimerax_file_name = self.write_maps_cxc(os.path.basename(masked_raw_map), local_resolution_map,
|
|
496
|
+
chimerax_file_name = self.write_maps_cxc(os.path.basename(masked_raw_map), local_resolution_map,
|
|
497
|
+
palette_colours, data_type)
|
|
491
498
|
out = self.run_chimerax(chimerax_file_name)
|
|
492
499
|
surfaces_dict = self.rescale_view(os.path.basename(masked_raw_map), None, None, data_type)
|
|
493
500
|
output_json[f'{data_type}_views'] = surfaces_dict
|
|
@@ -64,6 +64,12 @@ class GetStars:
|
|
|
64
64
|
|
|
65
65
|
return float(self.data_general_block()['_rlnFinalResolution'])
|
|
66
66
|
|
|
67
|
+
def bfactor_sharpen(self):
|
|
68
|
+
"""
|
|
69
|
+
Get the resolution value that Relion is use for the phase randomization calculation
|
|
70
|
+
"""
|
|
71
|
+
return float(self.data_general_block()['_rlnBfactorUsedForSharpening'])
|
|
72
|
+
|
|
67
73
|
def data_fsc_block(self):
|
|
68
74
|
"""
|
|
69
75
|
Get the data_fsc block
|
|
@@ -89,6 +95,73 @@ class GetStars:
|
|
|
89
95
|
|
|
90
96
|
return data_fsc_block
|
|
91
97
|
|
|
98
|
+
def data_guinier_block(self):
|
|
99
|
+
"""
|
|
100
|
+
Get the data_guinier block (RELION postprocess output).
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
dict: { column_name(str): [values...] }
|
|
104
|
+
Example keys (typical RELION):
|
|
105
|
+
- ResolutionSquared
|
|
106
|
+
- LogAmplitudesOriginal
|
|
107
|
+
- LogAmplitudesWeighted
|
|
108
|
+
- LogAmplitudesSharpened
|
|
109
|
+
- LogAmplitudesIntercept
|
|
110
|
+
"""
|
|
111
|
+
if 'data_guinier' not in self.star_blocks:
|
|
112
|
+
return {}
|
|
113
|
+
|
|
114
|
+
lines = [l.strip() for l in self.star_blocks['data_guinier'] if l.strip()]
|
|
115
|
+
if not lines:
|
|
116
|
+
return {}
|
|
117
|
+
|
|
118
|
+
# Find loop_ line
|
|
119
|
+
try:
|
|
120
|
+
loop_idx = lines.index('loop_')
|
|
121
|
+
except ValueError:
|
|
122
|
+
# Sometimes it could be "loop_" with trailing spaces already stripped above,
|
|
123
|
+
# or the block could be non-loop (rare). In that case, return empty for now.
|
|
124
|
+
return {}
|
|
125
|
+
|
|
126
|
+
# Read headers: consecutive lines starting with "_rln"
|
|
127
|
+
header_lines = []
|
|
128
|
+
i = loop_idx + 1
|
|
129
|
+
while i < len(lines) and lines[i].startswith('_rln'):
|
|
130
|
+
header_lines.append(lines[i])
|
|
131
|
+
i += 1
|
|
132
|
+
|
|
133
|
+
# Convert header lines to clean names (strip "_rln" and remove "#n")
|
|
134
|
+
headers = []
|
|
135
|
+
for h in header_lines:
|
|
136
|
+
# e.g. "_rlnResolutionSquared #1" -> "ResolutionSquared"
|
|
137
|
+
parts = h.split()
|
|
138
|
+
tag = parts[0] # "_rlnResolutionSquared"
|
|
139
|
+
headers.append(tag[4:]) # remove "_rln"
|
|
140
|
+
|
|
141
|
+
# Remaining lines are data rows
|
|
142
|
+
data_rows = lines[i:]
|
|
143
|
+
if not data_rows or not headers:
|
|
144
|
+
return {}
|
|
145
|
+
|
|
146
|
+
# Parse rows into columns
|
|
147
|
+
col_values = [[] for _ in headers]
|
|
148
|
+
for row in data_rows:
|
|
149
|
+
vals = row.split()
|
|
150
|
+
if len(vals) < len(headers):
|
|
151
|
+
# skip malformed/short row
|
|
152
|
+
continue
|
|
153
|
+
for ci in range(len(headers)):
|
|
154
|
+
v = vals[ci]
|
|
155
|
+
# RELION usually uses numeric values; be defensive anyway
|
|
156
|
+
try:
|
|
157
|
+
fv = float(v)
|
|
158
|
+
col_values[ci].append(keep_three_significant_digits(fv))
|
|
159
|
+
except Exception:
|
|
160
|
+
col_values[ci].append(v)
|
|
161
|
+
|
|
162
|
+
return dict(zip(headers, col_values))
|
|
163
|
+
|
|
164
|
+
|
|
92
165
|
def data_extra(self, data_fsc_block):
|
|
93
166
|
"""
|
|
94
167
|
Add half bit, one-bit and 3-sigma to data_fsc_block
|
|
@@ -148,6 +221,7 @@ class GetStars:
|
|
|
148
221
|
corrected = data_fsc_block['FourierShellCorrelationCorrected']
|
|
149
222
|
phase_rand = data_fsc_block.get('CorrectedFourierShellCorrelationPhaseRandomizedMaskedMaps', None)
|
|
150
223
|
randomise_from = self.randomise_from()
|
|
224
|
+
sharpen_bfactor = self.bfactor_sharpen()
|
|
151
225
|
|
|
152
226
|
x_gold, y_gold = interpolated_intercept(x, correlation, gold)
|
|
153
227
|
x_half, y_half = interpolated_intercept(x, correlation, half)
|
|
@@ -214,7 +288,8 @@ class GetStars:
|
|
|
214
288
|
'phase_randomized_0.143': {'x': x_phase_gold, 'y': y_phase_gold},
|
|
215
289
|
'phase_randomized_half': {'x': x_phase_half, 'y': y_phase_half},
|
|
216
290
|
'phase_randomized_halfbit': {'x': x_phase_halfbit, 'y': y_phase_halfbit},
|
|
217
|
-
'randomise_from': randomise_from
|
|
291
|
+
'randomise_from': randomise_from,
|
|
292
|
+
'sharpen_bfactor': sharpen_bfactor
|
|
218
293
|
}
|
|
219
294
|
}
|
|
220
295
|
|
|
@@ -240,6 +315,14 @@ class GetStars:
|
|
|
240
315
|
'fsc_corrected': 'FourierShellCorrelationCorrected'
|
|
241
316
|
}
|
|
242
317
|
curves = {key: data_fsc_block[value] for key, value in curve_mapping.items() if value in data_fsc_block}
|
|
318
|
+
|
|
319
|
+
# incorporate any guinier curves returned by data_guinier_block()
|
|
320
|
+
guinier = self.data_guinier_block()
|
|
321
|
+
if guinier:
|
|
322
|
+
# add guinier columns into curves; avoid overwriting existing keys
|
|
323
|
+
for gk, gv in guinier.items():
|
|
324
|
+
curves[f'guinier_{str(gk).lower()}'] = gv
|
|
325
|
+
|
|
243
326
|
final_curves = {'curves': curves}
|
|
244
327
|
|
|
245
328
|
return final_curves
|
|
@@ -315,6 +398,7 @@ class GetStars:
|
|
|
315
398
|
plt.plot(levels, golden_line, linestyle='-.', label='0.143')
|
|
316
399
|
plt.legend(loc='upper right', fontsize='x-small')
|
|
317
400
|
plt.savefig(self.va_dir + '/current_Relion_fsc.png')
|
|
401
|
+
print(f'FSC curve saved to {self.va_dir}/current_Relion_fsc.png')
|
|
318
402
|
plt.close()
|
|
319
403
|
|
|
320
404
|
def plot_feature_zone(self, intersections, levels, corrected_curve, phase_rand_curve):
|
|
@@ -365,6 +449,95 @@ class GetStars:
|
|
|
365
449
|
plt.close()
|
|
366
450
|
|
|
367
451
|
return feature_area, overfit_area
|
|
452
|
+
|
|
453
|
+
def plot_guinier(self, guinier_block=None, save_path=None, show=False):
|
|
454
|
+
"""
|
|
455
|
+
Plot Guinier curves (Log amplitudes vs ResolutionSquared).
|
|
456
|
+
|
|
457
|
+
Parameters:
|
|
458
|
+
guinier_block (dict): output from self.data_guinier_block(). If None, the method will call it.
|
|
459
|
+
save_path (str): full path to save the image. If None, saves to `self.va_dir/current_Relion_guinier.png`.
|
|
460
|
+
show (bool): if True, call plt.show() before closing.
|
|
461
|
+
Returns:
|
|
462
|
+
str or None: path to saved image or None if no data.
|
|
463
|
+
"""
|
|
464
|
+
if guinier_block is None:
|
|
465
|
+
guinier_block = self.data_guinier_block()
|
|
466
|
+
if not guinier_block:
|
|
467
|
+
print('No guinier data to plot')
|
|
468
|
+
return None
|
|
469
|
+
|
|
470
|
+
# prefer canonical key name
|
|
471
|
+
x_key = None
|
|
472
|
+
for candidate in ('ResolutionSquared', 'resolutionSquared', 'Resolution_Squared', 'Resolution'):
|
|
473
|
+
if candidate in guinier_block:
|
|
474
|
+
x_key = candidate
|
|
475
|
+
break
|
|
476
|
+
if x_key is None:
|
|
477
|
+
print('No resolution column found in guinier data')
|
|
478
|
+
return None
|
|
479
|
+
|
|
480
|
+
try:
|
|
481
|
+
x = np.array(guinier_block[x_key], dtype=float)
|
|
482
|
+
except Exception:
|
|
483
|
+
print('Resolution column contains non-numeric data')
|
|
484
|
+
return None
|
|
485
|
+
|
|
486
|
+
# detect weighted column to filter out -99 sentinel rows
|
|
487
|
+
weighted_key = next((k for k in guinier_block.keys() if 'weighted' in k.lower()), None)
|
|
488
|
+
mask = None
|
|
489
|
+
if weighted_key is not None:
|
|
490
|
+
try:
|
|
491
|
+
weighted_arr = np.array(guinier_block[weighted_key], dtype=float)
|
|
492
|
+
mask = weighted_arr != -99
|
|
493
|
+
if not np.any(mask):
|
|
494
|
+
print('All weighted values are -99; no guinier data to plot')
|
|
495
|
+
return None
|
|
496
|
+
# apply mask to x
|
|
497
|
+
x = x[mask]
|
|
498
|
+
except Exception:
|
|
499
|
+
mask = None
|
|
500
|
+
|
|
501
|
+
# pick numeric columns excluding the x column
|
|
502
|
+
y_keys = [k for k in guinier_block.keys() if k != x_key]
|
|
503
|
+
if not y_keys:
|
|
504
|
+
print('No guinier amplitude columns to plot')
|
|
505
|
+
return None
|
|
506
|
+
|
|
507
|
+
plt.figure(figsize=(6, 4))
|
|
508
|
+
for key in y_keys:
|
|
509
|
+
try:
|
|
510
|
+
y = np.array(guinier_block[key], dtype=float)
|
|
511
|
+
except Exception:
|
|
512
|
+
# skip non-numeric series
|
|
513
|
+
continue
|
|
514
|
+
if mask is not None:
|
|
515
|
+
# ensure same length before applying mask
|
|
516
|
+
if y.shape[0] != mask.shape[0]:
|
|
517
|
+
# skip series with mismatched length
|
|
518
|
+
continue
|
|
519
|
+
y = y[mask]
|
|
520
|
+
if y.size == 0 or x.size == 0 or x.shape[0] != y.shape[0]:
|
|
521
|
+
# skip empty or mismatched series
|
|
522
|
+
continue
|
|
523
|
+
plt.plot(x, y, linestyle='-', label=key)
|
|
524
|
+
|
|
525
|
+
plt.xlabel(x_key)
|
|
526
|
+
plt.ylabel('Log Amplitude')
|
|
527
|
+
plt.title('Guinier plot')
|
|
528
|
+
plt.legend(loc='best', fontsize='x-small')
|
|
529
|
+
plt.grid(True)
|
|
530
|
+
|
|
531
|
+
out_path = save_path or f'{self.va_dir}/current_Relion_guinier.png'
|
|
532
|
+
plt.tight_layout()
|
|
533
|
+
plt.savefig(out_path)
|
|
534
|
+
if show:
|
|
535
|
+
plt.show()
|
|
536
|
+
plt.close()
|
|
537
|
+
print(f'Guinier plot saved to {out_path}')
|
|
538
|
+
return out_path
|
|
539
|
+
|
|
540
|
+
|
|
368
541
|
@staticmethod
|
|
369
542
|
def area_difference(curve_one, curve_two, levels):
|
|
370
543
|
"""
|
|
@@ -293,7 +293,11 @@ class ValidationAnalysis:
|
|
|
293
293
|
star = GetStars(star_file_dir)
|
|
294
294
|
nomask_resolution = star.final_resolution()
|
|
295
295
|
# For cases where Relion resolution is too high, use the input resolution
|
|
296
|
-
|
|
296
|
+
if self.resolution is not None:
|
|
297
|
+
try:
|
|
298
|
+
nomask_resolution = min(nomask_resolution, 15 * float(self.resolution))
|
|
299
|
+
except (TypeError, ValueError):
|
|
300
|
+
pass
|
|
297
301
|
raw_map_name = find_rawmap_file(self.workdir)
|
|
298
302
|
filtered_raw_map = self.get_lowpassed_map(f'{self.workdir}/{raw_map_name}', nomask_resolution)
|
|
299
303
|
relion_mask_name = relion_mask(filtered_raw_map, relion_mask_dir, self.mapname)
|
|
@@ -3845,6 +3849,7 @@ class ValidationAnalysis:
|
|
|
3845
3849
|
star.plot_fsc(data_curves, (xlist, ylist))
|
|
3846
3850
|
else:
|
|
3847
3851
|
star.plot_fsc(data_curves)
|
|
3852
|
+
star.plot_guinier()
|
|
3848
3853
|
data_intersections = star.all_intersection(data_fsc_block)
|
|
3849
3854
|
|
|
3850
3855
|
fsc_dict = {**data_curves, **data_intersections, **zones}
|
|
@@ -6464,93 +6469,233 @@ class ValidationAnalysis:
|
|
|
6464
6469
|
def phenix_mmfsc(self):
|
|
6465
6470
|
"""
|
|
6466
6471
|
Run Phenix map-model FSC calculation
|
|
6472
|
+
Now also supports:
|
|
6473
|
+
- raw map (existing)
|
|
6474
|
+
- half map odd
|
|
6475
|
+
- half map even
|
|
6467
6476
|
:return:
|
|
6468
6477
|
"""
|
|
6469
6478
|
|
|
6470
|
-
if self.platform == 'emdb' and self.met != 'tomo' and self.met != 'crys'
|
|
6479
|
+
if self.platform == 'emdb' and self.met != 'tomo' and self.met != 'crys':
|
|
6471
6480
|
start = timeit.default_timer()
|
|
6472
6481
|
errlist = []
|
|
6482
|
+
|
|
6473
6483
|
result_dict = {}
|
|
6474
6484
|
raw_result_dict = {}
|
|
6475
|
-
|
|
6485
|
+
odd_result_dict = {}
|
|
6486
|
+
even_result_dict = {}
|
|
6487
|
+
|
|
6476
6488
|
if self.models:
|
|
6477
6489
|
nummodels = 0
|
|
6490
|
+
|
|
6478
6491
|
allresults = {}
|
|
6479
6492
|
raw_allresults = {}
|
|
6493
|
+
odd_allresults = {}
|
|
6494
|
+
even_allresults = {}
|
|
6495
|
+
|
|
6480
6496
|
for model in self.models:
|
|
6497
|
+
# prepare some vars so they always exist
|
|
6498
|
+
rerr = None
|
|
6499
|
+
mmfsclog = None
|
|
6500
|
+
|
|
6501
|
+
raw_rerr = None
|
|
6502
|
+
raw_mmfsclog = None
|
|
6503
|
+
|
|
6504
|
+
odd_rerr = None
|
|
6505
|
+
odd_mmfsclog = None
|
|
6506
|
+
|
|
6507
|
+
even_rerr = None
|
|
6508
|
+
even_mmfsclog = None
|
|
6509
|
+
|
|
6481
6510
|
try:
|
|
6482
6511
|
full_model = '{}{}'.format(self.workdir, os.path.basename(model.filename))
|
|
6483
6512
|
full_map = '{}{}'.format(self.workdir, self.mapname)
|
|
6484
6513
|
out_path = '{}_phenix'.format(full_model)
|
|
6514
|
+
|
|
6515
|
+
# -------------------------
|
|
6516
|
+
# Primary map mmFSC (existing)
|
|
6517
|
+
# -------------------------
|
|
6485
6518
|
rerr = run_phenixmmfsc(full_model, full_map, out_path)
|
|
6486
6519
|
tmmfsclog = '{}/fsc_model.unmasked.mtriage.log'.format(out_path)
|
|
6487
6520
|
mmfsclog = '{}/fsc_model.unmasked.mtriage_{}.log'.format(out_path, self.mapname)
|
|
6488
6521
|
change_filename(tmmfsclog, mmfsclog)
|
|
6489
|
-
|
|
6490
|
-
|
|
6522
|
+
|
|
6523
|
+
# -------------------------
|
|
6524
|
+
# Raw map mmFSC (existing behavior)
|
|
6525
|
+
# NOTE: your code checks self.hmodd and self.hmeven to decide raw.
|
|
6526
|
+
# If you actually mean "if rawmap exists", replace condition with "if self.rawmap"
|
|
6527
|
+
# -------------------------
|
|
6491
6528
|
if self.hmodd and self.hmeven:
|
|
6492
6529
|
raw_full_map = self.rawmap.fullname
|
|
6493
6530
|
raw_mapname = os.path.basename(raw_full_map)
|
|
6494
6531
|
raw_rerr = run_phenixmmfsc(full_model, raw_full_map, out_path)
|
|
6532
|
+
tmmfsclog = '{}/fsc_model.unmasked.mtriage.log'.format(out_path)
|
|
6495
6533
|
raw_mmfsclog = '{}/fsc_model.unmasked.mtriage_{}.log'.format(out_path, raw_mapname)
|
|
6496
6534
|
change_filename(tmmfsclog, raw_mmfsclog)
|
|
6535
|
+
|
|
6536
|
+
# -------------------------
|
|
6537
|
+
# Half-map odd/even mmFSC (NEW)
|
|
6538
|
+
# -------------------------
|
|
6539
|
+
if self.hmodd and self.hmeven:
|
|
6540
|
+
# odd
|
|
6541
|
+
odd_full_map = getattr(self.hmodd, "fullname", self.hmodd)
|
|
6542
|
+
odd_mapname = os.path.basename(odd_full_map)
|
|
6543
|
+
odd_rerr = run_phenixmmfsc(full_model, odd_full_map, out_path)
|
|
6544
|
+
tmmfsclog = '{}/fsc_model.unmasked.mtriage.log'.format(out_path)
|
|
6545
|
+
odd_mmfsclog = '{}/fsc_model.unmasked.mtriage_{}.log'.format(out_path, odd_mapname)
|
|
6546
|
+
change_filename(tmmfsclog, odd_mmfsclog)
|
|
6547
|
+
|
|
6548
|
+
# even
|
|
6549
|
+
even_full_map = getattr(self.hmeven, "fullname", self.hmeven)
|
|
6550
|
+
even_mapname = os.path.basename(even_full_map)
|
|
6551
|
+
even_rerr = run_phenixmmfsc(full_model, even_full_map, out_path)
|
|
6552
|
+
tmmfsclog = '{}/fsc_model.unmasked.mtriage.log'.format(out_path)
|
|
6553
|
+
even_mmfsclog = '{}/fsc_model.unmasked.mtriage_{}.log'.format(out_path, even_mapname)
|
|
6554
|
+
change_filename(tmmfsclog, even_mmfsclog)
|
|
6555
|
+
|
|
6497
6556
|
end = timeit.default_timer()
|
|
6498
6557
|
print('Phenix mmFSC time: %s' % (end - start))
|
|
6499
6558
|
print('------------------------------------')
|
|
6559
|
+
|
|
6500
6560
|
except:
|
|
6501
6561
|
err = 'Phenix mmFSC calculation error: {}.'.format(sys.exc_info()[1])
|
|
6502
6562
|
errlist.append(err)
|
|
6503
6563
|
sys.stderr.write(err + '\n')
|
|
6564
|
+
|
|
6504
6565
|
nyquist = 1 / (2 * self.map.voxel_size.tolist()[0])
|
|
6505
|
-
try:
|
|
6506
|
-
df = read_mmfsc(mmfsclog, rerr)
|
|
6507
|
-
mmfscdict = mmfscdf_todict(df, nyquist)
|
|
6508
6566
|
|
|
6509
|
-
|
|
6510
|
-
|
|
6567
|
+
# -------------------------
|
|
6568
|
+
# Parse + collect results (Primary)
|
|
6569
|
+
# -------------------------
|
|
6570
|
+
try:
|
|
6571
|
+
if mmfsclog is not None and rerr is not None:
|
|
6572
|
+
df = read_mmfsc(mmfsclog, rerr)
|
|
6573
|
+
mmfscdict = mmfscdf_todict(df, nyquist)
|
|
6574
|
+
|
|
6575
|
+
allresults[str(nummodels)] = {
|
|
6576
|
+
'name': os.path.basename(model.filename),
|
|
6577
|
+
'data': mmfscdict
|
|
6578
|
+
}
|
|
6579
|
+
except:
|
|
6580
|
+
err = 'Save Phenix mmFSC data error: {}.'.format(sys.exc_info()[1])
|
|
6581
|
+
errlist.append(err)
|
|
6582
|
+
sys.stderr.write(err + '\n')
|
|
6511
6583
|
|
|
6512
|
-
|
|
6584
|
+
# -------------------------
|
|
6585
|
+
# Parse + collect results (Raw)
|
|
6586
|
+
# -------------------------
|
|
6587
|
+
try:
|
|
6588
|
+
if self.hmodd and self.hmeven and raw_mmfsclog is not None and raw_rerr is not None:
|
|
6513
6589
|
raw_df = read_mmfsc(raw_mmfsclog, raw_rerr)
|
|
6514
6590
|
raw_mmfscdict = mmfscdf_todict(raw_df, nyquist)
|
|
6515
6591
|
|
|
6516
|
-
raw_allresults[str(nummodels)] = {
|
|
6517
|
-
|
|
6592
|
+
raw_allresults[str(nummodels)] = {
|
|
6593
|
+
'name': os.path.basename(model.filename),
|
|
6594
|
+
'data': raw_mmfscdict
|
|
6595
|
+
}
|
|
6596
|
+
except:
|
|
6597
|
+
err = 'Save raw Phenix mmFSC data error: {}.'.format(sys.exc_info()[1])
|
|
6598
|
+
errlist.append(err)
|
|
6599
|
+
sys.stderr.write(err + '\n')
|
|
6600
|
+
|
|
6601
|
+
# -------------------------
|
|
6602
|
+
# Parse + collect results (Half odd) NEW
|
|
6603
|
+
# -------------------------
|
|
6604
|
+
try:
|
|
6605
|
+
if self.hmodd and self.hmeven and odd_mmfsclog is not None and odd_rerr is not None:
|
|
6606
|
+
odd_df = read_mmfsc(odd_mmfsclog, odd_rerr)
|
|
6607
|
+
odd_mmfscdict = mmfscdf_todict(odd_df, nyquist)
|
|
6608
|
+
|
|
6609
|
+
odd_allresults[str(nummodels)] = {
|
|
6610
|
+
'name': os.path.basename(model.filename),
|
|
6611
|
+
'data': odd_mmfscdict
|
|
6612
|
+
}
|
|
6613
|
+
except:
|
|
6614
|
+
err = 'Save half-odd Phenix mmFSC data error: {}.'.format(sys.exc_info()[1])
|
|
6615
|
+
errlist.append(err)
|
|
6616
|
+
sys.stderr.write(err + '\n')
|
|
6518
6617
|
|
|
6618
|
+
# -------------------------
|
|
6619
|
+
# Parse + collect results (Half even) NEW
|
|
6620
|
+
# -------------------------
|
|
6621
|
+
try:
|
|
6622
|
+
if self.hmodd and self.hmeven and even_mmfsclog is not None and even_rerr is not None:
|
|
6623
|
+
even_df = read_mmfsc(even_mmfsclog, even_rerr)
|
|
6624
|
+
even_mmfscdict = mmfscdf_todict(even_df, nyquist)
|
|
6625
|
+
|
|
6626
|
+
even_allresults[str(nummodels)] = {
|
|
6627
|
+
'name': os.path.basename(model.filename),
|
|
6628
|
+
'data': even_mmfscdict
|
|
6629
|
+
}
|
|
6519
6630
|
except:
|
|
6520
|
-
err = 'Save Phenix mmFSC data error: {}.'.format(sys.exc_info()[1])
|
|
6631
|
+
err = 'Save half-even Phenix mmFSC data error: {}.'.format(sys.exc_info()[1])
|
|
6521
6632
|
errlist.append(err)
|
|
6522
6633
|
sys.stderr.write(err + '\n')
|
|
6634
|
+
|
|
6523
6635
|
nummodels += 1
|
|
6524
6636
|
|
|
6637
|
+
# -------------------------
|
|
6638
|
+
# Build output dicts (same pattern you used)
|
|
6639
|
+
# -------------------------
|
|
6525
6640
|
if allresults:
|
|
6526
6641
|
result_dict['mmfsc'] = allresults
|
|
6642
|
+
|
|
6527
6643
|
if raw_allresults:
|
|
6528
6644
|
raw_result_dict['raw_mmfsc'] = raw_allresults
|
|
6529
6645
|
|
|
6646
|
+
if odd_allresults:
|
|
6647
|
+
odd_result_dict['half_odd_mmfsc'] = odd_allresults
|
|
6648
|
+
|
|
6649
|
+
if even_allresults:
|
|
6650
|
+
even_result_dict['half_even_mmfsc'] = even_allresults
|
|
6651
|
+
|
|
6530
6652
|
if errlist:
|
|
6653
|
+
# keep your behavior: errors only attached to result_dict
|
|
6531
6654
|
result_dict['err'] = errlist
|
|
6532
6655
|
|
|
6656
|
+
# -------------------------
|
|
6657
|
+
# Write JSON files (same gating logic you used)
|
|
6658
|
+
# -------------------------
|
|
6533
6659
|
if len(result_dict) == 1 and 'mmfsc' in result_dict:
|
|
6534
6660
|
try:
|
|
6535
|
-
with codecs.open(self.workdir + self.mapname + '_mmfsc.json', 'w',
|
|
6536
|
-
encoding='utf-8') as f:
|
|
6661
|
+
with codecs.open(self.workdir + self.mapname + '_mmfsc.json', 'w', encoding='utf-8') as f:
|
|
6537
6662
|
json.dump(result_dict, f)
|
|
6538
6663
|
except:
|
|
6539
6664
|
sys.stderr.write('Saving to mmFSC json error: {}.\n'.format(sys.exc_info()[1]))
|
|
6540
|
-
|
|
6541
6665
|
else:
|
|
6542
6666
|
print('mmFSC was not collected, please check the error!')
|
|
6543
6667
|
|
|
6544
6668
|
if len(raw_result_dict) == 1 and 'raw_mmfsc' in raw_result_dict:
|
|
6545
6669
|
try:
|
|
6546
|
-
with codecs.open(self.workdir + self.mapname + '_raw_mmfsc.json', 'w',
|
|
6547
|
-
encoding='utf-8') as f:
|
|
6670
|
+
with codecs.open(self.workdir + self.mapname + '_raw_mmfsc.json', 'w', encoding='utf-8') as f:
|
|
6548
6671
|
json.dump(raw_result_dict, f)
|
|
6549
6672
|
except:
|
|
6550
6673
|
sys.stderr.write('Saving to raw mmFSC json error: {}.\n'.format(sys.exc_info()[1]))
|
|
6674
|
+
else:
|
|
6675
|
+
if self.hmodd and self.hmeven:
|
|
6676
|
+
print('Raw map mmFSC was not collected, please check the error!')
|
|
6677
|
+
|
|
6678
|
+
if len(odd_result_dict) == 1 and 'half_odd_mmfsc' in odd_result_dict:
|
|
6679
|
+
try:
|
|
6680
|
+
with codecs.open(self.workdir + self.mapname + '_half_odd_mmfsc.json', 'w',
|
|
6681
|
+
encoding='utf-8') as f:
|
|
6682
|
+
json.dump(odd_result_dict, f)
|
|
6683
|
+
except:
|
|
6684
|
+
sys.stderr.write('Saving to half-odd mmFSC json error: {}.\n'.format(sys.exc_info()[1]))
|
|
6685
|
+
else:
|
|
6686
|
+
if self.hmodd and self.hmeven:
|
|
6687
|
+
print('Half-odd map mmFSC was not collected, please check the error!')
|
|
6551
6688
|
|
|
6689
|
+
if len(even_result_dict) == 1 and 'half_even_mmfsc' in even_result_dict:
|
|
6690
|
+
try:
|
|
6691
|
+
with codecs.open(self.workdir + self.mapname + '_half_even_mmfsc.json', 'w',
|
|
6692
|
+
encoding='utf-8') as f:
|
|
6693
|
+
json.dump(even_result_dict, f)
|
|
6694
|
+
except:
|
|
6695
|
+
sys.stderr.write('Saving to half-even mmFSC json error: {}.\n'.format(sys.exc_info()[1]))
|
|
6552
6696
|
else:
|
|
6553
|
-
|
|
6697
|
+
if self.hmodd and self.hmeven:
|
|
6698
|
+
print('Half-even map mmFSC was not collected, please check the error!')
|
|
6554
6699
|
|
|
6555
6700
|
else:
|
|
6556
6701
|
print('No model!!')
|
|
@@ -6558,6 +6703,7 @@ class ValidationAnalysis:
|
|
|
6558
6703
|
|
|
6559
6704
|
return None
|
|
6560
6705
|
|
|
6706
|
+
|
|
6561
6707
|
@profile_peak_memory()
|
|
6562
6708
|
def locres_resmap(self):
|
|
6563
6709
|
"""
|
|
@@ -6633,10 +6779,16 @@ class ValidationAnalysis:
|
|
|
6633
6779
|
result_dict = {}
|
|
6634
6780
|
errlist = []
|
|
6635
6781
|
start = timeit.default_timer()
|
|
6782
|
+
local_res = None
|
|
6636
6783
|
if self.platform == 'emdb' and self.met != 'tomo' and self.hmodd and self.hmeven:
|
|
6637
|
-
|
|
6638
|
-
|
|
6639
|
-
|
|
6784
|
+
try:
|
|
6785
|
+
res_val = float(self.resolution) if self.resolution is not None else None
|
|
6786
|
+
except (TypeError, ValueError):
|
|
6787
|
+
res_val = None
|
|
6788
|
+
if res_val is not None:
|
|
6789
|
+
local_res = localres_histogram(self.hmodd.fullname, self.mapname, res_val)
|
|
6790
|
+
else:
|
|
6791
|
+
local_res = None
|
|
6640
6792
|
|
|
6641
6793
|
if local_res:
|
|
6642
6794
|
result_dict['local_res_histogram'] = local_res
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|