def test_FRM(self): import swig_frm from sh_alignment.frm import frm_align from pytom_volume import vol, rotate, shift from pytom.basic.structures import Rotation, Shift from pytom.tools.maths import rotation_distance v = vol(32,32,32) v.setAll(0) vMod = vol(32,32,32) vRot = vol(32,32,32) v.setV(1,10,10,10) v.setV(1,20,20,20) v.setV(1,15,15,15) v.setV(1,7,21,7) rotation = Rotation(10,20,30) shiftO = Shift(1,-3,5) rotate(v,vRot,rotation.getPhi(),rotation.getPsi(),rotation.getTheta()) shift(vRot,vMod,shiftO.getX(),shiftO.getY(),shiftO.getZ()) pos, ang, score = frm_align(vMod, None, v, None, [4, 64], 10) rotdist = rotation_distance(ang1=rotation, ang2=ang) diffx = shiftO[0] - (pos[0] - 16) diffy = shiftO[1] - (pos[1] - 16) diffz = shiftO[2] - (pos[2] - 16) self.assertTrue( rotdist < 5., msg='Rotations are different') self.assertTrue( diffx < .5, msg='x-difference > .5') self.assertTrue( diffy < .5, msg='y-difference > .5') self.assertTrue( diffz < .5, msg='z-difference > .5')
def fromXML(self, xmlObj): from lxml.etree import _Element if xmlObj.__class__ != _Element: from pytom.basic.exceptions import ParameterError raise ParameterError('You must provide a valid XML object.') if xmlObj.tag == "FoundParticle": main = xmlObj else: main = xmlObj.xpath('FoundParticle') if len(main) == 0: from pytom.basic.exceptions import PyTomClassError raise PyTomClassError("This XML is not a FoundParticle.") main = main[0] from pytom.basic.structures import PickPosition, Rotation from pytom.score.score import fromXML as fromXMLScore self.filename = main.get('Filename') p = main.xpath('PickPosition')[0] self.pos = PickPosition() self.pos.fromXML(p) o = main.xpath('Rotation')[0] self.orient = Rotation() self.orient.fromXML(o) s = main.xpath('Score')[0] self.score = fromXMLScore(s)
def fourier_rotate_vol(v, angle): """ """ if v.dtype != np.dtype('float32') or np.isfortran(v) is False: v = np.array(v, dtype="float32", order="F") # get the rotation matrix from pytom.basic.structures import Rotation rot = Rotation(angle) m = rot.toMatrix() m = m.transpose() # get the invert rotation matrix m = np.array([m.getRow(0), m.getRow(1), m.getRow(2)], dtype="float32") m = m.flatten() dim_x, dim_y, dim_z = v.shape # # Do the ifftshift first and then fftshift! # v = np.fft.fftshift(np.fft.ifftshift(v)) # linearize it v = v.reshape((v.size)) # allocate the memory for the result res = np.zeros(v.size * 2, dtype="float32") # call the low level c function swig_nufft.fourier_rotate_vol(v, dim_x, dim_y, dim_z, m, res) res = res[::2] + 1j * res[1::2] res = res.reshape((dim_x, dim_y, dim_z), order='F') # inverse fft ans = np.fft.fftshift(np.real(np.fft.ifftn(np.fft.ifftshift(res)))) return np.array(ans, dtype="float32", order="F")
def setUp(self): """set up""" #self.ang1=Rotation(z1=-016,z2=-114,x=0.2) self.Pole1 = Rotation(z1=9, z2=-114, x=0.) self.Pole2 = Rotation(z1=9, z2=-114, x=180.) self.ang1 = Rotation(z1=-16, z2=-114, x=-180) self.ang2 = Rotation(z1=0, z2=5., x=0.0) self.eps = .001
def test_matrixMult(self): from pytom.basic.structures import Rotation from pytom.angles.angleFnc import differenceAngleOfTwoRotations rot1 = Rotation(z1=0.12480606462, z2=-0.00132220288025, x=0.106087546687) rot2 = Rotation(0, 0, 0) self.assertTrue( differenceAngleOfTwoRotations(rotation1=rot1, rotation2=rot2) < .2, 'difference between determined angles too large :(')
def fromXML(self, xmlObj): """ fromXML : Assigns values to result attributes from XML object @param xmlObj: A xml object @author: Thomas Hrabe """ from lxml.etree import _Element if xmlObj.__class__ != _Element: from pytom.basic.exceptions import ParameterError raise ParameterError( 'Is not a lxml.etree._Element! You must provide a valid XML object.' ) from pytom.score.score import fromXML as fromXMLScore from pytom.angles.angle import AngleObject if xmlObj.tag == "Result": result = xmlObj else: result = xmlObj.xpath('Result') if len(result) == 0: raise PyTomClassError( "This XML is not an MaximisationResult. No Result provided." ) result = result[0] from pytom.basic.structures import Particle, Reference, Rotation, Shift particle_element = result.xpath('Particle')[0] p = Particle('') p.fromXML(particle_element) self._particle = p r = result.xpath('Reference') ref = Reference('') ref.fromXML(r[0]) self._reference = ref scoreXML = result.xpath('Score')[0] self._score = fromXMLScore(scoreXML) shiftXML = result.xpath('Shift')[0] self._shift = Shift() self._shift.fromXML(shiftXML) rotationXML = result.xpath('Rotation')[0] self._rotation = Rotation() self._rotation.fromXML(rotationXML) angleElement = result.xpath('Angles') ang = AngleObject() self._angleObject = ang.fromXML(angleElement[0])
def __init__(self, particle='', reference=-1.0, score=-1.0, shift=-1.0, rotation=-1.0, angleObject=-1): from pytom.basic.structures import Particle, Reference, Shift, Rotation from numpy import long if particle.__class__ == str: self._particle = Particle(particle) elif particle.__class__ == Particle: self._particle = particle else: self._particle = Particle() if reference.__class__ == str: self._reference = Reference(reference) elif reference.__class__ == Reference: self._reference = reference else: self._reference = Reference() if shift.__class__ == list: self._shift = Shift(shift) elif shift.__class__ == float: self._shift = Shift() else: self._shift = shift if rotation.__class__ == list: self._rotation = Rotation(rotation) elif rotation.__class__ == Rotation: self._rotation = rotation else: self._rotation = Rotation() if score.__class__ == float: from pytom.score.score import xcfScore self._score = xcfScore() else: self._score = score if angleObject.__class__ == float or isinstance( angleObject, (int, long)): from pytom.angles.angleList import AngleList self._angleObject = AngleList() else: self._angleObject = angleObject
def nextRotation(self): """ nextRotation : @return: [z1 z2 x] for the next rotation or [None,None,None] after all rotations were sampled @author: Friedrich Foerster @change: Local Rotation had a bug causing too large rotations in Phi @date: 07/07/2014 """ if self._finished: return [None, None, None] from math import sin, ceil, pi, sqrt, atan2 #,modf from pytom.basic.structures import Rotation from pytom.angles.angleFnc import matToZXZ phi = self._currentZ1 if self._currentX == 0: npsi = 1 dpsi = 360. else: dpsi = self._increment / sin( float(self._currentX * self._increment) / 180. * pi) npsi = ceil(360. / dpsi) #make dpsi equidistant again dpsi = 360. / npsi localRotation = Rotation(z1=phi - self._currentZ2 * dpsi, z2=self._currentZ2 * dpsi, x=self._currentX * self._increment, paradigm='ZXZ') globalMatrix = localRotation.toMatrix() * self._startMatrix [phi, psi, theta] = matToZXZ(globalMatrix) if self._currentZ2 >= npsi - 1: self._currentZ2 = 0 if self._currentX >= ceil(self._shells / 2): self._currentX = 0 if self._currentZ1 >= self._shells * self._increment: self._finished = True return [self._startZ1, self._startZ2, self._startX] else: self._currentZ1 = self._currentZ1 + self._increment else: self._currentX = self._currentX + 1 else: self._currentZ2 = self._currentZ2 + 1 return [phi % 360, psi % 360, theta % 360]
def __init__(self, rotation, translation): from pytom.basic.structures import Rotation, Shift if rotation.__class__ == Rotation: pass elif rotation.__class__ == list: rotation = Rotation(rotation) else: raise RuntimeError("Rotation should be of type list or pytom.basic.structures.Rotation!") if not isinstance(translation, (Shift, list)): raise RuntimeError("Translation should be of type list or pytom.basic.structures.Shift!") super(TransformationMatrix, self).__init__(4,4) self.setRotationCoef(rotation.toMatrix()) self.setTranslationCoef(translation)
def append(self, phi, psi=[], theta=[]): """ append: Appends a combination of Euler Angles to the current list @param phi: Euler Angle or Rotation object or list object @param psi: Euler Angle @param theta: Euler Angle """ from pytom.basic.structures import Rotation if phi.__class__ == Rotation: self._rotationList.append(phi) elif phi.__class__ == list: self._rotationList.append(Rotation(phi[0], phi[1], phi[2])) else: self._rotationList.append(Rotation(phi, psi, theta))
def matPoleTest1(self): """ check that conversion to angle from matrix works for x == 0 """ z1 = 9 z2 = 360. - 114 x = 0. self.rot1 = Rotation(z1=z1, z2=z2, x=x) self.rot2 = Rotation(z1=0., z2=0., x=0.) newrot = self.rot2 * self.rot1 [nz1, nz2, nx] = matToZXZ(newrot.toMatrix(), inRad=False) self.assertTrue(nx == 0.0, 'Pole Test 1 failed: wrong x-angle') self.assertTrue( abs(nz2 + nz1 - z2 - z1) < 0.00001, 'Pole Test 2 failed: wrong assignment z1 and z2')
def project(v, rot, verbose=False): """ rotate and subsequently project volume along z @param v: volume @type v: L{pytom_volume.vol} @param rot: rotation - either Rotation object or single angle interpreted as rotation along y-axis @type rot: L{pytom.basic.structures.Rotation} or float @return: projection (2D image) @rtype: L{pytom_volume.vol} @author: FF """ from pytom_volume import vol from pytom_numpy import vol2npy, npy2vol from numpy import ndarray, float32 from pytom.basic.transformations import general_transform_crop from pytom.basic.structures import Rotation from numpy import sum as proj if not isinstance(v, vol): raise TypeError('project: v must be of type pytom_volume.vol! Got ' + str(v.__class__) + ' instead!') if isinstance(rot, float): rot = Rotation(z1=90., z2=270., x=rot, paradigm='ZXZ') if not isinstance(rot, Rotation): raise TypeError('project: rot must be of type Rotation or float! Got ' + str(v.__class__) + ' instead!') if verbose: print("project: Rotation for projection: "+str(rot)) rotvol = general_transform_crop(v=v, rot=rot, shift=None, scale=None, order=[0, 1, 2]) # slightly awkward: projection in numpy ... npvol = vol2npy(rotvol) npprojection = ndarray([v.sizeX(), v.sizeY(), 1], dtype=float32, buffer=None, offset=0, strides=npvol.strides, order='F') proj(npvol, axis=2, dtype=float32, out=npprojection) projection = npy2vol(npprojection,3) return projection
def matTestQ4(self): """ test that matToZXZ works for 180<z2<360 """ z1 = 169. z2 = 190. x = 10. self.rot1 = Rotation(z1=z1, z2=z2, x=x) self.rot2 = Rotation(z1=0., z2=0., x=0.) newrot = self.rot2 * self.rot1 [nz1, nz2, nx] = matToZXZ(newrot.toMatrix(), inRad=False) self.assertTrue(abs(nx - x) < self.eps, 'matTestQ3: nx and x differ') self.assertTrue( abs(nz1 - z1) < self.eps, 'matTestQ3: nz1 and z1 differ') self.assertTrue( abs(nz2 - z2) < self.eps, 'matTestQ3: nz2 and z2 differ')
def FoundParticle_Test(self): from pytom.localization.structures import FoundParticle from pytom.basic.structures import PickPosition, Rotation from pytom.score.score import FLCFScore r = Rotation([1, 2, 3]) p = PickPosition([4, 5, 6], originFilename='originalFilename') s = FLCFScore() s.setValue(0.2) a = FoundParticle(p, r, s, 'particleFilename') xmlObj = a.toXML() b = FoundParticle() b.fromXML(xmlObj) self.assertTrue(b.pos.toVector() == [4, 5, 6], msg='position not transferred from xml') self.assertTrue(b.pos.getOriginFilename() == 'originalFilename', msg='filename not transferred from xml') self.assertTrue(b.orient.toList() == [1, 2, 3], msg='orientation not transferred from xml') self.assertTrue(float(b.score.getValue()) == 0.2, msg='score not transferred from xml') self.assertTrue(b.filename == 'particleFilename', msg='particle filename not transferred from xml')
def frm_proxy(p, ref, freq, offset, binning, mask): from pytom_volume import read, pasteCenter, vol from pytom.basic.transformations import resize from pytom.basic.structures import Shift, Rotation from sh_alignment.frm import frm_align import time v = p.getVolume(binning) if mask.__class__ == str: maskBin = read(mask, 0, 0, 0, 0, 0, 0, 0, 0, 0, binning, binning, binning) if v.sizeX() != maskBin.sizeX() or v.sizeY() != maskBin.sizeY( ) or v.sizeZ() != maskBin.sizeZ(): mask = vol(v.sizeX(), v.sizeY(), v.sizeZ()) mask.setAll(0) pasteCenter(maskBin, mask) else: mask = maskBin pos, angle, score = frm_align(v, p.getWedge(), ref.getVolume(), None, [4, 64], freq, offset, mask) return (Shift([ pos[0] - v.sizeX() // 2, pos[1] - v.sizeY() // 2, pos[2] - v.sizeZ() // 2 ]), Rotation(angle), score, p.getFilename())
def __init__(self, shells=3, increment=3, z1Start=0.0, z2Start=0.0, xStart=0.0): """ @param shells: Number of shells to be scanned @param increment: Angular increment used @param z1Start: Start angle for Z1 rotation @param z2Start: Start angle for Z2 rotation @param xStart: Start angle for X rotation @author: Thomas Hrabe """ from pytom.basic.structures import Rotation self._shells = float(shells) if increment == 0.0: raise ValueError('LocalSampling : Increment is 0!') else: self._increment = float(increment) if shells == 0: raise ValueError('LocalSampling : Shells is 0!') self.setStartRotation(Rotation(z1=z1Start, z2=z2Start, x=xStart)) # initialize final rotation around z-axis of REFERENCE self.reset()
def alignTwoVolumes(particle,reference,angleObject,mask,score,preprocessing,progressBar=False): """ alignTwoVolumes: align two volumes with respect to each other @param particle: volume to be aligned @param reference: reference volume (not translated and rotated) @param angleObject: angular sampling @param mask: mask volume @param score: score type @param preprocessing: preprocessing parameters @param progressBar: show progress bar @type progressBar: bool """ from pytom.alignment.structures import GrowingAverageInterimResult from pytom.basic.structures import Rotation,Shift partVolume = particle.getVolume() refVolume = reference.getVolume() refWeight = reference.getWeighting() peak = bestAlignment(partVolume,refVolume,refWeight,particle.getWedge(), angleObject,score,mask,preprocessing) score.setValue(peak.getScoreValue()) return GrowingAverageInterimResult(particle,reference,Rotation(peak.getRotation()),Shift(peak.getShift()),score)
def matPoleTest2(self): """ check that conversion to angle from matrix works for x == 180 """ z1 = 9 z2 = -114 x = 180. self.rot1 = Rotation(z1=z1, z2=z2, x=x) self.rot2 = Rotation(z1=0., z2=0., x=0.) newrot = self.rot2 * self.rot1 [nz1, nz2, nx] = matToZXZ(newrot.toMatrix(), inRad=False) self.assertTrue(nx == 180.0, 'Pole Test 2 failed: wrong x-angle') self.assertTrue( abs( modf((nz2 - nz1 + 360.) / 360.)[0] * 360 - modf((z2 - z1 + 360.) / 360.)[0] * 360) < 0.00001, 'Pole Test 2 failed: z2 z1 not correct')
def fromXML(self, xmlObj=-1): """ fromXML : Assigns values to job attributes from XML object @param xmlObj: A xml object @author: Thomas Hrabe """ from lxml.etree import _Element from pytom.basic.structures import Rotation if xmlObj.__class__ != _Element or xmlObj.get('Type') not in [ 'LocalSampling', 'Equidistant', 'AV3Sampling' ]: raise TypeError( 'You must provide a valid XML-LocalSampling object.') if xmlObj.get('Type') == 'Equidistant': xmlObj = xmlObj.xpath('Parameters')[0] try: self._increment = float(xmlObj.get('Increment')) except TypeError: self._increment = float(xmlObj.get('AngleIncrement')) try: self._shells = float(xmlObj.get('Shells')) except TypeError: self._shells = float(xmlObj.get('NumberShells')) try: self._startZ1 = float(xmlObj.get('StartZ1')) self.av3 = False except: self._startZ1 = float(xmlObj.get('Phi_old')) self.av3 = True try: self._startZ2 = float(xmlObj.get('StartZ2')) except: self._startZ2 = float(xmlObj.get('Psi_old')) try: self._startX = float(xmlObj.get('StartX')) except: self._startX = float(xmlObj.get('Theta_old')) if self.av3: try: self._shellsParameter = int(xmlObj.get('ShellsParameter')) except TypeError: raise Exception('No ShellsParameter Defined') try: self._incrementParameter = int( xmlObj.get('IncrementParameter')) except TypeError: raise Exception('No IncrementParameter Defined') self.reset() self.setStartRotation(startRotation=Rotation( z1=self._startZ1, z2=self._startZ2, x=self._startX))
def getRotation(self): from pytom.basic.structures import Rotation if self._rotation.__class__ == list: return Rotation(self._rotation[0], self._rotation[1], self._rotation[2]) else: return self._rotation.copy()
def __init__(self, rotationList=None): """ @param rotationList: [phi,psi,theta] or one Rotation """ from pytom.basic.structures import Rotation self._rotationList = rotationList or [] if self._rotationList.__class__ == list and len( self._rotationList) == 3: #make sure its only one object self._rotationList = [ Rotation(rotationList[0], rotationList[1], rotationList[2]) ] elif self._rotationList.__class__ == list and len( self._rotationList) > 1: self._rotationList = [Rotation(rotationList[0])] elif self._rotationList.__class__ == Rotation: self._rotationList = [self._rotationList]
def _doAllInplaneRotations(self, z2, x): from pytom.basic.structures import Rotation from pytom.tools.macros import frange rotationList = [] for z1 in frange(0, 360, self._angleIncrement): rotationList.append(Rotation((self._startZ1 + z1) % 360, z2, x)) return rotationList
def setRotation(self, rotation): """ setRotation: @param rotation: """ from pytom.basic.structures import Rotation if rotation.__class__ == list: rotation = Rotation(rotation) self._rotation = rotation
def fourier_rotate_vol(v, angle): """Be careful with rotating a odd-sized volume, since nfft will not give correct result! """ # get the rotation matrix from pytom.basic.structures import Rotation rot = Rotation(angle) m = rot.toMatrix() m = m.transpose() # get the invert rotation matrix m = np.array([m.getRow(0), m.getRow(1), m.getRow(2)], dtype="float32") m = m.flatten() # prepare the volume from pytom_numpy import vol2npy v = vol2npy(v) dim_x, dim_y, dim_z = v.shape # twice shift means no shift! # v = np.fft.fftshift(v) # linearize it v = v.reshape((v.size)) # allocate the memory for the result res = np.zeros(v.size * 2, dtype="float32") # call the low level c function swig_nufft.fourier_rotate_vol(v, dim_x, dim_y, dim_z, m, res) res = res[::2] + 1j * res[1::2] res = res.reshape((dim_x, dim_y, dim_z), order='F') # inverse fft ans = np.fft.ifftshift(np.real(np.fft.ifftn(np.fft.ifftshift(res)))) # transfer to pytom volume format from sh.frm import np2vol res = np2vol(ans) return res
def run(self, verbose=False): from sh_alignment.frm import frm_align from pytom.basic.structures import Shift, Rotation from pytom.tools.ProgressBar import FixedProgBar while True: # get the job try: job = self.get_job() except: if verbose: print(self.node_name + ': end') break # get some non-job message, break it if verbose: prog = FixedProgBar(0, len(job.particleList) - 1, self.node_name + ':') i = 0 ref = job.reference[0].getVolume() # run the job for p in job.particleList: if verbose: prog.update(i) i += 1 v = p.getVolume() pos, angle, score = frm_align(v, p.getWedge(), ref, None, job.bw_range, job.freq, job.peak_offset, job.mask.getVolume()) p.setShift( Shift([ pos[0] - v.sizeX() / 2, pos[1] - v.sizeY() / 2, pos[2] - v.sizeZ() / 2 ])) p.setRotation(Rotation(angle)) p.setScore(FRMScore(score)) # average the particle list name_prefix = os.path.join( self.destination, self.node_name + '_' + str(job.max_iter)) self.average_sub_pl(job.particleList, name_prefix, job.weighting) # send back the result self.send_result( FRMResult(name_prefix, job.particleList, self.mpi_id)) pytom_mpi.finalise()
def setStartRotation(self, startRotation): """ setStartRotation: Sets start rotation. @param startRotation: The start rotation. @type startRotation: L{pytom.basic.structures.Rotation} @return: Reference to current object @author: FF """ from pytom.basic.structures import Rotation self._startZ1 = float(startRotation[0]) self._startZ2 = float(startRotation[1]) self._startX = float(startRotation[2]) self._startRotation = Rotation(z1=self._startZ1, z2=self._startZ2, x=self._startX, paradigm='ZXZ') self._startMatrix = self._startRotation.toMatrix() self.reset() return self
def fromXML(self, xmlObj): from lxml.etree import _Element if xmlObj.__class__ != _Element: raise RuntimeError( 'Is not a lxml.etree._Element! You must provide a valid XMLobject.' ) if xmlObj.tag == 'Angles': angleList_element = xmlObj else: RuntimeError( 'Is not an AngleList! You must provide a valid AngleList object.' ) from pytom.basic.structures import Rotation rotations = angleList_element.xpath('Rotation') # modified by chen for rotation in rotations: rot = Rotation(0, 0, 0) rot.fromXML(rotation) self._rotationList.append(rot)
def setStartRotation(self, rotation): """ """ from pytom.basic.structures import Rotation if rotation.__class__ == list: rotation = Rotation(rotation) if not rotation.__class__ == Rotation: raise TypeError('You must provide a Rotation to this function!') self._rotationList = [rotation] return self
def rotation_distance(ang1, ang2): """ rotation_distance: given two angles (lists), return the euler distance (degree). @param ang1: @type ang1: 3-dim list or L{pytom.basic.structures.Rotation} @param ang2: @type ang2: 3-dim list or L{pytom.basic.structures.Rotation} @return: distance in deg @rtype: float @author: FF """ from pytom.basic.structures import Rotation matrix1 = Rotation(ang1).toMatrix() matrix2 = Rotation(ang2).toMatrix() res = matrix1.elementwise_mult(matrix2) trace = res.trace() from math import pi, acos temp=0.5*(trace-1.0) if temp >= 1.0: return 0.0 if temp <= -1.0: return 180 return acos(temp)*180/pi
def vector2transRot(self, rot_trans): """ convert 6-dimensional vector to rotation and translation @param rot_trans: rotation and translation vector (6-dim: z1,z2,x \ angles, x,y,z, translations) @type rot_trans: L{list} @return: rotation of vol2, translation of vol2 @rtype: L{pytom.basic.Rotation}, L{pytom.basic.Shift} @author: FF """ from pytom.basic.structures import Rotation, Shift rot = Rotation() trans = Shift() for ii in range(0, 3): rot[ii] = self.rot_trans[ii] for ii in range(3, 6): trans[ii - 3] = self.rot_trans[ii] return rot, trans