pySPH学习

example taylor_bar   2D

主程序代码:mian.py

"""Taylor bar example with SPH. (5 minutes)
"""

# 导入函数
import numpy

from pysph.sph.equation import Group

from pysph.base.utils import get_particle_array
from pysph.base.kernels import WendlandQuintic
from pysph.solver.application import Application
from pysph.solver.solver import Solver
from pysph.sph.integrator import PECIntegrator
from pysph.sph.integrator_step import SolidMechStep

# basic sph equations
from pysph.sph.basic_equations import ContinuityEquation, \
    MonaghanArtificialViscosity, XSPHCorrection, VelocityGradient2D

# baic stress equations
from pysph.sph.solid_mech.basic import HookesDeviatoricStressRate,\
    MomentumEquationWithStress, EnergyEquationWithStress

# plasticity model and eos
from pysph.sph.solid_mech.hvi import VonMisesPlasticity2D, MieGruneisenEOS

# boundary force
from pysph.sph.boundary_equations import MonaghanBoundaryForce

# Numerical Parameters and constants
# 数值参数和常数
dx = dy = 0.000384848
hdx = 2.0
h = hdx * dx
r0 = 7850.0
m0 = dx * dy * r0
v_s = 200.0
ss = 4699.0
C = 3630.0
S = 1800.0
gamma = 1.81
alpha = 0.5
beta = 0.5
eta = 0.01
eps = 0.5
bar_width = 0.0076
G = 8*1e10
Yo = 6*1e8
ro2 = 2750.0
plate_start = -2.0*bar_width
plate_end = 2.0*bar_width

# 粒子初始化函数

# 创建平板粒子
# 初始化粒子属性,如法线、切线、声速和质量
def get_plate_particles():
    x = numpy.arange(plate_start, plate_end+dx, dx)
    y = numpy.zeros_like(x)

    # normals and tangents
    tx = numpy.ones_like(x)
    ty = numpy.zeros_like(x)
    tz = numpy.zeros_like(x)

    ny = numpy.ones_like(x)
    nx = numpy.zeros_like(x)
    nz = numpy.zeros_like(x)
    cs = numpy.ones_like(x)*ss
    pa = get_particle_array(name='plate', x=x, y=y, tx=tx, ty=ty, tz=tz,
                            nx=nx, ny=ny, nz=nz, cs=cs)
    pa.m[:] = m0

    return pa

# 创建矩形杆粒子
# 初始化粒子属性,如平滑长度、质量、密度、声速和初始速度
def get_bar_particles():
    xarr = numpy.arange(-bar_width/2.0, bar_width/2.0 + dx, dx)
    yarr = numpy.arange(4*dx, 0.0254 + 4*dx, dx)

    x,y = numpy.meshgrid( xarr, yarr )
    x, y = x.ravel(), y.ravel()

    print('Number of bar particles: ', len(x))

    hf = numpy.ones_like(x) * h
    mf = numpy.ones_like(x) * dx * dy * r0
    rhof = numpy.ones_like(x) * r0
    csf = numpy.ones_like(x) * ss
    z = numpy.zeros_like(x)
    pa = get_particle_array(name="bar",
                            x=x, y=y, h=hf, m=mf, rho=rhof, cs=csf,
                            e=z)
    # negative fluid particles
    pa.v[:]=-200
    return pa

