Exemplo n.º 1
0
 def _repr_html_(self):
     table = """
     <table style="border:none; width: 100%">
         <tr {nb}>
             <th {nb} >Central Moment / Cumulant</th>
             <th {nb} >Eq. Value </th>
             <th {nb} >Relaxation Rate</th>
         </tr>
         {content}
     </table>
     """
     content = ""
     for cumulant, (eq_value,
                    rr) in self._cumulant_to_relaxation_info_dict.items():
         vals = {
             'rr': f"${sp.latex(rr)}$",
             'cumulant': f"${sp.latex(cumulant)}$",
             'eq_value': f"${sp.latex(eq_value)}$",
             'nb': 'style="border:none"',
         }
         order = get_order(cumulant)
         if order <= 1:
             vals['cumulant'] += ' (central moment)'
             if order == 1 and self.force_model_rr_override:
                 vals['rr'] += ' (overridden by force model)'
         content += """<tr {nb}>
                         <td {nb}>{cumulant}</td>
                         <td {nb}>{eq_value}</td>
                         <td {nb}>{rr}</td>
                      </tr>\n""".format(**vals)
     return table.format(content=content, nb='style="border:none"')
Exemplo n.º 2
0
    def backward_transform(self,
                           cumulant_base=POST_COLLISION_CUMULANT,
                           central_moment_base=POST_COLLISION_MONOMIAL_CENTRAL_MOMENT,
                           simplification=True,
                           omit_conserved_moments=False,
                           subexpression_base='sub_C_to_k'):
        simplification = self._get_simp_strategy(simplification)

        main_assignments = []
        for exp in self.central_moment_exponents:
            if omit_conserved_moments and get_order(exp) <= 1:
                continue
            eq = self.central_moment_from_cumulants(exp, cumulant_base)
            k_symbol = statistical_quantity_symbol(central_moment_base, exp)
            main_assignments.append(Assignment(k_symbol, eq))
        symbol_gen = SymbolGen(subexpression_base)
        ac = AssignmentCollection(main_assignments, subexpression_symbol_generator=symbol_gen)
        
        if simplification:
            ac = simplification.apply(ac)
        return ac
Exemplo n.º 3
0
def _get_relaxation_info_dict(relaxation_rates, nested_moments, dim):
    r"""Creates a dictionary where each moment is mapped to a relaxation rate.

    Args:
        relaxation_rates: list of relaxation rates which should be used. This can also be a function which
                          takes a moment group in the list of nested moments and returns a list of relaxation rates.
                          This list has to have the length of the moment group and is then used for the moments
                          in the moment group.
        nested_moments: list of lists containing the moments.
        dim: dimension
    """
    result = OrderedDict()

    if callable(relaxation_rates):
        for group in nested_moments:
            rr = iter(relaxation_rates(group))
            for moment in group:
                result[moment] = next(rr)

        return result

    number_of_moments = 0
    shear_moments = 0
    bulk_moments = 0

    for group in nested_moments:
        for moment in group:
            number_of_moments += 1
            if is_shear_moment(moment, dim):
                shear_moments += 1
            if is_bulk_moment(moment, dim):
                bulk_moments += 1

    # if only one relaxation rate is specified it is used as the shear relaxation rate
    if len(relaxation_rates) == 1:
        for group in nested_moments:
            for moment in group:
                if get_order(moment) <= 1:
                    result[moment] = 0.0
                elif is_shear_moment(moment, dim):
                    result[moment] = relaxation_rates[0]
                else:
                    result[moment] = 1.0

    # if relaxation rate for each moment is specified they are all used
    if len(relaxation_rates) == number_of_moments:
        rr_iter = iter(relaxation_rates)
        for group in nested_moments:
            for moment in group:
                rr = next(rr_iter)
                result[moment] = rr

    # Fallback case, relaxes each group with the same relaxation rate and separates shear and bulk moments
    next_rr = True
    if len(relaxation_rates) != 1 and len(
            relaxation_rates) != number_of_moments:
        try:
            rr_iter = iter(relaxation_rates)
            if shear_moments > 0:
                shear_rr = next(rr_iter)
            if bulk_moments > 0:
                bulk_rr = next(rr_iter)
            for group in nested_moments:
                if next_rr:
                    rr = next(rr_iter)
                next_rr = False
                for moment in group:
                    if get_order(moment) <= 1:
                        result[moment] = 0.0
                    elif is_shear_moment(moment, dim):
                        result[moment] = shear_rr
                    elif is_bulk_moment(moment, dim):
                        result[moment] = bulk_rr
                    else:
                        next_rr = True
                        result[moment] = rr
        except StopIteration:
            raise ValueError(
                "Not enough relaxation rates are specified. You can either specify one relaxation rate, "
                "which is used as the shear relaxation rate. In this case, conserved moments are "
                "relaxed with 0, and higher-order moments are relaxed with 1. Another "
                "possibility is to specify a relaxation rate for shear, bulk and one for each order "
                "moment. In this case, conserved moments are also "
                "relaxed with 0. The last possibility is to specify a relaxation rate for each moment, "
                "including conserved moments")
    return result
