Beispiel #1
0
def mu_kernel(free_energy, order_parameters, phi_field, mu_field, dx=1, discretization='standard'):
    """Reads from order parameter (phi) field and updates chemical potentials"""
    assert phi_field.spatial_dimensions == mu_field.spatial_dimensions
    dim = phi_field.spatial_dimensions
    chemical_potential = chemical_potentials_from_free_energy(free_energy, order_parameters)
    chemical_potential = substitute_laplacian_by_sum(chemical_potential, dim)
    chemical_potential = chemical_potential.subs({op: phi_field(i) for i, op in enumerate(order_parameters)})
    return [Assignment(mu_field(i), discretize_spatial(mu_i, dx, discretization))
            for i, mu_i in enumerate(chemical_potential)]
Beispiel #2
0
def force_kernel_using_pressure_tensor(force_field, pressure_tensor_field, extra_force=None,
                                       pbs=None, dx=1, discretization='standard'):
    dim = force_field.spatial_dimensions
    index_map = symmetric_tensor_linearization(dim)

    p = sp.Matrix(dim, dim, lambda i, j: pressure_tensor_field(index_map[i, j] if i < j else index_map[j, i]))
    f = force_from_pressure_tensor(p, pbs=pbs)
    if extra_force:
        f += extra_force
    return [Assignment(force_field(i), discretize_spatial(f_i, dx, discretization).expand())
            for i, f_i in enumerate(f)]
Beispiel #3
0
def pressure_tensor_kernel_pbs(free_energy, order_parameters,
                               phi_field, pressure_tensor_field, pbs_field, density_field,
                               transformation_matrix=None, dx=1, discretization='standard'):
    dim = phi_field.spatial_dimensions

    p = pressure_tensor_from_free_energy(free_energy, order_parameters, dim, transformation_matrix, include_bulk=False)
    assert transformation_matrix is None

    p = p.subs({op: phi_field(i) for i, op in enumerate(order_parameters)})
    index_map = symmetric_tensor_linearization(dim)
    eqs = []
    for index, lin_index in index_map.items():
        eq = Assignment(pressure_tensor_field(lin_index), discretize_spatial(p[index], dx, discretization).expand())
        eqs.append(eq)

    rhs = pressure_tensor_bulk_sqrt_term(free_energy, order_parameters, density_field.center)
    pbs = Assignment(pbs_field.center, discretize_spatial(rhs, dx, discretization))

    eqs.append(pbs)
    return eqs
Beispiel #4
0
def pressure_tensor_kernel(free_energy, order_parameters, phi_field, pressure_tensor_field,
                           dx=1, discretization='standard', bulk_chemical_potential=None):
    dim = phi_field.spatial_dimensions

    p = pressure_tensor_from_free_energy(free_energy, order_parameters, dim,
                                         bulk_chemical_potential=bulk_chemical_potential)

    p = p.subs({op: phi_field(i) for i, op in enumerate(order_parameters)})
    index_map = symmetric_tensor_linearization(dim)
    eqs = []
    for index, lin_index in index_map.items():
        eq = Assignment(pressure_tensor_field(lin_index), discretize_spatial(p[index], dx, discretization).expand())
        eqs.append(eq)
    return eqs
Beispiel #5
0
    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()
Beispiel #6
0
def force_kernel_using_mu(force_field, phi_field, mu_field, dx=1, discretization='standard'):
    """Computes forces using precomputed chemical potential - needs mu_kernel first"""
    assert mu_field.index_dimensions == 1
    force = force_from_phi_and_mu(phi_field.center_vector, mu=mu_field.center_vector, dim=mu_field.spatial_dimensions)
    return [Assignment(force_field(i),
                       discretize_spatial(f_i, dx, discretization)).expand() for i, f_i in enumerate(force)]
