def _ydot_scratch(self, n_indent, of):
     # Assign scratch variables
     if self.use_cse:
         for si in self.ydot_out_scratch:
             siname = si[0]
             sivalue = self.fortranify(
                 sympy.fcode(si[1],
                             precision=15,
                             source_format='free',
                             standard=95))
             of.write('{}{} = {}\n'.format(self.indent * n_indent, siname,
                                           sivalue))
Example #2
0
 def _ydot(self, n_indent, of):
     # Write YDOT
     for i, n in enumerate(self.unique_nuclei):
         sol_value = self.fortranify(
             sympy.fcode(self.ydot_out_result[i],
                         precision=15,
                         source_format='free',
                         standard=95))
         of.write('{}{}(j{}) = ( &\n'.format(self.indent * n_indent,
                                             self.name_ydot_nuc, n))
         of.write("{}{} &\n".format(self.indent * (n_indent + 1),
                                    sol_value))
         of.write("{}   )\n\n".format(self.indent * n_indent))
Example #3
0
    def _set_axis_and_point(self, cond_eq: sympy.Equality, coords: cs.CoordinateSystem):
        coord_vars = coords.axises()
        self.axis, self.axis_point = None, None

        U = sympy.Function("u")
        u_entrances = list(cond_eq.find(U))
        if len(u_entrances) != 1:
            raise ValueError(
                "Cannot contain different args in U for derivative and u function"
            )

        a1 = sympy.Wild("a1", properties=[lambda x: x.is_constant])
        a2 = sympy.Wild("a2", properties=[lambda x: x.is_constant])
        u_pow = sympy.Wild("u_pow", properties=[lambda x: x.is_constant])
        axis = sympy.Wild("axis", properties=[lambda x: x.is_symbol])
        U_pattern = sympy.WildFunction("U_pattern", nargs=len(coords.axises()))

        res = cond_eq.lhs.match(
            a1 * U_pattern ** u_pow + a2 * sympy.Derivative(U_pattern, axis)
        )
        if res is None:
            raise ValueError(f"Cannot parse {cond_eq}")
        self.a1 = res[a1]
        self.a2 = res[a2]
        u_with_args = res[U_pattern]

        if self.a1 != 0 and self.a2 == 0:
            self.kind = ConditionKind.First.name
        elif self.a1 == 0 and self.a2 != 0:
            self.kind = ConditionKind.Second.name
        elif self.a1 != 0 and self.a2 != 0:
            self.kind = ConditionKind.Third.name
        else:
            raise ValueError(
                f"Left side of boundary condition: {cond_eq} does"
                "not contain u function"
            )

        for i, arg in enumerate(u_with_args.args):
            if arg.is_constant():
                self.axis = coord_vars[i]
                self.axis_point = sympy.fcode(arg.evalf())
                self._axis_point = arg
                break

        if self.axis is None:
            raise ValueError(
                "Bondary condition cannot be parsed"
                "Probably you did not specified U arguments or"
                "there is no constant in arguments"
            )
Example #4
0
    def _get_partial_pressure_code(self, str_list, str_trans):
        # Calculate flowrate of all gas species
        flowratecode = []
        flowrate = 0
        for species in self._species:
            if isinstance(species, _Fluid):
                flowrate += species.symbol
        fcode = sym.fcode(flowrate, source_format='free')

        for key in str_list:
            fcode = fcode.replace(key, str_trans[key])
        flowratecode.append(f'   flowrate = {fcode}')

        return flowratecode
 def writeCode_Fortran95(self, outname):
     ## Write Fortran-95 Solver Subroutine
     try:
         fo = open(outname, 'w')
     except:
         raise
     indent = ' '*2
     fo.write('module gauss_jordan_module\n')
     fo.write('{}implicit none\n'.format(indent))
     fo.write('\n')
     fo.write('contains\n')
     fo.write('\n')
     fo.write('{}subroutine gauss_jordan_solve(A, x, b)\n'.format(indent))
     fo.write('{}double precision, dimension({},{}), intent(in) :: A\n'.format(
         indent*2, self.nvars, self.nvars))
     fo.write('{}double precision, dimension({}), intent(out) :: x\n'.format(
         indent*2, self.nvars))
     fo.write('{}double precision, dimension({}), intent(in) :: b\n'.format(
         indent*2, self.nvars))
     if self.cse_rep:
         for rep in self.cse_rep:
             fo.write('{}double precision :: {}\n'.format(indent*2, rep[0]))
         fo.write('\n')
         for rep in self.cse_rep:
             rep_value = self.fortranify(sympy.fcode(rep[1], precision = 15,
                                                     source_format = 'free',
                                                     standard = 95))
             fo.write('{}{} = {}\n'.format(indent*2, rep[0], rep_value))
     fo.write('\n')
     for i, sol in enumerate(self.solution):
         sol_value = self.fortranify(sympy.fcode(sol, precision = 15,
                                                 source_format = 'free',
                                                 standard = 95))
         fo.write('{}x({}) = {}\n'.format(indent*2, i+1, sol_value))
     fo.write('{}end subroutine gauss_jordan_solve\n'.format(indent))
     fo.write('end module gauss_jordan_module\n')
     fo.close()
 def _jacnuc(self, n_indent, of):
     # now make the JACOBIAN
     n_unique_nuclei = len(self.unique_nuclei)
     for jnj, nj in enumerate(self.unique_nuclei):
         for ini, ni in enumerate(self.unique_nuclei):
             jac_idx = n_unique_nuclei * jnj + ini
             jvalue = self.fortranify(
                 sympy.fcode(self.jac_out_result[jac_idx],
                             precision=15,
                             source_format='free',
                             standard=95))
             of.write("{}{}(j{},j{}) = ( &\n".format(
                 self.indent * n_indent, self.name_jacobian_nuc, nj, ni))
             of.write("{}{} &\n".format(self.indent * (n_indent + 1),
                                        jvalue))
             of.write("{}   )\n\n".format(self.indent * n_indent))
Example #7
0
 def _jacnuc(self, n_indent, of):
     # now make the Jacobian
     n_unique_nuclei = len(self.unique_nuclei)
     for jnj, nj in enumerate(self.unique_nuclei):
         for ini, ni in enumerate(self.unique_nuclei):
             jac_idx = n_unique_nuclei*jnj + ini
             if not self.jac_null_entries[jac_idx]:
                 jvalue = self.fortranify(sympy.fcode(self.jac_out_result[jac_idx],
                                                      precision=15,
                                                      source_format='free',
                                                      standard=95))
                 of.write("{}scratch = (&\n".format(self.indent*(n_indent)))
                 of.write("{}{} &\n".format(self.indent*(n_indent+1), jvalue))
                 of.write("{}   )\n".format(self.indent*n_indent))
                 of.write("{}call set_jac_entry({}, j{}, j{}, scratch)\n\n".format(
                     self.indent*n_indent, self.name_jacobian, nj, ni))
Example #8
0
def expressionToCode(expression, language):
    '''Converts a SymPy Expression to a line of code in the target language'''
    if (language == "python"):
        return sympy.pycode(expression)
    elif (language == "javascript" or language == "typescript"):
        return sympy.jscode(expression)
    elif (language == "c"):
        return sympy.ccode(expression)
    elif (language == "cpp"):
        return sympy.cxxcode(expression)
    elif (language == "r"):
        return sympy.rcode(expression)
    elif (language == "fortran"):
        return sympy.fcode(expression)
    elif (language == "mathematica"):
        return sympy.mathematica_code(expression)
    elif (language == "matlab" or language == "octave"):
        return sympy.octave_code(expression)
    elif (language == "rust"):
        return sympy.rust_code(expression)
