def create_falling_drop( domain_size=(160, 200), omega=1.9, kappas=(0.001, 0.001, 0.0005), **kwargs): c = sp.symbols("c_:3") free_energy = free_energy_functional_n_phases_penalty_term(c, 1, kappas) gravity = -0.1e-5 if 'optimization' not in kwargs: kwargs['optimization'] = {'openmp': 4} sc = PhaseFieldStep(free_energy, c, domain_size=domain_size, hydro_dynamic_relaxation_rate=omega, order_parameter_force={ 2: (0, gravity), 1: (0, 0), 0: (0, 0) }, **kwargs) sc.set_concentration(make_slice[:, 0.4:], [1, 0, 0]) sc.set_concentration(make_slice[:, :0.4], [0, 1, 0]) sc.set_concentration(make_slice[0.45:0.55, 0.8:0.9], [0, 0, 1]) sc.hydro_lbm_step.boundary_handling.set_boundary(NoSlip(), make_slice[:, 0]) sc.set_pdf_fields_from_macroscopic_values() return sc
def test_boundary_2D(): with ManualCodeGenerationContext(openmp=True, double_accuracy=True) as ctx: lb_method = create_lb_method(stencil='D2Q9', method='srt') generate_boundary(ctx, 'Boundary', NoSlip(), lb_method, target='gpu')
def test_slice_mask_combination(): sc = LatticeBoltzmannStep(domain_size=(30, 30), method=Method.SRT, relaxation_rate=1.9) def callback(*coordinates): x = coordinates[0] print("x", coordinates[0][:, 0]) print("y", coordinates[1][0, :]) print(x.shape) return np.ones_like(x, dtype=bool) sc.boundary_handling.set_boundary(NoSlip(), make_slice[6:7, -1], callback)
def test_advanced_streaming_noslip_single_cell(stencil, streaming_pattern, prev_timestep): """ Advanced Streaming NoSlip Test """ stencil = LBStencil(stencil) pdf_field = ps.fields(f'pdfs({stencil.Q}): [{stencil.D}D]') prev_pdf_access = AccessPdfValues(stencil, streaming_pattern, prev_timestep, 'out') next_pdf_access = AccessPdfValues(stencil, streaming_pattern, prev_timestep.next(), 'in') pdfs = np.zeros((3, ) * stencil.D + (stencil.Q, )) pos = (1, ) * stencil.D for d in range(stencil.Q): prev_pdf_access.write_pdf(pdfs, pos, d, d) lbm_config = LBMConfig(stencil=stencil, method=Method.SRT) lb_method = create_lb_method(lbm_config=lbm_config) noslip = NoSlip() index_struct_dtype = numpy_data_type_for_boundary_object(noslip, stencil.D) index_field = Field('indexVector', FieldType.INDEXED, index_struct_dtype, layout=[0], shape=(TypedSymbol("indexVectorSize", create_type(np.int64)), 1), strides=(1, 1)) index_vector = np.array([pos + (d, ) for d in range(stencil.Q)], dtype=index_struct_dtype) ast = create_lattice_boltzmann_boundary_kernel( pdf_field, index_field, lb_method, noslip, prev_timestep=prev_timestep, streaming_pattern=streaming_pattern) flex_kernel = ast.compile() flex_kernel(pdfs=pdfs, indexVector=index_vector, indexVectorSize=len(index_vector)) reflected_pdfs = [ next_pdf_access.read_pdf(pdfs, pos, d) for d in range(stencil.Q) ] inverse_pdfs = [inverse_dir_index(stencil, d) for d in range(stencil.Q)] assert reflected_pdfs == inverse_pdfs
def test_boundary_utility_functions(): stencil = LBStencil(Stencil.D2Q9) method = create_lb_method(lbm_config=LBMConfig(stencil=stencil)) noslip = NoSlip("noslip") assert noslip == NoSlip("noslip") assert not noslip == NoSlip("test") assert not noslip == UBB((0, 0), name="ubb") assert noslip.name == "noslip" noslip.name = "test name setter" assert noslip.name == "test name setter" ubb = UBB((0, 0), name="ubb") assert ubb == UBB((0, 0), name="ubb") assert not noslip == UBB((0, 0), name="test") assert not ubb == NoSlip("noslip") simple_extrapolation = SimpleExtrapolationOutflow( normal_direction=stencil[4], stencil=stencil, name="simple") assert simple_extrapolation == SimpleExtrapolationOutflow( normal_direction=stencil[4], stencil=stencil, name="simple") assert not simple_extrapolation == SimpleExtrapolationOutflow( normal_direction=stencil[4], stencil=stencil, name="test") assert not simple_extrapolation == NoSlip("noslip") outflow = ExtrapolationOutflow(normal_direction=stencil[4], lb_method=method, name="outflow") assert outflow == ExtrapolationOutflow(normal_direction=stencil[4], lb_method=method, name="outflow") assert not outflow == ExtrapolationOutflow( normal_direction=stencil[4], lb_method=method, name="test") assert not outflow == simple_extrapolation density = FixedDensity(density=1.0, name="fixedDensity") assert density == FixedDensity(density=1.0, name="fixedDensity") assert not density == FixedDensity(density=1.0, name="test") assert not density == UBB((0, 0), name="ubb") diffusion = DiffusionDirichlet(concentration=1.0, name="diffusion") assert diffusion == DiffusionDirichlet(concentration=1.0, name="diffusion") assert not diffusion == DiffusionDirichlet(concentration=1.0, name="test") assert not diffusion == density neumann = NeumannByCopy(name="Neumann") assert neumann == NeumannByCopy(name="Neumann") assert not neumann == NeumannByCopy(name="test") assert not neumann == diffusion stream = StreamInConstant(constant=1.0, name="stream") assert stream == StreamInConstant(constant=1.0, name="stream") assert not stream == StreamInConstant(constant=1.0, name="test") assert not stream == noslip
def create_lid_driven_cavity(domain_size=None, lid_velocity=0.005, lbm_kernel=None, parallel=False, data_handling=None, **kwargs): """Creates a lid driven cavity scenario. 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 kwargs: other parameters are passed on to the method, see :mod:`lbmpy.creationfunctions` parallel: True for distributed memory parallelization with walberla data_handling: see documentation of :func:`create_fully_periodic_flow` Returns: instance of :class:`Scenario` """ assert domain_size is not None or data_handling is not None if data_handling is None: optimization = kwargs.get('optimization', None) target = optimization.get('target', None) if optimization else None data_handling = create_data_handling(domain_size, periodicity=False, default_ghost_layers=1, parallel=parallel, default_target=target) step = LatticeBoltzmannStep(data_handling=data_handling, lbm_kernel=lbm_kernel, name="ldc", **kwargs) my_ubb = UBB(velocity=[lid_velocity, 0, 0][:step.method.dim]) step.boundary_handling.set_boundary(my_ubb, slice_from_direction('N', step.dim)) for direction in ('W', 'E', 'S') if step.dim == 2 else ('W', 'E', 'S', 'T', 'B'): step.boundary_handling.set_boundary( NoSlip(), slice_from_direction(direction, step.dim)) return step
def test_force_on_boundary(): results = [] domain_size = (80, 30) boundaries = [ NoSlip('obstacle_noslip'), UBB((0, ) * len(domain_size), name='obstacle_UBB') ] for parallel in (False, True) if wLB else (False, ): for boundary_obj in boundaries: print(f"Testing parallel {parallel}, boundary {boundary_obj.name}") step = create_channel(domain_size, force=1e-5, relaxation_rate=1.5, parallel=parallel, force_model=ForceModel.BUICK) force = calculate_force(step, boundary_obj) print(f" -> force = {force}") results.append(force) for res in results[1:]: np.testing.assert_almost_equal(results[0], res)
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']
lb_method, update_rule_params=options_without_opt) # gpu LB sweep & boundaries generate_sweep(ctx, 'UniformGridGPU_LbKernel', update_rule, field_swaps=[('pdfs', 'pdfs_tmp')], inner_outer_split=True, target='gpu', gpu_indexing_params=sweep_params, varying_parameters=vp) generate_boundary(ctx, 'UniformGridGPU_NoSlip', NoSlip(), lb_method, target='gpu') generate_boundary(ctx, 'UniformGridGPU_UBB', UBB([0.05, 0, 0]), lb_method, target='gpu') # getter & setter setter_assignments = macroscopic_values_setter( lb_method, velocity=velocity_field.center_vector, pdfs=pdfs.center_vector, density=1) getter_assignments = macroscopic_values_getter(
def create_channel(domain_size=None, force=None, pressure_difference=None, u_max=None, diameter_callback=None, duct=False, wall_boundary=NoSlip(), parallel=False, data_handling=None, **kwargs): """Create a channel scenario (2D or 3D). The channel can be driven either by force, velocity inflow or pressure difference. Choose one and pass exactly one of the parameters 'force', 'pressure_difference' or 'u_max'. Args: domain_size: size of the simulation domain. First coordinate is the flow direction. force: Periodic channel, driven by a body force. Pass force in flow direction in lattice units here. pressure_difference: Inflow and outflow are fixed pressure conditions, with the given pressure difference. u_max: Parabolic velocity profile prescribed at inflow, pressure boundary =1.0 at outflow. diameter_callback: optional callback for channel with varying diameters. Only valid if duct=False. The callback receives x coordinate array and domain_size and returns a an array of diameters of the same shape duct: if true the channel has rectangular instead of circular cross section wall_boundary: instance of boundary class that should be set at the channel walls parallel: True for distributed memory parallelization with walberla data_handling: see documentation of :func:`create_fully_periodic_flow` kwargs: all other keyword parameters are passed directly to scenario class. """ assert domain_size is not None or data_handling is not None if [bool(p) for p in (force, pressure_difference, u_max)].count(True) != 1: raise ValueError( "Please specify exactly one of the parameters 'force', 'pressure_difference' or 'u_max'" ) periodicity = (True, False, False) if force else (False, False, False) if data_handling is None: dim = len(domain_size) assert dim in (2, 3) data_handling = create_data_handling(domain_size, periodicity=periodicity[:dim], default_ghost_layers=1, parallel=parallel) dim = data_handling.dim if force: kwargs['force'] = tuple([force, 0, 0][:dim]) assert data_handling.periodicity[0] step = LatticeBoltzmannStep(data_handling=data_handling, name="force_driven_channel", **kwargs) elif pressure_difference: inflow = FixedDensity(1.0 + pressure_difference) outflow = FixedDensity(1.0) step = LatticeBoltzmannStep(data_handling=data_handling, name="pressure_driven_channel", **kwargs) step.boundary_handling.set_boundary(inflow, slice_from_direction('W', dim)) step.boundary_handling.set_boundary(outflow, slice_from_direction('E', dim)) elif u_max: if duct: raise NotImplementedError( "Velocity inflow for duct flows not yet implemented") step = LatticeBoltzmannStep(data_handling=data_handling, name="velocity_driven_channel", **kwargs) diameter = diameter_callback(np.array([ 0 ]), domain_size)[0] if diameter_callback else min(domain_size[1:]) add_pipe_inflow_boundary(step.boundary_handling, u_max, slice_from_direction('W', dim), flow_direction=0, diameter=diameter) outflow = FixedDensity(1.0) step.boundary_handling.set_boundary(outflow, slice_from_direction('E', dim)) else: assert False directions = ('N', 'S', 'T', 'B') if dim == 3 else ('N', 'S') for direction in directions: step.boundary_handling.set_boundary( wall_boundary, slice_from_direction(direction, dim)) if duct and diameter_callback is not None: raise ValueError( "For duct flows, passing a diameter callback does not make sense.") if not duct: diameter = min(step.boundary_handling.shape[1:]) add_pipe_walls(step.boundary_handling, diameter_callback if diameter_callback else diameter, wall_boundary) return step
import sympy as sp import pystencils as ps from lbmpy.creationfunctions import create_lb_method from lbmpy.boundaries import NoSlip, UBB from pystencils_walberla import CodeGeneration from lbmpy_walberla import generate_lattice_model, RefinementScaling, generate_boundary with CodeGeneration() as ctx: omega = sp.Symbol("omega") force_field = ps.fields("force(3): [3D]", layout='fzyx') # lattice Boltzmann method lb_method = create_lb_method(stencil='D3Q19', method='srt', relaxation_rates=[omega], force_model='guo', force=force_field.center_vector) scaling = RefinementScaling() scaling.add_standard_relaxation_rate_scaling(omega) scaling.add_force_scaling(force_field) # generate components generate_lattice_model(ctx, 'SrtWithForceFieldModel', lb_method, refinement_scaling=scaling) generate_boundary(ctx, 'MyUBB', UBB([0.05, 0, 0]), lb_method) generate_boundary(ctx, 'MyNoSlip', NoSlip(), lb_method)
def genNoSlip(): boundary = NoSlip(name='MyNoSlip') method = create_lb_method(stencil='D3Q19', method='srt') return create_boundary_class(boundary, method)
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 # for CPU simulations waLBerla's internal boundary handling can be used as well generate_lattice_model(ctx, 'LbCodeGenerationExample_LatticeModel', collision_rule, refinement_scaling=scaling) generate_boundary(ctx, 'LbCodeGenerationExample_UBB', UBB([0.05, 0, 0]), collision_rule.method) generate_boundary(ctx, 'LbCodeGenerationExample_NoSlip', NoSlip(), collision_rule.method)
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
def genNoSlip(): boundary = NoSlip(name='MyNoSlip') method = createLatticeBoltzmannMethod(stencil='D3Q19', method='srt') return createBoundaryClass(boundary, method)
from pystencils_walberla import CodeGeneration, generate_sweep with CodeGeneration() as ctx: # LB options options = { 'method': 'srt', 'stencil': 'D3Q19', 'relaxation_rate': sp.Symbol("omega"), 'field_name': 'pdfs', 'compressible': False, 'temporary_field_name': 'pdfs_tmp', 'optimization': {'cse_global': True, 'cse_pdfs': True, 'gpu_indexing_params': {'block_size': (128, 1, 1)}} } lb_method = create_lb_method(**options) update_rule = create_lb_update_rule(lb_method=lb_method, **options) # CPU lattice model - required for macroscopic value computation, VTK output etc. generate_lattice_model(ctx, 'UniformGridGPU_LatticeModel', lb_method) # gpu LB sweep & boundaries generate_sweep(ctx, 'UniformGridGPU_LbKernel', update_rule, field_swaps=[('pdfs', 'pdfs_tmp')], inner_outer_split=True, target='gpu') generate_boundary(ctx, 'UniformGridGPU_NoSlip', NoSlip(), lb_method, target='gpu') generate_boundary(ctx, 'UniformGridGPU_UBB', UBB([0.05, 0, 0]), lb_method, target='gpu') # communication generate_pack_info_from_kernel(ctx, 'UniformGridGPU_PackInfo', update_rule, target='gpu')
def poiseuille_channel(target, stencil_name): # physical parameters rho_0 = 1.2 # density eta = 0.2 # kinematic viscosity width = 41 # of box actual_width = width - 2 # subtract boundary layer from box width ext_force_density = 0.2 / actual_width ** 2 # scale by width to keep stable # LB parameters lb_stencil = LBStencil(stencil_name) if lb_stencil.D == 2: L = (4, width) elif lb_stencil.D == 3: L = (4, width, 4) else: raise Exception() periodicity = [True, False] + [True] * (lb_stencil.D - 2) omega = lbmpy.relaxationrates.relaxation_rate_from_lattice_viscosity(eta) # ## Data structures dh = ps.create_data_handling(L, periodicity=periodicity, default_target=target) src = dh.add_array('src', values_per_cell=len(lb_stencil)) dst = dh.add_array_like('dst', 'src') ρ = dh.add_array('rho', latex_name='\\rho', values_per_cell=1) u = dh.add_array('u', values_per_cell=dh.dim) # LB Setup lbm_config = LBMConfig(stencil=lb_stencil, relaxation_rate=omega, method=Method.TRT, compressible=True, force_model=ForceModel.GUO, force=tuple([ext_force_density] + [0] * (lb_stencil.D - 1)), kernel_type='collide_only') lbm_opt = LBMOptimisation(symbolic_field=src) collision = create_lb_update_rule(lbm_config=lbm_config, lbm_optimisation=lbm_opt) stream = create_stream_pull_with_output_kernel(collision.method, src, dst, {'velocity': u}) config = ps.CreateKernelConfig(cpu_openmp=False, target=dh.default_target) stream_kernel = ps.create_kernel(stream, config=config).compile() collision_kernel = ps.create_kernel(collision, config=config).compile() # Boundaries lbbh = LatticeBoltzmannBoundaryHandling(collision.method, dh, src.name, target=dh.default_target) # ## Set up the simulation init = macroscopic_values_setter(collision.method, velocity=(0,) * dh.dim, pdfs=src.center_vector, density=ρ.center) init_kernel = ps.create_kernel(init, ghost_layers=0).compile() noslip = NoSlip() wall_thickness = 2 if lb_stencil.D == 2: lbbh.set_boundary(noslip, ps.make_slice[:, :wall_thickness]) lbbh.set_boundary(noslip, ps.make_slice[:, -wall_thickness:]) elif lb_stencil.D == 3: lbbh.set_boundary(noslip, ps.make_slice[:, :wall_thickness, :]) lbbh.set_boundary(noslip, ps.make_slice[:, -wall_thickness:, :]) else: raise Exception() for bh in lbbh, : assert len(bh._boundary_object_to_boundary_info) == 1, "Restart kernel to clear boundaries" def init(): dh.fill(ρ.name, rho_0) dh.fill(u.name, np.nan, ghost_layers=True, inner_ghost_layers=True) dh.fill(u.name, 0) dh.run_kernel(init_kernel) # In[6]: sync_pdfs = dh.synchronization_function([src.name]) # Time loop def time_loop(steps): dh.all_to_gpu() i = -1 last_max_vel = -1 for i in range(steps): dh.run_kernel(collision_kernel) sync_pdfs() lbbh() dh.run_kernel(stream_kernel) dh.swap(src.name, dst.name) # Consider early termination if i % 100 == 0: if u.name in dh.gpu_arrays: dh.to_cpu(u.name) uu = dh.gather_array(u.name) # average periodic directions if lb_stencil.D == 3: # dont' swap order uu = np.average(uu, axis=2) uu = np.average(uu, axis=0) max_vel = np.nanmax(uu) if np.abs(max_vel / last_max_vel - 1) < 5E-6: break last_max_vel = max_vel # cut off wall regions uu = uu[wall_thickness:-wall_thickness] # correct for f/2 term uu -= np.array([ext_force_density / 2 / rho_0] + [0] * (lb_stencil.D - 1)) return uu init() # Simulation profile = time_loop(5000) # compare against analytical solution # The profile is of shape (n,3). Force is in x-direction y = np.arange(len(profile[:, 0])) mid = (y[-1] - y[0]) / 2 # Mid point of channel expected = poiseuille_flow((y - mid), actual_width, ext_force_density, rho_0 * eta) np.testing.assert_allclose(profile[:, 0], expected, rtol=0.006) # Test zero vel in other directions np.testing.assert_allclose(profile[:, 1:], np.zeros_like(profile[:, 1:]), atol=1E-9)
def rod_simulation(stencil_name, diameter, parallel=False, entropic=False, re=150, time_to_simulate=17.0, eval_interval=0.5, write_vtk=True, write_numpy=True): if stencil_name == 'D3Q19_new': stencil = Stencil.D3Q19 maxwellian_moments = True elif stencil_name == 'D3Q19_old': stencil = Stencil.D3Q19 maxwellian_moments = False elif stencil_name == 'D3Q27': stencil = Stencil.D3Q27 maxwellian_moments = False else: raise ValueError("Unknown stencil name " + stencil_name) d = diameter length = 16 * d u_max_at_throat = 0.07 u_max_at_inflow = 0.07 / (3**2) # Geometry parameters inflow_area = int(1.5 * d) constriction_length = int(1.8904 * d) throat_length = int(10 / 3 * d) constriction_diameter = int(d / 3) u_mean_at_throat = u_max_at_throat / 2 lattice_viscosity = u_mean_at_throat * constriction_diameter / re omega = relaxation_rate_from_lattice_viscosity(lattice_viscosity) lbm_config = LBMConfig(stencil=LBStencil(stencil), compressible=True, method=Method.SRT, relaxation_rate=omega, entropic=entropic, maxwellian_moments=maxwellian_moments) kernel_params = {} print("ω=", omega) dh = create_data_handling(domain_size=(length, d, d), parallel=parallel) sc = LatticeBoltzmannStep(data_handling=dh, kernel_params=kernel_params, name=stencil_name, lbm_config=lbm_config) # ----------------- Boundary Setup -------------------------------- def pipe_geometry(x, *_): # initialize with full diameter everywhere result = np.ones_like(x) * d # constriction constriction_begin = inflow_area constriction_end = constriction_begin + constriction_length c_x = np.linspace(0, 1, constriction_length) result[constriction_begin:constriction_end] = d * ( 1 - c_x) + constriction_diameter * c_x # throat throat_start = constriction_end throat_end = throat_start + throat_length result[throat_start:throat_end] = constriction_diameter return result bh = sc.boundary_handling add_pipe_inflow_boundary(bh, u_max_at_inflow, make_slice[0, :, :]) outflow = FixedDensity(1.0) bh.set_boundary(outflow, slice_from_direction('E', 3)) wall = NoSlip() add_pipe_walls(bh, pipe_geometry, wall) # ----------------- Run -------------------------------------------- scenario_name = stencil_name if not os.path.exists(scenario_name): os.mkdir(scenario_name) def to_time_steps(non_dimensional_time): return int(diameter / (u_max_at_inflow / 2) * non_dimensional_time) time_steps = to_time_steps(time_to_simulate) eval_interval = to_time_steps(eval_interval) print("Total number of time steps", time_steps) for i in range(time_steps // eval_interval): sc.run(eval_interval) if write_vtk: sc.write_vtk() vel = sc.velocity[:, :, :, :] max_vel = np.max(vel) print("Time steps:", sc.time_steps_run, "/", time_steps, "Max velocity: ", max_vel) if np.isnan(max_vel): raise ValueError("Simulation went unstable") if write_numpy: np.save(scenario_name + f'/velocity_{sc.time_steps_run}', sc.velocity_slice().filled(0.0))
def test_simple(target): if target == Target.GPU: import pytest pytest.importorskip('pycuda') dh = create_data_handling((4, 4), parallel=False, default_target=target) dh.add_array('pdfs', values_per_cell=9, cpu=True, gpu=target != Target.CPU) for i in range(9): dh.fill("pdfs", i, value_idx=i, ghost_layers=True) if target == Target.GPU: dh.all_to_gpu() lbm_config = LBMConfig(stencil=LBStencil(Stencil.D2Q9), compressible=False, relaxation_rate=1.8) config = CreateKernelConfig(target=target) lb_func = create_lb_function(lbm_config=lbm_config, config=config) bh = LatticeBoltzmannBoundaryHandling(lb_func.method, dh, 'pdfs', target=target) wall = NoSlip() moving_wall = UBB((1, 0)) bh.set_boundary(wall, make_slice[0, :]) bh.set_boundary(wall, make_slice[-1, :]) bh.set_boundary(wall, make_slice[:, 0]) bh.set_boundary(moving_wall, make_slice[:, -1]) bh.prepare() bh() if target == Target.GPU: dh.all_to_cpu() # left lower corner assert (dh.cpu_arrays['pdfs'][0, 0, 6] == 7) assert (dh.cpu_arrays['pdfs'][0, 1, 4] == 3) assert (dh.cpu_arrays['pdfs'][0, 1, 6] == 7) assert (dh.cpu_arrays['pdfs'][1, 0, 1] == 2) assert (dh.cpu_arrays['pdfs'][1, 0, 6] == 7) # left side assert (all(dh.cpu_arrays['pdfs'][0, 2:4, 4] == 3)) assert (all(dh.cpu_arrays['pdfs'][0, 2:4, 6] == 7)) assert (all(dh.cpu_arrays['pdfs'][0, 2:4, 5] == 5)) # left upper corner assert (dh.cpu_arrays['pdfs'][0, 4, 4] == 3) assert (dh.cpu_arrays['pdfs'][0, 4, 8] == 5) assert (dh.cpu_arrays['pdfs'][0, 5, 8] == 5 + 6 / 36) assert (dh.cpu_arrays['pdfs'][1, 5, 8] == 5 + 6 / 36) assert (dh.cpu_arrays['pdfs'][1, 5, 2] == 1) # top side assert (all(dh.cpu_arrays['pdfs'][2:4, 5, 2] == 1)) assert (all(dh.cpu_arrays['pdfs'][2:4, 5, 7] == 6 - 6 / 36)) assert (all(dh.cpu_arrays['pdfs'][2:4, 5, 8] == 5 + 6 / 36)) # right upper corner assert (dh.cpu_arrays['pdfs'][4, 5, 2] == 1) assert (dh.cpu_arrays['pdfs'][4, 5, 7] == 6 - 6 / 36) assert (dh.cpu_arrays['pdfs'][5, 5, 7] == 6 - 6 / 36) assert (dh.cpu_arrays['pdfs'][5, 4, 3] == 4) assert (dh.cpu_arrays['pdfs'][5, 4, 7] == 6) # right side assert (all(dh.cpu_arrays['pdfs'][5, 2:4, 3] == 4)) assert (all(dh.cpu_arrays['pdfs'][5, 2:4, 5] == 8)) assert (all(dh.cpu_arrays['pdfs'][5, 2:4, 7] == 6)) # right lower corner assert (dh.cpu_arrays['pdfs'][5, 1, 3] == 4) assert (dh.cpu_arrays['pdfs'][5, 1, 5] == 8) assert (dh.cpu_arrays['pdfs'][5, 0, 5] == 8) assert (dh.cpu_arrays['pdfs'][4, 0, 1] == 2) assert (dh.cpu_arrays['pdfs'][4, 0, 5] == 8) # lower side assert (all(dh.cpu_arrays['pdfs'][0, 2:4, 4] == 3)) assert (all(dh.cpu_arrays['pdfs'][0, 2:4, 6] == 7)) assert (all(dh.cpu_arrays['pdfs'][0, 2:4, 8] == 5))
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()