<commit_before># cerbero - a multi-platform build system for Open Source software
# Copyright (C) 2012 Andoni Morales Alastruey <ylatuya@gmail.com>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Library General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library 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
# Library General Public License for more details.
#
# You should have received a copy of the GNU Library General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.

import os
import sys

from cerbero import enums
from cerbero.errors import FatalError, ConfigurationError
from cerbero.utils import _, system_info, validate_packager, to_unixpath
from cerbero.utils import messages as m

CONFIG_DIR = os.path.expanduser('~/.cerbero')
CONFIG_EXT = 'cbc'
DEFAULT_CONFIG_FILENAME = 'cerbero.%s' % CONFIG_EXT
DEFAULT_CONFIG_FILE = os.path.join(CONFIG_DIR, DEFAULT_CONFIG_FILENAME)
DEFAULT_GIT_ROOT = 'git+ssh://git.keema.collabora.co.uk/git/gst-sdk/'
DEFAULT_WIX_PREFIX = 'C:\\\\Program Files\\Windows Installer XML v3.5\\bin\\'
DEFAULT_ALLOW_PARALLEL_BUILD = False
DEFAULT_PACKAGER = "Default <default@change.me>"
CERBERO_UNINSTALLED = 'CERBERO_UNINSTALLED'
#FIXME change it with autotools
DATA_DIR = os.path.join(os.path.dirname(__file__), '..',  'data')

Platform = enums.Platform
Architecture = enums.Architecture
Distro = enums.Distro
DistroVersion = enums.DistroVersion

class Config (object):

    _properties = ['platform', 'target_platform', 'arch', 'target_arch',
                   'prefix', 'recipes_dir', 'host', 'build', 'target',
                   'sources', 'local_sources', 'lib_suffix', 'git_root',
                   'distro', 'target_distro', 'environ_dir', 'cache_file',
                   'toolchain_prefix', 'distro_version',
                   'target_distro_version', 'allow_system_libs',
                   'packages_dir', 'wix_prefix', 'py_prefix',
                   'install_dir', 'allow_parallel_build', 'num_of_cpus',
                   'use_configure_cache', 'packages_prefix', 'packager',
                   'data_dir']

    def __init__(self, filename=None, load=True):
        self._check_uninstalled()

        for a in self._properties:
            setattr(self, a, None)

        if not load:
            return

        # First load the default configuration
        self.load_defaults()

        # Next parse the main configuration file
        if os.path.exists(DEFAULT_CONFIG_FILE):
            self.parse(DEFAULT_CONFIG_FILE)
        else:
            msg = _('Using default configuration because %s is missing') % \
                    DEFAULT_CONFIG_FILE
            m.warning(msg)

        # Next, if a config file is provided use it to override the settings
        # from the main configuration file
        if filename is not None:
            if os.path.exists(filename):
                self.parse(filename)
                self.filename = DEFAULT_CONFIG_FILE
            else:
                raise ConfigurationError(_("Configuration file %s doesn't "
                                           "exsits") % filename)

        # Next, load the platform configuration
        self._load_platform_config()

        # Finally fill the missing gaps in the config
        self._load_last_defaults()

        self.validate_properties()

        self.setup_env()
        self._create_path(self.local_sources)
        self._create_path(self.sources)

    def parse(self, filename, reset=True):
        config = {'os': os}
        if not reset:
            for prop in self._properties:
                if hasattr(self, prop):
                    config[prop] = getattr(self, prop)

        try:
            execfile(filename, config)
        except:
            raise ConfigurationError(_('Could not include config file (%s)') %
                             filename)
        for key in self._properties:
            if key in config:
                self.set_property(key, config[key], True)

    def setup_env(self):
        self._create_path(self.prefix)

        os.environ['CERBERO_PREFIX'] = self.prefix

        libdir = os.path.join(self.prefix, 'lib%s' % self.lib_suffix)
        self.libdir = libdir

        # Get paths for environment variables
        includedir = os.path.join(self.prefix, 'include')
        bindir = os.path.join(self.prefix, 'bin')
        manpathdir = os.path.join(self.prefix, 'share', 'man')
        infopathdir = os.path.join(self.prefix, 'share', 'info')
        pkgconfigdatadir = os.path.join(self.prefix, 'share', 'pkgconfig')
        pkgconfigdir = os.path.join(libdir, 'pkgconfig')
        typelibpath = os.path.join(self.libdir, 'girepository-1.0')
        xdgdatadir = os.path.join(self.prefix, 'share')
        xdgconfigdir = os.path.join(self.prefix, 'etc', 'xdg')
        xcursordir = os.path.join(self.prefix, 'share', 'icons')
        aclocal = os.environ.get('ACLOCAL', 'aclocal')
        aclocaldir = os.path.join(self.prefix, 'share', 'aclocal')
        perl5lib = ':'.join(
                [to_unixpath(os.path.join(self.prefix, 'lib', 'perl5')),
                to_unixpath(os.path.join(self.prefix, 'lib', 'perl5',
                                         'site_perl', '5.8'))])
        gstpluginpath = os.path.join(self.prefix, 'lib', 'gstreamer-0.10')
        gstregistry = os.path.join(os.path.expanduser('~'), '.gstreamer-0.10',
                                    '.cerbero-registry-%s' % self.target_arch)
        pythonpath = os.path.join(self.prefix, self.py_prefix, 'site-packages')

        if self.platform == Platform.LINUX:
            xdgdatadir += ":/usr/share:/usr/local/share"

        self._create_path(aclocaldir)

        # Most of these variables are extracted from jhbuild
        # FIXME: add python when needed
        env = {'LD_LIBRARY_PATH': libdir,
               'LDFLAGS': '-L%s %s' % (libdir,  os.environ.get('LDFLAGS', '')),
               'C_INCLUDE_PATH': includedir,
               'CPLUS_INCLUDE_PATH': includedir,
               'DYLD_FALLBACK_LIBRARY_PATH': libdir,
               'PATH': self._join_path(os.environ.get('PATH', ''), bindir),
               'MANPATH': manpathdir,
               'INFOPATH': infopathdir,
               'PKG_CONFIG_PATH': '%s' % pkgconfigdatadir,
               'PKG_CONFIG_LIBDIR': '%s' % pkgconfigdir,
               'GI_TYPELIB_PATH': typelibpath,
               'XDG_DATA_DIRS': xdgdatadir,
               'XDG_CONFIG_DIRS': xdgconfigdir,
               'XCURSOR_PATH': xcursordir,
               'ACLOCAL_FLAGS': '-I %s' % aclocaldir,
               'ACLOCAL': aclocal,
               'PERL5LIB': perl5lib,
               'MONO_PREFIX': self.prefix,
               'MONO_GAC_PREFIX': self.prefix,
               'GST_PLUGIN_PATH': gstpluginpath,
               'GST_REGISTRY': gstregistry,
               'PYTHONPATH': pythonpath
               }

        if self.platform == Platform.WINDOWS:
            # for pkg-config installed with the toolchain
            env['ACLOCAL_FLAGS'] += ' -I %s/share/aclocal' % self.toolchain_prefix
            env['ACLOCAL'] = '%s %s' % (aclocal, env['ACLOCAL_FLAGS'])

        # set all the variables
        self.env = env
        for e, v in env.iteritems():
            os.environ[e] = v

    def _check_uninstalled(self):
        self.uninstalled = int(os.environ.get(CERBERO_UNINSTALLED, 0)) == 1

    def _create_path(self, path):
        if not os.path.exists(path):
            try:
                os.makedirs(path)
            except:
                raise FatalError(_('directory (%s) can not be created') % path)

    def _join_path(self, path1, path2):
        if self.platform == Platform.WINDOWS:
            separator = ';'
        else:
            separator = ':'
        return "%s%s%s" % (path1, separator, path2)

    def _load_platform_config(self):
        platform_config = os.path.join(self.environ_dir, '%s.config' %
                                       self.target_platform)
        arch_config = os.path.join(self.environ_dir, '%s_%s.config' %
                                   (self.target_platform, self.target_arch))

        for config in [platform_config, arch_config]:
            if os.path.exists(config):
                self.parse(config, reset=False)

    def _load_last_defaults(self):
        cerbero_home = os.path.expanduser('~/cerbero')
        self.set_property('prefix', os.path.join(cerbero_home, 'dist'))
        self.set_property('install_dir', self.prefix)
        self.set_property('sources', os.path.join(cerbero_home, 'sources'))
        self.set_property('local_sources',
                os.path.join(cerbero_home, 'sources', 'local'))

    def load_defaults(self):
        cerbero_home = os.path.expanduser('~/cerbero')
        self.set_property('cache_file', None)
        self.set_property('prefix', None)
        self.set_property('sources', None)
        self.set_property('local_sources', None)
        if not self.uninstalled:
            self.set_property('recipes_dir',
                              os.path.join(cerbero_home, 'recipes'))
            self.set_property('packages_dir',
                              os.path.join(cerbero_home, 'packages'))
        else:
            self.set_property('recipes_dir',
                os.path.join(os.path.dirname(__file__), '..', 'recipes'))
            self.set_property('packages_dir',
                os.path.join(os.path.dirname(__file__), '..', 'packages'))
        self.set_property('git_root', DEFAULT_GIT_ROOT)
        self.set_property('allow_parallel_build', DEFAULT_ALLOW_PARALLEL_BUILD)
        self.set_property('wix_prefix', DEFAULT_WIX_PREFIX)
        self.set_property('host', None)
        self.set_property('build', None)
        self.set_property('target', None)
        platform, arch, distro, distro_version, num_of_cpus = system_info()
        self.set_property('platform', platform)
        self.set_property('num_of_cpus', num_of_cpus)
        self.set_property('target_platform', platform)
        self.set_property('arch', arch)
        self.set_property('target_arch', arch)
        self.set_property('distro', distro)
        self.set_property('target_distro', distro)
        self.set_property('distro_version', distro_version)
        self.set_property('target_distro_version', distro_version)
        self.set_property('packages_prefix', None)
        self.set_property('packager', DEFAULT_PACKAGER)
        self.set_property('py_prefix', 'lib/python%s.%s' %
                (sys.version_info[0], sys.version_info[1]))
        self.set_property('lib_suffix', '')
        if not self.uninstalled:
            self.set_property('data_dir', DATA_DIR)
            self.set_property('environ_dir', os.path.join(CONFIG_DIR))
        else:
            self.set_property('data_dir',
                os.path.join(os.path.dirname(__file__), '..', 'data'))
            self.set_property('environ_dir',
                os.path.join(os.path.dirname(__file__), '..', 'config'))
        self.set_property('allow_system_libs', True)
        self.set_property('use_configure_cache', False)

    def validate_properties(self):
        if not validate_packager(self.packager):
            raise FatalError(_('packager "%s" must be in the format "Name <email>"') % self.packager)

    def set_property(self, name, value, force=False):
        if name not in self._properties:
            raise ConfigurationError('Unkown key %s' % name)
        if force or getattr(self, name) is None:
            setattr(self, name, value)