Example #9
0
def camb_fortran(expr, name='camb_function', frame='CDM', expand=False):
    """
    Convert symbolic expression to CAMB fortran code, using CAMB variable notation.
    This is not completely general, but it will handle conversion of Newtonian gauge
    variables like Psi_N, and most derivatives up to second order.

    :param expr: symbolic sympy expression using camb.symbolic variables and functions (plus any
                 standard general functions that CAMB can convert to fortran).
    :param name: lhs variable string to assign result to
    :param frame: frame in which to interret non gauge-invariant expressions.
                  By default uses CDM frame (synchronous gauge), as used natively by CAMB.
    :param expand: do a sympy expand before generating code
    :return: fortran code snippet
    """

    camb_diff_vars = 'etakdot qgdot qrdot vbdot pigdot pirdot pinudot ' + \
                     'octg octgdot polterdot polterddot diff_rhopi sigmadot phidot  ' + \
                     'ddvisibility dvisibility dopacity ddopacity'
    camb_arr_vars = 'Edot E'

    tau = _camb_cache.setdefault('tau', Symbol('tau'))

    etakdot, qgdot, qrdot, vbdot, pigdot, pirdot, pinudot, octg, octgdot, \
    polterdot, polterddot, diff_rhopi, sigmadot, phidot, \
    ddvisibility, dvisibility, dopacity, ddopacity = \
        define_variables(camb_diff_vars, _camb_cache)
    Edot, E = \
        sympy.symbols(camb_arr_vars, cls=sympy.IndexedBase, shape=(sympy.oo,))

    # Keep everything except baryons pressure which is very small
    camb_diff_subs = [(diff(q_g, t), qgdot), (diff(pi_g, t), pigdot),
                      (diff(pi_r, t), pirdot), (diff(q_r, t), qrdot),
                      (diff(v_b, t), vbdot),
                      (diff(visibility, t, t), ddvisibility),
                      (diff(visibility, t), dvisibility),
                      (diff(opacity, t, t), ddopacity),
                      (diff(opacity, t), dopacity), (diff(J_3, t), octgdot),
                      (diff(E_2, t), Edot[2]), (diff(E_3, t), Edot[3]),
                      (diff(pi_nu, t), pinudot),
                      (diff(eta, t), -2 * etakdot / k),
                      (diff(Pi, t), diff_rhopi / kappa / a**2),
                      (diff(polter, t, t), polterddot),
                      (diff(polter, t), polterdot), (diff(sigma, t), sigmadot),
                      (diff(phi, t), phidot), (diff(p_b, t), 0)]

    if frame != 'CDM':
        expr = make_frame_invariant(expr, frame)

    # substitute for variables not available in CAMB function
    expr = cdm_gauge(
        subs(Newt_vars + synchronous_vars + [hdot_sub, z_sub],
             expr)).doit().simplify()
    res = cdm_gauge(
        subs(background_eqs + total_eqs, expr).subs(camb_diff_subs))

    if 'Derivative' in str(res):
        raise Exception(
            'Unknown derivatives, generally can only handle up to second.\nRemaining derivatives: '
            + str(res))

    res = cdm_gauge(subs([K_sub, hdot_sub, z_sub], res))
    camb_var_subs = []
    for var in res.atoms(Function):
        camb_var = getattr(var, 'camb_var', None)
        if camb_var:
            if isinstance(camb_var, (list, tuple)):
                for x in camb_var:
                    define_variable(x)
                camb_sub = getattr(var, 'camb_sub', None)
                if not camb_sub:
                    raise Exception(
                        'must have camb_sub if camb_var has more than one variable'
                    )
            else:
                camb_var = define_variable(camb_var)
                camb_sub = getattr(var, 'camb_sub', None) or camb_var
            if camb_sub:
                if isinstance(camb_sub, six.string_types):
                    camb_sub = eval(camb_sub)
                camb_var_subs.append((var, camb_sub))

    camb_subs = camb_var_subs + [(p_b, 0), (E_2, E[2]), (E_3, E[3]),
                                 (J_3, octg), (K_fac, Kf[1])]
    res = res.subs(camb_subs).simplify()
    no_arg_funcs = [
        f for f in res.atoms(Function) if f.args[0] == t and not f is f_K
    ]
    res = res.subs(
        zip(no_arg_funcs, [Symbol(str(x.func)) for x in no_arg_funcs]))
    res = res.subs(t, tau)
    if expand: res = res.expand()
    res = res.collect([
        Symbol(str(x.func)) for x in
        [k, sigma, opacity, visibility, dopacity, dvisibility, ddvisibility]
    ])
    res = sympy.fcode(res,
                      source_format='free',
                      standard=95,
                      assign_to=name,
                      contract=False)
    import textwrap

    if not 'if ' in res:
        lines = res.split('\n')
        for i, line in enumerate(lines):
            if '=' in line:
                res = '\n'.join(lines[i:])
                break
        res = ''.join([x.strip() for x in res.split('&')])
        res = ' &\n    '.join(textwrap.wrap(res))
    return res
Example #10
0
def FORTRAN_jacobian(x, jac, parameters=[]):
    # TODO document
    # TODO remove this function if unused in paper
    NX = len(x)
    NP = len(parameters)
    Nrowpd = jac.shape[0]
    Ncolpd = jac.shape[1]
    if NX != Nrowpd != Ncolpd:
        raise Exception("System is not square!")

    _X = sy.tensor.IndexedBase("X", shape=(NX, ))
    X = [_X[i + 1] for i in xrange(NX)]
    X = X + [_X[NX + i + 1] for i in xrange(NP)]

    if type(jac) == sy.Matrix: jac = sy.Matrix(jac)
    jac_sub = jac.subs(zip(list(x) + list(parameters), X))

    ijs = [i for i in it.product(xrange(Nrowpd), xrange(Ncolpd))]

    # generate FORTRAN code
    fstrs = [sy.fcode(jac_ij) for jac_ij in jac_sub]

    # remove whitespace and newlines
    fstrs = ["".join(jac_ij.split()) for jac_ij in fstrs]

    # remove all @ (FORTRAN line continuation indicator)
    fstrs = [jac_ij.replace("@", "") for jac_ij in fstrs]

    # find FORTRAN inline merge statements and replace with a hidden "switch"
    # variable whose value is set by a full IF statement at the start of the
    # function call.
    # -- this is needed because FORTRAN77 doesn't support inline merge statements
    Hstrs = []  # to hold hidden switch expressions

    for i in xrange(len(fstrs)):
        while fstrs[i].find("merge") != -1:
            H = "H(" + str(len(Hstrs) + 1) + ")"
            i_merge_start, i_merge_end, Hstr = parse_merge(H, fstrs[i])
            fstrs[i] = fstrs[i][:i_merge_start] + H + fstrs[i][i_merge_end:]
            Hstrs.append(Hstr)
    NH = len(Hstrs)

    # format the fstrs
    wrapper = textwrap.TextWrapper(expand_tabs=True,
                                   replace_whitespace=True,
                                   initial_indent="      ",
                                   subsequent_indent="     @    ",
                                   width=60)

    for k in xrange(len(fstrs)):
        i, j = ijs[k]
        fstrs[k] = wrapper.fill("pd(" + str(i + 1) + "," + str(j + 1) + ")=" +
                                fstrs[k]) + "\n"

    # put the above elements together into a FORTRAN subroutine
    hdr = "      subroutine jac_f77(neq, t, X, ml, mu, pd, nrowpd) \n" +\
          "Cf2py intent(hide) neq, ml, mu, nrowpd \n" +\
          "Cf2py intent(out) pd \n" +\
          "      integer neq, ml, mu, nrowpd \n" +\
          "      double precision t, X, pd \n" +\
          "      dimension X(neq), pd(neq, neq) \n"
    if NH > 0: hdr += "      real, dimension(" + str(NH) + ") :: H \n"
    H_block = "".join(Hstrs)
    pd_block = "".join(fstrs)

    fcode = hdr + H_block + pd_block + "      return \n" + "      end \n"

    return fcode
