Exemple #1
0
def get_bulk_relaxation_rate(method):
    """
    The bulk moment is x^2 + y^2 + z^2, plus a constant for orthogonalization.
    If this moment does not exist, the bulk relaxation is part of the shear relaxation.
    The bulk relaxation rate determines the bulk viscosity in hydrodynamic LBM schemes.
    """
    for moment, relax_info in method.relaxation_info_dict.items():
        if is_bulk_moment(moment, method.dim):
            return relax_info.relaxation_rate
    return get_shear_relaxation_rate(method)
Exemple #2
0
def create_central_moment(stencil,
                          relaxation_rates,
                          nested_moments=None,
                          maxwellian_moments=False,
                          **kwargs):
    r"""
    Creates moment based LB method where the collision takes place in the central moment space.

    Args:
        stencil: instance of :class:`lbmpy.stencils.LBStencil`
        relaxation_rates: relaxation rates (inverse of the relaxation times) for each moment
        nested_moments: a list of lists of modes, grouped by common relaxation times.
        maxwellian_moments: determines if the discrete or continuous maxwellian equilibrium is
                        used to compute the equilibrium moments.
    Returns:
        :class:`lbmpy.methods.momentbased.CentralMomentBasedLbMethod` instance
    """
    if nested_moments and not isinstance(nested_moments[0], list):
        nested_moments = list(
            sort_moments_into_groups_of_same_order(nested_moments).values())
        second_order_moments = nested_moments[2]
        bulk_moment = [
            m for m in second_order_moments if is_bulk_moment(m, stencil.D)
        ]
        shear_moments = [
            m for m in second_order_moments if is_shear_moment(m, stencil.D)
        ]
        assert len(shear_moments) + len(bulk_moment) == len(
            second_order_moments)
        nested_moments[2] = shear_moments
        nested_moments.insert(3, bulk_moment)

    if not nested_moments:
        nested_moments = cascaded_moment_sets_literature(stencil)

    rr_dict = _get_relaxation_info_dict(relaxation_rates, nested_moments,
                                        stencil.D)

    if maxwellian_moments:
        return create_with_continuous_maxwellian_eq_moments(
            stencil, rr_dict, central_moment_space=True, **kwargs)
    else:
        return create_with_discrete_maxwellian_eq_moments(
            stencil, rr_dict, central_moment_space=True, **kwargs)
