{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# The conservative Allen-Cahn model for high Reynolds number, two phase flow with large-density and viscosity constrast" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from pystencils.session import *\n", "from lbmpy.session import *\n", "\n", "from pystencils.boundaries import BoundaryHandling\n", "\n", "from lbmpy.phasefield_allen_cahn.contact_angle import ContactAngle\n", "from lbmpy.phasefield_allen_cahn.kernel_equations import *\n", "from lbmpy.phasefield_allen_cahn.parameter_calculation import calculate_parameters_rti, AllenCahnParameters\n", "from lbmpy.advanced_streaming import LBMPeriodicityHandling\n", "from lbmpy.boundaries import NoSlip, LatticeBoltzmannBoundaryHandling" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If `cupy` is installed the simulation automatically runs on GPU" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "try:\n", " import cupy\n", "except ImportError:\n", " cupy = None\n", " gpu = False\n", " target = ps.Target.CPU\n", " print('No cupy installed')\n", "\n", "if cupy:\n", " gpu = True\n", " target = ps.Target.GPU" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The conservative Allen-Cahn model (CACM) for two-phase flow is based on the work of Fakhari et al. (2017) [Improved locality of the phase-field lattice-Boltzmann model for immiscible fluids at high density ratios](http://dx.doi.org/10.1103/PhysRevE.96.053301). The model can be created for two-dimensional problems as well as three-dimensional problems, which have been described by Mitchell et al. (2018) [Development of a three-dimensional\n", "phase-field lattice Boltzmann method for the study of immiscible fluids at high density ratios](http://dx.doi.org/10.1103/PhysRevE.96.053301). Furthermore, cascaded lattice Boltzmann methods can be combined with the model which was described in [A cascaded phase-field lattice Boltzmann model for the simulation of incompressible, immiscible fluids with high density contrast](http://dx.doi.org/10.1016/j.camwa.2019.08.018)\n", "\n", "\n", "The CACM is suitable for simulating highly complex two phase flow problems with high-density ratios and high Reynolds numbers. In this tutorial, an overview is provided on how to derive the model with lbmpy. For this, the model is defined with two LBM populations. One for the interface tracking, which we call the phase-field LB step and one for recovering the hydrodynamic properties. The latter is called the hydrodynamic LB step." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Geometry Setup\n", "\n", "First of all, the stencils for the phase-field LB step as well as the stencil for the hydrodynamic LB step are defined. According to the stencils, the simulation can be performed in either 2D- or 3D-space. For 2D simulations, only the D2Q9 stencil is supported. For 3D simulations, the D3Q15, D3Q19 and the D3Q27 stencil are supported. Note here that the cascaded LBM can not be derived for D3Q15 stencils." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "stencil_phase = LBStencil(Stencil.D2Q9)\n", "stencil_hydro = LBStencil(Stencil.D2Q9)\n", "assert(len(stencil_phase[0]) == len(stencil_hydro[0]))\n", "\n", "dimensions = len(stencil_phase[0])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Definition of the domain size" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "# domain \n", "L0 = 256\n", "domain_size = (L0, 4 * L0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Parameter definition\n", "\n", "The next step is to calculate all parameters which are needed for the simulation. In this example, a Rayleigh-Taylor instability test case is set up. The parameter calculation for this setup is already implemented in lbmpy and can be used with the dimensionless parameters which describe the problem." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "# time step\n", "timesteps = 8000\n", "\n", "# reference time\n", "reference_time = 4000\n", "\n", "# calculate the parameters for the RTI\n", "parameters = calculate_parameters_rti(reference_length=L0,\n", " reference_time=reference_time,\n", " density_heavy=1.0,\n", " capillary_number=0.44,\n", " reynolds_number=3000,\n", " atwood_number=0.998,\n", " peclet_number=1000,\n", " density_ratio=1000,\n", " viscosity_ratio=100)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This function returns a `AllenCahnParameters` class. It is struct like class holding all parameters for the conservative Allen Cahn model:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", "\n", "
NameSymPy Symbol Value
Density heavy phase$\\rho_{H}$$1.0$
Density light phase$\\rho_{L}$$0.001$
Relaxation time heavy phase$\\tau_{H}$$0.0164004086170318$
Relaxation time light phase$\\tau_{L}$$0.164004086170318$
Relaxation rate Allen Cahn LB$\\omega_{\\phi}$$1.82082623441035$
Gravitational acceleration$F_{g}$$-1.60320641282565 \\cdot 10^{-5}$
Interface thickness$W$$5$
Mobility$M_{m}$$0.0164004086170318$
Surface tension$\\sigma$$0.000795967692961681$
\n", " " ], "text/plain": [ "" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "parameters" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Fields\n", "\n", "As a next step all fields which are needed get defined. To do so, we create a `datahandling` object. More details about it can be found in the third tutorial of the [pystencils framework]( http://pycodegen.pages.walberla.net/pystencils/). This object holds all fields and manages the kernel runs." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "# create a datahandling object\n", "dh = ps.create_data_handling((domain_size), periodicity=(True, False), parallel=False, default_target=target)\n", "\n", "# pdf fields. g is used for hydrodynamics and h for the interface tracking \n", "g = dh.add_array(\"g\", values_per_cell=len(stencil_hydro))\n", "dh.fill(\"g\", 0.0, ghost_layers=True)\n", "h = dh.add_array(\"h\",values_per_cell=len(stencil_phase))\n", "dh.fill(\"h\", 0.0, ghost_layers=True)\n", "\n", "g_tmp = dh.add_array(\"g_tmp\", values_per_cell=len(stencil_hydro))\n", "dh.fill(\"g_tmp\", 0.0, ghost_layers=True)\n", "h_tmp = dh.add_array(\"h_tmp\",values_per_cell=len(stencil_phase))\n", "dh.fill(\"h_tmp\", 0.0, ghost_layers=True)\n", "\n", "# velocity field\n", "u = dh.add_array(\"u\", values_per_cell=dh.dim)\n", "dh.fill(\"u\", 0.0, ghost_layers=True)\n", "\n", "# phase-field\n", "C = dh.add_array(\"C\")\n", "dh.fill(\"C\", 0.0, ghost_layers=True)\n", "C_tmp = dh.add_array(\"C_tmp\")\n", "dh.fill(\"C_tmp\", 0.0, ghost_layers=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As a next step the relaxation time is stated in a symbolic form. It is calculated via interpolation." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "rho_L = parameters.symbolic_density_light\n", "rho_H = parameters.symbolic_density_heavy\n", "density = rho_L + C.center * (rho_H - rho_L)\n", "\n", "body_force = [0, 0, 0]\n", "body_force[1] = parameters.symbolic_gravitational_acceleration * density" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Definition of the lattice Boltzmann methods" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For both LB steps, a weighted orthogonal MRT (WMRT) method is used. It is also possible to change the method to a simpler SRT scheme or a more complicated CLBM scheme. The CLBM scheme can be obtained with `Method.CENTRAL_MOMENT`. Note here that the hydrodynamic LB step is formulated as an incompressible velocity-based LBM. Thus, the velocity terms can not be removed from the equilibrium in the central moment space." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
\n", " Moment-Based Method\n", " Stencil: D2Q9Zero-Centered Storage: ✓Force Model: Guo
\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
\n", " Continuous Hydrodynamic Maxwellian Equilibrium\n", " \n", " $f (\\rho, \\left( u_{0}, \\ u_{1}\\right), \\left( v_{0}, \\ v_{1}\\right)) \n", " = \\frac{3 \\rho e^{- \\frac{3 \\left(- u_{0} + v_{0}\\right)^{2}}{2} - \\frac{3 \\left(- u_{1} + v_{1}\\right)^{2}}{2}}}{2 \\pi}$\n", "
Compressible: ✓Deviation Only: ✗Order: 2
\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", "
Relaxation Info
MomentEq. Value Relaxation Rate
$1$$\\rho$$0$
$x$$\\rho u_{0}$$\\omega_{\\phi}$
$y$$\\rho u_{1}$$\\omega_{\\phi}$
$x^{2} - y^{2}$$\\rho u_{0}^{2} - \\rho u_{1}^{2}$$1$
$x y$$\\rho u_{0} u_{1}$$1$
$3 x^{2} + 3 y^{2} - 2$$3 \\rho u_{0}^{2} + 3 \\rho u_{1}^{2}$$1$
$3 x^{2} y - y$$0$$1$
$3 x y^{2} - x$$0$$1$
$9 x^{2} y^{2} - 3 x^{2} - 3 y^{2} + 1$$0$$1$
" ], "text/plain": [ "" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "w_c = parameters.symbolic_omega_phi\n", "\n", "config_phase = LBMConfig(stencil=stencil_phase, method=Method.MRT, compressible=True,\n", " delta_equilibrium=False,\n", " force=sp.symbols(\"F_:2\"), velocity_input=u,\n", " weighted=True, relaxation_rates=[0, w_c, w_c, 1, 1, 1, 1, 1, 1],\n", " output={'density': C_tmp})\n", "\n", "method_phase = create_lb_method(lbm_config=config_phase)\n", "\n", "method_phase" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
\n", " Moment-Based Method\n", " Stencil: D2Q9Zero-Centered Storage: ✓Force Model: Guo
\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
\n", " Continuous Hydrodynamic Maxwellian Equilibrium\n", " \n", " $f (\\rho, \\left( u_{0}, \\ u_{1}\\right), \\left( v_{0}, \\ v_{1}\\right)) \n", " = \\frac{3 \\delta_{\\rho} e^{- \\frac{3 v_{0}^{2}}{2} - \\frac{3 v_{1}^{2}}{2}}}{2 \\pi} - \\frac{3 e^{- \\frac{3 v_{0}^{2}}{2} - \\frac{3 v_{1}^{2}}{2}}}{2 \\pi} + \\frac{3 e^{- \\frac{3 \\left(- u_{0} + v_{0}\\right)^{2}}{2} - \\frac{3 \\left(- u_{1} + v_{1}\\right)^{2}}{2}}}{2 \\pi}$\n", "
Compressible: ✗Deviation Only: ✓Order: 2
\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", "
Relaxation Info
MomentEq. Value Relaxation Rate
$1$$\\delta_{\\rho}$$0.0$
$x$$u_{0}$$0.0$
$y$$u_{1}$$0.0$
$x^{2} - y^{2}$$u_{0}^{2} - u_{1}^{2}$$\\frac{2}{2 {C}_{(0,0)} \\left(\\tau_{H} - \\tau_{L}\\right) + 2 \\tau_{L} + 1}$
$x y$$u_{0} u_{1}$$\\frac{2}{2 {C}_{(0,0)} \\left(\\tau_{H} - \\tau_{L}\\right) + 2 \\tau_{L} + 1}$
$3 x^{2} + 3 y^{2} - 2$$3 u_{0}^{2} + 3 u_{1}^{2}$$1$
$3 x^{2} y - y$$0$$1$
$3 x y^{2} - x$$0$$1$
$9 x^{2} y^{2} - 3 x^{2} - 3 y^{2} + 1$$0$$1$
" ], "text/plain": [ "" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "omega = parameters.omega(C)\n", "config_hydro = LBMConfig(stencil=stencil_hydro, method=Method.MRT, compressible=False,\n", " weighted=True, relaxation_rates=[omega, 1, 1, 1],\n", " force=sp.symbols(\"F_:2\"), output={'velocity': u})\n", "\n", "method_hydro = create_lb_method(lbm_config=config_hydro)\n", "\n", "method_hydro" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Initialization" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The probability distribution functions (pdfs) are initialised with the equilibrium distribution for the LB methods." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "h_updates = initializer_kernel_phase_field_lb(method_phase, C, u, h, parameters)\n", "g_updates = initializer_kernel_hydro_lb(method_hydro, 1, u, g)\n", "\n", "h_init = ps.create_kernel(h_updates, target=dh.default_target, cpu_openmp=True).compile()\n", "g_init = ps.create_kernel(g_updates, target=dh.default_target, cpu_openmp=True).compile()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Following this, the phase field is initialised directly in python." ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [], "source": [ "# initialize the domain\n", "def Initialize_distributions():\n", " Nx = domain_size[0]\n", " Ny = domain_size[1]\n", " \n", " for block in dh.iterate(ghost_layers=True, inner_ghost_layers=False):\n", " x = np.zeros_like(block.midpoint_arrays[0])\n", " x[:, :] = block.midpoint_arrays[0]\n", " \n", " y = np.zeros_like(block.midpoint_arrays[1])\n", " y[:, :] = block.midpoint_arrays[1]\n", "\n", " y -= 2 * L0\n", " tmp = 0.1 * Nx * np.cos((2 * np.pi * x) / Nx)\n", " init_values = 0.5 + 0.5 * np.tanh((y - tmp) / (parameters.interface_thickness / 2))\n", " block[\"C\"][:, :] = init_values\n", " block[\"C_tmp\"][:, :] = init_values\n", " \n", " if gpu:\n", " dh.all_to_gpu() \n", " \n", " dh.run_kernel(h_init, **parameters.symbolic_to_numeric_map)\n", " dh.run_kernel(g_init)" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAA64AAAFlCAYAAADrtrUsAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/NK7nSAAAACXBIWXMAAAsTAAALEwEAmpwYAAAbkUlEQVR4nO3df7DddX3n8df75ibhl5IAMQLBBiVV6Q+pjZSq46i0CnSn0K51dXaUseyws6Pd7tqZLd3dGXfa3f7Y6dbWbtcdtlhwp611aa2MtVqKWmstSLQUREQigiRCEkISfuTnveezf9xv7BUJkNybez+59/GYuXO/53O+55zPzXzm3vvM93u+t1prAQAAgF6NzfcEAAAA4OkIVwAAALomXAEAAOiacAUAAKBrwhUAAICuCVcAAAC6Nj7fE3g6p512Wlu7du18TwOAheLAl+d7BgvD0u+f7xkAsEB88YtffLi1tuqZ9us6XNeuXZsNGzbM9zQAWCBGD62b7yksCGPP97MZgNlRVfc/m/2cKgwAAEDXhCsAAABde8ZwraoPVNXWqvrytLFTqurGqrpn+LxyGK+qel9Vbayq26vq5dMec/mw/z1VdfnR+XIAAABYaJ7NEddrk1z0pLGrktzUWluX5KbhdpJcnGTd8HFlkvcnU6Gb5D1JfiTJ+UneczB2AQAA4Ok8Y7i21j6b5JEnDV+a5Lph+7okl00b/2CbcnOSFVV1epI3JrmxtfZIa21Hkhvz3TEMAAAA3+VI3+O6urX24LD9UJLVw/aZSR6Ytt+mYexQ49+lqq6sqg1VtWHbtm1HOD0AAAAWihlfnKm11pK0WZjLwee7urW2vrW2ftWqZ/xzPgAAACxwRxquW4ZTgDN83jqMb05y1rT91gxjhxoHAACAp3Wk4XpDkoNXBr48yUenjb99uLrwBUl2DacUfzLJG6pq5XBRpjcMYwAAAPC0xp9ph6r64ySvTXJaVW3K1NWBfz3Jh6vqiiT3J3nzsPvHk1ySZGOS3UnekSSttUeq6leS3Drs98uttSdf8AkAAAC+yzOGa2vtrYe468Kn2LcleechnucDST5wWLMDAABg0ZvxxZkAAADgaBKuAAAAdE24AgAA0DXhCgAAQNeEKwAAAF0TrgAAAHRNuAIAANA14QoAAEDXhCsAAABdE64AAAB0TbgCAADQNeEKAABA14QrAAAAXROuAAAAdE24AgAA0DXhCgAAQNeEKwAAAF0TrgAAAHRNuAIAANA14QoAAEDXhCsAAABdE64AAAB0TbgCAADQNeEKAABA14QrAAAAXROuAAAAdE24AgAA0DXhCgAAQNeEKwAAAF0TrgAAAHRNuAIAANA14QoAAEDXhCsAAABdE64AAAB0TbgCAADQNeEKAABA14QrAAAAXROuAAAAdE24AgAA0DXhCgAAQNeEKwAAAF0TrgAAAHRNuAIAANA14QoAAEDXhCsAAABdE64AAAB0TbgCAADQNeEKAABA14QrAAAAXROuAAAAdE24AgAA0DXhCgAAQNeEKwAAAF0TrgAAAHRtRuFaVf++qu6sqi9X1R9X1XFVdXZV3VJVG6vqT6pq2bDv8uH2xuH+tbPyFQAAALCgHXG4VtWZSf5tkvWtte9PsiTJW5L8RpL3ttbOSbIjyRXDQ65IsmMYf++wHwAAADytmZ4qPJ7k+KoaT3JCkgeTvD7J9cP91yW5bNi+dLid4f4Lq6pm+PoAAAAscEccrq21zUl+M8k3MxWsu5J8McnO1trEsNumJGcO22cmeWB47MSw/6lH+voAAAAsDjM5VXhlpo6inp3kjCQnJrlophOqqiurakNVbdi2bdtMnw4AAIBj3ExOFf6xJN9orW1rrR1I8mdJXpVkxXDqcJKsSbJ52N6c5KwkGe4/Ocn2Jz9pa+3q1tr61tr6VatWzWB6AAAALAQzCddvJrmgqk4Y3qt6YZKvJPl0kjcN+1ye5KPD9g3D7Qz3f6q11mbw+gAAACwCM3mP6y2ZusjSl5LcMTzX1Ul+Mcm7q2pjpt7Des3wkGuSnDqMvzvJVTOYNwAAAIvE+DPvcmittfckec+Thu9Ncv5T7Ls3yc/M5PUAAABYfGb653AAAADgqBKuAAAAdE24AgAA0DXhCgAAQNeEKwAAAF0TrgAAAHRNuAIAANA14QoAAEDXhCsAAABdE64AAAB0TbgCAADQNeEKAABA14QrAAAAXROuAAAAdE24AgAA0DXhCgAAQNeEKwAAAF0TrgAAAHRNuAIAANA14QoAAEDXhCsAAABdE64AAAB0TbgCAADQNeEKAABA14QrAAAAXROuAAAAdE24AgAA0DXhCgAAQNeEKwAAAF0TrgAAAHRNuAIAANA14QoAAEDXhCsAAABdE64AAAB0TbgCAADQNeEKAABA14QrAAAAXROuAAAAdE24AgAA0DXhCgAAQNeEKwAAAF0TrgAAAHRNuAIAANA14QoAAEDXhCsAAABdE64AAAB0TbgCAADQNeEKAABA14QrAAAAXROuAAAAdE24AgAA0DXhCgAAQNeEKwAAAF0TrgAAAHRNuAIAANC1GYVrVa2oquur6qtVdVdV/WhVnVJVN1bVPcPnlcO+VVXvq6qNVXV7Vb18dr4EAAAAFrKZHnH9nSSfaK29JMnLktyV5KokN7XW1iW5abidJBcnWTd8XJnk/TN8bQAAABaBIw7Xqjo5yWuSXJMkrbX9rbWdSS5Nct2w23VJLhu2L03ywTbl5iQrqur0I319AAAAFoeZHHE9O8m2JH9QVf9QVb9fVScmWd1ae3DY56Ekq4ftM5M8MO3xm4YxAAAAOKSZhOt4kpcneX9r7YeSPJF/Oi04SdJaa0na4TxpVV1ZVRuqasO2bdtmMD0AAAAWgpmE66Ykm1prtwy3r89UyG45eArw8HnrcP/mJGdNe/yaYew7tNaubq2tb62tX7Vq1QymBwAAwEJwxOHaWnsoyQNV9eJh6MIkX0lyQ5LLh7HLk3x02L4hyduHqwtfkGTXtFOKAQAA4CmNz/DxP5fkD6tqWZJ7k7wjUzH84aq6Isn9Sd487PvxJJck2Zhk97AvAAAAPK0ZhWtr7bYk65/irgufYt+W5J0zeT0AAAAWn5n+HVcAAAA4qoQrAAAAXROuAAAAdE24AgAA0DXhCgAAQNeEKwAAAF0TrgAAAHRNuAIAANA14QoAAEDXhCsAAABdE64AAAB0TbgCAADQtfH5ngAAzJV97UCSZCxjGUslSZaU/8N9OpNtlCQZpWWUqe3j53NCACxKwhWAReP6x5+f4+pAVix5IqeO7c7JYweyYmwsJ4wtzXiWiNjBZBtlIpPZPTqQnaNRdo2WZvvohOycPDF729K8bb4nCMCiI1wBWDR+9dp/kdHy5MCJLZOnHshpz3s0563anFedfE/OW/5A1oxP5DljyxZlxB6M1cdG+7NpYjy37Tsrf7drXW7bdmYe3vLcLHlkaZY+Xhnbn7ztv833bAFYbIQrAIvG2j/4ejI+niwdz+jE4zOx8sTcecYP5PMvfFn2vGRvXrnu3vzUaV/Ky5d/K6uXLMvyGl/wATvZRtnXJrJlcn++tO+M/Om2H87N97wwx9+9PCffO8qKb+3LaTsez9gTe5L9B5LJyUS4AjDHhCsAi8bElq1TGzWWGqssWbIkJy9blpUnnpDR81bmvnUvzn962UuzYv22/OzZn8+FJ3wtpy/QgD0YrA9O7s+NT7w41973o9m5YVVO+8dRXnzProxt3ZTRE7vT9u9Pm5zMxKglw/tdAWCuCVcAFo/Whs+TUw02MZG2b19Gjz+eenh7nvP15Tn5Cyuz79PPy/vOvyz/+1Xb8851f5MfP3FjVi9ZnuW1dF6nP1v2tQPZMrkvNz5xTv7n116bib87Jatv3ZtTNz6Q0SM70vbty8Tk5D/9ewHAPBOuANBa2sRE2sRERnv2ZnzrtnzPXSuy//Nn5Lde/dP5v6/7Vt599l/llcdty8ljx2VpLZnvGR+RA20yu0Z78/m9q/Kb974x2z9zes743J4su+frmdyxMxMHJpLR5HxPEwC+i3AFgOlGk2n7JjOxZWuW7NiZtRtXZveX1uQXXnd5Xv3aL+ddq2/Ki5ceyPG17Jg5fXiyjbKn7c/dB8byOw9dnJv/5vuy5lMHsvaOezP5yI5M7N/v6CoAXROuAPBUWps6ZfahLTlux85879dW5+7bvi9veuP35ude8em86bm35/Qlx3d/9PVAm8yDk3ty/aM/mN+99XU5/RNLs+4L38rowS2Z2LdPsAJwTBCuAPB0Wsto796M7t+UFdt35OSvrsm1r78of/7Gl+U/v+hjecXyXXnu2HHdHX2dbKM8OtqbW/atzK9+/U3Z9YnT85JP70zde08mHn/CKcEAHFOEKwA8G6PJTD76aOrOjVnz4IrsufMF+TcXXZHLXvOF/KtTP5cXLl3azcWbdo/25/6Jifz+9lfnz//m/LzgkxM587aNGW1/JKOJifmeHgAcNuEKAIehHdifya3bctzfPp4Xf+P0fPaOH8lfXnJurvr+T+THT7gvp83j6cMH2mQentyTG3evza/dcXFO+suT8uK/3ZK2+aFM7tnjtGAAjlnCFQAOV2sZ7d6dbLwvq7Y9kpVffUF+7cfenD+78Ot591mfzMuW7clJtXzOTh+ebKM83vblH/cfn9964J/na3/9opx10xMZv+urmdz1qNOCATjmCVcAOFKjyUzu3JmxL+7OC795WrbfsTaX//iVedMFt+Ztp/x9Xjieo3r14YNXC753Irlu+6vykZtfkTU3tpy94f5Mbns4k64WDMACIVwBYCYOXn34Ww/lpL/amZd+9Yx8ZsMF+ciF5+Vnf+DzufS5t+V7xivLa+msnUJ8oE1mXzuQ+ydaPvroebnm9lfmlJuOy0tufjjtm9/KxJ69jrICsKAIVwCYDaPJjJ54InXPN7LqoYdz6j+ekf93wYW59tUX5K3nbshPPPe2vHB8b54ztizjWXLYR2En2ygTmcxjo/25d2JZ/uLRH84f3fmKnPS5E7Lull0Zu/e+jB57LM3FlwBYgIQrAMyiNjGRyZ07U7c/kdPvf05GXzgjH/uh1+SDr3hlfvTcjfnJ027LDyz/VlYtGeWEWpKltSRjGctY6jueZ5SWUUY50Cazu01m2+RY7th3Rm54+Lz8/VfOySm3judFX3osY/fdndGuxzI5ccBpwQAsWMIVAGZba1NXH97+SGrXY1l970lZ/Xer8s2XfG9++dyXZv9L9uQHz9qU9Su+mXOOeyjPH9+V59a+LK1RkmRvW5In2rI8NHFKNu59fjbsfEFuf2BNlt11fE79ymReevfO5KFtGT36uGAFYFEQrgBwtBwM2Ed2pHY9mufctzwn33xyJp+3MtvXnJ3rzzwne55f2XfKZNpJkxlbNvW+1NG+JaknlmT59iU5fkvLczZP5pxNT2TJ1i0Z7dyV0b59aZOTghWARUO4AsDR1lraxETaxERGu3entmzNCXcvy4nHH5c67ri045cny5eljU+977UmRsm+/ak9+9L27k3bszdt//5MiFUAFinhCgBzaVrEZs+eqbEaS43903tcW5I2akkbffsxALCYCVcAmC8Hg7RNfrtRAYDvdnT+IjoAAADMEuEKAABA14QrAAAAXROuAAAAdE24AgAA0DXhCgAAQNeEKwAAAF0TrgAAAHRNuAIAANA14QoAAEDXhCsAAABdE64AAAB0TbgCAADQNeEKAABA14QrAAAAXROuAAAAdE24AgAA0DXhCgAAQNeEKwAAAF0TrgAAAHRNuAIAANC1GYdrVS2pqn+oqo8Nt8+uqluqamNV/UlVLRvGlw+3Nw73r53pawMAALDwzcYR159Pcte027+R5L2ttXOS7EhyxTB+RZIdw/h7h/0AAADgac0oXKtqTZKfSPL7w+1K8vok1w+7XJfksmH70uF2hvsvHPYHAACAQ5rpEdffTvIfkoyG26cm2dlamxhub0py5rB9ZpIHkmS4f9ew/3eoqiurakNVbdi2bdsMpwcAAMCx7ojDtar+WZKtrbUvzuJ80lq7urW2vrW2ftWqVbP51AAAAByDxmfw2Fcl+cmquiTJcUmem+R3kqyoqvHhqOqaJJuH/TcnOSvJpqoaT3Jyku0zeH0AAAAWgSM+4tpa+6XW2prW2tokb0nyqdbav0zy6SRvGna7PMlHh+0bhtsZ7v9Ua60d6esDAACwOByNv+P6i0neXVUbM/Ue1muG8WuSnDqMvzvJVUfhtQEAAFhgZnKq8Le11j6T5DPD9r1Jzn+KffYm+ZnZeD0AAAAWj6NxxBUAAABmjXAFAACga8IVAACArglXAAAAuiZcAQAA6JpwBQAAoGvCFQAAgK4JVwAAALomXAEAAOiacAUAAKBrwhUAAICuCVcAAAC6JlwBAADomnAFAACga8IVAACArglXAAAAuiZcAQAA6JpwBQAAoGvCFQAAgK4JVwAAALomXAEAAOiacAUAAKBrwhUAAICuCVcAAAC6JlwBAADomnAFAACga8IVAACArglXAAAAuiZcAQAA6JpwBQAAoGvCFQAAgK4JVwAAALomXAEAAOiacAUAAKBrwhUAAICuCVcAAAC6JlwBAADomnAFAACga8IVAACArglXAAAAuiZcAQAA6JpwBQAAoGvCFQAAgK4JVwAAALomXAEAAOiacAUAAKBrwhUAAICuCVcAAAC6JlwBAADomnAFAACga8IVAACArglXAAAAuiZcAQAA6JpwBQAAoGtHHK5VdVZVfbqqvlJVd1bVzw/jp1TVjVV1z/B55TBeVfW+qtpYVbdX1ctn64sAAABg4ZrJEdeJJL/QWjs3yQVJ3llV5ya5KslNrbV1SW4abifJxUnWDR9XJnn/DF4bAACAReKIw7W19mBr7UvD9mNJ7kpyZpJLk1w37HZdksuG7UuTfLBNuTnJiqo6/UhfHwAAgMVhVt7jWlVrk/xQkluSrG6tPTjc9VCS1cP2mUkemPawTcMYAAAAHNKMw7WqTkryp0n+XWvt0en3tdZaknaYz3dlVW2oqg3btm2b6fQAAAA4xs0oXKtqaaai9Q9ba382DG85eArw8HnrML45yVnTHr5mGPsOrbWrW2vrW2vrV61aNZPpAQAAsADM5KrCleSaJHe11n5r2l03JLl82L48yUenjb99uLrwBUl2TTulGAAAAJ7S+Awe+6okb0tyR1XdNoz9xyS/nuTDVXVFkvuTvHm47+NJLkmyMcnuJO+YwWsDAACwSBxxuLbWPpekDnH3hU+xf0vyziN9PQAAABanWbmqMAAAABwtwhUAAICuCVcAAAC6JlwBAADomnAFAACga8IVAACArglXAAAAuiZcAQAA6JpwBQAAoGvCFQAAgK4JVwAAALomXAEAAOiacAUAAKBrwhUAAICuCVcAAAC6JlwBAADomnAFAACga8IVAACArglXAAAAuiZcAQAA6JpwBQAAoGvCFQAAgK4JVwAAALomXAEAAOiacAUAAKBrwhUAAICuCVcAAAC6JlwBAADomnAFAACga8IVAACArglXAAAAuiZcAQAA6JpwBQAAoGvCFQAAgK4JVwAAALomXAEAAOiacAUAAKBrwhUAAICuCVcAAAC6JlwBAADomnAFAACga8IVAACArglXAAAAuiZcAQAA6JpwBQAAoGvCFQAAgK4JVwAAALomXAEAAOiacAUAAKBrwhUAAICuCVcAAAC6JlwBAADomnAFAACga8IVAACArglXAAAAujbn4VpVF1XV3VW1saqumuvXBwAA4Ngyp+FaVUuS/F6Si5Ocm+StVXXuXM4BAACAY8tcH3E9P8nG1tq9rbX9ST6U5NI5ngMAAADHkLkO1zOTPDDt9qZhDAAAAJ7S+HxP4Mmq6sokVw43H6+qu+dzPgvcaUkenu9JsChZe8wXa28WVNV8T+FYZO0xn6w/5suzWXvf82yeaK7DdXOSs6bdXjOMfVtr7eokV8/lpBarqtrQWls/3/Ng8bH2mC/WHvPF2mM+WX/Ml9lce3N9qvCtSdZV1dlVtSzJW5LcMMdzAAAA4Bgyp0dcW2sTVfWuJJ9MsiTJB1prd87lHAAAADi2zPl7XFtrH0/y8bl+XZ6SU7KZL9Ye88XaY75Ye8wn64/5Mmtrr1prs/VcAAAAMOvm+j2uAAAAcFiE6wJVVT9TVXdW1aiq1j/pvl+qqo1VdXdVvXHa+EXD2Maqumra+NlVdcsw/ifDhbXgGVXVf6mqzVV12/BxybT7DmsdwkxZWxxtVXVfVd0xfL/bMIydUlU3VtU9w+eVw3hV1fuG9Xh7Vb18fmfPsaSqPlBVW6vqy9PGDnutVdXlw/73VNXl8/G1cGw5xNqbk9/3hOvC9eUkP53ks9MHq+rcTF3N+fuSXJTkf1XVkqpakuT3klyc5Nwkbx32TZLfSPLe1to5SXYkuWJuvgQWiPe21s4bPj6eHPE6hCNmbTGHXjd8vzv4n8ZXJbmptbYuyU3D7WRqLa4bPq5M8v45nynHsmsz9fNzusNaa1V1SpL3JPmRJOcnec/B2IWncW2+e+0lc/D7nnBdoFprd7XW7n6Kuy5N8qHW2r7W2jeSbMzUN6vzk2xsrd3bWtuf5ENJLq2pvzL/+iTXD4+/LsllR/0LYKE7rHU4j/Nk4bC2mC+XZupnZ/KdP0MvTfLBNuXmJCuq6vR5mB/HoNbaZ5M88qThw11rb0xyY2vtkdbajiQ35qmDBL7tEGvvUGb19z3huvicmeSBabc3DWOHGj81yc7W2sSTxuHZetdwatIHpv1P7uGuQ5gpa4u50JL8VVV9saquHMZWt9YeHLYfSrJ62LYmmW2Hu9asQWbTUf99T7gew6rqr6vqy0/x4SgCc+YZ1uH7k7woyXlJHkzyP+ZzrgBH2atbay/P1Olv76yq10y/s039KQd/zoGjzlpjjs3J73tz/ndcmT2ttR87godtTnLWtNtrhrEcYnx7pk4pGR+Ouk7fH571Oqyq/5PkY8PNw12HMFNPt+ZgVrTWNg+ft1bVRzJ1OtyWqjq9tfbgcHrm1mF3a5LZdrhrbXOS1z5p/DNzME8WmNbaloPbR/P3PUdcF58bkrylqpZX1dmZeqP+F5LcmmRdTV1BeFmm3kh9w/A/dp9O8qbh8Zcn+eg8zJtj0JPer/VTmbpoWHKY63Au58yCZW1xVFXViVX1nIPbSd6Qqe95N2TqZ2fynT9Db0jy9uGKrxck2TXtNE84Eoe71j6Z5A1VtXI4tfMNwxgclrn6fc8R1wWqqn4qye8mWZXkL6rqttbaG1trd1bVh5N8JclEkne21iaHx7wrU9+wliT5QGvtzuHpfjHJh6rqvyb5hyTXzPGXw7Hrv1fVeZk6Xem+JP86SY5wHcIRa61NWFscZauTfGTqmoYZT/JHrbVPVNWtST5cVVckuT/Jm4f9P57kkkxdrGR3knfM/ZQ5VlXVH2fqaOlpVbUpU1cH/vUcxlprrT1SVb+SqYhIkl9urT3bi+6wSB1i7b12Ln7fq6kDagAAANAnpwoDAADQNeEKAABA14QrAAAAXROuAAAAdE24AgAA0DXhCgAAQNeEKwAAAF0TrgAAAHTt/wO4DKC00SnD+AAAAABJRU5ErkJggg==\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "Initialize_distributions()\n", "plt.scalar_field(dh.gather_array(C.name))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Source Terms" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For the Allen-Cahn LB step, the Allen-Cahn equation needs to be applied as a source term. Here, a simple forcing model is used which is directly applied in the moment space: \n", "$$\n", "F_i^\\phi (\\boldsymbol{x}, t) = \\Delta t \\frac{\\left[1 - 4 \\left(\\phi - \\phi_0\\right)^2\\right]}{\\xi} w_i \\boldsymbol{c}_i \\cdot \\frac{\\nabla \\phi}{|{\\nabla \\phi}|},\n", "$$\n", "where $\\phi$ is the phase-field, $\\phi_0$ is the interface location, $\\Delta t$ it the timestep size $\\xi$ is the interface width, $\\boldsymbol{c}_i$ is the discrete direction from stencil_phase and $w_i$ are the weights. Furthermore, the equilibrium needs to be shifted:\n", "\n", "$$\n", "\\bar{h}^{eq}_\\alpha = h^{eq}_\\alpha - \\frac{1}{2} F^\\phi_\\alpha\n", "$$\n", "\n", "The hydrodynamic force is given by:\n", "$$\n", "F_i (\\boldsymbol{x}, t) = \\Delta t w_i \\frac{\\boldsymbol{c}_i \\boldsymbol{F}}{\\rho c_s^2},\n", "$$\n", "where $\\rho$ is the interpolated density and $\\boldsymbol{F}$ is the source term which consists of the pressure force \n", "$$\n", "\\boldsymbol{F}_p = -p^* c_s^2 \\nabla \\rho,\n", "$$\n", "the surface tension force:\n", "$$\n", "\\boldsymbol{F}_s = \\mu_\\phi \\nabla \\phi\n", "$$\n", "and the viscous force term:\n", "$$\n", "F_{\\mu, i}^{\\mathrm{MRT}} = - \\frac{\\nu}{c_s^2 \\Delta t} \\left[\\sum_{\\beta} c_{\\beta i} c_{\\beta j} \\times \\sum_{\\alpha} \\Omega_{\\beta \\alpha}(g_\\alpha - g_\\alpha^{\\mathrm{eq}})\\right] \\frac{\\partial \\rho}{\\partial x_j}.\n", "$$\n", "\n", "In the above equations $p^*$ is the normalised pressure which can be obtained from the zeroth order moment of the hydrodynamic distribution function $g$. The lattice speed of sound is given with $c_s$ and the chemical potential is $\\mu_\\phi$. Furthermore, the viscosity is $\\nu$ and $\\Omega$ is the moment-based collision operator. Note here that the hydrodynamic equilibrium is also adjusted as shown above for the phase-field distribution functions.\n", "\n", "\n", "For CLBM methods the forcing is applied directly in the central moment space. This is done with the `CentralMomentMultiphaseForceModel`. Furthermore, the GUO force model is applied here to be consistent with [A cascaded phase-field lattice Boltzmann model for the simulation of incompressible, immiscible fluids with high density contrast](http://dx.doi.org/10.1016/j.camwa.2019.08.018). Here we refer to equation D.7 which can be derived for 3D stencils automatically with lbmpy." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "force_h = interface_tracking_force(C, stencil_phase, parameters)\n", "hydro_force = hydrodynamic_force(C, method_hydro, parameters, body_force)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Definition of the LB update rules" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The update rule for the phase-field LB step is defined as:\n", "\n", "$$\n", "h_i (\\boldsymbol{x} + \\boldsymbol{c}_i \\Delta t, t + \\Delta t) = h_i(\\boldsymbol{x}, t) + \\Omega_{ij}^h(\\bar{h_j}^{eq} - h_j)|_{(\\boldsymbol{x}, t)} + F_i^\\phi(\\boldsymbol{x}, t).\n", "$$\n", "In our framework the pull scheme is applied as streaming step. Furthermore, the update of the phase-field is directly integrated into the kernel. As a result of this, a second temporary phase-field is needed." ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "lbm_optimisation = LBMOptimisation(symbolic_field=h, symbolic_temporary_field=h_tmp)\n", "allen_cahn_update_rule = create_lb_update_rule(lbm_config=config_phase,\n", " lbm_optimisation=lbm_optimisation)\n", "\n", "allen_cahn_update_rule = add_interface_tracking_force(allen_cahn_update_rule, force_h)\n", "\n", "ast_kernel = ps.create_kernel(allen_cahn_update_rule, target=dh.default_target, cpu_openmp=True)\n", "kernel_allen_cahn_lb = ast_kernel.compile()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The update rule for the hydrodynmaic LB step is defined as:\n", "\n", "$$\n", "g_i (\\boldsymbol{x} + \\boldsymbol{c}_i \\Delta t, t + \\Delta t) = g_i(\\boldsymbol{x}, t) + \\Omega_{ij}^g(\\bar{g_j}^{eq} - g_j)|_{(\\boldsymbol{x}, t)} + F_i(\\boldsymbol{x}, t).\n", "$$\n", "\n", "Here, the push scheme is applied which is easier due to the data access required for the viscous force term. Furthermore, the velocity update is directly done in the kernel." ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "scrolled": false }, "outputs": [], "source": [ "force_Assignments = hydrodynamic_force_assignments(u, C, method_hydro, parameters, body_force)\n", "\n", "lbm_optimisation = LBMOptimisation(symbolic_field=g, symbolic_temporary_field=g_tmp)\n", "hydro_lb_update_rule = create_lb_update_rule(lbm_config=config_hydro,\n", " lbm_optimisation=lbm_optimisation)\n", "\n", "hydro_lb_update_rule = add_hydrodynamic_force(hydro_lb_update_rule, force_Assignments, C, g, parameters,\n", " config_hydro)\n", "\n", "ast_kernel = ps.create_kernel(hydro_lb_update_rule, target=dh.default_target, cpu_openmp=True)\n", "kernel_hydro_lb = ast_kernel.compile()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Boundary Conditions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As a last step suitable boundary conditions are applied" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": [ "# periodic Boundarys for g, h and C\n", "periodic_BC_C = dh.synchronization_function(C.name, target=dh.default_target, optimization = {\"openmp\": True})\n", "\n", "periodic_BC_g = LBMPeriodicityHandling(stencil=stencil_hydro, data_handling=dh, pdf_field_name=g.name,\n", " streaming_pattern=config_hydro.streaming_pattern)\n", "periodic_BC_h = LBMPeriodicityHandling(stencil=stencil_phase, data_handling=dh, pdf_field_name=h.name,\n", " streaming_pattern=config_phase.streaming_pattern)\n", "\n", "# No slip boundary for the phasefield lbm\n", "bh_allen_cahn = LatticeBoltzmannBoundaryHandling(method_phase, dh, 'h',\n", " target=dh.default_target, name='boundary_handling_h',\n", " streaming_pattern=config_phase.streaming_pattern)\n", "\n", "# No slip boundary for the velocityfield lbm\n", "bh_hydro = LatticeBoltzmannBoundaryHandling(method_hydro, dh, 'g' ,\n", " target=dh.default_target, name='boundary_handling_g',\n", " streaming_pattern=config_hydro.streaming_pattern)\n", "\n", "contact_angle = BoundaryHandling(dh, C.name, stencil_hydro, target=dh.default_target)\n", "contact = ContactAngle(90, parameters.interface_thickness)\n", "\n", "wall = NoSlip()\n", "if dimensions == 2:\n", " bh_allen_cahn.set_boundary(wall, make_slice[:, 0])\n", " bh_allen_cahn.set_boundary(wall, make_slice[:, -1])\n", "\n", " bh_hydro.set_boundary(wall, make_slice[:, 0])\n", " bh_hydro.set_boundary(wall, make_slice[:, -1])\n", " \n", " contact_angle.set_boundary(contact, make_slice[:, 0])\n", " contact_angle.set_boundary(contact, make_slice[:, -1])\n", "else:\n", " bh_allen_cahn.set_boundary(wall, make_slice[:, 0, :])\n", " bh_allen_cahn.set_boundary(wall, make_slice[:, -1, :])\n", "\n", " bh_hydro.set_boundary(wall, make_slice[:, 0, :])\n", " bh_hydro.set_boundary(wall, make_slice[:, -1, :])\n", " \n", " contact_angle.set_boundary(contact, make_slice[:, 0, :])\n", " contact_angle.set_boundary(contact, make_slice[:, -1, :])\n", "\n", "\n", "bh_allen_cahn.prepare()\n", "bh_hydro.prepare()\n", "contact_angle.prepare()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Full timestep" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [], "source": [ "# definition of the timestep for the immiscible fluids model\n", "def timeloop():\n", " # Solve the interface tracking LB step with boundary conditions\n", " periodic_BC_h()\n", " bh_allen_cahn() \n", " dh.run_kernel(kernel_allen_cahn_lb, **parameters.symbolic_to_numeric_map)\n", " # Solve the hydro LB step with boundary conditions\n", " periodic_BC_g()\n", " bh_hydro()\n", " dh.run_kernel(kernel_hydro_lb, **parameters.symbolic_to_numeric_map)\n", " \n", " dh.swap(\"C\", \"C_tmp\")\n", " # apply the three phase-phase contact angle\n", " contact_angle()\n", " # periodic BC of the phase-field\n", " periodic_BC_C()\n", " \n", " # field swaps\n", " dh.swap(\"h\", \"h_tmp\")\n", " dh.swap(\"g\", \"g_tmp\")" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "scrolled": false }, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Initialize_distributions()\n", "\n", "frames = 300\n", "steps_per_frame = (timesteps//frames) + 1\n", "\n", "if 'is_test_run' not in globals():\n", " def run():\n", " for i in range(steps_per_frame):\n", " timeloop()\n", " \n", " if gpu:\n", " dh.to_cpu(\"C\")\n", " return dh.gather_array(C.name)\n", "\n", " animation = plt.scalar_field_animation(run, frames=frames, rescale=True)\n", " set_display_mode('video')\n", " res = display_animation(animation)\n", "else:\n", " timeloop()\n", " res = None\n", "res" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that the video is played for 10 seconds while the simulation time is only 2 seconds!" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.4" } }, "nbformat": 4, "nbformat_minor": 2 }