用python编写的三维电磁fdtd模拟器
fdtd的Python项目详细描述
python三维fdtd模拟器
用python编写的三维电磁fdtd模拟器。FDTD模拟器具有 可选Pythorch后端,在GPU上启用FDTD模拟。
注意:该库正在建设中。只实现了一些最小的特性 API可能会发生很大变化。
安装
fdtd
-库可以用pip
安装:
pip install fdtd
可以通过克隆存储库来安装开发版本
git clone http://github.com/flaport/fdtd
并将其与pip链接
pip install -e fdtd
依赖关系
- 巨蟒3.6+
- 努比
- matplotlib
- 全面质量管理
- Pythorch(可选)
贡献
图书馆仍处于发展的早期阶段,但所有的改进 或添加(例如新对象、源或检测器)是受欢迎的。 请提出拉取请求。
库简介
进口
fdtd库简单地导入如下:
importfdtd
设置后端
fdtd库允许选择后端。后端是 默认为一个,但也有几个额外的pytorch后端:
"numpy"
(默认为float64数组)"torch"
(默认为float64张量)"torch.float32"
"torch.float64"
"torch.cuda"
(默认为float64张量)"torch.cuda.float32"
"torch.cuda.float64"
例如,这是如何选择"torch"
后端:
fdtd.set_backend("torch")
一般来说,对于标准的CPU计算,首选使用"numpy"
后端
具有"float64"
精度。通常,精度总是
然而,对于fdtd模拟来说,优先于"float32",但是,"float32"
可能
显著提高性能。
"CUDA"
后端仅适用于带有GPU的计算机。
FDTD网格
FDTD网格定义了模拟区域。
# signaturefdtd.Grid(shape:Tuple[Number,Number,Number],grid_spacing:float=155e-9,permittivity:float=1.0,permeability:float=1.0,courant_number:float=None,)
网格是由其形状定义的,它只是
数字类型的3d元组
(整数或浮点数)。如果形状是浮点数,它表示宽度,
网格的高度和长度(以米为单位)。如果形状是整数,那么
表示网格的宽度、高度和长度
网格间距
。在内部,这些数字将转换为三个整数:
grid.nx
,grid.ny
和grid.nz
可以给出网格间距
。出于稳定性考虑,建议
选择至少比最小值小10倍的网格间距
网格中的波长。这意味着对于包含
波长1550nm
和折射率3.1
的材料,
建议的最小网格间距
为50pm
对于介电常数和磁导率 形状
(grid.nx,grid.ny,grid.nz)
- 或
(grid.nx,grid.ny,grid.nz,1)
- 或
(grid.nx,grid.ny,grid.nz,3)
是应该的。在最后一种情况下,形状意味着
每个主轴的介电常数(所谓的单轴或双轴
材料)。在内部,这些变量将被转换(为了性能
原因)它们的逆网格。介电常数逆
数组和
网格.反渗透性
形状数组(grid.nx,grid.ny,grid.nz,3)
。它
可以在生成网格后更改这些数组。
最后,网格的courant_数决定了
模拟的时间步以及网格的网格间距。如果不给,
它被选为courant friedrichs lewy允许的最大数目
条件:
1
用于1d
模拟,1/√2
用于2d
模拟,1/√3
用于3d
模拟(维度将由网格的形状导出)。为了
出于稳定性原因,建议不要更改此值。
grid=fdtd.Grid(shape=(25e-6,15e-6,1),# 25um x 15um x 1 (grid_spacing) --> 2D FDTD)print(grid)
Grid(shape=(161,97,1), grid_spacing=1.55e-07, courant_number=0.70)
将对象添加到网格
另一个选项是在
网格是将对象添加到网格中。
# signaturefdtd.Object(permittivity:Tensorlike,name:str=None)
对象使用修改后的更新公式定义网格的一部分,允许
引入例如吸收材料或双轴材料
轴之间的混合通过pockels系数或许多
更多。在这种情况下,我们将创建一个不同于
它所在的网格。
就像对于网格一样,对象
期望介电常数
是浮点数或
下列可能形状的数组
(obj.nx,obj.ny,obj.nz)
- 或
(obj.nx,obj.ny,obj.nz,1)
- 或
(obj.nx,obj.ny,obj.nz,3)
请注意,值obj.nx
,obj.ny
和obj.nz
没有给
对象构造函数。它们是从网格中的位置派生出来的:
pip install fdtd
0
这里发生了几件事。首先,物体被赋予空间
网格中的[11:32,30:84,0]
。因为给了这个空间,物体
nx
,ny
和nz
自动设置。此外,通过提供
对象,此名称将在网格中可用:
pip install fdtd
1
pip install fdtd
2
第二个对象可以添加到网格:
pip install fdtd
3
这里,选择了一个带浮点数的切片。这些漂浮物
在对象注册过程中替换为整数nx
,ny
和nz
。
由于对象没有收到名称,因此该对象将不能作为
网格的属性。但是,它仍然可以通过网格.objects获得
清单:
pip install fdtd
4
pip install fdtd
5
此列表按以下顺序存储所有对象(即fdtd.object
类型)
它们被添加到网格中。
将源添加到网格
与向网格中添加对象类似,fdtd.linesource也可以是 新增:
pip install fdtd
6
而且就像fdtd.objectfdtd.source
size一样,fdtd.source
的大小由它的
网格上的位置:
pip install fdtd
7
但是,需要注意的是,在这种情况下,会将linesource
添加到
网格,即源跨越由切片定义的立方体的对角线。
在内部,这些切片将转换为列表,以确保此行为:
pip install fdtd
8
pip install fdtd
9
注意,还可以提供列表来索引第一个网格 地点。此功能可用于创建任意 形状:
在网格中添加检测器
git clone http://github.com/flaport/fdtd
0
向网格中添加检测器的工作原理与添加源相同
git clone http://github.com/flaport/fdtd
1
git clone http://github.com/flaport/fdtd
2
git clone http://github.com/flaport/fdtd
3
添加网格边界
git clone http://github.com/flaport/fdtd
4
不过,原则上有一个对象、源和探测器来模拟
足够进行fdtd模拟,还需要定义网格边界。
以防止字段被反射。其中一个界限可以是
网格中添加了一个完全匹配的层
层或pml
。这些
基本上是吸收边界。
git clone http://github.com/flaport/fdtd
5
网格摘要
可以通过打印ou来显示网格的简单摘要t网格:
git clone http://github.com/flaport/fdtd
6
git clone http://github.com/flaport/fdtd
7
运行模拟
运行模拟就像使用grid.run
方法一样简单。
git clone http://github.com/flaport/fdtd
8
与网格中的长度一样,模拟的总时间
。
可以指定为整数(时间步数)或浮点(in
秒)。
git clone http://github.com/flaport/fdtd
9
网格可视化
让我们想象一下网格。这可以通过网格来完成。visualize
方法:
pip install -e fdtd
0
默认情况下,此方法将可视化网格中的所有对象,以及
在当前时间步
的某个x
,y
或z
-平面上通电。通过
设置show=false
,可以禁用
matplotlib图像。
pip install -e fdtd
1
背景
尽快解释麦克斯韦方程的fdtd离散化。
更新公式
电磁fdtd求解器求解含时maxwell方程组
pip install -e fdtd
2
这两个方程分别称为安培定律和法拉第定律。
在这些方程中,ε和μ是相对介电常数和磁导率张量
分别是。ε0和μ0是真空介电常数和磁导率
平方根可以分别被吸收到e和h中,使得e:=√ε0*e
以及h:=√μ0*h
这样,麦克斯韦方程可以写成更新方程:
pip install -e fdtd
3
电场和磁场可以在网格上离散 交错的yee坐标,在3d中如下所示:
根据yee离散化算法,本质上有两种类型
网格上的字段数:e
-键入整数网格位置上的字段和h
-键入
半整数网格位置上的字段。
这些交错坐标的美妙之处在于它们使 电场和磁场旋度的书写方法:旋度 h-type字段将是e-type字段,反之亦然。
这样,e的旋度可以写成
pip install -e fdtd
4
这可以用数组切片高效地编写(注意
(1/du)
被省略:
pip install -e fdtd
5
h的旋度可以用类似的方法获得(再次注意
(1/du)
被省略:
pip install -e fdtd
6
更新公式现在可以重写为
pip install -e fdtd
7
数字(c*dt/du)
是一个无量纲参数,称为courant数。为了
稳定性原因,courant数应始终小于1/√d
,且d
模拟的维度。这可以直观地理解为
这些信息在网格中的传播速度应该总是比光速慢。
在这里描述的fdtd方法中,信息只能传递到相邻的网格。
细胞(通过卷曲的应用)。因此,需要d
时间步才能
在ad
维度立方体的对角线上移动(在2d
中为正方形,在3d
中为立方体),然后
然后,courant条件自动从以下事实开始
对角线是1/√d
这将得到fdtd算法的最终更新方程:
pip install -e fdtd
8
这也是它的实现方式:
pip install -e fdtd
9
来源
安培定律可以更新为包含电流密度:
importfdtd0
再次进行通常的替换sc:=c*dt/du
,e:=√ε0*e
和h:=√μ0*h
,则
可以修改更新公式以包含current密度:
importfdtd1
进行最后一次替换es:=-dt*inv(ε)*j/√ε0
允许我们将其写入
非常干净的方式:
importfdtd2
其中,es定义为电场源项。
通常还可以定义磁场源项 由磁电流密度导出。以同样的方式, 法拉第的更新方程可以重写为
importfdtd3
importfdtd4
有损介质
当材料具有电导率σe时,传导电流将确保介质是有损耗的。带传导电流的安培定律变为
importfdtd5
进行通常的替换,这将变为:
importfdtd6
这个更新方程依赖于半整数时间步上的电场(a磁场时间步)。我们需要做一个替换,将电场插值到这个时间步:
importfdtd7
其中,在替换后σ:=inv(ε)*σe/ε0
产生新的更新方程:
importfdtd8
如果我们想跟踪吸收的能量:
请注意,介电常数张量ε越复杂,则 算法将是。因此,有时通过引入(非物理)磁导率将吸收转移到磁畴是正确的决定,因为 渗透张量μ通常等于1。
代换后,得到磁场更新方程:
importfdtd9
能量密度和poynting矢量
电磁能量密度可由
fdtd.set_backend("torch")0
在进行上述替换时,这将变为模拟单位:
fdtd.set_backend("torch")1
poynting向量由
fdtd.set_backend("torch")2
在模拟单元中变成
fdtd.set_backend("torch")3
源es
引入的能量可以通过跟踪能量密度的变化来获得
fdtd.set_backend("torch")4
这也可以从poyntings能量守恒定律中得到:
fdtd.set_backend("torch")5
其中第一项只描述能量在体积中的再分配,第二项描述能量在体积中的再分配。 电流密度产生的能量。
注:虽然它是非物理的,但也可以引入磁源。这个能量源将引入以下能量:
fdtd.set_backend("torch")6
由于μ张量通常等于1,使用磁源项通常更有效。
类似地,还可以通过以下方式跟踪导电性引起的吸收能量:
fdtd.set_backend("torch")7
或者,如果我们想跟踪磁性吸收的能量,磁传导率:
fdtd.set_backend("torch")8
能量密度中的电项和磁项通常大小相同。因此,通过引入a磁导率σm,可以吸收相同数量的能量 如果:
fdtd.set_backend("torch")9
边界条件
周期边界条件
假设我们想要沿x方向的周期性边界条件,那么我们必须
确保xlow
和xhigh
处的字段相同。必须强制执行
执行更新公式后:
请注意,电场e
取决于旋度h
,这意味着
e
的第一个索引将不会通过更新公式进行更新。
这些指标需要通过周期边界条件来设定。
具体来说:e[0]
需要设置为等于e[-1]
。对于磁场,
逆是真的:h
依赖于curl,这意味着它的最后一个索引
不会被设置。这必须通过边界条件来实现:
h[-1]
需要
设为h[0]
:
# signaturefdtd.Grid(shape:Tuple[Number,Number,Number],grid_spacing:float=155e-9,permittivity:float=1.0,permeability:float=1.0,courant_number:float=None,)0
完全匹配的层
完全匹配的层(pml)是 在fdtd网格中引入吸收边界条件。 PML是电网中阻抗匹配的吸收区域。结果发现 为了保持阻抗匹配条件,PML只能在 一个单一的方向。这就是为什么PML实际上是一种非物理材料。
考虑ez
组件的安培定律,其中通常的替换
e:=√ε0*e
,h:=√μ0*h
和σ:=inv(ε)*σe/ε0
是
已经介绍:
# signaturefdtd.Grid(shape:Tuple[Number,Number,Number],grid_spacing:float=155e-9,permittivity:float=1.0,permeability:float=1.0,courant_number:float=None,)1
这在频域中变为:
# signaturefdtd.Grid(shape:Tuple[Number,Number,Number],grid_spacing:float=155e-9,permittivity:float=1.0,permeability:float=1.0,courant_number:float=None,)2
我们可以把这个方程分为x传播波和y传播波:
# signaturefdtd.Grid(shape:Tuple[Number,Number,Number],grid_spacing:float=155e-9,permittivity:float=1.0,permeability:float=1.0,courant_number:float=None,)3
我们可以如下定义s
-运算符
# signaturefdtd.Grid(shape:Tuple[Number,Number,Number],grid_spacing:float=155e-9,permittivity:float=1.0,permeability:float=1.0,courant_number:float=None,)4
一般来说,我们倾向于将稳定因子au
和比例因子ku
添加到su
:
# signaturefdtd.Grid(shape:Tuple[Number,Number,Number],grid_spacing:float=155e-9,permittivity:float=1.0,permeability:float=1.0,courant_number:float=None,)5
将ez
的两个方程除以相应的s
-运算符后求和
# signaturefdtd.Grid(shape:Tuple[Number,Number,Number],grid_spacing:float=155e-9,permittivity:float=1.0,permeability:float=1.0,courant_number:float=None,)6
将其转换回时间域可获得
# signaturefdtd.Grid(shape:Tuple[Number,Number,Number],grid_spacing:float=155e-9,permittivity:float=1.0,permeability:float=1.0,courant_number:float=None,)7
其中,sx
表示(1/sx)
的逆傅里叶变换,[*]
表示卷积。
su
的表达式[经过一些推导]可以证明如下:
# signaturefdtd.Grid(shape:Tuple[Number,Number,Number],grid_spacing:float=155e-9,permittivity:float=1.0,permeability:float=1.0,courant_number:float=None,)8
式中,δ(t)
表示狄拉克δ函数,c(t)
指数
衰减函数由:
# signaturefdtd.Grid(shape:Tuple[Number,Number,Number],grid_spacing:float=155e-9,permittivity:float=1.0,permeability:float=1.0,courant_number:float=None,)9
插入此选项将得到:
grid=fdtd.Grid(shape=(25e-6,15e-6,1),# 25um x 15um x 1 (grid_spacing) --> 2D FDTD)print(grid)0
这可以写成一个更新公式:
grid=fdtd.Grid(shape=(25e-6,15e-6,1),# 25um x 15um x 1 (grid_spacing) --> 2D FDTD)print(grid)1
其中我们将Фeu
定义为
grid=fdtd.Grid(shape=(25e-6,15e-6,1),# 25um x 15um x 1 (grid_spacing) --> 2D FDTD)print(grid)2
并取v
方向上hw
的导数,作为更新分量eu
的卷积:
grid=fdtd.Grid(shape=(25e-6,15e-6,1),# 25um x 15um x 1 (grid_spacing) --> 2D FDTD)print(grid)3
这可以重写[经过一些推导]作为更新方程本身:
grid=fdtd.Grid(shape=(25e-6,15e-6,1),# 25um x 15um x 1 (grid_spacing) --> 2D FDTD)print(grid)4
其中,常数bu
和cu
导出为:
grid=fdtd.Grid(shape=(25e-6,15e-6,1),# 25um x 15um x 1 (grid_spacing) --> 2D FDTD)print(grid)5
电场的最终pml算法现在变成:
- 通过使用
Ψ
-组件的更新方程,更新Фe=[Фex,Фey,Фez]
。 - 以正常方式更新电场
- 将
Фe
加到电场中。 < > >
或者作为python代码:
grid=fdtd.Grid(shape=(25e-6,15e-6,1),# 25um x 15um x 1 (grid_spacing) --> 2D FDTD)print(grid)6
同样的方法也适用于磁场。
PML的这些更新公式基于Schneider,第11章 ?Floris Laporte-麻省理工学院许可证许可证
推荐PyPI第三方库