Skip to content

Commit

Permalink
Merge pull request #203 from I2PC/add-ctf-to-tomo-projector
Browse files Browse the repository at this point in the history
Add ctf to tomo projector
  • Loading branch information
Vilax authored Dec 5, 2024
2 parents a736b2b + 7a07de0 commit d445061
Show file tree
Hide file tree
Showing 10 changed files with 46 additions and 47 deletions.
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
## V3.24.06.2
- CTF addeed to projection protocols
## V3.24.06
- New protocols:
- apply_segmentation: Applies a segmentation to a set of tomograms.
Expand Down
2 changes: 1 addition & 1 deletion xmipptomo/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@

_logo = "xmipp_logo.png"
_references = ['delaRosaTrevin2013', 'Jimenez2022']
__version__ = "3.24.06.1" #X.YY.MM.sv
__version__ = "3.24.06.2" #X.YY.MM.sv
# X.Y.M = version of the xmipp release associated.
# sv = Set this to ".0" on each xmipp release.
# For not release version (hotfix) increase it --> ".1", ".2", ...
Expand Down
2 changes: 0 additions & 2 deletions xmipptomo/legacy/protocols/protocol_denoising_confidence.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@

import os

from pyworkflow import VERSION_2_0
from pyworkflow.utils import getExt
from pyworkflow.object import Set, Float
import pyworkflow.utils.path as path
Expand Down Expand Up @@ -65,7 +64,6 @@ class XmippProtConfTomo(EMProtocol, ProtTomoBase):
Tomograms:
"""
_label = 'local confidence maps'
_lastUpdateVersion = VERSION_2_0

def __init__(self, **args):
ProtAnalysis3D.__init__(self, **args)
Expand Down
2 changes: 1 addition & 1 deletion xmipptomo/legacy/viewers/viewer_score_subtomos.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def plotAngularDistibution(self, subtomos:SetOfSubTomograms, **kwargs):

plotter = EmPlotter(x=1, y=1, windowTitle='Angular distribution')

plotter.plotAngularDistributionFromSet(subtomos, "Angular distribution", weightAttr=XmippProtScoreTransform.SCORE_ATTR)
plotter.plotAngularDistributionFromSet(subtomos, "Angular distribution")

return plotter

Expand Down
52 changes: 24 additions & 28 deletions xmipptomo/protocols/protocol_project_subtomograms.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,11 @@ class XmippProtProjectSubtomograms(EMProtocol, ProtTomoBase):
COLUMN_ANGLE_ROT = 'angleRot'
COLUMN_ANGLE_TILT = 'angleTilt'

# --------------------------- Class constructor --------------------------------------------
def __init__(self, **args):
# Calling parent class constructor
super().__init__(**args)
# Defining execution mode. Steps will take place in parallel now
# Full tutorial on how to parallelize protocols can be read here:
# https://scipion-em.github.io/docs/release-3.0.0/docs/developer/parallelization.html
stepsExecutionMode = params.STEPS_PARALLEL

# Defining execution mode. Steps will take place in parallel now
# Full tutorial on how to parallelize protocols can be read here:
# https://scipion-em.github.io/docs/release-3.0.0/docs/developer/parallelization.html
self.stepsExecutionMode = params.STEPS_PARALLEL

# --------------------------- DEFINE param functions ------------------------
def _defineParams(self, form):
Expand All @@ -105,15 +101,15 @@ def _defineParams(self, form):
form.addParam('transformMethod', params.EnumParam, display=params.EnumParam.DISPLAY_COMBO, default=self.METHOD_FOURIER,
choices=['Fourier', 'Real space', 'Shears'], label="Transform method: ", expertLevel=params.LEVEL_ADVANCED,
help='Select the algorithm that will be used to obtain the projections.')

# Parameter group for fourier transform method
fourierGroup = form.addGroup('Fourier parameters', condition=f"transformMethod=={self.METHOD_FOURIER}", expertLevel=params.LEVEL_ADVANCED)
fourierGroup.addParam('pad', params.IntParam, default=2, label="Pad: ", help="Controls the padding factor.")
fourierGroup.addParam('maxfreq', params.FloatParam, default=0.25, label="Maximum frequency: ",
help="Maximum frequency for the pixels.\nBy default, pixels with frequency more than 0.25 are not considered.")
fourierGroup.addParam('interp', params.EnumParam, default=self.INTERPOLATION_BSPLINE, label="Interpolation method: ", choices=["BSpline", "Nearest", "Linear"],
help="Method for interpolation.\nOptions:\n\nBSpline: Cubic BSpline\nNearest: Nearest Neighborhood\nLinear: Linear BSpline")

# Tilt related parameter group
tiltGroup = form.addGroup('Tilt parameters')
tiltGroup.addParam('tiltTypeGeneration', params.EnumParam, display=params.EnumParam.DISPLAY_COMBO, default=self.TYPE_N_SAMPLES,
Expand Down Expand Up @@ -156,20 +152,20 @@ def _insertAllSteps(self):
values[self.COLUMN_ANGLE_TILT] # angleTilt
)
angTable.write(angleFile, tableName='projectionAngles')

# Generating param file
paramDeps.append(self._insertFunctionStep(self.generateParamFile, tsId))

else:
# If type of generation is not from Tilt Series, generate single param file
paramDeps.append(self._insertFunctionStep(self.generateParamFile))

# Generating projections for each subtomogram
generationDeps = []
for subtomogram in self.inputSubtomograms.get():
tsId = '' if self.tiltTypeGeneration.get() != self.TYPE_TILT_SERIES or len([ts for ts in self.tiltRangeTS.get()]) == 1 else subtomogram.getCoordinate3D().getTomoId()
generationDeps.append(self._insertFunctionStep(self.generateSubtomogramProjections, subtomogram.getFileName(), tsId, prerequisites=paramDeps))

# Conditionally removing temporary files
if self.cleanTmps.get():
self._insertFunctionStep(self.removeTempFiles, prerequisites=generationDeps)
Expand Down Expand Up @@ -218,7 +214,7 @@ def generateSubtomogramProjections(self, subtomogram: Union[SubTomogram, Volume,
params += ' --method {}'.format(self.getMethodValue()) # Projection algorithm
params += ' --params {}'.format(self.getXmippParamPath(tsId=tsId)) # Path to Xmipp param file
self.runJob("xmipp_phantom_project", params)

def renameMetadataFile(self, metadataFile: str):
"""
This function renames the given metadata file with a generic name.
Expand Down Expand Up @@ -284,16 +280,16 @@ def createOutputStep(self):
row.setValue(MDL_CTF_DEFOCUSV, defV)
# TODO: This only works if the TS is aligned
row.setValue(MDL_CTF_DEFOCUS_ANGLE, 0.0)

