Python 3D FDTD模拟器

Python 3D FDTD模拟器

翻译自:https://github.com/flaport/fdtd
未获得作者翻译授权,只是为方便自己查看。

一个用Python编写的三维电磁FDTD模拟器。FDTD模拟器有一个可选的PyTorch后端,支持GPU上的FDTD模拟。

安装

fdtd库可以用pip安装:

pip install fdtd

可以通过克隆存储库来安装开发版本:

git clone http://github.com/flaport/fdtd

并与pip连接

pip install -e fdtd

可以安装开发依赖项:

pip install -e fdtd[dev]

依赖项

  • python 3.6+
  • numpy
  • scipy
  • matplotlib
  • tqdm
  • pytorch (optional)

贡献

欢迎所有改进或添加(例如新的对象、源或检测器)。请提出拉拔请求 。

文档

在这里阅读文档: https://fdtd.readthedocs.org

导入

fdtd库简单地导入如下:

import fdtd

设置后端

fdtd库允许选择后端。numpy后端是默认的,但也有几个额外的PyTorch后端:

  • "numpy" (默认为float64数组)
  • "torch" (默认为float64数组)
  • "torch.float32"
  • "torch.float64"
  • "torch.cuda" (默认为float64数组)
  • "torch.cuda.float32"
  • "torch.cuda.float64"

例如,这是如何选择torch后端:

fdtd.set_backend("torch")

一般来说,numpy后端首选用于具有float64精度的标准CPU计算。一般来说,在FDTD模拟中,float64的精度总是优于float32,然而,float32可能会提供显著的性能提升。

cuda后端只适用于带有GPU的计算机。

FDTD网格

FDTD网格定义了仿真区域。

# signature
fdtd.Grid(
    shape: Tuple[Number, Number, Number],
    grid_spacing: float = 155e-9,
    permittivity: float = 1.0,
    permeability: float = 1.0,
    courant_number: float = None,
)

网格是由它的shape定义的,它只是一个Number类型(整数或浮点数)的3D元组。如果形状以浮动形式给出,则表示网格的宽度、高度和长度(以米为单位)。如果形状以整数形式给出,则用grid_spacing表示网格的宽度、高度和长度。在内部,这些数字将被转换为三个整数:grid.Nx, grid.Nygrid.Nz

可以给出一个grid_spacing。出于稳定性考虑,建议选择比网格中最小波长至少小10倍的网格间距。这意味着对于包含波长为1550nm的光源和折射率为3.1的材料的栅格,推荐的grid_spacing间距是50pm

对于有一下形式的permittivitypermeability 的浮点数或数组:

  • (grid.Nx, grid.Ny, grid.Nz)
  • or (grid.Nx, grid.Ny, grid.Nz, 1)
  • or (grid.Nx, grid.Ny, grid.Nz, 3)

在最后一种情况下,这种形状暗示了每个长轴(所谓的单轴或双轴材料)的不同介电常数的可能性。在内部,这些变量将(出于性能原因)转换为它们的反向 grid.inverse_permittivity阵列和grid.inverse_permeability阵列的形状(grid.Nx, grid.Ny, grid.Nz, 3)。在制作网格之后,可以改变这些数组。

最后,网格的courant_number决定了仿真的time_stepgrid_spacing之间的关系。如果没有给出,则选择为 Courant-Friedrichs-Lewy Condition所允许的最大值:
11D 模拟, 1/√22D 模拟 , 1/√33D模拟 (根据网格的形状计算维数)。出于稳定性考虑,建议不要更改此值。

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)

向网格中添加对象

另一种局部改变栅极 permittivitypermeability的方法是向栅极添加一个Object

# signature
fdtd.Object(
    permittivity: Tensorlike,
    name: str = None
)

一个对象用修改的更新方程定义网格的一部分,允许引入例如吸收材料或双轴材料,轴之间的混合通过Pockels coefficients或更多。在这种情况下,我们将使一个物体的permittivity不同于它所在的网格。

就像网格一样,Object期望permittivity为float或以下可能形状的数组

  • (obj.Nx, obj.Ny, obj.Nz)
  • or (obj.Nx, obj.Ny, obj.Nz, 1)
  • or (obj.Nx, obj.Ny, obj.Nz, 3)

注意, obj.Nx, obj.Ny and obj.Nz 没有给出给对象构造函数。它们是从它在网格中的位置派生出来的:

grid[11:32, 30:84, 0] = fdtd.Object(permittivity=1.7**2, name="object")

这里发生了几件事。首先,对象在网格中被赋予空间[11:32,30:84,0]。因为它被赋予了这个空间,对象的NxNyNz会被自动设置。此外,通过为对象提供一个名称,该名称将在网格中可用:

