示例#1
0
 def __init__(self, resolution, reynolds_number, mach_number, lattice, initialize_with_zeros=True):
     self.resolution = resolution
     self.lattice = lattice
     self.units = UnitConversion(
         lattice,
         reynolds_number=reynolds_number, mach_number=mach_number,
         characteristic_length_lu=resolution, characteristic_length_pu=1,
         characteristic_velocity_pu=1
     )
     self.initialize_with_zeros = initialize_with_zeros
示例#2
0
 def __init__(self, resolution, reynolds_number, mach_number, lattice, k0=20, ic_energy=0.5):
     self.k0 = k0
     self.ic_energy = ic_energy
     self.resolution = resolution
     self.units = UnitConversion(
         lattice,
         reynolds_number=reynolds_number, mach_number=mach_number,
         characteristic_length_lu=resolution, characteristic_length_pu=2 * np.pi,
         characteristic_velocity_pu=None
     )
     self.wavenumbers = []
     self.spectrum = []
示例#3
0
 def __init__(self, resolution, reynolds_number, mach_number, lattice):
     self.resolution = resolution
     self.units = UnitConversion(lattice,
                                 reynolds_number=reynolds_number,
                                 mach_number=mach_number,
                                 characteristic_length_lu=resolution,
                                 characteristic_length_pu=2 * np.pi,
                                 characteristic_velocity_pu=1)
示例#4
0
 def __init__(self, resolution, reynolds_number, mach_number, lattice, shear_layer_width=80,
              initial_perturbation_magnitude=0.05):
     self.initial_perturbation_magnitude = initial_perturbation_magnitude
     self.shear_layer_width = shear_layer_width
     self.resolution = resolution
     self.units = UnitConversion(
         lattice,
         reynolds_number=reynolds_number, mach_number=mach_number,
         characteristic_length_lu=resolution, characteristic_length_pu=1,
         characteristic_velocity_pu=1
     )
示例#5
0
文件: obstacle.py 项目: McBs/lettuce
 def __init__(self, resolution_x, resolution_y, reynolds_number,
              mach_number, lattice, char_length_lu):
     self.resolution_x = resolution_x
     self.resolution_y = resolution_y
     self.units = UnitConversion(lattice,
                                 reynolds_number=reynolds_number,
                                 mach_number=mach_number,
                                 characteristic_length_lu=char_length_lu,
                                 characteristic_length_pu=1,
                                 characteristic_velocity_pu=1)
     self._mask = np.zeros(shape=(self.resolution_x, self.resolution_y),
                           dtype=np.bool)
示例#6
0
 def __init__(self,
              shape,
              reynolds_number,
              mach_number,
              lattice,
              domain_length_x,
              char_length=1,
              char_velocity=1):
     if len(shape) != lattice.D:
         raise ValueError(
             f"{lattice.D}-dimensional lattice requires {lattice.D}-dimensional `shape`"
         )
     self.shape = shape
     char_length_lu = shape[0] / domain_length_x * char_length
     self.units = UnitConversion(lattice,
                                 reynolds_number=reynolds_number,
                                 mach_number=mach_number,
                                 characteristic_length_lu=char_length_lu,
                                 characteristic_length_pu=char_length,
                                 characteristic_velocity_pu=char_velocity)
     self._mask = np.zeros(shape=self.shape, dtype=np.bool)
示例#7
0
class PoiseuilleFlow2D(object):
    def __init__(self, resolution, reynolds_number, mach_number, lattice, initialize_with_zeros=True):
        self.resolution = resolution
        self.lattice = lattice
        self.units = UnitConversion(
            lattice,
            reynolds_number=reynolds_number, mach_number=mach_number,
            characteristic_length_lu=resolution, characteristic_length_pu=1,
            characteristic_velocity_pu=1
        )
        self.initialize_with_zeros = initialize_with_zeros

    def analytic_solution(self, grid):
        half_lattice_spacing = 0.5 / self.resolution
        x, y = grid
        nu = self.units.viscosity_pu
        rho = 1
        u = np.array([
            self.acceleration[0] / (2 * rho * nu) * ((y - half_lattice_spacing) * (1 - half_lattice_spacing - y)),
            np.zeros(x.shape)
        ])
        p = np.array([y * 0 + self.units.convert_density_lu_to_pressure_pu(rho)])
        return p, u

    def initial_solution(self, grid):
        if self.initialize_with_zeros:
            p = np.array([0 * grid[0]], dtype=float)
            u = np.array([0 * grid[0], 0 * grid[1]], dtype=float)
            return p, u
        else:
            return self.analytic_solution(grid)

    @property
    def grid(self):
        x = np.linspace(0, 1, num=self.resolution + 1, endpoint=True)
        y = np.linspace(0, 1, num=self.resolution + 1, endpoint=True)
        return np.meshgrid(x, y, indexing='ij')

    @property
    def boundaries(self):
        mask = np.zeros(self.grid[0].shape, dtype=bool)
        mask[:, [0, -1]] = True
        boundary = BounceBackBoundary(mask=mask, lattice=self.units.lattice)
        return [boundary]

    @property
    def acceleration(self):
        return np.array([0.001, 0])
