# **************************************************************************
# *
# * 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 pyworkflow import BETA
import pyworkflow.protocol.params as params
from pyworkflow.utils import path
from pyworkflow.object import Set
from pyworkflow.protocol.constants import STEPS_PARALLEL
import tomo.objects as tomoObj
import tomo.constants as constants
from imod import Plugin
from imod import utils
from imod.protocols.protocol_base import ProtImodBase
[docs]class ProtImodGoldBeadPicker3d(ProtImodBase):
"""
3-dimensional gold bead picker using the IMOD procedure.
More info:
https://bio3d.colorado.edu/imod/doc/man/findbeads3d.html
"""
_label = 'Gold bead picker 3D'
_devStatus = BETA
# -------------------------- DEFINE param functions -----------------------
def _defineParams(self, form):
form.addSection('Input')
form.addParam('inputSetOfTomograms',
params.PointerParam,
pointerClass='SetOfTomograms',
important=True,
label='Input set of tilt-series',
help='Input set of tomograms from which gold beads will be picked.')
form.addParam('beadDiameter',
params.IntParam,
label='Fiducial diameter (pixels)',
default='10',
help="Diameter of beads in pixels.")
form.addParam('beadsColor',
params.EnumParam,
choices=['Dark', 'Light'],
label='Bead contrast',
default='0',
display=params.EnumParam.DISPLAY_HLIST,
help='Contrast of the gold beads:\n'
'-Dark: beads are dark on light background.\n'
'-Light: beads are light on dark background.')
form.addParam('minRelativeStrength',
params.FloatParam,
label='Minimum relative Strength',
default=0.05,
help='Minimum relative peak strength for keeping a peak in the analysis. The square root of the '
'specified value is used for comparing with the square root of peak strength, for '
'compatibility with existing command files. The default is 0.05, which corresponds to a '
'relative square root peak strength of 0.22. Too many weak peaks can prevent a dip from '
'showing up in the smoothed histogram of strengths. If the program fails to find a '
'histogram dip, one strategy is to try raising this value.')
form.addParam('minSpacing',
params.FloatParam,
label='Minimum spacing',
default=0.9,
help='Minimum spacing between peaks as a fraction of the bead size. When two peaks are closer '
'than this distance apart, the weaker one is eliminated unless the -both option is entered. '
'The default is 0.9. A value less than 1 is helpful for picking both beads in a pair.')
form.addParallelSection(threads=4, mpi=1)
# -------------------------- INSERT steps functions ---------------------
def _insertAllSteps(self):
self.defineExecutionPararell()
allOutputId = []
for ts in self.inputSetOfTomograms.get():
pickId = self._insertFunctionStep(self.pickGoldBeadsStep,
ts.getObjId(),
prerequisites=[])
convertId = self._insertFunctionStep(self.convertModelToCoordinatesStep,
ts.getObjId(),
prerequisites=[pickId])
outputID = self._insertFunctionStep(self.createOutputStep,
ts.getObjId(),
prerequisites=[convertId])
allOutputId.append(outputID)
self._insertFunctionStep('closeOutputSetStep',
prerequisites=allOutputId)
# --------------------------- STEPS functions ----------------------------
[docs] def pickGoldBeadsStep(self, tsObjId):
tomo = self.inputSetOfTomograms.get()[tsObjId]
location = tomo.getLocation()[1]
fileName, _ = os.path.splitext(location)
extraPrefix = self._getExtraPath(os.path.basename(fileName))
path.makePath(extraPrefix)
""" Run findbeads3d IMOD program """
paramsFindbeads3d = {
'inputFile': location,
'outputFile': os.path.join(extraPrefix, "%s.mod" % os.path.basename(fileName)),
'beadSize': self.beadDiameter.get(),
'minRelativeStrength': self.minRelativeStrength.get(),
'minSpacing': self.minSpacing.get(),
}
argsFindbeads3d = "-InputFile %(inputFile)s " \
"-OutputFile %(outputFile)s " \
"-BeadSize %(beadSize)d " \
"-MinRelativeStrength %(minRelativeStrength)f " \
"-MinSpacing %(minSpacing)d "
if self.beadsColor.get() == 1:
argsFindbeads3d += "-LightBeads "
Plugin.runImod(self, 'findbeads3d', argsFindbeads3d % paramsFindbeads3d)
[docs] def convertModelToCoordinatesStep(self, tsObjId):
tomo = self.inputSetOfTomograms.get()[tsObjId]
location = tomo.getLocation()[1]
fileName, _ = os.path.splitext(location)
extraPrefix = self._getExtraPath(os.path.basename(fileName))
""" Run model2point IMOD program """
paramsModel2Point = {
'inputFile': os.path.join(extraPrefix, "%s.mod" % os.path.basename(fileName)),
'outputFile': os.path.join(extraPrefix, "%s.xyz" % os.path.basename(fileName)),
}
argsModel2Point = "-InputFile %(inputFile)s " \
"-OutputFile %(outputFile)s " \
Plugin.runImod(self, 'model2point', argsModel2Point % paramsModel2Point)
[docs] def createOutputStep(self, tsObjId):
tomo = self.inputSetOfTomograms.get()[tsObjId]
location = tomo.getLocation()[1]
fileName, _ = os.path.splitext(location)
extraPrefix = self._getExtraPath(os.path.basename(fileName))
""" Create the output set of coordinates 3D from gold beads detected """
self.getOutputSetOfCoordinates3Ds(self.inputSetOfTomograms.get(), self.inputSetOfTomograms.get())
coordFilePath = os.path.join(extraPrefix, "%s.xyz" % os.path.basename(fileName))
coordList = utils.formatGoldBead3DCoordinatesList(coordFilePath)
with self._lock:
for element in coordList:
newCoord3D = tomoObj.Coordinate3D()
newCoord3D.setVolume(tomo)
newCoord3D.setX(element[0], constants.BOTTOM_LEFT_CORNER)
newCoord3D.setY(element[1], constants.BOTTOM_LEFT_CORNER)
newCoord3D.setZ(element[2], constants.BOTTOM_LEFT_CORNER)
newCoord3D.setVolId(tsObjId)
self.outputSetOfCoordinates3D.append(newCoord3D)
self.outputSetOfCoordinates3D.update(newCoord3D)
self.outputSetOfCoordinates3D.write()
self._store()
[docs] def closeOutputSetStep(self):
self.outputSetOfCoordinates3D.setStreamState(Set.STREAM_CLOSED)
self._store()