Esempio n. 1
0
def get_galilean_correction_terms(
        cumulant_to_relaxation_info_dict,
        rho,
        u_vector,
        pre_collision_cumulant_base=PRE_COLLISION_CUMULANT):

    pc1 = corrected_polynomials[0]
    pc2 = corrected_polynomials[1]
    pc3 = corrected_polynomials[2]

    try:
        omega_1 = cumulant_to_relaxation_info_dict[pc1].relaxation_rate
        assert omega_1 == cumulant_to_relaxation_info_dict[pc2].relaxation_rate, \
            "Cumulants (x^2 - y^2) and (x^2 - z^2) must have the same relaxation rate"
        omega_2 = cumulant_to_relaxation_info_dict[pc3].relaxation_rate
    except IndexError:
        raise ValueError(
            "For the galilean correction, all three polynomial cumulants" +
            "(x^2 - y^2), (x^2 - z^2) and (x^2 + y^2 + z^2) must be present!")

    dx, dy, dz = sp.symbols('Dx, Dy, Dz')
    c_xx = statistical_quantity_symbol(pre_collision_cumulant_base, (2, 0, 0))
    c_yy = statistical_quantity_symbol(pre_collision_cumulant_base, (0, 2, 0))
    c_zz = statistical_quantity_symbol(pre_collision_cumulant_base, (0, 0, 2))

    cor1, cor2, cor3 = sp.symbols("corr_:3")

    #   Derivative Approximations
    subexpressions = [
        Assignment(
            dx, -omega_1 / (2 * rho) * (2 * c_xx - c_yy - c_zz) - omega_2 /
            (2 * rho) * (c_xx + c_yy + c_zz - rho)),
        Assignment(dy, dx + (3 * omega_1) / (2 * rho) * (c_xx - c_yy)),
        Assignment(dz, dx + (3 * omega_1) / (2 * rho) * (c_xx - c_zz))
    ]

    #   Correction Terms
    main_assignments = [
        Assignment(
            cor1, -3 * rho * (1 - omega_1 / 2) *
            (u_vector[0]**2 * dx - u_vector[1]**2 * dy)),
        Assignment(
            cor2, -3 * rho * (1 - omega_1 / 2) *
            (u_vector[0]**2 * dx - u_vector[2]**2 * dz)),
        Assignment(
            cor3, -3 * rho * (1 - omega_2 / 2) *
            (u_vector[0]**2 * dx + u_vector[1]**2 * dy + u_vector[2]**2 * dz))
    ]
    return AssignmentCollection(main_assignments=main_assignments,
                                subexpressions=subexpressions)
Esempio n. 2
0
def relax_polynomial_cumulants(monomial_exponents,
                               polynomials,
                               relaxation_rates,
                               equilibrium_values,
                               pre_simplification,
                               galilean_correction_terms=None,
                               pre_collision_base=PRE_COLLISION_CUMULANT,
                               post_collision_base=POST_COLLISION_CUMULANT,
                               subexpression_base='sub_col'):
    mon_to_poly_matrix = monomial_to_polynomial_transformation_matrix(
        monomial_exponents, polynomials)
    mon_vec = sp.Matrix([
        statistical_quantity_symbol(pre_collision_base, exp)
        for exp in monomial_exponents
    ])
    equilibrium_vec = sp.Matrix(equilibrium_values)
    relaxation_matrix = sp.diag(*relaxation_rates)

    subexpressions = []

    poly_vec = mon_to_poly_matrix * mon_vec
    relaxed_polys = poly_vec + relaxation_matrix * (equilibrium_vec - poly_vec)

    if galilean_correction_terms is not None:
        relaxed_polys = add_galilean_correction(relaxed_polys, polynomials,
                                                galilean_correction_terms)
        subexpressions = galilean_correction_terms.all_assignments

    relaxed_monos = mon_to_poly_matrix.inv() * relaxed_polys

    main_assignments = [
        Assignment(statistical_quantity_symbol(post_collision_base, exp), v)
        for exp, v in zip(monomial_exponents, relaxed_monos)
    ]

    symbol_gen = SymbolGen(subexpression_base)
    ac = AssignmentCollection(main_assignments,
                              subexpressions=subexpressions,
                              subexpression_symbol_generator=symbol_gen)
    if pre_simplification == 'default_with_cse':
        ac = sympy_cse(ac)
    return ac