<commit_msg>config: clean-up code for paths<commit_after># cerbero - a multi-platform build system for Open Source software
# Copyright (C) 2012 Andoni Morales Alastruey <ylatuya@gmail.com>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Library General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library 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
# Library General Public License for more details.
#
# You should have received a copy of the GNU Library General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.

import os
import sys

from cerbero import enums
from cerbero.errors import FatalError, ConfigurationError
from cerbero.utils import _, system_info, validate_packager, to_unixpath
from cerbero.utils import messages as m

CONFIG_DIR = os.path.expanduser('~/.cerbero')
CONFIG_EXT = 'cbc'
DEFAULT_CONFIG_FILENAME = 'cerbero.%s' % CONFIG_EXT
DEFAULT_CONFIG_FILE = os.path.join(CONFIG_DIR, DEFAULT_CONFIG_FILENAME)
DEFAULT_GIT_ROOT = 'git+ssh://git.keema.collabora.co.uk/git/gst-sdk/'
DEFAULT_WIX_PREFIX = 'C:\\\\Program Files\\Windows Installer XML v3.5\\bin\\'
DEFAULT_ALLOW_PARALLEL_BUILD = False
DEFAULT_PACKAGER = "Default <default@change.me>"
CERBERO_UNINSTALLED = 'CERBERO_UNINSTALLED'
#FIXME change it with autotools
DATA_DIR = os.path.join(os.path.dirname(__file__), '..',  'data')

Platform = enums.Platform
Architecture = enums.Architecture
Distro = enums.Distro
DistroVersion = enums.DistroVersion

class Config (object):

    _properties = ['platform', 'target_platform', 'arch', 'target_arch',
                   'prefix', 'recipes_dir', 'host', 'build', 'target',
                   'sources', 'local_sources', 'lib_suffix', 'git_root',
                   'distro', 'target_distro', 'environ_dir', 'cache_file',
                   'toolchain_prefix', 'distro_version',
                   'target_distro_version', 'allow_system_libs',
                   'packages_dir', 'wix_prefix', 'py_prefix',
                   'install_dir', 'allow_parallel_build', 'num_of_cpus',
                   'use_configure_cache', 'packages_prefix', 'packager',
                   'data_dir']

    def __init__(self, filename=None, load=True):
        self._check_uninstalled()

        for a in self._properties:
            setattr(self, a, None)

        if not load:
            return

        # First load the default configuration
        self.load_defaults()

        # Next parse the main configuration file
        if os.path.exists(DEFAULT_CONFIG_FILE):
            self.parse(DEFAULT_CONFIG_FILE)
        else:
            msg = _('Using default configuration because %s is missing') % \
                    DEFAULT_CONFIG_FILE
            m.warning(msg)

        # Next, if a config file is provided use it to override the settings
        # from the main configuration file
        if filename is not None:
            if os.path.exists(filename):
                self.parse(filename)
                self.filename = DEFAULT_CONFIG_FILE
            else:
                raise ConfigurationError(_("Configuration file %s doesn't "
                                           "exsits") % filename)

        # Next, load the platform configuration
        self._load_platform_config()

        # Finally fill the missing gaps in the config
        self._load_last_defaults()

        self.validate_properties()

        self.setup_env()
        self._create_path(self.local_sources)
        self._create_path(self.sources)

    def parse(self, filename, reset=True):
        config = {'os': os}
        if not reset:
            for prop in self._properties:
                if hasattr(self, prop):
                    config[prop] = getattr(self, prop)

        try:
            execfile(filename, config)
        except:
            raise ConfigurationError(_('Could not include config file (%s)') %
                             filename)
        for key in self._properties:
            if key in config:
                self.set_property(key, config[key], True)

    def setup_env(self):
        self._create_path(self.prefix)

        os.environ['CERBERO_PREFIX'] = self.prefix

        libdir = os.path.join(self.prefix, 'lib%s' % self.lib_suffix)
        self.libdir = libdir

        # Get paths for environment variables
        includedir = os.path.join(self.prefix, 'include')
        bindir = os.path.join(self.prefix, 'bin')
        manpathdir = os.path.join(self.prefix, 'share', 'man')
        infopathdir = os.path.join(self.prefix, 'share', 'info')
        pkgconfigdatadir = os.path.join(self.prefix, 'share', 'pkgconfig')
        pkgconfigdir = os.path.join(libdir, 'pkgconfig')
        typelibpath = os.path.join(self.libdir, 'girepository-1.0')
        xdgdatadir = os.path.join(self.prefix, 'share')
        xdgconfigdir = os.path.join(self.prefix, 'etc', 'xdg')
        xcursordir = os.path.join(self.prefix, 'share', 'icons')
        aclocal = os.environ.get('ACLOCAL', 'aclocal')
        aclocaldir = os.path.join(self.prefix, 'share', 'aclocal')
        perl5lib = ':'.join(
                [to_unixpath(os.path.join(self.prefix, 'lib', 'perl5')),
                to_unixpath(os.path.join(self.prefix, 'lib', 'perl5',
                                         'site_perl', '5.8'))])
        gstpluginpath = os.path.join(self.prefix, 'lib', 'gstreamer-0.10')
        gstregistry = os.path.join(os.path.expanduser('~'), '.gstreamer-0.10',
                                    '.cerbero-registry-%s' % self.target_arch)
        pythonpath = os.path.join(self.prefix, self.py_prefix, 'site-packages')

        if self.platform == Platform.LINUX:
            xdgdatadir += ":/usr/share:/usr/local/share"

        self._create_path(aclocaldir)

        # Most of these variables are extracted from jhbuild
        # FIXME: add python when needed
        env = {'LD_LIBRARY_PATH': libdir,
               'LDFLAGS': '-L%s %s' % (libdir,  os.environ.get('LDFLAGS', '')),
               'C_INCLUDE_PATH': includedir,
               'CPLUS_INCLUDE_PATH': includedir,
               'DYLD_FALLBACK_LIBRARY_PATH': libdir,
               'PATH': self._join_path(os.environ.get('PATH', ''), bindir),
               'MANPATH': manpathdir,
               'INFOPATH': infopathdir,
               'PKG_CONFIG_PATH': '%s' % pkgconfigdatadir,
               'PKG_CONFIG_LIBDIR': '%s' % pkgconfigdir,
               'GI_TYPELIB_PATH': typelibpath,
               'XDG_DATA_DIRS': xdgdatadir,
               'XDG_CONFIG_DIRS': xdgconfigdir,
               'XCURSOR_PATH': xcursordir,
               'ACLOCAL_FLAGS': '-I %s' % aclocaldir,
               'ACLOCAL': aclocal,
               'PERL5LIB': perl5lib,
               'MONO_PREFIX': self.prefix,
               'MONO_GAC_PREFIX': self.prefix,
               'GST_PLUGIN_PATH': gstpluginpath,
               'GST_REGISTRY': gstregistry,
               'PYTHONPATH': pythonpath
               }

        if self.platform == Platform.WINDOWS:
            # for pkg-config installed with the toolchain
            env['ACLOCAL_FLAGS'] += ' -I %s/share/aclocal' % self.toolchain_prefix
            env['ACLOCAL'] = '%s %s' % (aclocal, env['ACLOCAL_FLAGS'])

        # set all the variables
        self.env = env
        for e, v in env.iteritems():
            os.environ[e] = v

    def _check_uninstalled(self):
        self.uninstalled = int(os.environ.get(CERBERO_UNINSTALLED, 0)) == 1

    def _create_path(self, path):
        if not os.path.exists(path):
            try:
                os.makedirs(path)
            except:
                raise FatalError(_('directory (%s) can not be created') % path)

    def _join_path(self, path1, path2):
        if self.platform == Platform.WINDOWS:
            separator = ';'
        else:
            separator = ':'
        return "%s%s%s" % (path1, separator, path2)

    def _load_platform_config(self):
        platform_config = os.path.join(self.environ_dir, '%s.config' %
                                       self.target_platform)
        arch_config = os.path.join(self.environ_dir, '%s_%s.config' %
                                   (self.target_platform, self.target_arch))

        for config in [platform_config, arch_config]:
            if os.path.exists(config):
                self.parse(config, reset=False)

    def _load_last_defaults(self):
        cerbero_home = os.path.expanduser('~/cerbero')
        self.set_property('prefix', os.path.join(cerbero_home, 'dist'))
        self.set_property('install_dir', self.prefix)
        self.set_property('sources', os.path.join(cerbero_home, 'sources'))
        self.set_property('local_sources',
                os.path.join(cerbero_home, 'sources', 'local'))

    def load_defaults(self):
        cerbero_home = os.path.expanduser('~/cerbero')
        self.set_property('cache_file', None)
        self.set_property('prefix', None)
        self.set_property('sources', None)
        self.set_property('local_sources', None)
        self.set_property('git_root', DEFAULT_GIT_ROOT)
        self.set_property('allow_parallel_build', DEFAULT_ALLOW_PARALLEL_BUILD)
        self.set_property('wix_prefix', DEFAULT_WIX_PREFIX)
        self.set_property('host', None)
        self.set_property('build', None)
        self.set_property('target', None)
        platform, arch, distro, distro_version, num_of_cpus = system_info()
        self.set_property('platform', platform)
        self.set_property('num_of_cpus', num_of_cpus)
        self.set_property('target_platform', platform)
        self.set_property('arch', arch)
        self.set_property('target_arch', arch)
        self.set_property('distro', distro)
        self.set_property('target_distro', distro)
        self.set_property('distro_version', distro_version)
        self.set_property('target_distro_version', distro_version)
        self.set_property('packages_prefix', None)
        self.set_property('packager', DEFAULT_PACKAGER)
        self.set_property('py_prefix', 'lib/python%s.%s' %
                (sys.version_info[0], sys.version_info[1]))
        self.set_property('lib_suffix', '')
        if not self.uninstalled:
            self.set_property('recipes_dir',
                              os.path.join(cerbero_home, 'recipes'))
            self.set_property('packages_dir',
                              os.path.join(cerbero_home, 'packages'))
            self.set_property('data_dir', DATA_DIR)
            self.set_property('environ_dir', os.path.join(CONFIG_DIR))
        else:
            self.set_property('data_dir', self._relative_path('data'))
            self.set_property('environ_dir', self._relative_path('config'))
            self.set_property('recipes_dir', self._relative_path('recipes'))
            self.set_property('packages_dir', self._relative_path('packages'))
        self.set_property('allow_system_libs', True)
        self.set_property('use_configure_cache', False)

    def validate_properties(self):
        if not validate_packager(self.packager):
            raise FatalError(_('packager "%s" must be in the format "Name <email>"') % self.packager)

    def set_property(self, name, value, force=False):
        if name not in self._properties:
            raise ConfigurationError('Unkown key %s' % name)
        if force or getattr(self, name) is None:
            setattr(self, name, value)

    def _relative_path(self, path):
        p = os.path.join(os.path.dirname(__file__), '..', path)
        return os.path.abspath(p)
