Example #1
0
    def _parse(self, value):
        """
        Parse media type string into components
        :attr value: Media type value 
                 e.g. text/html;level=2;q=0.4
        :type value: str, bytes
        :returns: MediaType instance
        """
        full_type, parameters = padded_split(value.strip(), ';', 1)
        full_type = '*/*' if full_type == '*' else full_type

        type, subtype = padded_split(full_type, '/', 1)
        if type is None or subtype is None:
            raise ParseError()

        # type can only be a wildcard with subtype
        if type == '*' and subtype != '*':
            raise ParseError()

        def fix_param(x):
            key, value = padded_split(x, '=', 1)
            if not key or not value:
                raise ParseError()
            if str.isdigit(value):
                value = int(value)
            return (key, value)

        parameters = OrderedDict([ fix_param(param) 
            for param in parameters.split(";") ]) if parameters else {}

        kwargs = dict(type=type, subtype=subtype, parameters=parameters)
        return kwargs
Example #2
0
def ionic_strength(molalities,
                   charges=None,
                   units=None,
                   substances=None,
                   substance_factory=Substance.from_formula,
                   warn=True):
    """ Calculates the ionic strength

    Parameters
    ----------
    molalities: array_like or dict
        Optionally with unit (amount / mass).
        when dict: mapping substance key to molality.
    charges: array_like
        Charge of respective ion, taken for substances when None.
    units: object (optional, default: None)
        Attributes accessed: molal.
    substances: dict, optional
        Mapping of substance keys to Substance instances (used when molalities
        is a dict).
    substance_factory: callback
        Used if `substances` is a string.
    warn: bool
        Issue a warning if molalities violates net charge neutrality.

    Examples
    --------
    >>> ionic_strength([1e-3, 3e-3], [3, -1]) == .5 * (9 + 3) * 1e-3
    True
    >>> ionic_strength({'Mg+2': 6, 'PO4-3': 4})
    30.0

    """
    tot = None
    if charges is None:
        if substances is None:
            substances = ' '.join(molalities.keys())
        if isinstance(substances, str):
            substances = OrderedDict([(k, substance_factory(k))
                                      for k in substances.split()])
        charges, molalities = zip(*[(substances[k].charge, v)
                                    for k, v in molalities.items()])
    if len(molalities) != len(charges):
        raise ValueError("molalities and charges of different lengths")
    for b, z in zip(molalities, charges):
        if tot is None:
            tot = b * z**2
        else:
            tot += b * z**2
    if warn:
        net = None
        for b, z in zip(molalities, charges):
            if net is None:
                net = b * z
            else:
                net += b * z
        if not allclose(net, tot * 0, atol=tot * 1e-14):
            warnings.warn("Molalities not charge neutral: %s" % str(net))
    return tot / 2
Example #3
0
    def __init__(self, word, columns):
        word = OrderedDict(zip(columns, word.split()))
        self.idx = int(word.pop('idx'))
        self.token = word.pop('token')
        self.lemma = word.pop('lemma')
        self.tag = word.pop('tag')

        self._extras = word.copy()
Example #4
0
def ionic_strength(molalities, charges=None, units=None, substances=None,
                   substance_factory=Substance.from_formula, warn=True):
    """ Calculates the ionic strength

    Parameters
    ----------
    molalities: array_like or dict
        Optionally with unit (amount / mass).
        when dict: mapping substance key to molality.
    charges: array_like
        Charge of respective ion, taken for substances when None.
    units: object (optional, default: None)
        Attributes accessed: molal.
    substances: dict, optional
        Mapping of substance keys to Substance instances (used when molalities
        is a dict).
    substance_factory: callback
        Used if `substances` is a string.
    warn: bool
        Issue a warning if molalities violates net charge neutrality.

    Examples
    --------
    >>> ionic_strength([1e-3, 3e-3], [3, -1]) == .5 * (9 + 3) * 1e-3
    True
    >>> ionic_strength({'Mg+2': 6, 'PO4-3': 4})
    30.0

    """
    tot = None
    if charges is None:
        if substances is None:
            substances = ' '.join(molalities.keys())
        if isinstance(substances, str):
            substances = OrderedDict([(k, substance_factory(k)) for k
                                      in substances.split()])
        charges, molalities = zip(*[(substances[k].charge, v) for k, v in molalities.items()])
    if len(molalities) != len(charges):
        raise ValueError("molalities and charges of different lengths")
    for b, z in zip(molalities, charges):
        if tot is None:
            tot = b * z**2
        else:
            tot += b * z**2
    if warn:
        net = None
        for b, z in zip(molalities, charges):
            if net is None:
                net = b * z
            else:
                net += b * z
        if not allclose(net, tot*0, atol=tot*1e-14):
            warnings.warn("Molalities not charge neutral: %s" % str(net))
    return tot/2
Example #5
0
    def _simplify_feature_value(self, name, value):
        """Return simplified and more pythonic feature values."""
        if name == 'prefix':
            channel_modes, channel_chars = value.split(')')
            channel_modes = channel_modes[1:]

            # [::-1] to reverse order and go from lowest to highest privs
            value = OrderedDict(list(zip(channel_modes, channel_chars))[::-1])

            return value

        elif name == 'chanmodes':
            value = value.split(',')
            return value

        elif name == 'targmax':
            max_available = {}
            for sort in value.split(','):
                command, limit = sort.split(':')
                command = command.casefold()
                max_available[command] = limit_to_number(limit)

            return max_available

        elif name == 'chanlimit':
            limit_available = {}
            for sort in value.split(','):
                chan_types, limit = sort.split(':')
                for prefix in chan_types:
                    limit_available[prefix] = limit_to_number(limit)

            return limit_available

        elif name in _limits:
            value = limit_to_number(value)
            return value

        else:
            return value
Example #6
0
def compact_etable_plot(df,
                        title=None,
                        size=2.2,
                        col_wrap=8,
                        xticks=np.arange(0, 7),
                        yticks=np.arange(-2, 3),
                        xlim=(0.0, 6.0),
                        ylim=(-2.5, 2.5),
                        marker='',
                        ms=0,
                        lw=1,
                        aspect=0.7,
                        scores=None):
    if not scores:
        scores = OrderedDict(
            fa_atr='green',
            fa_rep='red',
            fa_sol='blue',
            fa_elec='orange',
            lk_ball_wtd='purple',
            score='black',
        )
    elif isinstance(scores, str):
        colors = 'black red green blue orange purple'.split()
        tmp = OrderedDict()
        for i, k in enumerate(scores.split()):
            tmp[k] = colors[i]
        scores = tmp
    sns.set(style="ticks")
    grid = sns.FacetGrid(df,
                         col='t',
                         size=size,
                         col_wrap=col_wrap,
                         aspect=aspect)
    grid.map(plt.axhline, y=0, ls=":", c='.5')
    for score, col in list(scores.items()):
        grid.map(plt.plot,
                 'dist',
                 score,
                 marker=marker,
                 lw=lw,
                 ms=ms,
                 color=col)
    grid.set(xticks=xticks, yticks=yticks, xlim=xlim, ylim=ylim)
    grid.fig.tight_layout(h_pad=1, w_pad=0)
    if title:
        grid.fig.suptitle(title)
    return grid