Esempio n. 3
0
    def cumulant_from_central_moments(self, cumulant_exponents, moment_symbol_base):
        dim = self.dim
        assert len(cumulant_exponents) == dim
        wave_numbers = WAVE_NUMBER_SYMBOLS[:dim]
        K = sp.Function('K')

        u_symbols = self.equilibrium_velocity
        rho = self.equilibrium_density

        C = sum(w * u for w, u in zip(wave_numbers, u_symbols)) + sp.log(K(*wave_numbers))

        diff_args = chain.from_iterable([var, i] for var, i in zip(wave_numbers, cumulant_exponents))
        cumulant = C.diff(*diff_args)
        required_central_moments = set()

        derivatives = cumulant.atoms(sp.Derivative)
        derivative_subs = []
        for d in derivatives:
            moment_index = moment_index_from_derivative(d, wave_numbers)
            if sum(moment_index) > 1:  # lower order moments are replaced anyway
                required_central_moments.add(moment_index)
            derivative_subs.append((d, statistical_quantity_symbol(moment_symbol_base, moment_index)))
        derivative_subs = sorted(derivative_subs, key=lambda x: count_derivatives(x[0]), reverse=True)

        # K(0,0,0) = rho
        cumulant = cumulant.subs(derivative_subs)

        # First central moments equal zero
        value_subs = {x: 0 for x in wave_numbers}
        for i in range(dim):
            indices = [0] * dim
            indices[i] = 1
            value_subs[statistical_quantity_symbol(
                moment_symbol_base, indices)] = 0

        cumulant = cumulant.subs(value_subs)
        cumulant = cumulant.subs(K(*((0,) * dim)), rho)  # K(0,0,0) = rho

        return (rho * cumulant).collect(rho)
Esempio n. 4
0
    def central_moment_from_cumulants(self, moment_exponents, cumulant_symbol_base):
        dim = len(moment_exponents)
        wave_numbers = WAVE_NUMBER_SYMBOLS[:dim]
        C = sp.Function('C')

        u_symbols = self.equilibrium_velocity
        rho = self.equilibrium_density

        K = sp.exp(C(*wave_numbers) - sum(w * u for w,
                                          u in zip(wave_numbers, u_symbols)))

        diff_args = chain.from_iterable(
            [var, i] for var, i in zip(wave_numbers, moment_exponents))
        moment = K.diff(*diff_args)

        derivatives = moment.atoms(sp.Derivative)
        c_indices = [moment_index_from_derivative(d, wave_numbers) for d in derivatives]

        derivative_subs = [(d, derivative_as_statistical_quantity(d, wave_numbers, 'c')) for d in derivatives]
        derivative_subs = sorted(derivative_subs, key=lambda x: count_derivatives(x[0]), reverse=True)

        moment = moment.subs(derivative_subs)

        # C(0,0,0) = log(rho), c_100 = u_x, etc.
        value_subs = [(x, 0) for x in wave_numbers]
        for i, u in enumerate(u_symbols):
            c_idx = [0] * dim
            c_idx[i] = 1
            value_subs.append((statistical_quantity_symbol('c', c_idx), u))

        moment = moment.subs(value_subs)
        moment = moment.subs(C(*((0,) * dim)), sp.log(rho))
        moment = moment.subs([(statistical_quantity_symbol('c', idx),
                               statistical_quantity_symbol(cumulant_symbol_base, idx) / rho)
                              for idx in c_indices])

        return moment.expand().collect(rho)
Esempio n. 5
0
    def forward_transform(self,
                          cumulant_base=PRE_COLLISION_CUMULANT,
                          central_moment_base=PRE_COLLISION_MONOMIAL_CENTRAL_MOMENT,
                          simplification=True,
                          subexpression_base='sub_k_to_C'):
        simplification = self._get_simp_strategy(simplification)

        main_assignments = []
        for exp in self.cumulant_exponents:
            eq = self.cumulant_from_central_moments(exp, central_moment_base)
            c_symbol = statistical_quantity_symbol(cumulant_base, exp)
            main_assignments.append(Assignment(c_symbol, eq))
        symbol_gen = SymbolGen(subexpression_base)
        ac = AssignmentCollection(
            main_assignments, subexpression_symbol_generator=symbol_gen)
        
        if simplification:
            ac = simplification.apply(ac)
        return ac
