# **************************************************************************
# *
# * 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 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'
# *
# **************************************************************************
"""
This module contains classes related with EM
"""
import os
from pkg_resources import parse_version
import pyworkflow as pw
from pyworkflow.protocol import Protocol
from pyworkflow.utils import getSubclasses
from pyworkflow.viewer import Viewer
from pyworkflow.wizard import Wizard
import pyworkflow.plugin
from .constants import *
from .objects import EMObject
from .tests import defineDatasets
from .utils import *
__version__ = '3.3.0'
NO_VERSION_FOUND_STR = "0.0"
CUDA_LIB_VAR = 'CUDA_LIB'
_logo = "scipion_icon.png"
_references = ["delaRosaTrevin201693"]
[docs]class Config(pw.Config):
_get = pw.Config._get
_join = pw.Config._join
EM_ROOT = _join(_get(EM_ROOT_VAR, _join(pw.Config.SCIPION_SOFTWARE, 'em')))
# Default XMIPP_HOME: needed here for ShowJ viewers
XMIPP_HOME = _join(_get('XMIPP_HOME', os.path.join(EM_ROOT, 'xmipp')))
# Get java home, we might need to provide correct default value. Use SCIPION_JAVA_HOME to force it when there is other JAVA_HOME you don't want/cant to change: e.g. pycharm debugging.
JAVA_HOME = _get('SCIPION_JAVA_HOME', _get('JAVA_HOME', ''))
JAVA_MAX_MEMORY = _get('JAVA_MAX_MEMORY', '4')
# MPI
MPI_LIBDIR = _get('MPI_LIBDIR', '/usr/lib64/mpi/gcc/openmpi/lib')
MPI_BINDIR = _get('MPI_BINDIR', '/usr/lib64/mpi/gcc/openmpi/bin')
# CUDA
CUDA_LIB = _get(CUDA_LIB_VAR, '/usr/local/cuda/lib64')
CUDA_BIN = _get('CUDA_BIN', '/usr/local/cuda/bin')
MAX_PREVIEW_FILE_SIZE = float(_get("MAX_PREVIEW_FILE_SIZE", DEFAULT_MAX_PREVIEW_FILE_SIZE))
# OLD CHIMERA variable
CHIMERA_OLD_BINARY_PATH = _get("CHIMERA_OLD_BINARY_PATH",'')
# Path to either ImageJ or Fiji binary program
IMAGEJ_BINARY_PATH = _get("IMAGEJ_BINARY_PATH",'')
[docs]class Domain(pyworkflow.plugin.Domain):
_name = __name__
_objectClass = EMObject
_protocolClass = Protocol
_viewerClass = Viewer
_wizardClass = Wizard
_baseClasses = getSubclasses(EMObject, globals())
[docs]class Plugin(pyworkflow.plugin.Plugin):
_url = URL
@classmethod
def _defineEmVar(cls, varName, defaultValue):
""" Shortcut method to define variables prepending EM_ROOT if variable is not absolute"""
# Get the value, either whatever is in the environment or a join of EM_ROOT + defaultValue
value = os.environ.get(varName, os.path.join(Config.EM_ROOT, defaultValue))
# CASE-1 : Users might have used ~ and that has to be expanded
value = os.path.expanduser(value)
# CASE-2 :Old configs 2.0 will likely have:
# EM_ROOT = software/em
# CHIMERA_HOME = %(EM_ROOT)s/chimera-13.0.1
# ...
#
# this end up in the environment resolved like: software/em/chimera-13.0.1
# whereas as default values will come as absolute:
# /<scipion_home>/software/em/chimera-13.0.1
# In any case we join it (absolute paths will not join)
value = os.path.join(pw.Config.SCIPION_HOME, value)
cls._addVar(varName, value)
[docs] @classmethod
def getMaxitHome(cls):
return cls.getVar(MAXIT_HOME)
[docs] @classmethod
def getMaxitBin(cls):
return os.path.join(cls.getMaxitHome(), 'bin', MAXIT)
@classmethod
def _defineVariables(cls):
# Avoid defining variables from children that does not define variables.
if cls == Plugin:
cls._defineVar(EM_ROOT_VAR, pwem.Config.EM_ROOT)
cls._defineEmVar(MAXIT_HOME, 'maxit-10.1')
# Take this initialization event to define own datasets
defineDatasets()
# Register filehandlers too
cls._registerFileHandlers()
[docs] @classmethod
def defineBinaries(cls, env):
cls.defineBinariesMaxit(False, env)
[docs] @classmethod
def defineBinariesMaxit(cls, default, env):
# If not defined already (several plugins needs this and call this but has to be added once
if not env.hasPackage(MAXIT):
MAXIT_URL = 'https://sw-tools.rcsb.org/apps/MAXIT/maxit-v10.100-prod-src.tar.gz'
MAXIT_TAR = 'maxit-v10.100-prod-src.tar.gz'
maxit_commands = [('make -j 1 binary ', ['bin/maxit'])]
env.addPackage(MAXIT, version='10.1',
tar=MAXIT_TAR,
url=MAXIT_URL,
neededProgs=['gcc', 'flex', 'make', 'bison', 'tcsh'],
commands=maxit_commands,
default=default) # scipion installb maxit
# requirements bison, flex, gcc
maxit10 = env.getTarget(env._getExtName(MAXIT, "10.1"))
maxit10.setDefault(default)
[docs] @classmethod
def guessCudaVersion(cls, variable, default="10.1"):
""" Guesses the cuda version from a variable
:param variable: Name of a variable defined by a plugin
:param default: Default value in case cuda is not found
:return Version after parsing the variable or default"""
return cls.getVersionFromVariable(variable, default=default, pattern="cuda")
[docs] @classmethod
def getVersionFromVariable(cls, variable, default=NO_VERSION_FOUND_STR, pattern=None):
""" Returns a Version instance from parsing the content of
a variable
:param variable: Variable name to use and parse
:param default: Optional. Default value to return in case version is not found
:param pattern: Optional. If passed, the pattern will be used to locate the folder
:return Version after parsing the variable"""
value = cls.getVar(variable)
return cls.getVersionFromPath(value, default= default, pattern=pattern)
[docs] @classmethod
def getVersionFromPath(cls, path, separator="-", default=NO_VERSION_FOUND_STR, pattern=None):
""" Resolves path to the realpath (links) and returns the last part
of the path after the separator as a Version object.
If separator is not present returns None
:param path: string containing a path with a version as part of its name
:param separator: Optional. defaults to "-".
:param default: Optional. Default version ("X.Y" string) to return if no version is found
:param pattern: Optional. If passed, the pattern will be used to locate the folder
:return Version object filled with version found or 0.0
"""
path = os.path.realpath(path)
if pattern is not None:
path = findFolderWithPattern(path, pattern)
if path is None:
return parse_version(default)
parts = path.split(separator)
if len(parts)>=2:
# Version should be the last bit
versionStr = parts[-1]
return parse_version(versionStr)
else:
return parse_version(default)
@classmethod
def _registerFileHandlers(cls):
# register file handlers to preview info in the Filebrowser....
from pyworkflow.gui.browser import FileTreeProvider, STANDARD_IMAGE_EXTENSIONS
from .viewers.filehandlers import MdFileHandler, ParticleFileHandler, VolFileHandler, StackHandler, ChimeraHandler, ImajeJFileHandler
register = FileTreeProvider.registerFileHandler
register(MdFileHandler(), '.xmd', '.star', '.pos', '.ctfparam', '.doc')
register(ParticleFileHandler(),
'.xmp', '.tif', '.tiff', '.spi', '.mrc', '.map', '.raw',
'.inf', '.dm3', '.em', '.pif', '.psd', '.spe', '.ser', '.img',
'.hed', *STANDARD_IMAGE_EXTENSIONS)
register(VolFileHandler(), '.vol', '.hdf', '.rec')
register(StackHandler(), '.stk', '.mrcs', '.st', '.pif', '.dm4', '.ali')
register(ChimeraHandler(), '.bild', '.mrc', '.pdb', '.vol', '.hdf', '.cif', '.mmcif')
if Config.IMAGEJ_BINARY_PATH:
register(ImajeJFileHandler(), '.mrcs', '.mrc', '.st', '.ali', '.rec', '.tif', '.tiff', *STANDARD_IMAGE_EXTENSIONS)
else:
msg= "Optional: ImageJ of Fiji not configured can be configured to open files from the File Browser." \
" Please add 'IMAGEJ_BINARY_PATH' to the config file (%s)" \
"and point to the binary file that will open the files." % pw.Config.SCIPION_CONFIG
logger.info(msg)
[docs]def findFolderWithPattern(path, pattern):
"""
Returns the first folder found from the right that matches the pattern
:param path: path to do the search on
:param pattern: pattern to look for. No regex for now, just a contains
:return the folder matching the pattern or None
"""
previous, last = os.path.split(path)
# If end reached: windows Paths and linux paths seems to end in a different way
if previous == "" or last=="":
return None
elif pattern in last:
return last
else:
return findFolderWithPattern(previous, pattern)