class TaylorBar(Application):
    def create_particles(self):
        bar = get_bar_particles()
        plate = get_plate_particles()

        # add requisite properties

        # velocity gradient for the bar
        for name in ('v00', 'v01', 'v02', 'v10', 'v11', 'v12', 'v20', 'v21', 'v22'):
            bar.add_property(name)

        # deviatoric stress components
        for name in ('s00', 's01', 's02', 's11', 's12', 's22'):
            bar.add_property(name)

        # deviatoric stress accelerations
        for name in ('as00', 'as01', 'as02', 'as11', 'as12', 'as22'):
            bar.add_property(name)

        # deviatoric stress initial values
        for name in ('s000', 's010', 's020', 's110', 's120', 's220'):
            bar.add_property(name)

        bar.add_property('e0')

        # artificial stress properties
        for name in ('r00', 'r01', 'r02', 'r11', 'r12', 'r22'):
            bar.add_property(name)

        # standard acceleration variables and initial values.
        for name in ('arho', 'au', 'av', 'aw', 'ax', 'ay', 'az', 'ae',
                     'rho0', 'u0', 'v0', 'w0', 'x0', 'y0', 'z0', 'e0'):
            bar.add_property(name)

        bar.add_constant('G', G)
        bar.add_constant('n', 4)

        kernel = WendlandQuintic(dim=2)
        wdeltap = kernel.kernel(rij=dx, h=hdx*dx) #核函数的值,为常量
        bar.add_constant('wdeltap', wdeltap)

        return [bar, plate]

    def create_solver(self):
        kernel = WendlandQuintic(dim=2)
        self.wdeltap = kernel.kernel(rij=dx, h=hdx*dx) # 核函数的值,为常数

        integrator = PECIntegrator(bar=SolidMechStep())

        solver = Solver(kernel=kernel, dim=2, integrator=integrator)
        dt = 1e-9
        tf = 2.5e-5
        solver.set_time_step(dt)
        solver.set_final_time(tf)
        return solver

    def create_equations(self):
        equations = [

            # Properties computed set from the current state
            Group(
                equations=[
                    # p
                    MieGruneisenEOS(dest='bar', sources=None, gamma=gamma,
                                    r0=r0, c0=C, S=S),

                    # vi,j : requires properties v00, v01, v10, v11
                    VelocityGradient2D(dest='bar', sources=['bar',]),

                    # rij : requires properties s00, s01, s11
                    VonMisesPlasticity2D(flow_stress=Yo, dest='bar',
                                         sources=None),
                    ],
                ),

            # Acceleration variables are now computed
            Group(
                equations=[

                    # arho
                    ContinuityEquation(dest='bar', sources=['bar']),

                    # au, av
                    MomentumEquationWithStress(
                        dest='bar', sources=['bar']),

                    # au, av
                    MonaghanArtificialViscosity(
                        dest='bar', sources=['bar'], alpha=0.5, beta=0.5),

                    # au av
                    MonaghanBoundaryForce(
                        dest='bar', sources=['plate'], deltap=dx),

                    # ae
                    EnergyEquationWithStress(dest='bar', sources=['bar'],
                                             alpha=0.5, beta=0.5, eta=0.01),

                    # a_s00, a_s01, a_s11
                    HookesDeviatoricStressRate(
                        dest='bar', sources=None),

                    # ax, ay, az
                    XSPHCorrection(
                        dest='bar', sources=['bar',], eps=0.5),

                    ]

                ) # End Acceleration Group

        ] # End Group list
        return equations


if __name__ == '__main__':
    app = TaylorBar()
    app.run()

总体分析

 时间积分框架示意

PySPH参考文档

        此处翻译并记录

PySPH implementation

        example dam_break.2d

                two ParticleArrays 两组粒子数据

                pysph.base.nnps.NNPS 邻域搜索

Specifying the equations 指定方程

给定粒子数组,我们通过向求解器(见pysph.solver.solver.Solver)传递一个Equation对象列表(见SPH方程)来请求对粒子执行一组给定的操作。

equations = [
    # Equation of state
    Group(equations=[
        ...
    ], ),

    # Acceleration
    Group(equations=[
        ...
    ] ),
]

python笔记:Class及其实例化

python类的定义与实例化-CSDN博客

我们看到我们使用了两个Group对象(参见pysph.sph.equation.Group),分离了逻辑依赖的求值的两个部分。计算加速度的第二组必须在更新压力的第一组之后进行计算。

class pysph.sph.equation.Group

classpysph.sph.equation.Group(equations, real=True, update_nnps=False, iterate=False, max_iterations=1, min_iterations=0, pre=None, post=None, condition=None, start_idx=0, stop_idx=None, name=None)

source:

        real (bool) - 指定是否只对非远程/非鬼影粒子进行操作。

Notes

当并行运行模拟时,通常应该在每个处理器中运行所有粒子(本地和远程)的总和密度。这是因为我们必须在当前处理器中更新远程邻居的压力/密度。否则,由于远端粒子具有较老的密度,结果可能不正确。TaitEOS也是如此。在这些情况下,计算方程的组应该将real设为False。

回想一下,在我们假设的实现中,我们必须对SPHCalc.compute方法进行类似的隔离:

class SPHCalc:
    def __init__(nnps, particles):
        ...

    def compute(self):
        self.eos()
        self.accelerations()