Esempio n. 6
0
def relax_lower_order_central_moments(
        moment_indices,
        pre_collision_values,
        relaxation_rates,
        equilibrium_values,
        post_collision_base=POST_COLLISION_MONOMIAL_CENTRAL_MOMENT):
    post_collision_symbols = [
        statistical_quantity_symbol(post_collision_base, i)
        for i in moment_indices
    ]
    equilibrium_vec = sp.Matrix(equilibrium_values)
    moment_vec = sp.Matrix(pre_collision_values)
    relaxation_matrix = sp.diag(*relaxation_rates)
    moment_vec = moment_vec + relaxation_matrix * (equilibrium_vec -
                                                   moment_vec)
    main_assignments = [
        Assignment(s, eq) for s, eq in zip(post_collision_symbols, moment_vec)
    ]

    return AssignmentCollection(main_assignments)
Esempio n. 7
0
    def backward_transform(self,
                           cumulant_base=POST_COLLISION_CUMULANT,
                           central_moment_base=POST_COLLISION_MONOMIAL_CENTRAL_MOMENT,
                           simplification=True,
                           omit_conserved_moments=False,
                           subexpression_base='sub_C_to_k'):
        simplification = self._get_simp_strategy(simplification)

        main_assignments = []
        for exp in self.central_moment_exponents:
            if omit_conserved_moments and get_order(exp) <= 1:
                continue
            eq = self.central_moment_from_cumulants(exp, cumulant_base)
            k_symbol = statistical_quantity_symbol(central_moment_base, exp)
            main_assignments.append(Assignment(k_symbol, eq))
        symbol_gen = SymbolGen(subexpression_base)
        ac = AssignmentCollection(main_assignments, subexpression_symbol_generator=symbol_gen)
        
        if simplification:
            ac = simplification.apply(ac)
        return ac
Esempio n. 8
0
def derivative_as_statistical_quantity(d, variables, quantity_name):
    indices = moment_index_from_derivative(d, variables)
    return statistical_quantity_symbol(quantity_name, indices)