Exemple #3
0
def _check_modes(stencil, force_model, compressible):
    omega_s = sp.Symbol("omega_s")
    omega_b = sp.Symbol("omega_b")
    omega_o = sp.Symbol("omega_o")
    omega_e = sp.Symbol("omega_e")

    F = list(sp.symbols(f"F_:{stencil.D}"))

    lbm_config = LBMConfig(method=Method.MRT,
                           stencil=stencil,
                           relaxation_rates=[
                               omega_s, omega_b, omega_o, omega_e, omega_o,
                               omega_e
                           ],
                           compressible=compressible,
                           force_model=force_model,
                           force=tuple(F))
    method = create_lb_method(lbm_config=lbm_config)

    subs_dict = method.subs_dict_relxation_rate
    force_moments = method.force_model.moment_space_forcing(method)
    force_moments = force_moments.subs(subs_dict)

    # The mass mode should be zero
    assert force_moments[0] == 0

    # The momentum moments should contain the force
    assert list(force_moments[1:stencil.D + 1]) == F

    if force_model == ForceModel.GUO:
        num_stresses = (stencil.D * stencil.D - stencil.D) // 2 + stencil.D
        lambda_s, lambda_b = -omega_s, -omega_b

        # The stress moments should match eq. 47 from https://doi.org/10.1023/A:1010414013942
        u = method.first_order_equilibrium_moment_symbols

        def traceless(m):
            tr = sp.simplify(sum([m[i, i] for i in range(stencil.D)]))
            return m - tr / m.shape[0] * sp.eye(m.shape[0])

        C = sp.Rational(1, 2) * (2 + lambda_s) * (traceless(sp.Matrix(u) * sp.Matrix(F).transpose()) +
                                                  traceless(sp.Matrix(F) * sp.Matrix(u).transpose())) + \
            sp.Rational(1, method.dim) * (2 + lambda_b) * sp.Matrix(u).dot(F) * sp.eye(method.dim)

        subs = {
            sp.Symbol(chr(ord("x") + i)) * sp.Symbol(chr(ord("x") + j)): C[i,
                                                                           j]
            for i in range(stencil.D) for j in range(stencil.D)
        }
        for force_moment, moment in zip(
                force_moments[stencil.D + 1:stencil.D + 1 + num_stresses],
                method.moments[stencil.D + 1:stencil.D + 1 + num_stresses]):
            ref = moment.subs(subs)
            diff = sp.simplify(ref - force_moment)
            if is_bulk_moment(moment, stencil.D):
                assert diff == 0 or isinstance(
                    diff,
                    sp.Rational)  # difference should be zero or a constant
            else:
                assert diff == 0  # difference should be zero

        ff = method.moment_matrix.inv() * sp.Matrix(
            method.force_model.moment_space_forcing(method).subs(subs_dict))
        # Check eq. 4.53a from schiller2008thermal
        assert sp.simplify(sum(ff)) == 0
        # Check eq. 4.53b from schiller2008thermal
        assert [
            sp.simplify(sum(ff[i] * stencil[i][j]
                            for i in range(len(stencil))))
            for j in range(stencil.D)
        ] == F
        # Check eq. 4.61a from schiller2008thermal
        ref = (2 + lambda_s) / 2 * (
            traceless(sp.Matrix(u) * sp.Matrix(F).transpose()) +
            traceless(sp.Matrix(F) * sp.Matrix(u).transpose()))
        s = sp.zeros(stencil.D)
        for i in range(0, len(stencil)):
            s += ff[i] * traceless(
                sp.Matrix(stencil[i]) * sp.Matrix(stencil[i]).transpose())
        assert sp.simplify(s - ref) == sp.zeros(stencil.D)
        # Check eq. 4.61b from schiller2008thermal
        assert sp.simplify(
            sum(ff[i] * stencil[i][a]**2 for i in range(len(stencil))
                for a in range(stencil.D)) -
            (2 + lambda_b) * sp.Matrix(u).dot(F)) == 0

        # All other moments should be zero
        assert list(force_moments[stencil.D + 1 + num_stresses:]) == [0] * (
            len(stencil) - (stencil.D + 1 + num_stresses))
    elif force_model == ForceModel.SIMPLE:
        # All other moments should be zero
        assert list(force_moments[stencil.D + 1:]) == [0] * (len(stencil) -
                                                             (stencil.D + 1))