PySPH将尊重用户提供的方程和方程组的顺序。这种灵活性也意味着很容易犯细微的错误。

一般来说,SPH算法的过程如下伪代码所示:

for destination in particles:
    for equation in equations:
        equation.initialize(destination)

# This is where bulk of the computation happens.
for destination in particles:
    for source in destination.neighbors:
        for equation in equations:
            equation.loop(source, destination)

for destination in particles:
    for equation in equations:
        equation.post_loop(destination)

# Reduce any properties if needed.
total_mass = reduce_array(particles.m, 'sum')
max_u = reduce_array(particles.u, 'max')

对每一个目标粒子,循环每一个方程,初始化方程

对每一个目标粒子,循环每一个源粒子,再循环计算每一个方程的loop

使用最近邻算法识别给定粒子的邻居。PySPH会自动为用户完成这项工作,并在内部使用基于链表的算法来识别邻居。

在PySPH中,我们在写方程时遵循一些简单的约定。让我们先看几个方程。为了与我们假设的实现和SPHCalc保持类比,我们考虑了 pysph.sph.basic.TaitEOS 和 pysph.sph.basic_ContinuityEquation 对象的实现。

前者看起来像:

MomentumEquation

细看代码结构

if __name__ == '__main__':
    app = TaylorBar()
    app.run()
run()

run() 方法是应用程序的主要入口点,负责初始化和运行主要功能,调用一次
包含 setup()solve() ,分别进行设置和求解。三者均在 application.py
argv 参数使得应用程序可以在命令行环境和交互环境下灵活运行。

solve() 

求解    in  application.py,class Application(object):

def solve(self):
        """This runs the solver.

        Note that this method expects that `setup has already been called.

        Don't use this method unless you really know what you are doing.
        """
        start_time = time.time()

        # 运行求解器
        self.solver.solve(not self.options.quiet)

        end_time = time.time()
        run_duration = end_time - start_time
        self._message("Run took: %.5f secs" % (run_duration))
        self._write_info(
            self.info_filename, completed=True, cpu_time=run_duration
        )

        self._stop_interfaces()
        self._write_profile_info()

 运行求解器就一行,循环在这其中进行:

self.solver.solve(not self.options.quiet)

1. self.solver 对象
定义:self.solver 是 Application 类的一个实例变量,代表一个求解器对象。
职责:求解器对象负责执行模拟计算的实际过程。它可能是 pysph.solver.solver.Solver 类的一个实例,或者是某个自定义求解器类的实例。
作用:该求解器对象封装了模拟计算中涉及的所有数值方法、迭代过程和求解逻辑。
2. solve 方法
定义:solve 是 self.solver 对象中的一个方法
职责:solve 方法启动求解器的计算过程,进行流体动力学模拟。
作用:该方法负责按设定的方案和初始条件推进模拟至完成。
3. 参数 not self.options.quiet
定义:self.options.quiet 是 Application 类中的一个布尔属性,通常从命令行参数或默认设置中获取。

职责:该属性控制输出日志的详细程度。

作用:

self.options.quiet 为 True:求解器在运行时不输出详细信息。
self.options.quiet 为 False:求解器在运行时输出详细信息,便于调试和监控进程。
参数传递:通过传递 not self.options.quiet,代码控制日志输出的开关。

self.solver

        in setup(),  self.solver = self.create_solver()

 在主程序中:

    def create_solver(self):
        # 设置核函数
        kernel = WendlandQuintic(dim=2)
        self.wdeltap = kernel.kernel(rij=dx, h=hdx*dx)

        # 积分方法
        integrator = PECIntegrator(bar=SolidMechStep())

        # 导入求解器
        solver = Solver(kernel=kernel, dim=2, integrator=integrator)
        # 设置时间步长、总时间
        dt = 1e-9
        tf = 2.5e-5
        solver.set_time_step(dt)
        solver.set_final_time(tf)
        return solver

这个求解器是怎么样的?

Solver 的输入:核函数 自由度 时间积分方法:PECIntegrator(bar=SolidMechStep)

pysph/solver/solver.py  class Solver(object)

python笔记:@函数装饰器 Python @函数装饰器及用法(超级详细) (biancheng.net)

使用函数装饰器 A() 去装饰另一个函数 B(),其底层执行了如下 2 步操作:
1 将 B 作为参数传给 A() 函数;
2 将 A() 函数执行完成的返回值反馈回 B()。

