Beispiel #1
0
    def get_pdf_hierarchy(self,
                          order,
                          collision_operator_symbol=sp.Symbol("omega")):
        def substitute_non_commuting_symbols(eq):
            return eq.subs({a: sp.Symbol(a.name) for a in eq.atoms(sp.Symbol)})

        result = self.pdf_hierarchy[order].subs(self.collision_op_sym,
                                                collision_operator_symbol)
        result = normalize_diff_order(result,
                                      functions=(self.f_syms[0],
                                                 self.force_sym))
        return substitute_non_commuting_symbols(result)
Beispiel #2
0
    def _compute_moments(self, recombined_eq, symbols_to_values):
        eq = recombined_eq.expand()
        assert eq.func is sp.Add

        new_products = []
        for product in eq.args:
            assert product.func is sp.Mul

            derivative = None

            new_prod = 1
            for arg in reversed(normalize_product(product)):
                if isinstance(arg, Diff):
                    assert derivative is None, "More than one derivative term in the product"
                    derivative = arg
                    arg = arg.get_arg_recursive(
                    )  # new argument is inner part of derivative

                if arg in symbols_to_values:
                    arg = symbols_to_values[arg]

                have_shape = hasattr(arg, 'shape') and hasattr(
                    new_prod, 'shape')
                if have_shape and arg.shape == new_prod.shape and arg.shape[
                        1] == 1:
                    # since sympy 1.9 sp.matrix_multiply_elementwise does not work anymore in this case
                    new_prod = sp.Matrix(np.multiply(new_prod, arg))
                else:
                    new_prod = arg * new_prod
                if new_prod == 0:
                    break

            if new_prod == 0:
                continue

            new_prod = sp.expand(sum(new_prod))

            if derivative is not None:
                new_prod = derivative.change_arg_recursive(new_prod)

            new_products.append(new_prod)

        return normalize_diff_order(
            expand_diff_linear(sp.Add(*new_products),
                               functions=self.physical_variables))
Beispiel #3
0
def get_taylor_expanded_lb_equation(pdf_symbol_name="f",
                                    pdfs_after_collision_operator="\\Omega f",
                                    velocity_name="c",
                                    dim=3,
                                    taylor_order=2,
                                    shift=True):
    dim_labels = [sp.Rational(i, 1) for i in range(dim)]

    c = sp.Matrix([
        expanded_symbol(velocity_name, subscript=label) for label in dim_labels
    ])
    dt, t = sp.symbols("Delta_t t")
    pdf = sp.Symbol(pdf_symbol_name)
    collided_pdf = sp.Symbol(pdfs_after_collision_operator)

    dt_operator = DiffOperator(target=t)
    dx_operator = sp.Matrix([DiffOperator(target=l) for l in dim_labels])

    taylor_operator = sum(dt**k * (dt_operator + c.dot(dx_operator))**k /
                          sp.functions.factorial(k)
                          for k in range(1, taylor_order + 1))

    functions = [pdf, collided_pdf]
    eq_4_5 = taylor_operator - dt * collided_pdf
    applied_eq_4_5 = expand_diff_linear(
        DiffOperator.apply(eq_4_5, pdf, apply_to_constants=False), functions)

    if shift:
        operator = ((dt / 2) * (dt_operator + c.dot(dx_operator))).expand()
        op_times_eq_4_5 = expand_diff_linear(
            DiffOperator.apply(operator,
                               applied_eq_4_5,
                               apply_to_constants=False), functions).expand()
        op_times_eq_4_5 = normalize_diff_order(op_times_eq_4_5, functions)
        eq_4_7 = (applied_eq_4_5 - op_times_eq_4_5).subs(
            dt**(taylor_order + 1), 0)
    else:
        eq_4_7 = applied_eq_4_5.subs(dt**(taylor_order + 1), 0)

    eq_4_7 = eq_4_7.subs(dt, 1)
    return eq_4_7.expand()
def force_computation_equivalence(dim=3, num_phases=4):

    def Λ(i, j):
        if i > j:
            i, j = j, i
        return sp.Symbol("Lambda_{}{}".format(i, j))

    φ = sp.symbols("φ_:{}".format(num_phases))
    f_if = sum(Λ(α, β) / 2 * Diff(φ[α]) * Diff(φ[β])
               for α in range(num_phases) for β in range(num_phases))
    μ = chemical_potentials_from_free_energy(f_if, order_parameters=φ)
    μ = substitute_laplacian_by_sum(μ, dim=dim)

    p = sp.Matrix(dim, dim,
                  lambda i, j: pressure_tensor_interface_component_new(f_if, φ, dim, i, j))
    force_from_p = force_from_pressure_tensor(p, functions=φ)

    for d in range(dim):
        t1 = normalize_diff_order(force_from_p[d])
        t2 = expand_diff_full(force_from_phi_and_mu(φ, dim=dim, mu=μ)[d], functions=φ).expand()
        assert t1 - t2 == 0
    print("Success")