Example #7
0
 def get_dropout(self, conv_drop='', blocks=0):
     if conv_drop.startswith('all-'):
         dropout = float(conv_drop.split('-')[1])
         conv_drop = OrderedDict()
         for i in range(1, blocks + 1):
             conv_drop.setdefault(i, dropout)
         return conv_drop
     elif conv_drop.startswith('bet-'):
         import numpy as np
         dropout = conv_drop.split('-')
         dropout = [float(dropout[1]), float(dropout[2])]
         dropout = np.arange(dropout[0], dropout[1],
                             (dropout[1] - dropout[0]) / blocks)
         conv_drop = OrderedDict()
         for i in range(1, blocks + 1):
             conv_drop.setdefault(i, round(dropout[i - 1], 3))
         return conv_drop
Example #8
0
def ionic_strength(molalities,
                   charges=None,
                   b0=1,
                   units=None,
                   substances=None,
                   substance_factory=Substance.from_formula):
    """ Calculates the ionic strength

    Parameters
    ----------
    molalities: array_like or dict
        Optionally with unit (amount / mass).
        when dict: mapping substance key to molality.
    charges: array_like
        Charge of respective ion, taken for substances when None.
    units: object (optional, default: None)
        Attributes accessed: molal.
    substances: dict, optional
        Mapping of substance keys to Substance instances (used when molalities
        is a dict).
    substance_factory: callback
        Used if `substances` is a string.

    Examples
    --------
    >>> ionic_strength([1e-3, 3e-3], [3, -1]) == .5 * (9 + 3) * 1e-3
    True
    >>> ionic_strength({'Mg+2': 6, 'PO4-3': 4})
    30.0

    """
    tot = 0
    if charges is None:
        if substances is None:
            substances = ' '.join(molalities.keys())
        if isinstance(substances, str):
            substances = OrderedDict([(k, substance_factory(k))
                                      for k in substances.split()])
        charges, molalities = zip(*[(substances[k].charge, v)
                                    for k, v in molalities.items()])
    if len(molalities) != len(charges):
        raise ValueError("molalities and charges of different lengths")
    for b, z in zip(molalities, charges):
        tot += b * z**2
    return tot / 2
Example #9
0
def ionic_strength(molalities, charges=None, b0=1, units=None, substances=None,
                   substance_factory=Substance.from_formula):
    """ Calculates the ionic strength

    Parameters
    ----------
    molalities: array_like or dict
        Optionally with unit (amount / mass).
        when dict: mapping substance key to molality.
    charges: array_like
        Charge of respective ion, taken for substances when None.
    units: object (optional, default: None)
        Attributes accessed: molal.
    substances: dict, optional
        Mapping of substance keys to Substance instances (used when molalities
        is a dict).
    substance_factory: callback
        Used if `substances` is a string.

    Examples
    --------
    >>> ionic_strength([1e-3, 3e-3], [3, -1]) == .5 * (9 + 3) * 1e-3
    True
    >>> ionic_strength({'Mg+2': 6, 'PO4-3': 4})
    30.0

    """
    tot = 0
    if charges is None:
        if substances is None:
            substances = ' '.join(molalities.keys())
        if isinstance(substances, str):
            substances = OrderedDict([(k, substance_factory(k)) for k
                                      in substances.split()])
        charges, molalities = zip(*[(substances[k].charge, v) for k, v in molalities.items()])
    if len(molalities) != len(charges):
        raise ValueError("molalities and charges of different lengths")
    for b, z in zip(molalities, charges):
        tot += b * z**2
    return tot/2
Example #10
0
def parse_ascconv(ascconv_str, str_delim='"'):
    '''Parse the 'ASCCONV' format from `input_str`.

    Parameters
    ----------
    ascconv_str : str
        The string we are parsing
    str_delim : str, optional
        String delimiter.  Typically '"' or '""'

    Returns
    -------
    prot_dict : OrderedDict
        Meta data pulled from the ASCCONV section.
    attrs : OrderedDict
        Any attributes stored in the 'ASCCONV BEGIN' line

    Raises
    ------
    AsconvParseError
        A line of the ASCCONV section could not be parsed.
    '''
    attrs, content = ASCCONV_RE.match(ascconv_str).groups()
    attrs = OrderedDict((tuple(x.split('=')) for x in attrs.split()))
    # Normalize string start / end markers to something Python understands
    content = content.replace(str_delim, '"""').replace("\\", "\\\\")
    # Use Python's own parser to parse modified ASCCONV assignments
    tree = ast.parse(content)

    prot_dict = OrderedDict()
    for assign in tree.body:
        atoms = assign2atoms(assign)
        obj_to_index, key = obj_from_atoms(atoms, prot_dict)
        obj_to_index[key] = _get_value(assign)

    return prot_dict, attrs
Example #11
0
class SMParser(object):

    TOKENS = (
        'TITLE', 'SUBTITLE', 'ARTIST',
        'TITLETRANSLIT', 'SUBTITLETRANSLIT',
        'ARTISTTRANSLIT', 'CREDIT', 'BANNER',
        'BACKGROUND', 'LYRICSPATH', 'CDTITLE',
        'MUSIC', 'OFFSET', 'SAMPLESTART',
        'SAMPLELENGTH', 'SELECTABLE', 'DISPLAYBPM',
        'BPMS', 'STOPS', 'BGCHANGES',
    )

    BOM_CHAR = '\xef\xbb\xbf'

    SECTION_HEADER = '//--'

    STYLES = ('dance-single', 'dance-double')
    DIFFICULTIES = ('Easy', 'Medium', 'Hard')
    FOOT_RATINGS = range(1, 11)
    STEP_TYPES = '0123'

    def __init__(self, simfile):
        self.charts = {}
        self._simfile = simfile
        self._parse_header_tokens()
        self._parse_sections()

    def _parse_header_tokens(self):
        for line in StringIO(self._simfile):
            try:
                token, value = (line.strip()
                                .replace(self.BOM_CHAR, '')
                                .split(':')[:2])
            except ValueError:
                continue
            if token[1:] in self.TOKENS:
                setattr(self, token[1:], value.strip(';'))
            if token[1:] == 'BPMS':
                self.BPMS = OrderedDict([measure.split('=') for measure
                                         in self.BPMS.split(',')])
            elif line.startswith(self.SECTION_HEADER):
                break

    def _parse_sections(self):

        def _dos_to_unix(s):
            return s.replace('\r', '')

        parsing = False
        parsing_measure = False
        measure_counter = 1

        for line in StringIO(self._simfile):
            line = _dos_to_unix(line.strip())

            if not parsing and not line.startswith(self.SECTION_HEADER):
                continue

            elif line.startswith(self.SECTION_HEADER):
                # parse section header
                parsing = True
                style = 'Double' if 'double' in line else 'Single'
                self.charts[style] = self.charts.setdefault(style, {})

            elif parsing and ':' in line:
                # Parse #INFO section
                value = line.split(':')[0]
                if value in self.DIFFICULTIES:
                    difficulty = value
                    self.charts[style][difficulty] = {}
                elif value in self.FOOT_RATINGS:
                    self.charts[style][difficulty]['foot rating'] = value
                elif ',' in value:
                    self.charts[style][difficulty]['?'] = value

            elif all((c in self.STEP_TYPES for c in line)) and line != '':
                # parse individual measures
                if parsing_measure:
                    measure['steps'].append(line)
                else:
                    measure = {'measure': measure_counter, 'steps': [line]}
                    parsing_measure = True
                self.charts[style][difficulty]['chart'] = self.charts[style][
                    difficulty].setdefault('chart', [])

            elif line.startswith(',') and parsing_measure:
                # stop parsing measure
                self.charts[style][difficulty]['chart'].append(measure)
                parsing_measure = False
                measure_counter += 1

            elif line.startswith(';') and parsing:
                # stop parsing section
                parsing, parsing_measure = False, False
                measure_counter = 1