Example #11
0
def _to_fcode(expr):
    return sympy.fcode(sympy.simplify(expr).evalf()).replace("\n", "").replace("@", "")
Example #12
0
def sympy_to_muparser(expr):
    code = sympy.fcode(expr)
    code = code.replace('\n     @', '')
    code = code.replace('**', '^')
    return code
Example #13
0
def f90code(r, l):
    f90sym, f90fun, f90cod = fcode(r.evalf(6), l, source_format = 'free', \
        standard = 2008, human = False)
    return f90cod
Example #14
0
def main(argv):

    # Define arguments applicable to all commands
    from argparse import ArgumentParser, RawDescriptionHelpFormatter, SUPPRESS
    p = ArgumentParser(description=__doc__,
                       formatter_class=RawDescriptionHelpFormatter)
    p.add_argument('-v', '--verbosity', action='count',
                   help='increase verbosity; may be supplied repeatedly')
    p.add_argument('-n', '--newline', action='store_const', dest='statements',
                   const=statements_by_newline,
                   default=statements_by_semicolon,
                   help='expect newline-delimited input with "#" comments;'
                        ' otherwise semicolons delimit with "//" comments')
    p.add_argument('-d', '--decl', action='append', default=[],
                   help='file containing SymPy-based declarations defaulting'
                        ' to standard input when declarations required')

    # Control C vs Fortran vs SymPy (default) output for expressions
    g = p.add_mutually_exclusive_group()
    g.add_argument('-c', '--ccode', dest='style', default=str,
                   help='output symbolic expressions as C code',
                   action='store_const',
                   const=lambda expr: sympy.ccode(expr, human=False)[2])
    g.add_argument('-f', '--fcode', dest='style', default=SUPPRESS,
                   help='output symbolic expressions as Fortran code',
                   action='store_const',
                   const=lambda expr: sympy.fcode(expr,
                                                  source_format='free',
                                                  human=False)[2])

    # Control order of the approximation to any used expectations
    g = p.add_mutually_exclusive_group()
    g.add_argument('-1', dest='order', action='store_const', const=1,
                    help='employ 1st order approximation to the expectation')
    g.add_argument('-2', dest='order', action='store_const', const=2,
                    help='employ 2nd order approximation to the expectation')
    p.set_defaults(order=2)

    # Add command-specific subparsers
    sp = p.add_subparsers(title='subcommands, each possibly using declarations',
                          metavar='')
    sp_chk = sp.add_parser('chk', help='run verification sanity checks',
                           description='run verification sanity checks')
    sp_dec = sp.add_parser('dec', help='output known declarations',
                           description='output known declarations')
    sp_lib = sp.add_parser('lib', help='list undefined symbols in declarations',
                           description=prerequisites.__doc__,
                           formatter_class=RawDescriptionHelpFormatter)
    sp_pre = sp.add_parser('pre', help='list prerequisites for E[f(x)], Var[f(x)]',
                           description=prerequisites.__doc__,
                           formatter_class=RawDescriptionHelpFormatter)
    sp_exp = sp.add_parser('exp', help='tabulate terms in E[f(x)]',
                           description=expectation.__doc__,
                           formatter_class=RawDescriptionHelpFormatter)
    sp_var = sp.add_parser('var', help='tabulate terms in Var[f(x)]',
                           description=variance.__doc__,
                           formatter_class=RawDescriptionHelpFormatter)

    # Some of the subparsers take one or more symbols to process
    f_help = 'quantities of interest; if empty, process all declarations'
    sp_dec.add_argument('f', nargs='*', help=f_help)
    sp_lib.add_argument('f', nargs='*', help=f_help)
    sp_pre.add_argument('f', nargs='*', help=f_help)
    sp_exp.add_argument('f', nargs='*', help=f_help)
    sp_var.add_argument('f', nargs='*', help=f_help)

    # Each command dispatches to one of the following methods
    sp_chk.set_defaults(command=command_chk)
    sp_dec.set_defaults(command=command_dec)
    sp_lib.set_defaults(command=command_lib)
    sp_pre.set_defaults(command=command_pre)
    sp_exp.set_defaults(command=command_exp)
    sp_var.set_defaults(command=command_var)

    # Parse the incoming command line
    args = p.parse_args()

    # Supply "all known declarations" behavior for any f arguments first
    # parsing any requested files into one unified dictionary "args.syms".
    # Additionally, provide nicer error messages on unknown symbols
    # (otherwise a messy stacktrace appears and folks doubt the code).
    if ('f' in args):
        args.syms = parser(args.statements(args.decl))
        if not args.f:
            args.f = args.syms.keys()
        else:
            unknown = filter(lambda k: k not in args.syms, args.f)
            if unknown:
                raise LookupError("Requested but not in declarations: %s"
                                  % ', '.join(unknown))

    # Dispatch to the chosen command
    retval = args.command(args)

    # Warn if the results are likely bogus due to an older SymPy version
    if (   distutils.version.LooseVersion(sympy.__version__)
         < distutils.version.LooseVersion('0.7.2')           ):
        print('WARN: %s notes SymPy %s older than minimum 0.7.2'
              % (argv[0], sympy.__version__),
              file=sys.stderr)

    return retval
