def test_sliced_iteration_llvm(): size = (4, 4) src_arr = np.ones(size) dst_arr = np.zeros_like(src_arr) src_field = Field.create_from_numpy_array('src', src_arr) dst_field = Field.create_from_numpy_array('dst', dst_arr) a, b = sp.symbols("a b") update_rule = Assignment(dst_field[0, 0], (a * src_field[0, 1] + a * src_field[0, -1] + b * src_field[1, 0] + b * src_field[-1, 0]) / 4) x_end = TypedSymbol("x_end", "int") s = make_slice[1:x_end, 1] x_end_value = size[1] - 1 import pystencils.llvm as llvm_generator ast = llvm_generator.create_kernel(sympy_cse_on_assignment_list( [update_rule]), iteration_slice=s) kernel = llvm_generator.make_python_function(ast) kernel(src=src_arr, dst=dst_arr, a=1.0, b=1.0, x_end=x_end_value) expected_result = np.zeros(size) expected_result[1:x_end_value, 1] = 1 np.testing.assert_almost_equal(expected_result, dst_arr)
def test_variable_sized_fields(): src_field = Field.create_generic('src', spatial_dimensions=2) dst_field = Field.create_generic('dst', spatial_dimensions=2) update_rule = Assignment(dst_field[0, 0], (src_field[0, 1] + src_field[0, -1] + src_field[1, 0] + src_field[-1, 0]) / 4) ast = create_cuda_kernel(sympy_cse_on_assignment_list([update_rule])) kernel = make_python_function(ast) size = (3, 3) src_arr = np.random.rand(*size) src_arr = add_ghost_layers(src_arr) dst_arr = np.zeros_like(src_arr) gpu_src_arr = gpuarray.to_gpu(src_arr) gpu_dst_arr = gpuarray.to_gpu(dst_arr) kernel(src=gpu_src_arr, dst=gpu_dst_arr) gpu_dst_arr.get(dst_arr) stencil = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]]) / 4.0 reference = convolve(remove_ghost_layers(src_arr), stencil, mode='constant', cval=0.0) reference = add_ghost_layers(reference) np.testing.assert_almost_equal(reference, dst_arr)
def __init__(self, free_energy, order_parameters, domain_size, data_handling=None, name='pfn', hydro_dynamic_relaxation_rate=1.0, cahn_hilliard_relaxation_rates=1.0, cahn_hilliard_gammas=1, optimization=None): if optimization is None: optimization = {'openmp': False, 'target': Target.CPU} openmp = optimization.get('openmp', False) target = optimization.get('target', Target.CPU) if not hasattr(cahn_hilliard_relaxation_rates, '__len__'): cahn_hilliard_relaxation_rates = [cahn_hilliard_relaxation_rates ] * len(order_parameters) if not hasattr(cahn_hilliard_gammas, '__len__'): cahn_hilliard_gammas = [cahn_hilliard_gammas ] * len(order_parameters) if data_handling is None: data_handling = create_data_handling(domain_size, periodicity=True, parallel=False) dh = data_handling self.data_handling = dh stencil = LBStencil(Stencil.D3Q19) if dh.dim == 3 else LBStencil( Stencil.D2Q9) self.free_energy = free_energy # Data Handling kernel_parameters = { 'cpu_openmp': openmp, 'target': target, 'ghost_layers': 2 } gpu = target == Target.GPU phi_size = len(order_parameters) gl = kernel_parameters['ghost_layers'] self.phi_field = dh.add_array(f'{name}_phi', values_per_cell=phi_size, gpu=gpu, latex_name='φ', ghost_layers=gl) self.mu_field = dh.add_array(f"{name}_mu", values_per_cell=phi_size, gpu=gpu, latex_name="μ", ghost_layers=gl) self.vel_field = dh.add_array(f"{name}_u", values_per_cell=data_handling.dim, gpu=gpu, latex_name="u", ghost_layers=gl) self.force_field = dh.add_array(f"{name}_force", values_per_cell=dh.dim, gpu=gpu, latex_name="F", ghost_layers=gl) self.phi = SlicedGetterDataHandling(self.data_handling, self.phi_field.name) self.mu = SlicedGetterDataHandling(self.data_handling, self.mu_field.name) self.velocity = SlicedGetterDataHandling(self.data_handling, self.vel_field.name) self.force = SlicedGetterDataHandling(self.data_handling, self.force_field.name) self.ch_pdfs = [] for i in range(len(order_parameters)): src = dh.add_array(f"{name}_ch_src{i}", values_per_cell=stencil.Q, ghost_layers=gl) dst = dh.add_array(f"{name}_ch_dst{i}", values_per_cell=stencil.Q, ghost_layers=gl) self.ch_pdfs.append((src, dst)) self.hydro_pdfs = (dh.add_array(f"{name}_hydro_src", values_per_cell=stencil.Q, ghost_layers=gl), dh.add_array(f"{name}_hydro_dst", values_per_cell=stencil.Q, ghost_layers=gl)) # Compute Kernels mu_assignments = mu_kernel(self.free_energy, order_parameters, self.phi_field, self.mu_field) mu_assignments = [ Assignment(a.lhs, a.rhs.doit()) for a in mu_assignments ] mu_assignments = sympy_cse_on_assignment_list(mu_assignments) self.mu_kernel = create_kernel(mu_assignments, **kernel_parameters).compile() force_rhs = force_from_phi_and_mu(self.phi_field.center_vector, dim=dh.dim, mu=self.mu_field.center_vector) force_rhs = [ discretize_spatial(e, dx=1, stencil=fd_stencils_forth_order_isotropic) for e in force_rhs ] force_assignments = [ Assignment(lhs, rhs) for lhs, rhs in zip(self.force_field.center_vector, force_rhs) ] self.force_kernel = create_kernel(force_assignments, **kernel_parameters).compile() self.ch_lb_kernels = [] for i, (src, dst) in enumerate(self.ch_pdfs): ch_method = cahn_hilliard_lb_method( stencil, self.mu_field(i), relaxation_rate=cahn_hilliard_relaxation_rates[i], gamma=cahn_hilliard_gammas[i]) opt = optimization.copy() opt['symbolic_field'] = src opt['symbolic_temporary_field'] = dst kernel = create_lb_function( lb_method=ch_method, optimization=opt, velocity_input=self.vel_field.center_vector, output={'density': self.phi_field(i)}) self.ch_lb_kernels.append(kernel) opt = optimization.copy() opt['symbolic_field'] = self.hydro_pdfs[0] opt['symbolic_temporary_field'] = self.hydro_pdfs[1] self.hydro_lb_kernel = create_lb_function( stencil=stencil, relaxation_rate=hydro_dynamic_relaxation_rate, force=self.force_field.center_vector, output={'velocity': self.vel_field}, optimization=opt) # Setter Kernels self.init_kernels = [] for i in range(len(order_parameters)): ch_method = self.ch_lb_kernels[i].method init_assign = pdf_initialization_assignments( lb_method=ch_method, density=self.phi_field.center_vector[i], velocity=self.vel_field.center_vector, pdfs=self.ch_pdfs[i][0].center_vector) init_kernel = create_kernel(init_assign, **kernel_parameters).compile() self.init_kernels.append(init_kernel) init_assign = pdf_initialization_assignments( lb_method=self.hydro_lb_kernel.method, density=1, velocity=self.vel_field.center_vector, pdfs=self.hydro_pdfs[0].center_vector) self.init_kernels.append( create_kernel(init_assign, **kernel_parameters).compile()) # Sync functions self.phi_sync = dh.synchronization_function([self.phi_field.name]) self.mu_sync = dh.synchronization_function([self.mu_field.name]) self.pdf_sync = dh.synchronization_function( [self.hydro_pdfs[0].name] + [src.name for src, _ in self.ch_pdfs]) self.reset()
def __init__(self, free_energy, order_parameters, domain_size=None, data_handling=None, name='pf', hydro_lbm_parameters=MappingProxyType({}), hydro_dynamic_relaxation_rate=1.0, cahn_hilliard_relaxation_rates=1.0, cahn_hilliard_gammas=1, density_order_parameter=None, optimization=None, kernel_params=MappingProxyType({}), dx=1, dt=1, solve_cahn_hilliard_with_finite_differences=False, order_parameter_force=None, transformation_matrix=None, concentration_to_order_parameters=None, order_parameters_to_concentrations=None, homogeneous_neumann_boundaries=False, discretization='standard'): if optimization is None: optimization = {'openmp': False, 'target': Target.CPU} openmp = optimization.get('openmp', False) target = optimization.get('target', Target.CPU) if data_handling is None: data_handling = create_data_handling(domain_size, periodicity=True, parallel=False) self.free_energy = free_energy self.concentration_to_order_parameter = concentration_to_order_parameters self.order_parameters_to_concentrations = order_parameters_to_concentrations if transformation_matrix: op_transformation = np.array(transformation_matrix).astype(float) op_transformation_inv = np.array( transformation_matrix.inv()).astype(float) axes = ([-1], [1]) if self.concentration_to_order_parameter is None: self.concentration_to_order_parameter = lambda c: np.tensordot( c, op_transformation, axes=axes) if self.order_parameters_to_concentrations is None: self.order_parameters_to_concentrations = lambda p: np.tensordot( p, op_transformation_inv, axes=axes) self.chemical_potentials = chemical_potentials_from_free_energy( free_energy, order_parameters) # ------------------ Adding arrays --------------------- gpu = target == Target.GPU self.gpu = gpu self.num_order_parameters = len(order_parameters) self.order_parameters = order_parameters pressure_tensor_size = len( symmetric_tensor_linearization(data_handling.dim)) self.name = name self.phi_field_name = name + "_phi" self.mu_field_name = name + "_mu" self.vel_field_name = name + "_u" self.force_field_name = name + "_F" self.pressure_tensor_field_name = name + "_P" self.data_handling = data_handling dh = self.data_handling phi_size = len(order_parameters) self.phi_field = dh.add_array(self.phi_field_name, values_per_cell=phi_size, gpu=gpu, latex_name='φ') self.mu_field = dh.add_array(self.mu_field_name, values_per_cell=phi_size, gpu=gpu, latex_name="μ") self.vel_field = dh.add_array(self.vel_field_name, values_per_cell=data_handling.dim, gpu=gpu, latex_name="u") self.force_field = dh.add_array(self.force_field_name, values_per_cell=dh.dim, gpu=gpu, latex_name="F") self.pressure_tensor_field = data_handling.add_array( self.pressure_tensor_field_name, gpu=gpu, values_per_cell=pressure_tensor_size, latex_name='P') self.flag_interface = FlagInterface(data_handling, 'flags') # ------------------ Creating kernels ------------------ phi = tuple(self.phi_field(i) for i in range(len(order_parameters))) F = self.free_energy.subs( {old: new for old, new in zip(order_parameters, phi)}) if homogeneous_neumann_boundaries: def apply_neumann_boundaries(eqs): fields = [ data_handling.fields[self.phi_field_name], data_handling.fields[self.pressure_tensor_field_name] ] flag_field = data_handling.fields[ self.flag_interface.flag_field_name] return add_neumann_boundary(eqs, fields, flag_field, "neumann_flag", inverse_flag=False) else: def apply_neumann_boundaries(eqs): return eqs # μ and pressure tensor update self.phi_sync = data_handling.synchronization_function( [self.phi_field_name], target=target) self.mu_eqs = mu_kernel(F, phi, self.phi_field, self.mu_field, dx) self.pressure_tensor_eqs = pressure_tensor_kernel( self.free_energy, order_parameters, self.phi_field, self.pressure_tensor_field, dx=dx, discretization=discretization) mu_and_pressure_tensor_eqs = self.mu_eqs + self.pressure_tensor_eqs mu_and_pressure_tensor_eqs = apply_neumann_boundaries( mu_and_pressure_tensor_eqs) self.mu_and_pressure_tensor_kernel = create_kernel( sympy_cse_on_assignment_list(mu_and_pressure_tensor_eqs), target=target, cpu_openmp=openmp).compile() # F Kernel extra_force = sp.Matrix([0] * self.data_handling.dim) if order_parameter_force is not None: for order_parameter_idx, force in order_parameter_force.items(): extra_force += sp.Matrix([ f_i * self.phi_field(order_parameter_idx) for f_i in force ]) self.force_eqs = force_kernel_using_pressure_tensor( self.force_field, self.pressure_tensor_field, dx=dx, extra_force=extra_force, discretization=discretization) self.force_from_pressure_tensor_kernel = create_kernel( apply_neumann_boundaries(self.force_eqs), target=target, cpu_openmp=openmp).compile() self.pressure_tensor_sync = data_handling.synchronization_function( [self.pressure_tensor_field_name], target=target) hydro_lbm_parameters = hydro_lbm_parameters.copy() # Hydrodynamic LBM if density_order_parameter is not None: density_idx = order_parameters.index(density_order_parameter) hydro_lbm_parameters['compute_density_in_every_step'] = True hydro_lbm_parameters['density_data_name'] = self.phi_field_name hydro_lbm_parameters['density_data_index'] = density_idx if 'optimization' not in hydro_lbm_parameters: hydro_lbm_parameters['optimization'] = optimization else: hydro_lbm_parameters['optimization'].update(optimization) self.hydro_lbm_step = LatticeBoltzmannStep( data_handling=data_handling, name=name + '_hydroLBM', relaxation_rate=hydro_dynamic_relaxation_rate, compute_velocity_in_every_step=True, force=tuple([self.force_field(i) for i in range(dh.dim)]), velocity_data_name=self.vel_field_name, kernel_params=kernel_params, flag_interface=self.flag_interface, time_step_order='collide_stream', **hydro_lbm_parameters) # Cahn-Hilliard LBMs if not hasattr(cahn_hilliard_relaxation_rates, '__len__'): cahn_hilliard_relaxation_rates = [cahn_hilliard_relaxation_rates ] * len(order_parameters) if not hasattr(cahn_hilliard_gammas, '__len__'): cahn_hilliard_gammas = [cahn_hilliard_gammas ] * len(order_parameters) self.cahn_hilliard_steps = [] if solve_cahn_hilliard_with_finite_differences: if density_order_parameter is not None: raise NotImplementedError( "density_order_parameter not supported when " "CH is solved with finite differences") ch_step = CahnHilliardFDStep( self.data_handling, self.phi_field_name, self.mu_field_name, self.vel_field_name, target=target, dx=dx, dt=dt, mobilities=1, equation_modifier=apply_neumann_boundaries) self.cahn_hilliard_steps.append(ch_step) else: for i, op in enumerate(order_parameters): if op == density_order_parameter: continue ch_method = cahn_hilliard_lb_method( self.hydro_lbm_step.method.stencil, self.mu_field(i), relaxation_rate=cahn_hilliard_relaxation_rates[i], gamma=cahn_hilliard_gammas[i]) ch_step = LatticeBoltzmannStep( data_handling=data_handling, relaxation_rate=1, lb_method=ch_method, velocity_input_array_name=self.vel_field.name, density_data_name=self.phi_field.name, stencil='D3Q19' if self.data_handling.dim == 3 else 'D2Q9', compute_density_in_every_step=True, density_data_index=i, flag_interface=self.hydro_lbm_step.boundary_handling. flag_interface, name=name + f"_chLbm_{i}", optimization=optimization) self.cahn_hilliard_steps.append(ch_step) self._vtk_writer = None self.run_hydro_lbm = True self.density_order_parameter = density_order_parameter self.time_steps_run = 0 self.reset() self.neumann_flag = 0