Example #12
0
def balance_stoichiometry(reactants, products, substances=None,
                          substance_factory=Substance.from_formula,
                          parametric_symbols=None, underdetermined=True, allow_duplicates=False):
    """ Balances stoichiometric coefficients of a reaction

    Parameters
    ----------
    reactants : iterable of reactant keys
    products : iterable of product keys
    substances : OrderedDict or string or None
        Mapping reactant/product keys to instances of :class:`Substance`.
    substance_factory : callback
    parametric_symbols : generator of symbols
        Used to generate symbols for parametric solution for
        under-determined system of equations. Default is numbered "x-symbols" starting
        from 1.
    underdetermined : bool
        Allows to find a non-unique solution (in addition to a constant factor
        across all terms). Set to ``False`` to disallow (raise ValueError) on
        e.g. "C + O2 -> CO + CO2". Set to ``None`` if you want the symbols replaced
        so that the coefficients are the smallest possible positive (non-zero) integers.
    allow_duplicates : bool
        If False: raises an excpetion if keys appear in both ``reactants`` and ``products``.

    Examples
    --------
    >>> ref = {'C2H2': 2, 'O2': 3}, {'CO': 4, 'H2O': 2}
    >>> balance_stoichiometry({'C2H2', 'O2'}, {'CO', 'H2O'}) == ref
    True
    >>> ref2 = {'H2': 1, 'O2': 1}, {'H2O2': 1}
    >>> balance_stoichiometry('H2 O2'.split(), ['H2O2'], 'H2 O2 H2O2') == ref2
    True
    >>> reac, prod = 'CuSCN KIO3 HCl'.split(), 'CuSO4 KCl HCN ICl H2O'.split()
    >>> Reaction(*balance_stoichiometry(reac, prod)).string()
    '4 CuSCN + 7 KIO3 + 14 HCl -> 4 CuSO4 + 7 KCl + 4 HCN + 7 ICl + 5 H2O'
    >>> balance_stoichiometry({'Fe', 'O2'}, {'FeO', 'Fe2O3'}, underdetermined=False)
    Traceback (most recent call last):
        ...
    ValueError: The system was under-determined
    >>> r, p = balance_stoichiometry({'Fe', 'O2'}, {'FeO', 'Fe2O3'})
    >>> list(set.union(*[v.free_symbols for v in r.values()]))
    [x1]
    >>> b = balance_stoichiometry({'Fe', 'O2'}, {'FeO', 'Fe2O3'}, underdetermined=None)
    >>> b == ({'Fe': 3, 'O2': 2}, {'FeO': 1, 'Fe2O3': 1})
    True
    >>> d = balance_stoichiometry({'C', 'CO'}, {'C', 'CO', 'CO2'}, underdetermined=None, allow_duplicates=True)
    >>> d == ({'CO': 2}, {'C': 1, 'CO2': 1})
    True

    Returns
    -------
    balanced reactants : dict
    balanced products : dict

    """
    import sympy
    from sympy import (
        MutableDenseMatrix, gcd, zeros, linsolve, numbered_symbols, Wild, Symbol,
        Integer, Tuple, preorder_traversal as pre
    )

    _intersect = sorted(set.intersection(*map(set, (reactants, products))))
    if _intersect:
        if allow_duplicates:
            if underdetermined is not None:
                raise NotImplementedError("allow_duplicates currently requires underdetermined=None")
            if set(reactants) == set(products):
                raise ValueError("cannot balance: reactants and products identical")

            # For each duplicate, try to drop it completely:
            for dupl in _intersect:
                try:
                    result = balance_stoichiometry(
                        [sp for sp in reactants if sp != dupl],
                        [sp for sp in products if sp != dupl],
                        substances=substances, substance_factory=substance_factory,
                        underdetermined=underdetermined, allow_duplicates=True)
                except Exception:
                    continue
                else:
                    return result
            for perm in product(*[(False, True)]*len(_intersect)):  # brute force (naive)
                r = set(reactants)
                p = set(products)
                for remove_reac, dupl in zip(perm, _intersect):
                    if remove_reac:
                        r.remove(dupl)
                    else:
                        p.remove(dupl)
                try:
                    result = balance_stoichiometry(
                        r, p, substances=substances, substance_factory=substance_factory,
                        parametric_symbols=parametric_symbols, underdetermined=underdetermined,
                        allow_duplicates=False)
                except ValueError:
                    continue
                else:
                    return result
            else:
                raise ValueError("Failed to remove duplicate keys: %s" % _intersect)
        else:
            raise ValueError("Substances on both sides: %s" % str(_intersect))
    if substances is None:
        substances = OrderedDict([(k, substance_factory(k)) for k in chain(reactants, products)])
    if isinstance(substances, str):
        substances = OrderedDict([(k, substance_factory(k)) for k in substances.split()])
    if type(reactants) == set:  # we don't want isinstance since it might be "OrderedSet"
        reactants = sorted(reactants)
    if type(products) == set:
        products = sorted(products)
    subst_keys = list(reactants) + list(products)

    cks = Substance.composition_keys(substances.values())

    if parametric_symbols is None:
        parametric_symbols = numbered_symbols('x', start=1, integer=True, positive=True)

    # ?C2H2 + ?O2 -> ?CO + ?H2O
    # Ax = 0
    #   A:                    x:
    #
    #   C2H2   O2  CO  H2O
    # C -2     0    1   0      x0    =   0
    # H -2     0    0   2      x1        0
    # O  0    -2    1   1      x2        0
    #                          x3

    def _get(ck, sk):
        return substances[sk].composition.get(ck, 0) * (-1 if sk in reactants else 1)

    for ck in cks:  # check that all components are present on reactant & product sides
        for rk in reactants:
            if substances[rk].composition.get(ck, 0) != 0:
                break
        else:
            any_pos = any(substances[pk].composition.get(ck, 0) > 0 for pk in products)
            any_neg = any(substances[pk].composition.get(ck, 0) < 0 for pk in products)
            if any_pos and any_neg:
                pass  # negative and positive parts among products, no worries
            else:
                raise ValueError("Component '%s' not among reactants" % ck)

        for pk in products:
            if substances[pk].composition.get(ck, 0) != 0:
                break
        else:
            any_pos = any(substances[pk].composition.get(ck, 0) > 0 for pk in reactants)
            any_neg = any(substances[pk].composition.get(ck, 0) < 0 for pk in reactants)
            if any_pos and any_neg:
                pass  # negative and positive parts among reactants, no worries
            else:
                raise ValueError("Component '%s' not among products" % ck)

    A = MutableDenseMatrix([[_get(ck, sk) for sk in subst_keys] for ck in cks])
    symbs = list(reversed([next(parametric_symbols) for _ in range(len(subst_keys))]))
    sol, = linsolve((A, zeros(len(cks), 1)), symbs)
    wi = Wild('wi', properties=[lambda k: not k.has(Symbol)])
    cd = reduce(gcd, [1] + [1/m[wi] for m in map(
        lambda n: n.match(symbs[-1]/wi), pre(sol)) if m is not None])
    sol = sol.func(*[arg/cd for arg in sol.args])

    def remove(cont, symb, remaining):
        subsd = dict(zip(remaining/symb, remaining))
        cont = cont.func(*[(arg/symb).expand().subs(subsd) for arg in cont.args])
        if cont.has(symb):
            raise ValueError("Bug, please report an issue at https://github.com/bjodah/chempy")
        return cont

    done = False
    for idx, symb in enumerate(symbs):
        for expr in sol:
            iterable = expr.args if expr.is_Add else [expr]
            for term in iterable:
                if term.is_number:
                    done = True
                    break
            if done:
                break
        if done:
            break
        for expr in sol:
            if (expr/symb).is_number:
                sol = remove(sol, symb, MutableDenseMatrix(symbs[idx+1:]))
                break
    for symb in symbs:
        cd = 1
        for expr in sol:
            iterable = expr.args if expr.is_Add else [expr]
            for term in iterable:
                if term.is_Mul and term.args[0].is_number and term.args[1] == symb:
                    cd = gcd(cd, term.args[0])
        if cd != 1:
            sol = sol.func(*[arg.subs(symb, symb/cd) for arg in sol.args])
    integer_one = 1  # need 'is' check, SyntaxWarning when checking against literal
    if underdetermined is integer_one:
        from ._release import __version__
        if int(__version__.split('.')[1]) > 6:
            warnings.warn(  # deprecated because comparison with ``1`` problematic (True==1)
                ("Pass underdetermined == None instead of ``1`` (depreacted since 0.7.0,"
                 " will_be_missing_in='0.9.0')"), ChemPyDeprecationWarning)
        underdetermined = None
    if underdetermined is None:
        sol = Tuple(*[Integer(x) for x in _solve_balancing_ilp_pulp(A)])

    fact = gcd(sol)
    sol = MutableDenseMatrix([e/fact for e in sol]).reshape(len(sol), 1)
    sol /= reduce(gcd, sol)
    if 0 in sol:
        raise ValueError("Superfluous species given.")
    if underdetermined:
        if any(x == sympy.nan for x in sol):
            raise ValueError("Failed to balance reaction")
    else:
        for x in sol:
            if len(x.free_symbols) != 0:
                raise ValueError("The system was under-determined")
        if not all(residual == 0 for residual in A * sol):
            raise ValueError("Failed to balance reaction")

    def _x(k):
        coeff = sol[subst_keys.index(k)]
        return int(coeff) if underdetermined is None else coeff

    return (
        OrderedDict([(k, _x(k)) for k in reactants]),
        OrderedDict([(k, _x(k)) for k in products])
    )