#funA 作为装饰器函数
def funA(fn):
    print("AAA")
    fn() # 执行传入的fn参数
    print("BBB")
    return "CCC"

@funA
def funB():
    print("DDD")


print(funB)

程序执行流程:

AAA
DDD
BBB

CCC

class SolidMechStep(IntegratorStep):

        initialize

        stage1

        stage2

粒子属性存在名为 bar 的变量中,由 get_particle_array(additional_props=None, constants=None, backend=None, props): 设置

        默认属性 + 额外添加属性

create_equations

在当前步内计算的参数
 # Properties computed set from the current state
            Group(
                equations=[
                    # p
                    MieGruneisenEOS(dest='bar', sources=None, gamma=gamma,
                                    r0=r0, c0=C, S=S),

                    # vi,j : requires properties v00, v01, v10, v11
                    VelocityGradient2D(dest='bar', sources=['bar',]),

                    # rij : requires properties s00, s01, s11
                    VonMisesPlasticity2D(flow_stress=Yo, dest='bar',
                                         sources=None),
                    ],
                ),
1 MieGruneisenEOS        

状态方程,根据密度、内能 计算压力

2 VelocityGradient2D

计算速度梯度

输入:目标粒子及源粒子的位置、速度分量

输出:目标粒子的速度梯度

3 VonMisesPlasticity2D

屈服准则,屈服强度Y是直接输入的 Yo

检查材料的应力状态是否超过了指定的屈服应力,如果超过了,则进行塑性修正以确保应力不会超过屈服极限。

输入:直接使用dest的数据并更新,一个粒子索引及其应力张量的不同分量

输出:更新后的应力张量

计算加速度的公式组

计算加速度的第二组必须在更新压力的第一组之后进行计算。

# Acceleration variables are now computed
            Group(
                equations=[

                    # arho
                    ContinuityEquation(dest='bar', sources=['bar']),

                    # au, av
                    MomentumEquationWithStress(
                        dest='bar', sources=['bar']),

                    # au, av
                    MonaghanArtificialViscosity(
                        dest='bar', sources=['bar'], alpha=0.5, beta=0.5),

                    # au av
                    MonaghanBoundaryForce(
                        dest='bar', sources=['plate'], deltap=dx),

                    # ae
                    EnergyEquationWithStress(dest='bar', sources=['bar'],
                                             alpha=0.5, beta=0.5, eta=0.01),

                    # a_s00, a_s01, a_s11
                    HookesDeviatoricStressRate(
                        dest='bar', sources=None),

                    # ax, ay, az
                    XSPHCorrection(
                        dest='bar', sources=['bar',], eps=0.5),

                    ]

                ) # End Acceleration Group
1 ContinuityEquation

class ContinuityEquation(Equation):
    r"""Density rate:

    :math:`\frac{d\rho_a}{dt} = \sum_b m_b \boldsymbol{v}_{ab}\cdot
    \nabla_a W_{ab}`

    """
    def initialize(self, d_idx, d_arho):
        d_arho[d_idx] = 0.0


    def loop(self, d_idx, d_arho, s_idx, s_m, DWIJ, VIJ):
        vijdotdwij = DWIJ[0]*VIJ[0] + DWIJ[1]*VIJ[1] + DWIJ[2]*VIJ[2]
        d_arho[d_idx] += s_m[s_idx]*vijdotdwij

初始化 + 循环

输入:目标粒子位置、源粒子位置及质量、粒子对的核函数梯度及速度差

输出:该粒子的速度对时间的导数 

2 MomentumEquationWithStress

输入:目标粒子及源粒子的位置、密度、质量、应力、粒子对核函数的梯度、应力分量

输出:目标粒子速度对时间的导数

3 MonaghanArtificialViscosity

在动量方程补充人工粘性力,更新速度对时间的导数

4 MonaghanBoundaryForce 

边界力计算

        SPH particle boundary forces for arbitrary boundaries - ScienceDirect

5 EnergyEquationWithStress

6 HookesDeviatoricStressRate   

Jaumann

7 XSPHCorrection

输出:位置对时间的导数

时间积分用的预估-矫正法

        Predict-Evaluate-Correct(PEC)积分器类。PEC方法是一种用于求解微分方程的数值积分方法,其核心思想是在一个时间步内进行预测、评估和校正三个步骤,以提高数值积分的精度和稳定性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值