<|endoftext|>


<commit_before>'''Script to import/export all the skeleton related objects.'''

# ***** BEGIN LICENSE BLOCK *****
#
# Copyright © 2005-2012, NIF File Format Library and Tools contributors.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
#    * Redistributions of source code must retain the above copyright
#      notice, this list of conditions and the following disclaimer.
#
#    * Redistributions in binary form must reproduce the above
#      copyright notice, this list of conditions and the following
#      disclaimer in the documentation and/or other materials provided
#      with the distribution.
#
#    * Neither the name of the NIF File Format Library and Tools
#      project nor the names of its contributors may be used to endorse
#      or promote products derived from this software without specific
#      prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# ***** END LICENSE BLOCK *****

import os

import bpy
import mathutils

from pyffi.formats.nif import NifFormat

class Armature():

    def __init__(self, parent):
        self.nif_common = parent

        # dictionary of bones, maps Blender bone name to matrix that maps the
        # NIF bone matrix on the Blender bone matrix
        # Recall from the import script
        #   B' = X * B,
        # where B' is the Blender bone matrix, and B is the NIF bone matrix,
        # both in armature space. So to restore the NIF matrices we need to do
        #   B = X^{-1} * B'
        # Hence, we will restore the X's, invert them, and store those inverses in the
        # following dictionary.
        self.nif_common.bones_extra_matrix_inv = {}

    def rebuild_bones_extra_matrices(self):
        """Recover bone extra matrices."""

        try:
            bonetxt = bpy.data.texts["BoneExMat"]
        except NameError:
            return
        # Blender bone names are unique so we can use them as keys.
        for b_textline in bonetxt.lines:
            line = b_textline.body
            if len(line) > 0:
                # reconstruct matrix from text
                b, m = line.split('/')
                try:
                    matrix = mathutils.Matrix(
                        [[float(f) for f in row.split(',')]
                         for row in m.split(';')])
                except:
                    raise NifExportError('Syntax error in BoneExMat buffer.')
                # Check if matrices are clean, and if necessary fix them.
                quat = matrix.to_3x3().to_quaternion()
                if sum(sum(abs(x) for x in vec)
                       for vec in matrix.to_3x3() - quat.to_matrix()) > 0.01:
                    self.nif_common.warning(
                        "Bad bone extra matrix for bone %s. \n"
                        "Attempting to fix... but bone transform \n"
                        "may be incompatible with existing animations." % b)
                    self.nif_common.warning("old invalid matrix:\n%s" % matrix)
                    trans = matrix.to_translation()
                    matrix = quat.to_matrix().resize_4x4()
                    matrix[0][3] = trans[0]
                    matrix[1][3] = trans[1]
                    matrix[2][3] = trans[2]
                    self.nif_common.warning("new valid matrix:\n%s" % matrix)
                # Matrices are stored inverted for easier math later on.
                matrix.invert()
                self.set_bone_extra_matrix_inv(b, matrix)

    def set_bone_extra_matrix_inv(self, bone_name, matrix):
        """Set bone extra matrix, inverted. The bone_name is first converted
        to blender style (to ensure compatibility with older imports).
        """
        self.nif_common.bones_extra_matrix_inv[self.nif_common.get_bone_name_for_blender(bone_name)] = matrix

    def get_bone_extra_matrix_inv(self, bone_name):
        """Get bone extra matrix, inverted. The bone_name is first converted
        to blender style (to ensure compatibility with older imports).
        """
        return self.nif_common.bones_extra_matrix_inv[self.nif_common.get_bone_name_for_blender(bone_name)]

    def export_bones(self, arm, parent_block):
        """Export the bones of an armature."""
        # the armature was already exported as a NiNode
        # now we must export the armature's bones
        assert( arm.type == 'ARMATURE' )

        # find the root bones
        # dictionary of bones (name -> bone)
        bones = dict(list(arm.data.bones.items()))
        root_bones = []
        for root_bone in list(bones.values()):
            while root_bone.parent in list(bones.values()):
                root_bone = root_bone.parent
            if root_bones.count(root_bone) == 0:
                root_bones.append(root_bone)

        if (bpy.types.Action(arm)):
            bones_ipo = bpy.types.ActionGroups(arm) # dictionary of Bone Ipos (name -> ipo)
        else:
            bones_ipo = {} # no ipos

        bones_node = {} # maps bone names to NiNode blocks

        # here all the bones are added
        # first create all bones with their keyframes
        # and then fix the links in a second run

        # ok, let's create the bone NiNode blocks
        for bone in list(bones.values()):
            # create a new block for this bone
            node = self.nif_common.create_ninode(bone)
            # doing bone map now makes linkage very easy in second run
            bones_node[bone.name] = node

            # add the node and the keyframe for this bone
            node.name = self.nif_common.get_full_name(bone.name)
            if self.nif_common.properties.game in ('OBLIVION', 'FALLOUT_3'):
                # default for Oblivion bones
                # note: bodies have 0x000E, clothing has 0x000F
                node.flags = 0x000E
            elif self.nif_common.properties.game in ('CIVILIZATION_IV', 'EMPIRE_EARTH_II'):
                if bone.children:
                    # default for Civ IV/EE II bones with children
                    node.flags = 0x0006
                else:
                    # default for Civ IV/EE II final bones
                    node.flags = 0x0016
            elif self.nif_common.properties.game in ('DIVINITY_2',):
                if bone.children:
                    # default for Div 2 bones with children
                    node.flags = 0x0186
                elif bone.name.lower()[-9:] == 'footsteps':
                    node.flags = 0x0116
                else:
                    # default for Div 2 final bones
                    node.flags = 0x0196
            else:
                node.flags = 0x0002 # default for Morrowind bones
            self.nif_common.export_matrix(bone, 'localspace', node) # rest pose

            # bone rotations are stored in the IPO relative to the rest position
            # so we must take the rest position into account
            # (need original one, without extra transforms, so extra = False)
            bonerestmat = self.get_bone_rest_matrix(bone, 'BONESPACE',
                                                    extra = False)
            try:
                bonexmat_inv = mathutils.Matrix(
                    self.get_bone_extra_matrix_inv(bone.name))
            except KeyError:
                bonexmat_inv = mathutils.Matrix()
                bonexmat_inv.identity()
            if bone.name in bones_ipo:
                self.nif_common.animationhelper.export_keyframes(
                    bones_ipo[bone.name], 'localspace', node,
                    bind_matrix = bonerestmat, extra_mat_inv = bonexmat_inv)

            # does bone have priority value in NULL constraint?
            for constr in arm.pose.bones[bone.name].constraints:
                # yes! store it for reference when creating the kf file
                if constr.name[:9].lower() == "priority:":
                    self.nif_common.bone_priorities[
                        self.get_bone_name_for_nif(bone.name)
                        ] = int(constr.name[9:])

        # now fix the linkage between the blocks
        for bone in list(bones.values()):
            # link the bone's children to the bone
            if bone.children:
                self.nif_common.debug("Linking children of bone %s" % bone.name)
                for child in bone.children:
                    # bone.children returns also grandchildren etc.
                    # we only want immediate children, so do a parent check
                    if child.parent.name == bone.name:
                        bones_node[bone.name].add_child(bones_node[child.name])
            # if it is a root bone, link it to the armature
            if not bone.parent:
                parent_block.add_child(bones_node[bone.name])

    def export_children(self, b_obj, parent_block):
        """Export all children of blender object b_obj as children of
        parent_block."""
        # loop over all obj's children
        for b_obj_child in b_obj.children:
            # is it a regular node?
            if b_obj_child.type in ['MESH', 'EMPTY', 'ARMATURE']:
                if (b_obj.type != 'ARMATURE'):
                    # not parented to an armature
                    self.nif_common.export_node(b_obj_child, 'localspace',
                                     parent_block, b_obj_child.name)
                else:
                    # this object is parented to an armature
                    # we should check whether it is really parented to the
                    # armature using vertex weights
                    # or whether it is parented to some bone of the armature
                    parent_bone_name = b_obj_child.parent_bone
                    if parent_bone_name is None:
                        self.nif_common.export_node(b_obj_child, 'localspace',
                                         parent_block, b_obj_child.name)
                    else:
                        # we should parent the object to the bone instead of
                        # to the armature
                        # so let's find that bone!
                        nif_bone_name = self.nif_common.get_full_name(parent_bone_name)
                        for bone_block in self.nif_common.blocks:
                            if isinstance(bone_block, NifFormat.NiNode) and \
                                bone_block.name.decode() == nif_bone_name:
                                # ok, we should parent to block
                                # instead of to parent_block
                                # two problems to resolve:
                                #   - blender bone matrix is not the exported
                                #     bone matrix!
                                #   - blender objects parented to bone have
                                #     extra translation along the Y axis
                                #     with length of the bone ("tail")
                                # this is handled in the get_object_srt function
                                self.nif_common.export_node(b_obj_child, 'localspace',
                                                 bone_block, b_obj_child.name)
                                break
                        else:
                            assert(False) # BUG!

    def get_bone_rest_matrix(self, bone, space, extra = True, tail = False):
        """Get bone matrix in rest position ("bind pose"). Space can be
        ARMATURESPACE or BONESPACE. This returns also a 4x4 matrix if space
        is BONESPACE (translation is bone head plus tail from parent bone).
        If tail is True then the matrix translation includes the bone tail."""
        # Retrieves the offset from the original NIF matrix, if existing
        correction_matrix = mathutils.Matrix()
        if extra:
            try:
                correction_matrix = mathutils.Matrix(
                    self.get_bone_extra_matrix_inv(bone.name))
            except KeyError:
                correction_matrix.identity()
        else:
            correction_matrix.identity()
        if (space == 'ARMATURESPACE'):
            matrix = mathutils.Matrix(bone.matrix_local)
            if tail:
                tail_pos = bone.tail_local
                matrix[0][3] = tail_pos[0]
                matrix[1][3] = tail_pos[1]
                matrix[2][3] = tail_pos[2]
            return correction_matrix * matrix
        elif (space == 'BONESPACE'):
            if bone.parent:
                # not sure why extra = True is required here
                # but if extra = extra then transforms are messed up, so keep
                # for now
                parinv = self.get_bone_rest_matrix(bone.parent, 'ARMATURESPACE',
                                                   extra = True, tail = False)
                parinv.invert()
                return self.get_bone_rest_matrix(bone,
                                                 'ARMATURESPACE',
                                                 extra = extra,
                                                 tail = tail) * parinv
            else:
                return self.get_bone_rest_matrix(bone, 'ARMATURESPACE',
                                                 extra = extra, tail = tail)
        else:
            assert(False) # bug!