Example #13
0
def gdx_to_df(gdx_file, symbol, type='L', domain_info=None):
    def __get_set(gdx_file, set_name):
        if sys.platform in ['linux2', 'darwin']:
            proc = subprocess.Popen(['gdxdump %s Symb=%s Format=csv NoHeader' % (gdx_file, set_name), ""],
                                    stdout=subprocess.PIPE, shell=True,
                                    stderr=subprocess.STDOUT)
        elif sys.platform in ['win32']:
            proc = subprocess.Popen(['gdxdump', '%s' % gdx_file, 'Symb=%s' % set_name, 'Format=csv', 'NoHeader', ''],
                                    stdout=subprocess.PIPE, shell=True,
                                    stderr=subprocess.STDOUT)
        else:
            raise GamsAddOnException('ERROR {platform} not handled'.format(platform=sys.platform))
        (out, err) = proc.communicate()
        try:
            csv_in = csv.reader(out.split('\n'), delimiter=',')
            return [int(row[0]) for row in csv_in if row]
        except ValueError:
            csv_in = csv.reader(out.split('\n'), delimiter=',')
            return [row[0] for row in csv_in if row]

    def __int(v):
        try:
            return int(v)
        except ValueError:
            return v

    def __float(v):
        try:
            return float(v)
        except ValueError:
            return v

    if domain_info is None:
        domain_info = DomainInfo(gdx_file)
    if symbol not in domain_info.symbols:
        raise GamsAddOnException('"%s" not in Domain of "%s"' % (symbol, gdx_file))

    sets = domain_info.get_sets(symbol)
    index = OrderedDict()
    if sets is None:
        index['Idx'] = [1]
        sets = ['Idx']
    else:
        for s in sets:
            if s in domain_info.symbols:
                set_values = __get_set(gdx_file, s)
                set_name = s
                while set_name in index.keys():
                    set_name = set_name + s
                index[set_name] = set_values
            elif s == '*':
                index[s] = ['---PLACEHOLDER---']
            else:
                raise GamsAddOnException('Set "%s" of "%s" not in Domain of "%s"' % (s, symbol, gdx_file))

    # print index.values()+[['l', 'm']]

    if domain_info.symbols[symbol][0] in ['Var', 'Equ']:
        multi_index = MultiIndex.from_product([index[s] for s in sets] + [['L', 'M', 'LO', 'UP', 'SCALE']])
        df = DataFrame(0.0, index=multi_index, columns=[symbol])
        df.index.names = index.keys() + ['Type']
    else:
        multi_index = MultiIndex.from_product([index[s] for s in index.keys()])
        df = DataFrame(0.0, index=multi_index, columns=[symbol])
        df.index.names = index.keys()
    if sys.platform in ['linux2', 'darwin']:
        proc = subprocess.Popen(['gdxdump %s Symb=%s FilterDef=N' % (gdx_file, symbol), ""],
                                stdout=subprocess.PIPE, shell=True,
                                stderr=subprocess.STDOUT)
    elif sys.platform in ['win32']:
        proc = subprocess.Popen(['gdxdump', '%s' % gdx_file, 'Symb=%s' % symbol, 'FilterDef=N', ''],
                                stdout=subprocess.PIPE, shell=True,
                                stderr=subprocess.STDOUT)
    else:
        raise GamsAddOnException('ERROR {platform} not handled'.format(platform=sys.platform))
    (out, err) = proc.communicate()
    out = out.replace('\n', '')
    content = re.search(r'/.*/', out).group(0)[1:-1].replace('\'', '').strip().split(',')

    if err:
        raise GamsAddOnException('ERROR: {err}'.format(err=err))
    elif content is []:
        raise GamsAddOnException('ERROR: No content found for {symbol}'.format(symbol=symbol))
    else:
        indices = []
        values = []
        if domain_info.symbols[symbol][0] in ['Set']:
            df[symbol] = False
            for data in content:
                if '.' in data:
                    indices.append(tuple([__int(d) for d in data.strip().split('.')]))
                else:
                    indices.append(__int(data.strip()))
                values.append(True)
        else:
            for data in content:
                data = data.strip().split(' ')
                if len(data) == 1:
                    indices.append(1)
                    values.append(__float(data[0]))
                else:
                    index = data[0]
                    if '.' in index:
                        index = tuple([__int(i) for i in index.split('.')])
                        indices.append(index)
                    elif index in ['L', 'M', 'UP', 'LO', 'SCALE']:
                        index = (1, index)
                        indices.append(index)
                    else:
                        indices.append(__int(index))
                    values.append(__float(data[1]))
        try:
            # print 'NAME:', symbol, indices, values, len(values), df
            if len(values) == 1 and values[0] == '':
                return df
            else:
                # df.loc[indices, symbol] = values
                # print df.index
                df.loc[indices, symbol] = values
                # for i,idx in enumerate(indices):
                #     df.loc[idx, symbol] = values[i]
        except KeyError as ke:
            print 'Warning', ke
            if '*' in df.index.names:
                for i, idx in enumerate(indices):
                    df.loc[idx, symbol] = True
                df.drop('---PLACEHOLDER---', inplace=True)

        if type is not None and 'Type' in df.index.names:
            # print type
            # print df.head()
            return df.query('Type == "%s"' % type)
        else:
            return df