Exemplo n.º 4
0
def create_centered_cumulant_model(
        stencil,
        cumulant_to_rr_dict,
        force_model=None,
        equilibrium_order=None,
        c_s_sq=sp.Rational(1, 3),
        galilean_correction=False,
        central_moment_transform_class=PdfsToCentralMomentsByShiftMatrix,
        cumulant_transform_class=CentralMomentsToCumulantsByGeneratingFunc):
    r"""Creates a cumulant lattice Boltzmann model.

    Args:
        stencil: instance of :class:`lbmpy.stencils.LBStencil`
        cumulant_to_rr_dict: dict that has as many entries as the stencil. Each cumulant, which can be
                             represented by an exponent tuple or in polynomial form is mapped to a relaxation rate.
                             See :func:`lbmpy.methods.default_moment_sets.cascaded_moment_sets_literature`
        force_model: force model used for the collision. For cumulant LB method a good choice is
                     `lbmpy.methods.centeredcumulant.CenteredCumulantForceModel`
        equilibrium_order: approximation order of macroscopic velocity :math:`\mathbf{u}` in the equilibrium
        c_s_sq: Speed of sound squared
        galilean_correction: special correction for D3Q27 cumulant collisions. See Appendix H in
                             :cite:`geier2015`. Implemented in :mod:`lbmpy.methods.centeredcumulant.galilean_correction`
        central_moment_transform_class: Class which defines the transformation to the central moment space
                                        (see :mod:`lbmpy.moment_transforms`)
        cumulant_transform_class: Class which defines the transformation from the central moment space to the
                                  cumulant space (see :mod:`lbmpy.methods.centeredcumulant.cumulant_transform`)

    Returns:
        :class:`lbmpy.methods.centeredcumulant.CenteredCumulantBasedLbMethod` instance
    """

    one = sp.Integer(1)

    assert len(cumulant_to_rr_dict) == stencil.Q, \
        "The number of moments has to be equal to the number of stencil entries"

    # CQC
    cqc = DensityVelocityComputation(stencil, True, force_model=force_model)
    density_symbol = cqc.zeroth_order_moment_symbol
    velocity_symbols = cqc.first_order_moment_symbols

    #   Equilibrium Values
    higher_order_polynomials = list(
        filter(lambda x: get_order(x) > 1, cumulant_to_rr_dict.keys()))

    #   Lower Order Equilibria
    cumulants_to_relaxation_info_dict = {
        one: RelaxationInfo(density_symbol, cumulant_to_rr_dict[one])
    }
    for d in MOMENT_SYMBOLS[:stencil.D]:
        cumulants_to_relaxation_info_dict[d] = RelaxationInfo(
            0, cumulant_to_rr_dict[d])

    #   Polynomial Cumulant Equilibria
    polynomial_equilibria = get_equilibrium_values_of_maxwell_boltzmann_function(
        higher_order_polynomials,
        stencil.D,
        rho=density_symbol,
        u=velocity_symbols,
        c_s_sq=c_s_sq,
        order=equilibrium_order,
        space="cumulant")
    polynomial_equilibria = [density_symbol * v for v in polynomial_equilibria]

    for i, c in enumerate(higher_order_polynomials):
        cumulants_to_relaxation_info_dict[c] = RelaxationInfo(
            polynomial_equilibria[i], cumulant_to_rr_dict[c])

    return CenteredCumulantBasedLbMethod(
        stencil,
        cumulants_to_relaxation_info_dict,
        cqc,
        force_model,
        galilean_correction=galilean_correction,
        central_moment_transform_class=central_moment_transform_class,
        cumulant_transform_class=cumulant_transform_class)
