Source code for pwem.protocols.protocol_export.protocol_export_DB

# **************************************************************************
# *
# * Authors:     Amaya Jimenez (ajimenez@cnb.csic.es)
# *              Marta Martinez (mmmtnez@cnb.csic.es)
# *              Roberto Marabini (roberto@cnb.csic.es)
# *
# * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
# *
# * 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 3 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

import pyworkflow.protocol.params as params
from pwem.convert import Ccp4Header

from pwem.convert.atom_struct import fromPDBToCIF, fromCIFTommCIF, \
    AtomicStructHandler
from pwem.emlib.image import ImageHandler
from pwem.protocols import EMProtocol
from pwem.objects import FSC
from pyworkflow.utils.path import copyFile

from pwem.constants import (SYM_I222, SYM_I222r, SYM_In25, SYM_In25r,
                            SYM_I2n3, SYM_I2n3r, SYM_I2n5, SYM_I2n5r,
                            SYM_DIHEDRAL_X, SYM_DIHEDRAL_Y, SYM_OCTAHEDRAL,
                            SYM_TETRAHEDRAL_222, SYM_TETRAHEDRAL_Z3,
                            SYM_TETRAHEDRAL_Z3R, SCIPION_SYM_NAME, SYM_CYCLIC
                            )

from pwem.convert.symmetry import SymmetryHelper
[docs]class ProtExportDataBases(EMProtocol): """ generates files for elements to submit structures to EMDB/PDB. Since mmcif/pdb is only partially supported by some software the protocol creates 4 versions of the atomic struct file with the hope that at least one of them will work. """ _label = 'export to emdb/pdb' _program = "" VOLUMENAME = 'main_map.mrc' HALFVOLUMENAME = 'half_map_%d.mrc' COORDINATEFILENAME = 'coordinates.cif' ADDITIONALVOLUMEDIR = "addMaps" ADDITIONALVOLUMENAME = "map_%02d.mrc" MASKDIR = "masks" MASKNAME = "mask_%02d.mrc" SYMNAMEORDER = "symmetry_%s_%d.txt" SYMNAME = "symmetry_%s.txt" SYMPLIFIED_STRUCT = "symplified_atom_structure.cif" SYM_CHOICES = { SYM_CYCLIC: SCIPION_SYM_NAME[SYM_CYCLIC], SYM_DIHEDRAL_X: SCIPION_SYM_NAME[SYM_DIHEDRAL_X], SYM_DIHEDRAL_Y: SCIPION_SYM_NAME[SYM_DIHEDRAL_Y], SYM_TETRAHEDRAL_222: SCIPION_SYM_NAME[SYM_TETRAHEDRAL_222], SYM_TETRAHEDRAL_Z3: SCIPION_SYM_NAME[SYM_TETRAHEDRAL_Z3], SYM_TETRAHEDRAL_Z3R: SCIPION_SYM_NAME[SYM_TETRAHEDRAL_Z3R], SYM_OCTAHEDRAL: SCIPION_SYM_NAME[SYM_OCTAHEDRAL], SYM_I222: SCIPION_SYM_NAME[SYM_I222], SYM_I222r: SCIPION_SYM_NAME[SYM_I222r], SYM_In25: SCIPION_SYM_NAME[SYM_In25], SYM_In25r: SCIPION_SYM_NAME[SYM_In25r], SYM_I2n3: SCIPION_SYM_NAME[SYM_I2n3], SYM_I2n3r: SCIPION_SYM_NAME[SYM_I2n3r], SYM_I2n5: SCIPION_SYM_NAME[SYM_I2n5], SYM_I2n5r: SCIPION_SYM_NAME[SYM_I2n5r], } # --------------------------- DEFINE param functions ---------------------- def _defineParams(self, form): form.addSection(label='Input') form.addParam('exportVolume', params.PointerParam, label="Main EM map to export", allowsNull=True, pointerClass='Volume', help='This EM map is mandatory for EMDB and it ' 'will be exported using mrc format. ' 'If this map is associated to their respective ' 'half maps, they will be exported as well.') form.addParam('additionalVolumesToExport', params.BooleanParam, default=False, label='Additional maps to export?', help='Select YES if you want to add some more ' 'EM maps to export.') form.addParam('exportAdditionalVolumes', params.MultiPointerParam, label="Additional EM maps to export", allowsNull=True, condition='additionalVolumesToExport == True', pointerClass='Volume', help='These additional EM maps will be also exported ' 'using mrc format.') form.addParam('exportFSC', params.PointerParam, label="FSC file to export", allowsNull=True, pointerClass='FSC, SetOfFSCs', help='This FSCs will be exported using XML format') form.addParam('masksToExport', params.BooleanParam, default=False, label='Masks to export?', help='Select YES if you want to add some ' 'masks to export.') form.addParam('exportMasks', params.MultiPointerParam, label="Masks to export", allowsNull=True, condition='masksToExport == True', pointerClass='Mask', help='These mask will be exported using mrc format') form.addParam('exportAtomStruct', params.PointerParam, label="Atomic structure to export", allowsNull=True, pointerClass='AtomStruct', help='This atomic structure will be exported using mmCIF format') form.addParam('exportPicture', params.PathParam, label="Image to export", allowsNull=True, pointerClass='Image', help='This image is mandatory for EMDB') form.addParam("exportSymmetryGrp", params.EnumParam, label="symmetry group", choices=list(self.SYM_CHOICES.values()), default=SYM_CYCLIC, help='symmetry group of the map.' ) form.addParam('symmetryOrder', params.IntParam, default=1, condition='exportSymmetryGrp<=%d' % SYM_DIHEDRAL_X, label='Symmetry Order', help='Order of cyclic symmetry.') form.addParam('filesPath', params.PathParam, important=True, label="Export to directory", help="Directory where the files will be generated.") # --------------------------- INSERT steps functions ---------------------- def _insertAllSteps(self): self.dirName = self.filesPath.get() self._insertFunctionStep('createDirectoryStep', self.dirName) if self.exportVolume.get() is not None: self._insertFunctionStep('exportVolumeStep') if self.additionalVolumesToExport: self._insertFunctionStep('exportAdditionalVolumeStep') if self.exportFSC.get() is not None: self._insertFunctionStep('exportFSCStep') if self.masksToExport: self._insertFunctionStep('exportMasksStep') if self.exportAtomStruct.get() is not None: self._insertFunctionStep('exportAtomStructStep') if self.exportPicture.get() is not None: self._insertFunctionStep('exportImageStep') if self.exportSymmetryGrp.get() != SYM_CYCLIC or \ self.symmetryOrder.get() != 1: self._insertFunctionStep('exportSymmetryStep') # --------------------------- STEPS functions -----------------------------
[docs] def createDirectoryStep(self, dirPath): try: os.makedirs(dirPath) except OSError: if not os.path.isdir(dirPath): print("Can not create directory %s" % dirPath) raise
[docs] def exportSymmetryStep(self): """ Export symmetry information in a file """ # OUTPUT FILE NAME order = self.symmetryOrder.get() symGrp = self.exportSymmetryGrp.get() if order != 1: outSymFileName = os.path.join(self.dirName, self.SYMNAMEORDER % (SCIPION_SYM_NAME[symGrp], order)) else: outSymFileName = os.path.join(self.dirName, self.SYMNAME % (SCIPION_SYM_NAME[symGrp])) # get list of matrices symHelper = SymmetryHelper() (matrices, planes) = symHelper.getSymmetryMatricesAndPlanes(symGrp, order) # write them t list with open(outSymFileName, 'w') as f: for matrix in matrices: for line in matrix[:3]: f.write('%f %f %f %f\n' % (line[0], line[1], line[2], line[3])) f.write('\n') with open(outSymFileName.replace("txt", "pdb"), 'w') as f: f.write("REMARK 350 APPLY THE FOLLOWING TO CHAINS: A, B place chains here\n") f.write("REMARK 350 AND CHAINS: ...\n") for i, matrix in enumerate(matrices, 1): for j, line in enumerate(matrix[:3], 1): f.write("REMARK 350 BIOMT%d %2d %.6f %.6f %.6f %.6f\n" % (j, i, line[0], line[1], line[2], line[3]))
# REMARK 350 APPLY THE FOLLOWING TO CHAINS: A, B, C, D, E, F, G, H, I # REMARK 350 AND CHAINS: J, K, L, M, N, O, P # REMARK 350 BIOMT1 1 1.000000 0.000000 0.000000 0.00000 # REMARK 350 BIOMT2 1 0.000000 1.000000 0.000000 0.00000 # REMARK 350 BIOMT3 1 0.000000 0.000000 1.000000 0.00000 # REMARK 350 BIOMT1 2 0.309017 0.500000 -0.809017 0.00000 # REMARK 350 BIOMT2 2 0.500000 -0.809017 -0.309017 0.00000 # REMARK 350 BIOMT3 2 -0.809017 -0.309017 -0.500000 0.00000
[docs] def exportVolumeStep(self): inVolFileName = self.exportVolume.get().getFileName() inVol = self.exportVolume.get() outVolFileName = os.path.join(self.dirName, self.VOLUMENAME) shifts = inVol.getOrigin(force=True).getShifts() sampling = inVol.getSamplingRate() ccp4header = Ccp4Header(inVolFileName) ccp4header.fixFile(inVolFileName, outVolFileName, shifts, sampling=sampling) # Do we have half volumes? if self.exportVolume.get().hasHalfMaps(): ih = ImageHandler() for counter, half_map in enumerate( self.exportVolume.get().getHalfMaps().split(','), 1): outVolFileName = os.path.join(self.dirName, self.HALFVOLUMENAME % counter) ccp4header.fixFile(half_map, outVolFileName, shifts, sampling=sampling)
[docs] def exportAdditionalVolumeStep(self): outputDir = os.path.join(self.dirName, self.ADDITIONALVOLUMEDIR) self.createDirectoryStep(outputDir) ih = ImageHandler() for counter, map in enumerate(self.exportAdditionalVolumes, 1): map = map.get() inVolFileName = map.getFileName() outVolFileName = os.path.join(outputDir, self.ADDITIONALVOLUMENAME % counter) shifts = map.getOrigin(force=True).getShifts() sampling = map.getSamplingRate() ccp4header = Ccp4Header(inVolFileName) ccp4header.fixFile(inVolFileName, outVolFileName, shifts, sampling=sampling)
[docs] def exportFSCStep(self): exportFSC = self.exportFSC.get() if isinstance(self.exportFSC.get(), FSC): fscSet = self._createSetOfFSCs() fscSet.append(exportFSC) else: fscSet = exportFSC dirName = self.filesPath.get() for i, exportFSC in enumerate(fscSet, 1): x, y = exportFSC.getData() fnFSC = os.path.join(dirName, "fsc_%02d.xml" % i) fo = open(fnFSC, "w") fo.write('<fsc title="FSC(%s)" xaxis="Resolution (A-1)" ' 'yaxis="Correlation Coefficient">\n' % os.path.join(dirName, self.VOLUMENAME)) for k in range(len(x)): fo.write("<coordinate>\n") fo.write("<x>%f</x>\n" % x[k]) fo.write("<y>%f</y>\n" % y[k]) fo.write("</coordinate>\n") fo.write("</fsc>\n") fo.close()
[docs] def exportMasksStep(self): outputDir = os.path.join(self.dirName, self.MASKDIR) self.createDirectoryStep(outputDir) for counter, mask in enumerate(self.exportMasks, 1): mask = mask.get() inVolFileName = mask.getFileName() outVolFileName = os.path.join(outputDir, self.MASKNAME % counter) shifts = mask.getOrigin(force=True).getShifts() sampling = mask.getSamplingRate() ccp4header = Ccp4Header(inVolFileName) ccp4header.fixFile(inVolFileName, outVolFileName, shifts, sampling=sampling)
[docs] def exportAtomStructStep(self): exportAtomStruct = self.exportAtomStruct.get() originStructPath = exportAtomStruct.getFileName() dirName = self.filesPath.get() destinyStructPath = os.path.join(dirName, self.COORDINATEFILENAME) destinySympleStructPath = os.path.join(dirName, self.SYMPLIFIED_STRUCT) # save input atom struct with no change baseName = os.path.basename(originStructPath) localPath = os.path.abspath(os.path.join(dirName, baseName)) copyFile(originStructPath, localPath) # call biopython to simplify atom struct and save it aSH = AtomicStructHandler() aSH.read(originStructPath) aSH.write(destinySympleStructPath) # if pdb convert to mmcif calling maxit twice if originStructPath.endswith(".pdb"): # convert pdb to cif using maxit program log = self._log fromPDBToCIF(originStructPath, destinyStructPath, log) try: # convert cif to mmCIF by using maxit program fromCIFTommCIF(destinyStructPath, destinyStructPath, log) except Exception as e: pass # if cif convert to mmcif using maxit elif originStructPath.endswith(".cif"): # convert cif to mmCIF by using maxit program log = self._log try: fromCIFTommCIF(originStructPath, destinyStructPath, log) except Exception as e: pass
[docs] def exportImageStep(self): imageBaseFileName = os.path.basename(self.exportPicture.get()) outputFile = os.path.join(self.dirName, imageBaseFileName) copyFile(self.exportPicture.get(), outputFile)
# --------------------------- INFO functions ------------------------------ def _validate(self): message = [] fnPath = self.filesPath.get() if fnPath == "" or fnPath is None: message.append("You must set a path to export.") return message def _summary(self): message = "Data Available at : *%s*" % self.filesPath.get() return [message] def _methods(self): return [] # --------------------------- UTILS functions ---------------------------------
[docs] def getFnPath(self, label='volume'): return os.path.join(self.filesPath.get(), self._getFileName(label))