Example #15
0
def camb_fortran(expr, name='camb_function', frame='CDM', expand=False):
    """
    Convert symbolic expression to CAMB fortran code, using CAMB variable notation.
    This is not completely general, but it will handle conversion of Newtonian gauge
    variables like Psi_N, and most derivatives up to second order.

    :param expr: symbolic sympy expression using camb.symbolic variables and functions (plus any
                 standard general functions that CAMB can convert to fortran).
    :param name: lhs variable string to assign result to
    :param frame: frame in which to interret non gauge-invariant expressions.
                  By default uses CDM frame (synchronous gauge), as used natively by CAMB.
    :param expand: do a sympy expand before generating code
    :return: fortran code snippet
    """

    camb_diff_vars = 'etakdot qgdot qrdot vbdot pigdot pirdot pinudot ' + \
                     'octg octgdot polterdot polterddot diff_rhopi sigmadot phidot  ' + \
                     'ddvisibility dvisibility dopacity ddopacity'
    camb_arr_vars = 'Edot E'

    tau = _camb_cache.setdefault('tau', Symbol('tau'))

    etakdot, qgdot, qrdot, vbdot, pigdot, pirdot, pinudot, octg, octgdot, \
    polterdot, polterddot, diff_rhopi, sigmadot, phidot, \
    ddvisibility, dvisibility, dopacity, ddopacity = \
        define_variables(camb_diff_vars, _camb_cache)
    Edot, E = \
        sympy.symbols(camb_arr_vars, cls=sympy.IndexedBase, shape=(sympy.oo,))

    # Keep everything except baryons pressure which is very small
    camb_diff_subs = [(diff(q_g, t), qgdot), (diff(pi_g, t), pigdot), (diff(pi_r, t), pirdot),
                      (diff(q_r, t), qrdot), (diff(v_b, t), vbdot),
                      (diff(visibility, t, t), ddvisibility), (diff(visibility, t), dvisibility),
                      (diff(opacity, t, t), ddopacity), (diff(opacity, t), dopacity),
                      (diff(J_3, t), octgdot), (diff(E_2, t), Edot[2]),
                      (diff(E_3, t), Edot[3]), (diff(pi_nu, t), pinudot),
                      (diff(eta, t), -2 * etakdot / k), (diff(Pi, t), diff_rhopi / kappa / a ** 2),
                      (diff(polter, t, t), polterddot), (diff(polter, t), polterdot),
                      (diff(sigma, t), sigmadot), (diff(phi, t), phidot), (diff(p_b, t), 0)]

    if frame != 'CDM':
        expr = make_frame_invariant(expr, frame)

    # substitute for variables not available in CAMB function
    expr = cdm_gauge(subs(Newt_vars + synchronous_vars + [hdot_sub, z_sub], expr)).doit().simplify()
    res = cdm_gauge(subs(background_eqs + total_eqs, expr).subs(camb_diff_subs))

    if 'Derivative' in str(res):
        raise Exception(
            'Unknown derivatives, generally can only handle up to second.\nRemaining derivatives: ' + str(res))

    res = cdm_gauge(subs([K_sub, hdot_sub, z_sub], res))
    camb_var_subs = []
    for var in res.atoms(Function):
        camb_var = getattr(var, 'camb_var', None)
        if camb_var:
            if isinstance(camb_var, (list, tuple)):
                for x in camb_var:
                    define_variable(x)
                camb_sub = getattr(var, 'camb_sub', None)
                if not camb_sub:
                    raise Exception('must have camb_sub if camb_var has more than one variable')
            else:
                camb_var = define_variable(camb_var)
                camb_sub = getattr(var, 'camb_sub', None) or camb_var
            if camb_sub:
                if isinstance(camb_sub, six.string_types): camb_sub = eval(camb_sub)
                camb_var_subs.append((var, camb_sub))

    camb_subs = camb_var_subs + [(p_b, 0), (E_2, E[2]), (E_3, E[3]), (J_3, octg), (K_fac, Kf[1])]
    res = res.subs(camb_subs).simplify()
    no_arg_funcs = [f for f in res.atoms(Function) if f.args[0] == t and not f is f_K]
    res = res.subs(zip(no_arg_funcs, [Symbol(str(x.func)) for x in no_arg_funcs]))
    res = res.subs(t, tau)
    if expand: res = res.expand()
    res = res.collect([Symbol(str(x.func)) for x in
                       [k, sigma, opacity, visibility, dopacity, dvisibility, ddvisibility]])
    res = sympy.fcode(res, source_format='free', standard=95, assign_to=name, contract=False)
    import textwrap

    if not 'if ' in res:
        lines = res.split('\n')
        for i, line in enumerate(lines):
            if '=' in line:
                res = '\n'.join(lines[i:])
                break
        res = ''.join([x.strip() for x in res.split('&')])
        res = ' &\n    '.join(textwrap.wrap(res))
    return res
Example #16
0
def FORTRAN_f(x, f, parameters=[], verbose=False):
    """
    Produce FORTRAN function for evaluating a vector-valued SymPy expression f
    given a state vector x. 
    
    The FORTRAN function will have the signature f_f77(neq, t, X, Y) where neq
    is hidden and Y is an output matrix.
    """
    # TODO remove code for dealing with stochastic systems -- it is not used in
    # this paper
    x = list(x) + list(parameters)
    f = list(f) + [0] * len(parameters)
    rv = list(
        set((np.concatenate([sy.stats.random_symbols(f_i) for f_i in f]))))

    NR = len(rv)
    if NR > 0:
        x += [sy.symbols("dt"), sy.symbols("seed")]
        f += [0, 0]
    NX = len(x)
    NY = len(f)
    if NX != NY:
        raise Exception("System is not square!")

    if verbose: print "generating FORTRAN matrices..."
    _X = sy.tensor.IndexedBase("X", shape=(NX, ))
    X = [_X[i + 1] for i in xrange(NX)]

    _R = sy.tensor.IndexedBase("R", shape=(NR, ))
    R = [_R[i + 1] for i in xrange(NR)]

    if type(f) != sy.Matrix: f = sy.Matrix(f)
    # WARNING : These substitution steps are VERY SLOW!!! It might be wise to
    # parallelise them in the future, or at least substitute into one dynamical
    # equation at a time so that progress can be monitored.
    if verbose:
        print "substituting matrix elements for original state variables and parameters (WARNING: SLOW)..."
    f_sub = f.subs(zip(x, X))
    if verbose:
        print "substituting matrix elements for random variables (WARNING: SLOW)..."
    f_sub = f_sub.subs(zip(rv, R))

    # generate FORTRAN code
    if verbose: print "generating FORTRAN code from dynamics equations..."
    fstrs = [sy.fcode(fi, standard=95) for fi in f_sub]

    # remove whitespace and newlines
    if verbose: print "removing whitespace and newlines..."
    fstrs = ["".join(fi.split()) for fi in fstrs]

    # remove all @ (FORTRAN line continuation indicator)
    if verbose: print "removing line continuations..."
    fstrs = [fi.replace("@", "") for fi in fstrs]

    # find FORTRAN inline merge statements and replace with a hidden "switch"
    # variable whose value is set by a full IF statement at the start of the
    # function call.
    # -- this is needed because FORTRAN77 doesn't support inline merge statements
    Hstrs = []  # to hold hidden switch expressions

    if verbose: print "formatting piecewise functions..."
    for i in xrange(len(fstrs)):
        while fstrs[i].find("merge") != -1:
            H = "H(" + str(len(Hstrs) + 1) + ")"
            i_merge_start, i_merge_end, Hstr = parse_merge(H, fstrs[i])
            fstrs[i] = fstrs[i][:i_merge_start] + H + fstrs[i][i_merge_end:]
            Hstrs.append(Hstr)
    NH = len(Hstrs)

    # format the fstrs
    wrapper = textwrap.TextWrapper(expand_tabs=True,
                                   replace_whitespace=True,
                                   initial_indent="      ",
                                   subsequent_indent="     @    ",
                                   width=60)

    if verbose: print "formatting state equations..."
    for i in xrange(len(fstrs)):
        fstrs[i] = wrapper.fill("Y(" + str(i + 1) + ")=" + fstrs[i]) + "\n"

    # put the above elements together into a FORTRAN subroutine
    if verbose: print "formatting preamble..."
    hdr = "      subroutine f_f77(neq, t, X, Y) \n" +\
          "Cf2py intent(hide) neq \n" +\
          "Cf2py intent(out) Y \n" +\
          "      integer neq \n" +\
          "      double precision t, X, Y \n" +\
          "      dimension X(neq), Y(neq) \n"
    if NH > 0: hdr += "      real, dimension(" + str(NH) + ") :: H \n"
    # TODO fix the following -- assumes dt = 0.01
    # NOTE this is only important when dealing with stochastic systems
    if NR > 0:        hdr += "      real, dimension(" + str(NR) + ") :: R \n" +\
               "      integer :: SEED \n" +\
               "      real :: RTRASH \n" +\
               "      SEED = INT((t/" + sy.fcode(X[-2]).strip() +\
                        ") + " + sy.fcode(X[-1]).strip() + ") \n" +\
               "      CALL SRAND(SEED) \n" +\
               "      DO i=1,4 \n" +\
               "            RTRASH=RAND(0) \n" +\
               "      END DO \n"
    R_block = "".join([sy.fcode(R_i) + "=RAND(0) \n" for R_i in R])
    H_block = "".join(Hstrs)
    Y_block = "".join(fstrs)

    if verbose: print "assembling source code blocks..."
    fcode = hdr + R_block + H_block + Y_block + "      return \n" + "      end \n"

    # final formatting
    if verbose: print "final source code formatting..."
    wrapper = textwrap.TextWrapper(expand_tabs=True,
                                   replace_whitespace=True,
                                   initial_indent="",
                                   subsequent_indent="     @    ",
                                   width=60)

    fcode = "".join([wrapper.fill(src) + "\n" for src in fcode.split("\n")])

    return fcode