<commit_msg>Converted armature_export parent to nif_export to match import functions and corrected connections<commit_after>'''Script to import/export all the skeleton related objects.'''

# ***** BEGIN LICENSE BLOCK *****
#
# Copyright © 2005-2012, NIF File Format Library and Tools contributors.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
#    * Redistributions of source code must retain the above copyright
#      notice, this list of conditions and the following disclaimer.
#
#    * Redistributions in binary form must reproduce the above
#      copyright notice, this list of conditions and the following
#      disclaimer in the documentation and/or other materials provided
#      with the distribution.
#
#    * Neither the name of the NIF File Format Library and Tools
#      project nor the names of its contributors may be used to endorse
#      or promote products derived from this software without specific
#      prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# ***** END LICENSE BLOCK *****

import os

import bpy
import mathutils

from pyffi.formats.nif import NifFormat

class Armature():

    def __init__(self, parent):
        self.nif_export = parent

        # dictionary of bones, maps Blender bone name to matrix that maps the
        # NIF bone matrix on the Blender bone matrix
        # Recall from the import script
        #   B' = X * B,
        # where B' is the Blender bone matrix, and B is the NIF bone matrix,
        # both in armature space. So to restore the NIF matrices we need to do
        #   B = X^{-1} * B'
        # Hence, we will restore the X's, invert them, and store those inverses in the
        # following dictionary.
        self.nif_export.bones_extra_matrix_inv = {}

    def rebuild_bones_extra_matrices(self):
        """Recover bone extra matrices."""

        try:
            bonetxt = bpy.data.texts["BoneExMat"]
        except NameError:
            return
        # Blender bone names are unique so we can use them as keys.
        for b_textline in bonetxt.lines:
            line = b_textline.body
            if len(line) > 0:
                # reconstruct matrix from text
                b, m = line.split('/')
                try:
                    matrix = mathutils.Matrix(
                        [[float(f) for f in row.split(',')]
                         for row in m.split(';')])
                except:
                    raise NifExportError('Syntax error in BoneExMat buffer.')
                # Check if matrices are clean, and if necessary fix them.
                quat = matrix.to_3x3().to_quaternion()
                if sum(sum(abs(x) for x in vec)
                       for vec in matrix.to_3x3() - quat.to_matrix()) > 0.01:
                    self.nif_export.warning(
                        "Bad bone extra matrix for bone %s. \n"
                        "Attempting to fix... but bone transform \n"
                        "may be incompatible with existing animations." % b)
                    self.nif_export.warning("old invalid matrix:\n%s" % matrix)
                    trans = matrix.to_translation()
                    matrix = quat.to_matrix().resize_4x4()
                    matrix[0][3] = trans[0]
                    matrix[1][3] = trans[1]
                    matrix[2][3] = trans[2]
                    self.nif_export.warning("new valid matrix:\n%s" % matrix)
                # Matrices are stored inverted for easier math later on.
                matrix.invert()
                self.set_bone_extra_matrix_inv(b, matrix)

    def set_bone_extra_matrix_inv(self, bone_name, matrix):
        """Set bone extra matrix, inverted. The bone_name is first converted
        to blender style (to ensure compatibility with older imports).
        """
        self.nif_export.bones_extra_matrix_inv[self.nif_export.get_bone_name_for_blender(bone_name)] = matrix

    def get_bone_extra_matrix_inv(self, bone_name):
        """Get bone extra matrix, inverted. The bone_name is first converted
        to blender style (to ensure compatibility with older imports).
        """
        return self.nif_export.bones_extra_matrix_inv[self.nif_export.get_bone_name_for_blender(bone_name)]

    def export_bones(self, arm, parent_block):
        """Export the bones of an armature."""
        # the armature was already exported as a NiNode
        # now we must export the armature's bones
        assert( arm.type == 'ARMATURE' )

        # find the root bones
        # dictionary of bones (name -> bone)
        bones = dict(list(arm.data.bones.items()))
        root_bones = []
        for root_bone in list(bones.values()):
            while root_bone.parent in list(bones.values()):
                root_bone = root_bone.parent
            if root_bones.count(root_bone) == 0:
                root_bones.append(root_bone)

        if (bpy.types.Action(arm)):
            bones_ipo = bpy.types.ActionGroups(arm) # dictionary of Bone Ipos (name -> ipo)
        else:
            bones_ipo = {} # no ipos

        bones_node = {} # maps bone names to NiNode blocks

        # here all the bones are added
        # first create all bones with their keyframes
        # and then fix the links in a second run

        # ok, let's create the bone NiNode blocks
        for bone in list(bones.values()):
            # create a new block for this bone
            node = self.nif_export.create_ninode(bone)
            # doing bone map now makes linkage very easy in second run
            bones_node[bone.name] = node

            # add the node and the keyframe for this bone
            node.name = self.nif_export.get_full_name(bone.name)
            if self.nif_export.properties.game in ('OBLIVION', 'FALLOUT_3'):
                # default for Oblivion bones
                # note: bodies have 0x000E, clothing has 0x000F
                node.flags = 0x000E
            elif self.nif_export.properties.game in ('CIVILIZATION_IV', 'EMPIRE_EARTH_II'):
                if bone.children:
                    # default for Civ IV/EE II bones with children
                    node.flags = 0x0006
                else:
                    # default for Civ IV/EE II final bones
                    node.flags = 0x0016
            elif self.nif_export.properties.game in ('DIVINITY_2',):
                if bone.children:
                    # default for Div 2 bones with children
                    node.flags = 0x0186
                elif bone.name.lower()[-9:] == 'footsteps':
                    node.flags = 0x0116
                else:
                    # default for Div 2 final bones
                    node.flags = 0x0196
            else:
                node.flags = 0x0002 # default for Morrowind bones
            self.nif_export.export_matrix(bone, 'localspace', node) # rest pose

            # bone rotations are stored in the IPO relative to the rest position
            # so we must take the rest position into account
            # (need original one, without extra transforms, so extra = False)
            bonerestmat = self.get_bone_rest_matrix(bone, 'BONESPACE',
                                                    extra = False)
            try:
                bonexmat_inv = mathutils.Matrix(
                    self.get_bone_extra_matrix_inv(bone.name))
            except KeyError:
                bonexmat_inv = mathutils.Matrix()
                bonexmat_inv.identity()
            if bone.name in bones_ipo:
                self.nif_export.animationhelper.export_keyframes(
                    bones_ipo[bone.name], 'localspace', node,
                    bind_matrix = bonerestmat, extra_mat_inv = bonexmat_inv)

            # does bone have priority value in NULL constraint?
            for constr in arm.pose.bones[bone.name].constraints:
                # yes! store it for reference when creating the kf file
                if constr.name[:9].lower() == "priority:":
                    self.nif_export.bone_priorities[
                        self.get_bone_name_for_nif(bone.name)
                        ] = int(constr.name[9:])

        # now fix the linkage between the blocks
        for bone in list(bones.values()):
            # link the bone's children to the bone
            if bone.children:
                self.nif_export.debug("Linking children of bone %s" % bone.name)
                for child in bone.children:
                    # bone.children returns also grandchildren etc.
                    # we only want immediate children, so do a parent check
                    if child.parent.name == bone.name:
                        bones_node[bone.name].add_child(bones_node[child.name])
            # if it is a root bone, link it to the armature
            if not bone.parent:
                parent_block.add_child(bones_node[bone.name])

    def export_children(self, b_obj, parent_block):
        """Export all children of blender object b_obj as children of
        parent_block."""
        # loop over all obj's children
        for b_obj_child in b_obj.children:
            # is it a regular node?
            if b_obj_child.type in ['MESH', 'EMPTY', 'ARMATURE']:
                if (b_obj.type != 'ARMATURE'):
                    # not parented to an armature
                    self.nif_export.export_node(b_obj_child, 'localspace',
                                     parent_block, b_obj_child.name)
                else:
                    # this object is parented to an armature
                    # we should check whether it is really parented to the
                    # armature using vertex weights
                    # or whether it is parented to some bone of the armature
                    parent_bone_name = b_obj_child.parent_bone
                    if parent_bone_name is None:
                        self.nif_export.export_node(b_obj_child, 'localspace',
                                         parent_block, b_obj_child.name)
                    else:
                        # we should parent the object to the bone instead of
                        # to the armature
                        # so let's find that bone!
                        nif_bone_name = self.nif_export.get_full_name(parent_bone_name)
                        for bone_block in self.nif_export.blocks:
                            if isinstance(bone_block, NifFormat.NiNode) and \
                                bone_block.name.decode() == nif_bone_name:
                                # ok, we should parent to block
                                # instead of to parent_block
                                # two problems to resolve:
                                #   - blender bone matrix is not the exported
                                #     bone matrix!
                                #   - blender objects parented to bone have
                                #     extra translation along the Y axis
                                #     with length of the bone ("tail")
                                # this is handled in the get_object_srt function
                                self.nif_export.export_node(b_obj_child, 'localspace',
                                                 bone_block, b_obj_child.name)
                                break
                        else:
                            assert(False) # BUG!

    def get_bone_rest_matrix(self, bone, space, extra = True, tail = False):
        """Get bone matrix in rest position ("bind pose"). Space can be
        ARMATURESPACE or BONESPACE. This returns also a 4x4 matrix if space
        is BONESPACE (translation is bone head plus tail from parent bone).
        If tail is True then the matrix translation includes the bone tail."""
        # Retrieves the offset from the original NIF matrix, if existing
        correction_matrix = mathutils.Matrix()
        if extra:
            try:
                correction_matrix = mathutils.Matrix(
                    self.get_bone_extra_matrix_inv(bone.name))
            except KeyError:
                correction_matrix.identity()
        else:
            correction_matrix.identity()
        if (space == 'ARMATURESPACE'):
            matrix = mathutils.Matrix(bone.matrix_local)
            if tail:
                tail_pos = bone.tail_local
                matrix[0][3] = tail_pos[0]
                matrix[1][3] = tail_pos[1]
                matrix[2][3] = tail_pos[2]
            return correction_matrix * matrix
        elif (space == 'BONESPACE'):
            if bone.parent:
                # not sure why extra = True is required here
                # but if extra = extra then transforms are messed up, so keep
                # for now
                parinv = self.get_bone_rest_matrix(bone.parent, 'ARMATURESPACE',
                                                   extra = True, tail = False)
                parinv.invert()
                return self.get_bone_rest_matrix(bone,
                                                 'ARMATURESPACE',
                                                 extra = extra,
                                                 tail = tail) * parinv
            else:
                return self.get_bone_rest_matrix(bone, 'ARMATURESPACE',
                                                 extra = extra, tail = tail)
        else:
            assert(False) # bug!

