Example #1
0
def test_3d_4b():
    """Alfven operator."""
    x, y, z = symbols('x y z')

    u = IndexedBase('u')
    v = IndexedBase('v')

    bx = Constant('bx')
    by = Constant('by')
    bz = Constant('bz')
    b = Tuple(bx, by, bz)

    c0, c1, c2 = symbols('c0 c1 c2')

    a = Lambda((x, y, z, v, u),
               (c0 * Dot(u, v) - c1 * Div(u) * Div(v) +
                c2 * Dot(Curl(Cross(b, u)), Curl(Cross(b, v)))))
    print('> input       := {0}'.format(a))

    # ...
    expr = construct_weak_form(a, dim=DIM, is_block=True, verbose=True)
    print('> weak form := {0}'.format(expr))
    # ...

    print('')
Example #2
0
def test_3d_3():
    x, y, z = symbols('x y z')

    u = IndexedBase('u')
    v = IndexedBase('v')

    a = Lambda((x, y, z, v, u), Dot(Curl(u), Curl(v)) + 0.2 * Dot(u, v))
    print('> input       := {0}'.format(a))

    # ...
    expr = construct_weak_form(a, dim=DIM, is_block=True, verbose=True)
    print('> weak form := {0}'.format(expr))
    # ...

    print('')
Example #3
0
def test_3d_1():
    x, y, z = symbols('x y z')

    u = Symbol('u')
    v = Symbol('v')

    a = Lambda((x, y, z, v, u), Dot(Grad(u), Grad(v)))
    print('> input       := {0}'.format(a))

    # ...
    expr = construct_weak_form(a, dim=DIM)
    print('> weak form := {0}'.format(expr))
    # ...

    print('')
Example #4
0
def test_1d_3():
    x = Symbol('x')

    u0, u1 = symbols('u0 u1')
    v0, v1 = symbols('v0 v1')

    a = Lambda((x,v0,v1,u0,u1), dx(u0)*dx(v0) + dx(u1)*v0 + u0*dx(v1) + u1*v1)
    print('> input       := {0}'.format(a))

    # ...
    expr = construct_weak_form(a, dim=DIM, is_block=True)
    print('> weak form := {0}'.format(expr))
    # ...

    print('')
Example #5
0
def test_2d_3():
    x, y = symbols('x y')

    u = Symbol('u')
    v = Symbol('v')

    a = Lambda((x, y, v, u), Cross(Curl(u), Curl(v)) + 0.2 * u * v)
    print('> input       := {0}'.format(a))

    # ...
    expr = construct_weak_form(a, dim=DIM, is_block=True)
    print('> weak form := {0}'.format(expr))
    # ...

    print('')
Example #6
0
def test_2d_2():
    x, y = symbols('x y')

    u = IndexedBase('u')
    v = IndexedBase('v')

    a = Lambda((x, y, v, u),
               Rot(u) * Rot(v) + Div(u) * Div(v) + 0.2 * Dot(u, v))
    print('> input       := {0}'.format(a))

    # ...
    expr = construct_weak_form(a, dim=DIM, is_block=True, verbose=True)
    print('> weak form := {0}'.format(expr))
    # ...

    print('')
Example #7
0
def test_1d_4():
    x = Symbol('x')

    u = Symbol('u')
    v = Symbol('v')

    b = Function('b')

    a = Lambda((x,v,u), Dot(Grad(u), Grad(v)) + b(x)*u*v)
    print('> input     := {0}'.format(a))

    # ...
    expr = construct_weak_form(a, dim=DIM)
    print('> weak form := {0}'.format(expr))
    # ...

    print('')
Example #8
0
def test_2d_4():
    x, y = symbols('x y')

    u = Symbol('u')
    v = Symbol('v')

    bx = Constant('bx')
    by = Constant('by')
    b = Tuple(bx, by)

    a = Lambda((x, y, v, u), 0.2 * u * v + Dot(b, Grad(v)) * u)
    print('> input       := {0}'.format(a))

    # ...
    expr = construct_weak_form(a, dim=DIM, is_block=False)
    print('> weak form := {0}'.format(expr))
    # ...

    print('')
