zoukankan      html  css  js  c++  java
  • 流体模拟基础1

    1,散度 鼠标右键打开(高清图)

     1.1 探讨1D 情况下的advection

    (来自Fluid simulation for computer graphic - Robert Bridson)

    初始化一些变量:,

    其中dt 按照文章写的:

    import numpy as np
    from matplotlib import pyplot
    import time,sys
    
    nx = 100
    dx = 2/(nx-1)
    nt = 100  #25 steps
    u  = 1   #assume advection speed = 1
    dt = dx/2
    
    
    q = np.array([0.2 for x in range(nx)])
    
    ############ our init condition#######################################
    # THIS CONDITION FROM PAGE-41 Robert Bridson
    for x in range(2,11,1):
        q[x] = x/10.0
    q[10:19] = (q[2:11])[::-1]
    ######################################################################

    这个是初值条件:

    pyplot.plot(np.linspace(0,nx,nx),q)
    pyplot.show()
    pyplot.close()

     接下来先用 这个方法做:

    def eulerian_advection():
        rhq = q.copy()  # this function compute THIS, and return this!
        qn = np.zeros(nx)
        for step in range(nt):
            # every time step we need update our READY-Q: qn
            qn = rhq.copy()
            for i in range(1,nx):
                rhq[i] = qn[i] - u * dt / dx* (qn[i] - qn[i-1])
        return rhq
    
    pyplot.plot(np.linspace(0,nx,nx),q)
    pyplot.show()
    pyplot.close()

    然后把这个写成人类可读的 py易读:

    def eulerian_advection_very_numpy():
        rhq = q.copy()  # this function compute THIS, and return this!
        qn = np.zeros(nx)
        for step in range(nt):
            # every time step we need update our READY-Q: qn
            qn = rhq.copy()
            rhq[1:] = qn[1:] - u * dt / dx *(qn[1:] - qn[0:-1])
        return rhq
    pyplot.plot(np.linspace(0,nx,nx),q)
    pyplot.show()
    pyplot.close()

     这个公式经过100 time step size步带来的效果,

     使用semi-lagrangian:

    # fluid simulation computer graphics [page 33]
    def semi_lagrangian():
        rhq = q.copy()  # this function compute THIS, and return this!
        qn = np.zeros(nx)
    
        for step in range(nt):
            qn = rhq.copy()
    
            for i in range(1, nx-1):
                xj = (i-1) * dx
                xg = i*dx
                xp = xg - dt * u
                w = (xp-xj)/dx
                qj  = qn[i-1]
                qj1 = qn[i+1]
    
                rhq[i] = (1-w) * qj + w * qj1
            plot_data(rhq)
        return rhq
    
    semi_lagrangian()

     1.2 signed distance

    假设速度是vector(0,1,0) 会出现下面的可视化:

    2,如何在Houdini里解 2-D Linear Convection

    离散完之后:

     初始条件:

    Boundry地方全为0

    中间设置了一些 数值.不过是把u映射到y 的高度

    int row = chi("ny");
    int column = chi("nx");
    float c = 1;
    float dx = 2.0 / float(row - 1);
    float dy = 2.0 / float(column - 1);
    float sigma = .2;
    float dt = sigma * dx;
    
    
    for(int j=0; j< row ;j++)
    {
        for(int i=0; i< column ; i++)
        {
            int pt =  j * row + i;
            float u = point(0,"u",pt);
            
            // partial u/x
            int pt_x_next = j * row + i-1;
            float x_next_u = point(0,"u",pt_x_next);
            float partial_u_x = u - x_next_u;
            
            // partial u/y
            int pt_y_next = (j-1)*row + i;
            float y_next_u = point(0,"u",pt_y_next);
            float partial_u_y = u - y_next_u;
            
            
            float newu = u - c * dt/dx * ( partial_u_x) - c * dt/dy *( partial_u_y);
            setpointattrib(0,"u",pt,newu);
        }
    }
    code detail 模式

     过了一些帧

     

     Diffusion 方程:做完感觉是个高斯模糊。。。。

    int row = chi("ny");
    int column = chi("nx");
    float c = 16;
    float dx = 2.0 / float(row - 1);
    float dy = 2.0 / float(column - 1);
    float sigma = .05;
    float dt = sigma * dx;
    float viscosity = 0.05;
    
    for(int j=1; j< row ;j++)
    {
        for(int i=1; i< column ; i++)
        {
            int pt =  j * row + i;
            float u = point(0,"u",pt);
            
            
            int uxnext  = j * row + i+1;
            int uxfront = j * row + i-1;
            
            int uynext = (j+1)*row + i;
            int uyfront = (j-1)*row + i;
            
            
            // u/x 二阶偏导数
            float uxnext_val = point(0,"u",uxnext);
            float uxfront_val = point(0,"u",uxfront);
            float partial_uu_xx = uxnext_val - 2 * u + uxfront_val;
            
            // u/y 二阶偏导数
            float uynext_val = point(0,"u",uynext);
            float uyfront_val = point(0,"u",uyfront);
            float partial_uu_yy = uynext_val - 2 * u + uyfront_val;
            
     
            
            float newu = u + viscosity * dt / (dx*dx) * partial_uu_xx + viscosity*dt / (dy*dy) * partial_uu_yy ;
            
            
        
            setpointattrib(geoself(),"u",pt,newu);
        }
    }
    View Code

     

     第一帧:

     

    过了60帧:

     

    欧拉方法,K阶泰勒方法, 龙格-库塔RK2(中点midpoint), RK4

    欧拉向前公式: 

    欧拉向前步进法 精度测试,事实上可以用托马斯微积分给的 改进欧拉法(梯形法) 比现在这个要精确的多。

    在[0,1]区间,看到n的步伐增加,对y的预测更加准确。

    import numpy
    from matplotlib import pyplot
    
    def euler_step(t, y, h, yPrimFunction):
        """
        :param t: 当前时间t
        :param y: 当前值y
        :param h: 当前步长h
        :return: 时间上t+h的近似解
        """
        val =  y + h * yPrimFunction(t, y)
        return val
    
    def euler(space, y0, n, yPrime):
        """
        :param space: [x 轴向上的区间]
        :param y0:  初值y0
        :param n:   步伐总值
        :return: [( t array) (y array)]
        """
    
        h = (space[1] - space[0]) / float(n)
        tArray = numpy.linspace(space[0], space[1], n)
        yArray = numpy.zeros(n)
        yArray[0] = y0
        
        for i in range(n-1):
            yArray[i+1] = euler_step(tArray[i], yArray[i], h, yPrime)
        return numpy.array((tArray,yArray))
    
    
    func = lambda t, y : t * y + t*t*t
    mapped_10 = euler([0, 1], 1, 10, func )
    mapped_20 = euler([0, 1], 1, 20, func )
    mapped_30 = euler([0, 1], 1, 30, func )
    mapped_40 = euler([0, 1], 1, 40, func )
    
    def plot_simple():
        pyplot.plot(mapped_10[0],mapped_10[1])  ##Plot the results
        pyplot.plot(mapped_20[0],mapped_20[1])  ##Plot the results
        pyplot.show()
    
    def plot_complex():
        fig, ax = pyplot.subplots()
        ax.plot(mapped_10[0], mapped_10[1], label="n=10")
        ax.plot(mapped_20[0], mapped_20[1], label="n=20")
        ax.plot(mapped_30[0], mapped_30[1], label="n=30")
        ax.plot(mapped_40[0], mapped_40[1], label="n=40")
        ax.legend(loc=2)  # upper left corner
        ax.set_xlabel('t')
        ax.set_ylabel('y')
        ax.set_title("Euler Step method for: y'= t*y + t^3 ")
        pyplot.show()
    
    plot_complex()
    View Code

    根据斜率场预测下一个值的除了欧拉法 还有几个出名的方法。

    1, K阶泰勒方法 ,一阶的泰勒方法正是 欧拉方法。

        K阶的泰勒方法有个缺点,就是必须把K阶导数求出来

        围绕泰勒方法,离散方法: 求导数,ODE, PDE

        而ODE的离散方法 和 导数的离散方法,仔细观察就是从泰勒定理里 完全剥离出来的

    2,但是RK2 RK3 RK4  完全是不用把不用知道 f'' f''' ... 的情况下把K阶的方法求出来,

         RK4 全局误差和h^4 成正比. 流体力学用到RK4 已经算出很高的精度了

    3,还有更高级的 可变步长方法。

    泊松方程

    import numpy
    from matplotlib import pyplot, cm
    from mpl_toolkits.mplot3d import Axes3D
    
    nx = 100
    ny = 100
    
    xmin = 0
    xmax = 2
    
    ymin = 0
    ymax = 1
    
    dx = (xmax - xmin) / (nx - 1)
    dy = (ymax - ymin) / (ny - 1)
    
    print(dx, dy)
    
    p = numpy.zeros((ny, nx))
    b = numpy.zeros((ny, nx))
    
    x = numpy.linspace(xmin, xmax, nx)
    y = numpy.linspace(ymin, ymax, ny)
    
    # boundary condition for p
    p[0, :] = 0  # p = 0 @ y = 1      最顶一行
    p[ny - 1, :] = 0  # p = 0 @ y = 0     最底一行
    
    p[:, 0] = 0  # p = 0 @ x = 0     左边一列
    p[:, nx - 1] = 0  # p = 0 @ x = 2     右边一列
    
    # print(p)
    # init condition for b
    
    b[:, int(ny / 2 - 10):int(ny / 2 + 10)] = 100
    b[int(ny / 2 - 10):int(ny / 2 + 10):] = 100
    
    # print(b)
    
    
    square_dx = dx * dx
    square_dy = dy * dy
    
    nt = 200
    
    
    def plot2D(x, y, p, frame):
        fig = pyplot.figure(figsize=(11, 7), dpi=100)
        ax = fig.gca(projection='3d')
        X, Y = numpy.meshgrid(x, y)
        surf = ax.plot_surface(X, Y, p[:], rstride=1, cstride=1, cmap=cm.viridis,
                               linewidth=0, antialiased=False)
        ax.view_init(30, 225)
        ax.set_xlabel('$x$')
        ax.set_ylabel('$y$')
        fig.savefig('./imgs/Laplace2d.' + ('00000' + str(frame))[-4:] + '.png')
        # pyplot.close()
        pyplot.show()
    
    
    for it in range(nt):
        pre_p = p.copy()
    
        p[1:-1, 1:-1] = ((pre_p[1:-1, 2:] + pre_p[1:-1, 0:-2]) * dy * dy +
                         (pre_p[2:, 1:-1] + pre_p[:-2, 1:-1]) * dx * dx -
                         b[1:-1, 1:-1] * dx * dx * dy * dy) / (2 * (dx * dx + dy * dy))
    
        p[0, :] = 0  # p = 0 @ y = 1      最顶一行
        p[ny - 1, :] = 0  # p = 0 @ y = 0     最底一行
        p[:, 0] = 0  # p = 0 @ x = 0     左边一列
        p[:, nx - 1] = 0  # p = 0 @ x = 2     右边一列
        plot2D(x, y, p, it)
    View Code

    迭代100次的过程 

    REF:

    http://nbviewer.jupyter.org/github/barbagroup/CFDPython/blob/master/lessons/07_Step_5.ipynb

    https://en.wikipedia.org/wiki/Euler_method

    https://en.wikipedia.org/wiki/Runge%E2%80%93Kutta_methods

  • 相关阅读:
    linux nohup
    并发编程-多进程模块介绍
    并发编程-多进程
    网络编程-粘包现象
    Typora快捷键Mac
    网络编程
    异常处理
    面向对象-元类介绍
    面向对象-内置方法
    面向对象-反射
  • 原文地址:https://www.cnblogs.com/gearslogy/p/10049855.html
Copyright © 2011-2022 走看看