示例#8
0
class DecayingTurbulence_validation:
    def __init__(self,
                 resolution,
                 reynolds_number,
                 mach_number,
                 lattice,
                 k0=20,
                 ic_energy=0.5,
                 case=None):
        from lettuce.unit import UnitConversion
        self.k0 = k0
        self.ic_energy = ic_energy
        self.resolution = resolution
        self.units = UnitConversion(lattice,
                                    reynolds_number=reynolds_number,
                                    mach_number=mach_number,
                                    characteristic_length_lu=resolution,
                                    characteristic_length_pu=2 * np.pi,
                                    characteristic_velocity_pu=None)
        self.case = case
        self.dimensions = self.grid[0].shape
示例#9
0
class Obstacle:
    """
    Flow class to simulate the flow around an object (mask).
    It consists of one inflow (equilibrium boundary)
    and one outflow (anti-bounce-back-boundary), leading to a flow in positive x direction.

    Parameters
    ----------
    shape : Tuple[int]:
        Grid resolution.
    domain_length_x : float
        Length of the domain in physical units.

    Attributes
    ----------
    mask : np.array with dtype = np.bool
        Boolean mask to define the obstacle. The shape of this object is the shape of the grid.
        Initially set to zero (no obstacle).

    Examples
    --------
    Initialization of flow around a cylinder:

    >>> from lettuce import Lattice, D2Q9
    >>> flow = Obstacle(
    >>>     shape=(101, 51),
    >>>     reynolds_number=100,
    >>>     mach_number=0.1,
    >>>     lattice=lattice,
    >>>     domain_length_x=10.1
    >>> )
    >>> x, y = flow.grid
    >>> condition = np.sqrt((x-2.5)**2+(y-2.5)**2) < 1.
    >>> flow.mask[np.where(condition)] = 1
   """
    def __init__(self,
                 shape,
                 reynolds_number,
                 mach_number,
                 lattice,
                 domain_length_x,
                 char_length=1,
                 char_velocity=1):
        if len(shape) != lattice.D:
            raise ValueError(
                f"{lattice.D}-dimensional lattice requires {lattice.D}-dimensional `shape`"
            )
        self.shape = shape
        char_length_lu = shape[0] / domain_length_x * char_length
        self.units = UnitConversion(lattice,
                                    reynolds_number=reynolds_number,
                                    mach_number=mach_number,
                                    characteristic_length_lu=char_length_lu,
                                    characteristic_length_pu=char_length,
                                    characteristic_velocity_pu=char_velocity)
        self._mask = np.zeros(shape=self.shape, dtype=np.bool)

    @property
    def mask(self):
        return self._mask

    @mask.setter
    def mask(self, m):
        assert isinstance(m, np.ndarray) and m.shape == self.shape
        self._mask = m.astype(np.bool)

    def initial_solution(self, x):
        p = np.zeros_like(x[0], dtype=float)[None, ...]
        u_char = self.units.characteristic_velocity_pu * self._unit_vector()
        u_char = append_axes(u_char, self.units.lattice.D)
        u = (1 - self.mask) * u_char
        return p, u

    @property
    def grid(self):
        xyz = tuple(
            self.units.convert_length_to_pu(np.arange(n)) for n in self.shape)
        return np.meshgrid(*xyz, indexing='ij')

    @property
    def boundaries(self):
        x = self.grid[0]
        return [
            EquilibriumBoundaryPU(
                np.abs(x) < 1e-6, self.units.lattice, self.units,
                self.units.characteristic_velocity_pu * self._unit_vector()),
            AntiBounceBackOutlet(self.units.lattice,
                                 self._unit_vector().tolist()),
            BounceBackBoundary(self.mask, self.units.lattice)
        ]

    def _unit_vector(self, i=0):
        return np.eye(self.units.lattice.D)[i]