# Add metadata row to file
row.addToMd(mdCtf)

# Write metadata file with modified info
mdCtf.write(self.getProjectionMetadataAbsolutePath(subtomogram))

# Add particles to set from metadata file
readSetOfParticles(self.getProjectionMetadataAbsolutePath(subtomogram), outputSetOfParticles)

# Defining the ouput with summary and source relation
outputSetOfParticles.setObjComment(self.getSummary(outputSetOfParticles))
self._defineOutputs(outputSetOfParticles=outputSetOfParticles)
Expand All @@ -320,7 +316,7 @@ def _validate(self):
errors.append(angleExtractionError)

return errors

# --------------------------- Auxiliary INFO functions --------------------------------------------
def _validateGenerationType(self):
# Initializing base error string
Expand Down Expand Up @@ -349,7 +345,7 @@ def _validateGenerationType(self):
elif subtomogram.getCoordinate3D().getTomoId() not in tsIdList:
error = 'At least one input subtomogram\'s 3D coordinate does not match any Tilt Series id.\n'
break

return baseErrorStr + error if error else ''

# --------------------------- UTILS functions --------------------------------------------
Expand Down Expand Up @@ -420,7 +416,7 @@ def getProjectionMetadataAbsolutePath(self, subtomogram: Union[SubTomogram, Volu
This function returns the full path of a given subtomogram's metadata file.
"""
return os.path.splitext(self.getProjectionAbsolutePath(subtomogram))[0] + '.xmd'

def getAngleFileAbsolutePath(self, tsId: str) -> str:
"""
This function returns the full path of a given tilt series's metadata angle file.
Expand Down Expand Up @@ -452,7 +448,7 @@ def getMethodValue(self) -> str:
methodString += 'nearest'
else:
methodString += 'linear'

# Returning complete fourier params
return methodString
elif self.transformMethod.get() == self.METHOD_REAL_SPACE:
Expand Down Expand Up @@ -485,7 +481,7 @@ def getReferenceMetadataFile(self) -> str:
based on a Tilt Series.
"""
return os.path.join(os.path.dirname(self.getXmippParamPath()), 'reference.xmd')

def getSummary(self, setOfParticles: SetOfParticles) -> str:
"""
Returns the summary of a given set of particles.
Expand All @@ -500,7 +496,7 @@ def getCorrectedDefocus(self, tiltAngle: Float, coordinates: Coordinate3D) -> Tu
"""
# Converting tilt angle to radians (received in degrees)
radiansTiltAngle = math.radians(tiltAngle)

# Calculating defocus direction
defocusDir = -1 if self.defocusDir.get() else 1

Expand All @@ -517,7 +513,7 @@ def getCorrectedDefocus(self, tiltAngle: Float, coordinates: Coordinate3D) -> Tu

# Obtain CTF's defocus
defocusU, defocusV = closestCTF.getDefocusU(), closestCTF.getDefocusV()

# Obtain and return corrected defocus
generalDefocus = (coordinates.getX() * math.cos(radiansTiltAngle) + coordinates.getZ() * math.sin(radiansTiltAngle)) * ts.getSamplingRate() * math.sin(radiansTiltAngle)
correctedDefU = defocusU + defocusDir * generalDefocus
Expand All @@ -532,7 +528,7 @@ def getClosestCTF(self, tiltSeries: TiltSeries, tiltAngle: Float) -> CTFModel:
# Initial distance
distance = 360

# Find ,
# Find ,
for tiltImage in tiltSeries:
# Obtaining difference in tilt between given angle and tilt image angle
tiltDistance = abs(tiltAngle - tiltImage.getTiltAngle())
Expand All @@ -542,17 +538,17 @@ def getClosestCTF(self, tiltSeries: TiltSeries, tiltAngle: Float) -> CTFModel:
if tiltDistance < distance:
distance = tiltDistance
outputCTF = tiltImage.getCTF()

# Returning closest CTF
return outputCTF

def getAngleDictionary(self) -> TypedDict:
"""
This function returs a dictionary containing all the angles of each Tilt Series of the input set
"""
# Initializing empty dictionary
angleDict = {}

if self.tiltTypeGeneration.get() == self.TYPE_TILT_SERIES:
for ts in self.tiltRangeTS.get():
tsId = ts.getTsId()
Expand Down
11 changes: 10 additions & 1 deletion xmipptomo/protocols/protocol_project_top.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
import numpy as np
from pwem.emlib.image import ImageHandler as ih
from pwem.emlib import lib
from pwem.objects import Particle, Transform, String, SetOfVolumes, SetOfParticles
from pwem.objects import Particle, Transform, String, SetOfVolumes, SetOfParticles, CTFModel, Acquisition
from pwem.protocols import ProtAnalysis3D
from pyworkflow import BETA
from pyworkflow.protocol.params import PointerParam, EnumParam, IntParam, BooleanParam, Form, LEVEL_ADVANCED
Expand Down Expand Up @@ -151,6 +151,11 @@ def createOutputStep(self):
imgSetOut.setSamplingRate(input.getSamplingRate())
imgSetOut.setAlignmentProj()

# Acquisition
newAquisition = Acquisition()
newAquisition.copy(input.getAcquisition())
imgSetOut.setAcquisition(newAquisition)

# Input could be SetOfVolumes or SetOfSubtomograms
for item in input.iterItems():
idx = item.getObjId()
Expand All @@ -164,6 +169,10 @@ def createOutputStep(self):
p.setTransform(transform)
imgSetOut.append(p)

# Add a faked CTF
fakeCtf= CTFModel(defocusU=0, defocusAngle=1, defocusV=0)
p.setCTF(fakeCtf)

self._defineOutputs(**{SubtomoProjectOutput.particles.name:imgSetOut})
self._defineSourceRelation(self.input, imgSetOut)

Expand Down
2 changes: 0 additions & 2 deletions xmipptomo/protocols/protocol_reconstruct_tomograms.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import numpy as np
import os

from pyworkflow import VERSION_2_0
from pyworkflow.object import Set, Float
from pyworkflow.protocol.params import (PointerParam, FloatParam, EnumParam, LEVEL_ADVANCED)
import pyworkflow.utils.path as path
Expand All @@ -51,7 +50,6 @@ class XmippProtReconstructTomograms(EMProtocol, ProtTomoBase):
Given a set of Tilt series with the corresponding alignment parameters. This protocol
will reconstruct the tomograms associated to the tilt series."""
_label = 'reconstruct tomogram'
_lastUpdateVersion = VERSION_2_0

RECONSTRUCT_ART = 0
RECONSTRUCT_SIRT = 1
Expand Down
3 changes: 1 addition & 2 deletions xmipptomo/protocols/protocol_resolution_local_monotomo.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import numpy as np
import os

from pyworkflow import VERSION_2_0
from pyworkflow.utils import getExt
from pyworkflow.object import Set, Float
from pyworkflow.protocol.params import (PointerParam, BooleanParam, FloatParam,
Expand Down Expand Up @@ -62,8 +61,8 @@ class XmippProtMonoTomo(EMProtocol, ProtTomoBase):
tomogram with the values of local resolution.
"""
_label = 'local Resolution MonoTomo'
_lastUpdateVersion = VERSION_2_0
_devStatus = UPDATED

def __init__(self, **args):
ProtAnalysis3D.__init__(self, **args)
self.min_res_init = Float()
Expand Down
14 changes: 7 additions & 7 deletions xmipptomo/protocols/protocol_subtomo_map_back.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,10 @@ class XmippProtSubtomoMapBack(EMProtocol, ProtTomoBase):
_label = 'map back subtomos'
_devStatus = BETA
_possibleOutputs = MapBackOutputs
stepsExecutionMode = STEPS_PARALLEL

def __init__(self, **args):
EMProtocol.__init__(self, **args)
self.stepsExecutionMode = STEPS_PARALLEL
self.tomos = None

# --------------------------- DEFINE param functions ------------------------
Expand Down Expand Up @@ -123,10 +123,10 @@ def _insertAllSteps(self):
# For each tomogram
for key, value in self._getTomogramsInvolved().items():
mapBackStepId = self._insertFunctionStep(self.runMapBack, value.getTsId(),
self.paintingType.get(),
self.removeBackground.get(),
self.threshold.get(),
prerequisites=prepRefId)
self.paintingType.get(),
self.removeBackground.get(),
self.threshold.get(),
prerequisites=prepRefId)

mapBacksStepIds.append(mapBackStepId)

Expand Down Expand Up @@ -357,7 +357,7 @@ def _validate(self):
subtomo = self.inputSubtomos.get().getFirstItem()
if not subtomo.hasCoordinate3D():
validateMsgs.append('Please provide a set of subtomograms which contains subtomograms with 3D '
'coordinates.')
'coordinates.')
return validateMsgs

def _summary(self):
Expand All @@ -380,5 +380,5 @@ def _methods(self):

if hasattr(self, MapBackOutputs.tomograms.name):
methods.append("A reference was mapped back %d times into %s." %
(setSize, self.getObjectTag(getattr(self, MapBackOutputs.tomograms.name))))
(setSize, self.getObjectTag(getattr(self, MapBackOutputs.tomograms.name))))
return methods
3 changes: 0 additions & 3 deletions xmipptomo/viewers/viewer_resolution_local_monotomo.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,6 @@
from matplotlib import cm
from pwem.wizards import ColorScaleWizardBase
from pyworkflow.gui.dialog import showError

import os

from pyworkflow.protocol.params import (LabelParam, EnumParam,
IntParam, LEVEL_ADVANCED, StringParam)
from pyworkflow.viewer import ProtocolViewer, DESKTOP_TKINTER
Expand Down

0 comments on commit d445061

Please sign in to comment.