#! /usr/bin/env python

import glob
import multiprocessing
import numpy as np
import os
import string
import subprocess
import sys

from waflib import Logs, Options, Tools
from waflib.Build import BuildContext
from waflib.Configure import conf
from waflib.Context import Context

APPNAME = 'tamasis'
VERSION = '5.0'

top = '.'
out = 'build'

# List of packages to be built
subdirs = ['core', 'madcap', 'pacs']

# Required libraries
libraries = ['CFITSIO', 'FFTW3', 'OPENMP']

# Required Python packages
required_modules = ['numpy>=1.6',
                    'scipy>=0.9',
                    'pyoperators>=0.7',
                    'pysimulators>=0.2',
                    'matplotlib',
                    'fftw3',
                    'pyfits>=3.0',
                    'kapteyn',
                    'numexpr>=2.0']

#
# Read options
#

def options(opt):

    opt.load('compiler_c')
    opt.load('compiler_fc')
    opt.load('python')
    opt.add_option('--enable-mpi',
                   action='store_true',
                   default=False,
                   help='MPI-enabled installation')
    opt.add_option('--enable-wcslib',
                   action='store_true',
                   default=False,
                   help='enables linking WCSLIB')
    opt.add_option('--precision-real',
                   action='store',
                   default='8',
                   choices=['4', '8', '16'],
                   help='precision of reals: single (4), double (8) or quadrupl'
                        'e precision (16)')
    opt.add_option('--debug',
                   action='store_true',
                   default=False,
                   help='use compiler flags for debugging (export symbols, add '
                        'checks...)')
    opt.add_option('--np',
                   action='store',
                   help='number of MPI copies')

#
# Configuration
#

def configure(conf):

    global required_modules, libraries

    if conf.options.enable_mpi:
        required_modules += ['mpi4py']
        libraries += ['MPI']

    if conf.options.enable_wcslib:
        libraries += ['WCSLIB']

    for platform in 'linux', 'darwin', 'default':
        Tools.compiler_fc.fc_compiler[platform] = ['ifort', 'gfortran']

    conf.load('compiler_c')
    conf.load('compiler_fc')
    conf.load('python')

    conf.check_python_version((2,6))
    for module in required_modules:
        conf.check_python_module(module)
    conf.check_fortran()
    conf.check_fortran_verbose_flag()
    conf.check_fortran_clib()
    conf.check_fortran_dummy_main()
    conf.check_fortran_mangling()

    if conf.env.FC_NAME == 'GFORTRAN':
        conf.env.FCFLAGS = ['-ffree-form', '-Wall', '-fPIC', '-cpp']
        if conf.options.debug:
            conf.env.FCFLAGS += ['-g', '-fcheck=all', '-fbacktrace']
        else:
            conf.env.FCFLAGS += ['-O3']
        if 'OPENMP' in libraries:
            conf.env.FCFLAGS_OPENMP = ['-fopenmp']
            conf.env.LIB_OPENMP = ['gomp']
        conf.env.F2PYFCOMPILER = 'gnu95'
        conf.env.LIB_LAPACK = ['lapack', 'blas']
    elif conf.env.FC_NAME == 'IFORT':
        conf.env.FCFLAGS = ['-fpp', '-fPIC', '-free', '-ftz', '-fp-model',
                            'precise', '-ftrapuv', '-fast', '-warn', 'all']
        if conf.options.debug:
            conf.env.FCFLAGS += ['-debug', '-check', 'all', '-traceback']
        if 'OPENMP' in libraries:
            conf.env.FCFLAGS_OPENMP = ['-openmp']
            conf.env.LIB_OPENMP = ['iomp5']
        conf.env.F2PYFCOMPILER = 'intelem'
        # should add -Wl,--start-group and -Wl,--end-group
        conf.env.LIB_LAPACK = ['mkl_intel_lp64','mkl_intel_thread','mkl_core', 'iomp5']

    if conf.options.precision_real == '16':
        conf.check_cc(
            fragment         = """
program test
    integer, parameter :: qp = selected_real_kind(2*precision(1.0d0))
    real(kind=qp)      :: quad
end program test""",
            compile_filename = 'test.f',
            features         = 'fc fcprogram',
            msg              = 'Checking for quadruple precision')

    conf.find_program(['ipython'  + sys.version[0:3],
                       'ipython-' + sys.version[0:3],
                       'ipython'], var='IPYTHON')
    conf.env.IPYTHON_VERSION = _get_version(conf.env.IPYTHON, flag='-Version')

    conf.find_program(['f2py'  + sys.version[0:3],
                       'f2py-' + sys.version[0:3],
                       'f2py'], var='F2PY')

    conf.find_program(['nosetests'  + sys.version[0:3],
                       'nosetests-' + sys.version[0:3],
                       'nosetests'], var='NOSETESTS')

    # these two environment variables are required by pkg-config
    os.putenv('PKG_CONFIG_ALLOW_SYSTEM_CFLAGS', '1')
    os.putenv('PKG_CONFIG_ALLOW_SYSTEM_LIBS',   '1')
    conf.check_cfg(package='cfitsio', args=['--libs', '--cflags'])
    conf.check_cfg(package='fftw3',   args=['--libs', '--cflags'])
    conf.check_cc(
        fragment         = """
program test
    include 'fftw3.f'
    integer, parameter :: dp = kind(1.d0)
    integer*8          :: plan
    real(dp)           :: in(10), out(10)
    call dfftw_plan_r2r_1d(plan, 10, in, out, FFTW_R2HC, FFTW_ESTIMATE)
    call dfftw_destroy_plan(plan)
end program test""",
        compile_filename = 'test.f',
        features         = 'fc fcprogram',
        msg              = "Checking for 'fftw3' double precision",
        use              = ['FFTW3'])

    if 'LAPACK' in libraries:
        fragment = """
program test
    integer, parameter :: p = kind(1.d0)
    real(p)            :: u(2), v(2)
    u = 1._p
    v = 0._p
    call daxpy(2, 3._p, u, 1, v, 1)
end program test
"""
        if conf.options.precision_real == '4':
            fragment = fragment.replace('kind(1.d0)', 'kind(1.)') \
                               .replace('daxpy','saxpy')
        conf.check_cc(
            fragment         = fragment,
            compile_filename = 'test.f',
            features         = 'fc fcprogram',
            msg              = "Checking for 'blas'",
            use              = ['LAPACK'])

        fragment = """
program test
    integer, parameter :: p = kind(1.d0)
    integer            :: status
    real(p)            :: cd(2,2), vr(2), vim(2), junk, work(6)
    cd = 0
    call dgeev('N', 'N', 2, cd, 2, vr, vim, junk, 1, junk, 1, work, size(work), status)
end program test
"""
        if conf.options.precision_real == '4':
            fragment = fragment.replace('kind(1.d0)', 'kind(1.)') \
                               .replace('dgeev','sgeev')
        conf.check_cc(
            fragment         = fragment,
            compile_filename = 'test.f',
            features         = 'fc fcprogram',
            msg              = "Checking for 'lapack'",
            use              = ['LAPACK'])

    if conf.options.enable_mpi:
        conf.env.OMPI_FC = conf.env.FC
        conf.find_program('mpif90', var='MPIFC')
        conf.env.FC = conf.env.MPIFC
        conf.check_cc(fragment    = 'program test\nuse mpi\nend',
                      compile_filename = 'test.f',
                      features    = 'fc fcprogram',
                      msg         = 'Checking for the MPI fortran module',
                      define_name = 'HAVE_MPI_MODULE',
                      mandatory   = False)
        if conf.env['HAVE_MPI_MODULE'] == 0:
            conf.check_cc(fragment= "program test\ninclude 'mpif.h'\nend",
                          compile_filename = 'test.f',
                          features    = 'fc fcprogram',
                          msg         = 'Checking for the MPI fortran header',
                          define_name = 'HAVE_MPI_HEADER')
        conf.define('HAVE_MPI', 1)

    if 'WCSLIB' in libraries:
        conf.check_cfg(package='wcslib',  args=['--libs', '--cflags'])
        conf.check_cfg(modversion='wcslib')
        check_wcslib_external(conf.env)
        # Since WCSLIB doesn't provide F90 include files, we generate them
        # from the F77 ones
        f77dir = conf.root.find_node(conf.env['INCLUDES_WCSLIB'][0])
        f90dir = conf.bldnode.make_node('include').mkdir()
        f77files = f77dir.ant_glob('*inc')
        for f77file in f77dir.ant_glob('*inc'):
            f90file = conf.bldnode.make_node('include/'+f77file.name)
            f77_to_f90(f77file, f90file)
        conf.define('HAVE_WCSLIB', 1)

    conf.env.SHAREDIR = os.path.abspath(conf.env.PYTHONDIR + '/../../../share')
    conf.define(conf.env.FC_NAME, 1)
    conf.define('TAMASIS_DIR', os.path.join(conf.env.SHAREDIR, 'tamasis'))
    conf.define('PRECISION_REAL', int(conf.options.precision_real))

    # Write the file .f2py_f2cmap which maps the real or complex type parameter
    # 'p' to a C type
    p = conf.options.precision_real
    ctype = {'4' : 'float',
             '8' : 'double',
             '16': 'long_double'}[p]
    cctype = {'4' : 'complex_float',
              '8' : 'complex_double',
              '16': 'complex_long_double'}[p]
    os.system("echo {\\'real\\':{\\'p\\':\\'" + ctype + \
        "\\'}, \\'complex\\':{\\'p\\':\\'" + cctype + "\\'}} > %s/.f2py_f2cmap"
        % out)

#
# Build & Installation
#

