Example #1
0
def create_lb_method_from_existing(method, modification_function):
    """Creates a new method based on an existing method by modifying its collision table.

    Args:
        method: old method
        modification_function: function receiving (moment, equilibrium_value, relaxation_rate) as arguments,
                               i.e. one row of the relaxation table, returning a modified version
    """
    compressible = method.conserved_quantity_computation.compressible
    if isinstance(method, CenteredCumulantBasedLbMethod):
        rr_dict = OrderedDict()
        relaxation_table = (modification_function(m, eq, rr)
                            for m, eq, rr in
                            zip(method.cumulants, method.cumulant_equilibrium_values, method.relaxation_rates))

        for cumulant, eq_value, rr in relaxation_table:
            cumulant = sp.sympify(cumulant)
            rr_dict[cumulant] = RelaxationInfo(eq_value, rr)

        return CenteredCumulantBasedLbMethod(method.stencil, rr_dict,
                                             method.conserved_quantity_computation,
                                             method.force_model,
                                             galilean_correction=method.galilean_correction,
                                             central_moment_transform_class=method.central_moment_transform_class,
                                             cumulant_transform_class=method.cumulant_transform_class)
    else:
        relaxation_table = (modification_function(m, eq, rr)
                            for m, eq, rr in
                            zip(method.moments, method.moment_equilibrium_values, method.relaxation_rates))
        return create_generic_mrt(method.stencil, relaxation_table, compressible, method.force_model)
Example #2
0
    def get_equilibrium(self, conserved_quantity_equations=None, subexpressions=False, pre_simplification=False,
                        keep_cqc_subexpressions=True, include_force_terms=False):
        """Returns equation collection, to compute equilibrium values.
        The equations have the post collision symbols as left hand sides and are
        functions of the conserved quantities

        Args:
            conserved_quantity_equations: equations to compute conserved quantities.
            subexpressions: if set to false all subexpressions of the equilibrium assignments are plugged
                            into the main assignments
            pre_simplification: with or without pre_simplifications for the calculation of the collision
            keep_cqc_subexpressions: if equilibrium is returned without subexpressions keep_cqc_subexpressions
                                     determines if also subexpressions to calculate conserved quantities should be
                                     plugged into the main assignments
        """
        r_info_dict = {c: RelaxationInfo(info.equilibrium_value, 1)
                       for c, info in self._moment_to_relaxation_info_dict.items()}
        ac = self._central_moment_collision_rule(r_info_dict, conserved_quantity_equations, pre_simplification,
                                                 include_force_terms=include_force_terms,
                                                 symbolic_relaxation_rates=False)
        if not subexpressions:
            if keep_cqc_subexpressions:
                bs = self._bound_symbols_cqc(conserved_quantity_equations)
                return ac.new_without_subexpressions(subexpressions_to_keep=bs)
            else:
                return ac.new_without_subexpressions()
        else:
            return ac
Example #3
0
 def set_first_moment_relaxation_rate(self, relaxation_rate):
     for e in MOMENT_SYMBOLS[:self.dim]:
         assert e in self._momentToRelaxationInfoDict, "First moments are not relaxed separately by this method"
     for e in MOMENT_SYMBOLS[:self.dim]:
         prev_entry = self._momentToRelaxationInfoDict[e]
         new_entry = RelaxationInfo(prev_entry[0], relaxation_rate)
         self._momentToRelaxationInfoDict[e] = new_entry
Example #4
0
 def set_first_moment_relaxation_rate(self, relaxation_rate):
     if self.force_model_rr_override:
         warn(
             "Overwriting first-order relaxation rates governed by CenteredCumulantForceModel "
             "might break your forcing scheme.")
     for e in MOMENT_SYMBOLS[:self.dim]:
         assert e in self._cumulant_to_relaxation_info_dict, \
             "First cumulants are not relaxed separately by this method"
     for e in MOMENT_SYMBOLS[:self.dim]:
         prev_entry = self._cumulant_to_relaxation_info_dict[e]
         new_entry = RelaxationInfo(prev_entry[0], relaxation_rate)
         self._cumulant_to_relaxation_info_dict[e] = new_entry