示例#10
0
class DecayingTurbulence:

    def __init__(self, resolution, reynolds_number, mach_number, lattice, k0=20, ic_energy=0.5):
        self.k0 = k0
        self.ic_energy = ic_energy
        self.resolution = resolution
        self.units = UnitConversion(
            lattice,
            reynolds_number=reynolds_number, mach_number=mach_number,
            characteristic_length_lu=resolution, characteristic_length_pu=2 * np.pi,
            characteristic_velocity_pu=None
        )
        self.wavenumbers = []
        self.spectrum = []

    def analytic_solution(self, x, t=0):
        return

    def _generate_wavenumbers(self):
        self.dimensions = self.grid[0].shape
        frequencies = [np.fft.fftfreq(dim, d=1 / dim) for dim in self.dimensions]
        wavenumber = np.meshgrid(*frequencies)
        wavenorms = np.linalg.norm(wavenumber, axis=0)
        self.wavenumbers = np.arange(int(np.max(wavenorms)))
        wavemask = (wavenorms[..., None] > self.wavenumbers - 0.5) & (wavenorms[..., None] <= self.wavenumbers + 0.5)
        return wavenorms, wavenumber, wavemask

    def _generate_spectrum(self):
        wavenorms, wavenumber, wavemask = self._generate_wavenumbers()
        ek = (wavenorms) ** 4 * np.exp(-2 * (wavenorms / self.k0) ** 2)
        ek /= np.sum(ek)
        ek *= self.ic_energy
        self.spectrum = ek[..., None] * wavemask
        self.spectrum = np.sum(self.spectrum, axis=tuple((np.arange(self.units.lattice.D))))
        return ek, wavenumber

    def _generate_initial_velocity(self, ek, wavenumber):
        dx = self.units.convert_length_to_pu(1.0)
        u = np.random.random(np.array(wavenumber).shape) * 2 * np.pi + 0j
        u = [np.fft.fftn(u[dim], axes=tuple((np.arange(self.units.lattice.D)))) for dim in range(self.units.lattice.D)]

        u_real = [u[dim].real for dim in range(self.units.lattice.D)]
        u_imag = [u[dim].imag for dim in range(self.units.lattice.D)]
        for dim in range(self.units.lattice.D):
            u_real[dim].ravel()[0] = 0
            u_imag[dim].ravel()[0] = 0

        u_real_h = [np.sqrt(2 / self.units.lattice.D * ek / (u_imag[dim] ** 2 + u_real[dim] ** 2 + 1.e-15))
                    * u_real[dim] for dim in range(self.units.lattice.D)]
        u_imag_h = [np.sqrt(2 / self.units.lattice.D * ek / (u_imag[dim] ** 2 + u_real[dim] ** 2 + 1.e-15))
                    * u_imag[dim] for dim in range(self.units.lattice.D)]
        for dim in range(self.units.lattice.D):
            u_real_h[dim].ravel()[0] = 0
            u_imag_h[dim].ravel()[0] = 0

        ### Remove divergence
        # modified wave number sin(k*dx) is used, as the gradient below uses second order cental differences
        # Modify if other schemes are used or use kx, ky if you don't know the modified wavenumber !!!
        wavenumber_modified = [np.sin(wavenumber[dim] * dx) / dx for dim in range(self.units.lattice.D)]
        wavenorm_modified = np.linalg.norm(wavenumber_modified, axis=0) + 1e-16

        divergence_real = np.zeros(self.dimensions)
        divergence_imag = np.zeros(self.dimensions)
        for dim in range(self.units.lattice.D):
            divergence_real += wavenumber_modified[dim] * u_real_h[dim]
            divergence_imag += wavenumber_modified[dim] * u_imag_h[dim]

        u_real = [u_real_h[dim] - divergence_real * wavenumber_modified[dim]
                  / wavenorm_modified ** 2 for dim in range(self.units.lattice.D)]
        u_imag = [u_imag_h[dim] - divergence_imag * wavenumber_modified[dim]
                  / wavenorm_modified ** 2 for dim in range(self.units.lattice.D)]
        for dim in range(self.units.lattice.D):
            u_real[dim].ravel()[0] = 0
            u_imag[dim].ravel()[0] = 0

        ### Scale velocity field to achieve the desired inicial energy
        e_kin = [np.sum(u_real[dim] ** 2 + u_imag[dim] ** 2) for dim in range(self.units.lattice.D)]
        e_kin = np.sum(e_kin) * .5

        factor = np.sqrt(self.ic_energy / e_kin)
        u_real = [u_real[dim] * factor for dim in range(self.units.lattice.D)]
        u_imag = [u_imag[dim] * factor for dim in range(self.units.lattice.D)]

        ### Backtransformation to physical space
        norm = ((self.resolution * dx ** (1 - self.units.lattice.D) * np.sqrt(self.units.characteristic_length_pu))
                if self.units.lattice.D == 3 else (self.resolution / dx))

        u = np.asarray([
            (np.fft.ifftn(u_real[dim] + u_imag[dim] * 1.0j, axes=tuple((np.arange(self.units.lattice.D)))) * norm).real
            for dim in range(self.units.lattice.D)])

        return u

    def _compute_initial_pressure(self):
        return np.zeros(self.dimensions)[None, ...]

    def initial_solution(self, x):
        """Return initial solution. Note: this function sets the characteristic velocity in phyiscal units."""
        ek, wavenumber = self._generate_spectrum()
        u = self._generate_initial_velocity(ek, wavenumber)
        p = self._compute_initial_pressure()
        self.units.characteristic_velocity_pu = np.linalg.norm(u, axis=0).max()
        return p, u

    @property
    def energy_spectrum(self):
        return self.spectrum, self.wavenumbers

    @property
    def grid(self):
        grid = [np.linspace(0, 2 * np.pi, num=self.resolution, endpoint=False) for _ in range(self.units.lattice.D)]
        return np.meshgrid(*grid)

    @property
    def boundaries(self):
        return []