Esempio n. 1
0
    def process_scalar_bin(holder, label):
        assign = []
        dassign = []
        deplabels = np.zeros((num_equations, num_equations), 'O')
        deplabels[:] = 'none'
        for (i, x) in enumerate(holder):
            if x:
                xstr = "c[('%s', %d)][:] = %s" % (label, i, x)
                assign.append(xstr)
                for j, psi in enumerate(unk_scalar_fields):
                    dx = differentiate(x, psi)
                    if dx:
                        deplabels[i][j] = classify_dep(dx)
                        if deplabels[i][j] == 'nonlinear' \
                           or deplabels[i][j] == 'linear':
                            dxstr = "c[('d%s', %d, %d)][:] = %s" % (label, i, j, dx)
                            dassign.append(dxstr)
                    else:
                        pass

        return assign, dassign, deplabels
Esempio n. 2
0
def generate_proteus_problem_file(bvp, clsnm):
    from ibvp.language import scalarize
    scalarized_system = scalarize(bvp)

    #import ibvp.sym as sym
    #print(sym.pretty(scalarized_system.pde_system))

    distr_system = DistributeMapper()(scalarized_system.pde_system)

    scalar_unknowns = [v.name for v in scalarized_system.unknowns]

    num_equations = len(scalar_unknowns)
    ambient_dim = bvp.ambient_dim

    if len(set(scalar_unknowns)) != len(scalar_unknowns):
        raise ValueError("names of unknowns not unique "
                "after scalarization")

    # import ibvp.sym as sym
    # print sym.pretty(distr_system)

    tc_storage = TransportCoefficientStorage(scalarized_system,
                                             bvp.ambient_dim,
                                             scalar_unknowns)

    has_time_derivative = HasTimeDerivativeMapper()
    has_spatial_derivative = HasSpatialDerivativeMapper()

    for i, eqn_i in enumerate(distr_system):
        if isinstance(eqn_i, pp.Sum):
            terms = eqn_i.children
        else:
            terms = (eqn_i,)

        for term in terms:
            constant, term_without_constant = pick_off_constants(term)

            if isinstance(term_without_constant, p.OperatorBinding):
                op = term_without_constant.op

                if isinstance(op, p.TimeDerivativeOperator):
                    if has_spatial_derivative(term_without_constant.argument):
                        raise ValueError("no spatial derivatives allowed inside "
                                "of time derivative")
                    tc_storage.mass[i] += (
                            constant * term_without_constant.argument)
                    continue

                if has_time_derivative(term_without_constant):
                    raise ValueError("time derivatives found below "
                            "root of tree of term '%s'" % pretty(term))

                if isinstance(op, p.DerivativeOperator):
                    outer_deriv_axis = term_without_constant.op.ambient_axis
                    outer_deriv_argument = term_without_constant.argument

                    if not has_spatial_derivative(outer_deriv_argument):
                        tc_storage.advection[i, outer_deriv_axis] += (
                                constant * outer_deriv_argument)
                    else:
                        # diffusion
                        coeff, inner_derivative = \
                                find_inner_deriv_and_coeff(outer_deriv_argument)

                        pot_const, pot_expr = pick_off_constants(
                                inner_derivative.argument)
                        pot_index = tc_storage.register_potential(pot_expr)

                        tc_storage.diffusion[
                                i, pot_index,
                                outer_deriv_axis,
                                inner_derivative.op.ambient_axis] \
                                        += pot_const*coeff

                else:
                    raise ValueError("unexpected operator: %s"
                            % type(term_without_constant.op).__name__)
            else:
                if has_time_derivative(term_without_constant):
                    raise ValueError("time derivatives found below "
                            "root of tree of term '%s'" % pretty(term))

                if has_spatial_derivative(term_without_constant):
                    tc_storage.hamiltonian[i] += term
                else:
                    tc_storage.reaction[i] += term

    # Python code we generate, we create references to the coefficient arrays
    # in the dictionary that will conveniently have the same name as our
    # pymbolic variables.  This makes printing easy and has no major
    # performance penalty.

    defs_list = ["    %s = c[('u', %d)]" % (str(v), i)
                 for (i, v) in enumerate(scalar_unknowns)]

    defs = '\n'.join(defs_list)  # noqa

    unk_scalar_fields = [p.Field(psi) for psi in scalar_unknowns]

    def process_scalar_bin(holder, label):
        assign = []
        dassign = []
        deplabels = np.zeros((num_equations, num_equations), 'O')
        deplabels[:] = 'none'
        for (i, x) in enumerate(holder):
            if x:
                xstr = "c[('%s', %d)][:] = %s" % (label, i, x)
                assign.append(xstr)
                for j, psi in enumerate(unk_scalar_fields):
                    dx = differentiate(x, psi)
                    if dx:
                        deplabels[i][j] = classify_dep(dx)
                        if deplabels[i][j] == 'nonlinear' \
                           or deplabels[i][j] == 'linear':
                            dxstr = "c[('d%s', %d, %d)][:] = %s" % (label, i, j, dx)
                            dassign.append(dxstr)
                    else:
                        pass

        return assign, dassign, deplabels

    mass_assigns, dmass_assigns, mass_deps \
        = process_scalar_bin(tc_storage.mass, "m")

    for md in mass_deps.ravel():
        if md == 'constant':
            raise Exception("Constant mass illegal")

    reaction_assigns, dreaction_assigns, reaction_deps \
        = process_scalar_bin(tc_storage.reaction, "r")

    hamiltonian_assigns, dhamiltonian_assigns, hamiltonian_deps \
        = process_scalar_bin(tc_storage.hamiltonian, "h")

    advect_assigns = []
    dadvect_assigns = []

    advect_deps_p = np.zeros((num_equations, num_equations, ambient_dim), 'O')
    advect_deps_p[:] = 'none'

    for i, bi in enumerate(tc_storage.advection):
        for j, bij in enumerate(bi):
            if bij:
                bstr = "c[('f', %d)][..., %d] = %s" % (i, j, bij)
                advect_assigns.append(bstr)
                for k, psi in enumerate(unk_scalar_fields):
                    dbij = differentiate(bij, psi)
                    if dbij:
                        advect_deps_p[i, k, j] = classify_dep(dbij)
                        dbstr = "c[('df', %d, %d)][...,%d] = %s" % (i, k, j, dbij)
                        dadvect_assigns.append(dbstr)

    # now "reduce" over the vector component dependences and take the worst.
    dep2int = {'none': 0,
               'constant':  1,
               'linear':    2,
               'nonlinear': 3}
    from pytools import reverse_dictionary
    int2dep = reverse_dictionary(dep2int)

    advect_deps = np.zeros((num_equations, num_equations), "O")
    for i in range(num_equations):
        for j in range(num_equations):
            advect_deps[i, j] = int2dep[
                    reduce(max,
                        (dep2int[x] for x in advect_deps_p[i, j, :]),
                        0)
                    ]

    diff_assigns = []
    ddiff_assigns = []
    diff_deps_p = np.zeros((num_equations,
                            num_equations,
                            num_equations,
                            ambient_dim,
                            ambient_dim), 'O')

    diff_deps_p[:] = 'none'

    for i, ai in enumerate(tc_storage.diffusion):
        for j, aij in enumerate(ai):
            for k, aijk in enumerate(aij):
                for ell, aijkell in enumerate(aijk):
                    if aijkell:
                        astr = "c[('a', %d, %d)][..., %d, %d] = %s" \
                               % (i, j, k, ell, aijkell)
                        diff_assigns.append(astr)
                        for q, psi in enumerate(unk_scalar_fields):
                            da = differentiate(aijkell, psi)
                            if da:
                                diff_deps_p[i, j, q, k, ell] = classify_dep(da)
                                dastr = "c[('da',%d,%d,%d)][...,%d,%d] = %s" \
                                        % (i, j, q, k, ell, da)
                                ddiff_assigns.append(dastr)
                            else:
                                diff_deps_p[i, j, q, k, ell] = 'constant'

    diff_deps = np.zeros((num_equations,
                          num_equations,
                          num_equations), 'O')

    ddp = diff_deps_p.reshape((num_equations,
                               num_equations,
                               num_equations,
                               ambient_dim**2))

    for i in range(num_equations):
        for j in range(num_equations):
            for k in range(num_equations):
                diff_deps[i, j, k] = int2dep[
                                        reduce(max,
                                            (dep2int[x] for x in ddp[i, j, k]), 0)]

    # potential is a bit different from other scalars.
    potential_assigns = []
    dpotential_assigns = []

    phi_deps = np.zeros((num_equations, num_equations), 'O')
    for i, phi in enumerate(tc_storage.potential):
        for j, u in enumerate(unk_scalar_fields):
            if phi == u:
                phi_deps[i, j] = 'u'
            else:
                phi_str = "c[('phi', %d)] = %s" % (i, phi)
                potential_assigns.extend(phi_str)
                D = differentiate(phi, u)
                if D:
                    phi_deps[i, j] = 'nonlinear'
                    dphi_str = "c[('dphi', %d, %d)] = %s" % (i, j, D)
                    dpotential_assigns.extend(dphi_str)

    def spacer(x):
        return "        " + x

    assigns = "\n".join(
                map(spacer,
                    reduce(lambda x, y: x+y,
                           [mass_assigns, dmass_assigns,
                            advect_assigns, dadvect_assigns,
                            diff_assigns, ddiff_assigns,
                            reaction_assigns, dreaction_assigns,
                            hamiltonian_assigns, dhamiltonian_assigns])))

    # we dict-ify the dependencies so we can repr them.
    def dictify(arr):
        if len(arr.shape) == 1:
            return dict((i, a) for (i, a) in enumerate(arr) if a and a != 'none')
        else:
            result = {}
            for i, a in enumerate(arr):
                da = dictify(a)
                if len(da) > 0:
                    result[i] = da
            return result

    names = ["mass", "advection", "diffusion", "potential",
            "reaction", "hamiltonian"]
    deps = [mass_deps, advect_deps, diff_deps, phi_deps,
            reaction_deps, hamiltonian_deps]

    dep_stmnts = []
    for (nm, d) in zip(names, deps):
        ddict = dictify(d)
        dep_stmnts.append("        %s = %s" % (nm, repr(ddict)))

    dep_st = "\n".join(dep_stmnts)

    # This is for creating, e.g. u = c[('u',0)] before we make assignments
    # in evaluate so that we have references into the c dictionary for our
    # data.  This makes the pretty-printed code more readable.
    ref_list = []
    for i, phi in enumerate(scalar_unknowns):
        ref_list.append("%s = c[('u',%d)]" % (phi, i))

    refs = "\n".join((spacer(x) for x in ref_list))

    tc_class_str = """
from proteus.TransportCoefficients import TC_base

class %s(TC_base):
    def __init__(self):
%s
        variableNames=%s
        TC_base.__init__(self,
                         nc=%d,
                         mass=mass,
                         advection=advection,
                         diffusion=diffusion,
                         potential=potential,
                         reaction=reaction,
                         hamiltonian=hamiltonian,
                         variableNames=variableNames)

    def evaluate(self, t, c):
%s
%s
""" % (clsnm, dep_st, repr(scalar_unknowns), num_equations, refs, assigns)

    return(tc_class_str)