Example #14
0
class SMParser(object):

    TOKENS = (
        'TITLE',
        'SUBTITLE',
        'ARTIST',
        'TITLETRANSLIT',
        'SUBTITLETRANSLIT',
        'ARTISTTRANSLIT',
        'CREDIT',
        'BANNER',
        'BACKGROUND',
        'LYRICSPATH',
        'CDTITLE',
        'MUSIC',
        'OFFSET',
        'SAMPLESTART',
        'SAMPLELENGTH',
        'SELECTABLE',
        'DISPLAYBPM',
        'BPMS',
        'STOPS',
        'BGCHANGES',
    )

    BOM_CHAR = '\xef\xbb\xbf'

    SECTION_HEADER = '//--'

    STYLES = ('dance-single', 'dance-double')
    DIFFICULTIES = ('Easy', 'Medium', 'Hard')
    FOOT_RATINGS = range(1, 11)
    STEP_TYPES = '0123'

    def __init__(self, simfile):
        self.charts = {}
        self._simfile = simfile
        self._parse_header_tokens()
        self._parse_sections()

    def _parse_header_tokens(self):
        for line in StringIO(self._simfile):
            try:
                token, value = (line.strip().replace(self.BOM_CHAR,
                                                     '').split(':')[:2])
            except ValueError:
                continue
            if token[1:] in self.TOKENS:
                setattr(self, token[1:], value.strip(';'))
            if token[1:] == 'BPMS':
                self.BPMS = OrderedDict(
                    [measure.split('=') for measure in self.BPMS.split(',')])
            elif line.startswith(self.SECTION_HEADER):
                break

    def _parse_sections(self):
        def _dos_to_unix(s):
            return s.replace('\r', '')

        parsing = False
        parsing_measure = False
        measure_counter = 1

        for line in StringIO(self._simfile):
            line = _dos_to_unix(line.strip())

            if not parsing and not line.startswith(self.SECTION_HEADER):
                continue

            elif line.startswith(self.SECTION_HEADER):
                # parse section header
                parsing = True
                style = 'Double' if 'double' in line else 'Single'
                self.charts[style] = self.charts.setdefault(style, {})

            elif parsing and ':' in line:
                # Parse #INFO section
                value = line.split(':')[0]
                if value in self.DIFFICULTIES:
                    difficulty = value
                    self.charts[style][difficulty] = {}
                elif value in self.FOOT_RATINGS:
                    self.charts[style][difficulty]['foot rating'] = value
                elif ',' in value:
                    self.charts[style][difficulty]['?'] = value

            elif all((c in self.STEP_TYPES for c in line)) and line != '':
                # parse individual measures
                if parsing_measure:
                    measure['steps'].append(line)
                else:
                    measure = {'measure': measure_counter, 'steps': [line]}
                    parsing_measure = True
                self.charts[style][difficulty]['chart'] = self.charts[style][
                    difficulty].setdefault('chart', [])

            elif line.startswith(',') and parsing_measure:
                # stop parsing measure
                self.charts[style][difficulty]['chart'].append(measure)
                parsing_measure = False
                measure_counter += 1

            elif line.startswith(';') and parsing:
                # stop parsing section
                parsing, parsing_measure = False, False
                measure_counter = 1