Example #9
0
def glt_symbol(expr,
               n_deriv=1,
               space=None,
               verbose=False,
               evaluate=False,
               is_block=False,
               discretization=None,
               instructions=[],
               **settings):
    """
    computes the glt symbol of a weak formulation given as a sympy expression.

    expr: sympy.Expression
        a sympy expression or a text

    space: spl.fem.SplineSpace, spl.fem.TensorFemSpace, spl.fem.VectorFemSpace
        a Finite elements space from spl. Default: None

    n_deriv: int
        maximum derivatives that appear in the weak formulation.

    verbose: bool
        talk more

    evaluate: bool
        causes the evaluation of the atomic symbols, if true

    is_block: bool
        treat a block prolbem if True. Must be supplied only when using
        discretization. Otherwise, the fem space should be consistent with the
        weak formulation.

    discretization: dict
        a dictionary that contains the used discretization

    instructions: list
        a list to keep track of the applied instructions.

    settings: dict
        dictionary for different settings

    """
    # ...
    if not isinstance(expr, Lambda):
        raise TypeError('Expecting a Lambda expression')
    # ...

    # ...
    if not (discretization is None):
        dim = len(discretization['n_elements'])

    elif not (space is None):
        dim = space.pdim

        n_elements = space.ncells
        if not (isinstance(n_elements, (list, tuple))):
            n_elements = [n_elements]

        degrees = space.degree
        if not (isinstance(degrees, (list, tuple))): degrees = [degrees]

        discretization = {'n_elements': n_elements, 'degrees': degrees}

        from spl.fem.vector import VectorFemSpace
        is_block = isinstance(space, VectorFemSpace)

        if is_block:
            # TODO make sure all degrees are the same?
            #      or remove discretization and use only the space
            discretization['degrees'] = degrees[0]

        # TODO check that the weak form is consistent with the space (both are blocks)

    else:
        raise ValueError('discretization (dict) or fem space must be given')
    # ...

    # ...
    expr = construct_weak_form(expr,
                               dim=dim,
                               is_block=is_block,
                               verbose=verbose)
    # ...

    # ...
    if verbose:
        print("*** Input expression : ", expr)
    # ...

    # ...
    if type(expr) == dict:
        d_expr = {}
        for key, txt in list(expr.items()):
            # ... when using vale, we may get also a coefficient.
            if type(txt) == list:
                txt = str(txt[0]) + " * (" + txt[1] + ")"
            # ...

            # ...
            title = "Computing the GLT symbol for the block " + str(key)
            instructions.append(latex_title_as_paragraph(title))
            # ...

            # ...
            d_expr[key] = glt_symbol(txt,
                                     n_deriv=n_deriv,
                                     verbose=verbose,
                                     evaluate=evaluate,
                                     discretization=discretization,
                                     instructions=instructions,
                                     **settings)
            # ...

        if len(d_expr) == 1:
            key = d_expr.keys()[0]
            return d_expr[key]

        return dict_to_matrix(d_expr, instructions=instructions, **settings)
    else:
        # ...
        ns = {}
        # ...

        # ...
        d = basis_symbols(dim, n_deriv)
        for key, item in list(d.items()):
            ns[key] = item
        # ...

        # ...
        if isinstance(expr, Lambda):
            expr = normalize_weak_from(expr)
        # ...

        # ...
        expr = sympify(expr, locals=ns)
        expr = expr.expand()
        # ...
    # ...

    # ...
    if verbose:
        # ...
        instruction = "We consider the following weak formulation:"
        instructions.append(instruction)
        instructions.append(glt_latex(expr, **settings))
        # ...

        print(">>> weak formulation: ", expr)
    # ...

    # ...
    expr = apply_mapping(expr, dim=dim, \
                         instructions=instructions, \
                         **settings)
    if verbose:
        print('>>> apply mapping: ', expr)
    # ...

    # ...
    expr = apply_tensor(expr, dim=dim, \
                         instructions=instructions, \
                         **settings)
    if verbose:
        print('>>> apply tensor: ', expr)
    # ...

    # ...
    expr = apply_factor(expr, dim, \
                         instructions=instructions, \
                         **settings)
    if verbose:
        print('>>> apply factor: ', expr)
    # ...

    # ...
    if not evaluate:
        return expr
    # ...

    # ...
    if not discretization:
        return expr
    # ...

    # ...
    expr = glt_update_atoms(expr, discretization)
    # ...

    return expr
