# **************************************************************************
# *
# * Authors: J.M. De la Rosa Trevin (delarosatrevin@scilifelab.se) [1]
# *
# * [1] SciLifeLab, Stockholm University
# *
# * 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 pyworkflow as pw
from pyworkflow.protocol.params import (PointerParam, EnumParam, PathParam,
FloatParam, StringParam,
BooleanParam, LEVEL_ADVANCED)
from pyworkflow.mapper.sqlite_db import SqliteDb
from pyworkflow.utils.properties import Message
from pwem.protocols import ProtImport, EMProtocol, ProtImportFiles
import tomo.objects
[docs]class ProtTomoBase:
def _createSet(self, SetClass, template, suffix, **kwargs):
""" Create a set and set the filename using the suffix.
If the file exists, it will be delete. """
setFn = self._getPath(template % suffix)
# Close the connection to the database if
# it is open before deleting the file
pw.utils.cleanPath(setFn)
SqliteDb.closeConnection(setFn)
setObj = SetClass(filename=setFn, **kwargs)
return setObj
def _createSetOfTiltSeriesM(self, suffix=''):
return self._createSet(tomo.objects.SetOfTiltSeriesM,
'tiltseriesM%s.sqlite', suffix)
def _createSetOfTiltSeries(self, suffix=''):
self._ouputSuffix = ''
return self._createSet(tomo.objects.SetOfTiltSeries,
'tiltseries%s.sqlite', suffix)
def _createSetOfCoordinates3D(self, volSet, suffix=''):
coord3DSet = self._createSet(tomo.objects.SetOfCoordinates3D,
'coordinates%s.sqlite', suffix,
indexes=['_volId'])
coord3DSet.setPrecedents(volSet)
return coord3DSet
def _createSetOfTomograms(self, suffix=''):
return self._createSet(tomo.objects.SetOfTomograms,
'tomograms%s.sqlite', suffix)
def _createSetOfSubTomograms(self, suffix=''):
return self._createSet(tomo.objects.SetOfSubTomograms,
'subtomograms%s.sqlite', suffix)
def _createSetOfAverageSubTomograms(self, suffix=''):
return self._createSet(tomo.objects.SetOfAverageSubTomograms,
'avgSubtomograms%s.sqlite', suffix)
def _createSetOfClassesSubTomograms(self, subTomograms, suffix=''):
classes = self._createSet(tomo.objects.SetOfClassesSubTomograms,
'subtomogramClasses%s.sqlite', suffix)
classes.setImages(subTomograms)
return classes
def _createSetOfLandmarkModels(self, suffix=''):
return self._createSet(tomo.objects.SetOfLandmarkModels, 'setOfLandmarks%s.sqlite', suffix)
def _createSetOfMeshes(self, volSet, suffix=''):
meshSet = self._createSet(tomo.objects.SetOfMeshes,
'meshes%s.sqlite', suffix)
meshSet.setPrecedents(volSet)
return meshSet
def _getOutputSuffix(self, cls):
""" Get the name to be used for a new output.
For example: output3DCoordinates7.
It should take into account previous outputs
and number with a higher value.
"""
maxCounter = -1
for attrName, _ in self.iterOutputAttributes(cls):
suffix = attrName.replace(self.OUTPUT_PREFIX, '')
try:
counter = int(suffix)
except:
counter = 1 # when there is not number assume 1
maxCounter = max(counter, maxCounter)
return str(maxCounter+1) if maxCounter > 0 else '' # empty if not output
[docs]class ProtTomoPicking(ProtImport, ProtTomoBase):
OUTPUT_PREFIX = 'output3DCoordinates'
""" Base class for Tomogram boxing protocols. """
def _defineParams(self, form):
form.addSection(label='Input')
form.addParam('inputTomograms', PointerParam, label="Input Tomograms", important=True,
pointerClass='SetOfTomograms',
help='Select the Tomogram to be used during picking.')
def _summary(self):
summary = []
if self.isFinished():
summary.append("Output 3D Coordinates not ready yet.")
if self.getOutputsSize() >= 1:
for key, output in self.iterOutputAttributes():
summary.append("*%s:* \n %s " % (key, output.getSummary()))
else:
summary.append(Message.TEXT_NO_OUTPUT_CO)
return summary
[docs]class ProtTomoImportFiles(ProtImportFiles, ProtTomoBase):
def _defineParams(self, form):
self._defineImportParams(form)
self._defineAcquisitionParams(form)
def _defineImportParams(self, form):
""" Override to add options related to the different types
of import that are allowed by each protocol.
"""
importChoices = self._getImportChoices()
form.addSection(label='Import')
if len(importChoices) > 1: # not only from files
form.addParam('importFrom', EnumParam,
choices=importChoices, default=self._getDefaultChoice(),
label='Import from',
help='Select the type of import.')
else:
form.addHidden('importFrom', EnumParam,
choices=importChoices, default=self.IMPORT_FROM_FILES,
label='Import from',
help='Select the type of import.')
form.addParam('filesPath', PathParam,
label="Files directory",
help="Directory with the files you want to import.\n\n"
"The path can also contain wildcards to select"
"from several folders. \n\n"
"Examples:\n"
" ~/Tomograms/data/day??_tomograms/\n"
"Each '?' represents one unknown character\n\n"
" ~/Tomograms/data/day*_tomograms/\n"
"'*' represents any number of unknown characters\n\n"
" ~/Tomograms/data/day#_tomograms/\n"
"'#' represents one digit that will be used as "
"tomogram ID\n\n"
"NOTE: wildcard characters ('*', '?', '#') "
"cannot appear in the actual path.)")
form.addParam('filesPattern', StringParam,
label='Pattern',
help="Pattern of the files to be imported.\n\n"
"The pattern can contain standard wildcards such as\n"
"*, ?, etc, or special ones like ### to mark some\n"
"digits in the filename as ID.\n\n"
"NOTE: wildcards and special characters "
"('*', '?', '#', ':', '%') cannot appear in the "
"actual path.")
form.addParam('copyFiles', BooleanParam, default=False,
expertLevel=LEVEL_ADVANCED,
label="Copy files?",
help="By default the files are not copied into the "
"project to avoid data duplication and to save "
"disk space. Instead of copying, symbolic links are "
"created pointing to original files. This approach "
"has the drawback that if the project is moved to "
"another computer, the links need to be restored.")
def _defineAcquisitionParams(self, form):
""" Override to add options related to acquisition info.
"""
form.addParam('samplingRate', FloatParam,
label=Message.LABEL_SAMP_RATE)
def _validate(self):
pass
[docs]class ProtTomoSubtomogramAveraging(EMProtocol, ProtTomoBase):
""" Base class for subtomogram averaging protocols. """
pass
[docs]class ProtTomoImportAcquisition:
MANUAL_IMPORT = 0
FROM_FILE_IMPORT = 1
def _defineParams(self, form):
""" Override to add options related to acquisition info.
"""
importAcquisitionChoices = ['Manual', 'From file']
form.addSection(label='Acquisition Info')
form.addParam('importAcquisitionFrom', EnumParam,
choices=importAcquisitionChoices,
default=self._getDefaultChoice(),
label='Import from',
help='Select the type of import.')
form.addParam('acquisitionData', PathParam,
label="Acquisition parameters file",
help="File with the acquisition parameters for every "
"subtomogram to import. File must be in plain format."
" The file must contain a row per file to be imported "
"and have the following parameters in order: \n"
"\n"
"'File_name AcquisitionAngleMin AcquisitionAngleMax Step AngleAxis1 AngleAxis2' \n"
"\n"
"An example would be: \n"
"subtomo1.em -40 40 3 25 30 \n"
"subtomo2.em -45 50 2 15 15 \n",
condition="importAcquisitionFrom == %d" % self.FROM_FILE_IMPORT)
form.addParam('acquisitionAngleMax', FloatParam,
default=60,
label='Acquisition angle max',
condition="importAcquisitionFrom == %d" % self.MANUAL_IMPORT,
help='Enter the positive limit of the acquisition angle')
form.addParam('acquisitionAngleMin', FloatParam,
default=-60,
condition="importAcquisitionFrom == %d" % self.MANUAL_IMPORT,
label='Acquisition angle min',
help='Enter the negative limit of the acquisition angle')
form.addParam('step', FloatParam,
allowsNull=True,
condition="importAcquisitionFrom == %d" % self.MANUAL_IMPORT,
label='Step',
help='Enter the step size for the import')
form.addParam('angleAxis1', FloatParam,
allowsNull=True,
condition="importAcquisitionFrom == %d" % self.MANUAL_IMPORT,
label='Angle axis 1',
help='Enter the angle axis 1')
form.addParam('angleAxis2', FloatParam,
allowsNull=True,
condition="importAcquisitionFrom == %d" % self.MANUAL_IMPORT,
label='Angle Axis 2',
help='Enter the angle axis 2')
def _parseAcquisitionData(self):
if self.importAcquisitionFrom.get() == self.MANUAL_IMPORT:
self.acquisitionParameters = {
'angleMin': self.acquisitionAngleMin.get(),
'angleMax': self.acquisitionAngleMax.get(),
'step': self.step.get(),
'angleAxis1': self.angleAxis1.get(),
'angleAxis2': self.angleAxis2.get()
}
else:
params = open(self.acquisitionData.get(), "r")
self.acquisitionParameters = {}
for line in params.readlines():
param = line.split()
try:
self.acquisitionParameters.update({param[0]: {
'angleMin': float(param[1]),
'angleMax': float(param[2]),
'step': int(param[3]),
'angleAxis1': float(param[4]),
'angleAxis2': float(param[5])
}})
except Exception as e:
print('Wrong acquisition data file format', e)
def _extractAcquisitionParameters(self, fileName):
if self.importAcquisitionFrom.get() == self.FROM_FILE_IMPORT:
onlyName = fileName.split('/')[-1]
acquisitionParams = self.acquisitionParameters[onlyName]
else:
acquisitionParams = self.acquisitionParameters
return tomo.objects.TomoAcquisition(**acquisitionParams)
def _summary(self, summary, setOfObject):
for obj in setOfObject:
if obj.hasAcquisition():
summary.append(u"File: %s" % obj.getFileName())
summary.append(u"Acquisition angle max: *%0.2f*" % obj.getAcquisition().getAngleMax())
summary.append(u"Acquisition angle min: *%0.2f*" % obj.getAcquisition().getAngleMin())
if obj.getAcquisition().getStep():
summary.append(u"Step: *%d*" % obj.getAcquisition().getStep())
if obj.getAcquisition().getAngleAxis1():
summary.append(u"Angle axis 1: *%0.2f*" % obj.getAcquisition().getAngleAxis1())
if obj.getAcquisition().getAngleAxis2():
summary.append(u"Angle axis 2: *%0.2f*" % obj.getAcquisition().getAngleAxis2())