Beispiel #5
0
    def __init__(self, method, order=4):
        self.method = method
        dim = method.dim
        moment_computation = LbMethodEqMoments(method)

        eps, collision_operator, f, dt = sp.symbols("epsilon B f Delta_t")
        self.dt = dt
        expanded_pdf_symbols = [
            expanded_symbol("f", superscript=i) for i in range(0, order + 1)
        ]
        feq = expanded_pdf_symbols[0]
        c = sp.Matrix([expanded_symbol("c", subscript=i) for i in range(dim)])
        dx = sp.Matrix([DiffOperator(target=l) for l in range(dim)])
        differential_operator = sum((dt * eps * c.dot(dx))**n / sp.factorial(n)
                                    for n in range(1, order + 1))
        taylor_expansion = DiffOperator.apply(differential_operator.expand(),
                                              f,
                                              apply_to_constants=False)
        eps_dict = chapman_enskog_ansatz(
            taylor_expansion,
            spatial_derivative_orders=
            None,  # do not expand the differential operator
            pdfs=(['f', 0, order + 1], ))  # expand only the 'f' terms

        self.scale_hierarchy = [
            -collision_operator * eps_dict[i] for i in range(0, order + 1)
        ]
        self.scale_hierarchy_raw = self.scale_hierarchy.copy()

        expanded_pdfs = [feq, self.scale_hierarchy[1]]
        subs_dict = {expanded_pdf_symbols[1]: self.scale_hierarchy[1]}

        for i in range(2, len(self.scale_hierarchy)):
            eq = self.scale_hierarchy[i].subs(subs_dict)
            eq = expand_diff_linear(eq, functions=expanded_pdf_symbols)
            eq = normalize_diff_order(eq, functions=expanded_pdf_symbols)
            subs_dict[expanded_pdf_symbols[i]] = eq
            expanded_pdfs.append(eq)
        self.scale_hierarchy = expanded_pdfs

        constants = sp.Matrix(method.relaxation_rates).atoms(sp.Symbol)
        recombined = -sum(self.scale_hierarchy[n]
                          for n in range(1, order + 1))  # Eq 18a
        recombined = sp.cancel(
            recombined /
            (dt * collision_operator)).expand()  # cancel common factors

        def handle_postcollision_values(expr):
            expr = expr.expand()
            assert isinstance(expr, sp.Add)
            result = 0
            for summand in expr.args:

                moment = summand.atoms(CeMoment)
                moment = moment.pop()
                collision_operator_exponent = normalize_product(summand).count(
                    collision_operator)
                if collision_operator_exponent == 0:
                    result += summand
                else:
                    substitutions = {
                        collision_operator:
                        1,
                        moment:
                        -moment_computation.get_post_collision_moment(
                            moment, -collision_operator_exponent),
                    }
                    result += summand.subs(substitutions)

            return result

        # Continuity equation (mass transport)
        cont_eq = take_moments(recombined, max_expansion=(order + 1) * 2)
        cont_eq = handle_postcollision_values(cont_eq)
        cont_eq = expand_diff_linear(cont_eq,
                                     constants=constants).expand().collect(dt)
        self.continuity_equation_with_moments = cont_eq
        cont_eq = insert_moments(cont_eq,
                                 moment_computation,
                                 use_solvability_conditions=False)
        cont_eq = expand_diff_linear(cont_eq,
                                     constants=constants).expand().collect(dt)
        self.continuity_equation = cont_eq

        # Momentum equation (momentum transport)
        self.momentum_equations_with_moments = []
        self.momentum_equations = []
        for h in range(dim):
            mom_eq = take_moments(recombined * c[h],
                                  max_expansion=(order + 1) * 2)
            mom_eq = handle_postcollision_values(mom_eq)
            mom_eq = expand_diff_linear(
                mom_eq, constants=constants).expand().collect(dt)
            self.momentum_equations_with_moments.append(mom_eq)
            mom_eq = insert_moments(mom_eq,
                                    moment_computation,
                                    use_solvability_conditions=False)
            mom_eq = expand_diff_linear(
                mom_eq, constants=constants).expand().collect(dt)
            self.momentum_equations.append(mom_eq)