diff --git a/lbmpy/phasefield_allen_cahn/derivatives.py b/lbmpy/phasefield_allen_cahn/derivatives.py deleted file mode 100644 index 2a5f45b981a277489c99e8fa3730f4ca16a71154..0000000000000000000000000000000000000000 --- a/lbmpy/phasefield_allen_cahn/derivatives.py +++ /dev/null @@ -1,53 +0,0 @@ -def laplacian(phi_field): - r""" - Get a symbolic expression for the laplacian. - Args: - phi_field: the phase-field on which the laplacian is applied - """ - lp_phi = 16.0 * ((phi_field[1, 0, 0]) + (phi_field[-1, 0, 0]) - + (phi_field[0, 1, 0]) + (phi_field[0, -1, 0]) - + (phi_field[0, 0, 1]) + (phi_field[0, 0, -1])) \ - + 1.0 * ( - (phi_field[1, 1, 1]) + (phi_field[-1, 1, 1]) - + (phi_field[1, -1, 1]) + (phi_field[-1, -1, 1]) - + (phi_field[1, 1, -1]) + (phi_field[-1, 1, -1]) - + (phi_field[1, -1, -1]) + (phi_field[-1, -1, -1])) \ - + 4.0 * ( - (phi_field[1, 1, 0]) + (phi_field[-1, 1, 0]) - + (phi_field[1, -1, 0]) + (phi_field[-1, -1, 0]) - + (phi_field[1, 0, 1]) + (phi_field[-1, 0, 1]) - + (phi_field[1, 0, -1]) + (phi_field[-1, 0, -1]) - + (phi_field[0, 1, 1]) + (phi_field[0, -1, 1]) - + (phi_field[0, 1, -1]) + (phi_field[0, -1, -1])) \ - - 152.0 * phi_field[0, 0, 0] - - lp_phi = lp_phi / 36 - - return lp_phi - - -def isotropic_gradient(phi_field): - r""" - Get a symbolic expression for the isotropic gradient of the phase-field - Args: - phi_field: the phase-field on which the isotropic gradient is applied - """ - grad_phi_x = 16.00 * (phi_field[1, 0, 0] - phi_field[-1, 0, 0])\ - + (phi_field[1, 1, 1] - phi_field[-1, 1, 1] + phi_field[1, -1, 1] - phi_field[-1, -1, 1] - + phi_field[1, 1, -1] - phi_field[-1, 1, -1] + phi_field[1, -1, -1] - phi_field[-1, -1, -1])\ - + 4.00 * (phi_field[1, 1, 0] - phi_field[-1, 1, 0] + phi_field[1, -1, 0] - phi_field[-1, -1, 0] - + phi_field[1, 0, 1] - phi_field[-1, 0, 1] + phi_field[1, 0, -1] - phi_field[-1, 0, -1]) - grad_phi_y = 16.00 * (phi_field[0, 1, 0] - phi_field[0, -1, 0]) \ - + (phi_field[1, 1, 1] + phi_field[-1, 1, 1] - phi_field[1, -1, 1] - phi_field[-1, -1, 1] - + phi_field[1, 1, -1] + phi_field[-1, 1, -1] - phi_field[1, -1, -1] - phi_field[-1, -1, -1])\ - + 4.00 * (phi_field[1, 1, 0] + phi_field[-1, 1, 0] - phi_field[1, -1, 0] - phi_field[-1, -1, 0] - + phi_field[0, 1, 1] - phi_field[0, -1, 1] + phi_field[0, 1, -1] - phi_field[0, -1, -1]) - grad_phi_z = 16.00 * (phi_field[0, 0, 1] - phi_field[0, 0, -1]) \ - + (phi_field[1, 1, 1] + phi_field[-1, 1, 1] + phi_field[1, -1, 1] + phi_field[-1, -1, 1] - - phi_field[1, 1, -1] - phi_field[-1, 1, -1] - phi_field[1, -1, -1] - phi_field[-1, -1, -1])\ - + 4.00 * (phi_field[1, 0, 1] + phi_field[-1, 0, 1] - phi_field[1, 0, -1] - phi_field[-1, 0, -1] - + phi_field[0, 1, 1] + phi_field[0, -1, 1] - phi_field[0, 1, -1] - phi_field[0, -1, -1]) - - grad = [grad_phi_x / 72, grad_phi_y / 72, grad_phi_z / 72] - - return grad diff --git a/lbmpy/phasefield_allen_cahn/kernel_equations.py b/lbmpy/phasefield_allen_cahn/kernel_equations.py index 985702f424aa139040f862429fc3ef73781a5252..b6904aa90b2900d55358786bab1c5f457efa2572 100644 --- a/lbmpy/phasefield_allen_cahn/kernel_equations.py +++ b/lbmpy/phasefield_allen_cahn/kernel_equations.py @@ -4,7 +4,6 @@ from lbmpy.fieldaccess import StreamPushTwoFieldsAccessor, CollideOnlyInplaceAcc from pystencils.fd.derivation import FiniteDifferenceStencilDerivation from lbmpy.maxwellian_equilibrium import get_weights from pystencils import Assignment, AssignmentCollection -from lbmpy.phasefield_allen_cahn.derivatives import laplacian, isotropic_gradient import sympy as sp import numpy as np @@ -15,30 +14,34 @@ def chemical_potential_symbolic(phi_field, stencil, beta, kappa): Get a symbolic expression for the chemical potential according to equation (5) in PhysRevE.96.053301. Args: phi_field: the phase-field on which the chemical potential is applied - stencil: stencil of the lattice Boltzmann step + stencil: stencil to derive the finite difference for the laplacian (2nd order isotropic) beta: coefficient related to surface tension and interface thickness kappa: coefficient related to surface tension and interface thickness """ dimensions = len(stencil[0]) - - deriv = FiniteDifferenceStencilDerivation((0, 0), stencil) - # assume the stencil is symmetric - deriv.assume_symmetric(0) - deriv.assume_symmetric(1) - if dimensions == 3: - deriv.assume_symmetric(2) - - # set weights for missing degrees of freedom in the calculation - if len(stencil) == 9: - deriv.set_weight((1, 1), sp.Rational(1, 6)) - deriv.set_weight((0, -1), sp.Rational(2, 3)) - deriv.set_weight((0, 0), sp.Rational(-10, 3)) - - # assume the stencil is isotropic - res = deriv.get_stencil(isotropic=True) - lap = res.apply(phi_field.center) - else: - lap = laplacian(phi_field) + q = len(stencil) + lap = sp.simplify(0) + for i in range(dimensions): + deriv = FiniteDifferenceStencilDerivation((i, i), stencil) + for j in range(dimensions): + # assume the stencil is symmetric + deriv.assume_symmetric(dim=j, anti_symmetric=False) + + # set weights for missing degrees of freedom in the calculation and assume the stencil is isotropic + if q == 9: + res = deriv.get_stencil(isotropic=True) + lap += res.apply(phi_field.center) + elif q == 15: + deriv.set_weight((0, 0, 0), sp.Rational(-32, 27)) + res = deriv.get_stencil(isotropic=True) + lap += res.apply(phi_field.center) + elif q == 19: + res = deriv.get_stencil(isotropic=True) + lap += res.apply(phi_field.center) + else: + deriv.set_weight((0, 0, 0), sp.Rational(-38, 27)) + res = deriv.get_stencil(isotropic=True) + lap += res.apply(phi_field.center) # get the chemical potential mu = 4.0 * beta * phi_field.center * (phi_field.center - 1.0) * (phi_field.center - 0.5) - \ @@ -51,9 +54,10 @@ def isotropic_gradient_symbolic(phi_field, stencil): Get a symbolic expression for the isotropic gradient of the phase-field Args: phi_field: the phase-field on which the isotropic gradient is applied - stencil: stencil of the lattice Boltzmann step + stencil: stencil to derive the finite difference for the gradient (2nd order isotropic) """ dimensions = len(stencil[0]) + q = len(stencil) deriv = FiniteDifferenceStencilDerivation((0,), stencil) deriv.assume_symmetric(0, anti_symmetric=True) @@ -61,39 +65,55 @@ def isotropic_gradient_symbolic(phi_field, stencil): if dimensions == 3: deriv.assume_symmetric(2, anti_symmetric=False) - if len(stencil) == 9: + # set weights for missing degrees of freedom in the calculation and assume the stencil is isotropic + # furthermore the stencils gets rotated to get the y and z components + if q == 9: res = deriv.get_stencil(isotropic=True) grad = [res.apply(phi_field.center), res.rotate_weights_and_apply(phi_field.center, (0, 1)), 0] - elif len(stencil) == 19: - deriv.set_weight((0, 0, 0), sp.Integer(0)) + elif q == 15: + res = deriv.get_stencil(isotropic=True) + grad = [res.apply(phi_field.center), + res.rotate_weights_and_apply(phi_field.center, (0, 1)), + res.rotate_weights_and_apply(phi_field.center, (1, 2))] + elif q == 19: + deriv.set_weight((0, 0, 0), sp.sympify(0)) deriv.set_weight((1, 0, 0), sp.Rational(1, 6)) - deriv.set_weight((1, 1, 0), sp.Rational(1, 12)) res = deriv.get_stencil(isotropic=True) grad = [res.apply(phi_field.center), - res.rotate_weights_and_apply(phi_field.center, (1, 0)), - res.rotate_weights_and_apply(phi_field.center, (2, 1))] + res.rotate_weights_and_apply(phi_field.center, (0, 1)), + res.rotate_weights_and_apply(phi_field.center, (1, 2))] else: - grad = isotropic_gradient(phi_field) + deriv.set_weight((0, 0, 0), sp.sympify(0)) + deriv.set_weight((1, 0, 0), sp.Rational(2, 9)) + + res = deriv.get_stencil(isotropic=True) + grad = [res.apply(phi_field.center), + res.rotate_weights_and_apply(phi_field.center, (0, 1)), + res.rotate_weights_and_apply(phi_field.center, (1, 2))] return grad -def normalized_isotropic_gradient_symbolic(phi_field, stencil): +def normalized_isotropic_gradient_symbolic(phi_field, stencil, fd_stencil=None): r""" Get a symbolic expression for the normalized isotropic gradient of the phase-field Args: phi_field: the phase-field on which the normalized isotropic gradient is applied stencil: stencil of the lattice Boltzmann step + fd_stencil: stencil to derive the finite differences of the isotropic gradient and the laplacian of the phase + field. If it is not given the stencil of the LB method will be applied. """ - iso_grad = isotropic_gradient_symbolic(phi_field, stencil) - tmp = (sum(map(lambda x: x * x, isotropic_gradient_symbolic(phi_field, stencil))) + 1.e-32) ** 0.5 + if fd_stencil is None: + fd_stencil = stencil - result = [x / tmp for x in iso_grad] + tmp = (sum(map(lambda x: x * x, isotropic_gradient_symbolic(phi_field, fd_stencil))) + 1.e-32) ** 0.5 + + result = [x / tmp for x in isotropic_gradient_symbolic(phi_field, fd_stencil)] return result -def pressure_force(phi_field, stencil, density_heavy, density_light): +def pressure_force(phi_field, stencil, density_heavy, density_light, fd_stencil=None): r""" Get a symbolic expression for the pressure force Args: @@ -101,13 +121,18 @@ def pressure_force(phi_field, stencil, density_heavy, density_light): stencil: stencil of the lattice Boltzmann step density_heavy: density of the heavier fluid density_light: density of the lighter fluid + fd_stencil: stencil to derive the finite differences of the isotropic gradient and the laplacian of the phase + field. If it is not given the stencil of the LB method will be applied. """ - iso_grad = isotropic_gradient_symbolic(phi_field, stencil) + if fd_stencil is None: + fd_stencil = stencil + + iso_grad = isotropic_gradient_symbolic(phi_field, fd_stencil) result = list(map(lambda x: sp.Rational(-1, 3) * sp.symbols("rho") * (density_heavy - density_light) * x, iso_grad)) return result -def viscous_force(lb_velocity_field, phi_field, mrt_method, tau, density_heavy, density_light): +def viscous_force(lb_velocity_field, phi_field, mrt_method, tau, density_heavy, density_light, fd_stencil=None): r""" Get a symbolic expression for the viscous force Args: @@ -117,11 +142,16 @@ def viscous_force(lb_velocity_field, phi_field, mrt_method, tau, density_heavy, tau: relaxation time of the hydrodynamic lattice boltzmann step density_heavy: density of the heavier fluid density_light: density of the lighter fluid + fd_stencil: stencil to derive the finite differences of the isotropic gradient and the laplacian of the phase + field. If it is not given the stencil of the LB method will be applied. """ stencil = mrt_method.stencil dimensions = len(stencil[0]) - iso_grad = isotropic_gradient_symbolic(phi_field, stencil) + if fd_stencil is None: + fd_stencil = stencil + + iso_grad = isotropic_gradient_symbolic(phi_field, fd_stencil) moment_matrix = mrt_method.moment_matrix rel = mrt_method.relaxation_rates @@ -166,7 +196,7 @@ def viscous_force(lb_velocity_field, phi_field, mrt_method, tau, density_heavy, return [fmx, fmy, fmz] -def surface_tension_force(phi_field, stencil, beta, kappa): +def surface_tension_force(phi_field, stencil, beta, kappa, fd_stencil=None): r""" Get a symbolic expression for the surface tension force Args: @@ -174,14 +204,19 @@ def surface_tension_force(phi_field, stencil, beta, kappa): stencil: stencil of the lattice Boltzmann step beta: coefficient related to surface tension and interface thickness kappa: coefficient related to surface tension and interface thickness + fd_stencil: stencil to derive the finite differences of the isotropic gradient and the laplacian of the phase + field. If it is not given the stencil of the LB method will be applied. """ - chemical_potential = chemical_potential_symbolic(phi_field, stencil, beta, kappa) - iso_grad = isotropic_gradient_symbolic(phi_field, stencil) + if fd_stencil is None: + fd_stencil = stencil + + chemical_potential = chemical_potential_symbolic(phi_field, fd_stencil, beta, kappa) + iso_grad = isotropic_gradient_symbolic(phi_field, fd_stencil) return [chemical_potential * x for x in iso_grad] def hydrodynamic_force(lb_velocity_field, phi_field, lb_method, tau, - density_heavy, density_light, kappa, beta, body_force): + density_heavy, density_light, kappa, beta, body_force, fd_stencil=None): r""" Get a symbolic expression for the hydrodynamic force Args: @@ -194,12 +229,18 @@ def hydrodynamic_force(lb_velocity_field, phi_field, lb_method, tau, beta: coefficient related to surface tension and interface thickness kappa: coefficient related to surface tension and interface thickness body_force: force acting on the fluids. Usually the gravity + fd_stencil: stencil to derive the finite differences of the isotropic gradient and the laplacian of the phase + field. If it is not given the stencil of the LB method will be applied. """ stencil = lb_method.stencil dimensions = len(stencil[0]) - fp = pressure_force(phi_field, stencil, density_heavy, density_light) - fm = viscous_force(lb_velocity_field, phi_field, lb_method, tau, density_heavy, density_light) - fs = surface_tension_force(phi_field, stencil, beta, kappa) + + if fd_stencil is None: + fd_stencil = stencil + + fp = pressure_force(phi_field, stencil, density_heavy, density_light, fd_stencil) + fm = viscous_force(lb_velocity_field, phi_field, lb_method, tau, density_heavy, density_light, fd_stencil) + fs = surface_tension_force(phi_field, stencil, beta, kappa, fd_stencil) result = [] for i in range(dimensions): @@ -208,16 +249,21 @@ def hydrodynamic_force(lb_velocity_field, phi_field, lb_method, tau, return result -def interface_tracking_force(phi_field, stencil, interface_thickness): +def interface_tracking_force(phi_field, stencil, interface_thickness, fd_stencil=None): r""" Get a symbolic expression for the hydrodynamic force Args: phi_field: phase-field stencil: stencil of the phase-field distribution lattice Boltzmann step interface_thickness: interface thickness + fd_stencil: stencil to derive the finite differences of the isotropic gradient and the laplacian of the phase + field. If it is not given the stencil of the LB method will be applied. """ + if fd_stencil is None: + fd_stencil = stencil + dimensions = len(stencil[0]) - normal_fd = normalized_isotropic_gradient_symbolic(phi_field, stencil) + normal_fd = normalized_isotropic_gradient_symbolic(phi_field, stencil, fd_stencil) result = [] for i in range(dimensions): result.append(((1.0 - 4.0 * (phi_field.center - 0.5) ** 2) / interface_thickness) * normal_fd[i]) @@ -264,15 +310,16 @@ def get_update_rules_velocity(src_field, u_in, lb_method, force, density): return update_u -def get_collision_assignments_hydro(collision_rule=None, density=1, optimization={}, **kwargs): +def get_collision_assignments_hydro(density=1, optimization=None, **kwargs): r""" Get collision assignments for the hydrodynamic lattice Boltzmann step. Here the force gets applied in the moment space. Afterwards the transformation back to the pdf space happens. Args: - collision_rule: arbitrary collision rule, e.g. created with create_lb_collision_rule density: the interpolated density of the simulation optimization: for details see createfunctions.py """ + if optimization is None: + optimization = {} params, opt_params = update_with_default_parameters(kwargs, optimization) lb_method = params['lb_method'] @@ -288,12 +335,8 @@ def get_collision_assignments_hydro(collision_rule=None, density=1, optimization if opt_params['symbolic_field'] is not None: src_field = opt_params['symbolic_field'] - elif opt_params['field_size']: - field_size = [s + 2 for s in opt_params['field_size']] + [q] - src_field = Field.create_fixed_size(params['field_name'], field_size, index_dimensions=1, - layout=opt_params['field_layout'], dtype=field_data_type) else: - src_field = Field.create_generic(params['field_name'], spatial_dimensions=collision_rule.method.dim, + src_field = Field.create_generic(params['field_name'], spatial_dimensions=lb_method.dim, index_shape=(q,), layout=opt_params['field_layout'], dtype=field_data_type) if opt_params['symbolic_temporary_field'] is not None: @@ -348,26 +391,33 @@ def get_collision_assignments_hydro(collision_rule=None, density=1, optimization return hydro_lb_update_rule -def initializer_kernel_phase_field_lb(phi_field_distributions, phi_field, velocity, mrt_method, interface_thickness): +def initializer_kernel_phase_field_lb(lb_phase_field, phi_field, velocity_field, mrt_method, interface_thickness, + fd_stencil=None): r""" Returns an assignment list for initializing the phase-field distribution functions Args: - phi_field_distributions: source field of phase-field distribution function + lb_phase_field: source field of phase-field distribution function phi_field: phase-field - velocity: velocity field + velocity_field: velocity field mrt_method: lattice Boltzmann method of the phase-field lattice Boltzmann step interface_thickness: interface thickness + fd_stencil: stencil to derive the finite differences of the isotropic gradient and the laplacian of the phase + field. If it is not given the stencil of the LB method will be applied. """ stencil = mrt_method.stencil dimensions = len(stencil[0]) + + if fd_stencil is None: + fd_stencil = stencil + weights = get_weights(stencil, c_s_sq=sp.Rational(1, 3)) u_symp = sp.symbols("u_:{}".format(dimensions)) - normal_fd = normalized_isotropic_gradient_symbolic(phi_field, stencil) + normal_fd = normalized_isotropic_gradient_symbolic(phi_field, stencil, fd_stencil) gamma = mrt_method.get_equilibrium_terms() gamma = gamma.subs({sp.symbols("rho"): 1}) - gamma_init = gamma.subs({x: y for x, y in zip(u_symp, velocity.center_vector)}) + gamma_init = gamma.subs({x: y for x, y in zip(u_symp, velocity_field.center_vector)}) # create the kernels for the initialization of the h field h_updates = list() @@ -380,17 +430,17 @@ def initializer_kernel_phase_field_lb(phi_field_distributions, phi_field, veloci * scalar_product(d, normal_fd[0:dimensions])) for i, _ in enumerate(stencil): - h_updates.append(Assignment(phi_field_distributions.center(i), phi_field.center * gamma_init[i] - 0.5 * f[i])) + h_updates.append(Assignment(lb_phase_field.center(i), phi_field.center * gamma_init[i] - 0.5 * f[i])) return h_updates -def initializer_kernel_hydro_lb(velocity_distributions, velocity, mrt_method): +def initializer_kernel_hydro_lb(lb_velocity_field, velocity_field, mrt_method): r""" Returns an assignment list for initializing the velocity distribution functions Args: - velocity_distributions: source field of velocity distribution function - velocity: velocity field + lb_velocity_field: source field of velocity distribution function + velocity_field: velocity field mrt_method: lattice Boltzmann method of the hydrodynamic lattice Boltzmann step """ stencil = mrt_method.stencil @@ -400,10 +450,10 @@ def initializer_kernel_hydro_lb(velocity_distributions, velocity, mrt_method): gamma = mrt_method.get_equilibrium_terms() gamma = gamma.subs({sp.symbols("rho"): 1}) - gamma_init = gamma.subs({x: y for x, y in zip(u_symp, velocity.center_vector)}) + gamma_init = gamma.subs({x: y for x, y in zip(u_symp, velocity_field.center_vector)}) g_updates = list() for i, _ in enumerate(stencil): - g_updates.append(Assignment(velocity_distributions.center(i), gamma_init[i] - weights[i])) + g_updates.append(Assignment(lb_velocity_field.center(i), gamma_init[i] - weights[i])) return g_updates diff --git a/lbmpy_tests/phasefield_allen_cahn/test_codegen_3D.py b/lbmpy_tests/phasefield_allen_cahn/test_codegen_3d.py similarity index 77% rename from lbmpy_tests/phasefield_allen_cahn/test_codegen_3D.py rename to lbmpy_tests/phasefield_allen_cahn/test_codegen_3d.py index d5b7319c61bc831a699f8907d43a37c9868e2eb3..cf461876169ccc7ac1e5e913b655faae7822a343 100644 --- a/lbmpy_tests/phasefield_allen_cahn/test_codegen_3D.py +++ b/lbmpy_tests/phasefield_allen_cahn/test_codegen_3d.py @@ -13,10 +13,9 @@ from lbmpy.phasefield_allen_cahn.parameter_calculation import ( calculate_dimensionless_rising_bubble, calculate_parameters_rti) from lbmpy.stencils import get_stencil from pystencils import AssignmentCollection, fields -from pystencils.simp import sympy_cse -def test_codegen_3D(): +def test_codegen_3d(): stencil_phase = get_stencil("D3Q15") stencil_hydro = get_stencil("D3Q27") assert (len(stencil_phase[0]) == len(stencil_hydro[0])) @@ -69,7 +68,6 @@ def test_codegen_3D(): # fields u = fields("vel_field(" + str(dimensions) + "): [" + str(dimensions) + "D]", layout='fzyx') C = fields("phase_field: [" + str(dimensions) + "D]", layout='fzyx') - force = fields("force(" + str(dimensions) + "): [" + str(dimensions) + "D]", layout='fzyx') h = fields("lb_phase_field(" + str(len(stencil_phase)) + "): [" + str(dimensions) + "D]", layout='fzyx') h_tmp = fields("lb_phase_field_tmp(" + str(len(stencil_phase)) + "): [" + str(dimensions) + "D]", layout='fzyx') @@ -100,7 +98,8 @@ def test_codegen_3D(): force_h = [f / 3 for f in interface_tracking_force(C, stencil_phase, W)] force_model_h = MultiphaseForceModel(force=force_h) - force_g = hydrodynamic_force(g, C, method_hydro, relaxation_time, density_liquid, density_gas, kappa, beta, body_force) + force_g = hydrodynamic_force(g, C, method_hydro, + relaxation_time, density_liquid, density_gas, kappa, beta, body_force) force_model_g = MultiphaseForceModel(force=force_g, rho=density) h_tmp_symbol_list = [h_tmp.center(i) for i, _ in enumerate(stencil_phase)] @@ -122,22 +121,28 @@ def test_codegen_3D(): allen_cahn_lb.set_main_assignments_from_dict({**allen_cahn_lb.main_assignments_dict, **{C.center: sum_h}}) allen_cahn_update_rule = AssignmentCollection(main_assignments=allen_cahn_lb.main_assignments, subexpressions=allen_cahn_lb.subexpressions) - allen_cahn_update_rule = sympy_cse(allen_cahn_update_rule) - # --------------------------------------------------------------------------------------------------------- method_hydro = create_with_discrete_maxwellian_eq_moments(stencil_hydro, rr_dict, force_model=force_model_g) - hydro_lb_update_rule = get_collision_assignments_hydro(lb_method=method_hydro, - density=density, - velocity_input=u, - force=force_g, - optimization={"symbolic_field": g, - "symbolic_temporary_field": g_tmp}, - kernel_type='collide_only') - - # streaming of the hydrodynamic distribution - stream_hydro = create_lb_update_rule(stencil=stencil_hydro, - optimization={"symbolic_field": g, - "symbolic_temporary_field": g_tmp}, - kernel_type='stream_pull_only') + hydro_lb_update_rule_normal = get_collision_assignments_hydro(lb_method=method_hydro, + density=density, + velocity_input=u, + force=force_g, + optimization={"symbolic_field": g, + "symbolic_temporary_field": g_tmp}, + kernel_type='collide_only') + + hydro_lb_update_rule_push = get_collision_assignments_hydro(lb_method=method_hydro, + density=density, + velocity_input=u, + force=force_g, + optimization={"symbolic_field": g, + "symbolic_temporary_field": g_tmp}, + kernel_type='collide_stream_push') + + hydro_lb_update_rule_generic_fields = get_collision_assignments_hydro(lb_method=method_hydro, + density=density, + velocity_input=u, + force=force_g, + kernel_type='collide_only') diff --git a/lbmpy_tests/phasefield_allen_cahn/test_phase_field_allen_cahn.ipynb b/lbmpy_tests/phasefield_allen_cahn/test_phase_field_allen_cahn_2d.ipynb similarity index 100% rename from lbmpy_tests/phasefield_allen_cahn/test_phase_field_allen_cahn.ipynb rename to lbmpy_tests/phasefield_allen_cahn/test_phase_field_allen_cahn_2d.ipynb diff --git a/lbmpy_tests/phasefield_allen_cahn/test_phase_field_derivatives.ipynb b/lbmpy_tests/phasefield_allen_cahn/test_phase_field_derivatives.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..64e03f04c2a69de07547630aefa9240859484bf1 --- /dev/null +++ b/lbmpy_tests/phasefield_allen_cahn/test_phase_field_derivatives.ipynb @@ -0,0 +1,323 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "from lbmpy.phasefield_allen_cahn.kernel_equations import *\n", + "from lbmpy.stencils import get_stencil\n", + "from pystencils import fields\n", + "\n", + "from lbmpy.creationfunctions import create_lb_method" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "def apply(field_access: Field.Access, stencil, weights):\n", + " f = field_access\n", + " return sum(f.get_shifted(*offset) * weight for offset, weight in zip(stencil, weights))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# test chemical potencial" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "stencil = get_stencil(\"D2Q9\")\n", + "dimensions = len(stencil[0])\n", + "C = fields(\"phase_field: [\" + str(dimensions) + \"D]\", layout='fzyx')\n", + "\n", + "beta = 0\n", + "kappa = 1\n", + "\n", + "a = chemical_potential_symbolic(C, stencil, beta, kappa)\n", + "\n", + "expected_result = sp.Array([20, -4, -4, -4, -4, -1, -1, -1, -1]) / 6\n", + "b = apply(C.center, stencil, expected_result)\n", + "\n", + "assert a == b" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "stencil = get_stencil(\"D3Q15\")\n", + "dimensions = len(stencil[0])\n", + "C = fields(\"phase_field: [\" + str(dimensions) + \"D]\", layout='fzyx')\n", + "\n", + "beta = 0\n", + "kappa = 1\n", + "\n", + "a = chemical_potential_symbolic(C, stencil, beta, kappa)\n", + "\n", + "expected_result = sp.Array([256, -28, -28, -28, -28, -28, -28, -11, -11, -11, -11, -11, -11, -11, -11]) / 72\n", + "b = apply(C.center, stencil, expected_result)\n", + "\n", + "assert a == b" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "stencil = get_stencil(\"D3Q19\")\n", + "dimensions = len(stencil[0])\n", + "C = fields(\"phase_field: [\" + str(dimensions) + \"D]\", layout='fzyx')\n", + "\n", + "beta = 0\n", + "kappa = 1\n", + "\n", + "a = chemical_potential_symbolic(C, stencil, beta, kappa)\n", + "\n", + "expected_result = sp.Array([24, -2, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]) / 6\n", + "b = apply(C.center, stencil, expected_result)\n", + "\n", + "assert a == b" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "stencil = get_stencil(\"D3Q27\")\n", + "dimensions = len(stencil[0])\n", + "C = fields(\"phase_field: [\" + str(dimensions) + \"D]\", layout='fzyx')\n", + "\n", + "beta = 0\n", + "kappa = 1\n", + "\n", + "a = chemical_potential_symbolic(C, stencil, beta, kappa)\n", + "\n", + "expected_result = sp.Array([152,\n", + " -16, -16, -16, -16, -16, -16,\n", + " -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4,\n", + " -1, -1, -1, -1, -1, -1, -1, -1]) / 36\n", + "b = apply(C.center, stencil, expected_result)\n", + "\n", + "assert a == b" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# test isotropic gradient" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "stencil = get_stencil(\"D2Q9\")\n", + "dimensions = len(stencil[0])\n", + "C = fields(\"phase_field: [\" + str(dimensions) + \"D]\", layout='fzyx')\n", + "\n", + "a = isotropic_gradient_symbolic(C, stencil)\n", + "\n", + "expected_result = sp.Array([-1, -4, -1, 1, 4, 1]) / 12\n", + "expected_grad_stencil = ((-1,-1), (-1,0), (-1,1), (1,-1), (1,0), (1,1))\n", + "b = apply(C.center, expected_grad_stencil, expected_result)\n", + "\n", + "assert a[0] == b" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "stencil = get_stencil(\"D3Q15\")\n", + "dimensions = len(stencil[0])\n", + "C = fields(\"phase_field: [\" + str(dimensions) + \"D]\", layout='fzyx')\n", + "\n", + "a = isotropic_gradient_symbolic(C, stencil)\n", + "\n", + "expected_result = sp.Array([-1, -1, -8, -1, -1, 1, 1, 8, 1, 1]) / 24\n", + "expected_grad_stencil = ((-1,-1,-1), (-1,-1,1), (-1,0,0), (-1,1,-1), (-1,1,1), (1,-1,-1), (1,-1,1), (1,0,0), (1,1,-1), (1,1,1))\n", + "b = apply(C.center, expected_grad_stencil, expected_result)\n", + "\n", + "assert a[0] == b" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "stencil = get_stencil(\"D3Q19\")\n", + "dimensions = len(stencil[0])\n", + "C = fields(\"phase_field: [\" + str(dimensions) + \"D]\", layout='fzyx')\n", + "\n", + "a = isotropic_gradient_symbolic(C, stencil)\n", + "\n", + "expected_result = sp.Array([-1, -1, -2, -1, -1, 1, 1, 2, 1, 1]) / 12\n", + "expected_grad_stencil = ((-1,-1,0), (-1,0,-1), (-1,0,0), (-1,0,1), (-1,1,0), (1,-1,0), (1,0,-1), (1,0,0), (1,0,1), (1,1,0))\n", + "b = apply(C.center, expected_grad_stencil, expected_result)\n", + "\n", + "assert a[0] == b" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "stencil = get_stencil(\"D3Q27\")\n", + "dimensions = len(stencil[0])\n", + "C = fields(\"phase_field: [\" + str(dimensions) + \"D]\", layout='fzyx')\n", + "\n", + "a = isotropic_gradient_symbolic(C, stencil)\n", + "\n", + "expected_result = sp.Array([-1, -4, -1, -4, -16, -4, -1, -4, -1, 1, 4, 1, 4, 16, 4, 1, 4, 1]) / 72\n", + "expected_grad_stencil = ((-1,-1,-1), (-1,-1,0), (-1,-1,1), (-1,0,-1), (-1,0,0), (-1,0,1), (-1,1,-1), (-1,1,0), (-1,1,1),\n", + " (1,-1,-1), (1,-1,0), (1,-1,1), (1,0,-1), (1,0,0), (1,0,1), (1,1,-1), (1,1,0), (1,1,1))\n", + "b = apply(C.center, expected_grad_stencil, expected_result)\n", + "\n", + "assert a[0] == b" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# test hydrodynamic force" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "stencil = get_stencil(\"D3Q27\")\n", + "dimensions = len(stencil[0])\n", + "C = fields(\"phase_field: [\" + str(dimensions) + \"D]\", layout='fzyx')\n", + "g = fields(\"lb_velocity_field(\" + str(len(stencil)) + \"): [\" + str(dimensions) + \"D]\", layout='fzyx')\n", + "\n", + "tau = 0.53\n", + "\n", + "lb_method = create_lb_method(stencil=stencil, method=\"mrt\", relaxation_rates=[1/tau, 1, 1, 1, 1, 1])" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "a = hydrodynamic_force(g, C, lb_method, tau, 1, 0.1, 1, 0, [0, 0, 0] , fd_stencil=None)\n", + "b = hydrodynamic_force(g, C, lb_method, tau, 1, 0.1, 1, 0, [0, 0, 0] , fd_stencil=get_stencil(\"D3Q27\"))\n", + "c = hydrodynamic_force(g, C, lb_method, tau, 1, 0.1, 1, 0, [0, 0, 0] , fd_stencil=get_stencil(\"D3Q19\"))\n", + "d = hydrodynamic_force(g, C, lb_method, tau, 1, 0.1, 1, 0, [0, 0, 0] , fd_stencil=get_stencil(\"D3Q15\"))" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "stencil = get_stencil(\"D2Q9\")\n", + "dimensions = len(stencil[0])\n", + "C = fields(\"phase_field: [\" + str(dimensions) + \"D]\", layout='fzyx')\n", + "g = fields(\"lb_velocity_field(\" + str(len(stencil)) + \"): [\" + str(dimensions) + \"D]\", layout='fzyx')\n", + "\n", + "tau = 0.53\n", + "\n", + "lb_method = create_lb_method(stencil=stencil, method=\"mrt\", relaxation_rates=[1/tau, 1, 1, 1, 1, 1])\n", + "\n", + "a = hydrodynamic_force(g, C, lb_method, tau, 1, 0.1, 1, 0, [0, 0, 0] , fd_stencil=None)\n", + "b = hydrodynamic_force(g, C, lb_method, tau, 1, 0.1, 1, 0, [0, 0, 0] , fd_stencil=get_stencil(\"D2Q9\"))" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "stencil = get_stencil(\"D3Q27\")\n", + "dimensions = len(stencil[0])\n", + "C = fields(\"phase_field: [\" + str(dimensions) + \"D]\", layout='fzyx')\n", + "u = fields(\"vel_field(\" + str(dimensions) + \"): [\" + str(dimensions) + \"D]\", layout='fzyx')\n", + "h = fields(\"lb_velocity_field(\" + str(len(stencil)) + \"): [\" + str(dimensions) + \"D]\", layout='fzyx')\n", + "\n", + "tau = 0.53\n", + "\n", + "lb_method = create_lb_method(stencil=stencil, method=\"srt\")\n", + "\n", + "a = initializer_kernel_phase_field_lb(h, C, u, lb_method, 5, fd_stencil=None)\n", + "b = initializer_kernel_phase_field_lb(h, C, u, lb_method, 5, fd_stencil=get_stencil(\"D3Q27\"))\n", + "c = initializer_kernel_phase_field_lb(h, C, u, lb_method, 5, fd_stencil=get_stencil(\"D3Q19\"))\n", + "d = initializer_kernel_phase_field_lb(h, C, u, lb_method, 5, fd_stencil=get_stencil(\"D3Q15\"))" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "stencil = get_stencil(\"D2Q9\")\n", + "dimensions = len(stencil[0])\n", + "C = fields(\"phase_field: [\" + str(dimensions) + \"D]\", layout='fzyx')\n", + "u = fields(\"vel_field(\" + str(dimensions) + \"): [\" + str(dimensions) + \"D]\", layout='fzyx')\n", + "h = fields(\"lb_velocity_field(\" + str(len(stencil)) + \"): [\" + str(dimensions) + \"D]\", layout='fzyx')\n", + "\n", + "tau = 0.53\n", + "\n", + "lb_method = create_lb_method(stencil=stencil, method=\"srt\")\n", + "\n", + "a = initializer_kernel_phase_field_lb(h, C, u, lb_method, 5, fd_stencil=None)\n", + "b = initializer_kernel_phase_field_lb(h, C, u, lb_method, 5, fd_stencil=get_stencil(\"D2Q9\"))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.4" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +}