基于MindFlow定义符号化偏微分方程
偏微分方程(PDE)在工程应用中发挥着重要作用,大多数控制系统和人造复杂系统的物理学都是有PDE描述的。本文介绍如何基于MindFlow使用sympy定义PDE,构建基于物理神经网络(Physics-Informed Neural Networks,PINNs)的问题求解模型。利用 mindflow.pde.PDEWithLoss ,可以很容易以符号形式描绘偏微分方程,并计算所有方程的损失。这使得方程的描述简洁易懂,易于扩展。用户可继承 mindflow.pde.PDEWithLoss 实现自定义偏微分方程。
问题建模样例
下面的 CylinderFlow
定义了二维非定常圆柱绕流问题。具体来说,它包括上面定义的三个部分:控制方程、初始条件和边界条件。
NavierStokes
基类,定义了输入和输出变量,以及控制方程。
用户可以通过重写 NavierStokes
类定义其他控制方程。
[6]:
from mindspore import nn
from mindflow.pde import PDEWithLoss
class NavierStokes(PDEWithLoss):
def __init__(self, model, re=100, loss_fn=nn.MSELoss()):
self.number = np.float32(1.0 / re)
self.x, self.y, self.t = symbols('x y t')
self.u = Function('u')(self.x, self.y, self.t)
self.v = Function('v')(self.x, self.y, self.t)
self.p = Function('p')(self.x, self.y, self.t)
self.in_vars = [self.x, self.y, self.t]
self.out_vars = [self.u, self.v, self.p]
super(NavierStokes, self).__init__(model, self.in_vars, self.out_vars)
self.loss_fn = loss_fn
def pde(self):
momentum_x = self.u.diff(self.t) + self.u * self.u.diff(self.x) + self.v * self.u.diff(self.y) +\
self.p.diff(self.x) - self.number * (diff(self.u, (self.x, 2)) + diff(self.u, (self.y, 2)))
momentum_y = self.v.diff(self.t) + self.u * self.v.diff(self.x) + self.v * self.v.diff(self.y) +\
self.p.diff(self.y) - self.number * (diff(self.v, (self.x, 2)) + diff(self.v, (self.y, 2)))
continuty = self.u.diff(self.x) + self.v.diff(self.y)
equations = {"momentum_x": momentum_x, "momentum_y": momentum_y, "continuty": continuty}
return equations
下面,我们使用 NavierStokes
基类定义初始条件和边界条件,以及损失函数。
[7]:
from mindspore import nn, ops, Tensor
from mindspore import dtype as mstype
from mindflow.pde import PDEWithLoss, NavierStokes, sympy_to_mindspore
class CylinderFlow(NavierStokes):
def __init__(self, model, re=100, loss_fn=nn.MSELoss()):
super(CylinderFlow, self).__init__(model, re=re, loss_fn=loss_fn)
self.ic_nodes = sympy_to_mindspore(self.ic(), self.in_vars, self.out_vars)
self.bc_nodes = sympy_to_mindspore(self.bc(), self.in_vars, self.out_vars)
def bc(self):
bc_u = self.u
bc_v = self.v
equations = {"bc_u": bc_u, "bc_v": bc_v}
return equations
def ic(self):
ic_u = self.u
ic_v = self.v
ic_p = self.p
equations = {"ic_u": ic_u, "ic_v": ic_v, "ic_p": ic_p}
return equations
def get_loss(self, pde_data, bc_data, bc_label, ic_data, ic_label):
pde_res = self.parse_node(self.pde_nodes, inputs=pde_data)
pde_residual = ops.Concat(1)(pde_res)
pde_loss = self.loss_fn(pde_residual, Tensor(np.array([0.0]).astype(np.float32), mstype.float32))
ic_res = self.parse_node(self.ic_nodes, inputs=ic_data)
ic_residual = ops.Concat(1)(ic_res)
ic_loss = self.loss_fn(ic_residual, ic_label)
bc_res = self.parse_node(self.bc_nodes, inputs=bc_data)
bc_residual = ops.Concat(1)(bc_res)
bc_loss = self.loss_fn(bc_residual, bc_label)
return pde_loss + ic_loss + bc_loss
Neumann边界条件定义样例
在数学中,Neumann边界条件也被称为常微分方程或偏微分方程的“第二类边界条件”。Neumann边界条件指定微分方程解边界处的微分。
下述 Poisson2D
问题定义了Dirichlet边界条件(bc_outer
)和Neumann边界条件(bc_inner
)。
[8]:
import sympy
from mindflow.pde import Poisson
class Poisson2D(Poisson):
def __init__(self, model, loss_fn=nn.MSELoss()):
super(Poisson2D, self).__init__(model, loss_fn=loss_fn)
self.bc_outer_nodes = sympy_to_mindspore(self.bc_outer(), self.in_vars, self.out_vars)
self.bc_inner_nodes = sympy_to_mindspore(self.bc_inner(), self.in_vars, self.out_vars)
def bc_outer(self):
bc_outer_eq = self.u
equations = {"bc_outer": bc_outer_eq}
return equations
def bc_inner(self):
bc_inner_eq = sympy.Derivative(self.u, self.normal) - 0.5
equations = {"bc_inner": bc_inner_eq}
return equations
def get_loss(self, pde_data, bc_outer_data, bc_inner_data, bc_inner_normal):
pde_res = self.parse_node(self.pde_nodes, inputs=pde_data)
pde_loss = self.loss_fn(pde_res[0], Tensor(np.array([0.0]), mstype.float32))
bc_inner_res = self.parse_node(self.bc_inner_nodes, inputs=bc_inner_data, norm=bc_inner_normal)
bc_inner_loss = self.loss_fn(bc_inner_res[0], Tensor(np.array([0.0]), mstype.float32))
bc_outer_res = self.parse_node(self.bc_outer_nodes, inputs=bc_outer_data)
bc_outer_loss = self.loss_fn(bc_outer_res[0], Tensor(np.array([0.0]), mstype.float32))
return pde_loss + bc_inner_loss + bc_outer_loss