def test_population_and_moment_space_equivalence(setup): stencil = LBStencil(setup[0]) method = setup[1] nested_moments = setup[2] fmodel = setup[3] force = sp.symbols(f'F_:{stencil.D}') conserved_moments = 1 + stencil.D rr = [ *[0] * conserved_moments, *sp.symbols(f'omega_:{stencil.Q - conserved_moments}') ] lbm_config = LBMConfig( stencil=stencil, method=method, relaxation_rates=rr, nested_moments=nested_moments, force_model=fmodel, force=force, weighted=True, compressible=True, moment_transform_class=PdfsToMomentsByChimeraTransform) lbm_opt = LBMOptimisation(cse_global=False, cse_pdfs=False, pre_simplification=True, simplification=False) lb_method_moment_space = create_lb_method(lbm_config=lbm_config) lbm_config = replace(lbm_config, moment_transform_class=None) lb_method_pdf_space = create_lb_method(lbm_config=lbm_config) rho = lb_method_moment_space.zeroth_order_equilibrium_moment_symbol u = lb_method_moment_space.first_order_equilibrium_moment_symbols keep = set((rho, ) + u) cr_moment_space = create_lb_collision_rule( lb_method=lb_method_moment_space, lbm_optimisation=lbm_opt) cr_moment_space = cr_moment_space.new_without_subexpressions( subexpressions_to_keep=keep) lbm_opt = replace(lbm_opt, simplification='auto') cr_pdf_space = create_lb_collision_rule(lb_method=lb_method_pdf_space, lbm_optimisation=lbm_opt) cr_pdf_space = cr_pdf_space.new_without_subexpressions( subexpressions_to_keep=keep) for a, b in zip(cr_moment_space.main_assignments, cr_pdf_space.main_assignments): diff = (a.rhs - b.rhs).expand() assert diff == 0, f"Mismatch between population- and moment-space equations in PDFs {a.lhs}, {b.lhs}"
def test_sparse(): from lbmpy.creationfunctions import create_lb_collision_rule from pystencils import get_code_str g = ListLbGenerator(create_lb_collision_rule()) kernel_code = get_code_str(g.kernel()) assert 'num_cells' in kernel_code setter_code = get_code_str(g.setter_ast()) assert 'num_cells' in setter_code getter_code = get_code_str(g.getter_ast()) assert 'num_cells' in getter_code
def test_incompressible(): with ManualCodeGenerationContext() as ctx: omega = sp.Symbol("omega") cr = create_lb_collision_rule(stencil='D3Q19', method='srt', relaxation_rates=[omega], compressible=False) generate_lattice_model(ctx, 'Model', cr) assert 'static const bool compressible = false;' in ctx.files[ 'Model.h']
def test_output_field(): with ManualCodeGenerationContext(openmp=True, double_accuracy=True) as ctx: omega_field = ps.fields("omega_out: [3D]", layout='fzyx') parameters = { 'stencil': 'D3Q27', 'method': 'trt-kbc-n1', 'compressible': True, 'entropic': True, 'omega_output_field': omega_field, } cr = create_lb_collision_rule(**parameters) generate_lattice_model(ctx, 'Model', cr)
def test_fluctuating(): with ManualCodeGenerationContext(openmp=True, double_accuracy=True) as ctx: omega_shear = sp.symbols("omega") force_field, vel_field = ps.fields("force(3), velocity(3): [3D]", layout='fzyx') # the collision rule of the LB method where the some advanced features collision_rule = create_lb_collision_rule( stencil='D3Q19', compressible=True, fluctuating={ 'seed': 0, 'temperature': 1e-6 }, method='mrt', relaxation_rates=[omega_shear] * 19, force_model='guo', force=force_field.center_vector, optimization={'cse_global': False}) generate_lattice_model(ctx, 'FluctuatingMRT', collision_rule)
def test_lattice_model(): with ManualCodeGenerationContext() as ctx: force_field = ps.fields("force(3): [3D]", layout='fzyx') omega = sp.Symbol("omega") cr = create_lb_collision_rule(stencil='D3Q19', method='srt', relaxation_rates=[omega], compressible=True, force_model='guo', force=force_field.center_vector) scaling = RefinementScaling() scaling.add_standard_relaxation_rate_scaling(omega) scaling.add_force_scaling(force_field) generate_lattice_model(ctx, 'SrtWithForceFieldModel', cr, refinement_scaling=scaling) generate_boundary(ctx, 'MyUBB', UBB([0.05, 0, 0]), cr.method) generate_boundary(ctx, 'MyNoSlip', NoSlip(), cr.method) assert 'static const bool compressible = true;' in ctx.files[ 'SrtWithForceFieldModel.h']
def test_fully_periodic_flow(target, stencil, streaming_pattern): gpu = False if target == Target.GPU: gpu = True # Stencil stencil = LBStencil(stencil) # Streaming inplace = is_inplace(streaming_pattern) timesteps = get_timesteps(streaming_pattern) zeroth_timestep = timesteps[0] # Data Handling and PDF fields domain_size = (30, ) * stencil.D periodicity = (True, ) * stencil.D dh = create_data_handling(domain_size=domain_size, periodicity=periodicity, default_target=target) pdfs = dh.add_array('pdfs', stencil.Q) if not inplace: pdfs_tmp = dh.add_array_like('pdfs_tmp', pdfs.name) # LBM Streaming and Collision lbm_config = LBMConfig(stencil=stencil, method=Method.SRT, relaxation_rate=1.0, streaming_pattern=streaming_pattern) lbm_opt = LBMOptimisation(symbolic_field=pdfs) config = CreateKernelConfig(target=target) if not inplace: lbm_opt = replace(lbm_opt, symbolic_temporary_field=pdfs_tmp) lb_collision = create_lb_collision_rule(lbm_config=lbm_config, lbm_optimisation=lbm_opt, config=config) lb_method = lb_collision.method lb_kernels = [] for t in timesteps: lbm_config = replace(lbm_config, timestep=t) lb_kernels.append( create_lb_function(collision_rule=lb_collision, lbm_config=lbm_config, lbm_optimisation=lbm_opt)) # Macroscopic Values density = 1.0 density_field = dh.add_array('rho', 1) u_x = 0.01 velocity = (u_x, ) * stencil.D velocity_field = dh.add_array('u', stencil.D) u_ref = np.full(domain_size + (stencil.D, ), u_x) setter = macroscopic_values_setter(lb_method, density, velocity, pdfs, streaming_pattern=streaming_pattern, previous_timestep=zeroth_timestep) setter_kernel = create_kernel( setter, config=CreateKernelConfig(target=target, ghost_layers=1)).compile() getter_kernels = [] for t in timesteps: getter = macroscopic_values_getter(lb_method, density_field, velocity_field, pdfs, streaming_pattern=streaming_pattern, previous_timestep=t) getter_kernels.append( create_kernel(getter, config=CreateKernelConfig(target=target, ghost_layers=1)).compile()) # Periodicity periodicity_handler = LBMPeriodicityHandling( stencil, dh, pdfs.name, streaming_pattern=streaming_pattern) # Initialization and Timestep current_timestep = zeroth_timestep def init(): global current_timestep current_timestep = zeroth_timestep dh.run_kernel(setter_kernel) def one_step(): global current_timestep # Periodicty periodicity_handler(current_timestep) # Here, the next time step begins current_timestep = current_timestep.next() # LBM Step dh.run_kernel(lb_kernels[current_timestep.idx]) # Field Swaps if not inplace: dh.swap(pdfs.name, pdfs_tmp.name) # Macroscopic Values dh.run_kernel(getter_kernels[current_timestep.idx]) # Run the simulation init() for _ in range(100): one_step() # Evaluation if gpu: dh.to_cpu(velocity_field.name) u = dh.gather_array(velocity_field.name) # Equal to the steady-state velocity field up to numerical errors assert_allclose(u, u_ref) # Flow must be equal up to numerical error for all streaming patterns global all_results for key, prev_u in all_results.items(): if key[0] == stencil: prev_pattern = key[1] assert_allclose( u, prev_u, err_msg= f'Velocity field for {streaming_pattern} differed from {prev_pattern}!' ) all_results[(stencil, streaming_pattern)] = u
from lbmpy_walberla import RefinementScaling, generate_boundary, generate_lattice_model with CodeGeneration() as ctx: omega, omega_free = sp.symbols("omega, omega_free") force_field, vel_field, omega_out = ps.fields( "force(3), velocity(3), omega_out: [3D]", layout='fzyx') # the collision rule of the LB method where the some advanced features collision_rule = create_lb_collision_rule( stencil='D3Q19', compressible=True, method='mrt3', relaxation_rates=[omega, omega, omega_free], entropic= True, # entropic method where second omega is chosen s.t. entropy condition omega_output_field= omega_out, # scalar field where automatically chosen omega of entropic or Smagorinsky method is written to force=force_field. center_vector, # read forces for each lattice cell from an external force field # that is initialized and changed in C++ app output={'velocity': vel_field }, # write macroscopic velocity to field in every time step # useful for coupling multiple LB methods, e.g. hydrodynamic to advection/diffusion LBM optimization={'cse_global': True}) # the refinement scaling object describes how certain parameters are scaled across grid scales # there are two default scaling behaviors available for relaxation rates and forces: scaling = RefinementScaling() scaling.add_standard_relaxation_rate_scaling(omega) scaling.add_force_scaling(force_field) # generate lattice model and (optionally) boundary conditions
def __init__(self, stencil, streaming_pattern, wall_boundary=None, target=Target.CPU): if wall_boundary is None: wall_boundary = NoSlip() self.target = target self.gpu = target in [Target.GPU] # Stencil self.stencil = stencil self.q = stencil.Q self.dim = stencil.D # Streaming self.streaming_pattern = streaming_pattern self.inplace = is_inplace(self.streaming_pattern) self.timesteps = get_timesteps(streaming_pattern) self.zeroth_timestep = self.timesteps[0] # Domain, Data Handling and PDF fields self.pipe_length = 60 self.pipe_radius = 15 self.domain_size = (self.pipe_length, ) + (2 * self.pipe_radius,) * (self.dim - 1) self.periodicity = (True, ) + (False, ) * (self.dim - 1) self.force = (0.0001, ) + (0.0,) * (self.dim - 1) self.dh = create_data_handling(domain_size=self.domain_size, periodicity=self.periodicity, default_target=self.target) self.pdfs = self.dh.add_array('pdfs', self.q) if not self.inplace: self.pdfs_tmp = self.dh.add_array_like('pdfs_tmp', self.pdfs.name) # LBM Streaming and Collision lbm_config = LBMConfig(stencil=stencil, method=Method.SRT, relaxation_rate=1.0, force_model=ForceModel.GUO, force=self.force, streaming_pattern=streaming_pattern) lbm_opt = LBMOptimisation(symbolic_field=self.pdfs) config = CreateKernelConfig(target=self.target) if not self.inplace: lbm_opt = replace(lbm_opt, symbolic_temporary_field=self.pdfs_tmp) self.lb_collision = create_lb_collision_rule(lbm_config=lbm_config, lbm_optimisation=lbm_opt) self.lb_method = self.lb_collision.method self.lb_kernels = [] for t in self.timesteps: lbm_config = replace(lbm_config, timestep=t) self.lb_kernels.append(create_lb_function(collision_rule=self.lb_collision, lbm_config=lbm_config, lbm_optimisation=lbm_opt, config=config)) # Macroscopic Values self.density = 1.0 self.density_field = self.dh.add_array('rho', 1) u_x = 0.0 self.velocity = (u_x,) * self.dim self.velocity_field = self.dh.add_array('u', self.dim) setter = macroscopic_values_setter( self.lb_method, self.density, self.velocity, self.pdfs, streaming_pattern=self.streaming_pattern, previous_timestep=self.zeroth_timestep) self.init_kernel = create_kernel(setter, config=CreateKernelConfig(target=target, ghost_layers=1)).compile() self.getter_kernels = [] for t in self.timesteps: getter = macroscopic_values_getter( self.lb_method, self.density_field, self.velocity_field, self.pdfs, streaming_pattern=self.streaming_pattern, previous_timestep=t) self.getter_kernels.append(create_kernel(getter, config=CreateKernelConfig(target=target, ghost_layers=1)).compile()) # Periodicity self.periodicity_handler = LBMPeriodicityHandling( self.stencil, self.dh, self.pdfs.name, streaming_pattern=self.streaming_pattern) # Boundary Handling self.wall = wall_boundary self.bh = LatticeBoltzmannBoundaryHandling( self.lb_method, self.dh, self.pdfs.name, streaming_pattern=self.streaming_pattern, target=self.target) self.bh.set_boundary(boundary_obj=self.wall, mask_callback=self.mask_callback) self.current_timestep = self.zeroth_timestep
import sympy as sp import pystencils as ps from lbmpy.creationfunctions import create_lb_collision_rule from pystencils_walberla import CodeGeneration from lbmpy_walberla import generate_lattice_model with CodeGeneration() as ctx: omega_shear, omega_bulk = sp.symbols("omega_shear, omega_bulk") temperature = sp.symbols("temperature") force_field, vel_field = ps.fields("force(3), velocity(3): [3D]", layout='fzyx') collision_rule = create_lb_collision_rule( stencil='D3Q19', compressible=True, fluctuating={ 'temperature': temperature, 'block_offsets': 'walberla', }, method='mrt3', relaxation_rates=[omega_shear, omega_bulk], force_model='guo', force=force_field.center_vector, optimization={'cse_global': True}) generate_lattice_model(ctx, 'FluctuatingMRT_LatticeModel', collision_rule)
def flow_around_sphere(stencil, galilean_correction, L_LU, total_steps): if galilean_correction and stencil.Q != 27: return True target = Target.GPU streaming_pattern = 'aa' timesteps = get_timesteps(streaming_pattern) u_max = 0.05 Re = 500000 kinematic_viscosity = (L_LU * u_max) / Re initial_velocity = (u_max, ) + (0, ) * (stencil.D - 1) omega_v = relaxation_rate_from_lattice_viscosity(kinematic_viscosity) channel_size = (10 * L_LU, ) + (5 * L_LU, ) * (stencil.D - 1) sphere_position = (channel_size[0] // 3, ) + (channel_size[1] // 2, ) * (stencil.D - 1) sphere_radius = L_LU // 2 lbm_config = LBMConfig(stencil=stencil, method=Method.CUMULANT, relaxation_rate=omega_v, galilean_correction=galilean_correction) lbm_opt = LBMOptimisation(pre_simplification=True) config = CreateKernelConfig(target=target) lb_method = create_lb_method(lbm_config=lbm_config) def get_extrapolation_kernel(timestep): boundary_assignments = [] indexing = BetweenTimestepsIndexing( pdf_field, stencil, streaming_pattern=streaming_pattern, prev_timestep=timestep) f_out, _ = indexing.proxy_fields for i, d in enumerate(stencil): if d[0] == -1: asm = Assignment(f_out.neighbor(0, 1)(i), f_out.center(i)) boundary_assignments.append(asm) boundary_assignments = indexing.substitute_proxies( boundary_assignments) iter_slice = get_slice_before_ghost_layer((1, ) + (0, ) * (stencil.D - 1)) extrapolation_ast = create_kernel(boundary_assignments, config=CreateKernelConfig( iteration_slice=iter_slice, ghost_layers=1, target=target)) return extrapolation_ast.compile() dh = create_data_handling(channel_size, periodicity=False, default_layout='fzyx', default_target=target) u_field = dh.add_array('u', stencil.D) rho_field = dh.add_array('rho', 1) pdf_field = dh.add_array('pdfs', stencil.Q) dh.fill(u_field.name, 0.0, ghost_layers=True) dh.fill(rho_field.name, 0.0, ghost_layers=True) dh.to_gpu(u_field.name) dh.to_gpu(rho_field.name) lbm_opt = replace(lbm_opt, symbolic_field=pdf_field) bh = LatticeBoltzmannBoundaryHandling(lb_method, dh, pdf_field.name, streaming_pattern=streaming_pattern, target=target) wall = NoSlip() inflow = UBB(initial_velocity) bh.set_boundary(inflow, slice_from_direction('W', stencil.D)) directions = ('N', 'S', 'T', 'B') if stencil.D == 3 else ('N', 'S') for direction in directions: bh.set_boundary(wall, slice_from_direction(direction, stencil.D)) outflow_kernels = [ get_extrapolation_kernel(Timestep.EVEN), get_extrapolation_kernel(Timestep.ODD) ] def sphere_boundary_callback(x, y, z=None): x = x - sphere_position[0] y = y - sphere_position[1] z = z - sphere_position[2] if z is not None else 0 return np.sqrt(x**2 + y**2 + z**2) <= sphere_radius bh.set_boundary(wall, mask_callback=sphere_boundary_callback) init_eqs = pdf_initialization_assignments( lb_method, 1.0, initial_velocity, pdf_field, streaming_pattern=streaming_pattern, previous_timestep=timesteps[0]) init_kernel = create_kernel(init_eqs, config=config).compile() output = {'density': rho_field, 'velocity': u_field} lbm_config = replace(lbm_config, output=output) lb_collision_rule = create_lb_collision_rule(lb_method=lb_method, lbm_config=lbm_config, lbm_optimisation=lbm_opt) lb_kernels = [] for t in timesteps: lbm_config = replace(lbm_config, timestep=t) lbm_config = replace(lbm_config, streaming_pattern=streaming_pattern) lb_kernels.append( create_lb_function(collision_rule=lb_collision_rule, lbm_config=lbm_config, lbm_optimisation=lbm_opt, config=config)) timestep = timesteps[0] dh.run_kernel(init_kernel) stability_check_frequency = 1000 for i in range(total_steps): bh(prev_timestep=timestep) dh.run_kernel(outflow_kernels[timestep.idx]) timestep = timestep.next() dh.run_kernel(lb_kernels[timestep.idx]) if i % stability_check_frequency == 0: dh.to_cpu(u_field.name) assert np.isfinite(dh.cpu_arrays[u_field.name]).all()