Exemplo n.º 5
0
def get_update_rules_velocity(src_field,
                              u_in,
                              lb_method,
                              force_model,
                              density,
                              sub_iterations=2):
    r"""
     Get assignments to update the velocity with a force shift
     Args:
         src_field: the source field of the hydrodynamic distribution function
         u_in: velocity field
         lb_method: mrt lattice boltzmann method used for hydrodynamics
         force_model: one of the phase_field force models which are applied in the collision space
         density: the interpolated density of the simulation
         sub_iterations: number of updates of the velocity field
     """
    stencil = lb_method.stencil

    rho = lb_method.conserved_quantity_computation.zeroth_order_moment_symbol
    u_symp = lb_method.conserved_quantity_computation.first_order_moment_symbols

    force = force_model._force
    force_symp = force_model.force_symp

    moment_matrix = lb_method.moment_matrix

    moments = lb_method.moments
    indices = list()
    for i in range(len(moments)):
        if get_order(moments[i]) == 1:
            indices.append(i)

    m0 = moment_matrix * sp.Matrix(src_field.center_vector)

    update_u = list()
    update_u.append(Assignment(rho, m0[0]))

    index = 0
    aleph = sp.symbols(f"aleph_:{stencil.D * sub_iterations}")

    for i in range(stencil.D):
        update_u.append(Assignment(aleph[i], u_in.center_vector[i]))
        index += 1

    for k in range(sub_iterations - 1):
        subs_dict = dict(zip(u_symp, aleph[k * stencil.D:index]))
        for i in range(stencil.D):
            update_u.append(
                Assignment(
                    aleph[index],
                    m0[indices[i]] + force[i].subs(subs_dict) / density / 2))
            index += 1

    subs_dict = dict(zip(u_symp, aleph[index - stencil.D:index]))

    for i in range(stencil.D):
        update_u.append(Assignment(force_symp[i], force[i].subs(subs_dict)))

    for i in range(stencil.D):
        update_u.append(
            Assignment(u_symp[i],
                       m0[indices[i]] + force_symp[i] / density / 2))

    return update_u
