diff --git a/lbmpy/creationfunctions.py b/lbmpy/creationfunctions.py index f7e30b3a96797ebb751726cb9c549c6de7b6c47f..5eb4ea74e5705c9a2d555c0ffd6c2113d7b9c018 100644 --- a/lbmpy/creationfunctions.py +++ b/lbmpy/creationfunctions.py @@ -414,7 +414,10 @@ def create_lb_method(**params): except IndexError: raise ValueError("Too few relaxation rates specified") return res - method = create_mrt_orthogonal(stencil_entries, relaxation_rate_getter, **common_params) + weighted = params['weighted'] if 'weighted' in params else None + nested_moments = params['nested_moments'] if 'nested_moments' in params else None + method = create_mrt_orthogonal(stencil_entries, relaxation_rate_getter, weighted=weighted, + nested_moments=nested_moments, **common_params) elif method_name.lower() == 'mrt_raw': method = create_mrt_raw(stencil_entries, relaxation_rates, **common_params) elif method_name.lower() == 'mrt3': diff --git a/lbmpy/methods/__init__.py b/lbmpy/methods/__init__.py index 2ed90edf50bd982de70d65a151768a3714a94dc2..e14d6fb21e16606bbef6313a8fa61cfe817d1d4f 100644 --- a/lbmpy/methods/__init__.py +++ b/lbmpy/methods/__init__.py @@ -1,7 +1,7 @@ from lbmpy.methods.creationfunctions import ( create_mrt3, create_mrt_orthogonal, create_mrt_raw, create_srt, create_trt, create_trt_kbc, create_trt_with_magic_number, create_with_continuous_maxwellian_eq_moments, - create_with_discrete_maxwellian_eq_moments) + create_with_discrete_maxwellian_eq_moments, mrt_orthogonal_modes_literature) from lbmpy.methods.momentbased import ( AbstractConservedQuantityComputation, AbstractLbMethod, MomentBasedLbMethod, RelaxationInfo) @@ -11,4 +11,5 @@ __all__ = ['RelaxationInfo', 'AbstractLbMethod', 'AbstractConservedQuantityComputation', 'DensityVelocityComputation', 'MomentBasedLbMethod', 'create_srt', 'create_trt', 'create_trt_with_magic_number', 'create_trt_kbc', 'create_mrt_orthogonal', 'create_mrt_raw', 'create_mrt3', - 'create_with_continuous_maxwellian_eq_moments', 'create_with_discrete_maxwellian_eq_moments'] + 'create_with_continuous_maxwellian_eq_moments', 'create_with_discrete_maxwellian_eq_moments', + 'mrt_orthogonal_modes_literature'] diff --git a/lbmpy/methods/creationfunctions.py b/lbmpy/methods/creationfunctions.py index 131ad9b493b1ca209557e6de67a4a5b06d5a3274..755a68cb08b43883659551320888ce3eb297a87f 100644 --- a/lbmpy/methods/creationfunctions.py +++ b/lbmpy/methods/creationfunctions.py @@ -10,7 +10,7 @@ from lbmpy.maxwellian_equilibrium import ( compressible_to_incompressible_moment_value, get_cumulants_of_continuous_maxwellian_equilibrium, get_cumulants_of_discrete_maxwellian_equilibrium, get_moments_of_continuous_maxwellian_equilibrium, - get_moments_of_discrete_maxwellian_equilibrium) + get_moments_of_discrete_maxwellian_equilibrium, get_weights) from lbmpy.methods.abstractlbmethod import RelaxationInfo from lbmpy.methods.conservedquantitycomputation import DensityVelocityComputation from lbmpy.methods.cumulantbased import CumulantBasedLbMethod @@ -358,9 +358,10 @@ def create_trt_kbc(dim, shear_relaxation_rate, higher_order_relaxation_rate, met return create_with_discrete_maxwellian_eq_moments(stencil, moment_to_rr, **kwargs) -def create_mrt_orthogonal(stencil, relaxation_rate_getter=None, maxwellian_moments=False, **kwargs): +def create_mrt_orthogonal(stencil, relaxation_rate_getter=None, maxwellian_moments=False, weighted=None, + nested_moments=None, **kwargs): r""" - Returns a orthogonal multi-relaxation time model for the stencils D2Q9, D3Q15, D3Q19 and D3Q27. + 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` @@ -375,23 +376,55 @@ def create_mrt_orthogonal(stencil, relaxation_rate_getter=None, maxwellian_momen - numbered :math:`\omega_i` for the rest 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 + modes: a list of lists of modes, grouped by common relaxation times. This is usually used in conjunction with + `mrt_orthogonal_modes_literature`. If this argument is not provided, Gram-Schmidt orthogonalization of + the default modes is performed. """ if relaxation_rate_getter is None: relaxation_rate_getter = default_relaxation_rate_names() if isinstance(stencil, str): stencil = get_stencil(stencil) - x, y, z = MOMENT_SYMBOLS - one = sp.Rational(1, 1) - is_cumulant = 'cumulant' in kwargs and kwargs['cumulant'] + if weighted is None and not nested_moments: + raise ValueError("Please specify whether you want weighted or unweighted orthogonality") + elif weighted: + weights = get_weights(stencil, sp.Rational(1, 3)) + else: + weights = None moment_to_relaxation_rate_dict = OrderedDict() - if have_same_entries(stencil, get_stencil("D2Q9")): + if not nested_moments: moments = get_default_moment_set_for_stencil(stencil) - orthogonal_moments = gram_schmidt(moments, stencil) + 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()) - elif have_same_entries(stencil, get_stencil("D3Q15")): + + for moment_list in nested_moments: + rr = relaxation_rate_getter(moment_list) + for m in moment_list: + moment_to_relaxation_rate_dict[m] = rr + + 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 mrt_orthogonal_modes_literature(stencil, is_weighted, is_cumulant): + """ + Returns a list of lists of modes, grouped by common relaxation times. + This is for commonly used MRT models found in literature. + + Args: + stencil: nested tuple defining the discrete velocity space. See `get_stencil` + is_weighted: whether to use weighted or unweighted orthogonality + is_cumulant: whether a moment-based or cumulant-based model is desired + """ + x, y, z = MOMENT_SYMBOLS + one = sp.Rational(1, 1) + + if have_same_entries(stencil, get_stencil("D3Q15")) and is_weighted: sq = x ** 2 + y ** 2 + z ** 2 nested_moments = [ [one, x, y, z], # [0, 3, 5, 7] @@ -401,7 +434,7 @@ def create_mrt_orthogonal(stencil, relaxation_rate_getter=None, maxwellian_momen [3 * x ** 2 - sq, y ** 2 - z ** 2, x * y, y * z, x * z], # [9, 10, 11, 12, 13] [x * y * z] ] - elif have_same_entries(stencil, get_stencil("D3Q19")): + elif have_same_entries(stencil, get_stencil("D3Q19")) and is_weighted: # This MRT variant mentioned in the dissertation of Ulf Schiller # "Thermal fluctuations and boundary conditions in the lattice Boltzmann method" (2008), p. 24ff # There are some typos in the moment matrix on p.27 @@ -446,7 +479,7 @@ def create_mrt_orthogonal(stencil, relaxation_rate_getter=None, maxwellian_momen [(2 * sq - 3) * (3 * x ** 2 - sq), (2 * sq - 3) * (y ** 2 - z ** 2)], # [10, 12] [(y ** 2 - z ** 2) * x, (z ** 2 - x ** 2) * y, (x ** 2 - y ** 2) * z] # [16, 17, 18] ] - elif have_same_entries(stencil, get_stencil("D3Q27")): + elif have_same_entries(stencil, get_stencil("D3Q27")) and not is_weighted: if is_cumulant: nested_moments = [ [sp.sympify(1), x, y, z], # conserved @@ -512,15 +545,7 @@ def create_mrt_orthogonal(stencil, relaxation_rate_getter=None, maxwellian_momen raise NotImplementedError("No MRT model is available (yet) for this stencil. " "Create a custom MRT using 'create_with_discrete_maxwellian_eq_moments'") - for moment_list in nested_moments: - rr = relaxation_rate_getter(moment_list) - for m in moment_list: - moment_to_relaxation_rate_dict[m] = rr - - 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) + return nested_moments # ----------------------------------------- Comparison view for notebooks ---------------------------------------------- diff --git a/lbmpy_tests/test_momentbased_methods_equilibrium.py b/lbmpy_tests/test_momentbased_methods_equilibrium.py index 5f3381d37f3ac88bacf0c4c9a5515ec959255081..5aae948b05f9efcc36e52bb3df7d3f64806d03fa 100644 --- a/lbmpy_tests/test_momentbased_methods_equilibrium.py +++ b/lbmpy_tests/test_momentbased_methods_equilibrium.py @@ -7,7 +7,7 @@ import sympy as sp from lbmpy.creationfunctions import create_lb_method from lbmpy.maxwellian_equilibrium import discrete_maxwellian_equilibrium -from lbmpy.methods import create_mrt_orthogonal, create_srt, create_trt +from lbmpy.methods import create_mrt_orthogonal, create_srt, create_trt, mrt_orthogonal_modes_literature from lbmpy.relaxationrates import get_shear_relaxation_rate from lbmpy.stencils import get_stencil @@ -69,14 +69,26 @@ def test_relaxation_rate_setter(): def test_mrt_orthogonal(): - m = create_mrt_orthogonal(get_stencil("D2Q9"), maxwellian_moments=True) + m = create_mrt_orthogonal(get_stencil("D2Q9"), maxwellian_moments=True, weighted=False) assert m.is_orthogonal - m = create_mrt_orthogonal(get_stencil("D3Q15"), maxwellian_moments=True) + m = create_mrt_orthogonal(get_stencil("D2Q9"), maxwellian_moments=True, weighted=True) assert m.is_weighted_orthogonal - m = create_mrt_orthogonal(get_stencil("D3Q19"), maxwellian_moments=True) + m = create_mrt_orthogonal(get_stencil("D3Q19"), maxwellian_moments=True, weighted=False) + assert m.is_orthogonal + + m = create_mrt_orthogonal(get_stencil("D3Q19"), maxwellian_moments=True, weighted=True) + assert m.is_weighted_orthogonal + + moments = mrt_orthogonal_modes_literature(get_stencil("D3Q15"), True, False) + m = create_mrt_orthogonal(get_stencil("D3Q15"), maxwellian_moments=True, nested_moments=moments) + assert m.is_weighted_orthogonal + + moments = mrt_orthogonal_modes_literature(get_stencil("D3Q19"), True, False) + m = create_mrt_orthogonal(get_stencil("D3Q19"), maxwellian_moments=True, nested_moments=moments) assert m.is_weighted_orthogonal - m = create_mrt_orthogonal(get_stencil("D3Q27"), maxwellian_moments=True) + moments = mrt_orthogonal_modes_literature(get_stencil("D3Q27"), False, False) + m = create_mrt_orthogonal(get_stencil("D3Q27"), maxwellian_moments=True, nested_moments=moments) assert m.is_orthogonal