Source code for xmipp3.protocols.protocol_volume_consensus

# -*- coding: utf-8 -*-
# **************************************************************************
# *
# * Authors:  Estrella Fernandez Gimenez (me.fernandez@cnb.csic.es)
# *
# * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
# *
# * This program is free software; you can redistribute it and/or modify
# * it under the terms of the GNU General Public License as published by
# * the Free Software Foundation; either version 2 of the License, or
# * (at your option) any later version.
# *
# * This program is distributed in the hope that it will be useful,
# * but WITHOUT ANY WARRANTY; without even the implied warranty of
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# * GNU General Public License for more details.
# *
# * You should have received a copy of the GNU General Public License
# * along with this program; if not, write to the Free Software
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
# * 02111-1307  USA
# *
# *  All comments concerning this program package may be sent to the
# *  e-mail address 'scipion@cnb.csic.es'
# *
# **************************************************************************

from os.path import exists
from pyworkflow.protocol.params import MultiPointerParam
from pwem.objects import Volume, Transform
from pwem.protocols import ProtInitialVolume

CITE = 'Fernandez-Gimenez2021'

[docs]class XmippProtVolConsensus(ProtInitialVolume): """ This protocol performs a fusion of all the input volumes, which should be preprocessed with protocol 'volume substraction' saving volume 2, in order to be as similar as possible before the fusion. The output of this protocol is the consensus volume and another volume which indicates the maximun difference between input volumes in each voxel. AI Generated ## Overview The Volume Consensus protocol fuses several input volumes into a single consensus volume. When several maps represent the same structure or related reconstructions, it can be useful to combine them into one consensus map. This protocol takes a set of input volumes and computes a consensus volume from them. It also produces a second volume that represents the maximum difference between the input volumes at each voxel. The consensus volume summarizes the common density shared by the input maps. The difference volume helps identify regions where the input volumes disagree. This protocol is intended for volumes that have already been made comparable. The code help specifically indicates that the input volumes should preferably be preprocessed with the **Volume subtraction** workflow, saving the adjusted second volume, so that the volumes are as similar as possible before fusion. ## Inputs and General Workflow The protocol requires a list of input volumes. It writes the file names of all selected volumes to an input list and then runs the Xmipp consensus-volume program. The program creates two output maps: - a consensus volume; - a difference volume. The protocol registers both maps as Scipion output volumes. It also creates a ChimeraX command script that opens both volumes and colors the consensus volume according to the difference map. ## Input Volumes The **Volumes** parameter defines the set of volumes to be fused. All input volumes should represent the same structure or comparable structural states. They should be aligned, have the same box size, have the same voxel size, and share a consistent origin. The protocol validates that all input volumes have the same pixel size. If the pixel sizes differ, it reports an error. If the box size, voxel size, or origin are not compatible, the consensus volume may not be generated correctly. In that case, the protocol raises an error asking the user to check that the input volumes have equal box size, voxel size, and origin. ## Preparing Volumes for Consensus The input volumes should be as comparable as possible before running this protocol. In practice, this means that they should usually be: - aligned to the same coordinate frame; - sampled at the same voxel size; - placed in the same box size; - normalized or adjusted to comparable amplitudes; - filtered or processed consistently. The protocol documentation in the code notes that the volumes are expected to have been preprocessed with **Volume subtraction**, saving Volume 2, so that they are as similar as possible before the consensus step. This preparation is important because the consensus operation assumes that differences between maps are meaningful, not caused by mismatched scale, origin, orientation, or box size. ## Consensus Volume The main output is **outputVolume**. This volume is written as: `consensus_volume.mrc` It represents the fused consensus map obtained from the selected input volumes. The output volume is assigned the sampling rate of the first input volume. The consensus volume can be used for visualization, comparison, or downstream processing when the user wants a single representative map derived from several related input maps. ## Difference Volume The second output is **outputVolumeDiff**. This volume is written as: `consensus_volume_diff.mrc` It represents the maximum difference between the input volumes at each voxel. This map is useful for identifying regions where the input volumes disagree. High values in the difference volume indicate regions with stronger variation among the input maps. Low values indicate regions where the input volumes are more similar. ## ChimeraX Visualization Script The protocol creates a ChimeraX command script named: `result_fusion_chimera.cxc` This script opens the consensus volume and the difference volume. It hides the difference volume and colors the consensus volume by sampling values from the difference map using a rainbow palette. This visualization helps the user inspect where the consensus map is stable and where the input volumes differ. ## Output Sampling Rate Both output volumes use the sampling rate of the first input volume. This is appropriate when all input volumes have the same sampling rate, which is required by the validation step. The output should therefore be interpreted in the same voxel-size units as the input maps. ## Interpreting the Consensus Result The consensus volume should be interpreted as a fused representation of the input maps. Regions that are consistent across the inputs are expected to appear more stable in the consensus. Regions where the inputs differ may still appear in the consensus, but their uncertainty or variability should be assessed using the difference volume. The difference volume is not a local-resolution map. It is a voxel-wise disagreement map derived from the input volumes. It should be interpreted as a measure of variability between the maps being fused. ## Practical Recommendations Use this protocol only after the input volumes have been aligned and brought to the same box size, voxel size, and origin. Check that the volumes are comparable in filtering, normalization, and amplitude scale before fusion. Use the difference volume to inspect where the input maps disagree. Open the generated ChimeraX script to visualize the consensus map colored by local disagreement. Do not interpret the consensus volume alone. Always compare it with the individual input volumes and with the difference map. If the protocol does not generate an output, check that all input volumes have equal box size, voxel size, and origin. ## Final Perspective Volume Consensus is a map-fusion protocol. For biological users, its main value is that it creates a representative consensus map from several comparable input volumes and provides a difference map showing where those volumes disagree. The protocol is most useful when the input maps have already been carefully prepared and adjusted. The consensus map summarizes common density, while the difference map highlights regions that may correspond to structural variability, processing differences, or remaining inconsistencies among the inputs. """ _label = 'volume consensus' # --------------------------- DEFINE param functions -------------------------------------------- def _defineParams(self, form): form.addSection(label='Input') form.addParam('vols', MultiPointerParam, pointerClass='Volume', label="Volumes", help='Select the volumes for the consensus.') # --------------------------- INSERT steps functions -------------------------------------------- def _insertAllSteps(self): self._insertFunctionStep('fusionStep') self._insertFunctionStep('createOutputStep') self._insertFunctionStep("createChimeraScript") # --------------------------- STEPS functions ---------------------------------------------------
[docs] def fusionStep(self): inputVols = self._getExtraPath("input_volumes.txt") fhInputVols = open(inputVols, 'w') for i, vol in enumerate(self.vols): fileName = vol.get().getFileName() if fileName.endswith(':mrc'): fileName = fileName[:-4] fhInputVols.write(fileName + '\n') fhInputVols.close() outVolFn = self._getExtraPath("consensus_volume.mrc") args = " -i %s -o %s" % (inputVols, outVolFn) self.runJob("xmipp_volume_consensus", args)
[docs] def createOutputStep(self): outVol = Volume() outVol.setSamplingRate(self.vols[0].get().getSamplingRate()) outVol.setFileName(self._getExtraPath("consensus_volume.mrc")) if not exists(self._getExtraPath("consensus_volume.mrc")): raise NoOutputGenerated("Consensus volume NOT generated, please check input volumes to ensure they have " "equal box size, voxel size and origin.") else: outVol2 = Volume() outVol2.setSamplingRate(self.vols[0].get().getSamplingRate()) outVol2.setFileName(self._getExtraPath("consensus_volume_diff.mrc")) self._defineOutputs(outputVolume=outVol) self._defineOutputs(outputVolumeDiff=outVol2)
[docs] def createChimeraScript(self): fnRoot = "extra/" scriptFile = self._getPath('result') + '_fusion_chimera.cxc' fhCmd = open(scriptFile, 'w') fhCmd.write("open %s\n" % (fnRoot+"consensus_volume.mrc")) fhCmd.write("open %s\n" % (fnRoot+"consensus_volume_diff.mrc")) fhCmd.write("vol #2 hide\n") fhCmd.write("color sample #1 map #2 palette rainbow\n") fhCmd.close()
# --------------------------- INFO functions -------------------------------------------- def _summary(self): summary = [] if not hasattr(self, 'outputVolume'): summary.append("Output volume not ready yet.") else: for i, vol in enumerate(self.vols): summary.append("Volume %d: %s" % (i+1, vol.get().getFileName())) return summary def _methods(self): methods = [] if not hasattr(self, 'outputVolume'): methods.append("Output volume not ready yet.") else: methods.append("We compute a consensus volume from %d input volumes at %f A/px" % (self.vols.getSize(), self.vols[0].get().getSamplingRate())) return methods def _validate(self): errors = [] voxel_size = [] for i, vol in enumerate(self.vols): voxel_size.append(round(vol.get().getSamplingRate(), 2)) result = all(element == voxel_size[0] for element in voxel_size) if not result: errors.append('Pixel size should be the same for all input volumes.') return errors def _citations(self): return ['Fernandez-Gimenez2021']
[docs]class NoOutputGenerated(Exception): """No output generation error""" pass