Beispiel #7
0
def create_model(domain_size,
                 num_phases,
                 coeff_a,
                 coeff_epsilon,
                 gabd,
                 alpha=1,
                 penalty_factor=0.01,
                 simplex_projection=False):
    def lapl(e):
        return sum(Diff(Diff(e, i), i) for i in range(dh.dim))

    def interfacial_chemical_potential(c):
        result = []
        n = len(c)
        for i in range(n):
            entry = 0
            for k in range(n):
                if i == k:
                    continue
                eps = coeff_epsilon[(k, i)] if i < k else coeff_epsilon[(i, k)]
                entry += alpha**2 * eps**2 * (c[k] * lapl(c[i]) -
                                              c[i] * lapl(c[k]))
            result.append(entry)
        return -sp.Matrix(result)

    def bulk(c):
        result = 0
        for i in range(num_phases):
            for j in range(i):
                result += (c[i]**2 * c[j]**2) / (4 * coeff_a[i, j])
        for i in range(num_phases):
            for j in range(i):
                for k in range(j):
                    result += gabd * c[i] * c[j] * c[k]
        return result

    # -------------- Data ------------------
    dh = create_data_handling(domain_size,
                              periodicity=(True, True),
                              default_ghost_layers=2)

    c = dh.add_array("c", values_per_cell=num_phases)
    rho = dh.add_array("rho", values_per_cell=1)
    mu = dh.add_array("mu", values_per_cell=num_phases, latex_name="\\mu")
    force = dh.add_array("F", values_per_cell=dh.dim)
    u = dh.add_array("u", values_per_cell=dh.dim)

    # Distribution functions for each order parameter
    pdf_field = []
    pdf_dst_field = []
    for i in range(num_phases):
        pdf_field_local = dh.add_array(f"pdf_ch_{i}",
                                       values_per_cell=9)  # 9 for D2Q9
        pdf_dst_field_local = dh.add_array(f"pdfs_ch_{i}_dst",
                                           values_per_cell=9)
        pdf_field.append(pdf_field_local)
        pdf_dst_field.append(pdf_dst_field_local)

    # Distribution functions for the hydrodynamics
    pdf_hydro_field = dh.add_array("pdfs", values_per_cell=9)
    pdf_hydro_dst_field = dh.add_array("pdfs_dst", values_per_cell=9)

    # ------------- Compute kernels --------
    c_vec = c.center_vector
    f_penalty = penalty_factor * (1 - sum(c_vec[i]
                                          for i in range(num_phases)))**2
    f_bulk = bulk(c_vec) + f_penalty
    print(f_bulk)
    mu_eq = chemical_potentials_from_free_energy(f_bulk,
                                                 order_parameters=c_vec)
    mu_eq += interfacial_chemical_potential(c_vec)
    mu_eq = [expand_diff_full(mu_i, functions=c) for mu_i in mu_eq]
    mu_assignments = [
        Assignment(mu(i), discretize_spatial(mu_i, dx=1, stencil='isotropic'))
        for i, mu_i in enumerate(mu_eq)
    ]
    mu_compute_kernel = create_kernel(mu_assignments).compile()

    mu_discretize_substitutions = forth_order_isotropic_discretize(mu)
    force_rhs = force_from_phi_and_mu(order_parameters=c_vec,
                                      dim=dh.dim,
                                      mu=mu.center_vector)
    force_rhs = force_rhs.subs(mu_discretize_substitutions)
    force_assignments = [
        Assignment(force(i), force_rhs[i]) for i in range(dh.dim)
    ]
    force_kernel = create_kernel(force_assignments).compile()

    ch_collide_kernels = []
    ch_methods = []
    for i in range(num_phases):
        ch_method = cahn_hilliard_lb_method(LBStencil(Stencil.D2Q9),
                                            mu(i),
                                            relaxation_rate=1.0,
                                            gamma=1.0)
        ch_methods.append(ch_method)

        lbm_config = LBMConfig(lb_method=ch_method,
                               kernel_type='collide_only',
                               density_input=c(i),
                               velocity_input=u.center_vector,
                               compressible=True)
        lbm_opt = LBMOptimisation(symbolic_field=pdf_field[i])
        ch_update_rule = create_lb_update_rule(lbm_config=lbm_config,
                                               lbm_optimisation=lbm_opt)

        ch_assign = ch_update_rule.all_assignments
        ch_kernel = create_kernel(ch_assign).compile()
        ch_collide_kernels.append(ch_kernel)

    ch_stream_kernels = []
    for i in range(num_phases):
        ch_method = ch_methods[i]

        lbm_config = LBMConfig(lb_method=ch_method,
                               kernel_type='stream_pull_only',
                               temporary_field_name=pdf_dst_field[i].name)
        lbm_opt = LBMOptimisation(symbolic_field=pdf_field[i])
        ch_update_rule = create_lb_update_rule(lbm_config=lbm_config,
                                               lbm_optimisation=lbm_opt)

        ch_assign = ch_update_rule.all_assignments
        ch_kernel = create_kernel(ch_assign).compile()
        ch_stream_kernels.append(ch_kernel)

    # Defining the initialisation kernels for the C-H pdfs
    init_kernels = []
    for i in range(num_phases):
        ch_method = ch_methods[i]
        init_assign = pdf_initialization_assignments(
            lb_method=ch_method,
            density=c_vec[i],
            velocity=(0, 0),
            pdfs=pdf_field[i].center_vector)
        init_kernel = create_kernel(init_assign).compile()
        init_kernels.append(init_kernel)

    getter_kernels = []
    for i in range(num_phases):
        cqc = ch_methods[i].conserved_quantity_computation
        output_assign = cqc.output_equations_from_pdfs(
            pdf_field[i].center_vector, {'density': c(i)})
        getter_kernel = create_kernel(output_assign).compile()
        getter_kernels.append(getter_kernel)

    lbm_config = LBMConfig(kernel_type='collide_only',
                           relaxation_rate=1.0,
                           force=force,
                           compressible=True)
    lbm_opt = LBMOptimisation(symbolic_field=pdf_hydro_field)
    collide_assign = create_lb_update_rule(lbm_config=lbm_config,
                                           lbm_optimisation=lbm_opt)
    collide_kernel = create_kernel(collide_assign).compile()

    lbm_config = LBMConfig(kernel_type='stream_pull_only',
                           temporary_field_name=pdf_hydro_dst_field.name,
                           output={
                               "density": rho,
                               "velocity": u
                           })
    lbm_opt = LBMOptimisation(symbolic_field=pdf_hydro_field)
    stream_assign = create_lb_update_rule(lbm_config=lbm_config,
                                          lbm_optimisation=lbm_opt)

    stream_kernel = create_kernel(stream_assign).compile()

    method_collide = collide_assign.method
    init_hydro_assign = pdf_initialization_assignments(
        lb_method=method_collide,
        density=rho.center,
        velocity=u.center_vector,
        pdfs=pdf_hydro_field.center_vector)
    init_hydro_kernel = create_kernel(init_hydro_assign).compile()

    output_hydro_assign = cqc.output_equations_from_pdfs(
        pdf_hydro_field.center_vector, {
            'density': rho.center,
            'velocity': u.center_vector
        }).all_assignments
    # Creating getter kernel to extract quantities
    getter_hydro_kernel = create_kernel(
        output_hydro_assign).compile()  # getter kernel

    # Setting values of arrays
    dh.cpu_arrays[c.name].fill(0)
    dh.cpu_arrays[u.name].fill(0)
    dh.cpu_arrays[rho.name].fill(1)
    dh.cpu_arrays[mu.name].fill(0)
    dh.cpu_arrays[force.name].fill(0)

    def init():
        for k in init_kernels:
            dh.run_kernel(k)
        dh.run_kernel(init_hydro_kernel)

    pdf_sync_fns = []
    for i in range(num_phases):
        sync_fn = dh.synchronization_function([pdf_field[i].name])
        pdf_sync_fns.append(sync_fn)
    hydro_sync_fn = dh.synchronization_function([pdf_hydro_field.name])
    c_sync_fn = dh.synchronization_function([c.name])
    mu_sync = dh.synchronization_function([mu.name])

    def run(steps):
        for t in range(steps):
            # μ and P
            c_sync_fn()
            dh.run_kernel(mu_compute_kernel)
            mu_sync()
            dh.run_kernel(force_kernel)

            # Hydrodynamic LB
            dh.run_kernel(collide_kernel)  # running collision kernel
            hydro_sync_fn()
            dh.run_kernel(stream_kernel)  # running streaming kernel
            dh.swap(pdf_hydro_field.name, pdf_hydro_dst_field.name)
            dh.run_kernel(getter_hydro_kernel)

            # Cahn-Hilliard LBs
            for i in range(num_phases):
                dh.run_kernel(ch_collide_kernels[i])
                pdf_sync_fns[i]()
                dh.run_kernel(ch_stream_kernels[i])
                dh.swap(pdf_field[i].name, pdf_dst_field[i].name)
                dh.run_kernel(getter_kernels[i])
            if simplex_projection:
                simplex_projection_2d(dh.cpu_arrays[c.name])
        return dh.cpu_arrays[c.name][1:-1, 1:-1, :]

    return dh, init, run