def build(bld):
    global libraries

    # Build static libraries libtamasis*.a
    for subdir in subdirs:
        files = bld.srcnode.ant_glob(subdir+'/src/module_*.f')
        if subdir == 'core' and 'WCSLIB' not in libraries:
            files = [f for f in files if 'wcslib' not in f.abspath()]
        bld(features = 'fc fcstlib',
            source   = files,
            target   = 'tamasis' + subdir,
            includes = 'include',
            use      = libraries)
    bld.add_group()

    # Python extension tamasisfortran.so
    target = 'tamasisfortran.so'
    source = [bld.srcnode.find_node('%s/src/tamasisfortran_%s.f90' % (s,s))
              for s in subdirs]
    additional_interfaces = ['math', 'operators', 'pointing', 'processing',
                             'wcsutils']
    if bld.env.HAVE_MPI:
        additional_interfaces += [ 'mpi' ]
    for a in additional_interfaces:
        source += bld.srcnode.ant_glob('core/src/tamasisfortran_core_{0}.f90'.
                                       format(a))

    #XXX this should be a Task...
    cmd = ''
    if bld.env.HAVE_MPI:
        cmd += 'OMPI_FC=${OMPI_FC} '
    cmd = '${F2PY} --fcompiler=${F2PYFCOMPILER} --f90exec=${FC}'
    cmd += ' --f90flags="${FCFLAGS}'
    cmd += ' ${FCFLAGS_OPENMP}"' if 'OPENMP' in libraries else '"'
    cmd += ' --quiet' if bld.options.verbose == 0 else ''
    cmd += ' -DF2PY_REPORT_ON_ARRAY_COPY=1'
    cmd += ' -m tamasisfortran -c ' + string.join(map(str, [s.abspath() for s in source]))
    cmd += ' ' + string.join([bld.env.fcstlib_PATTERN%('tamasis'+s) for s in reversed(subdirs)])
    cmd += ' ${FCINCPATH_ST:include} ' + string.join(['${FCINCPATH_ST:INCLUDES_%s}' % u for u in libraries])
    cmd += ' ' + string.join(['${FCLIBPATH_ST:LIBPATH_%s}' % u for u in libraries])
    cmd += ' ' + string.join(['${FCLIB_ST:LIB_%s}' % u for u in libraries])
    cmd += ' ${DEFINES_ST:DEFINES}'

    bld(rule=cmd,
        color='YELLOW',
        source=source + [bld.env.fcstlib_PATTERN%('tamasis' + s)
                         for s in subdirs],
        target=target,
        use=libraries)

    # include configuration information in Python files
    bld(features= 'subst', # feature 'subst' overrides source/target processing
        source='core/src/var.py.in',
        target='core/src/var.py',
        VERSION=VERSION, # variable to use in the substitution
        HAVE_MPI=str(bld.env.HAVE_MPI == 1),
        HAVE_WCSLIB=str(bld.env.HAVE_WCSLIB == 1))

    # Installation
    files = bld.path.ant_glob('*/src/*py') + \
            [bld.bldnode.find_or_declare('core/src/var.py')]
    pyfiles = [f for f in files if not os.access(f.abspath(), os.X_OK)]
    execfiles = [f for f in files if os.access(f.abspath(), os.X_OK)]
    bld.install_files('${PYTHONDIR}/tamasis', pyfiles + ['tamasisfortran.so'])
    bld.install_files('${PYTHONDIR}/tamasis', execfiles, chmod=0o755)

    for f in execfiles:
        bf = os.path.basename(f.abspath())
        bld.symlink_as('${BINDIR}/' + bf.replace('.py', ''),
                       bld.env['PYTHONDIR']+'/tamasis/' + bf)

    for subdir in subdirs:
        node = bld.srcnode.find_node(subdir+'/src')
        if node is not None:
            bld.install_files('${SHAREDIR}/tamasis/'+subdir,
                              node.ant_glob('*.cfg'))
        node = bld.srcnode.find_node(subdir+'/data')
        if node is not None:
            bld.install_files('${SHAREDIR}/tamasis/'+subdir, node.ant_glob('*'))
        node = bld.srcnode.find_node(subdir+'/example')
        if node is not None:
            bld.install_files('${SHAREDIR}/tamasis/'+subdir, node.ant_glob('*'))

    bld.install_files('${LIBDIR}/jython/tamasishcss', bld.srcnode.ant_glob(
                      'pacs/hcss/tamasishcss/*py'))

#
# test, test-fortran, test-python
#

class test(BuildContext):
    """run Fortran and Python test suites"""
    cmd = 'test'
    fun = 'test_fun'

def test_fun(ctx):
    tests = ['test-fortran', 'test-python']
    if 'MPI' in libraries:
        tests += ['test-mpi']
    Options.commands = tests + Options.commands

class test_fortran(BuildContext):
    """run Fortran test suite"""
    cmd = 'test-fortran'
    fun = 'test_fortran_fun'

def test_fortran_fun(bld):
    build(bld)
    tamasislib = ' '.join(['tamasis' + s for s in reversed(subdirs)])
    for subdir in subdirs:
        files = bld.srcnode.ant_glob(subdir+'/test/test_*.f')
        for file in files:
            if 'WCSLIB' not in libraries and 'wcslib' in str(file):
                continue
            bld(features = 'fc fcprogram',
                source   = file,
                target   = os.path.splitext(str(file))[0],
                includes = '. include',
                libpath  = '.',
                use      = ' '.join(libraries) + ' ' + tamasislib)
    bld.add_group()
    for subdir in subdirs:
        files = bld.path.ant_glob(subdir+'/test/test_*.f')
        for file in files:
            if str(file).startswith('test_wcs'):
                continue
            bld(rule   = os.path.join(out,os.path.splitext(str(file))[0]),
                cwd    = bld.path.abspath(),
                always = True)
            bld.add_group()

class test_python(BuildContext):
    """run Python test suite"""
    cmd = 'test-python'
    fun = 'test_python_fun'

def test_python_fun(bld):
    if bld.env.IPYTHON_VERSION >= '0.12':
        options = '--no-confirm-exit --i '
    else:
        options = '-noconfirm_exit '
#    bld(rule='${IPYTHON} ' + options + bld.path.find_node(
#        'core/test/test_broken_locale.py').abspath(), always=True)

    for subdir in subdirs:
        if subdir == 'pacs':
            continue
        files = bld.path.ant_glob(subdir + '/test/test_*.py')
        for file in files:
            file = file.abspath()
            if 'test_display' in file: continue
            if 'test_mpi' in file: continue
            bld(rule='${NOSETESTS} ' + file + (' --nocapture'
                if bld.options.verbose else ''), always=True)
            bld.add_group()
    if 'pacs' in subdirs:
        test_pacs_fun(bld)

class test_display(BuildContext):
    """run Python display suite"""
    cmd = 'test-display'
    fun = 'test_display_fun'

def test_display_fun(bld):
    for subdir in subdirs:
        files = bld.path.ant_glob(subdir + '/test/test_display*.py')
        for file in files:
            file = file.abspath()
            bld(rule='${PYTHON} ' + file + (' > /dev/null'
                if not bld.options.verbose else ''), always=True)
            bld.add_group()

class test_pacs(BuildContext):
    """run PACS test suite"""
    cmd = 'test-pacs'
    fun = 'test_pacs_fun'

def test_pacs_fun(bld):
    subdir = 'pacs'
    files = bld.path.ant_glob(subdir+'/test/test_*.py')
    for file in files:
        file = file.abspath()
        if 'test_display' in file: continue
        if bld.env.HAVE_MPI and 'test_mpi' in file: continue
        if '_nl_' in file: continue
        bld(rule='${NOSETESTS} ' + file + (' --nocapture'
            if bld.options.verbose else ''), always=True)
        bld.add_group()

class test_mpi(BuildContext):
    """run MPI test suite"""
    cmd = 'test-mpi'
    fun = 'test_mpi_fun'

def test_mpi_fun(bld):

    if not bld.env.HAVE_MPI:
        Logs.pprint('RED', 'The package is not configured to use MPI. Use --ena'
                    'ble-mpi option.')
        return

    if bld.options.np is None:
        ns = 2**np.arange(int(np.floor(np.log2(multiprocessing.cpu_count())))+1)
    else:
        ns = [ int(bld.options.np) ]
    for subdir in subdirs:
        files = bld.path.ant_glob(subdir+'/test/test_mpi*.py')
        for file in files:
            for n in ns:
                bld(rule='export OMP_NUM_THREADS=1; mpirun -n ' + str(n) +
                    ' ${NOSETESTS} ' + file.abspath() + (' > /dev/null' if bld.
                    options.verbose == 0 else '') + '; unset OMP_NUM_THREADS',
                    always=True)
                bld.add_group()

#
# loc, loc-fortran, loc-python
#

def loc(ctx):
    """
    Python/Fortran/all lines of code.

    """
    print('Python:')
    os.system('find . \( -name ".waf*" -prune -or -name ".bento*" -prune -or -name build -prune -or -name .git -prune -or -name include -prune -or -name "wscript" -or -name "*py" \) -and -not -type l -and -not -type d | xargs cat | wc -l')
    print('Fortran:')
    os.system('find . \( -name ".waf*" -prune -or -name ".bento*" -prune -or -name build -prune -or -name .git -prune -or -name include -prune -or -name "*.f" -or -name "*.f90" \) -and -not -type l -and -not -type d | xargs cat | wc -l')
    print('Total:')
    os.system('find . \( -name ".waf*" -prune -or -name ".bento*" -prune -or -name build -prune -or -name .git -prune -or -name include -prune -or -name "wscript" -or -name "*.f" -or -name "*.f90" -or -name "*py" \) -and -not -type l -and -not -type d | xargs cat | wc -l')

#
# Miscellaneous helpers
#

def f77_to_f90(source, target):
    f77name = source.abspath()
    f90name = target.abspath()
    with open(f77name, 'r') as f77:
        f77content = f77.readlines()
        f90content = []
        for i, l in enumerate(f77content):
            if l[0:1] != ' ':
                continue
            if i+1 < len(f77content) and f77content[i+1][5:6] not in ('',' '):
                l = l[0:-1] + ' &\n'
            l = '      ' + l[6:]
            f90content.append(l)
        with open(f90name, 'w') as f90:
            f90.writelines(f90content)

def check_wcslib_external(env):
    wme = 'WCSLIB_MISSING_EXTERNAL'
    i = (i for i in range(len(env.DEFINES)) if env.DEFINES[i].startswith('WCSLIB_VERSION')).next()
    version = env.DEFINES[i].split('=')[1].replace('"', '')
    env.DEFINES[i] = wme + '=' + str(int(version < '4.5'))
    env.define_key[i] = wme

def _get_version(progname, flag=None):
    return '0.12'
    p = subprocess.Popen([progname, '--version'], stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE)
    stdout, stderr = p.communicate()
    if stderr != '' and flag is not None:
        p = subprocess.Popen([progname, '-Version'], stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE)
        stdout, stderr = p.communicate()
    if stderr != '':
        raise RuntimeError(stderr)
    return stdout[:-1]

