From 9480b851b005671c92970774e718d6f515f7b8b4 Mon Sep 17 00:00:00 2001 From: Martin Bauer <martin.bauer@fau.de> Date: Fri, 11 Jan 2019 14:50:03 +0100 Subject: [PATCH] New phase field step that uses 4th order FD to compute force - complicated pressure tensor derivation not required --- phasefield/n_phase_boyer.py | 18 +-- phasefield/phasefieldstep_direct.py | 175 ++++++++++++++++++++++++++++ 2 files changed, 181 insertions(+), 12 deletions(-) create mode 100644 phasefield/phasefieldstep_direct.py diff --git a/phasefield/n_phase_boyer.py b/phasefield/n_phase_boyer.py index a1e2eec7..75f88f50 100644 --- a/phasefield/n_phase_boyer.py +++ b/phasefield/n_phase_boyer.py @@ -173,18 +173,12 @@ class capital_h(sp.Function): else: raise sp.function.ArgumentIndexError(self, argindex) - @staticmethod - def insert(expr): - if isinstance(expr, capital_h): - u, v = expr.args - av = sp.Abs(v) - zero_cond = sp.And(sp.Eq(u, 0), sp.Eq(v, 0)) - return sp.Piecewise((0, zero_cond), - (av * v / (av + u**2), True)) - else: - new_args = [capital_h.insert(arg) for arg in expr.args] - return expr.func(*new_args) if new_args else expr - + def doit(self, **hints): + u, v = self.args + av = sp.Abs(v) + zero_cond = sp.And(sp.Eq(u, 0), sp.Eq(v, 0)) + return sp.Piecewise((0, zero_cond), + (av * v / (av + u**2), True)) def correction_g(c, surface_tensions, symbolic_coefficients=False): assert len(c) == surface_tensions.rows diff --git a/phasefield/phasefieldstep_direct.py b/phasefield/phasefieldstep_direct.py new file mode 100644 index 00000000..29f3a196 --- /dev/null +++ b/phasefield/phasefieldstep_direct.py @@ -0,0 +1,175 @@ +import numpy as np +from lbmpy.creationfunctions import create_lb_function +from lbmpy.macroscopic_value_kernels import pdf_initialization_assignments +from lbmpy.phasefield.analytical import force_from_phi_and_mu +from lbmpy.phasefield.cahn_hilliard_lbm import cahn_hilliard_lb_method +from lbmpy.phasefield.kerneleqs import mu_kernel +from lbmpy.stencils import get_stencil +from pystencils import create_data_handling, Assignment, create_kernel +from pystencils.fd import discretize_spatial +from pystencils.fd.spatial import fd_stencils_forth_order_isotropic +from pystencils.simp import sympy_cse_on_assignment_list +from pystencils.slicing import SlicedGetterDataHandling + + +class PhaseFieldStepDirect: + + 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': 'cpu'} + openmp = optimization.get('openmp', False) + target = optimization.get('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 = get_stencil('D3Q19' if dh.dim == 3 else 'D2Q9') + + self.free_energy = free_energy + + # Data Handling + kernel_parameters = {'cpu_openmp': openmp, 'target': target, 'ghost_layers': 2} + gpu = target == 'gpu' + phi_size = len(order_parameters) + gl = kernel_parameters['ghost_layers'] + self.phi_field = dh.add_array('{}_phi'.format(name), values_per_cell=phi_size, gpu=gpu, latex_name='φ', + ghost_layers=gl) + self.mu_field = dh.add_array("{}_mu".format(name), values_per_cell=phi_size, gpu=gpu, latex_name="μ", + ghost_layers=gl) + self.vel_field = dh.add_array("{}_u".format(name), values_per_cell=data_handling.dim, gpu=gpu, latex_name="u", + ghost_layers=gl) + + self.force_field = dh.add_array("{}_force".format(name), 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("{}_ch_src{}".format(name, i), values_per_cell=len(stencil), ghost_layers=gl) + dst = dh.add_array("{}_ch_dst{}".format(name, i), values_per_cell=len(stencil), ghost_layers=gl) + self.ch_pdfs.append((src, dst)) + self.hydro_pdfs = (dh.add_array("{}_hydro_src".format(name), values_per_cell=len(stencil), ghost_layers=gl), + dh.add_array("{}_hydro_dst".format(name), values_per_cell=len(stencil), 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 reset(self): + dh = self.data_handling + dh.fill(self.vel_field.name, 0) + dh.fill(self.mu_field.name, 0) + dh.fill(self.force_field.name, 0) + + def set_pdf_fields_from_macroscopic_values(self): + self.reset() + for k in self.init_kernels: + self.data_handling.run_kernel(k) + + def set_concentration(self, slice_obj, concentration): + phi = np.array(concentration) + + for b in self.data_handling.iterate(slice_obj): + for i in range(phi.shape[-1]): + b[self.phi_field.name][..., i] = phi[i] + + def set_single_concentration(self, slice_obj, phase_idx, value=1): + num_phases = self.phi_field.index_shape[0] + zeros = [0] * num_phases + zeros[phase_idx] = value + self.set_concentration(slice_obj, zeros) + + def smooth(self, sigma=2): + from scipy.ndimage.filters import gaussian_filter + dh = self.data_handling + + for block in dh.iterate(ghost_layers=True): + c_arr = block[self.phi_field.name] + for i in range(self.phi_field.index_shape[0]): + gaussian_filter(c_arr[..., i], sigma=sigma, output=c_arr[..., i]) + + def time_step(self): + dh = self.data_handling + + self.phi_sync() + dh.run_kernel(self.mu_kernel) + + self.mu_sync() + dh.run_kernel(self.force_kernel) + + self.pdf_sync() + dh.run_kernel(self.hydro_lb_kernel) + dh.swap(self.hydro_pdfs[0].name, self.hydro_pdfs[1].name) + + for ch_kernel, (src, dst) in zip(self.ch_lb_kernels, self.ch_pdfs): + dh.run_kernel(ch_kernel) + dh.swap(src.name, dst.name) -- GitLab