Example #17
0
    def setup_execs(self):
        from micki.fortran2 import f90_template, pyf_template
        from numpy import f2py

        # y_vec is an array symbol that will represent the species
        # concentrations provided by the differential equation solver inside
        # the Fortran code (that is, y_vec is an INPUT to the functions that
        # calculate the residual, Jacobian, and rate)
        y_vec = sym.IndexedBase('y', shape=(self.nvariables, ))
        vac_vec = sym.IndexedBase('vac', shape=(len(self.vacancy), ))
        # Map y_vec elements (1-indexed, of course) onto 'modelparam' symbols
        trans = {self.symbols[i]: y_vec[i + 1] for i in range(self.nvariables)}
        trans.update(
            {vac.symbol: y_vec[i + 1]
             for i, vac in enumerate(self.vacancy)})
        # Map string represntation of 'modelparam' symbols onto string
        # representation of y-vec elements
        str_trans = {}
        for i, symbol in enumerate(self.symbols):
            str_trans[sym.fcode(symbol, source_format='free')] = \
                    sym.fcode(y_vec[i + 1], source_format='free')
        for i, vac in enumerate(self.vacancy):
            str_trans[sym.fcode(vac.symbol, source_format='free')] = \
                    sym.fcode(vac_vec[i + 1], source_format='free')

        str_list = [key for key in str_trans]
        str_list.sort(key=len, reverse=True)

        # these will contain lists of strings, with each element being one
        # Fortran assignment for the master equation, Jacobian, and
        # rate expressions
        dypdrcode = []
        drdycode = []
        vaccode = []
        drdvaccode = []
        dvacdycode = []

        for i, expr in enumerate(self.vac_sym):
            fcode = sym.fcode(expr, source_format='free')
            for key in str_list:
                fcode = fcode.replace(key, str_trans[key])
            vaccode.append('   vac({}) = '.format(i + 1) + fcode)

        for i, row in enumerate(self.drdvac):
            for j, elem in enumerate(row):
                if elem != 0:
                    fcode = sym.fcode(elem, source_format='free')
                    for key in str_list:
                        fcode = fcode.replace(key, str_trans[key])
                    drdvaccode.append(
                        '   drdvac({}, {}) = '.format(i + 1, j + 1) + fcode)

        for i, row in enumerate(self.dvacdy):
            for j, elem in enumerate(row):
                if elem != 0:
                    dvacdycode.append(
                        '   dvacdy({}, {}) = '.format(i + 1, j + 1) +
                        sym.fcode(elem, source_format='free'))

        for i, row in enumerate(self.dypdr):
            for j, elem in enumerate(row):
                if elem != 0:
                    dypdrcode.append(
                        '   dypdr({}, {}) = '.format(i + 1, j + 1) +
                        sym.fcode(elem, source_format='free'))

        # Effectively the same as above, except on the two-dimensional Jacobian
        # matrix.
        for i, row in enumerate(self.drdy):
            for j, elem in enumerate(row):
                if elem != 0:
                    fcode = sym.fcode(elem, source_format='free')
                    for key in str_list:
                        fcode = fcode.replace(key, str_trans[key])
                    drdycode.append('   drdy({}, {}) = '.format(i + 1, j + 1) +
                                    fcode)

        ratecode = self._get_rate_code(str_list, str_trans)
        #flowratecode = self._get_flowrate_code(str_list, str_trans)

        is_gas = ['   isgas = 0']
        for idx, species in enumerate(self._variable_species):
            if isinstance(species, _Fluid):
                is_gas.append(f'   isgas({idx+1}) = 1')
            else:
                is_gas.append(f'   isgas({idx+1}) = 0')

        # We insert all of the parameters of this differential equation into
        # the prewritten Fortran template, including the residual, Jacobian,
        # and rate expressions we just calculated.
        program = f90_template.format(
            neq=self.nvariables,
            nx=1,
            nrates=len(self.rates),
            nvac=len(self.vacancy),
            dypdrcalc='\n'.join(dypdrcode),
            drdycalc='\n'.join(drdycode),
            ratecalc='\n'.join(ratecode),
            vaccalc='\n'.join(vaccode),
            drdvaccalc='\n'.join(drdvaccode),
            dvacdycalc='\n'.join(dvacdycode),
            isgas='\n'.join(is_gas),
        )

        # Generate a randomly-named temp directory for compiling the module.
        # We will name the actual module file after the directory.
        dname = tempfile.mkdtemp()
        modname = os.path.split(dname)[1]
        fname = modname + '.f90'
        pyfname = modname + '.pyf'

        # For debugging purposes, write out the generated module
        with open('solve_ida.f90', 'w') as f:
            f.write(program)

        # Write the pertinent data into the temp directory
        with open(os.path.join(dname, pyfname), 'w') as f:
            f.write(
                pyf_template.format(modname=modname,
                                    neq=self.nvariables,
                                    nrates=len(self.rates),
                                    nvac=len(self.vacancy)))

        # Compile the module with f2py
        lapack = "-lmkl_rt"
        if "MICKI_LAPACK" in os.environ:
            lapack = os.environ["MICKI_LAPACK"]
        os.environ["CFLAGS"] = "-w"

        f2py.compile(program,
                     modulename=modname,
                     extra_args='--quiet '
                     '--f90flags="-Wno-unused-dummy-argument '
                     '-Wno-unused-variable -Wno-unused-func -w" '
                     '-lsundials_fida '
                     '-lsundials_fnvecserial '
                     '-lsundials_ida '
                     '-lsundials_fsunlinsollapackdense '
                     '-lsundials_sunlinsollapackdense '
                     '-lsundials_nvecserial ' + lapack + ' ' +
                     os.path.join(dname, pyfname),
                     source_fn=os.path.join(dname, fname),
                     verbose=0)
        # Delete the temporary directory
        shutil.rmtree(dname)

        # Import the module on-the-fly with __import__. This is kind of a hack.
        solve_ida = __import__(modname)
        self._solve_ida = solve_ida

        # The Fortran module's initialize, solve, and finalize routines
        # are mapped onto finitialize, fsolve, and ffinalize inside the Model
        # object. We don't want users touching these manually
        self.finitialize = solve_ida.initialize
        self.ffind_steady_state = solve_ida.find_steady_state
        self.fsolve = solve_ida.solve
        self.ffinalize = solve_ida.finalize

        # Delete the module file. We've already imported it, so it's in memory.
        modulefile = glob.glob(f'{modname}*.so')[0]
        os.remove(modulefile)