def _check_git_version(ctx):
    global VERSION
    cmd = 'git log HEAD^..'.split()
    # Python 2.7
    # line = subprocess.check_output(cmd).split('\n')[0]
    p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
    (stdout, stderr) = p.communicate()
    commit = stdout.split('\n')[0].split()[1]
    tagdir = os.path.join(ctx.path.abspath(), '.git', 'refs', 'tags')
    tags = os.listdir(os.path.join(ctx.path.abspath(), '.git', 'refs', 'tags'))
    for tag in os.listdir(tagdir):
        if commit == open(os.path.join(tagdir,tag)).read()[0:-1]:
            VERSION = tag
            if VERSION[0] == 'v': VERSION = VERSION[1:]
            break
    else:
        dev = '-dev' in VERSION
        VERSION = VERSION.replace('-dev', '') + '.' + commit[0:8] + \
                  ('-dev' if dev else '')

def dist(ctx):
    _check_git_version(ctx)


import os
import types
import functools
from zipfile import ZipFile, ZIP_DEFLATED
from pathlib import Path

def has(l , key, value):
    """Check if list has dict with matching key-value pair

    Parameters
    ----------
    l : List[Dict[str, Any]]
        List to check for matches
    key : str
        Key to find in list's dictionaries
    value : Any
        Value to be compared with value in suitable key-value pair in each dictionary in list

    Returns
    -------
    bool
        True if list has dictionary with key-value pair matching given key and value, False otherwise.
    """
    for item in l:
        if item[key] == value:
            return True
    return False

def split_by_key_presense(l, key):
    """Split list of dictionaries into two lists based on key presense

    Parameters
    ----------
    l : List[Dict[str, Any]]
        List to split
    key : str
        Key to find in list's dictionaries

    Returns
    -------
    Tuple[List[Any], List[Any]]
        First list in tuple containing l's dictionaries that have given key, second list contain l's dictionaries that don't
    """
    present, missing = [], []
    for item in l:
        present.append(item) if key in item else missing.append(item)
    return present, missing

def copy_func(f):
    """Copy function

    Based on http://stackoverflow.com/a/6528148/190597 (Glenn Maynard)

    Parameters
    ----------
    f : callable
        Function to copy

    Returns
    -------
    callable
        The exact independent copy of provided function
    """
    g = types.FunctionType(f.__code__, f.__globals__, name=f.__name__,
                           argdefs=f.__defaults__,
                           closure=f.__closure__)
    g = functools.update_wrapper(g, f)
    g.__kwdefaults__ = f.__kwdefaults__
    return g

def make_path(d, *paths):
    """Create nested dictionaries in path in dictionary

    Parameters
    ----------
    d : Dict[str, Any]
        Provided dictionary

    *args:
        Variable length list of path segments to create if not present

    Returns
    -------
    Dict
        Dict with nested dicts with paths items as keys

    Raises
    ------
    AttributeError
        If path segment already exists on the same level of provided dictionary AND is not a dictionary

    Examples
    --------
    >>> test = { "foo": { "baz": 42 } }
    >>> make_path(test, "foo", "bar", "baz")
    {}
    >>> test
    {'foo': {'baz': 42, 'bar': {'baz': {}}}}
    """
    while paths:
        key, *paths = paths
        d = d.setdefault(key, {})
    return d

def extract_zip(source_path, target_path):
    """Extract zip archive

    Parameters
    ----------
    source_path : str
        Path to archive to be extracted

    target_path : str
        Path to directory to extract archive content
    """
    with ZipFile(source_path, 'r') as zip_object:
        file_names = zip_object.namelist()
        for file_name in file_names:
            zip_object.extract(file_name, target_path)

def make_zip(source_path, target_path):
    """Create zip archive with only related paths (source_path > files or directories)

    Parameters
    ----------
    source_path : str
        Path to directory to be archived

    target_path : str
        Path (with file name) where to store resulting archive
    """
    source_path_last = source_path.split(os.sep)[-1] # relative path for zipf arcname construction
    zipf = ZipFile(target_path, 'w', ZIP_DEFLATED)
    for folder_name, subfolders, file_names in os.walk(source_path):
        for file_name in file_names:
            file_path = os.path.join(folder_name, file_name)
            segments = file_path.split(os.sep)
            archive_path = segments[segments.index(source_path_last):]
            zipf.write(file_path, arcname=os.sep.join(archive_path[1:]))
    zipf.close()

def fix_tk_file_path(incorrect_path):
    """Fix issue when tk.filedialog methods (like askdirectory) yield file paths with incorrect separators using slashes instead of backslashes on Windows

    Parameters
    ----------
    incorrect_path : str
        String using forward slashes like 'C:/Users/Foo/bar/baz'

    Returns
    -------
    str
        Correct platform-dependent path with os.sep as separator
    """
    return str(Path(incorrect_path).resolve())


import numpy as np
import gym
import _pickle as cPickle

from keras.models import Sequential
from keras.layers import Flatten, Dense, Activation, Embedding, Reshape
from keras.optimizers import Adam

from rl.agents.dqn import DQNAgent
from rl.policy import EpsGreedyQPolicy
from rl.memory import SequentialMemory
import tensorflow as tf
import os.path
from os import path
from time import sleep

tf.compat.v1.disable_eager_execution()

# import os
# os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"   # see issue #152
# os.environ["CUDA_VISIBLE_DEVICES"] = ""

class DQN_Agent:
	def __init__(self, env):
		self.env = env

		self.stats = dict()
		self.stats['timesteps'] = list()
		self.stats['reward'] = list()

		np.random.seed(1)
		self.nb_actions = env.action_space.n
		self.nb_observations = env.observation_space.n

		# Create the model
		model = Sequential()
		model.add(Embedding(self.nb_observations,10,input_length=1))
		model.add(Reshape((10,)))
		model.add(Dense(50, activation='relu'))
		model.add(Dense(50, activation='relu'))
		model.add(Dense(50, activation='relu'))
		model.add(Dense(self.nb_actions, activation='linear'))
		print(model.summary())

		memory = SequentialMemory(limit=50000, window_length=1)
		policy = EpsGreedyQPolicy()
		self.dqn = DQNAgent(model=model, nb_actions=self.nb_actions, memory=memory, nb_steps_warmup=500,target_model_update=1e-2, policy=policy)
		self.dqn.compile(Adam(lr=1e-3), metrics=['mae'])

	# Train the agent
	def train_agent(self, episodes, ep_step, filename):
		if(not path.exists(filename)):
			if ep_step == -1:
				self.dqn.fit(self.env, nb_steps=episodes, visualize=False, verbose=1, nb_max_episode_steps=99, log_interval=2000)
			else:
				for episode in range(ep_step,episodes+1, ep_step):
					data = self.dqn.fit(self.env, nb_steps=episode, visualize=False, verbose=1, nb_max_episode_steps=99, log_interval=2000)
					time, rew = self.simulate(visualize = False, episodes = 10)
					self.stats['timesteps'].append(time)
					self.stats['reward'].append(rew)
			self.dqn.save_weights(filename, overwrite=True)
		else:
			self.dqn.load_weights(filename)

	# Evaluate the agent
	def simulate(self, filename, visualize, episodes):
		if(not path.exists(filename)):
			train_agent(episodes = 2000, ep_step=-1, filename=filename)
		else:
		 	self.dqn.load_weights(filename)
		visual = visualize
		data = self.dqn.test(self.env, nb_episodes=episodes, visualize=visual, nb_max_episode_steps=99)
		return np.mean(data.history['nb_steps']),np.mean(data.history['episode_reward'])

	def getStats(self):
		return self.stats

	def resetStats(self):
		self.stats['timesteps'].clear()
		self.stats['reward'].clear()

	def loadWeights(self, filename):
		self.dqn.load_weights(filename)


import networkx as nx
from proj.config import configuration

from proj.context import Context

def construct_multigraph(graph, infrastructures):
  """
  Given a simple graph and infrastructures information, constructs a multigraph
  that includes the merged information.
  """
  infras = InfrastructureContext(**infrastructures)

  ret = nx.MultiDiGraph()

  for infra_index in range(len(infras.cost_factors) + 1):
    for edge in graph.edges():
      n1, n2 = edge
      data = dict(graph.edges[edge])
      if infra_index == 0:
        data.update({
          configuration.arc_cost_key: 0
        })
      else:
        data.update(infras.get_edge_weights(infra_index - 1, edge, data))

      ret.add_edge(n1, n2, **data)

  return ret

class InfrastructureContext(Context):
  def __init__(self, **kwargs):
    super().__init__(self, **kwargs)
    self._validate()

  def get_edge_weights(self, infra, edge, edge_attrs):
    weight = edge_attrs[configuration.arc_weight_key]

    if edge in self.costs:
      cost = self.costs.get(edge)
    else:
      cost = weight * self.cost_factors[infra]

    if edge in self.construction_costs:
      construction_cost = self.construction_costs.get(edge)
    else:
      construction_cost = configuration.construction_coefficient * weight * self.construction_cost_factors[infra]

    return {
      configuration.arc_weight_key: cost,
      configuration.arc_cost_key: construction_cost,
    }

  def _validate(self):
    """
    Dictionary with information about costs and construction costs:
    For example, for three infrastructures, without the base:
    {
      cost_factors: [x1, x2, x3],
      construction_cost_factors: [y1, y2, y3],
      costs: [ # One dict per infrastructure
        { (n1, n2): 123, (n4, n3): 12312 },
        {},
        {},
      ],
      construction_costs: [
        ...
        same format as costs
        ...
      ],
    }
    """
    infras = self

    infra_keys = ['cost_factors', 'construction_cost_factors', 'costs', 'construction_costs']

    for key in infra_keys[:2]:
      value = infras.get(key)
      if not value:
        raise Exception(f'Missing infrastructures {key}')
      if not isinstance(value, list):
        raise Exception(f'{key} must be an list')

    if len(infras.cost_factors) != len(infras.construction_cost_factors):
      raise Exception('cost_factors and construction_cost_factors have different length')

    for key in infra_keys[2:]:
      value = infras.get(key)

      if not value:
        infras[key] = []
        continue

      if not hasattr(value, '__iter__'):
        raise Exception(f'{key} must be an list')

      if any(map(lambda x: not isinstance(x, dict), value)):
        raise Exception(f'{key} must be an list of dicts')


# -*- coding: UTF-8 -*-

from io import StringIO

from .defines import (HTML_ORG_DIV_DATE_CLASS,
                      HTML_ORG_TABLE_CLASS,
                      HTML_ORG_DIV_CLASS,
                      HTML_EMPTY_CELL_CONTENT)