Example #15
0
def varsplit(ref, alts, info, frmt, gts):
    """
    Split a variant with multiple alternate alleles into separate records to aid
    in annotation.

    >>> n = varsplit('TA', ['TAA', 'TAAA', 'T'], 'AF=0.2,0.3,0.1;KKKK',
    ...              'GT:DP:PL', ['1/2:81:281,5,9,58,0,115,338,46,116,809',
    ...              '0/0:86:0,30,323,31,365,483,38,291,325,567'])
    >>> next(n)
    ('TA', 'TAA', 'KKKK;ORIG_ALLELES=TA/TAA,TAAA,T;ORIG_ALLELE_i=1', 'GT:PL', ['1/.:281,5,9', '0/0:0,30,323'])

    >>> next(n)
    ('TA', 'TAAA', 'KKKK;ORIG_ALLELES=TA/TAA,TAAA,T;ORIG_ALLELE_i=2', 'GT:PL', ['./1:281,58,115', '0/0:0,31,483'])

    >>> next(n)
    ('TA', 'T', 'KKKK;ORIG_ALLELES=TA/TAA,TAAA,T;ORIG_ALLELE_i=3', 'GT:PL', ['./.:281,338,809', '0/0:0,38,567'])


    # test new snp eff ANN= field
    >>> n = varsplit('G', ['A', 'C', 'T'],
    ...              'ANN=A|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.||||||,A|.|.|.|.|.|.|.|.|.||||||,A|.|.|.|.|.|.|.|.|.||||||,A|.|.|.|.|.|.|.|.|.||||||,A|.|.|.|.|.|.|.|.|.||||||,A|.|.|.|.|.|.|.|.|.||||||,A|.|.|.|.|.|.|.|.|.||||||,A|.|.|.|.|.|.|.|.|.||||||,A|.|.|.|.|.|.|.|.|.||||||,A|.|.|.|.|.|.|.|.|.||||||,A|.|.|.|.|.|.|.|.|.||||||,C|.|.|.|.|.|.|.|.|.||||||,C|.|.|.|.|.|.|.|.|.||||||,C|.|.|.|.|.|.|.|.|.||||||,C|.|.|.|.|.|.|.|.|.||||||,C|.|.|.|.|.|.|.|.|.||||||,C|.|.|.|.|.|.|.|.|.||||||,C|.|.|.|.|.|.|.|.|.||||||,C|.|.|.|.|.|.|.|.|.||||||,C|.|.|.|.|.|.|.|.|.||||||,C|.|.|.|.|.|.|.|.|.||||||,C|.|.|.|.|.|.|.|.|.||||||,T|.|.|.|.|.|.|.|.|.||||||,T|.|.|.|.|.|.|.|.|.||||||,T|.|.|.|.|.|.|.|.|.||||||,T|.|.|.|.|.|.|.|.|.||||||,T|.|.|.|.|.|.|.|.|.||||||,T|.|.|.|.|.|.|.|.|.||||||,T|.|.|.|.|.|.|.|.|.||||||,T|.|.|.|.|.|.|.|.|.||||||,T|.|.|.|.|.|.|.|.|.||||||,T|.|.|.|.|.|.|.|.|.||||||,T|.|.|.|.|.|.|.|.|.|||||||', 
    ...              'GT:DP:PL', ['1/2:81:281,5,9,58,0,115,338,46,116,809'])

    >>> next(n)
    ('G', 'A', 'ANN=A|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.||||||,A|.|.|.|.|.|.|.|.|.||||||,A|.|.|.|.|.|.|.|.|.||||||,A|.|.|.|.|.|.|.|.|.||||||,A|.|.|.|.|.|.|.|.|.||||||,A|.|.|.|.|.|.|.|.|.||||||,A|.|.|.|.|.|.|.|.|.||||||,A|.|.|.|.|.|.|.|.|.||||||,A|.|.|.|.|.|.|.|.|.||||||,A|.|.|.|.|.|.|.|.|.||||||,A|.|.|.|.|.|.|.|.|.||||||;ORIG_ALLELES=G/A,C,T;ORIG_ALLELE_i=1', 'GT:PL', ['1/.:281,5,9'])

    >>> next(n)
    ('G', 'C', 'ANN=C|.|.|.|.|.|.|.|.|.||||||,C|.|.|.|.|.|.|.|.|.||||||,C|.|.|.|.|.|.|.|.|.||||||,C|.|.|.|.|.|.|.|.|.||||||,C|.|.|.|.|.|.|.|.|.||||||,C|.|.|.|.|.|.|.|.|.||||||,C|.|.|.|.|.|.|.|.|.||||||,C|.|.|.|.|.|.|.|.|.||||||,C|.|.|.|.|.|.|.|.|.||||||,C|.|.|.|.|.|.|.|.|.||||||,C|.|.|.|.|.|.|.|.|.||||||;ORIG_ALLELES=G/A,C,T;ORIG_ALLELE_i=2', 'GT:PL', ['./1:281,58,115'])

    >>> next(n)
    ('G', 'T', 'ANN=T|.|.|.|.|.|.|.|.|.||||||,T|.|.|.|.|.|.|.|.|.||||||,T|.|.|.|.|.|.|.|.|.||||||,T|.|.|.|.|.|.|.|.|.||||||,T|.|.|.|.|.|.|.|.|.||||||,T|.|.|.|.|.|.|.|.|.||||||,T|.|.|.|.|.|.|.|.|.||||||,T|.|.|.|.|.|.|.|.|.||||||,T|.|.|.|.|.|.|.|.|.||||||,T|.|.|.|.|.|.|.|.|.||||||,T|.|.|.|.|.|.|.|.|.|||||||;ORIG_ALLELES=G/A,C,T;ORIG_ALLELE_i=3', 'GT:PL', ['./.:281,338,809'])

    >>> next(n)
    Traceback (most recent call last):
    ...
    StopIteration

    # test older snpeff EFF= field
    >>> n = varsplit('TTCC', ['T', 'TTCCTCC'], 'EFF=CODON_CHANGE_PLUS_CODON_DELETION(MODERATE||gaggaa/gaa|EE28E|196|MICAL3|protein_coding|CODING|ENST00000498573|1|1|WARNING_TRANSCRIPT_NO_START_CODON),CODON_CHANGE_PLUS_CODON_DELETION(MODERATE||gaggaa/gaa|EE4E|188|MICAL3|protein_coding|CODING|ENST00000578984|1|1|WARNING_TRANSCRIPT_INCOMPLETE),CODON_CHANGE_PLUS_CODON_DELETION(MODERATE||gaggaa/gaa|EE998E|2002|MICAL3|protein_coding|CODING|ENST00000441493|21|1),CODON_INSERTION(MODERATE||gag/gaGGAg|E28EE|196|MICAL3|protein_coding|CODING|ENST00000498573|1|2|WARNING_TRANSCRIPT_NO_START_CODON),CODON_INSERTION(MODERATE||gag/gaGGAg|E4EE|188|MICAL3|protein_coding|CODING|ENST00000578984|1|2|WARNING_TRANSCRIPT_INCOMPLETE),CODON_INSERTION(MODERATE||gag/gaGGAg|E998EE|2002|MICAL3|protein_coding|CODING|ENST00000441493|21|2),DOWNSTREAM(MODIFIER||2412||966|MICAL3|protein_coding|CODING|ENST00000400561||2),DOWNSTREAM(MODIFIER||2415||966|MICAL3|protein_coding|CODING|ENST00000400561||1),DOWNSTREAM(MODIFIER||2422||966|MICAL3|protein_coding|CODING|ENST00000444520||2),DOWNSTREAM(MODIFIER||2425||966|MICAL3|protein_coding|CODING|ENST00000444520||1)', 'GT:DP:PL', ['1/2:81:281,5,9,58,0,115,338'])
    >>> next(n)
    ('TTCC', 'T', 'EFF=CODON_CHANGE_PLUS_CODON_DELETION(MODERATE||gaggaa/gaa|EE28E|196|MICAL3|protein_coding|CODING|ENST00000498573|1|1|WARNING_TRANSCRIPT_NO_START_CODON),CODON_CHANGE_PLUS_CODON_DELETION(MODERATE||gaggaa/gaa|EE4E|188|MICAL3|protein_coding|CODING|ENST00000578984|1|1|WARNING_TRANSCRIPT_INCOMPLETE),CODON_CHANGE_PLUS_CODON_DELETION(MODERATE||gaggaa/gaa|EE998E|2002|MICAL3|protein_coding|CODING|ENST00000441493|21|1),DOWNSTREAM(MODIFIER||2415||966|MICAL3|protein_coding|CODING|ENST00000400561||1),DOWNSTREAM(MODIFIER||2425||966|MICAL3|protein_coding|CODING|ENST00000444520||1);ORIG_ALLELES=TTCC/T,TTCCTCC;ORIG_ALLELE_i=1', 'GT:PL', ['1/.:281,5,9'])

    >>> next(n)
    ('TTCC', 'TTCCTCC', 'EFF=CODON_INSERTION(MODERATE||gag/gaGGAg|E28EE|196|MICAL3|protein_coding|CODING|ENST00000498573|1|2|WARNING_TRANSCRIPT_NO_START_CODON),CODON_INSERTION(MODERATE||gag/gaGGAg|E4EE|188|MICAL3|protein_coding|CODING|ENST00000578984|1|2|WARNING_TRANSCRIPT_INCOMPLETE),CODON_INSERTION(MODERATE||gag/gaGGAg|E998EE|2002|MICAL3|protein_coding|CODING|ENST00000441493|21|2),DOWNSTREAM(MODIFIER||2412||966|MICAL3|protein_coding|CODING|ENST00000400561||2),DOWNSTREAM(MODIFIER||2422||966|MICAL3|protein_coding|CODING|ENST00000444520||2);ORIG_ALLELES=TTCC/T,TTCCTCC;ORIG_ALLELE_i=2', 'GT:PL', ['./1:281,58,115'])

    >>> next(n)
    Traceback (most recent call last):
    ...
    StopIteration


    """
    if len(alts) == 1:
        yield ref, alts[0], infostr(info, ()), frmt, gts
        raise StopIteration

    if not isinstance(info, dict):
        info = OrderedDict((kv[0], (kv[1] if len(kv) > 1 else None))
                           for kv in (x.split('=') for x in info.split(';')))

    fmts = frmt.split(':')
    gts = [OrderedDict(zip(fmts, x.split(':'))) for x in gts]

    for i, g in enumerate(gts):
        if 'GT' in g:
            gts[i]['__sep'] = "|" if "|" in g['GT'] else "/"
            gts[i]['GT'] = g['GT'].split(gts[i]['__sep'])

    for i, alt in enumerate(alts, start=1):
        if any('GT' in g for g in gts):
            fixed_genos = fix_genos(gts, i)
        else:
            fixed_genos = gts
        if fixed_genos:
            fields = [f for f in fixed_genos[0].keys()
                      if f != "__sep"]  # ordered
        else:
            fields = []
        info_sub = fix_info(info, alt, alts)
        # now we temporarily replace info[field] with ann

        info_sub['ORIG_ALLELES'] = '%s/%s' % (ref, ",".join(alts))
        info_sub['ORIG_ALLELE_i'] = str(i)
        ret = ref, alt, infostr(info_sub), ":".join(fields), fmt_genos(
            fixed_genos)
        yield ret