Exemple #4
0
def _get_relaxation_info_dict(relaxation_rates, nested_moments, dim):
    r"""Creates a dictionary where each moment is mapped to a relaxation rate.

    Args:
        relaxation_rates: list of relaxation rates which should be used. This can also be a function which
                          takes a moment group in the list of nested moments and returns a list of relaxation rates.
                          This list has to have the length of the moment group and is then used for the moments
                          in the moment group.
        nested_moments: list of lists containing the moments.
        dim: dimension
    """
    result = OrderedDict()

    if callable(relaxation_rates):
        for group in nested_moments:
            rr = iter(relaxation_rates(group))
            for moment in group:
                result[moment] = next(rr)

        return result

    number_of_moments = 0
    shear_moments = 0
    bulk_moments = 0

    for group in nested_moments:
        for moment in group:
            number_of_moments += 1
            if is_shear_moment(moment, dim):
                shear_moments += 1
            if is_bulk_moment(moment, dim):
                bulk_moments += 1

    # if only one relaxation rate is specified it is used as the shear relaxation rate
    if len(relaxation_rates) == 1:
        for group in nested_moments:
            for moment in group:
                if get_order(moment) <= 1:
                    result[moment] = 0.0
                elif is_shear_moment(moment, dim):
                    result[moment] = relaxation_rates[0]
                else:
                    result[moment] = 1.0

    # if relaxation rate for each moment is specified they are all used
    if len(relaxation_rates) == number_of_moments:
        rr_iter = iter(relaxation_rates)
        for group in nested_moments:
            for moment in group:
                rr = next(rr_iter)
                result[moment] = rr

    # Fallback case, relaxes each group with the same relaxation rate and separates shear and bulk moments
    next_rr = True
    if len(relaxation_rates) != 1 and len(
            relaxation_rates) != number_of_moments:
        try:
            rr_iter = iter(relaxation_rates)
            if shear_moments > 0:
                shear_rr = next(rr_iter)
            if bulk_moments > 0:
                bulk_rr = next(rr_iter)
            for group in nested_moments:
                if next_rr:
                    rr = next(rr_iter)
                next_rr = False
                for moment in group:
                    if get_order(moment) <= 1:
                        result[moment] = 0.0
                    elif is_shear_moment(moment, dim):
                        result[moment] = shear_rr
                    elif is_bulk_moment(moment, dim):
                        result[moment] = bulk_rr
                    else:
                        next_rr = True
                        result[moment] = rr
        except StopIteration:
            raise ValueError(
                "Not enough relaxation rates are specified. You can either specify one relaxation rate, "
                "which is used as the shear relaxation rate. In this case, conserved moments are "
                "relaxed with 0, and higher-order moments are relaxed with 1. Another "
                "possibility is to specify a relaxation rate for shear, bulk and one for each order "
                "moment. In this case, conserved moments are also "
                "relaxed with 0. The last possibility is to specify a relaxation rate for each moment, "
                "including conserved moments")
    return result
Exemple #5
0
def create_mrt_orthogonal(stencil,
                          relaxation_rates,
                          maxwellian_moments=False,
                          weighted=None,
                          nested_moments=None,
                          **kwargs):
    r"""
    Returns an orthogonal multi-relaxation time model for the stencils D2Q9, D3Q15, D3Q19 and D3Q27.
    These MRT methods are just one specific version - there are many MRT methods possible for all these stencils
    which differ by the linear combination of moments and the grouping into equal relaxation times.
    To create a generic MRT method use `create_with_discrete_maxwellian_eq_moments`

    Args:
        stencil: instance of :class:`lbmpy.stencils.LBStencil`
        relaxation_rates: relaxation rates for the moments
        maxwellian_moments: determines if the discrete or continuous maxwellian equilibrium is
                                               used to compute the equilibrium moments
        weighted: whether to use weighted or unweighted orthogonality
        nested_moments: a list of lists of modes, grouped by common relaxation times. If this argument is not provided,
                        Gram-Schmidt orthogonalization of the default modes is performed. The default modes equal the
                        raw moments except for the separation of the shear and bulk viscosity.
    """
    if weighted:
        weights = get_weights(stencil, sp.Rational(1, 3))
    else:
        weights = None

    if not nested_moments:
        moments = get_default_moment_set_for_stencil(stencil)
        x, y, z = MOMENT_SYMBOLS
        if stencil.D == 2:
            diagonal_viscous_moments = [x**2 + y**2, x**2]
        else:
            diagonal_viscous_moments = [x**2 + y**2 + z**2, x**2, y**2 - z**2]

        for i, d in enumerate(MOMENT_SYMBOLS[:stencil.D]):
            if d**2 in moments:
                moments[moments.index(d**2)] = diagonal_viscous_moments[i]
        orthogonal_moments = gram_schmidt(moments, stencil, weights)
        orthogonal_moments_scaled = [
            e * common_denominator(e) for e in orthogonal_moments
        ]
        nested_moments = list(
            sort_moments_into_groups_of_same_order(
                orthogonal_moments_scaled).values())
        # second order moments: separate bulk from shear
        second_order_moments = nested_moments[2]
        bulk_moment = [
            m for m in second_order_moments if is_bulk_moment(m, stencil.D)
        ]
        shear_moments = [
            m for m in second_order_moments if is_shear_moment(m, stencil.D)
        ]
        assert len(shear_moments) + len(bulk_moment) == len(
            second_order_moments)
        nested_moments[2] = shear_moments
        nested_moments.insert(3, bulk_moment)

    moment_to_relaxation_rate_dict = _get_relaxation_info_dict(
        relaxation_rates, nested_moments, stencil.D)

    if maxwellian_moments:
        return create_with_continuous_maxwellian_eq_moments(
            stencil, moment_to_relaxation_rate_dict, **kwargs)
    else:
        return create_with_discrete_maxwellian_eq_moments(
            stencil, moment_to_relaxation_rate_dict, **kwargs)