<|endoftext|>


<commit_before>#!/usr/bin/env python

'''
This module implements various transmuter classes.
Transmuters are essentially classes that generate TransformedStructures from
various data sources. They enable the high-throughput generation of new
structures and input files.

It also includes the helper function, batch_write_vasp_input to generate an entire
directory of vasp input files for running.
'''

from __future__ import division

__author__ = "Shyue Ping Ong, Will Richards"
__copyright__ = "Copyright 2012, The Materials Project"
__version__ = "0.1"
__maintainer__ = "Shyue Ping Ong"
__email__ = "shyue@mit.edu"
__date__ = "Mar 4, 2012"

import os
import re
import collections

from pymatgen.alchemy.materials import TransformedStructure

from copy import deepcopy

class TransformedStructureTransmuter(object):

    def __init__(self, transformed_structures, transformations = [], extend_collection = False):
        self._transformed_structures = transformed_structures
        for trans in transformations:
            self.append_transformation(trans)

    def __getitem__(self, index):
        return self._transformed_structures[index]

    def __getattr__(self, name):
        return [getattr(x, name) for x in self._transformed_structures]

    def undo_last_transformation(self):
        """
        Undo the last transformation in the TransformedStructure.

        Raises:
            IndexError if already at the oldest change.
        """
        for x in self._transformed_structures:
            x.undo_last_transformation()

    def redo_next_transformation(self):
        """
        Redo the last undone transformation in the TransformedStructure.

        Raises:
            IndexError if already at the latest change.
        """
        for x in self._transformed_structures:
            x.redo_next_transformation()

    def __len__(self):
        return len(self._transformed_structures)

    def append_transformation(self, transformation, extend_collection = False, clear_redo = True):
        """
        TODO: clean this up a lot

        Appends a transformation to the TransformedStructure.

        Arguments:
            transformation:
                Transformation to append
            clear_redo:
                Boolean indicating whether to clear the redo list. By default,
                this is True, meaning any appends clears the history of undoing.
                However, when using append_transformation to do a redo, the redo
                list should not be cleared to allow multiple redos.

        Returns:
            list of booleans corresponding to initial transformed structures
            each boolean describes whether the transformation altered the structure
        """
        new_structures = []

        for x in self._transformed_structures:
            new = x.append_transformation(transformation, return_alternatives = extend_collection, clear_redo = clear_redo)
            if new is not None:
                new_structures.extend(new)
        output = [x.was_modified for x in self._transformed_structures]
        self._transformed_structures.extend(new_structures)
        return output

    def branch_collection(self, transformations, retention_level = 1, extend_collection = False, clear_redo = True):
        '''
        copies the structures collection, applying one transformation to each copy.

        Args:
            transformations:
                List of transformations to apply (each structure gets one of
                these transformations. To append multiple transformations to
                each structure use extend_transformations)
            retention_level:
                Specifies which structures will be kept and which will be thrown out
                0 - throws out all structures that weren't modified by any of
                the transformations
                1 - keeps structures that weren't modified by anything.
                2 - keeps all structures, including the untransformed ones. Note
                that this may cause issues with undoing transformations
                since they will have different transformation histories

                e.g if you start with 2 structures and apply 2 transformations,
                and one structure isn't modified by either of them but the other
                structure is modified by both, for retention_level = 0, you will have
                2 structures left, for retention_level = 1 you will have 3 structures,
                and for retention_level 2, you will have 4. In most cases,
                retention_level = 1 will provide the desired functionality.
        '''
        any_modification = [False] * len(self._transformed_structures)
        old_transformed_structures = self._transformed_structures

        new_trans_structures = []
        for transformation in transformations:
            self._transformed_structures = deepcopy(old_transformed_structures)
            modified = self.append_transformation(transformation, extend_collection, clear_redo)
            for structure in self._transformed_structures:
                if structure.was_modified:
                    new_trans_structures.append(structure)
            any_modification = map(lambda x:x[0] or x[1], zip(modified, any_modification))

        self._transformed_structures = new_trans_structures

        if retention_level == 1:
            for i, structure in enumerate(old_transformed_structures):
                if not any_modification[i]:
                    self._transformed_structures.append(structure)
        elif retention_level == 2:
            self._transformed_structures.extend(old_transformed_structures)

    def extend_transformations(self, transformations):
        """
        Extends a sequence of transformations to the TransformedStructure.

        Args:
            transformations:
                Sequence of Transformations
        """
        for t in transformations:
            self.append_transformation(t)

    def write_vasp_input(self, vasp_input_set, output_dir, create_directory = True):
        """
        Batch write vasp input for a sequence of transformed structures to output_dir,
        following the format output_dir/{formula}_{number}.

        Args:
            vasp_input_set:
                pymatgen.io.vaspio_set.VaspInputSet like object that creates
                vasp input files from structures
            output_dir:
                Directory to output files
            create_directory:
                Create the directory if not present. Defaults to True.
        """
        batch_write_vasp_input(self._transformed_structures, vasp_input_set, output_dir, create_directory)

    def set_parameter(self, key, value):
        for x in self._transformed_structures:
            x.set_parameter(key, value)

    def __str__(self):
        output = ["Current structures"]
        output.append("------------")
        for x in self._transformed_structures:
            output.append(str(x._structures[-1]))
        return "\n".join(output)

    def remove_duplicates(self):
        '''
        TODO: write this method
        '''
        pass

    @staticmethod
    def from_cif_string(cif_string, transformations = [], primitive = True, extend_collection = False):
        '''
        Generates a TransformedStructureCollection from a cif string, possibly
        containing multiple structures.

        Args:
            cif_filenames:
                List of strings of the cif files
        '''
        transformed_structures = []
        lines = cif_string.split("\n")
        structure_data = []
        read_data = False
        for line in lines:
            if re.match("^\s*data", line):
                structure_data.append([])
                read_data = True
            if read_data:
                structure_data[-1].append(line)
        transformed_structures.extend([TransformedStructure.from_cif_string("".join(data), [], primitive) for data in structure_data])
        return TransformedStructureTransmuter(transformed_structures, transformations, extend_collection)

    @staticmethod
    def from_cifs(cif_filenames, transformations = [], primitive = True):
        '''
        Generates a TransformedStructureCollection from a cif, possibly
        containing multiple structures.

        Args:
            cif_filenames:
                List of strings of the cif files
        '''
        transformed_structures = []
        for filename in cif_filenames:
            with open(filename, "r") as f:
                structure_data = []
                read_data = False
                for line in f:
                    if re.match("^\s*data", line):
                        structure_data.append([])
                        read_data = True
                    if read_data:
                        structure_data[-1].append(line)
                transformed_structures.extend([TransformedStructure.from_cif_string("".join(data), transformations, primitive) for data in structure_data])
        return TransformedStructureTransmuter(transformed_structures, [])

    @staticmethod
    def from_poscars(poscar_filenames, transformations = []):
        transformed_structures = []
        for filename in poscar_filenames:
            with open(filename, "r") as f:
                transformed_structures.append(TransformedStructure.from_poscar_string(f.read(), transformations))
        return TransformedStructureTransmuter(transformed_structures, [])