Example #10
0
def compile_kernel(name,
                   expr,
                   V,
                   namespace=globals(),
                   verbose=False,
                   d_constants={},
                   d_args={},
                   context=None,
                   backend='python',
                   export_pyfile=True):
    """returns a kernel from a Lambda expression on a Finite Elements space."""

    from spl.fem.vector import VectorFemSpace
    from spl.fem.splines import SplineSpace
    from spl.fem.tensor import TensorFemSpace

    # ... parametric dimension
    dim = V.pdim
    # ...

    # ... number of partial derivatives
    #     TODO must be computed from the weak form then we re-initialize the
    #     space
    if isinstance(V, SplineSpace):
        nderiv = V.nderiv
    elif isinstance(V, TensorFemSpace):
        nderiv = max(W.nderiv for W in V.spaces)
    elif isinstance(V, VectorFemSpace):
        nds = []
        for W in V.spaces:
            if isinstance(W, SplineSpace):
                nderiv = W.nderiv
            elif isinstance(W, TensorFemSpace):
                nderiv = max(X.nderiv for X in W.spaces)
            nds.append(nderiv)
        nderiv = max(nds)
    # ...

    # ...
    if verbose:
        print('> input     := {0}'.format(expr))
    # ...

    # ...
    fields = [i for i in expr.free_symbols if isinstance(i, Field)]
    if verbose:
        print('> Fields = ', fields)
    # ...

    # ...
    expr = construct_weak_form(expr,
                               dim=dim,
                               is_block=isinstance(V, VectorFemSpace))
    if verbose:
        print('> weak form := {0}'.format(expr))
    # ...

    # ... contants
    #     for each argument, we compute its datatype (needed for Pyccel)
    #     case of Numeric Native Python types
    #     this means that a has a given value (1, 1.0 etc)
    if d_constants:
        for k, a in list(d_constants.items()):
            if not isinstance(a, Number):
                raise TypeError('Expecting a Python Numeric object')

        # update the weak formulation using the given arguments
        _d = {}
        for k, v in list(d_constants.items()):
            if isinstance(k, str):
                _d[Constant(k)] = v
            else:
                _d[k] = v

        expr = expr.subs(_d)

    args = ''
    dtypes = ''
    if d_args:
        # ... additional arguments
        #     for each argument, we compute its datatype (needed for Pyccel)
        for k, a in list(d_args.items()):
            # otherwise it can be a string, that specifies its type
            if not isinstance(a, str):
                raise TypeError('Expecting a string')

            if not a in ['int', 'double', 'complex']:
                raise TypeError('Wrong type for {} :: {}'.format(k, a))

        # we convert the dictionaries to OrderedDict, to avoid wrong ordering
        d_args = OrderedDict(sorted(list(d_args.items())))

        names = []
        dtypes = []
        for n, d in list(d_args.items()):
            names.append(n)
            dtypes.append(d)

        args = ', '.join('{}'.format(a) for a in names)
        dtypes = ', '.join('{}'.format(a) for a in dtypes)

        args = ', {}'.format(args)
        dtypes = ', {}'.format(dtypes)

        # TODO check what are the free_symbols of expr,
        #      to make sure the final code will compile
        #      the remaining free symbols must be the trial/test basis functions,
        #      and the coordinates
    # ...

    # ...
    if isinstance(V, VectorFemSpace) and not (V.is_block):
        raise NotImplementedError(
            'We only treat the case of a block space, for '
            'which all components have are identical.')
    # ...

    # ...
    pattern = 'scalar'
    if isinstance(V, VectorFemSpace):
        if V.is_block:
            pattern = 'block'

        else:
            raise NotImplementedError(
                'We only treat the case of a block space, for '
                'which all components have are identical.')

    # ...

    # ...
    template_str = 'template_{dim}d_{pattern}'.format(dim=dim, pattern=pattern)
    try:
        template = eval(template_str)
    except:
        raise ValueError('Could not find the corresponding template {}'.format(
            template_str))
    # ...

    # ... identation (def function body)
    tab = ' ' * 4
    # ...

    # ... field coeffs
    if fields:
        field_coeffs = OrderedDict()
        for f in fields:
            coeffs = 'coeff_{}'.format(f.name)
            field_coeffs[str(f.name)] = coeffs

        ls = [v for v in list(field_coeffs.values())]
        field_coeffs_str = ', '.join(i for i in ls)

        # add ',' for kernel signature
        field_coeffs_str = ', {}'.format(field_coeffs_str)

        eval_field_str = print_eval_field(expr,
                                          V.pdim,
                                          fields,
                                          verbose=verbose)

        # ...
        if dim == 1:
            e_pattern = '{field}{deriv} = {field}{deriv}_values[g1]'
        elif dim == 2:
            e_pattern = '{field}{deriv} = {field}{deriv}_values[g1,g2]'
        elif dim == 3:
            e_pattern = '{field}{deriv} = {field}{deriv}_values[g1,g2,g3]'
        else:
            raise NotImplementedError('only 1d, 2d and 3d are available')

        field_values = OrderedDict()
        free_names = [str(f.name) for f in expr.free_symbols]
        for f in fields:
            ls = []
            if f.name in free_names:
                ls.append(f.name)
            for deriv in BASIS_PREFIX:
                f_d = '{field}_{deriv}'.format(field=f.name, deriv=deriv)
                if f_d in free_names:
                    ls.append(f_d)

            field_values[f.name] = ls

        tab_base = tab
        # ... update identation to be inside the loop
        for i in range(0, 3 * dim):
            tab += ' ' * 4

        lines = []
        for k, fs in list(field_values.items()):
            coeff = field_coeffs[k]
            for f in fs:
                ls = f.split('_')
                if len(ls) == 1:
                    deriv = ''
                else:
                    deriv = '_{}'.format(ls[-1])
                line = e_pattern.format(field=k, deriv=deriv)
                line = tab + line

                lines.append(line)

        field_value_str = '\n'.join(line for line in lines)
        tab = tab_base
        # ...

        # ...
        field_types = []
        slices = ','.join(':' for i in range(0, dim))
        for v in list(field_coeffs.values()):
            field_types.append('double [{slices}]'.format(slices=slices))

        field_types_str = ', '.join(i for i in field_types)
        field_types_str = ', {}'.format(field_types_str)
        # ...

    else:
        field_coeffs_str = ''
        eval_field_str = ''
        field_value_str = ''
        field_types_str = ''

    # ...

    # ... compute indentation
    tab_base = tab
    for i in range(0, 3 * dim):
        tab += ' ' * 4
    # ...

    # ... print test functions
    d_test_basis = construct_test_functions(nderiv, dim)
    test_names = [i.name for i in expr.free_symbols if is_test_function(i)]
    test_names.sort()

    lines = []
    for a in test_names:
        if a == 'Ni':
            basis = ' * '.join(d_test_basis[k, 0] for k in range(1, dim + 1))
            line = 'Ni = {basis}'.format(basis=basis)
        else:
            deriv = a.split('_')[-1]
            nx = _count_letter(deriv, 'x')
            ny = _count_letter(deriv, 'y')
            nz = _count_letter(deriv, 'z')
            basis = ' * '.join(d_test_basis[k, d]
                               for k, d in zip(range(1, dim +
                                                     1), [nx, ny, nz]))
            line = 'Ni_{deriv} = {basis}'.format(deriv=deriv, basis=basis)
        lines.append(tab + line)
    test_function_str = '\n'.join(l for l in lines)
    # ...

    # ... print trial functions
    d_trial_basis = construct_trial_functions(nderiv, dim)
    trial_names = [i.name for i in expr.free_symbols if is_trial_function(i)]
    trial_names.sort()

    lines = []
    for a in trial_names:
        if a == 'Nj':
            basis = ' * '.join(d_trial_basis[k, 0] for k in range(1, dim + 1))
            line = 'Nj = {basis}'.format(basis=basis)
        else:
            deriv = a.split('_')[-1]
            nx = _count_letter(deriv, 'x')
            ny = _count_letter(deriv, 'y')
            nz = _count_letter(deriv, 'z')
            basis = ' * '.join(d_trial_basis[k, d]
                               for k, d in zip(range(1, dim +
                                                     1), [nx, ny, nz]))
            line = 'Nj_{deriv} = {basis}'.format(deriv=deriv, basis=basis)
        lines.append(tab + line)
    trial_function_str = '\n'.join(l for l in lines)
    # ...

    # ...
    tab = tab_base
    # ...

    # ...
    if isinstance(V, VectorFemSpace):
        if V.is_block:
            n_components = len(V.spaces)

            # ... - initializing element matrices
            #     - define arguments
            lines = []
            mat_args = []
            slices = ','.join(':' for i in range(0, 2 * dim))
            for i in range(0, n_components):
                for j in range(0, n_components):
                    mat = 'mat_{i}{j}'.format(i=i, j=j)
                    mat_args.append(mat)

                    line = '{mat}[{slices}] = 0.0'.format(mat=mat,
                                                          slices=slices)
                    line = tab + line

                    lines.append(line)

            mat_args_str = ', '.join(mat for mat in mat_args)
            mat_init_str = '\n'.join(line for line in lines)
            # ...

            # ... update identation to be inside the loop
            for i in range(0, 2 * dim):
                tab += ' ' * 4

            tab_base = tab
            # ...

            # ... initializing accumulation variables
            lines = []
            for i in range(0, n_components):
                for j in range(0, n_components):
                    line = 'v_{i}{j} = 0.0'.format(i=i, j=j)
                    line = tab + line

                    lines.append(line)

            accum_init_str = '\n'.join(line for line in lines)
            # ...

            # .. update indentation
            for i in range(0, dim):
                tab += ' ' * 4
            # ...

            # ... accumulation contributions
            lines = []
            for i in range(0, n_components):
                for j in range(0, n_components):
                    line = 'v_{i}{j} += ({__WEAK_FORM__}) * wvol'
                    e = _convert_int_to_float(expr[i, j].evalf())
                    # we call evalf to avoid having fortran doing the evaluation of rational
                    # division
                    line = line.format(i=i, j=j, __WEAK_FORM__=e)
                    line = tab + line

                    lines.append(line)

            accum_str = '\n'.join(line for line in lines)
            # ...

            # ... assign accumulated values to element matrix
            if dim == 1:
                e_pattern = 'mat_{i}{j}[il_1, p1 + jl_1 - il_1] = v_{i}{j}'
            elif dim == 2:
                e_pattern = 'mat_{i}{j}[il_1, il_2, p1 + jl_1 - il_1, p2 + jl_2 - il_2] = v_{i}{j}'
            elif dim == 3:
                e_pattern = 'mat_{i}{j}[il_1, il_2, il_3, p1 + jl_1 - il_1, p2 + jl_2 - il_2, p3 + jl_3 - il_3] = v_{i}{j}'
            else:
                raise NotImplementedError('only 1d, 2d and 3d are available')

            tab = tab_base
            lines = []
            for i in range(0, n_components):
                for j in range(0, n_components):
                    line = e_pattern.format(i=i, j=j)
                    line = tab + line

                    lines.append(line)

            accum_assign_str = '\n'.join(line for line in lines)
            # ...

            code = template.format(__KERNEL_NAME__=name,
                                   __MAT_ARGS__=mat_args_str,
                                   __FIELD_COEFFS__=field_coeffs_str,
                                   __FIELD_EVALUATION__=eval_field_str,
                                   __MAT_INIT__=mat_init_str,
                                   __ACCUM_INIT__=accum_init_str,
                                   __FIELD_VALUE__=field_value_str,
                                   __TEST_FUNCTION__=test_function_str,
                                   __TRIAL_FUNCTION__=trial_function_str,
                                   __ACCUM__=accum_str,
                                   __ACCUM_ASSIGN__=accum_assign_str,
                                   __ARGS__=args)

        else:
            raise NotImplementedError(
                'We only treat the case of a block space, for '
                'which all components have are identical.')

    else:
        e = _convert_int_to_float(expr.evalf())
        # we call evalf to avoid having fortran doing the evaluation of rational
        # division
        code = template.format(__KERNEL_NAME__=name,
                               __FIELD_COEFFS__=field_coeffs_str,
                               __FIELD_EVALUATION__=eval_field_str,
                               __FIELD_VALUE__=field_value_str,
                               __TEST_FUNCTION__=test_function_str,
                               __TRIAL_FUNCTION__=trial_function_str,
                               __WEAK_FORM__=e,
                               __ARGS__=args)

    # ...