Example #5
0
def create_from_equilibrium(
        stencil,
        equilibrium,
        moment_to_relaxation_rate_dict,
        compressible=False,
        force_model=None,
        moment_transform_class=PdfsToMomentsByChimeraTransform):
    r"""
    Creates a moment-based LB method using a given equilibrium distribution function

    Args:
        stencil: instance of :class:`lbmpy.stencils.LBStencil`
        equilibrium: list of equilibrium terms, dependent on rho and u, one for each stencil direction
        moment_to_relaxation_rate_dict: relaxation rate for each moment, or a symbol/float if all should relaxed with
                                        the same rate
        compressible: see create_with_discrete_maxwellian_eq_moments
        force_model: see create_with_discrete_maxwellian_eq_moments
        moment_transform_class: class to define the transformation to the moment space
    """
    if any(
            isinstance(moment_to_relaxation_rate_dict, t)
            for t in (sp.Symbol, float, int)):
        moment_to_relaxation_rate_dict = {
            m: moment_to_relaxation_rate_dict
            for m in get_default_moment_set_for_stencil(stencil)
        }

    mom_to_rr_dict = OrderedDict(moment_to_relaxation_rate_dict)
    assert len(
        mom_to_rr_dict
    ) == stencil.Q, "The number of moments has to be equal to the number of stencil entries"
    density_velocity_computation = DensityVelocityComputation(
        stencil, compressible, force_model)

    rr_dict = OrderedDict([
        (mom,
         RelaxationInfo(
             discrete_moment(equilibrium, mom, stencil).expand(), rr))
        for mom, rr in zip(mom_to_rr_dict.keys(), mom_to_rr_dict.values())
    ])
    return MomentBasedLbMethod(stencil, rr_dict, density_velocity_computation,
                               force_model, moment_transform_class)
Example #6
0
def create_generic_mrt(stencil,
                       moment_eq_value_relaxation_rate_tuples,
                       compressible=False,
                       force_model=None,
                       moment_transform_class=PdfsToMomentsByChimeraTransform):
    r"""
    Creates a generic moment-based LB method.

    Args:
        stencil: instance of :class:`lbmpy.stencils.LBStencil`
        moment_eq_value_relaxation_rate_tuples: sequence of tuples containing (moment, equilibrium value, relax. rate)
        compressible: compressibility, determines calculation of velocity for force models
        force_model: see create_with_discrete_maxwellian_eq_moments
        moment_transform_class: class to define the transformation to the moment space
    """
    density_velocity_computation = DensityVelocityComputation(
        stencil, compressible, force_model)

    rr_dict = OrderedDict()
    for moment, eq_value, rr in moment_eq_value_relaxation_rate_tuples:
        moment = sp.sympify(moment)
        rr_dict[moment] = RelaxationInfo(eq_value, rr)
    return MomentBasedLbMethod(stencil, rr_dict, density_velocity_computation,
                               force_model, moment_transform_class)
Example #7
0
 def set_zeroth_moment_relaxation_rate(self, relaxation_rate):
     one = sp.Rational(1, 1)
     prev_entry = self._momentToRelaxationInfoDict[one]
     new_entry = RelaxationInfo(prev_entry[0], relaxation_rate)
     self._momentToRelaxationInfoDict[one] = new_entry
Example #8
0
 def set_zeroth_moment_relaxation_rate(self, relaxation_rate):
     e = sp.Rational(1, 1)
     prev_entry = self._moment_to_relaxation_info_dict[e]
     new_entry = RelaxationInfo(prev_entry[0], relaxation_rate)
     self._moment_to_relaxation_info_dict[e] = new_entry
Example #9
0
    def _central_moment_collision_rule(self, moment_to_relaxation_info_dict,
                                       conserved_quantity_equations=None,
                                       pre_simplification=False,
                                       include_force_terms=False,
                                       symbolic_relaxation_rates=False):
        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, moment in enumerate(moment_to_relaxation_info_dict):
                relaxation_info_dict[moment] = RelaxationInfo(moment_to_relaxation_info_dict[moment][0], sd[i, i])
        else:
            relaxation_info_dict = moment_to_relaxation_info_dict

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

        forcing_subexpressions = AssignmentCollection([])
        moment_space_forcing = False
        if self._force_model is not None:
            if include_force_terms:
                moment_space_forcing = self.force_model.has_central_moment_space_forcing
            forcing_subexpressions = AssignmentCollection(self._force_model.subs_dict_force)
        else:
            include_force_terms = False

        #   1) Get Forward Transformation from PDFs to central moments
        pdfs_to_c_transform = self.central_moment_transform_class(
            stencil, self.moments, density, velocity, conserved_quantity_equations=cqe)
        pdfs_to_c_eqs = pdfs_to_c_transform.forward_transform(f, simplification=pre_simplification)

        #   2) Collision
        k_pre = pdfs_to_c_transform.pre_collision_symbols
        k_post = pdfs_to_c_transform.post_collision_symbols

        relaxation_infos = [relaxation_info_dict[m] for m in self.moments]
        relaxation_rates = [info.relaxation_rate for info in relaxation_infos]
        equilibrium_value = [info.equilibrium_value for info in relaxation_infos]

        if moment_space_forcing:
            force_model_terms = self._force_model.central_moment_space_forcing(self)
        else:
            force_model_terms = sp.Matrix([0] * stencil.Q)

        collision_eqs = relax_central_moments(k_pre, k_post, tuple(relaxation_rates),
                                              tuple(equilibrium_value), force_terms=force_model_terms)

        #   3) Get backward transformation from central moments to PDFs
        post_collision_values = self.post_collision_pdf_symbols
        c_post_to_pdfs_eqs = pdfs_to_c_transform.backward_transform(post_collision_values,
                                                                    simplification=pre_simplification)

        #   4) Now, put it all together.
        all_acs = [] if pdfs_to_c_transform.absorbs_conserved_quantity_equations else [cqe]
        subexpressions_relaxation_rates = AssignmentCollection(subexpressions_relaxation_rates)
        all_acs += [subexpressions_relaxation_rates, forcing_subexpressions, pdfs_to_c_eqs, collision_eqs]
        subexpressions = [ac.all_assignments for ac in all_acs]
        subexpressions += c_post_to_pdfs_eqs.subexpressions
        main_assignments = c_post_to_pdfs_eqs.main_assignments

        #   5) Maybe add forcing terms.
        if include_force_terms and not moment_space_forcing:
            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)]

        return LbmCollisionRule(self, main_assignments, subexpressions)