Example #16
0
def balance_stoichiometry(reactants, products, substances=None,
                          substance_factory=Substance.from_formula,
                          parametric_symbols=None, underdetermined=True, allow_duplicates=False):
    """ Balances stoichiometric coefficients of a reaction

    Parameters
    ----------
    reactants : iterable of reactant keys
    products : iterable of product keys
    substances : OrderedDict or string or None
        Mapping reactant/product keys to instances of :class:`Substance`.
    substance_factory : callback
    parametric_symbols : generator of symbols
        Used to generate symbols for parametric solution for
        under-determined system of equations. Default is numbered "x-symbols" starting
        from 1.
    underdetermined : bool
        Allows to find a non-unique solution (in addition to a constant factor
        across all terms). Set to ``False`` to disallow (raise ValueError) on
        e.g. "C + O2 -> CO + CO2". Set to ``None`` if you want the symbols replaced
        so that the coefficients are the smallest possible positive (non-zero) integers.
    allow_duplicates : bool
        If False: raises an excpetion if keys appear in both ``reactants`` and ``products``.

    Examples
    --------
    >>> ref = {'C2H2': 2, 'O2': 3}, {'CO': 4, 'H2O': 2}
    >>> balance_stoichiometry({'C2H2', 'O2'}, {'CO', 'H2O'}) == ref
    True
    >>> ref2 = {'H2': 1, 'O2': 1}, {'H2O2': 1}
    >>> balance_stoichiometry('H2 O2'.split(), ['H2O2'], 'H2 O2 H2O2') == ref2
    True
    >>> reac, prod = 'CuSCN KIO3 HCl'.split(), 'CuSO4 KCl HCN ICl H2O'.split()
    >>> Reaction(*balance_stoichiometry(reac, prod)).string()
    '4 CuSCN + 7 KIO3 + 14 HCl -> 4 CuSO4 + 7 KCl + 4 HCN + 7 ICl + 5 H2O'
    >>> balance_stoichiometry({'Fe', 'O2'}, {'FeO', 'Fe2O3'}, underdetermined=False)
    Traceback (most recent call last):
        ...
    ValueError: The system was under-determined
    >>> r, p = balance_stoichiometry({'Fe', 'O2'}, {'FeO', 'Fe2O3'})
    >>> list(set.union(*[v.free_symbols for v in r.values()]))
    [x1]
    >>> b = balance_stoichiometry({'Fe', 'O2'}, {'FeO', 'Fe2O3'}, underdetermined=None)
    >>> b == ({'Fe': 3, 'O2': 2}, {'FeO': 1, 'Fe2O3': 1})
    True
    >>> d = balance_stoichiometry({'C', 'CO'}, {'C', 'CO', 'CO2'}, underdetermined=None, allow_duplicates=True)
    >>> d == ({'CO': 2}, {'C': 1, 'CO2': 1})
    True

    Returns
    -------
    balanced reactants : dict
    balanced products : dict

    """
    import sympy
    from sympy import (
        MutableDenseMatrix, gcd, zeros, linsolve, numbered_symbols, Wild, Symbol,
        Integer, Tuple, preorder_traversal as pre
    )

    _intersect = sorted(set.intersection(*map(set, (reactants, products))))
    if _intersect:
        if allow_duplicates:
            if underdetermined is not None:
                raise NotImplementedError("allow_duplicates currently requires underdetermined=None")
            if set(reactants) == set(products):
                raise ValueError("cannot balance: reactants and products identical")

            # For each duplicate, try to drop it completely:
            for dupl in _intersect:
                try:
                    result = balance_stoichiometry(
                        [sp for sp in reactants if sp != dupl],
                        [sp for sp in products if sp != dupl],
                        substances=substances, substance_factory=substance_factory,
                        underdetermined=underdetermined, allow_duplicates=True)
                except Exception:
                    continue
                else:
                    return result
            for perm in product(*[(False, True)]*len(_intersect)):  # brute force (naive)
                r = set(reactants)
                p = set(products)
                for remove_reac, dupl in zip(perm, _intersect):
                    if remove_reac:
                        r.remove(dupl)
                    else:
                        p.remove(dupl)
                try:
                    result = balance_stoichiometry(
                        r, p, substances=substances, substance_factory=substance_factory,
                        parametric_symbols=parametric_symbols, underdetermined=underdetermined,
                        allow_duplicates=False)
                except Exception:
                    continue
                else:
                    return result
            else:
                raise ValueError("Failed to remove duplicate keys: %s" % _intersect)
        else:
            raise ValueError("Substances on both sides: %s" % str(_intersect))
    if substances is None:
        substances = OrderedDict([(k, substance_factory(k)) for k in chain(reactants, products)])
    if isinstance(substances, str):
        substances = OrderedDict([(k, substance_factory(k)) for k in substances.split()])
    if type(reactants) == set:  # we don't want isinstance since it might be "OrderedSet"
        reactants = sorted(reactants)
    if type(products) == set:
        products = sorted(products)
    subst_keys = list(reactants) + list(products)

    cks = Substance.composition_keys(substances.values())

    if parametric_symbols is None:
        parametric_symbols = numbered_symbols('x', start=1, integer=True, positive=True)

    # ?C2H2 + ?O2 -> ?CO + ?H2O
    # Ax = 0
    #   A:                    x:
    #
    #   C2H2   O2  CO  H2O
    # C -2     0    1   0      x0    =   0
    # H -2     0    0   2      x1        0
    # O  0    -2    1   1      x2        0
    #                          x3

    def _get(ck, sk):
        return substances[sk].composition.get(ck, 0) * (-1 if sk in reactants else 1)

    for ck in cks:  # check that all components are present on reactant & product sides
        for rk in reactants:
            if substances[rk].composition.get(ck, 0) != 0:
                break
        else:
            raise ValueError("Component '%s' not among reactants" % ck)
        for pk in products:
            if substances[pk].composition.get(ck, 0) != 0:
                break
        else:
            raise ValueError("Component '%s' not among products" % ck)

    A = MutableDenseMatrix([[_get(ck, sk) for sk in subst_keys] for ck in cks])
    symbs = list(reversed([next(parametric_symbols) for _ in range(len(subst_keys))]))
    sol, = linsolve((A, zeros(len(cks), 1)), symbs)
    wi = Wild('wi', properties=[lambda k: not k.has(Symbol)])
    cd = reduce(gcd, [1] + [1/m[wi] for m in map(
        lambda n: n.match(symbs[-1]/wi), pre(sol)) if m is not None])
    sol = sol.func(*[arg/cd for arg in sol.args])

    def remove(cont, symb, remaining):
        subsd = dict(zip(remaining/symb, remaining))
        cont = cont.func(*[(arg/symb).expand().subs(subsd) for arg in cont.args])
        if cont.has(symb):
            raise ValueError("Bug, please report an issue at https://github.com/bjodah/chempy")
        return cont

    done = False
    for idx, symb in enumerate(symbs):
        for expr in sol:
            iterable = expr.args if expr.is_Add else [expr]
            for term in iterable:
                if term.is_number:
                    done = True
                    break
            if done:
                break
        if done:
            break
        for expr in sol:
            if (expr/symb).is_number:
                sol = remove(sol, symb, MutableDenseMatrix(symbs[idx+1:]))
                break
    for symb in symbs:
        cd = 1
        for expr in sol:
            iterable = expr.args if expr.is_Add else [expr]
            for term in iterable:
                if term.is_Mul and term.args[0].is_number and term.args[1] == symb:
                    cd = gcd(cd, term.args[0])
        if cd != 1:
            sol = sol.func(*[arg.subs(symb, symb/cd) for arg in sol.args])
    if underdetermined is 1:
        from ._release import __version__
        if int(__version__.split('.')[1]) > 6:
            warnings.warn(  # deprecated because comparison with ``1`` problematic (True==1)
                ("Pass underdetermined == None instead of ``1`` (depreacted since 0.7.0,"
                 " will_be_missing_in='0.9.0')"), ChemPyDeprecationWarning)
        underdetermined = None
    if underdetermined is None:
        sol = Tuple(*[Integer(x) for x in _solve_balancing_ilp_pulp(A)])

    fact = gcd(sol)
    sol = MutableDenseMatrix([e/fact for e in sol]).reshape(len(sol), 1)
    sol /= reduce(gcd, sol)
    if 0 in sol:
        raise ValueError("Superfluous species given.")
    if underdetermined:
        if any(x == sympy.nan for x in sol):
            raise ValueError("Failed to balance reaction")
    else:
        for x in sol:
            if len(x.free_symbols) != 0:
                raise ValueError("The system was under-determined")
        if not all(residual == 0 for residual in A * sol):
            raise ValueError("Failed to balance reaction")

    def _x(k):
        coeff = sol[subst_keys.index(k)]
        return int(coeff) if underdetermined is None else coeff

    return (
        OrderedDict([(k, _x(k)) for k in reactants]),
        OrderedDict([(k, _x(k)) for k in products])
    )