Example #18
0
    for i in range(3):
        eqstream.append(Eq(yvar[i], sympy_exp(logY[i].subs(f, ff(r)))))

temp = Symbol('logR')

r12, r23 = symbols('r12 r23', real=True, positive=True)
f12, f23 = symbols('f12 f23', real=True, negative=False)

# przejscie 1->2
eq = nsimplify(logY_all[1][0]) - 3 * nsimplify(logY_all[1][1]) - sympy_log(
    (2 * cgs_stef * cgs_mhydr) / (3 * cgs_boltz * cgs_c))
for x in solveset(eq.replace(sympy_log(r), temp), temp):
    eqstream.append(Eq(r12, sympy_exp(x.subs(f, ff(r12)))))

# przejscie 2->3
eq = nsimplify(
    logY_all[1][0]) - Rational(7, 2) * nsimplify(logY_all[1][1]) - sympy_log(
        kappa_es / kappa_abs_0)
for x in solveset(eq.replace(sympy_log(r), temp), temp):
    eqstream.append(Eq(r23, sympy_exp(x.subs(f, ff(r23)))))

with open('3zones.f90', 'w') as f:
    for eq in eqstream:
        f.write(
            fcode(eq.rhs.evalf(6),
                  eq.lhs,
                  standard=2008,
                  source_format='free',
                  contract=False,
                  user_functions={'f': 'f'}) + "\n")
