Source code for localrec.protocols.protocol_filter_subparticles

# **************************************************************************
# *
# * Authors:   Vahid Abrishami (vahid.abrishami@helsinki.fi)
# *
# * Laboratory of Structural Biology,
# * Helsinki Institute of Life Science HiLIFE
# *
# * 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'
# *
# **************************************************************************

import sys
import pprint

from pyworkflow import VERSION_3_0
from pyworkflow.protocol.params import PointerParam, FloatParam, BooleanParam
from pwem.protocols import ProtParticles
from pwem.objects.data import SetOfParticles

from localrec.utils import *
# eventually progressbar will be move to scipion core
from pyworkflow.utils import ProgressBar


[docs]class ProtFilterSubParts(ProtParticles): """ This protocol mainly filters output particles from two protocols: extend symmetry and localized subparticles. It can filter the particles (sub-particles) according to spatial distance, view, and angular distance. """ _label = 'filter subparticles' _lastUpdateVersion = VERSION_3_0 # -------------------------- DEFINE param functions ----------------------- def _defineParams(self, form): form.addSection(label='Input') form.addParam('inputSet', PointerParam, pointerClass='SetOfCoordinates, SetOfParticles', label='Input type') form.addSection('Sub-particles') form.addParam('unique', FloatParam, default=-1, label='Angle to keep unique sub-particles (deg)', help='Keep only unique subparticles within angular ' 'distance. It is useful to remove overlapping ' 'sub-particles on symmetry axis.') form.addParam('mindist', FloatParam, default=-1, label='Minimum distance between sub-particles (px)', help='In pixels. Minimum distance between the ' 'subparticles in the image. All overlapping ones ' 'will be discarded.') form.addParam('keepRedundant', BooleanParam, default=False, condition='mindist>0', label='keep overlapping particles in simmetry axis', help="In order to break symmetry constraints, sometimes you want" " all the repetitions of your particle related by symmetry." " but not particles that overlap" ) form.addParam('distorigin', FloatParam, default=-1, label='Minimum distance to origin (px)', help='In pixels. Minimum distance from subparticle to origin' ' If positive it will drop the subparticles closer' ' to the origin') form.addParam('side', FloatParam, default=-1, label='Angle to keep sub-particles from side views (deg)', help='Keep only particles within specified angular ' 'distance from side views. All others will be ' 'discarded. ') form.addParam('top', FloatParam, default=-1, label='Angle to keep sub-particles from top views (deg)', help='Keep only particles within specified angular ' 'distance from top views. All others will be ' 'discarded. ') form.addParallelSection(threads=0, mpi=0) # -------------------------- INSERT steps functions ----------------------- def _insertAllSteps(self): self._insertFunctionStep('createOutputStep') # -------------------------- STEPS functions ------------------------------
[docs] def createOutputStep(self): inputSet = self.inputSet.get() params = {"unique": self.unique.get(), "mindist": self.mindist.get(), "keepRedundant": self.keepRedundant.get(), "distorigin": self.distorigin.get(), "side": self.side.get(), "top": self.top.get() } if isinstance(inputSet, SetOfParticles): self._particlesOutputStep(inputSet, params) else: self._coordinateOutputStep(inputSet, params)
def _particlesOutputStep(self, inputSet, params): outputParts = self._createSetOfParticles() outputParts.copyInfo(inputSet) lastPartId = None particlesList = [] isSubPart = False; firstParticle = inputSet.getFirstItem() if firstParticle.hasAttribute('_transorg'): isSubPart = True; print("Processing particles:") progress = ProgressBar(total=len(inputSet), fmt=ProgressBar.NOBAR) progress.start() sys.stdout.flush() step = max(100, len(inputSet) // 100) for i, particle in enumerate(inputSet.iterItems(orderBy=['_index'])): if i % step == 0: progress.update(i+1) if (isSubPart): partId = int(particle._coordinate._micId) else: partId = int(particle._index) if partId != lastPartId: lastPartId = partId particlesList = [] subpart = particle.clone() if (isSubPart): _, cAngles = geometryFromMatrix(inv(particle._transorg.getMatrix())) else: _, cAngles = geometryFromMatrix(inv(particle.getTransform().getMatrix())) subpart._angles = cAngles if not self._filterParticles(params, particlesList, subpart): continue particlesList.append(subpart) outputParts.append(subpart) progress.finish() self._defineOutputs(outputParticles=outputParts) self._defineSourceRelation(self.inputSet, outputParts) def _coordinateOutputStep(self, inputSet, params): inputMics = inputSet.getMicrographs() outputSet = self._createSetOfCoordinates(inputMics) outputSet.copyInfo(inputSet) lastPartId = None subParticles = [] coordArr = [] subParticleId = 0 progress = ProgressBar(len(inputSet), fmt=ProgressBar.NOBAR) print("Processing coordinates:") progress.start() step = max(100, len(inputSet) // 100) for i, coord in enumerate(inputSet.iterItems(orderBy=['_subparticle._micId', '_micId', 'id'])): if i % step == 0: progress.update(i+1) # The original particle id is stored in the sub-particle as micId partId = coord._micId.get() # Load the particle if it has changed from the last sub-particle if partId != lastPartId: self._genOutputCoordinates(subParticles, coordArr, outputSet, params["mindist"], params["keepRedundant"], params["distorigin"]) subParticleId = 0 coordArr = [] subParticles = [] lastPartId = partId subParticle = coord._subparticle subpart = subParticle.clone() _, cAngles = geometryFromMatrix(inv(subParticle._transorg.getMatrix())) subpart._angles = cAngles subParticleId += 1 subpart._id = subParticleId if not self._filterParticles(params, subParticles, subpart): continue subParticles.append(subpart) coordArr.append(coord.clone()) progress.finish() self._genOutputCoordinates(subParticles, coordArr, outputSet, params["mindist"], params["keepRedundant"], params["distorigin"]) self._defineOutputs(outputCoordinates=outputSet) self._defineTransformRelation(self.inputSet, self.outputCoordinates) # -------------------------- INFO functions ------------------------------- def _validate(self): errors = [] inputSet = self.inputSet.get() if isinstance(inputSet, SetOfParticles): if not inputSet.hasAlignmentProj(): errors.append('The selected input particles do not have ' 'alignment information.') else: firstCoord = inputSet.getFirstItem() if not firstCoord.hasAttribute('_subparticle'): errors.append('The selected input coordinates are not the ' 'output from a localized-subparticles protocol.') return errors def _citations(self): return ['Ilca2015', 'Abrishami2020'] def _summary(self): summary = [] return summary def _methods(self): return [] # -------------------------- UTILS functions ------------------------------ def _genOutputCoordinates(self, subParticles, coordArr, outputSet, minDist, keepRedundant, distorigin): for index, coordinate in enumerate(coordArr): if minDist > 0 or distorigin > 0: subpart = subParticles[index] if not filter_mindist(subParticles, subpart, minDist, keepRedundant): continue if not filter_distorigin(subParticles, subpart, distorigin): continue outputSet.append(coordinate.clone()) else: outputSet.append(coordinate.clone()) def _filterParticles(self, params, subParticles, subPart): if params["side"] > 0: # print("Side Filter") if not filter_side(subPart, params["side"]): return False if params["top"] > 0: # print("Top Filter", params["top"]) if not filter_top(subPart, params["top"]): return False if params["unique"] >= 0: # print(np.degrees(subPart._angles)) if not filter_unique(subParticles, subPart, params["unique"]): return False return True