Example #10
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)
Example #11
0
def create_with_discrete_maxwellian_eq_moments(
        stencil,
        moment_to_relaxation_rate_dict,
        compressible=False,
        force_model=None,
        equilibrium_order=2,
        c_s_sq=sp.Rational(1, 3),
        central_moment_space=False,
        moment_transform_class=None,
        central_moment_transform_class=PdfsToCentralMomentsByShiftMatrix):
    r"""Creates a moment-based LBM by taking a list of moments with corresponding relaxation rate.

    These moments are relaxed against the moments of the discrete Maxwellian distribution.

    Args:
        stencil: instance of :class:`lbmpy.stencils.LBStenil`
        moment_to_relaxation_rate_dict: dict that has as many entries as the stencil. Each moment, which can be
                                        represented by an exponent tuple or in polynomial form
                                        (see `lbmpy.moments`), is mapped to a relaxation rate.
        compressible: incompressible LBM methods split the density into :math:`\rho = \rho_0 + \Delta \rho`
                      where :math:`\rho_0` is chosen as one, and the first moment of the pdfs is :math:`\Delta \rho` .
                      This approximates the incompressible Navier-Stokes equations better than the standard
                      compressible model.
        force_model: force model instance, or None if no external forces
        equilibrium_order: approximation order of macroscopic velocity :math:`\mathbf{u}` in the equilibrium
        c_s_sq: Speed of sound squared
        central_moment_space: If set to True, an instance of 
                              :class:`lbmpy.methods.momentbased.CentralMomentBasedLbMethod` is returned, 
                              and the the collision will be performed in the central moment space.
        moment_transform_class: Class implementing the transform from populations to moment space.
        central_moment_transform_class: Class implementing the transform from populations to central moment space.

    Returns:
        Instance of either :class:`lbmpy.methods.momentbased.MomentBasedLbMethod` or 
        :class:`lbmpy.methods.momentbased.CentralMomentBasedLbMethod` 
    """
    mom_to_rr_dict = OrderedDict(moment_to_relaxation_rate_dict)
    assert len(mom_to_rr_dict) == stencil.Q, \
        "The number of moments has to be the same as the number of stencil entries"

    density_velocity_computation = DensityVelocityComputation(
        stencil, compressible, force_model)

    moments = tuple(mom_to_rr_dict.keys())
    eq_values = get_moments_of_discrete_maxwellian_equilibrium(
        stencil,
        moments,
        c_s_sq=c_s_sq,
        compressible=compressible,
        order=equilibrium_order)
    if central_moment_space:
        N = set_up_shift_matrix(moments, stencil)
        eq_values = sp.simplify(N * sp.Matrix(eq_values))

    rr_dict = OrderedDict([
        (mom, RelaxationInfo(eq_mom, rr)) for mom, rr, eq_mom in zip(
            mom_to_rr_dict.keys(), mom_to_rr_dict.values(), eq_values)
    ])

    if central_moment_space:
        return CentralMomentBasedLbMethod(stencil, rr_dict,
                                          density_velocity_computation,
                                          force_model,
                                          central_moment_transform_class)
    else:
        return MomentBasedLbMethod(stencil, rr_dict,
                                   density_velocity_computation, force_model,
                                   moment_transform_class)
Example #12
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)