print(grid.object)
    Object(name='object')
        @ x=11:32, y=30:84, z=0:1

第二个对象可以添加到网格中:

grid[13e-6:18e-6, 5e-6:8e-6, 0] = fdtd.Object(permittivity=1.5**2)

这里选择了一个带有浮点数的切片。在对象注册期间,这些浮点数将被整数NxNyNz替换。由于该对象没有接收到名称,因此该对象不能作为网格的属性使用。然而,它仍然可以通过 grid.objects 列表:

print(grid.objects)
[Object(name='object'), Object(name=None)]

这个列表存储所有对象(例如类型为fdtd.Object的对象),按照它们被添加到网格的顺序

向网格中添加一个源

类似于将对象添加到网格中,一个fdtd.LineSource也可以添加:

# signature
fdtd.LineSource(
    period: Number = 15, # timesteps or seconds
    power: float = 1.0,
    phase_shift: float = 0.0,
    name: str = None,
)

就像fdtd.Object一样,一个fdtd.LineSource 的大小由它在网格中的位置来定义:

grid[7.5e-6:8.0e-6, 11.8e-6:13.0e-6, 0] = fdtd.LineSource(
    period = 1550e-9 / (3e8), name="source"
)

然而,需要注意的是,在这种情况下,一个LineSource被添加到网格中,也就是说,源跨越了由切片定义的立方体的对角线。在内部,这些片将被转换为列表,以确保以下行为:

print(grid.source)
    LineSource(period=14, power=1.0, phase_shift=0.0, name='source')
        @ x=[48, ... , 51], y=[76, ... , 83], z=[0, ... , 0]

请注意,我们也可以首先提供列表来索引网格。这个特性对于创建任意形状的LineSource非常有用。

给网格添加一个检测器

# signature
fdtd.LineDetector(
    name=None
)

向网格中添加检测器的工作原理与添加源相同

grid[12e-6, :, 0] = fdtd.LineDetector(name="detector")
print(grid.detector)
    LineDetector(name='detector')
        @ x=[77, ... , 77], y=[0, ... , 96], z=[0, ... , 0]

添加网格边界

# signature
fdtd.PML(
    a: float = 1e-8, # stability factor
    name: str = None
)

虽然,有一个对象,源和探测器,以进行FDTD模拟在原则上是足够的,人们还需要定义一个网格边界,以防止场被反射。其中一个可以添加到网格的边界是 Perfectly Matched Layer or PML完美匹配层。这些基本上是吸收边界。

# x boundaries
grid[0:10, :, :] = fdtd.PML(name="pml_xlow")
grid[-10:, :, :] = fdtd.PML(name="pml_xhigh")

# y boundaries
grid[:, 0:10, :] = fdtd.PML(name="pml_ylow")
grid[:, -10:, :] = fdtd.PML(name="pml_yhigh")

网格的总结

可以通过打印出网格来显示网格的简单摘要:

print(grid)
Grid(shape=(161,97,1), grid_spacing=1.55e-07, courant_number=0.70)

sources:
    LineSource(period=14, power=1.0, phase_shift=0.0, name='source')
        @ x=[48, ... , 51], y=[76, ... , 83], z=[0, ... , 0]

detectors:
    LineDetector(name='detector')
        @ x=[77, ... , 77], y=[0, ... , 96], z=[0, ... , 0]

boundaries:
    PML(name='pml_xlow')
        @ x=0:10, y=:, z=:
    PML(name='pml_xhigh')
        @ x=-10:, y=:, z=:
    PML(name='pml_ylow')
        @ x=:, y=0:10, z=:
    PML(name='pml_yhigh')
        @ x=:, y=-10:, z=:

objects:
    Object(name='object')
        @ x=11:32, y=30:84, z=0:1
    Object(name=None)
        @ x=84:116, y=32:52, z=0:1

运行一个仿真

运行一个模拟就像使用grid.run方法一样简单。

grid.run(
    total_time: Number,
    progress_bar: bool = True
)

与网格中的长度一样,模拟的total_time可以指定为整数(time_steps的数量)或浮点数(以秒为单位)。

grid.run(total_time=100)

网格可视化

Le让我们把网格形象化。这可以通过grid.visualize来实现方法:

# signature
grid.visualize(
    grid,
    x=None,
    y=None,
    z=None,
    cmap="Blues",
    pbcolor="C3",
    pmlcolor=(0, 0, 0, 0.1),
    objcolor=(1, 0, 

你可能感兴趣的:(FDTD,python,深度学习,pytorch)