Exemplo n.º 6
0
    def _centered_cumulant_collision_rule(self,
                                          cumulant_to_relaxation_info_dict,
                                          conserved_quantity_equations=None,
                                          pre_simplification=False,
                                          include_force_terms=False,
                                          include_galilean_correction=True,
                                          symbolic_relaxation_rates=False):

        # Filter out JobLib warnings. They are not usefull for use:
        # https://github.com/joblib/joblib/issues/683
        filterwarnings("ignore", message="Persisting input arguments took")

        stencil = self.stencil
        f = self.pre_collision_pdf_symbols
        density = self.zeroth_order_equilibrium_moment_symbol
        velocity = self.first_order_equilibrium_moment_symbols
        cqe = conserved_quantity_equations

        relaxation_info_dict = dict()
        subexpressions_relaxation_rates = []
        if symbolic_relaxation_rates:
            subexpressions_relaxation_rates, sd = self._generate_symbolic_relaxation_matrix(
            )
            for i, cumulant in enumerate(cumulant_to_relaxation_info_dict):
                relaxation_info_dict[cumulant] = RelaxationInfo(
                    cumulant_to_relaxation_info_dict[cumulant][0], sd[i, i])
        else:
            relaxation_info_dict = cumulant_to_relaxation_info_dict

        if cqe is None:
            cqe = self._conserved_quantity_computation.equilibrium_input_equations_from_pdfs(
                f, False)

        forcing_subexpressions = AssignmentCollection([])
        if self._force_model is not None:
            forcing_subexpressions = AssignmentCollection(
                self._force_model.subs_dict_force)

        #   1) Extract Monomial Cumulants for the higher-order polynomials
        polynomial_cumulants = relaxation_info_dict.keys()
        polynomial_cumulants = sorted(list(polynomial_cumulants),
                                      key=moment_sort_key)
        higher_order_polynomials = [
            p for p in polynomial_cumulants if get_order(p) > 1
        ]
        monomial_cumulants = sorted(list(
            extract_monomials(higher_order_polynomials, dim=self.dim)),
                                    key=exponent_tuple_sort_key)

        #   2) Get Forward and Backward Transformations between central moment and cumulant space,
        #      and find required central moments
        k_to_c_transform = self._cumulant_transform_class(
            stencil, monomial_cumulants, density, velocity)
        k_to_c_eqs = cached_forward_transform(
            k_to_c_transform, simplification=pre_simplification)
        c_post_to_k_post_eqs = cached_backward_transform(
            k_to_c_transform,
            simplification=pre_simplification,
            omit_conserved_moments=True)
        central_moments = k_to_c_transform.required_central_moments
        assert len(
            central_moments
        ) == stencil.Q, 'Number of required central moments must match stencil size.'

        #   3) Get Forward Transformation from PDFs to central moments
        pdfs_to_k_transform = self._central_moment_transform_class(
            stencil,
            None,
            density,
            velocity,
            moment_exponents=central_moments,
            conserved_quantity_equations=cqe)
        pdfs_to_k_eqs = cached_forward_transform(
            pdfs_to_k_transform,
            f,
            simplification=pre_simplification,
            return_monomials=True)

        #   4) Add relaxation rules for lower order moments
        lower_order_moments = moments_up_to_order(1, dim=self.dim)
        lower_order_moment_symbols = [
            statistical_quantity_symbol(PRE_COLLISION_MONOMIAL_CENTRAL_MOMENT,
                                        exp) for exp in lower_order_moments
        ]

        lower_order_relaxation_infos = [
            relaxation_info_dict[exponent_to_polynomial_representation(e)]
            for e in lower_order_moments
        ]
        lower_order_relaxation_rates = [
            info.relaxation_rate for info in lower_order_relaxation_infos
        ]
        lower_order_equilibrium = [
            info.equilibrium_value for info in lower_order_relaxation_infos
        ]

        lower_order_moment_collision_eqs = relax_lower_order_central_moments(
            lower_order_moments, tuple(lower_order_moment_symbols),
            tuple(lower_order_relaxation_rates),
            tuple(lower_order_equilibrium))

        #   5) Add relaxation rules for higher-order, polynomial cumulants
        poly_relaxation_infos = [
            relaxation_info_dict[c] for c in higher_order_polynomials
        ]
        poly_relaxation_rates = [
            info.relaxation_rate for info in poly_relaxation_infos
        ]
        poly_equilibrium = [
            info.equilibrium_value for info in poly_relaxation_infos
        ]

        if self._galilean_correction and include_galilean_correction:
            galilean_correction_terms = get_galilean_correction_terms(
                relaxation_info_dict, density, velocity)
        else:
            galilean_correction_terms = None

        cumulant_collision_eqs = relax_polynomial_cumulants(
            tuple(monomial_cumulants),
            tuple(higher_order_polynomials),
            tuple(poly_relaxation_rates),
            tuple(poly_equilibrium),
            pre_simplification,
            galilean_correction_terms=galilean_correction_terms)

        #   6) Get backward transformation from central moments to PDFs
        d = self.post_collision_pdf_symbols
        k_post_to_pdfs_eqs = cached_backward_transform(
            pdfs_to_k_transform,
            d,
            simplification=pre_simplification,
            start_from_monomials=True)

        #   7) That's all. Now, put it all together.
        all_acs = [] if pdfs_to_k_transform.absorbs_conserved_quantity_equations else [
            cqe
        ]
        subexpressions_relaxation_rates = AssignmentCollection(
            subexpressions_relaxation_rates)
        all_acs += [
            subexpressions_relaxation_rates, forcing_subexpressions,
            pdfs_to_k_eqs, k_to_c_eqs, lower_order_moment_collision_eqs,
            cumulant_collision_eqs, c_post_to_k_post_eqs
        ]
        subexpressions = [ac.all_assignments for ac in all_acs]
        subexpressions += k_post_to_pdfs_eqs.subexpressions
        main_assignments = k_post_to_pdfs_eqs.main_assignments

        #   8) Maybe add forcing terms if CenteredCumulantForceModel was not used
        if self._force_model is not None and \
                not isinstance(self._force_model, CenteredCumulantForceModel) and include_force_terms:
            force_model_terms = self._force_model(self)
            force_term_symbols = sp.symbols(
                f"forceTerm_:{len(force_model_terms)}")
            force_subexpressions = [
                Assignment(sym,
                           force_model_term) for sym, force_model_term in zip(
                               force_term_symbols, force_model_terms)
            ]
            subexpressions += force_subexpressions
            main_assignments = [
                Assignment(eq.lhs, eq.rhs + force_term_symbol) for eq,
                force_term_symbol in zip(main_assignments, force_term_symbols)
            ]

        #   Aaaaaand we're done.
        return LbmCollisionRule(self, main_assignments, subexpressions)