Example #19
0
    if signu is 'fixed':
        ei.signu = '%f_wp' % (0.5 * proxy.std())
        print(ei.signu)
        ei.nextra_para = 2
    else:
        ei.signu = 'para(self%nA+self%nF+2)'
        ei.nextra_para = 2
    x = sympy.symbols(
        ['para({:d})'.format(i + 1) for i in range(ei.nA + ei.nF)],
        positive=True)
    a0, aplus = ei.para_trans(x, dtype=object)

    mat_str = lambda *x: '    {}({}, {}) = {}'.format(*x)
    A0str = [
        mat_str('A', i + 1, j + 1, sympy.fcode(value, source_format='free'))
        for (i, j), value in np.ndenumerate(a0) if value > 0
    ]
    Apstr = [
        mat_str('F', i + 1, j + 1, sympy.fcode(value, source_format='free'))
        for (i, j), value in np.ndenumerate(aplus) if value > 0
    ]

    varfile = open('svar.f90', 'r').read()
    varfile = varfile.format(assign_para='\n'.join(A0str + Apstr), **vars(ei))

    other_files = {
        'data.txt': data['1993':'2007-06'][model['yy']].values,
        'proxy.txt': proxy.values,
        'priordraws.txt': priorsim[:args.nsim].T,
        'phistar.txt': phihatT.flatten(order='F'),
Example #20
0
    def setup_execs(self):
        from micki.fortran import f90_template, pyf_template
        from numpy import f2py

        # y_vec is an array symbol that will represent the species
        # concentrations provided by the differential equation solver inside
        # the Fortran code (that is, y_vec is an INPUT to the functions that
        # calculate the residual, Jacobian, and rate)
        y_vec = sym.IndexedBase('yin', shape=(self.nvariables, ))
        # Map y_vec elements (1-indexed, of course) onto 'modelparam' symbols
        trans = {self.symbols[i]: y_vec[i + 1] for i in range(self.nvariables)}
        # Map string represntation of 'modelparam' symbols onto string
        # representation of y-vec elements
        str_trans = {}
        for i in range(self.nvariables):
            str_trans[sym.fcode(self.symbols[i], source_format='free')] = \
                    sym.fcode(y_vec[i + 1], source_format='free')

        str_list = [key for key in str_trans]
        str_list.sort(key=len, reverse=True)

        # these will contain lists of strings, with each element being one
        # Fortran assignment for the master equation, Jacobian, and
        # rate expressions
        rescode = []
        jaccode = []
        ratecode = []

        # Convert symbolic master equation into a valid Fortran string
        for i in range(self.nvariables):
            fcode = sym.fcode(self.f_sym[i], source_format='free')
            # Replace modelparam symbols with their y_vec counterpart
            for key in str_list:
                fcode = fcode.replace(key, str_trans[key])
            # Create actual line of code for calculating residual
            rescode.append('   res({}) = '.format(i + 1) + fcode)

        # Effectively the same as above, except on the two-dimensional Jacobian
        # matrix.
        for i in range(self.nvariables):
            for j in range(self.nvariables):
                expr = self.jac_sym[j, i]
                # Unlike the residual, some elements of the Jacobian can be 0.
                # We don't need to bother writing 'jac(x,y) = 0' a hundred
                # times in Fortran, so we omit those.
                if expr != 0:
                    fcode = sym.fcode(expr, source_format='free')
                    for key in str_list:
                        fcode = fcode.replace(key, str_trans[key])
                    jaccode.append('   jac({}, {}) = '.format(j + 1, i + 1) +
                                   fcode)

        # See residual above
        for i, rate in enumerate(self.rates):
            fcode = sym.fcode(rate, source_format='free')
            for key in str_list:
                fcode = fcode.replace(key, str_trans[key])
            ratecode.append('   rates({}) = '.format(i + 1) + fcode)

        # We insert all of the parameters of this differential equation into
        # the prewritten Fortran template, including the residual, Jacobian,
        # and rate expressions we just calculated.
        program = f90_template.format(neq=self.nvariables,
                                      nx=1,
                                      nrates=len(self.rates),
                                      rescalc='\n'.join(rescode),
                                      jaccalc='\n'.join(jaccode),
                                      ratecalc='\n'.join(ratecode))

        # Generate a randomly-named temp directory for compiling the module.
        # We will name the actual module file after the directory.
        dname = tempfile.mkdtemp()
        modname = os.path.split(dname)[1]
        fname = modname + '.f90'
        pyfname = modname + '.pyf'

        # For debugging purposes, write out the generated module
        with open('solve_ida.f90', 'w') as f:
            f.write(program)

        # Write the pertinent data into the temp directory
        with open(os.path.join(dname, pyfname), 'w') as f:
            f.write(
                pyf_template.format(modname=modname,
                                    neq=self.nvariables,
                                    nrates=len(self.rates)))

        # Compile the module with f2py
        f2py.compile(program,
                     modulename=modname,
                     extra_args='--quiet '
                     '--f90flags="-Wno-unused-dummy-argument '
                     '-Wno-unused-variable -w -fopenmp" '
                     '-lsundials_fcvode '
                     '-lsundials_cvode -lsundials_fnvecopenmp '
                     '-lsundials_nvecopenmp -lopenblas_openmp -lgomp ' +
                     os.path.join(dname, pyfname),
                     source_fn=os.path.join(dname, fname),
                     verbose=0)

        # Delete the temporary directory
        shutil.rmtree(dname)

        # Import the module on-the-fly with __import__. This is kind of a hack.
        solve_ida = __import__(modname)

        # The Fortran module's initialize, solve, and finalize routines
        # are mapped onto finitialize, fsolve, and ffinalize inside the Model
        # object. We don't want users touching these manually
        self.finitialize = solve_ida.initialize
        self.ffind_steady_state = solve_ida.find_steady_state
        self.fsolve = solve_ida.solve
        self.ffinalize = solve_ida.finalize

        # Delete the module file. We've already imported it, so it's in memory.
        os.remove(modname + '.so')
Example #21
0
# + [markdown] {"slideshow": {"slide_type": "slide"}}
# ## Code printers
# The most basic form of code generation are the code printers. They convert SymPy expressions into over a dozen target languages.
#

# + {"slideshow": {"slide_type": "fragment"}}
x = symbols('x')
expr = abs(sin(x**2))
expr

# + {"slideshow": {"slide_type": "fragment"}}
sym.ccode(expr)

# + {"slideshow": {"slide_type": "fragment"}}
sym.fcode(expr, standard=2003, source_format='free')

# + {"slideshow": {"slide_type": "fragment"}}
from sympy.printing.cxxcode import cxxcode
cxxcode(expr)

# + {"slideshow": {"slide_type": "slide"}}
sym.tanh(x).rewrite(sym.exp)

# + {"slideshow": {"slide_type": "fragment"}}
from sympy import sqrt, exp, pi
expr = 1/sqrt(2*pi*sigma**2)* exp(-(x-mu)**2/(2*sigma**2))
print(sym.fcode(expr, standard=2003, source_format='free'))

# + [markdown] {"slideshow": {"slide_type": "slide"}}
# ## Creating a function from a symbolic expression
Example #22
0
def dalton_functional_printer(kernel,
                              routinename,
                              input_variables,
                              output_variables,
                              shortrange=False,
                              description=["No description.\n"],
                              diff_order=[1],
                              diff_idx=[[0]],
                              output_files=[]):
    """
    shortrange = True, if mu is an input parameter
    diff_order, is a list that indicatices how many of of each derivative that is present
       diff_order[0] = Energy, diff_order[1] = number of first derivatives
    diff_idx, is a list of lists that containts the idx of the given derivatives.
    """
    if len(diff_order) != len(diff_idx):
        print("ERROR: order of derivatives does not match number of idx lists")
    for i in range(0, len(diff_order)):
        if diff_order[i] != len(diff_idx[i]):
            print(
                "ERROR: Number of " + i +
                "'th derivatives does not match lenght of corrosponding idx list"
            )
    # Format kernel expression
    #kernel = kernel.evalf() # evalf is super slow!
    E_cse = cse(kernel, optimizations="basic")
    E_clean = []
    E_clean_temp = []
    for i in range(len(E_cse[0])):
        E_clean.append((E_cse[0][i][0], E_cse[0][i][1].evalf()))
    for i in range(len(E_cse[1])):
        E_clean_temp.append(E_cse[1][i].evalf())
    E_clean = (E_clean, E_clean_temp)
    string_list = []
    subroutine_input = ", ".join(input_variables)
    if shortrange == True:
        subroutine_input += ", mu"
    subroutine_input += ", " + ", ".join(
        output_variables[0:int(len(output_variables) / 4)])
    string_list.append(
        "C*****************************************************************************\n"
    )
    string_list.append("pure subroutine " + routinename + "(" +
                       subroutine_input + ")\n")
    string_list.append(
        "C*****************************************************************************\n"
    )
    for i in description:
        string_list.append("C   " + i)
    string_list.append("C\nC   Subroutine generated using Sympy " +
                       str(sympy.__version__) + "\n")
    string_list.append("C   Generated: " +
                       datetime.datetime.now().strftime("%B %d, %Y") + "\n")
    string_list.append(
        "C*****************************************************************************\n"
    )
    string_list.append("implicit none\n")
    string_list.append("real*8, intent(in) :: " + ", ".join(input_variables))
    if shortrange == True:
        string_list[-1] += ", mu"
    string_list[-1] += "\n"
    string_list.append(
        "real*8, intent(out) :: " +
        ", ".join(output_variables[0:int(len(output_variables) / 4)]) + "\n")
    if "d1Ea" in output_variables:
        string_list[-1] = string_list[-1].replace("d1Ea", "d1Ea(4)")
    else:
        string_list[-1] = string_list[-1].replace("d1E", "d1E(9)")
    if "d2Ea" in output_variables:
        string_list[-1] = string_list[-1].replace("d2Ea", "d2Ea(10)")
    else:
        string_list[-1] = string_list[-1].replace("d2E", "d2E(45)")
    string_list.append(
        "real*8 :: PBE_value, PBE_alpha_value, PBE_beta_value\n")
    if len(E_clean[0]) > 0:
        string_list.append("real*8 :: ")
        for term in E_clean[0]:
            for letter in str(
                    fcode(term[0],
                          source_format="free").replace('&\n      ', "")):
                string_list[-1] += letter
            if term != E_clean[0][-1]:
                string_list[-1] += ", "
        string_list[-1] += "\n"
    if len(diff_order) / 4 >= 1 and "Ea" in output_variables:
        string_list.append("Ea = 0.0d0\n")
    elif len(diff_order) / 4 >= 1:
        string_list.append("E = 0.0d0\n")
    if len(diff_order) / 4 >= 2 and "d1Ea" in output_variables:
        string_list.append("d1Ea(:) = 0.0d0\n")
    elif len(diff_order) / 4 >= 2:
        string_list.append("d1E(:) = 0.0d0\n")
    if len(diff_order) / 4 >= 3 and "d2Ea" in output_variables:
        string_list.append("d2Ea(:) = 0.0d0\n")
    elif len(diff_order) / 4 >= 3:
        string_list.append("d2E(:) = 0.0d0\n")

    for term in E_clean[0]:
        string_list.append(str(term[0]) + " = ")
        for letter in str(
                fcode(term[1],
                      source_format="free").replace('&\n      ', "").replace(
                          "parameter (pi = 3.1415926535897932d0)\n", "")):
            string_list[-1] += letter
        string_list[-1] += "\n"

    output_counter = 0
    diff_counter = 0
    term_counter = 0
    for term in E_clean[1]:
        if term_counter < 3:
            if term_counter == 0:
                string_list.append("PBE_value = ")
            elif term_counter == 2:
                string_list.append("PBE_alpha_value = ")
            elif term_counter == 1:
                string_list.append("PBE_beta_value = ")
            for letter in str(
                    fcode(term, source_format="free").replace(
                        '&\n      ',
                        "").replace("parameter (pi = 3.1415926535897932d0)\n",
                                    "")):
                string_list[-1] += letter
            string_list[-1] += "\n"
            term_counter += 1
        else:
            # divide by four because of 4 different cases
            if len(diff_order) / 4 - len(diff_order) / 4 == diff_counter:
                string_list.append(
                    "if ((PBE_alpha_value .ge. PBE_value) .and. (PBE_beta_value .ge. PBE_value)) then\n"
                )
            elif len(diff_order) / 4 * 2 - len(diff_order) / 4 == diff_counter:
                string_list.append("end if\n")
                string_list.append(
                    "if ((PBE_alpha_value .ge. PBE_value) .and. (PBE_beta_value .lt. PBE_value)) then\n"
                )
            elif len(diff_order) / 4 * 3 - len(diff_order) / 4 == diff_counter:
                string_list.append("end if\n")
                string_list.append(
                    "if ((PBE_alpha_value .lt. PBE_value) .and. (PBE_beta_value .ge. PBE_value)) then\n"
                )
            elif len(diff_order) / 4 * 4 - len(diff_order) / 4 == diff_counter:
                string_list.append("end if\n")
                string_list.append(
                    "if ((PBE_alpha_value .lt. PBE_value) .and. (PBE_beta_value .lt. PBE_value)) then\n"
                )

            if diff_idx[diff_counter][output_counter] == 0:
                string_list.append(output_variables[0] + " = ")
            else:
                string_list.append(
                    output_variables[diff_counter] + "(" +
                    str(diff_idx[diff_counter][output_counter]) + ") = ")
            for letter in str(
                    fcode(term, source_format="free").replace(
                        '&\n      ',
                        "").replace("parameter (pi = 3.1415926535897932d0)\n",
                                    "")):
                string_list[-1] += letter
            string_list[-1] += "\n"
            output_counter += 1
            if diff_order[diff_counter] == output_counter:
                output_counter = 0
                diff_counter += 1

    string_list.append("end if\n")

    string_list.append("end subroutine")
    for output_file in output_files:
        print_function(string_list, output_file)
Example #23
0
    def setup_execs(self):
        from micki.fortran import f90_template, pyf_template
        from numpy import f2py

        # y_vec is an array symbol that will represent the species
        # concentrations provided by the differential equation solver inside
        # the Fortran code (that is, y_vec is an INPUT to the functions that
        # calculate the residual, Jacobian, and rate)
        y_vec = sym.IndexedBase('yin', shape=(self.nvariables,))
        # Map y_vec elements (1-indexed, of course) onto 'modelparam' symbols
        trans = {self.symbols[i]: y_vec[i + 1] for i in range(self.nvariables)}
        # Map string represntation of 'modelparam' symbols onto string
        # representation of y-vec elements
        str_trans = {}
        for i in range(self.nvariables):
            str_trans[sym.fcode(self.symbols[i], source_format='free')] = \
                    sym.fcode(y_vec[i + 1], source_format='free')
        
        str_list = [key for key in str_trans]
        str_list.sort(key=len, reverse=True)

        # these will contain lists of strings, with each element being one
        # Fortran assignment for the master equation, Jacobian, and
        # rate expressions
        rescode = []
        jaccode = []
        ratecode = []

        # Convert symbolic master equation into a valid Fortran string
        for i in range(self.nvariables):
            fcode = sym.fcode(self.f_sym[i], source_format='free')
            # Replace modelparam symbols with their y_vec counterpart
            for key in str_list:
                fcode = fcode.replace(key, str_trans[key])
            # Create actual line of code for calculating residual
            rescode.append('   res({}) = '.format(i + 1) + fcode)

        # Effectively the same as above, except on the two-dimensional Jacobian
        # matrix.
        for i in range(self.nvariables):
            for j in range(self.nvariables):
                expr = self.jac_sym[j, i]
                # Unlike the residual, some elements of the Jacobian can be 0.
                # We don't need to bother writing 'jac(x,y) = 0' a hundred
                # times in Fortran, so we omit those.
                if expr != 0:
                    fcode = sym.fcode(expr, source_format='free')
                    for key in str_list:
                        fcode = fcode.replace(key, str_trans[key])
                    jaccode.append('   jac({}, {}) = '.format(j + 1, i + 1) +
                                   fcode)

        # See residual above
        for i, rate in enumerate(self.rates):
            fcode = sym.fcode(rate, source_format='free')
            for key in str_list:
                fcode = fcode.replace(key, str_trans[key])
            ratecode.append('   rates({}) = '.format(i + 1) + fcode)

        # We insert all of the parameters of this differential equation into
        # the prewritten Fortran template, including the residual, Jacobian,
        # and rate expressions we just calculated.
        program = f90_template.format(neq=self.nvariables, nx=1,
                                      nrates=len(self.rates),
                                      rescalc='\n'.join(rescode),
                                      jaccalc='\n'.join(jaccode),
                                      ratecalc='\n'.join(ratecode))

        # Generate a randomly-named temp directory for compiling the module.
        # We will name the actual module file after the directory.
        dname = tempfile.mkdtemp()
        modname = os.path.split(dname)[1]
        fname = modname + '.f90'
        pyfname = modname + '.pyf'

        # For debugging purposes, write out the generated module
        with open('solve_ida.f90', 'w') as f:
            f.write(program)

        # Write the pertinent data into the temp directory
        with open(os.path.join(dname, pyfname), 'w') as f:
            f.write(pyf_template.format(modname=modname, neq=self.nvariables,
                    nrates=len(self.rates)))

        # Compile the module with f2py
        f2py.compile(program, modulename=modname,
                     extra_args='--quiet '
                                '--f90flags="-Wno-unused-dummy-argument '
                                '-Wno-unused-variable -w -fopenmp" ' 
                                '-lsundials_fcvode '
                                '-lsundials_cvode -lsundials_fnvecopenmp '
                                '-lsundials_nvecopenmp -lopenblas_openmp -lgomp ' +
                                os.path.join(dname, pyfname),
                     source_fn=os.path.join(dname, fname), verbose=0)

        # Delete the temporary directory
        shutil.rmtree(dname)

        # Import the module on-the-fly with __import__. This is kind of a hack.
        solve_ida = __import__(modname)

        # The Fortran module's initialize, solve, and finalize routines
        # are mapped onto finitialize, fsolve, and ffinalize inside the Model
        # object. We don't want users touching these manually
        self.finitialize = solve_ida.initialize
        self.ffind_steady_state = solve_ida.find_steady_state
        self.fsolve = solve_ida.solve
        self.ffinalize = solve_ida.finalize

        # Delete the module file. We've already imported it, so it's in memory.
        os.remove(modname + '.so')
Example #24
0
def sympy_to_muparser(expr):
    code = sympy.fcode(expr)
    code = code.replace('\n     @', '')
    code = code.replace('**', '^')
    return code
Example #25
0
                       modules=_lambdify_modules)


_ufns = {'argmax': 'argmax'}

#pylint: disable=unnecessary-lambda
_code_printers = {
    'c':
    lambda expr, **kw: sp.ccode(
        expr, standard='c99', user_functions=_ufns, **kw),
    'cxx':
    lambda expr, **kw: sp.cxxcode(expr, user_functions=_ufns, **kw),
    'rust':
    lambda expr, **kw: sp.rust_code(expr, user_functions=_ufns, **kw),
    'fortran':
    lambda expr, **kw: sp.fcode(expr, standard=95, user_functions=_ufns, **kw),
    'js':
    lambda expr, **kw: sp.jscode(expr, user_functions=_ufns, **kw),
    'r':
    lambda expr, **kw: sp.rcode(expr, user_functions=_ufns, **kw),
    'julia':
    lambda expr, **kw: sp.julia_code(expr, user_functions=_ufns, **kw),
    'mathematica':
    lambda expr, assign_to=None, **kw: sp.mathematica_code(
        expr, user_functions=_ufns, **kw),
    'octave':
    lambda expr, **kw: sp.octave_code(expr, user_functions=_ufns, **kw),
}


def to_code(syexpr, dialect, assign_to='y', **kw):