Esempio n. 9
0
    def _centered_cumulant_collision_rule(self,
                                          cumulant_to_relaxation_info_dict,
                                          conserved_quantity_equations=None,
                                          pre_simplification=False,
                                          include_force_terms=False,
                                          include_galilean_correction=True,
                                          symbolic_relaxation_rates=False):

        # Filter out JobLib warnings. They are not usefull for use:
        # https://github.com/joblib/joblib/issues/683
        filterwarnings("ignore", message="Persisting input arguments took")

        stencil = self.stencil
        f = self.pre_collision_pdf_symbols
        density = self.zeroth_order_equilibrium_moment_symbol
        velocity = self.first_order_equilibrium_moment_symbols
        cqe = conserved_quantity_equations

        relaxation_info_dict = dict()
        subexpressions_relaxation_rates = []
        if symbolic_relaxation_rates:
            subexpressions_relaxation_rates, sd = self._generate_symbolic_relaxation_matrix(
            )
            for i, cumulant in enumerate(cumulant_to_relaxation_info_dict):
                relaxation_info_dict[cumulant] = RelaxationInfo(
                    cumulant_to_relaxation_info_dict[cumulant][0], sd[i, i])
        else:
            relaxation_info_dict = cumulant_to_relaxation_info_dict

        if cqe is None:
            cqe = self._conserved_quantity_computation.equilibrium_input_equations_from_pdfs(
                f, False)

        forcing_subexpressions = AssignmentCollection([])
        if self._force_model is not None:
            forcing_subexpressions = AssignmentCollection(
                self._force_model.subs_dict_force)

        #   1) Extract Monomial Cumulants for the higher-order polynomials
        polynomial_cumulants = relaxation_info_dict.keys()
        polynomial_cumulants = sorted(list(polynomial_cumulants),
                                      key=moment_sort_key)
        higher_order_polynomials = [
            p for p in polynomial_cumulants if get_order(p) > 1
        ]
        monomial_cumulants = sorted(list(
            extract_monomials(higher_order_polynomials, dim=self.dim)),
                                    key=exponent_tuple_sort_key)

        #   2) Get Forward and Backward Transformations between central moment and cumulant space,
        #      and find required central moments
        k_to_c_transform = self._cumulant_transform_class(
            stencil, monomial_cumulants, density, velocity)
        k_to_c_eqs = cached_forward_transform(
            k_to_c_transform, simplification=pre_simplification)
        c_post_to_k_post_eqs = cached_backward_transform(
            k_to_c_transform,
            simplification=pre_simplification,
            omit_conserved_moments=True)
        central_moments = k_to_c_transform.required_central_moments
        assert len(
            central_moments
        ) == stencil.Q, 'Number of required central moments must match stencil size.'

        #   3) Get Forward Transformation from PDFs to central moments
        pdfs_to_k_transform = self._central_moment_transform_class(
            stencil,
            None,
            density,
            velocity,
            moment_exponents=central_moments,
            conserved_quantity_equations=cqe)
        pdfs_to_k_eqs = cached_forward_transform(
            pdfs_to_k_transform,
            f,
            simplification=pre_simplification,
            return_monomials=True)

        #   4) Add relaxation rules for lower order moments
        lower_order_moments = moments_up_to_order(1, dim=self.dim)
        lower_order_moment_symbols = [
            statistical_quantity_symbol(PRE_COLLISION_MONOMIAL_CENTRAL_MOMENT,
                                        exp) for exp in lower_order_moments
        ]

        lower_order_relaxation_infos = [
            relaxation_info_dict[exponent_to_polynomial_representation(e)]
            for e in lower_order_moments
        ]
        lower_order_relaxation_rates = [
            info.relaxation_rate for info in lower_order_relaxation_infos
        ]
        lower_order_equilibrium = [
            info.equilibrium_value for info in lower_order_relaxation_infos
        ]

        lower_order_moment_collision_eqs = relax_lower_order_central_moments(
            lower_order_moments, tuple(lower_order_moment_symbols),
            tuple(lower_order_relaxation_rates),
            tuple(lower_order_equilibrium))

        #   5) Add relaxation rules for higher-order, polynomial cumulants
        poly_relaxation_infos = [
            relaxation_info_dict[c] for c in higher_order_polynomials
        ]
        poly_relaxation_rates = [
            info.relaxation_rate for info in poly_relaxation_infos
        ]
        poly_equilibrium = [
            info.equilibrium_value for info in poly_relaxation_infos
        ]

        if self._galilean_correction and include_galilean_correction:
            galilean_correction_terms = get_galilean_correction_terms(
                relaxation_info_dict, density, velocity)
        else:
            galilean_correction_terms = None

        cumulant_collision_eqs = relax_polynomial_cumulants(
            tuple(monomial_cumulants),
            tuple(higher_order_polynomials),
            tuple(poly_relaxation_rates),
            tuple(poly_equilibrium),
            pre_simplification,
            galilean_correction_terms=galilean_correction_terms)

        #   6) Get backward transformation from central moments to PDFs
        d = self.post_collision_pdf_symbols
        k_post_to_pdfs_eqs = cached_backward_transform(
            pdfs_to_k_transform,
            d,
            simplification=pre_simplification,
            start_from_monomials=True)

        #   7) That's all. Now, put it all together.
        all_acs = [] if pdfs_to_k_transform.absorbs_conserved_quantity_equations else [
            cqe
        ]
        subexpressions_relaxation_rates = AssignmentCollection(
            subexpressions_relaxation_rates)
        all_acs += [
            subexpressions_relaxation_rates, forcing_subexpressions,
            pdfs_to_k_eqs, k_to_c_eqs, lower_order_moment_collision_eqs,
            cumulant_collision_eqs, c_post_to_k_post_eqs
        ]
        subexpressions = [ac.all_assignments for ac in all_acs]
        subexpressions += k_post_to_pdfs_eqs.subexpressions
        main_assignments = k_post_to_pdfs_eqs.main_assignments

        #   8) Maybe add forcing terms if CenteredCumulantForceModel was not used
        if self._force_model is not None and \
                not isinstance(self._force_model, CenteredCumulantForceModel) and include_force_terms:
            force_model_terms = self._force_model(self)
            force_term_symbols = sp.symbols(
                f"forceTerm_:{len(force_model_terms)}")
            force_subexpressions = [
                Assignment(sym,
                           force_model_term) for sym, force_model_term in zip(
                               force_term_symbols, force_model_terms)
            ]
            subexpressions += force_subexpressions
            main_assignments = [
                Assignment(eq.lhs, eq.rhs + force_term_symbol) for eq,
                force_term_symbol in zip(main_assignments, force_term_symbols)
            ]

        #   Aaaaaand we're done.
        return LbmCollisionRule(self, main_assignments, subexpressions)