diff --git a/conftest.py b/conftest.py index e71dff56416d4fa2a5c01eab39e1853b90fe1969..ebd72bdc77cc352960a98b4a763feb18ce76628a 100644 --- a/conftest.py +++ b/conftest.py @@ -60,7 +60,10 @@ try: except ImportError: collect_ignore += [os.path.join(SCRIPT_FOLDER, "lbmpy_tests/benchmark"), os.path.join(SCRIPT_FOLDER, - "lbmpy_tests/full_scenarios/kida_vortex_flow/scenario_kida_vortex_flow.py")] + "lbmpy_tests/full_scenarios/kida_vortex_flow/scenario_kida_vortex_flow.py"), + os.path.join(SCRIPT_FOLDER, "lbmpy_tests/full_scenarios/shear_wave/scenario_shear_wave.py"), + os.path.join(SCRIPT_FOLDER, "lbmpy_tests/test_json_serializer.py"), + os.path.join(SCRIPT_FOLDER, "lbmpy/db.py")] if platform.system().lower() == 'windows': collect_ignore += [os.path.join(SCRIPT_FOLDER, "lbmpy_tests/test_quicktests.py")] diff --git a/doc/sphinx/lbmpy.bib b/doc/sphinx/lbmpy.bib index 88198b2dcd4685c7024604b0b878ab0cd95b94c0..896a6a2a8deef32d432b8d004b43938c1c19fa10 100644 --- a/doc/sphinx/lbmpy.bib +++ b/doc/sphinx/lbmpy.bib @@ -110,6 +110,24 @@ issn = {0898-1221}, doi = {10.1016/j.camwa.2015.05.001}, } +@article{geier2017, +author = {Geier, Martin and Pasquali, Andrea and Sch{\"{o}}nherr, Martin}, +title = {Parametrization of the Cumulant Lattice Boltzmann Method for Fourth Order Accurate Diffusion Part I}, +year = {2017}, +issue_date = {November 2017}, +publisher = {Academic Press Professional, Inc.}, +address = {USA}, +volume = {348}, +number = {C}, +issn = {0021-9991}, +url = {https://doi.org/10.1016/j.jcp.2017.05.040}, +doi = {10.1016/j.jcp.2017.05.040}, +journal = {J. Comput. Phys.}, +month = {nov}, +pages = {862–888}, +numpages = {27} +} + @Article{Coreixas2019, title = {Comprehensive comparison of collision models in the lattice Boltzmann framework: Theoretical investigations}, author = {Coreixas, Christophe and Chopard, Bastien and Latt, Jonas}, diff --git a/lbmpy/creationfunctions.py b/lbmpy/creationfunctions.py index 73769bf97feaf33479cdb69732c371765c89babe..e27501e2b501a1f3097fc2154dd962da66bedc4e 100644 --- a/lbmpy/creationfunctions.py +++ b/lbmpy/creationfunctions.py @@ -87,7 +87,7 @@ from pystencils.simp import sympy_cse, SimplificationStrategy from lbmpy.methods.abstractlbmethod import LbmCollisionRule, AbstractLbMethod from lbmpy.methods.cumulantbased import CumulantBasedLbMethod -# Filter out JobLib warnings. They are not usefull for use: +# Filter out JobLib warnings. They are not useful for use: # https://github.com/joblib/joblib/issues/683 filterwarnings("ignore", message="Persisting input arguments took") @@ -99,7 +99,7 @@ class LBMConfig: """ stencil: lbmpy.stencils.LBStencil = LBStencil(Stencil.D2Q9) """ - All stencils are defined in :class:`lbmpy.enums.Stencil`. From that :class:`lbmpy.stencils.LBStenil` + All stencils are defined in :class:`lbmpy.enums.Stencil`. From that :class:`lbmpy.stencils.LBStencil` class will be created """ method: Method = Method.SRT @@ -197,6 +197,13 @@ class LBMConfig: Special correction for D3Q27 cumulant LBMs. For Details see :mod:`lbmpy.methods.cumulantbased.galilean_correction` """ + fourth_order_correction: Union[float, bool] = False + """ + Special correction for rendering D3Q27 cumulant LBMs fourth-order accurate in diffusion. For Details see + :mod:`lbmpy.methods.cumulantbased.fourth_order_correction`. If set to `True`, the fourth-order correction is + employed without limiters (or more precisely with a very high limiter, practically disabling the limiters). If this + variable is set to a number, the latter is used for the limiters (uniformly for omega_3, omega_4 and omega_5). + """ collision_space_info: CollisionSpaceInfo = None """ Information about the LB method's collision space (see :class:`lbmpy.methods.creationfunctions.CollisionSpaceInfo`) @@ -646,6 +653,19 @@ def create_lb_collision_rule(lb_method=None, lbm_config=None, lbm_optimisation=N from lbmpy.methods.cumulantbased import add_galilean_correction collision_rule = add_galilean_correction(collision_rule) + if lbm_config.fourth_order_correction: + from lbmpy.methods.cumulantbased import add_fourth_order_correction + + # must provide a second relaxation rate in implementation; defaults to 1 + if len(lbm_config.relaxation_rates) == 1: + lbm_config.relaxation_rates.append(1) + + cumulant_limiter = 1e6 if lbm_config.fourth_order_correction is True else lbm_config.fourth_order_correction + collision_rule = add_fourth_order_correction(collision_rule=collision_rule, + shear_relaxation_rate=lbm_config.relaxation_rates[0], + bulk_relaxation_rate=lbm_config.relaxation_rates[1], + limiter=cumulant_limiter) + if lbm_config.entropic: if lbm_config.smagorinsky or lbm_config.cassons: raise ValueError("Choose either entropic, smagorinsky or cassons") @@ -752,11 +772,25 @@ def create_lb_method(lbm_config=None, **params): method_nr = lbm_config.method.name[-1] method = create_trt_kbc(dim, relaxation_rates[0], relaxation_rates[1], 'KBC-N' + method_nr, **common_params) elif lbm_config.method == Method.CUMULANT: + if lbm_config.fourth_order_correction: + if lbm_config.stencil.D != 3 and lbm_config.stencil.Q != 27: + raise ValueError("Fourth-order correction can only be applied to D3Q27 cumulant methods.") + + assert len(relaxation_rates) <= 2, "Optimal parametrisation for fourth-order cumulants needs either one " \ + "or two relaxation rates, associated with the shear (and bulk) " \ + "viscosity. All other relaxation rates are automatically chosen " \ + "optimally" + + # define method in terms of symbolic relaxation rates and assign optimal values later + from lbmpy.methods.cumulantbased.fourth_order_correction import FOURTH_ORDER_RELAXATION_RATE_SYMBOLS + relaxation_rates = FOURTH_ORDER_RELAXATION_RATE_SYMBOLS + if lbm_config.nested_moments is not None: method = create_cumulant( lbm_config.stencil, relaxation_rates, lbm_config.nested_moments, **cumulant_params) else: method = create_with_default_polynomial_cumulants(lbm_config.stencil, relaxation_rates, **cumulant_params) + elif lbm_config.method == Method.MONOMIAL_CUMULANT: method = create_with_monomial_cumulants(lbm_config.stencil, relaxation_rates, **cumulant_params) else: diff --git a/lbmpy/db.py b/lbmpy/db.py new file mode 100644 index 0000000000000000000000000000000000000000..bca65fb182a125600b2e309dd2d5784f6d4d8c47 --- /dev/null +++ b/lbmpy/db.py @@ -0,0 +1,47 @@ +import json +import six +import inspect + +from pystencils.runhelper.db import PystencilsJsonEncoder +from pystencils.simp import SimplificationStrategy +from lbmpy import LBStencil, Method, CollisionSpace +from lbmpy.creationfunctions import LBMConfig, LBMOptimisation +from lbmpy.methods import CollisionSpaceInfo +from lbmpy.forcemodels import AbstractForceModel +from lbmpy.non_newtonian_models import CassonsParameters + + +class LbmpyJsonEncoder(PystencilsJsonEncoder): + + def default(self, obj): + if isinstance(obj, (LBMConfig, LBMOptimisation, CollisionSpaceInfo, CassonsParameters)): + return obj.__dict__ + if isinstance(obj, (LBStencil, Method, CollisionSpace)): + return obj.name + if isinstance(obj, AbstractForceModel): + return obj.__class__.__name__ + if isinstance(obj, SimplificationStrategy): + return obj.__str__() + if inspect.isclass(obj): + return obj.__name__ + return PystencilsJsonEncoder.default(self, obj) + + +class LbmpyJsonSerializer(object): + + @classmethod + def serialize(cls, data): + if six.PY3: + if isinstance(data, bytes): + return json.dumps(data.decode('utf-8'), cls=LbmpyJsonEncoder, ensure_ascii=False).encode('utf-8') + else: + return json.dumps(data, cls=LbmpyJsonEncoder, ensure_ascii=False).encode('utf-8') + else: + return json.dumps(data, cls=LbmpyJsonEncoder, ensure_ascii=False).encode('utf-8') + + @classmethod + def deserialize(cls, data): + if six.PY3: + return json.loads(data.decode('utf-8')) + else: + return json.loads(data.decode('utf-8')) diff --git a/lbmpy/methods/abstractlbmethod.py b/lbmpy/methods/abstractlbmethod.py index 03747ac9a0808f545982490e35cb34dee1852394..096a3dd6f264a0a15b12b813a24a251d2abd1514 100644 --- a/lbmpy/methods/abstractlbmethod.py +++ b/lbmpy/methods/abstractlbmethod.py @@ -67,8 +67,8 @@ class AbstractLbMethod(abc.ABC): return d @property - def subs_dict_relxation_rate(self): - """returns a dictonary which maps the replaced numerical relaxation rates to its original numerical value""" + def subs_dict_relaxation_rate(self): + """returns a dictionary which maps the replaced numerical relaxation rates to its original numerical value""" result = dict() for i in range(self._stencil.Q): result[self.symbolic_relaxation_matrix[i, i]] = self.relaxation_matrix[i, i] diff --git a/lbmpy/methods/cumulantbased/__init__.py b/lbmpy/methods/cumulantbased/__init__.py index 939617543159a0d10584e170acfb9030f72a16bb..604b48038a5e75a44410fab1c3c6090c574d900f 100644 --- a/lbmpy/methods/cumulantbased/__init__.py +++ b/lbmpy/methods/cumulantbased/__init__.py @@ -1,4 +1,5 @@ from .cumulantbasedmethod import CumulantBasedLbMethod from .galilean_correction import add_galilean_correction +from .fourth_order_correction import add_fourth_order_correction -__all__ = ['CumulantBasedLbMethod', 'add_galilean_correction'] +__all__ = ['CumulantBasedLbMethod', 'add_galilean_correction', 'add_fourth_order_correction'] diff --git a/lbmpy/methods/cumulantbased/cumulantbasedmethod.py b/lbmpy/methods/cumulantbased/cumulantbasedmethod.py index c0bd07008daf2afb4e0a6867c54544512602dd0a..6d013958890056be5704544700cdabe6c3250de6 100644 --- a/lbmpy/methods/cumulantbased/cumulantbasedmethod.py +++ b/lbmpy/methods/cumulantbased/cumulantbasedmethod.py @@ -23,7 +23,7 @@ class CumulantBasedLbMethod(AbstractLbMethod): This class implements cumulant-based lattice boltzmann methods which relax all the non-conserved quantities as either monomial or polynomial cumulants. It is mostly inspired by the work presented in :cite:`geier2015`. - This method is implemented modularily as the transformation from populations to central moments to cumulants + This method is implemented modularly as the transformation from populations to central moments to cumulants is governed by subclasses of :class:`lbmpy.moment_transforms.AbstractMomentTransform` which can be specified by constructor argument. This allows the selection of the most efficient transformation for a given setup. @@ -124,7 +124,7 @@ class CumulantBasedLbMethod(AbstractLbMethod): @property def zeroth_order_equilibrium_moment_symbol(self, ): """Returns a symbol referring to the zeroth-order moment of this method's equilibrium distribution, - which is the area under it's curve + which is the area under its curve (see :attr:`lbmpy.equilibrium.AbstractEquilibrium.zeroth_order_moment_symbol`).""" return self._equilibrium.zeroth_order_moment_symbol diff --git a/lbmpy/methods/cumulantbased/fourth_order_correction.py b/lbmpy/methods/cumulantbased/fourth_order_correction.py new file mode 100644 index 0000000000000000000000000000000000000000..e3249f5f7f9253abb783d200c3469167ffa8d7ad --- /dev/null +++ b/lbmpy/methods/cumulantbased/fourth_order_correction.py @@ -0,0 +1,237 @@ +import sympy as sp + +from lbmpy.moment_transforms import PRE_COLLISION_MONOMIAL_CUMULANT, POST_COLLISION_CUMULANT +from lbmpy.moments import MOMENT_SYMBOLS, statistical_quantity_symbol +from lbmpy.stencils import Stencil, LBStencil +from pystencils import Assignment +from pystencils.simp.assignment_collection import AssignmentCollection +from .cumulantbasedmethod import CumulantBasedLbMethod + +X, Y, Z = MOMENT_SYMBOLS +CORRECTED_FOURTH_ORDER_POLYNOMIALS = [X ** 2 * Y ** 2 - 2 * X ** 2 * Z ** 2 + Y ** 2 * Z ** 2, + X ** 2 * Y ** 2 + X ** 2 * Z ** 2 - 2 * Y ** 2 * Z ** 2, + X ** 2 * Y ** 2 + X ** 2 * Z ** 2 + Y ** 2 * Z ** 2, + X ** 2 * Y * Z, + X * Y ** 2 * Z, + X * Y * Z ** 2] +FOURTH_ORDER_CORRECTION_SYMBOLS = sp.symbols("corr_fourth_:6") +FOURTH_ORDER_RELAXATION_RATE_SYMBOLS = sp.symbols("corr_rr_:10") + + +def add_fourth_order_correction(collision_rule, shear_relaxation_rate, bulk_relaxation_rate, limiter): + """Adds the fourth order correction terms (:cite:`geier2017`, eq. 44-49) to a given polynomial D3Q27 + cumulant collision rule.""" + method = collision_rule.method + + if not isinstance(method, CumulantBasedLbMethod) or method.stencil != LBStencil(Stencil.D3Q27): + raise ValueError("Fourth-order correction is only defined for D3Q27 cumulant methods.") + + polynomials = method.cumulants + rho = method.zeroth_order_equilibrium_moment_symbol + + if not (set(CORRECTED_FOURTH_ORDER_POLYNOMIALS) < set(polynomials)): + raise ValueError("Fourth order correction requires polynomial cumulants " + f"{', '.join(CORRECTED_FOURTH_ORDER_POLYNOMIALS)} to be present") + + # Call + # PC1 = (x^2 * y^2 - 2 * x^2 * z^2 + y^2 * z^2), + # PC2 = (x^2 * y^2 + x^2 * z^2 - 2 * y^2 * z^2), + # PC3 = (x^2 * y^2 + x^2 * z^2 + y^2 * z^2), + # PC4 = (x^2 * y * z), + # PC5 = (x * y^2 * z), + # PC6 = (x * y * z^2) + poly_symbols = [sp.Symbol(f'{POST_COLLISION_CUMULANT}_{polynomials.index(poly)}') + for poly in CORRECTED_FOURTH_ORDER_POLYNOMIALS] + + a_symb, b_symb = sp.symbols("a_corr, b_corr") + a, b = get_optimal_additional_parameters(shear_relaxation_rate, bulk_relaxation_rate) + correction_terms = get_fourth_order_correction_terms(method.relaxation_rate_dict, rho, a_symb, b_symb) + optimal_parametrisation = get_optimal_parametrisation_with_limiters(collision_rule, shear_relaxation_rate, + bulk_relaxation_rate, limiter) + + subexp_dict = collision_rule.subexpressions_dict + subexp_dict = {**subexp_dict, + a_symb: a, + b_symb: b, + **correction_terms.subexpressions_dict, + **optimal_parametrisation.subexpressions_dict, + **correction_terms.main_assignments_dict, + **optimal_parametrisation.main_assignments_dict} + for sym, cor in zip(poly_symbols, FOURTH_ORDER_CORRECTION_SYMBOLS): + subexp_dict[sym] += cor + + collision_rule.set_sub_expressions_from_dict(subexp_dict) + collision_rule.topological_sort() + + return collision_rule + + +def get_optimal_additional_parameters(shear_relaxation_rate, bulk_relaxation_rate): + """ + Calculates the optimal parametrization for the additional parameters provided in :cite:`geier2017` + Equations 115-116. + """ + + omega_1 = shear_relaxation_rate + omega_2 = bulk_relaxation_rate + + omega_11 = omega_1 * omega_1 + omega_12 = omega_1 * omega_2 + omega_22 = omega_2 * omega_2 + + two = sp.Float(2) + three = sp.Float(3) + four = sp.Float(4) + nine = sp.Float(9) + + denom_ab = (omega_1 - omega_2) * (omega_2 * (two + three * omega_1) - sp.Float(8) * omega_1) + + a = (four * omega_11 + two * omega_12 * (omega_1 - sp.Float(6)) + omega_22 * ( + omega_1 * (sp.Float(10) - three * omega_1) - four)) / denom_ab + b = (four * omega_12 * (nine * omega_1 - sp.Float(16)) - four * omega_11 - two * omega_22 * ( + two + nine * omega_1 * (omega_1 - two))) / (three * denom_ab) + + return a, b + + +def get_fourth_order_correction_terms(rrate_dict, rho, a, b): + pc1, pc2, pc3, pc4, pc5, pc6 = CORRECTED_FOURTH_ORDER_POLYNOMIALS + + omega_1 = rrate_dict[X * Y] + omega_2 = rrate_dict[X ** 2 + Y ** 2 + Z ** 2] + + try: + omega_6 = rrate_dict[pc1] + assert omega_6 == rrate_dict[pc2], \ + "Cumulants (x^2 - y^2) and (x^2 - z^2) must have the same relaxation rate" + omega_7 = rrate_dict[pc3] + omega_8 = rrate_dict[pc4] + assert omega_8 == rrate_dict[pc5] == rrate_dict[pc6] + except IndexError: + raise ValueError("For the fourth order correction, all six polynomial cumulants" + "(x^2 * y^2 - 2 * x^2 * z^2 + y^2 * z^2)," + "(x^2 * y^2 + x^2 * z^2 - 2 * y^2 * z^2)," + "(x^2 * y^2 + x^2 * z^2 + y^2 * z^2)," + "(x^2 * y * z), (x * y^2 * z) and (x * y * z^2) must be present!") + + dxu, dyv, dzw, dxvdyu, dxwdzu, dywdzv = sp.symbols('Dx, Dy, Dz, DxvDyu, DxwDzu, DywDzv') + c_xy = statistical_quantity_symbol(PRE_COLLISION_MONOMIAL_CUMULANT, (1, 1, 0)) + c_xz = statistical_quantity_symbol(PRE_COLLISION_MONOMIAL_CUMULANT, (1, 0, 1)) + c_yz = statistical_quantity_symbol(PRE_COLLISION_MONOMIAL_CUMULANT, (0, 1, 1)) + c_xx = statistical_quantity_symbol(PRE_COLLISION_MONOMIAL_CUMULANT, (2, 0, 0)) + c_yy = statistical_quantity_symbol(PRE_COLLISION_MONOMIAL_CUMULANT, (0, 2, 0)) + c_zz = statistical_quantity_symbol(PRE_COLLISION_MONOMIAL_CUMULANT, (0, 0, 2)) + + cor1, cor2, cor3, cor4, cor5, cor6 = FOURTH_ORDER_CORRECTION_SYMBOLS + + one = sp.Float(1) + two = sp.Float(2) + three = sp.Float(3) + + # Derivative Approximations + subexpressions = [ + Assignment(dxu, - omega_1 / (two * rho) * (two * c_xx - c_yy - c_zz) + - omega_2 / (two * rho) * (c_xx + c_yy + c_zz - rho)), + Assignment(dyv, dxu + (three * omega_1) / (two * rho) * (c_xx - c_yy)), + Assignment(dzw, dxu + (three * omega_1) / (two * rho) * (c_xx - c_zz)), + Assignment(dxvdyu, - three * omega_1 / rho * c_xy), + Assignment(dxwdzu, - three * omega_1 / rho * c_xz), + Assignment(dywdzv, - three * omega_1 / rho * c_yz)] + + one_half = sp.Rational(1, 2) + one_over_three = sp.Rational(1, 3) + two_over_three = sp.Rational(2, 3) + four_over_three = sp.Rational(4, 3) + + # Correction Terms + main_assignments = [ + Assignment(cor1, two_over_three * (one / omega_1 - one_half) * omega_6 * a * rho * (dxu - two * dyv + dzw)), + Assignment(cor2, two_over_three * (one / omega_1 - one_half) * omega_6 * a * rho * (dxu + dyv - two * dzw)), + Assignment(cor3, - four_over_three * (one / omega_1 - one_half) * omega_7 * a * rho * (dxu + dyv + dzw)), + Assignment(cor4, - one_over_three * (one / omega_1 - one_half) * omega_8 * b * rho * dywdzv), + Assignment(cor5, - one_over_three * (one / omega_1 - one_half) * omega_8 * b * rho * dxwdzu), + Assignment(cor6, - one_over_three * (one / omega_1 - one_half) * omega_8 * b * rho * dxvdyu)] + + return AssignmentCollection(main_assignments=main_assignments, subexpressions=subexpressions) + + +def get_optimal_parametrisation_with_limiters(collision_rule, shear_relaxation_rate, bulk_relaxation_rate, limiter): + """ + Calculates the optimal parametrization for the relaxation rates provided in :cite:`geier2017` + Equations 112-114. + """ + + # if omega numbers + # assert omega_1 != omega_2, "Relaxation rates associated with shear and bulk viscosity must not be identical." + # assert omega_1 > 7/4 + + omega_1 = FOURTH_ORDER_RELAXATION_RATE_SYMBOLS[0] + omega_2 = FOURTH_ORDER_RELAXATION_RATE_SYMBOLS[1] + + non_limited_omegas = sp.symbols("non_limited_omega_3:6") + limited_omegas = sp.symbols("limited_omega_3:6") + + omega_11 = omega_1 * omega_1 + omega_12 = omega_1 * omega_2 + omega_22 = omega_2 * omega_2 + + one = sp.Float(1) + two = sp.Float(2) + three = sp.Float(3) + five = sp.Float(5) + six = sp.Float(6) + seven = sp.Float(7) + eight = sp.Float(8) + nine = sp.Float(9) + + omega_3 = (eight * (omega_1 - two) * (omega_2 * (three * omega_1 - one) - five * omega_1)) / ( + eight * (five - two * omega_1) * omega_1 + omega_2 * (eight + omega_1 * (nine * omega_1 - sp.Float(26)))) + + omega_4 = (eight * (omega_1 - two) * (omega_1 + omega_2 * (three * omega_1 - seven))) / ( + omega_2 * (sp.Float(56) - sp.Float(42) * omega_1 + nine * omega_11) - eight * omega_1) + + omega_5 = (sp.Float(24) * (omega_1 - two) * (sp.Float(4) * omega_11 + omega_12 * ( + sp.Float(18) - sp.Float(13) * omega_1) + omega_22 * (two + omega_1 * ( + six * omega_1 - sp.Float(11))))) / (sp.Float(16) * omega_11 * (omega_1 - six) - two * omega_12 * ( + sp.Float(216) + five * omega_1 * (nine * omega_1 - sp.Float(46))) + omega_22 * (omega_1 * ( + three * omega_1 - sp.Float(10)) * (sp.Float(15) * omega_1 - sp.Float(28)) - sp.Float(48))) + + rho = collision_rule.method.zeroth_order_equilibrium_moment_symbol + + # add limiters to improve stability + c_xyy = statistical_quantity_symbol(PRE_COLLISION_MONOMIAL_CUMULANT, (1, 2, 0)) + c_xzz = statistical_quantity_symbol(PRE_COLLISION_MONOMIAL_CUMULANT, (1, 0, 2)) + c_xyz = statistical_quantity_symbol(PRE_COLLISION_MONOMIAL_CUMULANT, (1, 1, 1)) + abs_c_xyy_plus_xzz = sp.Abs(c_xyy + c_xzz) + abs_c_xyy_minus_xzz = sp.Abs(c_xyy - c_xzz) + abs_c_xyz = sp.Abs(c_xyz) + + limited_omega_3 = non_limited_omegas[0] + ((one - non_limited_omegas[0]) * abs_c_xyy_plus_xzz) / \ + (rho * limiter + abs_c_xyy_plus_xzz) + limited_omega_4 = non_limited_omegas[1] + ((one - non_limited_omegas[1]) * abs_c_xyy_minus_xzz) / \ + (rho * limiter + abs_c_xyy_minus_xzz) + limited_omega_5 = non_limited_omegas[2] + ((one - non_limited_omegas[2]) * abs_c_xyz) / (rho * limiter + abs_c_xyz) + + subexpressions = [ + Assignment(non_limited_omegas[0], omega_3), + Assignment(non_limited_omegas[1], omega_4), + Assignment(non_limited_omegas[2], omega_5), + Assignment(limited_omegas[0], limited_omega_3), + Assignment(limited_omegas[1], limited_omega_4), + Assignment(limited_omegas[2], limited_omega_5)] + + # Correction Terms + main_assignments = [ + Assignment(FOURTH_ORDER_RELAXATION_RATE_SYMBOLS[0], shear_relaxation_rate), + Assignment(FOURTH_ORDER_RELAXATION_RATE_SYMBOLS[1], bulk_relaxation_rate), + Assignment(FOURTH_ORDER_RELAXATION_RATE_SYMBOLS[2], limited_omegas[0]), + Assignment(FOURTH_ORDER_RELAXATION_RATE_SYMBOLS[3], limited_omegas[1]), + Assignment(FOURTH_ORDER_RELAXATION_RATE_SYMBOLS[4], limited_omegas[2]), + Assignment(FOURTH_ORDER_RELAXATION_RATE_SYMBOLS[5], one), + Assignment(FOURTH_ORDER_RELAXATION_RATE_SYMBOLS[6], one), + Assignment(FOURTH_ORDER_RELAXATION_RATE_SYMBOLS[7], one), + Assignment(FOURTH_ORDER_RELAXATION_RATE_SYMBOLS[8], one), + Assignment(FOURTH_ORDER_RELAXATION_RATE_SYMBOLS[9], one), + ] + + return AssignmentCollection(main_assignments=main_assignments, subexpressions=subexpressions) diff --git a/lbmpy/methods/momentbased/entropic.py b/lbmpy/methods/momentbased/entropic.py index a9be8b1de0c07abb57b58c8074e7d7616a66c5ca..fae51497f82412cc7aa7468174d0e3eb424a7645 100644 --- a/lbmpy/methods/momentbased/entropic.py +++ b/lbmpy/methods/momentbased/entropic.py @@ -286,7 +286,7 @@ def _get_relaxation_rates(collision_rule): omega_s = get_shear_relaxation_rate(method) # if the shear relaxation rate is not specified as a symbol look for its symbolic counter part in the subs dict - for symbolic_rr, rr in method.subs_dict_relxation_rate.items(): + for symbolic_rr, rr in method.subs_dict_relaxation_rate.items(): if omega_s == rr: omega_s = symbolic_rr diff --git a/lbmpy/methods/momentbased/momentbasedmethod.py b/lbmpy/methods/momentbased/momentbasedmethod.py index 2ce9d51580b6c9d8ea37344fe2d5e606feaae87f..79aee5c813b71c358e93964b52b84b6b1532269f 100644 --- a/lbmpy/methods/momentbased/momentbasedmethod.py +++ b/lbmpy/methods/momentbased/momentbasedmethod.py @@ -16,8 +16,8 @@ from lbmpy.moment_transforms import PdfsToMomentsByChimeraTransform class MomentBasedLbMethod(AbstractLbMethod): """ Moment based LBM is a class to represent the single (SRT), two (TRT) and multi relaxation time (MRT) methods. - These methods work by transforming the pdfs into moment space using a linear transformation. In the moment - space each component (moment) is relaxed to an equilibrium moment by a certain relaxation rate. These + These methods work by transforming the pdfs into moment space using a linear transformation. In the moment-space + each component (moment) is relaxed to an equilibrium moment by a certain relaxation rate. These equilibrium moments can e.g. be determined by taking the equilibrium moments of the continuous Maxwellian. Parameters: @@ -378,7 +378,7 @@ class MomentBasedLbMethod(AbstractLbMethod): subexpressions += m_post_to_f_post_eqs.subexpressions main_assignments = m_post_to_f_post_eqs.main_assignments else: - # For SRT, TRT by default, and whenever customly required, derive equations entirely in + # For SRT, TRT by default, and whenever customarily required, derive equations entirely in # population space if self._zero_centered and not self._equilibrium.deviation_only: raise Exception("Can only derive population-space equations for zero-centered storage" diff --git a/lbmpy/scenarios.py b/lbmpy/scenarios.py index 861bad743f5022af33983a132548b879c9bc5729..484b3ad6833eae588bcdd502ce7dfadf603e597b 100644 --- a/lbmpy/scenarios.py +++ b/lbmpy/scenarios.py @@ -42,10 +42,10 @@ def create_fully_periodic_flow(initial_velocity, periodicity_in_kernel=False, lb initial_velocity: numpy array that defines an initial velocity for each cell. The shape of this array determines the domain size. periodicity_in_kernel: don't use boundary handling for periodicity, but directly generate the kernel periodic - lbm_kernel: a LBM function, which would otherwise automatically created + lbm_kernel: an LBM function, which would otherwise automatically created data_handling: data handling instance that is used to create the necessary fields. If a data handling is passed the periodicity and parallel arguments are ignored. - parallel: True for distributed memory parallelization with walberla + parallel: True for distributed memory parallelization with waLBerla kwargs: other parameters are passed on to the method, see :mod:`lbmpy.creationfunctions` Returns: @@ -76,9 +76,9 @@ def create_lid_driven_cavity(domain_size=None, lid_velocity=0.005, lbm_kernel=No Args: domain_size: tuple specifying the number of cells in each dimension lid_velocity: x velocity of lid in lattice coordinates. - lbm_kernel: a LBM function, which would otherwise automatically created + lbm_kernel: an LBM function, which would otherwise automatically created kwargs: other parameters are passed on to the method, see :mod:`lbmpy.creationfunctions` - parallel: True for distributed memory parallelization with walberla + parallel: True for distributed memory parallelization with waLBerla data_handling: see documentation of :func:`create_fully_periodic_flow` Returns: instance of :class:`Scenario` diff --git a/lbmpy_tests/cumulantmethod/test_flow_around_sphere.py b/lbmpy_tests/cumulantmethod/test_flow_around_sphere.py index 6db3fa9fbd3c91127b305cfda4864464763b2d64..ad5707bd13abcf14905455987aa46ce00dda4356 100644 --- a/lbmpy_tests/cumulantmethod/test_flow_around_sphere.py +++ b/lbmpy_tests/cumulantmethod/test_flow_around_sphere.py @@ -16,7 +16,7 @@ from pystencils import create_kernel, create_data_handling, Assignment, Target, from pystencils.slicing import slice_from_direction, get_slice_before_ghost_layer -def flow_around_sphere(stencil, galilean_correction, L_LU, total_steps): +def flow_around_sphere(stencil, galilean_correction, fourth_order_correction, L_LU, total_steps): if galilean_correction and stencil.Q != 27: pytest.skip() @@ -38,7 +38,7 @@ def flow_around_sphere(stencil, galilean_correction, L_LU, total_steps): lbm_config = LBMConfig(stencil=stencil, method=Method.CUMULANT, relaxation_rate=omega_v, compressible=True, - galilean_correction=galilean_correction) + galilean_correction=galilean_correction, fourth_order_correction=fourth_order_correction) lbm_opt = LBMOptimisation(pre_simplification=True) config = CreateKernelConfig(target=target) @@ -135,14 +135,22 @@ def flow_around_sphere(stencil, galilean_correction, L_LU, total_steps): @pytest.mark.parametrize('stencil', [Stencil.D2Q9, Stencil.D3Q19, Stencil.D3Q27]) @pytest.mark.parametrize('galilean_correction', [False, True]) -def test_flow_around_sphere_short(stencil, galilean_correction): +@pytest.mark.parametrize('fourth_order_correction', [False, True]) +def test_flow_around_sphere_short(stencil, galilean_correction, fourth_order_correction): pytest.importorskip('cupy') - flow_around_sphere(LBStencil(stencil), galilean_correction, 5, 200) + stencil = LBStencil(stencil) + if fourth_order_correction and stencil.Q != 27: + pytest.skip("Fourth-order correction only defined for D3Q27 stencil.") + flow_around_sphere(stencil, galilean_correction, fourth_order_correction, 5, 200) @pytest.mark.parametrize('stencil', [Stencil.D2Q9, Stencil.D3Q19, Stencil.D3Q27]) @pytest.mark.parametrize('galilean_correction', [False, True]) +@pytest.mark.parametrize('fourth_order_correction', [False, 0.01]) @pytest.mark.longrun -def test_flow_around_sphere_long(stencil, galilean_correction): +def test_flow_around_sphere_long(stencil, galilean_correction, fourth_order_correction): pytest.importorskip('cupy') - flow_around_sphere(LBStencil(stencil), galilean_correction, 20, 3000) + stencil = LBStencil(stencil) + if fourth_order_correction and stencil.Q != 27: + pytest.skip("Fourth-order correction only defined for D3Q27 stencil.") + flow_around_sphere(stencil, galilean_correction, fourth_order_correction, 20, 3000) diff --git a/lbmpy_tests/full_scenarios/shear_wave/scenario_shear_wave.py b/lbmpy_tests/full_scenarios/shear_wave/scenario_shear_wave.py index cd5e73b7953216c3dd22c79490ecf29c178dc944..8d91315eb447510f336082a64448435eab068731 100644 --- a/lbmpy_tests/full_scenarios/shear_wave/scenario_shear_wave.py +++ b/lbmpy_tests/full_scenarios/shear_wave/scenario_shear_wave.py @@ -5,15 +5,16 @@ Chapter 5.1 """ import numpy as np -import sympy as sp - import pytest -from pystencils import Target +import sympy as sp -from lbmpy.creationfunctions import update_with_default_parameters +from lbmpy import LatticeBoltzmannStep, LBStencil +from lbmpy.creationfunctions import LBMConfig, LBMOptimisation +from lbmpy.db import LbmpyJsonSerializer +from lbmpy.enums import Method, Stencil from lbmpy.relaxationrates import ( relaxation_rate_from_lattice_viscosity, relaxation_rate_from_magic_number) -from lbmpy.scenarios import create_fully_periodic_flow +from pystencils import Target, create_data_handling, CreateKernelConfig def get_exponent_term(l, **kwargs): @@ -53,14 +54,13 @@ def get_analytical_solution(l, l_0, u_0, v_0, nu, t): def plot_y_velocity(vel, **kwargs): import matplotlib.pyplot as plt - from matplotlib import cm - vel = vel[:, vel.shape[1]//2, :, 1] + vel = vel[:, vel.shape[1] // 2, :, 1] ranges = [np.arange(n, dtype=float) for n in vel.shape] x, y = np.meshgrid(*ranges, indexing='ij') fig = plt.gcf() ax = fig.gca(projection='3d') - ax.plot_surface(x, y, vel, cmap=cm.coolwarm, rstride=2, cstride=2, + ax.plot_surface(x, y, vel, cmap='coolwarm', rstride=2, cstride=2, linewidth=0, antialiased=True, **kwargs) @@ -71,9 +71,9 @@ def fit_and_get_slope(x_values, y_values): def get_phase_error(phases, evaluation_interval): - xValues = np.arange(len(phases) * evaluation_interval, step=evaluation_interval) - phaseError = fit_and_get_slope(xValues, phases) - return phaseError + x_values = np.arange(len(phases) * evaluation_interval, step=evaluation_interval) + phase_error = fit_and_get_slope(x_values, phases) + return phase_error def get_viscosity(abs_values, evaluation_interval, l): @@ -92,33 +92,44 @@ def get_amplitude_and_phase(vel_slice): return fft_abs[max_index], fft_phase[max_index] -def run(l, l_0, u_0, v_0, nu, y_size, periodicity_in_kernel, **kwargs): +def run(l, l_0, u_0, v_0, nu, y_size, lbm_config, lbm_optimisation, config): inv_result = { 'viscosity_error': np.nan, 'phase_error': np.nan, 'mlups': np.nan, } - if 'initial_velocity' in kwargs: - del kwargs['initial_velocity'] + if lbm_config.initial_velocity: + # no manually specified initial velocity allowed in shear wave setup + lbm_config.initial_velocity = None - print("Running size l=%d nu=%f " % (l, nu), kwargs) + print(f"Running size l={l} nu={nu}") initial_vel_arr = get_initial_velocity_field(l, l_0, u_0, v_0, y_size) omega = relaxation_rate_from_lattice_viscosity(nu) - kwargs['relaxation_rates'] = [sp.sympify(r) for r in kwargs['relaxation_rates']] - if 'entropic' not in kwargs or not kwargs['entropic']: - kwargs['relaxation_rates'] = [r.subs(sp.Symbol("omega"), omega) for r in kwargs['relaxation_rates']] + if lbm_config.fourth_order_correction and omega < 1.75: + pytest.skip("Fourth-order correction only allowed for omega >= 1.75.") + + lbm_config.relaxation_rates = [sp.sympify(r) for r in lbm_config.relaxation_rates] + lbm_config.relaxation_rates = [r.subs(sp.Symbol("omega"), omega) for r in lbm_config.relaxation_rates] + + periodicity_in_kernel = (lbm_optimisation.builtin_periodicity != (False, False, False)) + domain_size = initial_vel_arr.shape[:-1] - scenario = create_fully_periodic_flow(initial_vel_arr, periodicity_in_kernel=periodicity_in_kernel, **kwargs) + data_handling = create_data_handling(domain_size, periodicity=not periodicity_in_kernel, + default_ghost_layers=1, parallel=False) - if 'entropic' in kwargs and kwargs['entropic']: - scenario.kernelParams['omega'] = kwargs['relaxation_rates'][0].subs(sp.Symbol("omega"), omega) + scenario = LatticeBoltzmannStep(data_handling=data_handling, name="periodic_scenario", lbm_config=lbm_config, + lbm_optimisation=lbm_optimisation, config=config) + for b in scenario.data_handling.iterate(ghost_layers=False): + np.copyto(b[scenario.velocity_data_name], initial_vel_arr[b.global_slice]) + scenario.set_pdf_fields_from_macroscopic_values() total_time_steps = 20000 * (l // l_0) ** 2 initial_time_steps = 11000 * (l // l_0) ** 2 eval_interval = 1000 * (l // l_0) ** 2 scenario.run(initial_time_steps) if np.isnan(scenario.velocity_slice()).any(): + print(" Result", inv_result) return inv_result magnitudes = [] @@ -149,65 +160,77 @@ def run(l, l_0, u_0, v_0, nu, y_size, periodicity_in_kernel, **kwargs): def create_full_parameter_study(): from pystencils.runhelper import ParameterStudy - params = { + setup_params = { 'l_0': 32, 'u_0': 0.096, 'v_0': 0.1, - 'ySize': 1, - 'periodicityInKernel': True, - 'stencil': 'D3Q27', - 'compressible': True, + 'y_size': 1 } + + omega, omega_f = sp.symbols("omega, omega_f") + ls = [32 * 2 ** i for i in range(0, 5)] nus = [1e-2, 1e-3, 1e-4, 1e-5] - srt_and_trt_methods = [{'method': method, - 'stencil': stencil, - 'compressible': comp, - 'relaxation_rates': ["omega", str(relaxation_rate_from_magic_number(sp.Symbol("omega")))], - 'equilibrium_order': eqOrder, - 'continuous_equilibrium': mbEq, - 'optimization': {'target': Target.CPU, 'split': True, 'cse_pdfs': True}} - for method in ('srt', 'trt') - for stencil in ('D3Q19', 'D3Q27') + srt_and_trt_methods = [LBMConfig(method=method, + stencil=LBStencil(stencil), + compressible=comp, + relaxation_rates=[omega, str(relaxation_rate_from_magic_number(omega))], + equilibrium_order=eqOrder, + continuous_equilibrium=mbEq) + for method in (Method.SRT, Method.TRT) + for stencil in (Stencil.D3Q19, Stencil.D3Q27) for comp in (True, False) for eqOrder in (1, 2, 3) for mbEq in (True, False)] - methods = [{'method': 'trt', 'relaxation_rates': ["omega", 1]}, - {'method': 'mrt3', 'relaxation_rates': ["omega", 1, 1], 'equilibrium_order': 2}, - {'method': 'mrt3', 'relaxation_rates': ["omega", 1, 1], 'equilibrium_order': 3}, - {'method': 'mrt3', 'cumulant': True, 'relaxation_rates': ["omega", 1, 1], # cumulant - 'continuous_equilibrium': True, 'equilibrium_order': 3, - 'optimization': {'cse_global': True}}, - {'method': 'trt-kbc-n4', 'relaxation_rates': ["omega", "omega_f"], 'entropic': True, # entropic order 2 - 'continuous_equilibrium': True, 'equilibrium_order': 2}, - {'method': 'trt-kbc-n4', 'relaxation_rates': ["omega", "omega_f"], 'entropic': True, # entropic order 3 - 'continuous_equilibrium': True, 'equilibrium_order': 3}, - - # entropic cumulant: - {'method': 'trt-kbc-n4', 'relaxation_rates': ["omega", "omega_f"], 'entropic': True, - 'cumulant': True, 'continuous_equilibrium': True, 'equilibrium_order': 3}, - {'method': 'trt-kbc-n2', 'relaxation_rates': ["omega", "omega_f"], 'entropic': True, - 'cumulant': True, 'continuous_equilibrium': True, 'equilibrium_order': 3}, - {'method': 'mrt3', 'relaxation_rates': ["omega", "omega_f", "omega_f"], 'entropic': True, - 'cumulant': True, 'continuous_equilibrium': True, 'equilibrium_order': 3}, + optimization_srt_trt = LBMOptimisation(split=True, cse_pdfs=True) + + config = CreateKernelConfig(target=Target.CPU) + + methods = [LBMConfig(method=Method.TRT, relaxation_rates=[omega, 1]), + LBMConfig(method=Method.MRT, relaxation_rates=[omega], equilibrium_order=2), + LBMConfig(method=Method.MRT, relaxation_rates=[omega], equilibrium_order=3), + LBMConfig(method=Method.CUMULANT, relaxation_rates=[omega], # cumulant + compressible=True, continuous_equilibrium=True, equilibrium_order=3), + LBMConfig(method=Method.CUMULANT, relaxation_rates=[omega], # cumulant with fourth-order correction + compressible=True, continuous_equilibrium=True, fourth_order_correction=0.1), + LBMConfig(method=Method.TRT_KBC_N4, relaxation_rates=[omega, omega_f], entropic=True, + zero_centered=False, # entropic order 2 + continuous_equilibrium=True, equilibrium_order=2), + LBMConfig(method=Method.TRT_KBC_N4, relaxation_rates=[omega, omega_f], entropic=True, + zero_centered=False, # entropic order 3 + continuous_equilibrium=True, equilibrium_order=3), + + # entropic cumulant: not supported for the moment + # LBMConfig(method=Method.CUMULANT, relaxation_rates=["omega", "omega_f"], entropic=True, zero_centered=False, + # compressible=True, continuous_equilibrium=True, equilibrium_order=3) ] - parameter_study = ParameterStudy(run, database_connector="shear_wave_db") + parameter_study = ParameterStudy(run, database_connector="shear_wave_db", + serializer_info=('lbmpy_serializer', LbmpyJsonSerializer)) for L in ls: for nu in nus: - for methodParams in methods + srt_and_trt_methods: - simulation_params = params.copy() - simulation_params.update(methodParams) - if 'optimization' not in simulation_params: - simulation_params['optimization'] = {} - new_params, new_opt_params = update_with_default_parameters(simulation_params, - simulation_params['optimization'], False) - simulation_params = new_params - simulation_params['optimization'] = new_opt_params - - simulation_params['L'] = L + for methodParams in srt_and_trt_methods: + simulation_params = setup_params.copy() + + simulation_params['lbm_config'] = methodParams + simulation_params['lbm_optimisation'] = optimization_srt_trt + simulation_params['config'] = config + + simulation_params['l'] = L + simulation_params['nu'] = nu + l_0 = simulation_params['l_0'] + parameter_study.add_run(simulation_params.copy(), weight=(L / l_0) ** 4) + + for methodParams in methods: + simulation_params = setup_params.copy() + + simulation_params['lbm_config'] = methodParams + simulation_params['lbm_optimisation'] = LBMOptimisation() + simulation_params['config'] = config + + simulation_params['l'] = L simulation_params['nu'] = nu l_0 = simulation_params['l_0'] parameter_study.add_run(simulation_params.copy(), weight=(L / l_0) ** 4) @@ -217,13 +240,23 @@ def create_full_parameter_study(): def test_shear_wave(): pytest.importorskip('cupy') params = { + 'y_size': 1, 'l_0': 32, 'u_0': 0.096, 'v_0': 0.1, - 'stencil': 'D3Q19', - 'compressible': True, - "optimization": {"target": Target.GPU} + 'l': 32, + 'nu': 1e-2, } - run(32, nu=1e-2, equilibrium_order=2, method='srt', y_size=1, periodicity_in_kernel=True, - relaxation_rates=[sp.Symbol("omega"), 5, 5], continuous_equilibrium=True, **params) + + kernel_config = CreateKernelConfig(target=Target.GPU) + lbm_config = LBMConfig(method=Method.SRT, relaxation_rates=[sp.Symbol("omega")], stencil=LBStencil(Stencil.D3Q27), + compressible=True, continuous_equilibrium=True, equilibrium_order=2) + + run(**params, lbm_config=lbm_config, config=kernel_config, lbm_optimisation=LBMOptimisation()) + + +@pytest.mark.longrun +def test_all_scenarios(): + parameter_study = create_full_parameter_study() + parameter_study.run() diff --git a/lbmpy_tests/test_force.py b/lbmpy_tests/test_force.py index 7ac94f42b5cf649147cbefa5830d2221c628cc14..f0f59bb5490cb753d4f7b0e5efb70ec65c2b9caf 100644 --- a/lbmpy_tests/test_force.py +++ b/lbmpy_tests/test_force.py @@ -197,7 +197,7 @@ def test_literature(force_model, stencil, method): assert len(omega_momentum) == 1 omega_momentum = omega_momentum[0] - subs_dict = lb_method.subs_dict_relxation_rate + subs_dict = lb_method.subs_dict_relaxation_rate force_term = sp.simplify(lb_method.force_model(lb_method).subs(subs_dict)) u = sp.Matrix(lb_method.first_order_equilibrium_moment_symbols) rho = lb_method.conserved_quantity_computation.density_symbol @@ -282,7 +282,7 @@ def test_modes_central_moment(force_model, compressible): compressible=compressible, force_model=force_model, force=tuple(F)) method = create_lb_method(lbm_config=lbm_config) - subs_dict = method.subs_dict_relxation_rate + subs_dict = method.subs_dict_relaxation_rate force_moments = method.force_model.central_moment_space_forcing(method) force_moments = force_moments.subs(subs_dict) @@ -310,7 +310,7 @@ def test_symmetric_forcing_equivalence(force_model, compressible): if not method.force_model.has_symmetric_central_moment_forcing: return True - subs_dict = method.subs_dict_relxation_rate + subs_dict = method.subs_dict_relaxation_rate force_moments = method.force_model.central_moment_space_forcing(method) force_moments = force_moments.subs(subs_dict) @@ -335,7 +335,7 @@ def test_modes_central_moment_longrun(stencil, force_model, compressible): compressible=compressible, force_model=force_model, force=tuple(F)) method = create_lb_method(lbm_config=lbm_config) - subs_dict = method.subs_dict_relxation_rate + subs_dict = method.subs_dict_relaxation_rate force_moments = method.force_model.moment_space_forcing(method) force_moments = force_moments.subs(subs_dict) @@ -359,7 +359,7 @@ def _check_modes(stencil, force_model, compressible): compressible=compressible, force_model=force_model, force=tuple(F)) method = create_lb_method(lbm_config=lbm_config) - subs_dict = method.subs_dict_relxation_rate + subs_dict = method.subs_dict_relaxation_rate force_moments = method.force_model.moment_space_forcing(method) force_moments = force_moments.subs(subs_dict) diff --git a/lbmpy_tests/test_json_serializer.py b/lbmpy_tests/test_json_serializer.py new file mode 100644 index 0000000000000000000000000000000000000000..3429f12bb6ba0eff62e76e127707f08b290d8547 --- /dev/null +++ b/lbmpy_tests/test_json_serializer.py @@ -0,0 +1,40 @@ +""" +Test the lbmpy-specific JSON encoder and serializer as used in the Database class. +""" + +import tempfile +import pystencils as ps + +from lbmpy import Stencil, Method, ForceModel +from lbmpy.advanced_streaming import Timestep +from lbmpy.creationfunctions import LBMConfig, LBMOptimisation, LBStencil +from lbmpy.fieldaccess import StreamPullTwoFieldsAccessor + +from pystencils.runhelper import Database +from lbmpy.db import LbmpyJsonSerializer + + +def test_json_serializer(): + + stencil = LBStencil(Stencil.D3Q27) + q = stencil.Q + pdfs, pdfs_tmp = ps.fields(f"pdfs({q}), pdfs_tmp({q}): double[3D]", layout='fzyx') + density = ps.fields(f"rho: double[3D]", layout='fzyx') + + from lbmpy.non_newtonian_models import CassonsParameters + cassons_params = CassonsParameters(0.2) + + # create dummy lbmpy config + lbm_config = LBMConfig(stencil=LBStencil(Stencil.D3Q27), method=Method.CUMULANT, force_model=ForceModel.GUO, + compressible=True, relaxation_rate=1.999, smagorinsky=True, galilean_correction=True, + cassons=cassons_params, density_input=density, kernel_type=StreamPullTwoFieldsAccessor, + timestep=Timestep.BOTH) + + lbm_optimization = LBMOptimisation(cse_pdfs=False, cse_global=False, builtin_periodicity=(True, False, False), + symbolic_field=pdfs, symbolic_temporary_field=pdfs_tmp) + + # create dummy database + temp_dir = tempfile.TemporaryDirectory() + db = Database(file=temp_dir.name, serializer_info=('lbmpy_serializer', LbmpyJsonSerializer)) + + db.save(params={'lbm_config': lbm_config, 'lbm_optimization': lbm_optimization}, result={'test': 'dummy'}) diff --git a/lbmpy_tests/test_shear_flow.py b/lbmpy_tests/test_shear_flow.py index 9b22d0a5b0a8cd36ce53b0e32c649428959ecf9a..4f15d43ab5ae57fa5f3993b16be8e75fd5e357d6 100644 --- a/lbmpy_tests/test_shear_flow.py +++ b/lbmpy_tests/test_shear_flow.py @@ -1,5 +1,5 @@ """ -Test shear flow velocity and pressureagainst analytical solutions +Test shear flow velocity and pressure against analytical solutions """ @@ -205,7 +205,7 @@ def test_shear_flow(target, stencil_name, zero_centered): p_expected = rho_0 * np.identity(dh.dim) / 3.0 + dynamic_viscosity * shear_rate / correction_factor * ( np.outer(shear_plane_normal, shear_direction) + np.transpose(np.outer(shear_plane_normal, shear_direction))) - # Sustract the tensorproduct of the velosity to get the pressure + # Subtract the tensor product of the velocity to get the pressure pressure_profile[:, 0, 0] -= rho_0 * profile[:, 0]**2 np.testing.assert_allclose(profile[:, 0], expected[1:-1], atol=1E-9)