#    print('--------------')
#    print(code)
#    print('--------------')

# ...
    if context:
        from pyccel.epyccel import ContextPyccel

        if isinstance(context, ContextPyccel):
            context = [context]
        elif isinstance(context, (list, tuple)):
            for i in context:
                assert (isinstance(i, ContextPyccel))
        else:
            raise TypeError(
                'Expecting a ContextPyccel or list/tuple of ContextPyccel')

        # append functions to the namespace
        for c in context:
            for k, v in list(c.functions.items()):
                namespace[k] = v[0]
    # ...

    # ...
    exec(code, namespace)
    kernel = namespace[name]
    # ...

    # ... export the python code of the module
    if export_pyfile:
        write_code(name, code, ext='py', folder='.pyccel')
    # ...

    # ...
    if backend == 'fortran':
        #        try:
        # import epyccel function
        from pyccel.epyccel import epyccel

        #  ... define a header to specify the arguments types for kernel
        try:
            template = eval('template_header_{dim}d_{pattern}'.format(
                dim=dim, pattern=pattern))
        except:
            raise ValueError('Could not find the corresponding template')
        # ...

        # ...
        if isinstance(V, VectorFemSpace):
            if V.is_block:
                # ... declare element matrices dtypes
                mat_types = []
                for i in range(0, n_components):
                    for j in range(0, n_components):
                        if dim == 1:
                            mat_types.append('double [:,:]')
                        elif dim == 2:
                            mat_types.append('double [:,:,:,:]')
                        elif dim == 3:
                            mat_types.append('double [:,:,:,:,:,:]')
                        else:
                            raise NotImplementedError(
                                'only 1d, 2d and 3d are available')

                mat_types_str = ', '.join(mat for mat in mat_types)
                # ...

                header = template.format(__KERNEL_NAME__=name,
                                         __MAT_TYPES__=mat_types_str,
                                         __FIELD_TYPES__=field_types_str,
                                         __TYPES__=dtypes)

            else:
                raise NotImplementedError(
                    'We only treat the case of a block space, for '
                    'which all components have are identical.')

        else:
            header = template.format(__KERNEL_NAME__=name,
                                     __FIELD_TYPES__=field_types_str,
                                     __TYPES__=dtypes)
        # ...

        # compile the kernel
        kernel = epyccel(code, header, name=name, context=context)


#        except:
#            print('> COULD NOT CONVERT KERNEL TO FORTRAN')
#            print('  THE PYTHON BACKEND WILL BE USED')
# ...

    return kernel