def batch_write_vasp_input(transformed_structures, vasp_input_set, output_dir, create_directory = True):
    """
    Batch write vasp input for a sequence of transformed structures to output_dir,
    following the format output_dir/{formula}_{number}.

    Args:
        transformed_structures:
            Sequence of TransformedStructures.
        vasp_input_set:
            pymatgen.io.vaspio_set.VaspInputSet like object that creates
            vasp input files from structures
        output_dir:
            Directory to output files
        create_directory:
            Create the directory if not present. Defaults to True.
    """
    dnames_count = collections.defaultdict(int)
    for s in transformed_structures:
        formula = re.sub("\s+", "", s.final_structure.formula)
        dirname = os.path.join(output_dir, '{}_{}'.format(formula, dnames_count[formula] + 1))
        s.write_vasp_input(vasp_input_set, dirname, create_directory = True)
        dnames_count[formula] += 1
<commit_msg>More doc fixes.<commit_after>#!/usr/bin/env python

'''
This module implements various transmuter classes.
Transmuters are essentially classes that generate TransformedStructures from
various data sources. They enable the high-throughput generation of new
structures and input files.

It also includes the helper function, batch_write_vasp_input to generate an entire
directory of vasp input files for running.
'''

from __future__ import division

__author__ = "Shyue Ping Ong, Will Richards"
__copyright__ = "Copyright 2012, The Materials Project"
__version__ = "0.1"
__maintainer__ = "Shyue Ping Ong"
__email__ = "shyue@mit.edu"
__date__ = "Mar 4, 2012"

import os
import re
import collections

from pymatgen.alchemy.materials import TransformedStructure

from copy import deepcopy