Example #17
0
def read(filename):
    """Create a |Geoset| instance from a DS9 region file.

    .. note:: This will break if the region file was not written using
       `write`!

    Parameters
    ----------
    filename : str
        Path to the DS9 region file to be loaded.

    Returns
    -------
    out : |Geoset|
        A |Geoset| instance build using the polygons stored in the DS9 region
        file.

    """
    def parse_ds9_attrs(attrstr, global_attrs=False):
        attrstr = attrstr + ' junk'
        if not global_attrs:
            attrstr = 'junk ' + attrstr

        j = [0] + [i for i in range(len(attrstr)) if attrstr[i] == '='] + [-1]

        keys, vals = [], []
        for j1, j2 in zip(j[:-1], j[1:]):
            val, key = attrstr[j1+1:j2].rsplit(' ', 1)
            if ((val[0], val[-1]) == ('"', '"') or
                (val[0], val[-1]) == ('{', '}')):
                val = val[1:-1]
            keys.append(key)
            vals.append(val)
        return zip(keys[:-1], vals[1:])

    with open(filename, 'r') as file:
        lines = file.readlines()

    geoset = _geoset.Geoset(None)
    i0, j0, k0 = None, None, None
    for line in lines:
        line = line.split('\n')[0]
        # Skip comments and blank lines:
        if line.startswith('#') or not line:
            continue

        # Parse global attributes:
        elif line.startswith('global'):
            attrs = parse_ds9_attrs(line, global_attrs=True)
            attrs = OrderedDict(attrs)
            geoset.attrs = attrs

        # Parse coordinate system:
        elif line in ['physical', 'fk5']:
            if geoset.attrs is None:
                geoset.attrs = OrderedDict()
            geoset.attrs['coordsys'] = line

        # Build geoset:
        elif line.startswith('polygon'):
            coords, delim, attrs = line.partition('(')[-1].partition(')')
            coords, attrs = coords.replace(',', ' '), attrs.split('#')[-1]

            # Make polygon
            xy = [float(i) for i in coords.split()]
            x, y = xy[0::2], xy[1::2]
            poly = geometry.Polygon(zip(x, y))

            # Test if polygon is a hole:
            is_hole = False
            if 'background' in attrs:
                is_hole = True
                attrs = attrs.split('background')[-1]

            # Get item/geo/poly structure indices:
            idx_list = parse_ds9_attrs(attrs)
            for idx in idx_list:
                tag, n = idx[1].split()
                n = int(n)
                if tag == 'item':
                    i = n
                elif tag == 'geo':
                    j = n
                elif tag == 'poly':
                    k = n

            if i != i0:
                geo = _geoset.Geo(poly)
                item = _geoset.Item(geo)
                geoset.items.append(item)
            elif j != j0:
                geo = _geoset.Geo(poly)
                item.geos.append(geo)
            elif k != k0:
                geo.geo = geo.geo.union(poly)
            elif is_hole:
                geo.geo = geo.geo.difference(poly)
            i0, j0, k0 = i, j, k

    return geoset