Source code for imod.protocols.protocol_tomoProjection

# **************************************************************************
# *
# * Authors:     Federico P. de Isidro Gomez (fp.deisidro@cnb.csic.es) [1]
# *
# * [1] Centro Nacional de Biotecnologia, CSIC, Spain
# *
# * 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 os

from pwem.objects import Transform
from pyworkflow import BETA
from pyworkflow.object import Set, Integer
import pyworkflow.protocol.params as params
import pyworkflow.utils.path as path
import tomo.objects as tomoObj
from imod import Plugin
from pwem.emlib.image import ImageHandler
from imod.protocols.protocol_base import ProtImodBase


[docs]class ProtImodTomoProjection(ProtImodBase): """ Re-project a tomogram given a geometric description (axis and angles). More info: https://bio3d.colorado.edu/imod/doc/man/xyzproj.html """ _label = 'Tomo projection' _devStatus = BETA AXIS_X = 0 AXIS_Y = 1 AXIS_Z = 2 # -------------------------- DEFINE param functions ----------------------- def _defineParams(self, form): form.addSection('Input') form.addParam('inputSetOfTomograms', params.PointerParam, pointerClass='SetOfTomograms', important=True, label='Input set of tomograms') form.addParam('minAngle', params.FloatParam, default=-60.0, label='Minimum angle of rotation', important=True, help='Minimum angle of the projection range') form.addParam('maxAngle', params.FloatParam, default=60.0, label='Maximum angle of rotation', important=True, help='Maximum angle of the projection range') form.addParam('stepAngle', params.FloatParam, default=2.0, label='Step angle of rotation', important=True, help='Step angle of the projection range') form.addParam('rotationAxis', params.EnumParam, choices=['X', 'Y', 'Z'], default=self.AXIS_Y, label='Rotation axis for projection', important=True, display=params.EnumParam.DISPLAY_HLIST, help='Axis to tilt around (X, Y, or Z). Y axis usually corresponds to the typical rotation axis ' 'acquisition.') # -------------------------- INSERT steps functions --------------------- def _insertAllSteps(self): for tomo in self.inputSetOfTomograms.get(): self._insertFunctionStep(self.projectTomogram, tomo.getObjId()) self._insertFunctionStep(self.generateOutputStackStep, tomo.getObjId()) self._insertFunctionStep(self.closeOutputSetsStep) # --------------------------- STEPS functions ----------------------------
[docs] def projectTomogram(self, tomoObjId): tomo = self.inputSetOfTomograms.get()[tomoObjId] tomoId = os.path.splitext(os.path.basename(tomo.getFileName()))[0] extraPrefix = self._getExtraPath(tomoId) tmpPrefix = self._getTmpPath(tomoId) path.makePath(tmpPrefix) path.makePath(extraPrefix) paramsXYZproj = { 'input': tomo.getFileName(), 'output': os.path.join(extraPrefix, os.path.basename(tomo.getFileName())), 'axis': self.getRotationAxis(), 'angles': str(self.minAngle.get()) + ',' + str(self.maxAngle.get()) + ',' + str(self.stepAngle.get()), } argsXYZproj = "-input %(input)s " \ "-output %(output)s " \ "-axis %(axis)s " \ "-angles %(angles)s " Plugin.runImod(self, 'xyzproj', argsXYZproj % paramsXYZproj)
[docs] def generateOutputStackStep(self, tomoObjId): tomo = self.inputSetOfTomograms.get()[tomoObjId] tomoId = os.path.splitext(os.path.basename(tomo.getFileName()))[0] extraPrefix = self._getExtraPath(tomoId) self.getOutputSetOfTiltSeries(self.inputSetOfTomograms.get()) newTs = tomoObj.TiltSeries(tsId=tomoId) newTs.setTsId(tomo.getTsId()) newTs.setAcquisition(tomo.getAcquisition()) newTs.setTsId(tomoId) # Add origin to output tilt-series self.outputSetOfTiltSeries.append(newTs) tiltAngleList = self.getTiltAngleList() for index in range(self.getProjectionRange()): newTi = tomoObj.TiltImage() newTi.setTiltAngle(tiltAngleList[index]) newTi.setTsId(tomoId) newTi.setAcquisitionOrder(index+1) newTi.setLocation(index + 1, os.path.join(extraPrefix, os.path.basename(tomo.getFileName()))) newTi.setSamplingRate(self.inputSetOfTomograms.get().getSamplingRate()) newTs.append(newTi) ih = ImageHandler() x, y, z, _ = ih.getDimensions(newTs.getFirstItem().getFileName()) newTs.setDim((x, y, z)) # Set origin to output tilt-series origin = Transform() origin.setShifts(x / -2. * self.inputSetOfTomograms.get().getSamplingRate(), y / -2. * self.inputSetOfTomograms.get().getSamplingRate(), 0) newTs.setOrigin(origin) newTs.write(properties=False) self.outputSetOfTiltSeries.update(newTs) self.outputSetOfTiltSeries.updateDim() self.outputSetOfTiltSeries.write() self._store()
[docs] def closeOutputSetsStep(self): self.outputSetOfTiltSeries.setStreamState(Set.STREAM_CLOSED) self._store()
# --------------------------- UTILS functions ----------------------------
[docs] def getRotationAxis(self): parseParamsRotationAxis = { self.AXIS_X: 'X', self.AXIS_Y: 'Y', self.AXIS_Z: 'Z', } return parseParamsRotationAxis[self.rotationAxis.get()]
[docs] def getProjectionRange(self): return int((self.maxAngle.get() - self.minAngle.get()) / self.stepAngle.get()) + 1
[docs] def getTiltAngleList(self): tiltAngleList = [] angle = self.minAngle.get() while angle <= self.maxAngle.get(): tiltAngleList.append(angle) angle += self.stepAngle.get() return tiltAngleList
# --------------------------- INFO functions ---------------------------- def _validate(self): validateMsgs = [] if self.minAngle.get() > self.maxAngle.get(): validateMsgs.append("ERROR: Maximum angle of rotation bigger than minimum.") if (self.maxAngle.get() - self.minAngle.get()) < self.stepAngle.get(): validateMsgs.append("ERROR: Angle step of rotation bigger than range.") if self.stepAngle.get() < 0: validateMsgs.append("ERROR: Angle step of rotation mus be bigger than zero.") return validateMsgs def _summary(self): summary = [] if hasattr(self, 'outputSetOfTiltSeries'): summary.append("Input Tomograms: %d.\nTilt-series generated: %d.\n" % (self.inputSetOfTomograms.get().getSize(), self.outputSetOfTiltSeries.getSize())) else: summary.append("Output classes not ready yet.") return summary def _methods(self): methods = [] if hasattr(self, 'outputSetOfTiltSeries'): methods.append("%d tilt-series have been generated by projecting the input tomogram.\n" % (self.outputSetOfTiltSeries.getSize())) else: methods.append("Output classes not ready yet.") return methods