def test_mrt_orthogonal():
    m_ref = {}

    moments = mrt_orthogonal_modes_literature(LBStencil(Stencil.D2Q9), True)
    lbm_config = LBMConfig(method=Method.MRT,
                           stencil=LBStencil(Stencil.D2Q9),
                           maxwellian_moments=True,
                           nested_moments=moments)
    m = create_lb_method(lbm_config=lbm_config)
    assert m.is_weighted_orthogonal
    m_ref[(Stencil.D2Q9, True)] = m

    moments = mrt_orthogonal_modes_literature(LBStencil(Stencil.D3Q15), True)
    lbm_config = LBMConfig(method=Method.MRT,
                           stencil=LBStencil(Stencil.D3Q15),
                           maxwellian_moments=True,
                           nested_moments=moments)
    m = create_lb_method(lbm_config=lbm_config)
    assert m.is_weighted_orthogonal
    m_ref[(Stencil.D3Q15, True)] = m

    moments = mrt_orthogonal_modes_literature(LBStencil(Stencil.D3Q19), True)
    lbm_config = LBMConfig(method=Method.MRT,
                           stencil=LBStencil(Stencil.D3Q19),
                           maxwellian_moments=True,
                           nested_moments=moments)
    m = create_lb_method(lbm_config=lbm_config)
    assert m.is_weighted_orthogonal
    m_ref[(Stencil.D3Q19, True)] = m

    moments = mrt_orthogonal_modes_literature(LBStencil(Stencil.D3Q27), False)
    lbm_config = LBMConfig(method=Method.MRT,
                           stencil=LBStencil(Stencil.D3Q27),
                           maxwellian_moments=True,
                           nested_moments=moments)
    m = create_lb_method(lbm_config=lbm_config)
    assert m.is_orthogonal
    m_ref[(Stencil.D3Q27, False)] = m

    for weighted in [True, False]:
        for stencil in [
                Stencil.D2Q9, Stencil.D3Q15, Stencil.D3Q19, Stencil.D3Q27
        ]:
            lbm_config = LBMConfig(method=Method.MRT,
                                   stencil=LBStencil(stencil),
                                   maxwellian_moments=True,
                                   weighted=weighted)
            m = create_lb_method(lbm_config=lbm_config)
            if weighted:
                assert m.is_weighted_orthogonal
            else:
                assert m.is_orthogonal
            bulk_moments = set(
                [mom for mom in m.moments if is_bulk_moment(mom, m.dim)])
            shear_moments = set(
                [mom for mom in m.moments if is_shear_moment(mom, m.dim)])
            assert len(bulk_moments) == 1
            assert len(shear_moments) == 1 + (m.dim -
                                              2) + m.dim * (m.dim - 1) / 2

            if (stencil, weighted) in m_ref:
                ref = m_ref[(stencil, weighted)]
                bulk_moments_lit = set([
                    mom for mom in ref.moments if is_bulk_moment(mom, ref.dim)
                ])
                shear_moments_lit = set([
                    mom for mom in ref.moments
                    if is_shear_moment(mom, ref.dim)
                ])

                if stencil != stencil.D3Q27:  # this one uses a different linear combination in literature
                    assert shear_moments == shear_moments_lit
                assert bulk_moments == bulk_moments_lit