class OrgHTMLGenerator (object):
    """It is HTML generator for (:org:) command"""

    def __init__(self, config, parser):
        self._dateConfig = config.dateTimeFormat.value
        self._styles = config.orgStyles.value
        self._parser = parser

    def getHTML(self, dayDescription):
        builder = StringIO()

        builder.write(u'
\n'.format(HTML_ORG_DIV_CLASS))

        if dayDescription.date is not None:
            date_str = dayDescription.date.strftime(self._dateConfig)
            builder.write(self._getDateHTML(date_str))

        builder.write(self._getTableHTML(dayDescription))

        builder.write(u'
\n')
        return builder.getvalue()

    def getStyles(self):
        return self._styles

    def _getTableHTML(self, dayDescription):
        headers = self._getHeaders(dayDescription)
        builder = StringIO()
        builder.write(u'
\n'.format(HTML_ORG_TABLE_CLASS))

        if headers:
            # Append headers
            builder.write(u'
')
            for header in headers:
                builder.write(u'{}	'.format(header))
            builder.write(u'
\n')

            # Append rows
            for record in dayDescription:
                builder.write(self._getRecordRowHTML(headers, record))

        builder.write(u'
\n')
        return builder.getvalue()

    def _getRecordRowHTML(self, headers, record):
        builder = StringIO()
        builder.write('
')
        for header in headers:
            builder.write('')
            item = record[header]
            if item is not None:
                builder.write(self._parser.parseWikiMarkup(item))
            else:
                builder.write(HTML_EMPTY_CELL_CONTENT)
            builder.write('	')

        builder.write('
\n')
        return builder.getvalue()

    def _getDateHTML(self, date_str):
        return u'
{content}
'.format(
            classname=HTML_ORG_DIV_DATE_CLASS,
            content=date_str
        )

    def _getHeaders(self, dayDescription):
        headers = []
        for record in dayDescription:
            for header in record:
                if header not in headers:
                    headers.append(header)

        return headers


from typing import Optional, Any, Union

import matplotlib.pyplot as plt
import numpy as np

import qtt.algorithms.functions

def plot_horizontal_line(x: float, color: str = 'c', alpha: float = .5, label: Optional[str] = None) -> Any:
    """ Plot vertical alignment line

    Args:
        x: Position on horizontal axis to plot the line
        color: Color specification of the line
        alpha: Value to use for the transparency of the line
        label: Label for the line
    Return:
        Handle to the plotted line
    """
    vline = plt.axhline(x, label=label)
    vline.set_alpha(alpha)
    vline.set_color(color)
    vline.set_linestyle('--')
    return vline

def plot_vertical_line(x: float, color: str = 'c', alpha: float = .5, label: Optional[str] = None) -> Any:
    """ Plot vertical alignment line

    Args:
        x: Position on horizontal axis to plot the line
        color: Color specification of the line
        alpha: Value to use for the transparency of the line
        label: Label for the line
    Return:
        Handle to the plotted line

    """
    vline = plt.axvline(x, label=label)
    vline.set_alpha(alpha)
    vline.set_color(color)
    vline.set_linestyle('--')
    return vline

def plot_double_gaussian_fit(result_dict: dict, xdata: np.array) -> None:
    """ Plot a two Gaussians from a double Gaussian fit

    Args:
        result_dict: Result of the double Gaussian fitting
        xdata: Independent data
    """
    plt.plot(xdata, qtt.algorithms.functions.gaussian(xdata, *result_dict['left']), 'g', label='left')
    _ = plt.plot(xdata, qtt.algorithms.functions.gaussian(xdata, *result_dict['right']), 'r', label='right')

def plot_single_traces(traces: np.ndarray, time: Optional[np.ndarray] = None, trace_color: Optional[np.ndarray]
                       = None, offset: Union[None, bool, float] = None, fig: int = 1, maximum_number_of_traces: int = 40):
    """ Plot single traces with offset for separation

    Args:
       traces: Array with single traces in the rows
       time: Option array for time axis
       trace_color: Specification of trace color
       offset: Offset to use between traces. For None automatically determine the offset
       fig: Specification of Matplotlib window
       maximum_number_of_traces: Maximum number of traces to plot
    """
    if time is None:
        time = np.arange(traces.shape[1])
    if trace_color is None:
        trace_color = np.zeros(traces.shape[0])
    if offset is False:
        offset = 0
    if offset is None:
        offset = (np.percentile(traces, 99) - np.percentile(traces, 1)) * 1.95
    maximum_number_of_traces = min(maximum_number_of_traces, traces.shape[0])

    color_map = {0: 'b', 1: 'r', 2: 'm'}
    plt.figure(fig)
    plt.clf()
    for ii in range(maximum_number_of_traces):
        trace_offset = ii * offset

        color = color_map.get(trace_color[ii], 'c')
        plt.plot(time, traces[ii] + trace_offset, color=color)
    plt.xlabel('Time [us]')
    plt.ylabel('Signal [a.u.]')
    _ = plt.title('Elzerman traces (spin-down in blue, spin-up in red)')


# 在一定范围内随机创建100个立方体
# https://jingyan.baidu.com/article/6c67b1d6afa19b2786bb1e78.html

import bpy

from random import randint

bpy.ops.mesh.primitive_cube_add()

#创建模型的数量

count = 100

for c in range(0,count):

    x = randint(-100,100)

    y = randint(-100,100)

    z = randint(-100,100)

    bpy.ops.mesh.primitive_cube_add(location=(x,y,z))


# License: GNU Affero General Public License v3 or later
# A copy of GNU AGPL v3 should have been included in this software package in LICENSE.txt.

""" A collection of classes and functions that allow each antismash module to
    specify its own command line options.

    Also constructs the general/default options.
"""

import argparse
from collections import defaultdict
import multiprocessing
import os
from typing import Any, AnyStr, Dict, IO, List, Optional, Set, Tuple

from antismash.custom_typing import AntismashModule

from .executables import AlternateExecutablesAction, get_default_paths

# There are some issues with mypy's typeshed for argparse, so there's a lot of
# ignores sprinkled throughout. Most deal with ArgumentParser methods
# not being picked up or argparse's liberal use of *kwargs.

ANTISMASH_VERSION = ""  # needs to be set on module import, avoids cyclic imports

class AntismashParser(argparse.ArgumentParser):
    """ Custom argument parser for antiSMASH to override default help output

        Also helps with module level arguments

        Important changes
            parents argument: A list of ModuleArgs instead of other parsers
            add_help argument: Always overridden to False
    """
    def __init__(self, *args: Any, **kwargs: Any) -> None:
        # while keeping parents as ModuleArg instances is important
        # ArgumentParser itself expects parsers, so modify kwargs accordingly
        self.parents = kwargs.get("parents", [])
        if self.parents:
            kwargs["parents"] = [parent.parser for parent in self.parents]
        # ensure default -h/--help is disabled, since help is more complex here
        kwargs["add_help"] = False
        self._show_all = False
        # include in basic help any parent requesting it
        self._basic_help_groups = set(parent.title for parent in self.parents if parent.basic)
        # and since the additional analysis group doesn't propagate while empty
        self._basic_help_groups.add("Additional analysis")
        super().__init__(*args, **kwargs)

# overridden ArgumentParser methods which only used args/kwargs or with less options
# pylint: disable=arguments-differ
    def add_argument_group(self, title: str, description: str = None, basic: bool = False,  # type: ignore
                           **kwargs: Any):
        """ Overrides original to enable tracking of which help category a group
            is in.

            Arguments:
                title: the group label for showing help
                description: text with further information about the group
                basic: whether or not the group should be shown with just --help
                **kwargs: catches any argparse specific args that we don't use

            Returns:
                the group added
        """
        if not title:
            raise ValueError("Argument groups must have a group label/title")
        # if one group is added with a label and shows basic help, show for all
        # with the same label
        if basic:
            self._basic_help_groups.add(title)
        return super().add_argument_group(title, description, **kwargs)
# pylint: enable=arguments-differ

    def print_help(self, file: IO = None, show_all: bool = False
                   ) -> None:
        """ Overrides parent print_help() to be able to pass through whether all
            help should be shown or not.

            Arguments:
                file_handle: the file to write the help to, defaults to stdout
                show_all: True if all help should be shown, otherwise only basic

            Returns:
                None
        """
        self._show_all = show_all
        super().print_help(file)

    def write_to_config_file(self, filename: str, values: Dict[str, Any] = None) -> None:
        """ Write the default options to file in a form that can be parsed again

            Arguments:
                filename: the filename to write to
                values: a Namespace object with values to use instead of defaults
        """
        def construct_arg_text(arg: argparse.Action, processed_destinations: Set[str],
                               values: Dict[str, Any]) -> List[str]:
            """ Only construct if not already processed and not a help or input
                arg
            """
            if (arg.dest in ["help", "help_showall", "write_config_file",  # reserved
                             "reuse_results", "check_prereqs_only",
                             "list_plugins", "version", "genefinding_gff3"]
                    or arg.dest in processed_destinations  # already exists
                    or not arg.option_strings):  # skip postional args
                return []
            lines = []
            processed_destinations.add(arg.dest)
            flag = sorted(arg.option_strings, key=len, reverse=True)[0].lstrip('-')
            # fill in the current default if relevant
            assert arg.help is not None
            if "%(default)" in arg.help:
                help_text = arg.help % {"default": arg.default}
            else:
                help_text = arg.help
            lines.append(f"## {help_text}")
            # add the set of possible choices, if relevant
            if arg.choices:
                lines.append(f"## Possible choices: {','.join(arg.choices)}")
            # start with default value
            value = arg.default
            # and if it was supplied, use it
            if arg.dest in values:
                value = values.get(arg.dest)
            # convert options with list values to strings
            was_list = isinstance(value, list)
            if value and isinstance(value, list):
                value = ",".join(value)
            if arg.const and arg.default is False:  # i.e. is it a 'store_true'
                # don't write the value if it only changes to True,
                # otherwise the True will be considered a positional arg
                # and causes problems with the sequence
                state = "#"
                if value:
                    state = ""
                lines.append(f"{state}{flag}")
            elif not value:
                default = arg.default
                if not default:
                    default = arg.metavar
                lines.append(f"#{flag} {default}")
            else:
                default = ""
                if value == arg.default or was_list and value.split(",") == arg.default:
                    default = "#"
                lines.append(f"{default}{flag} {value}")
            return ["\n".join(lines)]

        if not values:
            values = {}

        dests: Set[str] = set()  # set of processed destinations
        titles: Dict[str, Dict[str, List[str]]] = defaultdict(lambda: defaultdict(list))
        for parent in sorted(self.parents, key=lambda group: group.title):
            for arg in parent.parser.get_actions():
                titles[parent.title][parent.prefix].extend(construct_arg_text(arg, dests, values))

        for arg in self._actions:
            titles["Core options"]["core"].extend(construct_arg_text(arg, dests, values))

        with open(filename, "w", encoding="utf-8") as outfile:
            for title, prefixes in titles.items():
                banner = "#"*10 + "\n"
                outfile.writelines([banner, f"#\t{title}\n", banner, "\n"])
                for lines in prefixes.values():
                    outfile.write("\n".join(lines))
                    outfile.write("\n")
                outfile.write("\n\n")

    def format_help(self) -> str:
        """Custom help formatter"""
        help_text = f"""
########### antiSMASH {ANTISMASH_VERSION} #############

{self.format_usage()}

{self._get_args_text()}
--------
Options
--------
{self._get_opts_text()}
"""
        return help_text

    def format_usage(self) -> str:
        """ Custom usage generator """
        if self._show_all:
            formatter = self._get_formatter()
            formatter.add_usage(self.usage, self._actions, self._mutually_exclusive_groups)
            return formatter.format_help()
        return f"usage: {self.prog} [-h] [options ..] sequence\n"

    def _get_args_text(self) -> str:
        # fetch arg lists using formatter
        formatter = self._get_formatter()
        for action_group in self._action_groups:
            if action_group.title == "positional arguments":
                formatter.start_section("arguments")
                formatter.add_arguments(action_group._group_actions)  # pylint: disable=protected-access
                formatter.end_section()
                break
        return formatter.format_help()

    def _get_opts_text(self) -> str:
        """ fetch opt lists using formatter """
        formatter = self._get_formatter()
        for action_group in self._action_groups:
            if action_group.title in ["optional arguments"]:
                formatter.add_arguments(action_group._group_actions)  # pylint: disable=protected-access
        for action_group in self._action_groups:
            if action_group.title not in ["optional arguments", "positional arguments"]:
                show_opt = self._show_all
                if not show_opt:
                    if action_group.title in self._basic_help_groups:
                        show_opt = True
                if show_opt:
                    formatter.start_section(action_group.title)
                    if action_group.description is None:
                        action_group.description = ''
                    formatter.add_text(action_group.description)
                    formatter.add_arguments(action_group._group_actions)  # pylint: disable=protected-access
                    formatter.end_section()
        return formatter.format_help()

    def convert_arg_line_to_args(self, arg_line: str) -> List[str]:
        """ overrides original to properly parse config files """
        line = arg_line.strip()
        if not line:
            return []
        # skip comments and section labels
        if line[0] in ["#", '[']:
            return []
        args = line.split()
        # prepend -- so the parser recognises it properly
        args[0] = "--" + args[0]
        return args

    def get_actions(self) -> Tuple[argparse.Action, ...]:
        """ a getter for _actions operated on by ArgumentParser, which may
            change behaviour """
        return tuple(self._actions)

class FullPathAction(argparse.Action):
    """ An argparse.Action to ensure provided paths are absolute. """
    def __call__(self, parser: argparse.ArgumentParser, namespace: argparse.Namespace,
                 values: Any, option_string: str = None) -> None:
        setattr(namespace, self.dest, os.path.abspath(str(values)))

class MultipleFullPathAction(argparse.Action):
    """ An argparse.Action to ensure provided paths are absolute in a comma separated list. """
    def __call__(self, parser: argparse.ArgumentParser, namespace: argparse.Namespace,
                 values: Any, option_string: str = None) -> None:
        setattr(namespace, self.dest, [os.path.abspath(value) for value in str(values).split(",")])

class ReadableFullPathAction(FullPathAction):
    """ An argparse.Action to ensure provided paths are absolute. """
    def __call__(self, parser: argparse.ArgumentParser, namespace: argparse.Namespace,  # type: ignore
                 values: AnyStr, option_string: str = None) -> None:
        path = os.path.abspath(values)
        if os.path.isdir(path):
            raise argparse.ArgumentError(self, f"{values!r} is a directory")
        if not os.path.isfile(path):
            raise argparse.ArgumentError(self, f"{values!r} does not exist")
        if not os.access(path, os.R_OK):
            raise argparse.ArgumentError(self, f"{values!r}: permission denied")
        super().__call__(parser, namespace, values, option_string)

class SplitCommaAction(argparse.Action):
    """ An argparse.Action to split an argument in the form of a comma separated
        list into a list of strings.
    """
    def __call__(self, parser: argparse.ArgumentParser, namespace: argparse.Namespace,
                 values: Any, option_string: str = None) -> None:
        setattr(namespace, self.dest, str(values).split(","))

class _SimpleArgs:
    """ Groups command line arguments which are unrelated to antiSMASH modules
    (such as help options). For module specific arguments, use ModuleArgs.

    To add arguments, use the following:
            _SimpleArgs.add_option('max-size', ...)

    Arguments:
        title: The label shown on the help screen
        override_safeties: If True, overrides many safety and consistency
            checks, only exists to help placeholders and will be removed
        basic_help: Whether help for module options (not analysis toggles)
            should be shown in the basic --help output.
            """
    def __init__(self, title: str, override_safeties: bool = False, basic_help: bool = False) -> None:
        if not title:
            raise ValueError("Argument group must have a title")
        self.title = str(title)
        self.parser = AntismashParser(parents=[])
        self.override = override_safeties

        # store options for this argument group
        self.options = self.parser.add_argument_group(title=title, basic=basic_help)

        self.skip_type_check = self.override
        self.args: List[argparse.Action] = []
        self.basic = basic_help
        self.prefix = ""  # core groups won't have one, but needed for writing config files

    def add_option(self, name: str, *args: Any, **kwargs: Any) -> None:
        """ Add a commandline option that takes a value """
        if not name:
            raise ValueError("Options must have a name")
        option_type = kwargs.get("type")
        default = kwargs.get("default")
        if kwargs.get("action") == "store_true" or hasattr(option_type, "__call__"):
            # skip checking of options with no value or options using lambdas
            pass
        elif option_type is not None:
            # if it has a type, ensure the default is that type
            assert isinstance(default, option_type)
        self._add_argument(self.options, name, *args, **kwargs)

    def _add_argument(self, group: argparse._ArgumentGroup, name: str,
                      *args: Any, **kwargs: Any) -> None:
        self.skip_type_check = self.override
        # prevent the option name being considered destination by argparse
        if not name.startswith("-"):
            name = f"-{'-' if len(name) > 1 else ''}{name}"
        # most actions make types optional, so handle that
        if "type" not in kwargs and "action" in kwargs:
            self.skip_type_check = True
        self.verify_required(kwargs)

        name, kwargs["dest"] = self.process_names(name, kwargs["dest"])
        self.args.append(group.add_argument(name, *args, **kwargs))

    def verify_required(self, kwargs: Dict[str, Any]) -> None:
        """ Checks that all the important sections have arguments provided.

            If self.skip_type_check is truthy, extra checks on default types
            will be ignored.

            Raises relevant exceptions for any problems.

            Arguments:
                kwargs: the keyword args to check

            Returns:
                None
        """
        if kwargs.get("default") is None:
            raise ValueError("Arguments must have a default, (default=)")
        if not kwargs.get("help"):
            raise ValueError("Arguments must have a help string, (help=)")
        if not kwargs.get("dest"):
            raise ValueError("Arguments must have a destination, (dest=)")

        if self.skip_type_check:
            return

        declared_type = kwargs.get("type")
        if declared_type is None:
            raise ValueError("Arguments must have a type declared, (type=)")
        if not isinstance(kwargs["default"], declared_type):
            raise TypeError("Argument default doesn't match chosen type")

    def process_names(self, name: str, dest: str) -> Tuple[str, str]:
        """ Ensures both commandline name and destination/attribute name are
            valid.

            Returns:
                a tuple of name and destination, modified to include prefix if
                it was ommitted
        """
        if isinstance(name, list):
            raise TypeError("Module arguments may not have short-forms")
        if not isinstance(name, str) or not isinstance(dest, str):
            raise TypeError("Argument name and dest must be strings")

        return name, dest

class ModuleArgs(_SimpleArgs):
    """ The vehicle for adding module specific arguments in sane groupings.
        Each module should have a unique prefix for their arguments, for clarity
        and safety. The prefix only has to be supplied when constructing a
        ModuleArgs instance, it will be automatically applied to each argument
        added.

        To add arguments, use the following:
            for an analysis option (e.g. --pref-general):
                ModuleArgs.add_analysis_toggle('general', ...)
            for a module config option (e.g. --pref-max-size):
                ModuleArgs.add_option('max-size', ...)

        Arguments:
            title: The label shown on the help screen
            prefix: A prefix to use for all options used by the module
            override_safeties: If True, overrides many safety and consistency
                    checks, only exists to help placeholders and will be removed
            enabled_by_default: whether the module's analysis will be on by
                    default or whether it has to be specifically enabled,
                    if True, it will create a --enable-* arg to be used if
                    --minimal is provided.
            basic_help: Whether help for module options (not analysis toggles)
                    should be shown in the basic --help output.
    """
    def __init__(self, title: str, prefix: str, override_safeties: bool = False,
                  enabled_by_default: bool = False, basic_help: bool = False) -> None:
        super().__init__(title, override_safeties, basic_help)
        self.enabled_by_default = enabled_by_default
        # store options of specific modules
        self._analysis_toggles = self.parser.add_argument_group(title="Additional analysis",
                                                    basic=True)

    # check if the prefix is valid
        if not isinstance(prefix, str):
            raise TypeError("Argument prefix must be a string")
        if len(prefix) < 2 and not self.override:
            raise ValueError("Argument prefixes must be at least 2 chars")
        if prefix and not prefix[0].isalpha():
            raise ValueError("Argument prefixes cannot start with numbers")
        if prefix and not prefix.isalnum():
            raise ValueError("Argument prefixes must be alphanumeric")
        self.prefix = prefix

    def add_analysis_toggle(self, name: str, *args: Any, **kwargs: Any) -> None:
        """ Add a simple on-off option to appear in the "Additional analysis"
        section. Every module that isn't running by default must have one
        of these arguments.
        """
        self._add_argument(self._analysis_toggles, name, *args, **kwargs)

    def process_names(self, name: str, dest: str) -> Tuple[str, str]:
        name, dest = super().process_names(name, dest)

        # skip the remaining safety checks if set up
        if self.override:
            return name, dest

        # ensure all destinations and flags start with the prefix
        if name.lstrip("-") == self.prefix:
            # not having anything else is ok if it's the only arg
            if not dest:
                dest = self.prefix
        elif not name.lstrip("-").startswith(self.prefix + "-"):
            name = f"--{self.prefix}-{name.lstrip('-')}"

        if not dest:
            dest = name.lstrip("--").replace("-", "_")
        elif dest != self.prefix and not dest.startswith(self.prefix + "_"):
            dest = f"{self.prefix}_{dest}"
        if "-" in dest:
            raise ValueError("Destination for option cannot contain hyphens")

        return name, dest

def build_parser(from_config_file: bool = False, modules: List[AntismashModule] = None) -> AntismashParser:
    """ Constructs an AntismashParser with all the default options antismash
        requires for proper operation, along with any added by the provided
        modules.

        Arguments:
            from_config_file: whether to allow loading from file with args like
                                @file
            modules: a list of modules/objects implementing get_arguments() for
                        construction of the arguments themselves

        Returns:
            an AntismashParser instance with options for all provided modules
    """
    parents = [help_options(), basic_options(), output_options(), advanced_options(),
               debug_options()]
    minimal = specific_debugging(modules)
    if minimal:
        parents.append(minimal)
    if modules is not None:
        parents.extend(module.get_arguments() for module in modules)

    if from_config_file:
        parser = AntismashParser(parents=parents, fromfile_prefix_chars="@")
    else:
        parser = AntismashParser(parents=parents)

    # positional arguments
    parser.add_argument('sequences',
                        metavar='SEQUENCE',
                        nargs="*",
                        help="GenBank/EMBL/FASTA file(s) containing DNA.")
    return parser

def help_options() -> _SimpleArgs:
    """ Constructs help options for antismash. """
    group = _SimpleArgs("Help options", basic_help=True)

    group.add_option('-h', '--help',
                    dest='help',
                    action='store_true',
                    default=False,
                    help="Show basic help text.")
    group.add_option('--help-showall',
                    dest='help_showall',
                    action='store_true',
                    default=False,
                    help="Show full list of arguments.")
    return group

def basic_options() -> _SimpleArgs:
    """ Constructs basic options for antismash. """
    group = _SimpleArgs("Basic analysis options", basic_help=True)

    group.add_option('-t', '--taxon',
                     dest='taxon',
                     default='bacteria',
                     choices=['bacteria', 'fungi'],
                     type=str,
                     help="Taxonomic classification of input sequence. (default: %(default)s)")
    group.add_option('-c', '--cpus',
                    dest='cpus',
                    type=int,
                    default=multiprocessing.cpu_count(),
                    help="How many CPUs to use in parallel. (default for this machine: %(default)s)")
    group.add_option('--databases',
                    dest='database_dir',
                    default=os.path.join(os.path.dirname(os.path.dirname(__file__)), 'databases'),
                    metavar="PATH",
                    action=FullPathAction,
                    type=str,
                    help="Root directory of the databases (default: %(default)s).")
    return group

def output_options() -> ModuleArgs:
    """ Constructs output options for antismash.
    """
    group = ModuleArgs("Output options", 'output', basic_help=True)
    group.add_option('--output-dir',
                     dest='output_dir',
                     default="",
                     type=str,
                     action=FullPathAction,
                     help="Directory to write results to.")
    group.add_option('--output-basename',
                     dest='output_basename',
                     default="",
                     type=str,
                     help="Base filename to use for output files within the output directory.")
    return group

def advanced_options() -> ModuleArgs:
    """ Constructs a ModuleArgs for all the advanced options not shown
        with just --help.
    """
    group = ModuleArgs("Advanced options", '', override_safeties=True)
    group.add_option('--reuse-results',
                     dest='reuse_results',
                     type=str,
                     action=ReadableFullPathAction,
                     default="",
                     metavar="PATH",
                     help="Use the previous results from the specified json datafile")
    group.add_option('--limit',
                     dest="limit",
                     type=int,
                     default=-1,
                     help="Only process the largest <limit> records (default: %(default)s). -1 to disable")
    group.add_option('--abort-on-invalid-records',
                     dest="abort_on_invalid_records",
                     action=argparse.BooleanOptionalAction,
                     default=True,
                     help="Abort runs when encountering invalid records instead of skipping them")
    group.add_option('--minlength',
                     dest="minlength",
                     type=int,
                     default=1000,
                     help="Only process sequences larger than <minlength> (default: %(default)d).")
    group.add_option('--start',
                     dest='start',
                     type=int,
                     default=-1,
                     help="Start analysis at nucleotide specified.")
    group.add_option('--end',
                     dest='end',
                     type=int,
                     default=-1,
                     help="End analysis at nucleotide specified")
    group.add_option('--write-config-file',
                     dest='write_config_file',
                     default="",
                     metavar="PATH",
                     action=FullPathAction,
                     type=str,
                     help="Write a config file to the supplied path")
    group.add_option('--without-fimo',
                     dest='without_fimo',
                     action='store_true',
                     default=False,
                     help="Run without FIMO (lowers accuracy of RiPP precursor predictions)")
    group.add_option('--executable-paths',
                     dest='executables',
                     metavar="EXECUTABLE=PATH,EXECUTABLE2=PATH2,...",
                     action=AlternateExecutablesAction,
                     default=argparse.Namespace(**get_default_paths()),
                     help=("A comma separated list of executable name->path pairs "
                           "to override any on the system path."
                           "E.g. diamond=/alternate/path/to/diamond,hmmpfam2=hmm2pfam"))
    group.add_option('--allow-long-headers',
                     dest='allow_long_headers',
                     action=argparse.BooleanOptionalAction,
                     default=True,
                     help="Should sequence identifiers longer than 16 characters be allowed")
    return group

def debug_options() -> ModuleArgs:
    """ Constructs a ModuleArgs object with antismash's debug options """
    group = ModuleArgs("Debugging & Logging options", '', override_safeties=True)
    group.add_option('-v', '--verbose',
                     dest='verbose',
                     action='store_true',
                     default=False,
                     help="Print verbose status information to stderr.")
    group.add_option('-d', '--debug',
                     dest='debug',
                     action='store_true',
                     default=False,
                     help="Print debugging information to stderr.")
    group.add_option('--logfile',
                     dest='logfile',
                     default="",
                     metavar="PATH",
                     action=FullPathAction,
                     type=str,
                     help="Also write logging output to a file.")
    group.add_option('--list-plugins',
                     dest='list_plugins',
                     action='store_true',
                     default=False,
                     help="List all available sec. met. detection modules.")
    group.add_option('--check-prereqs', '--prepare-data',
                     dest='check_prereqs_only',
                     action='store_true',
                     default=False,
                     help="Check if all prerequisites are met, preparing data files where possible.")
    group.add_option('--limit-to-record',
                     dest='limit_to_record',
                     default="",
                     metavar="RECORD_ID",
                     type=str,
                     help="Limit analysis to the record with ID record_id")
    group.add_option('-V', '--version',
                     dest='version',
                     action='store_true',
                     default=False,
                     help="Display the version number and exit.")
    group.add_option('--profiling',
                     dest='profile',
                     action='store_true',
                     default=False,
                     help="Generate a profiling report, disables multiprocess python.")
    group.add_option('--skip-sanitisation',
                     dest='skip_sanitisation',
                     action='store_true',
                     default=False,
                     help="Skip input record sanitisation. Use with care.")
    group.add_option('--skip-zip-file',
                     dest='skip_zip_file',
                     action='store_true',
                     default=False,
                     help="Do not create a zip of the output")
    return group

def specific_debugging(modules: Optional[List[AntismashModule]]) -> Optional[ModuleArgs]:
    """ Inserts a --minimal option, along with --enable-X for all modules which
        specified enabled_by_default as True.

        If no modules have specified enabled_by_default, --minimal will not be
        created.
    """
    if not modules:
        return None
    # only relevant for modules that are disabled by --minimal
    relevant_modules = []
    for module in modules:
        args = module.get_arguments()
        if not args.enabled_by_default:
            continue
        relevant_modules.append(module)
    if not relevant_modules:
        return None

    group = ModuleArgs('Debugging options for cluster-specific analyses', '', override_safeties=True)
    group.add_option('--minimal',
                     dest='minimal',
                     action='store_true',
                     default=False,
                     help="Only run core detection modules, no analysis modules unless explicitly enabled")
    errors = []
    for module in relevant_modules:
        try:
            group.add_option(f"--enable-{module.NAME.replace('_', '-')}",
                             dest=f"{module.NAME}_enabled",
                             action='store_true',
                             default=False,
                             help=(f"Enable {module.SHORT_DESCRIPTION}"
                                   " (default: enabled, unless --minimal is specified)"
                                   )
                             )
        except AttributeError as err:
            errors.append(str(err).replace("'module' object", module.__name__))
    if errors:
        raise AttributeError("\n\t".join([''] + errors))
    return group


import argparse
import json
from scipy.optimize import differential_evolution
import datetime
import sys

sys.path.append("..")

from helpers import parse_terms

from solvers import base_solver
import mofo
from solvers.mofo_mod_terms import MOFO_MOD_TERMS

def get_mofo_mod_results(game, season_team_attrs, team_stat_data, pitcher_stat_data, pitchers, terms, special_cases, mods):
    game_attrs = base_solver.get_attrs_from_paired_game(season_team_attrs, game)
    special_game_attrs = (game_attrs["home"].union(game_attrs["away"])) - base_solver.ALLOWED_IN_BASE
    if not special_game_attrs:
        return 0, 0, 0, 0
    away_game, home_game = game["away"], game["home"]
    home_rbi, away_rbi = float(away_game["opposing_team_rbi"]), float(home_game["opposing_team_rbi"])
    if away_rbi == home_rbi:
        return 0, 0, 0, 0
    awayPitcher, awayTeam = pitchers.get(away_game["pitcher_id"])
    homePitcher, homeTeam = pitchers.get(home_game["pitcher_id"])
    awayMods, homeMods = mofo.get_mods(mods, game_attrs["away"], game_attrs["home"], away_game["weather"])
    awayodds, _ = mofo.get_mofo(awayPitcher, homePitcher, awayTeam, homeTeam, team_stat_data, pitcher_stat_data, terms,
                                awayMods, homeMods)
    homeodds = 1.0 - awayodds
    if awayodds == .5:
        return 0, 0, awayodds, homeodds
    return 1, 1 if ((awayodds < .5 and away_rbi > home_rbi) or (awayodds > .5 and away_rbi < home_rbi)) else 0, awayodds, homeodds

def handle_args():
    parser = argparse.ArgumentParser()
    parser.add_argument('--statfolder', help="path to stat folder")
    parser.add_argument('--gamefile', help="path to game file")
    parser.add_argument('--mod', help="mod to calculate for")
    parser.add_argument('--debug', help="print output", action='store_true')
    parser.add_argument('--debug2', help="print output", action='store_true')
    parser.add_argument('--debug3', help="print output", action='store_true')
    args = parser.parse_args()
    return args

def main():
    print(datetime.datetime.now())
    cmd_args = handle_args()
    bounds_lol = [modterm.bounds for modterm in MOFO_MOD_TERMS]
    bounds = [item for sublist in bounds_lol for item in sublist]
    stat_file_map = base_solver.get_stat_file_map(cmd_args.statfolder)
    game_list = base_solver.get_games(cmd_args.gamefile)
    with open('team_attrs.json') as f_attrs:
        team_attrs = json.load(f_attrs)
    with open("base_mofo.csv") as f_mofo:
        mofo_base_terms, _ = parse_terms(f_mofo.read(), [])
    args = (get_mofo_mod_results, mofo_base_terms, None, MOFO_MOD_TERMS, stat_file_map, game_list, team_attrs,
            cmd_args.debug, cmd_args.debug2, cmd_args.debug3)
    result = differential_evolution(base_solver.minimize_func, bounds, args=args, popsize=15, tol=0.0001,
                                    mutation=(0.05, 1.99), recombination=0.7, workers=1, maxiter=1000)
    print("\n".join("{},{},{},{},{},{}".format(stat.attr, stat.team, stat.stat,
                                               a, b, c) for stat, (a, b, c) in zip(MOFO_MOD_TERMS, zip(*[iter(result.x)] * 3))))
    result_fail_rate = base_solver.minimize_func(result.x, get_mofo_mod_results, mofo_base_terms, None, MOFO_MOD_TERMS,
                                                 stat_file_map, game_list, team_attrs, cmd_args.mod, False, False,
                                                 False)
    print("Result fail rate: {:.2f}%".format(result_fail_rate*100.0))
    print(datetime.datetime.now())

if __name__ == "__main__":
    main()


import git

# Project Information

project = "Pendulum328 Manual"
copyright = "2022-2023"
author = "AKMJ, SNHU/CETA"

# The full version, including alpha/beta/rc tags

repo = git.Repo(search_parent_directories=True)
release = str(repo.git.describe("--tags", "--always"))

# General Config

extensions = ["sphinx.ext.autosectionlabel"]

# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]

# HTML output options

html_theme = "sphinx_rtd_theme"

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
# html_static_path = ['_static']

# PDF output options

latex_elements = {"extraclassoptions": "openany,oneside"}

latex_logo = "../Media/AJMK_Logo.png"


from pathlib import Path
from typing import Any, Optional

from PIL import Image
import numpy as np

import pytorch_lightning as pl
from pytorch_lightning.callbacks import Callback
from pytorch_lightning.utilities.types import STEP_OUTPUT

from src.visualization.images_grid import ImagesGridVisualizer
from src.models.base import SegmentationModelInterface

class DWTVisualizationCallback(Callback):
    def __init__(self, cfg, vis_frequency, n_vis_images=3, image_size=(960, 600), tile_sep=2, mode=None, save_dir='./vis', **kwargs):
        self._cfg = cfg
        self._mode = mode
        self._save_dir = Path(save_dir).resolve()
        self._save_dir.mkdir(exist_ok=True, parents=True)
        self._freq = vis_frequency
        self._n_vis_images = n_vis_images

        grid_size = 4
        self._visualizer = ImagesGridVisualizer(*image_size, grid_size, tile_sep)

    def _build_vis_image(self, batch:Any, model: SegmentationModelInterface, first_n:bool=False, log_key=None) -> Any:
        if first_n:
            batch = [item[:self._n_vis_images] for item in batch]
        else:
            inds = np.random.choice(range(len(batch[0])), min(self._n_vis_images, len(batch[0])), replace=False)
            batch = [item[inds] for item in batch]

        image, semseg, wngy = batch
        y_hat = model.process(image)

        x = image.byte().cpu().numpy()

        y = semseg.permute(0, 3, 1, 2).mul(255).byte().cpu().numpy()
        pred_masks, pred_energies = y_hat
        pred_masks = pred_masks.mul(255).byte().unsqueeze(1).cpu().numpy()
        pred_energies = pred_energies.div(pred_energies.max()).mul(255).unsqueeze(1).byte().cpu().numpy()
        y_hat = np.concatenate((pred_masks, pred_energies), axis=1)

        images = []
        for x, true_masks, pred_masks in zip(x, y, y_hat):
            images.append(x)
            images.extend(true_masks)
            images.extend(pred_masks)

        self._visualizer.draw(images)
        grid = self._visualizer.get_image()
        if log_key is not None:
            model.logger.experiment.add_image(log_key, grid, self.current_epoch, dataformats='HWC')
        return grid

    def on_train_batch_end(self, trainer: "pl.Trainer", pl_module: SegmentationModelInterface, outputs: STEP_OUTPUT, batch: Any, batch_idx: int, unused: Optional[int] = 0) -> None:
        if batch_idx % self._freq == 0:
            fmt_len = len(str(trainer.max_epochs * trainer.num_training_batches))
            save_fp = self._save_dir / 'train_step_{}.jpg'.format(str(trainer.global_step).zfill(fmt_len))
            pl_module.eval()
            img = self._build_vis_image(batch, pl_module)
            pl_module.train()
            Image.fromarray(img).save(save_fp, 'JPEG')

    def on_validation_batch_end(self, trainer: "pl.Trainer", pl_module: SegmentationModelInterface, outputs: Optional[STEP_OUTPUT], batch: Any, batch_idx: int, dataloader_idx: int) -> None:
        fmt_len = len(str(trainer.max_epochs * trainer.num_training_batches))
        save_fp = self._save_dir / 'val_step_{}_batch_{:03d}.jpg'.format(str(trainer.global_step).zfill(fmt_len), batch_idx)
        img = self._build_vis_image(batch, pl_module)
        Image.fromarray(img).save(save_fp, 'JPEG')

    def on_test_batch_end(self, trainer: "pl.Trainer", pl_module: SegmentationModelInterface, outputs: Optional[STEP_OUTPUT], batch: Any, batch_idx: int, dataloader_idx: int) -> None:
        fmt_len = len(str(trainer.max_epochs * trainer.num_training_batches))
        save_fp = self._save_dir / 'test_step_{}_batch_{:03d}.jpg'.format(str(trainer.global_step).zfill(fmt_len), batch_idx)
        img = self._build_vis_image(batch, pl_module)
        Image.fromarray(img).save(save_fp, 'JPEG')


import labrad
from matplotlib import pyplot
#get access to servers
cxn = labrad.connect()
dv = cxn.data_vault

directory = ['','Experiments','Excitation729','2013Jun28','1844_23']
filename = '00001 - Readout 2013Jun28_1844_23'
#change directory

figure = pyplot.figure()

dv.cd(directory)
dv.open(filename)
data = dv.get().asarray
readout_counts = data[:,1]
n, bins, patches = pyplot.hist(readout_counts, 30, histtype='stepfilled')

pyplot.vlines(20, 0, 1000, color = 'red', linewidth = 5)
pyplot.xlabel( 'Collected Counts', fontsize = 60)
pyplot.ylabel('Occurence', fontsize = 60)
pyplot.tick_params('both', labelsize = 40)
pyplot.show()


import os
import math
from typing import Any

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.ticker import StrMethodFormatter
from scipy.optimize import curve_fit
from sklearn.metrics import mean_squared_error
from sklearn.metrics import r2_score

from pandas import Series, DataFrame

NF = 50  # number of files
NP = 10500  # number of particles
folders = [4,5,9]

#dataframes para salvar dados
desvio_df = pd.DataFrame(columns=["Indice_1","Indice_2", 't'])
#v1 = pd.DataFrame()
#v2 = pd.DataFrame()

# construção das repartições no tambor
nd_x = 5
nd_y = 5

max_x = 0.075
min_x = -0.075
max_y = 0.075
min_y = -0.075
esp_x = (max_x - min_x) / nd_x
esp_y = (max_y - min_y) / nd_y
mse_final = np.zeros(folders)
r_final = np.zeros(folders)
k_final = np.zeros(folders)
isf_final = np.zeros(folders)
blocagens = ['','Mistura Associada','Mistura Concorrente']

#for w in range(1,3,1):
for r in range (0,len(folders),1):
    aux = folders[r]
    for m in range(0, NF):
            home = os.path.expanduser("~")
            path = f"/home/n002/Documents/Pedro_Antonio/sens_taman/{aux}/dados/"
            dados = pd.read_csv(path+f'rot__{m}.csv', sep=",")
            Dados_filter = dados.filter(items=['type', 'Points:0', 'Points:1','radius'])

            #filter by radius of particles
            Dados_filter_r1 = Dados_filter.loc[(Dados_filter.type == 1)]
            Dados_filter_r2 = Dados_filter.loc[(Dados_filter.type == 2)]
            Dados_filter_r1.reset_index(inplace=True, drop=True)
            Dados_filter_r2.reset_index(inplace=True, drop=True)

            #calculate volumn of particles

            v1 = list(4/3*(math.pi*(Dados_filter_r1['radius'])**3))
            v2 = list(4/3*(math.pi*(Dados_filter_r2['radius'])**3))

            Dados_filter_r1['v1'] = v1
            Dados_filter_r2['v2'] = v2
            Dados_filter = pd.merge(Dados_filter_r1, Dados_filter_r2, how='outer')
            Dados_filter = Dados_filter.replace(np.nan, 0)

            #construção do ponteiro para localização
            cd1 = Dados_filter
            cd1['Points:0'] = Dados_filter['Points:0'].div(esp_x).round(0) + 3
            cd1['Points:1'] = Dados_filter['Points:1'].div(esp_y).round(0) + 3
            posicao = -5 + cd1['Points:0'] + 5 * cd1['Points:1']
            cd1 = cd1.assign(posicao=posicao.values)

            # contagem de particulas repetidas em cada posição
            count = cd1.groupby(['type', 'posicao', 'v1','v2']).size().reset_index(name='count')
            count2 = pd.DataFrame(count)
            dftype1 = count2[(count2.type == 1)]
            dftype2 = count2[(count2.type == 2)]
            dftype1.reset_index(inplace=True, drop=True)
            dftype2.reset_index(inplace=True, drop=True)

            #Dataframe de zeros para preenchimento
            count3 = pd.DataFrame(0, columns=['type', 'posicao', 'count'], index=range(25))
            count4 = pd.DataFrame(0, columns=['type', 'posicao', 'count'], index=range(25))
            posicao1 = list(range(1, 26, 1))
            posicao2 = list(range(1, 26, 1))
            count3['posicao'] = posicao1
            count4['posicao'] = posicao2
            count3 = pd.concat([dftype1, count3], axis=0).sort_values(by='posicao', axis=0, ascending=True,
                                                                    kind='stable').drop_duplicates('posicao')
            count4 = pd.concat([dftype2, count4], axis=0).sort_values(by='posicao', axis=0, ascending=True,
                                                                    kind='stable').drop_duplicates('posicao')
            count3 = count3.replace(np.nan, 0)
            count4 = count4.replace(np.nan, 0)
            #cálculo da concentração por tipo de partícula

            total_count_df = pd.merge(count3, count4, on='posicao', how='left')
            total_count = total_count_df['count_x'].add(total_count_df['count_y'], fill_value=0)
            total_count_df['total_count'] = total_count
            total_count_df['concentracao_1'] = (total_count_df['count_x']* total_count_df['v1_x'])/ (total_count_df['count_x']* total_count_df['v1_x']+total_count_df['count_y']* total_count_df['v2_y'])
            total_count_df['concentracao_2'] = (total_count_df['count_y']* total_count_df['v2_y'])/ (total_count_df['count_x']* total_count_df['v1_x']+total_count_df['count_y']* total_count_df['v2_y'])
            total_count_df = total_count_df.replace(np.nan, 0)

            # filtro dos dados de concencetração
            total_count_df_new = total_count_df.drop(total_count_df[total_count_df.total_count < 10].index)

            IS_1 = np.std(total_count_df_new['concentracao_1'], ddof=1)
            IS_2 = np.std(total_count_df_new['concentracao_2'], ddof=1)
            #desvio_df[f'concentracao_1_{m}'] = [IS_1] para adicionar colunas
            #desvio_df[f'concentracao_2_{m}'] = [IS_2] para adicionar colunas
            desvio_df.loc[f'{0}'] = [0.5 , 0.5, 0]
            desvio_df.loc[f'{m+1}'] = [IS_1, IS_2, f'{m+1}']

    print(desvio_df)

    #construção do gráfico
    x = desvio_df['t']
    y = desvio_df['Indice_1']
    z = desvio_df['Indice_2']

    y1 = y.rolling(5).mean()

    plt.plot(x, y, label= f'Simulação {aux}', linewidth=3)
    plt.grid(True, linestyle='--')
    plt.title(f'Razão de Tamanho', color='black', fontsize=20, fontweight='bold')
    plt.xlabel('Tempo (s)', color='black', fontsize=14, fontweight='bold')
    plt.ylabel('IMF ( - )', color='black', fontsize=14, fontweight='bold')
    plt.xticks(np.arange(0, 51, 5))
    plt.yticks(np.arange(0, 0.51, 0.05))
    plt.axhline(y = 0.1, color = 'g', linestyle = ':', linewidth=3)
    plt.axhline(y = 0.2, color = 'r', linestyle = ':', linewidth=3)
    plt.xlim([0, 50])
    plt.ylim([0, 0.51])
    plt.legend(loc = 'upper right')

plt.savefig('/home/n002/Documents/Pedro_Antonio/resultados/graficos_sens_tamanho/'+f'RT.png', dpi=600, bbox_inches='tight', transparent=False, pad_inches=0.1, format='png', orientation='landscape')
#plt.show()
plt.close()


import time

import common
import com_motov3mm as v3mm
import com_motov325 as v325
import prototypes
import p_motov325
import helpids

parentphone=v3mm.Phone
class Phone(parentphone):
    """ Talk to a Motorola V3mM phone"""
    desc='Moto-V325M'
    helpid=helpids.ID_PHONE_MOTOV325M
    protocolclass=p_motov325
    serialsname='motov325m'
    MODEOBEX='modeobex'

    builtinringtones=(
        (0, ('Silent',)),
        (5, ('Vibe Dot', 'Vibe Dash', 'Vibe Dot Dot', 'Vibe Dot Dash',
             'Vibe Pulse')),
        (11, ('Alert', 'Standard', 'Bells', 'Triads', 'Up and Down')),
        (30, ('Moonlit Haze', 'Nightlife', 'Wind Chime', 'Random',
              'Bit & Bytes', 'Door Bell', 'Ding', 'One Moment', 'Provincial',
              'Harmonics', 'Interlude', 'Snaggle', 'Cosmic')),
        )

    def _get_del_new_list(self, index_key, media_key, merge, fundamentals,
                          origins):
        """Return a list of media being deleted and being added"""
        _index=fundamentals.get(index_key, {})
        _media=fundamentals.get(media_key, {})
        _index_file_list=[_entry['name'] for _entry in _index.values() \
                          if _entry.has_key('filename') and \
                          _entry['filename'].startswith(self.protocolclass.MOTO_SHARED_PATH) and \
                          _entry.get('origin', None) in origins ]
        _bp_file_list=[_entry['name'] for _entry in _media.values() \
                       if _entry.get('origin', None) in origins ]
        if merge:
            # just add the new files, don't delete anything
            _del_list=[]
            _new_list=_bp_file_list
        else:
            # Delete specified files and add everything
            _del_list=[x for x in _index_file_list if x not in _bp_file_list]
            _new_list=_bp_file_list
        return _del_list, _new_list

    def _add_files(self, index_key, media_key, media_path,
                   new_list, fundamentals):
        """Add new file using OBEX"""
        _index=fundamentals.get(index_key, {})
        _media=fundamentals.get(media_key, {})
        _adding_ringtones=index_key=='ringtone-index'
        for _file in new_list:
            _data=self._item_from_index(_file, 'data', _media)
            if not _data:
                self.log('Failed to write file %s due to no data'%_file)
                continue
            if self._item_from_index(_file, None, _index) is None:
                # new file
                _name=_file
                if _adding_ringtones and \
                   common.getext(_name).lower()=='mp3':
                    # need to adjust the file name since this model only
                    # accepts qcp and mid files (AFAIK).
                    _name='%s.mid'%common.stripext(_name)
                _file_name='%(pathname)s/%(filename)s'% \
                            { 'pathname': media_path,
                              'filename': _name }
                try:
                    self.obex.writefile(_file_name, _data)
                except:
                    self.log('Failed to write OBEX file '+_file_name)
                    if __debug__:
                        raise

    def getwallpapers(self, fundamentals):
        """Retrieve wallpaper data"""
        # The V325 needs some time to switch from BREW back to MODEM mode
        # without this sleep, the switch will always come back with ERROR
        self.log('Waiting for the phone to switch back to mode modem')
        time.sleep(2)
        self.setmode(self.MODEPHONEBOOK)
        return parentphone.getwallpapers(self, fundamentals)

    def getringtones(self, fundamentals):
        """Retrieve ringtones data"""
        self.log('Waiting for the phone to switch to MODEM')
        time.sleep(2)
        self.setmode(self.MODEPHONEBOOK)
        self.log('Reading ringtones')
        _res={}
        _rt_index=fundamentals.get('ringtone-index', {})
        # This model has ringtone files on both the normal dir (shared/audio)
        # as well as other dirs
        # 1st, get the BREW files
        self.setmode(self.MODEBREW)
        for _entry in _rt_index.values():
            if _entry.has_key('filename') and \
               not _entry['filename'].startswith(self.protocolclass.RT_PATH):
                try:
                    _res[_entry['name']]=self.getfilecontents(_entry['filename'])
                except:
                    self.log('Failed to read media file %s'%_entry['filename'])
        # Now, get the OBEX One
        self.setmode(self.MODEOBEX)
        for _entry in _rt_index.values():
            if _entry.has_key('filename') and \
               _entry['filename'].startswith(self.protocolclass.RT_PATH):
                try:
                    _res[_entry['name']]=self.obex.getfilecontents(
                        self.protocolclass.OBEXName(_entry['filename']))
                except:
                    self.log('Failed to read media file %s'%_entry['filename'])
        fundamentals['ringtone']=_res
        self.setmode(self.MODEMODEM)
        # The phone will need to be reset (unplugged & replug) after this!
        fundamentals['clearcomm']=True
        return fundamentals

    def saveringtones(self, fundamentals, merge):
        """Save ringtones to the phone"""
        self.log('Waiting for the phone to switch back to mode modem')
        time.sleep(2)
        parentphone.saveringtones(self, fundamentals, merge)
        fundamentals['clearcomm']=True
        return fundamentals

    def savewallpapers(self, fundamentals, merge):
        """Save wallpapers to the phone"""
        self.log('Waiting for the phone to switch back to mode modem')
        time.sleep(2)
        self.log('Writing wallpapers to the phone')
        self.setmode(self.MODEBREW)
        try:
            _del_list, _new_list=self._get_del_new_list('wallpaper-index',
                                                        'wallpapers',
                                                        merge,
                                                        fundamentals,
                                                        frozenset(['images']))
            # replace files
            self._replace_files('wallpaper-index', 'wallpapers',
                                _new_list, fundamentals)
        except:
            if __debug__:
                self.setmode(self.MODEMODEM)
                raise
        self.setmode(self.MODEMODEM)
        return fundamentals

#-------------------------------------------------------------------------------
parentprofile=v325.Profile
class Profile(parentprofile):
    serialsname=Phone.serialsname
    phone_model='V325M'
    generic_phone_model='Motorola V325M Phone'

    _supportedsyncs=(
        ('phonebook', 'read', None),  # all phonebook reading
        ('phonebook', 'write', 'OVERWRITE'),  # only overwriting phonebook
        ('calendar', 'read', None),   # all calendar reading
        ('calendar', 'write', 'OVERWRITE'),   # only overwriting calendar
        ('ringtone', 'read', None),   # all ringtone reading
        ('ringtone', 'read', 'EXCLUSIVE'),   # all ringtone reading
        ('ringtone', 'write', 'EXCLUSIVE'),
        ('ringtone', 'write', None),
        ('wallpaper', 'read', None),  # all wallpaper reading
        ('wallpaper', 'write', 'OVERWRITE'),
        ('sms', 'read', None),
        )