class TransformedStructureTransmuter(object):

    def __init__(self, transformed_structures, transformations = [], extend_collection = False):
        self._transformed_structures = transformed_structures
        for trans in transformations:
            self.append_transformation(trans)

    def __getitem__(self, index):
        return self._transformed_structures[index]

    def __getattr__(self, name):
        return [getattr(x, name) for x in self._transformed_structures]

    def undo_last_transformation(self):
        """
        Undo the last transformation in the TransformedStructure.

        Raises:
            IndexError if already at the oldest change.
        """
        for x in self._transformed_structures:
            x.undo_last_transformation()

    def redo_next_transformation(self):
        """
        Redo the last undone transformation in the TransformedStructure.

        Raises:
            IndexError if already at the latest change.
        """
        for x in self._transformed_structures:
            x.redo_next_transformation()

    def __len__(self):
        return len(self._transformed_structures)

    def append_transformation(self, transformation, extend_collection = False, clear_redo = True):
        """
        TODO: clean this up a lot

        Appends a transformation to the TransformedStructure.

        Arguments:
            transformation:
                Transformation to append
            clear_redo:
                Boolean indicating whether to clear the redo list. By default,
                this is True, meaning any appends clears the history of undoing.
                However, when using append_transformation to do a redo, the redo
                list should not be cleared to allow multiple redos.

        Returns:
            list of booleans corresponding to initial transformed structures
            each boolean describes whether the transformation altered the structure
        """
        new_structures = []

        for x in self._transformed_structures:
            new = x.append_transformation(transformation, return_alternatives = extend_collection, clear_redo = clear_redo)
            if new is not None:
                new_structures.extend(new)
        output = [x.was_modified for x in self._transformed_structures]
        self._transformed_structures.extend(new_structures)
        return output

    def branch_collection(self, transformations, retention_level = 1, extend_collection = False, clear_redo = True):
        '''
        Copies the structures collection, applying one transformation to each copy.

        Args:
            transformations:
                List of transformations to apply (each structure gets one of
                these transformations. To append multiple transformations to
                each structure use extend_transformations)
            retention_level:
                Specifies which structures will be kept and which will be thrown out
                0 - throws out all structures that weren't modified by any of
                the transformations
                1 - keeps structures that weren't modified by anything.
                2 - keeps all structures, including the untransformed ones. Note
                that this may cause issues with undoing transformations
                since they will have different transformation histories

                e.g if you start with 2 structures and apply 2 transformations,
                and one structure isn't modified by either of them but the other
                structure is modified by both, for retention_level = 0, you will have
                2 structures left, for retention_level = 1 you will have 3 structures,
                and for retention_level 2, you will have 4. In most cases,
                retention_level = 1 will provide the desired functionality.
        '''
        any_modification = [False] * len(self._transformed_structures)
        old_transformed_structures = self._transformed_structures

        new_trans_structures = []
        for transformation in transformations:
            self._transformed_structures = deepcopy(old_transformed_structures)
            modified = self.append_transformation(transformation, extend_collection, clear_redo)
            for structure in self._transformed_structures:
                if structure.was_modified:
                    new_trans_structures.append(structure)
            any_modification = map(lambda x:x[0] or x[1], zip(modified, any_modification))

        self._transformed_structures = new_trans_structures

        if retention_level == 1:
            for i, structure in enumerate(old_transformed_structures):
                if not any_modification[i]:
                    self._transformed_structures.append(structure)
        elif retention_level == 2:
            self._transformed_structures.extend(old_transformed_structures)

    def extend_transformations(self, transformations):
        """
        Extends a sequence of transformations to the TransformedStructure.

        Args:
            transformations:
                Sequence of Transformations
        """
        for t in transformations:
            self.append_transformation(t)

    def write_vasp_input(self, vasp_input_set, output_dir, create_directory = True):
        """
        Batch write vasp input for a sequence of transformed structures to output_dir,
        following the format output_dir/{formula}_{number}.

        Args:
            vasp_input_set:
                pymatgen.io.vaspio_set.VaspInputSet like object that creates
                vasp input files from structures
            output_dir:
                Directory to output files
            create_directory:
                Create the directory if not present. Defaults to True.
        """
        batch_write_vasp_input(self._transformed_structures, vasp_input_set, output_dir, create_directory)

    def set_parameter(self, key, value):
        for x in self._transformed_structures:
            x.set_parameter(key, value)

    def __str__(self):
        output = ["Current structures"]
        output.append("------------")
        for x in self._transformed_structures:
            output.append(str(x._structures[-1]))
        return "\n".join(output)

    def remove_duplicates(self):
        '''
        TODO: write this method
        '''
        pass

    @staticmethod
    def from_cif_string(cif_string, transformations = [], primitive = True, extend_collection = False):
        '''
        Generates a TransformedStructureCollection from a cif string, possibly
        containing multiple structures.

        Args:
            cif_filenames:
                List of strings of the cif files
        '''
        transformed_structures = []
        lines = cif_string.split("\n")
        structure_data = []
        read_data = False
        for line in lines:
            if re.match("^\s*data", line):
                structure_data.append([])
                read_data = True
            if read_data:
                structure_data[-1].append(line)
        transformed_structures.extend([TransformedStructure.from_cif_string("".join(data), [], primitive) for data in structure_data])
        return TransformedStructureTransmuter(transformed_structures, transformations, extend_collection)

    @staticmethod
    def from_cifs(cif_filenames, transformations = [], primitive = True):
        '''
        Generates a TransformedStructureCollection from a cif, possibly
        containing multiple structures.

        Args:
            cif_filenames:
                List of strings of the cif files
        '''
        transformed_structures = []
        for filename in cif_filenames:
            with open(filename, "r") as f:
                structure_data = []
                read_data = False
                for line in f:
                    if re.match("^\s*data", line):
                        structure_data.append([])
                        read_data = True
                    if read_data:
                        structure_data[-1].append(line)
                transformed_structures.extend([TransformedStructure.from_cif_string("".join(data), transformations, primitive) for data in structure_data])
        return TransformedStructureTransmuter(transformed_structures, [])

    @staticmethod
    def from_poscars(poscar_filenames, transformations = []):
        transformed_structures = []
        for filename in poscar_filenames:
            with open(filename, "r") as f:
                transformed_structures.append(TransformedStructure.from_poscar_string(f.read(), transformations))
        return TransformedStructureTransmuter(transformed_structures, [])

def batch_write_vasp_input(transformed_structures, vasp_input_set, output_dir, create_directory = True):
    """
    Batch write vasp input for a sequence of transformed structures to output_dir,
    following the format output_dir/{formula}_{number}.

    Args:
        transformed_structures:
            Sequence of TransformedStructures.
        vasp_input_set:
            pymatgen.io.vaspio_set.VaspInputSet like object that creates
            vasp input files from structures
        output_dir:
            Directory to output files
        create_directory:
            Create the directory if not present. Defaults to True.
    """
    dnames_count = collections.defaultdict(int)
    for s in transformed_structures:
        formula = re.sub("\s+", "", s.final_structure.formula)
        dirname = os.path.join(output_dir, '{}_{}'.format(formula, dnames_count[formula] + 1))
        s.write_vasp_input(vasp_input_set, dirname, create_directory = True)
        dnames_count[formula] += 1
<|endoftext|>


<commit_before>'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
''This script is used to download content from webpages
It Download the content from provided url.

It imports:
  -urllib

It defines:
  -main
  -extract_name
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'''Required modules'''
import urllib

def extract_name(url):
    """
    Extracts the name of the content item from provided url.
    """
    name = ""
    for ch in url[-1::-1]:
        if ch == "/":                                                 #extracting from last field separated by "/"
            break
        name+=ch

    return name[-1::-1]

def main(urls, path,panel,container):
    #When called with direct url
    print urls
    if (not(urls[0].startswith("u'http"))
        or ".html" not in urls[0]):
            return "Invalid url"

    print "Downloading into "+path+" ..."
    for url in urls:
        name = extract_name(url)
        try:
            data = urllib.urlopen(url).read()
            save_file = open(path+"/"+name, 'wb')
            save_file.write(data)
            save_file.close()

            print 'Progress bar'
            progress_bar = PG.PyGauge(panel,-1,size=(100,25),style=wx.GA_HORIZONTAL)
            container.Add(progress_bar)
            print "Added pro_bar"
            progress_bar.SetValue([20,80])
            progress_bar.SetBarColor([wx.Colour(162,255,178),wx.Colour(159,176,255)])
            progress_bar.SetBackgroundColour(wx.WHITE)
            progress_bar.SetBorderColor(wx.BLACK)
            progress_bar.SetBorderPadding(2)
            progress_bar.SetDrawValue(draw=True, drawPercent=True, font=wx.SMALL_FONT, colour=wx.BLUE)

            progress_bar.Update([30,0],2000)
        except:
            return "The connection could not establish."

if __name__ == "__main__":
    main(url,dir_)
<commit_msg>fetching size of files, progress bar demo<commit_after>'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
''This script is used to download content from webpages
It Download the content from provided url.

It imports:
  -urllib

It defines:
  -main
  -extract_name
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'''Required modules'''
import urllib

def extract_name(url):
    """
    Extracts the name of the content item from provided url.
    """
    name = ""
    for ch in url[-1::-1]:
        if ch == "/":                                                 #extracting from last field separated by "/"
            break
        name+=ch

    return name[-1::-1]

def main(urls, path,progress_bar):
    #When called with direct url
    stop = False
    print urls
    if (not(urls[0].startswith("http"))
        and ".html" not in urls[0]):
        return "Invalid url"

    total_size = 0
    for url in urls:
        connection = urllib.urlopen(url)
        meta = connection.info()
        try:
            size = meta.getheaders("content-length")[0]
            total_size += int(size)
        except IndexError:
            size = len(connection.read())
            total_size += size

    print "Downloading into "+path+" ..."
    for url in urls:
        name = extract_name(url)
        try:
            data = urllib.urlopen(url).read()
            save_file = open(path+"/"+name, 'wb')
            save_file.write(data)
            save_file.close()

            download_size = len(data)
            percent = download_size / float(total_size)

            progress_bar.SetValue([20,80])
            progress_bar.SetBarColor([wx.Colour(162,255,178),wx.Colour(159,176,255)])
            progress_bar.SetBackgroundColour(wx.WHITE)
            progress_bar.SetBorderColor(wx.BLACK)
            progress_bar.SetBorderPadding(2)
            progress_bar.SetDrawValue(draw=True, drawPercent=True, font=wx.SMALL_FONT, colour=wx.BLUE)

            progress_bar.Update([percent,0],2000)

            if stop:
                break
        except Exception as e:
            return e
            return "The connection could not establish."

if __name__ == "__main__":
    main(url,dir_)
<|endoftext|>


<commit_before>#!/usr/bin/env python
from __future__ import print_function, division
import os, sys
import matplotlib.pyplot as plt
import numpy as np
import argparse
from astropy import log
from os import path
from glob import glob
from subprocess import check_call
import shutil
from astropy.table import Table

from nicer.values import *

parser = argparse.ArgumentParser(description = "Process NICER background data.  Output will be written in current working directory.")
parser.add_argument("indirs", help="Input directories to process", nargs='+')
parser.add_argument("--emin", help="Minimum energy to include (keV, default=0.4)",
    type=float, default=0.5)
parser.add_argument("--emax", help="Maximum energy to include (kev, default=8.0)",
    type=float, default=8.0)
parser.add_argument("--mask",help="Mask these IDS", nargs = '*', type=int, default=None)
parser.add_argument("--obsid", help="Use this as OBSID for directory and filenames",
    default=None)
parser.add_argument("--ultraclean", help="Apply ultraclean background filters", action='store_true')
args = parser.parse_args()

os.environ['HEADASNOQUERY'] = ' '
os.environ['HEADASPROMPT'] = '/dev/null'

# For some reason if the script is called via #!/usr/bin/env python
# it does not inherit LD_LIBRARY_PATH so ftools don't run.
#print(os.environ['LD_LIBRARY_PATH'])
#print(os.environ['HEADAS'])
#os.environ['LD_LIBRARY_PATH'] = path.join(os.environ['HEADAS'],'lib')
#print(os.environ['LD_LIBRARY_PATH'])

def runcmd(cmd):
    # CMD should be a list of strings since it is not processed by a shell
    log.info('CMD: '+" ".join(cmd))
    check_call(cmd,env=os.environ)

for obsdir in args.indirs:

    # Set up a basename and make a work directory
    if args.obsid is not None:
        basename = args.obsid
    else:
        # Trim trailing / if needed
        if obsdir.endswith("/"):
            obsdir = obsdir[:-1]
        basename = path.basename(obsdir)

    # Make directory for working files and output
    pipedir = "{0}_bkg".format(basename)
    if not os.path.exists(pipedir):
        os.makedirs(pipedir)

    log.info('Making initial QL plots')
    cmd = ["master_plotter.py", "--save", "--filtall",
           "--writebkf", "--eventshootrate",
           "--guessobj", "--lclog", "--useftools",
           "--emin", "{0}".format(args.emin), "--emax", "{0}".format(args.emax),
           "--sci", "--eng", "--map", "--bkg", "--obsdir", obsdir,
           "--basename", path.join(pipedir,basename)+'_prefilt']
    # I don't think this mask is applied to the  .bkf data generated, but it should be
    if args.mask is not None:
        cmd.append(["--mask"].append(["{0}".format(m) for m in args.mask]))
    runcmd(cmd)

    # Get filter file
    mkfile = glob(path.join(obsdir,'auxil/ni*.mkf'))[0]
    log.info('MKF File: {0}'.format(mkfile))

    #  Get ATT hk files
    attfile = glob(path.join(obsdir,'auxil/ni*.att'))[0]
    log.info('ATT HK File: {0}'.format(attfile))

    #  Get BKF file for filtering based on background indicators
    bkffile = path.join(pipedir,basename)+'_prefilt.bkf'
    log.info('BKF File: {0}'.format(bkffile))

    # Create GTI from .mkf file
    if args.ultraclean:
        mkf_expr='(SAA.eq.0).and.(ANG_DIST.lt.0.01).and.(ELV>30.0).and.(SUNSHINE.eq.0)'
    else:
        mkf_expr='(SAA.eq.0).and.(ANG_DIST.lt.0.01).and.(ELV>30.0)'
    gtiname1 = path.join(pipedir,'mkf.gti')
    cmd = ["maketime", mkfile, gtiname1, 'expr={0}'.format(mkf_expr),
        "compact=no", "time=TIME",  "prefr=0", "postfr=0", "clobber=yes"]
    runcmd(cmd)
    if len(Table.read(gtiname1,hdu=1))==0:
        log.error('No good time left after filtering!')
        sys.exit(0)

    # Create GTI from attitude data
    gtiname2 = path.join(pipedir,'att.gti')
    att_expr = '(MODE.eq.1).and.(SUBMODE_AZ.eq.2).and.(SUBMODE_EL.eq.2)'
    cmd = ["maketime", attfile, gtiname2, 'expr={0}'.format(att_expr),
        "compact=no", "time=TIME", "prefr=0", "postfr=0", "clobber=yes"]
    runcmd(cmd)
    if len(Table.read(gtiname2,hdu=1))==0:
        log.error('No good time left after filtering!')
        sys.exit(0)

    gtiname_merged = path.join(pipedir,"tot.gti")
    try:
        os.remove(gtiname_merged)
    except:
        pass

    cmd = ["mgtime", "{0},{1}".format(gtiname1,gtiname2), gtiname_merged, "AND"]
    runcmd(cmd)

    ### Final step filters and masked detector and does ratio filter
    filteredname = path.join(pipedir,"filtered.bkf")
    expr = 'gtifilter("{0}")'.format(gtiname_merged)
    cmd = ["ftcopy", '{0}[{1}]'.format(bkffile,expr), filteredname,
        "clobber=yes", "history=yes"]
    runcmd(cmd)
<commit_msg>Remove eventshootrate from bkgpipe<commit_after>#!/usr/bin/env python
from __future__ import print_function, division
import os, sys
import matplotlib.pyplot as plt
import numpy as np
import argparse
from astropy import log
from os import path
from glob import glob
from subprocess import check_call
import shutil
from astropy.table import Table

from nicer.values import *

parser = argparse.ArgumentParser(description = "Process NICER background data.  Output will be written in current working directory.")
parser.add_argument("indirs", help="Input directories to process", nargs='+')
parser.add_argument("--emin", help="Minimum energy to include (keV, default=0.4)",
    type=float, default=0.5)
parser.add_argument("--emax", help="Maximum energy to include (kev, default=8.0)",
    type=float, default=8.0)
parser.add_argument("--mask",help="Mask these IDS", nargs = '*', type=int, default=None)
parser.add_argument("--obsid", help="Use this as OBSID for directory and filenames",
    default=None)
parser.add_argument("--ultraclean", help="Apply ultraclean background filters", action='store_true')
args = parser.parse_args()

os.environ['HEADASNOQUERY'] = ' '
os.environ['HEADASPROMPT'] = '/dev/null'

# For some reason if the script is called via #!/usr/bin/env python
# it does not inherit LD_LIBRARY_PATH so ftools don't run.
#print(os.environ['LD_LIBRARY_PATH'])
#print(os.environ['HEADAS'])
#os.environ['LD_LIBRARY_PATH'] = path.join(os.environ['HEADAS'],'lib')
#print(os.environ['LD_LIBRARY_PATH'])

def runcmd(cmd):
    # CMD should be a list of strings since it is not processed by a shell
    log.info('CMD: '+" ".join(cmd))
    check_call(cmd,env=os.environ)

for obsdir in args.indirs:

    # Set up a basename and make a work directory
    if args.obsid is not None:
        basename = args.obsid
    else:
        # Trim trailing / if needed
        if obsdir.endswith("/"):
            obsdir = obsdir[:-1]
        basename = path.basename(obsdir)

    # Make directory for working files and output
    pipedir = "{0}_bkg".format(basename)
    if not os.path.exists(pipedir):
        os.makedirs(pipedir)

    log.info('Making initial QL plots')
    cmd = ["master_plotter.py", "--save", "--filtall",
           "--writebkf",
           "--guessobj", "--lclog", "--useftools",
           "--emin", "{0}".format(args.emin), "--emax", "{0}".format(args.emax),
           "--sci", "--eng", "--map", "--bkg", "--obsdir", obsdir,
           "--basename", path.join(pipedir,basename)+'_prefilt']
    # I don't think this mask is applied to the  .bkf data generated, but it should be
    if args.mask is not None:
        cmd.append(["--mask"].append(["{0}".format(m) for m in args.mask]))
    runcmd(cmd)

    # Get filter file
    mkfile = glob(path.join(obsdir,'auxil/ni*.mkf'))[0]
    log.info('MKF File: {0}'.format(mkfile))

    #  Get ATT hk files
    attfile = glob(path.join(obsdir,'auxil/ni*.att'))[0]
    log.info('ATT HK File: {0}'.format(attfile))

    #  Get BKF file for filtering based on background indicators
    bkffile = path.join(pipedir,basename)+'_prefilt.bkf'
    log.info('BKF File: {0}'.format(bkffile))

    # Create GTI from .mkf file
    if args.ultraclean:
        mkf_expr='(SAA.eq.0).and.(ANG_DIST.lt.0.01).and.(ELV>30.0).and.(SUNSHINE.eq.0)'
    else:
        mkf_expr='(SAA.eq.0).and.(ANG_DIST.lt.0.01).and.(ELV>30.0)'
    gtiname1 = path.join(pipedir,'mkf.gti')
    cmd = ["maketime", mkfile, gtiname1, 'expr={0}'.format(mkf_expr),
        "compact=no", "time=TIME",  "prefr=0", "postfr=0", "clobber=yes"]
    runcmd(cmd)
    if len(Table.read(gtiname1,hdu=1))==0:
        log.error('No good time left after filtering!')
        sys.exit(0)

    # Create GTI from attitude data
    gtiname2 = path.join(pipedir,'att.gti')
    att_expr = '(MODE.eq.1).and.(SUBMODE_AZ.eq.2).and.(SUBMODE_EL.eq.2)'
    cmd = ["maketime", attfile, gtiname2, 'expr={0}'.format(att_expr),
        "compact=no", "time=TIME", "prefr=0", "postfr=0", "clobber=yes"]
    runcmd(cmd)
    if len(Table.read(gtiname2,hdu=1))==0:
        log.error('No good time left after filtering!')
        sys.exit(0)

    gtiname_merged = path.join(pipedir,"tot.gti")
    try:
        os.remove(gtiname_merged)
    except:
        pass

    cmd = ["mgtime", "{0},{1}".format(gtiname1,gtiname2), gtiname_merged, "AND"]
    runcmd(cmd)

    ### Final step filters and masked detector and does ratio filter
    filteredname = path.join(pipedir,"filtered.bkf")
    expr = 'gtifilter("{0}")'.format(gtiname_merged)
    cmd = ["ftcopy", '{0}[{1}]'.format(bkffile,expr), filteredname,
        "clobber=yes", "history=yes"]
    runcmd(cmd)
<|endoftext|>