Bohrium
robot
新建

空间站广场

论文
Notebooks
比赛
课程
Apps
我的主页
我的Notebooks
我的论文库
我的足迹

我的工作空间

任务
节点
文件
数据集
镜像
项目
数据库
公开
不同材料abTEM仿真
STEM
AI4S
STEMAI4S
OrangeFree
发布于 2023-09-21
推荐镜像 :Basic Image:ubuntu20.04-py3.10-cuda11.6
推荐机型 :c12_m92_1 * NVIDIA V100
赞 2
1
1. MoS2仿真
创建原子模型
存为cif文件
S原子随机缺失
存为cif文件
创建仿真图像
无缺陷
有缺陷
2. 不同材料仿真
批量生成
[1]
!pip install abtem==1.0.0b34
!pip install ase
!pip install cupy-cuda116
from ase import Atoms
from ase.build import mx2
from abtem import show_atoms
from abtem.structures import orthogonalize_cell

from ase.io import read, write
import os
import matplotlib.pyplot as plt
import numpy as np
import random
import pickle
import cupy as cp

from abtem import Probe, GridScan, Potential
from abtem import *

def show_atoms_top_and_side_view(atoms):
fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(12,4))

show_atoms(atoms, ax=ax1, title='Top view')
show_atoms(atoms, ax=ax2, plane='xz', title='Side view')
show_atoms(atoms, ax=ax3, plane='yz', title='Side view')
Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
Collecting abtem==1.0.0b34
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/23/bb/30276edd8e67b845498b259e7200bd3cf11b372258dbb74a9911501f02de/abtem-1.0.0b34-py3-none-any.whl (540 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 540.7/540.7 kB 7.3 MB/s eta 0:00:0000:0100:01
Requirement already satisfied: psutil in /opt/mamba/lib/python3.10/site-packages (from abtem==1.0.0b34) (5.9.4)
Collecting pyfftw
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/2d/0b/892b876ce00b4aa592d820867970de8e761eb71637ba74b5049f7f9fd46d/pyFFTW-0.13.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.4 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2.4/2.4 MB 26.6 MB/s eta 0:00:00a 0:00:01
Collecting ase
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/38/b0/3c0a7afaf66274588216c251376ac2bea0269eb7a5e1da77521811060553/ase-3.22.1-py3-none-any.whl (2.2 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2.2/2.2 MB 42.6 MB/s eta 0:00:00a 0:00:01
Collecting imageio
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/1a/55/7a7646d7cc42e771d689d39930afcbe57b3d82267544ebabead57ffb86d1/imageio-2.31.4-py3-none-any.whl (313 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 313.2/313.2 kB 7.3 MB/s eta 0:00:00a 0:00:01
Requirement already satisfied: scipy in /opt/mamba/lib/python3.10/site-packages (from abtem==1.0.0b34) (1.10.1)
Requirement already satisfied: h5py in /opt/mamba/lib/python3.10/site-packages (from abtem==1.0.0b34) (3.8.0)
Requirement already satisfied: numpy in /opt/mamba/lib/python3.10/site-packages (from abtem==1.0.0b34) (1.24.2)
Collecting matplotlib
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/b5/24/aaccf324ce862bb82277e8814d2aebbb2a2c160d04e95aa2b8c9dc3137a9/matplotlib-3.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (11.6 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 11.6/11.6 MB 67.1 MB/s eta 0:00:0000:0100:01
Requirement already satisfied: tqdm in /opt/mamba/lib/python3.10/site-packages (from abtem==1.0.0b34) (4.64.1)
Collecting numba
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/e7/69/d228b38ffb70858d74538bdfe5aa18c7640b7f07840239690985b3a94009/numba-0.58.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (3.6 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3.6/3.6 MB 43.4 MB/s eta 0:00:0000:01m
Collecting cycler>=0.10
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/5c/f9/695d6bedebd747e5eb0fe8fad57b72fdf25411273a39791cde838d5a8f51/cycler-0.11.0-py3-none-any.whl (6.4 kB)
Collecting contourpy>=1.0.1
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/f1/6b/e4b0f8708f22dd7c321f87eadbb98708975e115ac6582eb46d1f32197ce6/contourpy-1.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (301 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 301.7/301.7 kB 7.1 MB/s eta 0:00:00a 0:00:01
Requirement already satisfied: python-dateutil>=2.7 in /opt/mamba/lib/python3.10/site-packages (from matplotlib->abtem==1.0.0b34) (2.8.2)
Requirement already satisfied: packaging>=20.0 in /opt/mamba/lib/python3.10/site-packages (from matplotlib->abtem==1.0.0b34) (23.0)
Collecting pillow>=6.2.0
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/7a/07/e896b096a77375e78e02ce222ae4fd6014928cd76c691d312060a1645dfa/Pillow-10.0.1-cp310-cp310-manylinux_2_28_x86_64.whl (3.6 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3.6/3.6 MB 79.5 MB/s eta 0:00:00:00:01
Collecting pyparsing>=2.3.1
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/39/92/8486ede85fcc088f1b3dba4ce92dd29d126fd96b0008ea213167940a2475/pyparsing-3.1.1-py3-none-any.whl (103 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 103.1/103.1 kB 2.3 MB/s eta 0:00:00a 0:00:01
Collecting kiwisolver>=1.0.1
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/6f/40/4ab1fdb57fced80ce5903f04ae1aed7c1d5939dda4fd0c0aa526c12fe28a/kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl (1.6 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.6/1.6 MB 82.3 MB/s eta 0:00:00
Collecting fonttools>=4.22.0
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/2b/e8/61b8525acf26ec222518bdff127ae502bfa3408981fb5e5493f2b037d7fb/fonttools-4.42.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (4.5 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4.5/4.5 MB 42.0 MB/s eta 0:00:0000:01:00:01
Collecting llvmlite<0.42,>=0.41.0dev0
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/50/df/38c9fb5cc64f4fcc0577a14a0665c2a5de74f45a621ac7708320b1ac80c6/llvmlite-0.41.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (43.6 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 43.6/43.6 MB 15.1 MB/s eta 0:00:0000:0100:01
Requirement already satisfied: six>=1.5 in /opt/mamba/lib/python3.10/site-packages (from python-dateutil>=2.7->matplotlib->abtem==1.0.0b34) (1.16.0)
Installing collected packages: pyparsing, pyfftw, pillow, llvmlite, kiwisolver, fonttools, cycler, contourpy, numba, matplotlib, imageio, ase, abtem
Successfully installed abtem-1.0.0b34 ase-3.22.1 contourpy-1.1.1 cycler-0.11.0 fonttools-4.42.1 imageio-2.31.4 kiwisolver-1.4.5 llvmlite-0.41.0 matplotlib-3.8.0 numba-0.58.0 pillow-10.0.1 pyfftw-0.13.1 pyparsing-3.1.1
WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
Requirement already satisfied: ase in /opt/mamba/lib/python3.10/site-packages (3.22.1)
Requirement already satisfied: numpy>=1.15.0 in /opt/mamba/lib/python3.10/site-packages (from ase) (1.24.2)
Requirement already satisfied: scipy>=1.1.0 in /opt/mamba/lib/python3.10/site-packages (from ase) (1.10.1)
Requirement already satisfied: matplotlib>=3.1.0 in /opt/mamba/lib/python3.10/site-packages (from ase) (3.8.0)
Requirement already satisfied: pyparsing>=2.3.1 in /opt/mamba/lib/python3.10/site-packages (from matplotlib>=3.1.0->ase) (3.1.1)
Requirement already satisfied: contourpy>=1.0.1 in /opt/mamba/lib/python3.10/site-packages (from matplotlib>=3.1.0->ase) (1.1.1)
Requirement already satisfied: python-dateutil>=2.7 in /opt/mamba/lib/python3.10/site-packages (from matplotlib>=3.1.0->ase) (2.8.2)
Requirement already satisfied: pillow>=6.2.0 in /opt/mamba/lib/python3.10/site-packages (from matplotlib>=3.1.0->ase) (10.0.1)
Requirement already satisfied: kiwisolver>=1.0.1 in /opt/mamba/lib/python3.10/site-packages (from matplotlib>=3.1.0->ase) (1.4.5)
Requirement already satisfied: packaging>=20.0 in /opt/mamba/lib/python3.10/site-packages (from matplotlib>=3.1.0->ase) (23.0)
Requirement already satisfied: cycler>=0.10 in /opt/mamba/lib/python3.10/site-packages (from matplotlib>=3.1.0->ase) (0.11.0)
Requirement already satisfied: fonttools>=4.22.0 in /opt/mamba/lib/python3.10/site-packages (from matplotlib>=3.1.0->ase) (4.42.1)
Requirement already satisfied: six>=1.5 in /opt/mamba/lib/python3.10/site-packages (from python-dateutil>=2.7->matplotlib>=3.1.0->ase) (1.16.0)
WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
Collecting cupy-cuda116
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/9a/df/465470beb6c3f62dffba2b696c0967601eb3cc15d83ef9244785a25c1d79/cupy_cuda116-10.6.0-cp310-cp310-manylinux1_x86_64.whl (81.6 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 81.6/81.6 MB 12.5 MB/s eta 0:00:0000:0100:01
Collecting fastrlock>=0.5
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/bc/5d/d1f89b59f5b4b4710fd126e0df31ca4c58f46fc0a831058fc49010972d3d/fastrlock-0.8.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl (51 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 51.3/51.3 kB 14.9 MB/s eta 0:00:00
Requirement already satisfied: numpy<1.25,>=1.18 in /opt/mamba/lib/python3.10/site-packages (from cupy-cuda116) (1.24.2)
Installing collected packages: fastrlock, cupy-cuda116
Successfully installed cupy-cuda116-10.6.0 fastrlock-0.8.2
WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
/opt/mamba/lib/python3.10/site-packages/tqdm/auto.py:22: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
  from .autonotebook import tqdm as notebook_tqdm
代码
文本
[20]
# import abtem
# print(abtem.__version__)
# from abtem import structures
代码
文本

1. MoS2仿真

创建原子模型

代码
文本
[2]
# 使用ASE的mx2函数创建一个MoS2结构。这个结构是2H型的,晶格常数为3.18,厚度为3.19
atoms = mx2(formula='MoS2', kind='2H', a=3.19, thickness=3.35, size=(1, 1, 1), vacuum=None)
repetitions = (6, 4, 1)# 在x和y方向上分别有6个和4个单位的重复
atoms *= repetitions
atoms = orthogonalize_cell(atoms)# 将原子结构转化为正交晶胞。这是为了方便后续的模拟计算。
atoms.center(vacuum=1, axis=2)# 将原子结构中心化,以便于在模拟中观察
# show_atoms(atoms)# 使用abTEM自带的函数画出模型

show_atoms_top_and_side_view(atoms)
代码
文本

由此就完成了可以输入进abTEM的原子模型构建。当然,这是最简单的情况,如果想要更符合实际,我们可以在后续生成图像时添加一些热运动引起的原子位置随机抖动,应力引起的扭曲等等。

代码
文本

存为cif文件

代码
文本
[3]
os.makedirs('/data/abtem/', exist_ok=True)
write('/data/abtem/mos2.cif', atoms)
代码
文本

S原子随机缺失

代码
文本
[4]
# 每个位置的原子序数
atoms_ele_num = atoms.arrays['numbers']
# 每个原子的坐标
atoms_positions = atoms.arrays['positions']

# s原子的序数为16,se原子序数为34
S = 16
Se = 34
代码
文本
[5]
# 找出S/Se原子所在序列
S_index = np.where(atoms_ele_num== S)[0]
# S_index = np.where(atoms_ele_num== Se)[0]

# 找出S原子的所有坐标, numpy array [n,3]
S_positions = atoms_positions[S_index]

# 设置S原子缺失的比例
defect_ratio = 0.3
S_cnt = len(S_index)

# 随机生成要删除的s原子
S_delete_cnt = random.randint(1, int(S_cnt*defect_ratio))
S_delete_index = S_index[random.sample(range(S_cnt), S_delete_cnt)]

print('deleted S index',S_delete_index)

# 删除对应的s原子
atoms_ele_num_modified = np.delete(atoms_ele_num,S_delete_index)
atoms_positions_modified = np.delete(atoms_positions,S_delete_index,axis=0)

# 构建新的模型
atoms_modified = atoms.copy()
atoms_modified.arrays['numbers'] = atoms_ele_num_modified
atoms_modified.arrays['positions'] = atoms_positions_modified

# 显示新原子模型
show_atoms_top_and_side_view(atoms_modified)
代码
文本
[6]
# 删除的s原子的z坐标
deleted_z_axis = np.array([atoms_positions[del_idx][2] for del_idx in S_delete_index])

# 计算s原子z坐标的平均值,大于该值的为上层s原子,小于该值的为下层s原子
mean_z_axis = np.array([z_axis[2] for z_axis in S_positions]).mean()

# 得到删除的上层/下层s原子
upper_indexs = S_delete_index[np.where(deleted_z_axis > mean_z_axis)[0]]
lower_indexs = S_delete_index[np.where(deleted_z_axis < mean_z_axis)[0]]

print('s delete indexs', S_delete_index)
print('delete position', atoms_positions[S_delete_index])
print('upper_indexs',upper_indexs)
print('lower_indexs', lower_indexs)

# 搜索双s原子都缺失的位置
double_indexs = []

for upper_index in upper_indexs:
x0 = atoms_positions[upper_index][0]
y0 = atoms_positions[upper_index][1]
for lower_index in lower_indexs:
x1 = atoms_positions[lower_index][0]
y1 = atoms_positions[lower_index][1]
if (abs(x0-x1)<0.1 and abs(y0-y1)<0.1):
double_indexs.append(upper_index)
double_indexs.append(lower_index)

# 双s原子缺失
atoms_double = atoms.copy()

ele_double = atoms_ele_num[double_indexs]
positions_double = atoms_positions[double_indexs]
atoms_double.arrays['numbers'] = ele_double
atoms_double.arrays['positions'] = positions_double

# 上层s原子缺失
atoms_upper = atoms.copy()
upper_indexs = [i for i in upper_indexs if i not in double_indexs]

ele_upper = atoms_ele_num[upper_indexs]
positions_upper = atoms_positions[upper_indexs]
atoms_upper.arrays['numbers'] = ele_upper
atoms_upper.arrays['positions'] = positions_upper

# 下层s原子缺失
atoms_lower = atoms.copy()
lower_indexs = [i for i in lower_indexs if i not in double_indexs]

ele_lower = atoms_ele_num[lower_indexs]
positions_lower = atoms_positions[lower_indexs]
atoms_lower.arrays['numbers'] = ele_lower
atoms_lower.arrays['positions'] = positions_lower

print('upper_indexs',upper_indexs)
print('lower_indexs', lower_indexs)
print('double_index', double_indexs)
s delete indexs [ 44  45 103   1 107  50 165 106 110 132 188 162  39  12 176  56  18 180
 147 122  88  42  47  59  93 192 158  23 203 125  74 108]
delete position [[ 1.27600000e+01  3.68349472e+00  4.35000000e+00]
 [ 1.27600000e+01  3.68349472e+00  1.00000000e+00]
 [ 6.38000000e+00  2.02592209e+01  1.00000000e+00]
 [ 1.59500000e+00  9.20873679e-01  4.35000000e+00]
 [-7.39518594e-16  2.57844630e+01  4.35000000e+00]
 [ 9.57000000e+00  9.20873679e+00  4.35000000e+00]
 [ 6.38000000e+00  2.57844630e+01  1.00000000e+00]
 [ 1.59500000e+00  2.30218420e+01  1.00000000e+00]
 [ 4.78500000e+00  2.30218420e+01  4.35000000e+00]
 [ 1.27600000e+01  1.47339789e+01  4.35000000e+00]
 [ 1.27600000e+01  2.57844630e+01  4.35000000e+00]
 [ 7.97500000e+00  2.30218420e+01  1.00000000e+00]
 [ 6.38000000e+00  9.20873679e+00  1.00000000e+00]
 [ 1.59500000e+00  6.44611576e+00  4.35000000e+00]
 [ 9.57000000e+00  2.57844630e+01  4.35000000e+00]
 [ 1.59500000e+01  3.68349472e+00  4.35000000e+00]
 [ 7.97500000e+00  9.20873679e-01  1.00000000e+00]
 [ 7.97500000e+00  2.85470841e+01  1.00000000e+00]
 [ 1.43550000e+01  1.74965999e+01  4.35000000e+00]
 [ 1.75450000e+01  6.44611576e+00  4.35000000e+00]
 [ 4.78500000e+00  1.74965999e+01  1.00000000e+00]
 [ 1.43550000e+01  9.20873679e-01  1.00000000e+00]
 [ 1.11650000e+01  6.44611576e+00  4.35000000e+00]
 [ 1.43550000e+01  6.44611576e+00  4.35000000e+00]
 [ 1.11650000e+01  1.19713578e+01  4.35000000e+00]
 [ 1.11650000e+01  2.85470841e+01  1.00000000e+00]
 [ 1.59500000e+01  2.02592209e+01  1.00000000e+00]
 [ 4.78500000e+00  6.44611576e+00  4.35000000e+00]
 [ 1.43550000e+01  2.85470841e+01  4.35000000e+00]
 [ 1.59500000e+01  9.20873679e+00  4.35000000e+00]
 [ 3.19000000e+00  1.47339789e+01  1.00000000e+00]
 [-7.39518594e-16  2.57844630e+01  1.00000000e+00]]
upper_indexs [ 44   1 107  50 110 132 188  12 176  56 147 122  47  59  93  23 203 125]
lower_indexs [ 45 103 165 106 162  39  18 180  88  42 192 158  74 108]
upper_indexs [1, 50, 110, 132, 188, 12, 176, 56, 147, 122, 47, 59, 93, 23, 203, 125]
lower_indexs [103, 165, 106, 162, 39, 18, 180, 88, 42, 192, 158, 74]
double_index [44, 45, 107, 108]
代码
文本
[7]
# 可视化s/se原子缺失的位置
fig,axes=plt.subplots(figsize=(7,8))
plt.scatter(positions_upper[:, 0], positions_upper[:, 1], marker='o',label='upper S atoms')
plt.scatter(positions_lower[:, 0], positions_lower[:, 1], marker='>',label='lower S atoms')
plt.scatter(positions_double[:, 0],positions_double[:, 1], c='r', marker='*',label='double_S atoms')
# plt.scatter(positions_upper[:, 0], positions_upper[:, 1], marker='o',label='upper Se atoms')
# plt.scatter(positions_lower[:, 0], positions_lower[:, 1], marker='>',label='lower Se atoms')
# plt.scatter(positions_double[:, 0],positions_double[:, 1], c='r', marker='*',label='double_Se atoms')
axes.set_xlabel('angstrom',fontsize=15)
axes.set_ylabel('angstrom',fontsize=15)
axes.legend()
代码
文本
[8]
show_atoms_top_and_side_view(atoms_modified)
show_atoms_top_and_side_view(atoms_lower)
show_atoms_top_and_side_view(atoms_upper)
show_atoms_top_and_side_view(atoms_double)
代码
文本

存为cif文件

代码
文本
[9]
os.makedirs('/data/abtem/', exist_ok=True)
write('/data/abtem/mos2_defection.cif', atoms_modified)
# with open('/data/abtem/mos2.cif', 'r') as f:
# data = f.read()
# print(data)# 查看cif文件,它存储了晶胞的各种参数以及每个原子的位置信息
代码
文本

创建仿真图像

无缺陷

代码
文本
[10]
# 配置冻结声子模型的参数
sigmas={'Mo':.1,'S':.1}# Mo和S的热振动标准差,值越大,原子热振动越剧烈
num_configs=30
# 创建冻结声子模型
frozen_phonon=FrozenPhonons(atoms,num_configs=num_configs,sigmas=sigmas)
# 计算电子和原子核的库仑势,用于定量图像模拟
slice_thickness=2 # 多层切片方法的每一层的间隔(A)
sampling_poten=0.1 # x-y网格精度(A)
potential = Potential(frozen_phonon,
sampling=sampling_poten,
projection='infinite',
slice_thickness=slice_thickness,
parametrization='kirkland').build()

# 构建电子探针
energy_EM=80e3 # 电压(V)
conv_angle=30 # 收敛角(mrad)
df=0 # 散焦(A)
C30=0 # 球差(A)
probe = Probe(energy=energy_EM, semiangle_cutoff=conv_angle,defocus=df,C30=C30, device='gpu')
# 将电子探针的网格与库仑势相匹配
probe.grid.match(potential)

# 设置扫描参数
scan_start=(1,1)#扫描开始(A)
scan_end = potential.extent#扫描结束
print('scan_end',scan_end)
gridscan = GridScan(start=scan_start,end=scan_end,sampling=0.1)#扫描间隔为0.1A
# 创建环形探测器
detector = FlexibleAnnularDetector()
# 执行扫描并获取测量结果
measurement = probe.scan(gridscan, detector, potential)
measurement.write('/data/abtem/measurement_mos2.hdf5')

# 可视化扫描结果
import matplotlib.pyplot as plt
measurement = Measurement.read('/data/abtem/measurement_mos2.hdf5')
image1=abf_measurement = measurement.integrate(0,10)
image2=haadf_measurement = measurement.integrate(50, 250)
# 创建一个新的 figure
fig, axs = plt.subplots(nrows=1, ncols=2, figsize=(12,5))
# 在第一个子图上显示 image1
axs[0].imshow(image1.array, cmap='gray', interpolation='none')
axs[0].set_title('ABF') # 设置第一个子图的标题
axs[0].axis('off') # 关闭第一个子图的坐标轴
# 在第二个子图上显示 image2
axs[1].imshow(image2.array, cmap='gray', interpolation='none')
axs[1].set_title('HAADF') # 设置第二个子图的标题
axs[1].axis('off') # 关闭第二个子图的坐标轴
plt.tight_layout() # 调整子图的位置,使它们之间有适当的间距
plt.show() # 显示图像
代码
文本

有缺陷

代码
文本
[11]
# 配置冻结声子模型的参数
sigmas={'Mo':.1,'S':.1}# Mo和S的热振动标准差,值越大,原子热振动越剧烈
num_configs=30
# 创建冻结声子模型
frozen_phonon=FrozenPhonons(atoms_modified,num_configs=num_configs,sigmas=sigmas)
# 计算电子和原子核的库仑势,用于定量图像模拟
slice_thickness=2 # 多层切片方法的每一层的间隔(A)
sampling_poten=0.1 # x-y网格精度(A)
potential = Potential(frozen_phonon,
sampling=sampling_poten,
projection='infinite',
slice_thickness=slice_thickness,
parametrization='kirkland').build()

# 构建电子探针
energy_EM=80e3 # 电压(V)
conv_angle=30 # 收敛角(mrad)
df=0 # 散焦(A)
C30=0 # 球差(A)
probe = Probe(energy=energy_EM, semiangle_cutoff=conv_angle,defocus=df,C30=C30, device='gpu')
# 将电子探针的网格与库仑势相匹配
probe.grid.match(potential)

# 设置扫描参数
scan_start=(1,1)#扫描开始(A)
scan_end = potential.extent#扫描结束
print('scan_end',scan_end)
gridscan = GridScan(start=scan_start,end=scan_end,sampling=0.1)#扫描间隔为0.1A
# 创建环形探测器
detector = FlexibleAnnularDetector()
# 执行扫描并获取测量结果
measurement = probe.scan(gridscan, detector, potential)
measurement.write('/data/abtem/measurement_mos2_defection.hdf5')

# 可视化扫描结果
import matplotlib.pyplot as plt
measurement = Measurement.read('/data/abtem/measurement_mos2_defection.hdf5')
image1=abf_measurement = measurement.integrate(0,10)
image2=haadf_measurement = measurement.integrate(50, 250)
# 创建一个新的 figure
fig, axs = plt.subplots(nrows=1, ncols=2, figsize=(12,5))
# 在第一个子图上显示 image1
axs[0].imshow(image1.array, cmap='gray', interpolation='none')
axs[0].set_title('ABF') # 设置第一个子图的标题
axs[0].axis('off') # 关闭第一个子图的坐标轴
# 在第二个子图上显示 image2
axs[1].imshow(image2.array, cmap='gray', interpolation='none')
axs[1].set_title('HAADF') # 设置第二个子图的标题
axs[1].axis('off') # 关闭第二个子图的坐标轴
plt.tight_layout() # 调整子图的位置,使它们之间有适当的间距
plt.show() # 显示图像
代码
文本

2. 不同材料仿真

晶格常数 厚度
NbS2 3.37 3.16
NbSe2 3.50 3.35
TaS2 3.31 3.02
TaSe2 3.42 3.14
MoS2 3.19 3.35
MoSe2 3.32 3.39
WS2 3.18 3.25
WSe2 3.32 3.44
代码
文本
[ ]
# !nvidia-smi
# 定义模拟的标签,这些标签用于区分不同的原子模型和模拟设置
sim_tag = 'sim' # 用于表示模拟的原子结构
single_vacancy_tag = '1vacancy' # 用于表示具有单个空位缺陷的原子结构
double_vacancy_tag = '2vacancy' # 用于表示具有双空位缺陷的原子结构
# 指定进行模拟计算的硬件设备,这里设置为使用GPU
device = 'gpu'
# 模拟使用的库,这里是abtem
source = 'abtem'
# 数据集名称,这里是NbS2
dataset_name = 'MoS2'
# 定义项目的根目录
project_dir = '/data/'
# 根据上面的变量定义,构建用于存放模拟生成数据的目录
data_dir = project_dir + '{}/{}_generated/'.format(dataset_name, source)
# 如果目录不存在,则创建目录
os.makedirs(data_dir, exist_ok=True)
os.makedirs(data_dir+'image/', exist_ok=True)

# 该函数用于生成存储原子信息的 .cif 文件的文件名
def get_atom_name(data_dir, data_idfn, tag):
# data_dir 是文件的存储目录
# tag 是用于区分不同原子模型的标签
# data_idfn 是用于区分不同数据集或模拟运行的标识
return '{}/atoms_{}_{}.cif'.format(data_dir, tag, data_idfn)

# 该函数用于生成存储标签信息的 .cif 文件的文件名
def get_label_name(data_dir, data_idfn, tag):
return '{}/label_{}_{}.cif'.format(data_dir, tag, data_idfn)

# 该函数用于生成存储模拟测量结果的 .hdf5 文件的文件名
def get_measurement_name(data_dir, data_idfn, tag):
return '{}/measurement_{}_{}.hdf5'.format(data_dir, tag, data_idfn)

def get_pic_name(data_dir, data_idfn):
return '{}/image/pic_{}.png'.format(data_dir, data_idfn)
def get_ps_name(data_dir, data_idfn):
return '{}/image/ps_{}.png'.format(data_dir, data_idfn)
vacuum = 1
代码
文本
[ ]
def create_atoms(fomula_tag, lattice_constant_a, thick, x=15, randomize_std=0.01):
# fomula_tag表示分子式,lattice_constant_a表示晶格常数,thick表示厚度,x表示在x和y方向上都有x个单位的重复,randomize_std>0则对原子的位置进行随机扰动
atoms = mx2(formula=fomula_tag, kind='2H', a=lattice_constant_a, thickness=thick, size=(x, x, 1), vacuum=None)
atoms.set_pbc([True, True, False])
atoms = orthogonalize_cell(atoms)
atoms.center(vacuum=1, axis=2)
if randomize_std > 0:
for i in range(atoms.arrays['positions'].shape[0]):
perturbed = lattice_constant_a * np.array([np.random.normal(0, randomize_std), np.random.normal(0, randomize_std), 0])
atoms.arrays['positions'][i, :] += perturbed
return atoms
atoms=create_atoms(fomula_tag='MoS2', lattice_constant_a=3.18, thick=3.19)

代码
文本
[ ]
def generate_defect(atoms, data_dir, data_idfn, defect_ratio=0.1):
atoms_ele_num = atoms.arrays['numbers']
atoms_positions = atoms.arrays['positions']
S = 16
S_index = np.where(atoms_ele_num == S)[0]
S_positions = atoms_positions[S_index]
# 打印硫原子位置的最大值和最小值
# print('s postions min/max', S_positions[:,0].min(), S_positions[:,0].max(), S_positions[:,1].min(), S_positions[:,1].max())
ok = False
# 当没有生成缺陷时,持续循环
while not ok:
# 计算硫原子的数量
S_cnt = len(S_index)
# 随机决定要删除的硫原子的数量
S_delete_cnt = random.randint(3, int(S_cnt*defect_ratio))
# 随机选择要删除的硫原子的索引
S_delete_index = S_index[random.sample(range(S_cnt), S_delete_cnt)]
# 从原子序数中删除选定的硫原子
atoms_ele_num_modified = np.delete(atoms_ele_num,S_delete_index)
# 从原子坐标中删除选定的硫原子
atoms_positions_modified = np.delete(atoms_positions,S_delete_index,axis=0)
# 打印修改后的原子序数和坐标的形状
print(atoms_ele_num_modified.shape, atoms_positions_modified.shape)
# 复制原子模型并更新其原子序数和坐标
atoms_modified = atoms.copy()
atoms_modified.arrays['numbers'] = atoms_ele_num_modified
atoms_modified.arrays['positions'] = atoms_positions_modified
# 计算被删除的硫原子的z轴坐标和所有硫原子的平均z轴坐标
deleted_z_axis = np.array([atoms_positions[del_idx][2] for del_idx in S_delete_index])
mean_z_axis = np.array([z_axis[2] for z_axis in S_positions]).mean()
# 分别找出位于z轴上方和下方的被删除的硫原子的索引
upper_indexs = S_delete_index[np.where(deleted_z_axis > mean_z_axis)[0]]
lower_indexs = S_delete_index[np.where(deleted_z_axis < mean_z_axis)[0]]
double_index = []
# 查找双硫原子都被删除的位置
for upper_index in upper_indexs:
x0 = atoms_positions[upper_index][0]
y0 = atoms_positions[upper_index][1]
for lower_index in lower_indexs:
x1 = atoms_positions[lower_index][0]
y1 = atoms_positions[lower_index][1]
if (abs(x0-x1)<0.1 and abs(y0-y1)<0.1):
double_index.append(upper_index)
double_index.append(lower_index)
# 找出只有一个硫原子被删除的索引
single_index = [i for i in S_delete_index if i not in double_index]
# 如果双硫原子和单硫原子的缺失都发生了,那么标志变量ok设为True,结束循环?
if len(double_index) > 0 and len(single_index) > 0:
ok = True

# 复制原子模型,然后只留下双硫原子缺失的位置
atoms_double = atoms.copy()
ele_double = atoms_ele_num[double_index]
positions_double = atoms_positions[double_index]
atoms_double.arrays['numbers'] = ele_double
atoms_double.arrays['positions'] = positions_double

# 复制原子模型,然后只留下单硫原子缺失的位置
atoms_single = atoms.copy()
ele_single = atoms_ele_num[single_index]
positions_single = atoms_positions[single_index]
atoms_single.arrays['numbers'] = ele_single
atoms_single.arrays['positions'] = positions_single

# 在当前目录下创建一个名为'data'的子目录(如果该目录不存在)
os.makedirs('data', exist_ok=True)

# 将经过修改的原子模型、单硫原子缺失的原子模型、双硫原子缺失的原子模型分别写入文件
write(get_atom_name(data_dir, data_idfn, sim_tag), atoms_modified)
write(get_atom_name(data_dir, data_idfn, single_vacancy_tag), atoms_single)
write(get_atom_name(data_dir, data_idfn, double_vacancy_tag), atoms_double)

# 将单硫原子缺失和双硫原子缺失的位置坐标(仅x,y轴)分别保存为numpy数组文件
np.save(get_label_name(data_dir, data_idfn, single_vacancy_tag), positions_single[:,:2])
np.save(get_label_name(data_dir, data_idfn, double_vacancy_tag), positions_double[:,:2])
# 返回经过修改的原子模型、单硫原子缺失的原子模型、双硫原子缺失的原子模型
return atoms_modified, atoms_single, atoms_double
-----------------------------------
atoms_modified, atoms_single, atoms_double=generate_defect(atoms, data_dir, '00')
代码
文本
[ ]
def simulation(data_dir, data_idfn, tag, name):
# 获取原子样品文件名
atoms_file = get_atom_name(data_dir, data_idfn, tag)
# 从文件中读取原子样品数据
atoms = read(atoms_file)
# 设置电子显微镜的参数
slice_thickness=2 # 多层切片方法的每一层的间隔(A)
sampling_poten=0.1 # 网格精度
conv_angle=30 # 收敛角(mrad)
energy_EM=80e3 # 电压(V)
scan_start=(vacuum,vacuum) # 扫描的起始点

step_size=0.12 # 探针扫描步长(A)
df=0 # 调焦(A)

# 配置冻结声子模型的参数
sigmas={name:.1,'S':.1}
num_configs=30
# 创建冻结声子模型
frozen_phonon=FrozenPhonons(atoms,num_configs=num_configs,sigmas=sigmas)
# 计算电子和原子核的库仑势,用于定量图像模拟
potential = Potential(frozen_phonon,
sampling=sampling_poten,
projection='infinite',
slice_thickness=slice_thickness,
parametrization='kirkland').build()

# 获取扫描的结束点
scan_end = potential.extent
print('extent of potential:', potential.extent)
#scan_end = [10,10]
print('scan_start',scan_start'-scan_end',scan_end)
# 创建探测器探针
probe = Probe(energy=energy_EM, semiangle_cutoff=conv_angle,defocus=df,C30=0, device=device)

# 将探针的网格与库仑势相匹配
probe.grid.match(potential)
# 设置探针步长
print('ctf.nyquist_sampling',probe.ctf.nyquist_sampling)
gridscan = GridScan(start=scan_start,end=scan_end,sampling=probe.ctf.nyquist_sampling * .9)
# 创建环形探测器
detector = FlexibleAnnularDetector()
# 执行扫描并获取测量结果
measurement = probe.scan(gridscan, detector, potential)
#image1=haadf_measurement = measurement.integrate(80, 250)
#image1.show()
#with open('image00.pkl', 'wb') as f:
# pickle.dump(measurement, f)

# 获取测量结果文件名
file_name = get_measurement_name(data_dir, data_idfn, tag)

# 将测量结果写入文件
measurement.write(file_name)
return file_name
------------------------
sim_file_name = simulation(data_dir, '00', sim_tag, 'Mo')
代码
文本
[ ]
def draw_pic(data_dir, data_idfn):
file_name = get_measurement_name(data_dir, data_idfn, sim_tag)
measurement = Measurement.read(file_name)
image1=haadf_measurement = measurement.integrate(50, 250)
#全像素
dpi = 300
fig = plt.figure(figsize=(image1.array.shape[1]/dpi, image1.array.shape[0]/dpi), dpi=dpi)
plt.imshow(image1.array, cmap='gray', interpolation='none')
# 关闭坐标轴
plt.axis('off')
# 设置布局和保存
plt.gca().set_position([0, 0, 1, 1])
plt.savefig(get_pic_name(data_idfn), dpi=dpi, bbox_inches=0, pad_inches=0)
# 关闭图像以释放内存
plt.close(fig)
return
----------------
draw_pic(data_dir, '00')
代码
文本
[ ]
def draw_ps(data_dir, data_idfn):
file_name = get_measurement_name(data_dir, data_idfn, sim_tag)
measurement = Measurement.read(file_name)
image1 = haadf_measurement = measurement.integrate(50, 250)
#有单位标注
ax, _ = image1.show()
fig = ax.get_figure()
fig.savefig(get_ps_name(data_idfn), dpi=300)
plt.close(fig)
return
----------------
draw_ps(data_dir, '00')
代码
文本

批量生成

代码
文本
[ ]
# 数据集名称,这里是NbS2
dataset_name = 'NbS2'
# 定义项目的根目录
project_dir = '/data/'
# 根据上面的变量定义,构建用于存放模拟生成数据的目录
data_dir = project_dir + '{}/{}_generated/'.format(dataset_name, source)
# 如果目录不存在,则创建目录
os.makedirs(data_dir, exist_ok=True)
os.makedirs(data_dir+'image/', exist_ok=True)

id_start = 0
id_end = 100

for data_idfn in range(id_start,id_end):
a=data_idfn
data_idfn="{:03d}".format(data_idfn)
atoms = create_atoms(fomula_tag='NbS2', lattice_constant_a=, thick=, x=15, randomize_std=0.01)
atoms_modified, atoms_single, atoms_double = generate_defect(atoms, data_dir, data_idfn, 0.1)
sim_file_name = simulation(data_dir, data_idfn, sim_tag, 'Nb')
draw_pic(data_dir, data_idfn)
draw_ps(data_dir, data_idfn)
sim_file_name = simulation(data_dir, data_idfn, single_vacancy_tag, 'Nb')
draw_pic(data_dir, data_idfn)
draw_ps(data_dir, data_idfn)
sim_file_name = simulation(data_dir, data_idfn, double_vacancy_tag, 'Nb')
draw_pic(data_dir, data_idfn)
draw_ps(data_dir, data_idfn)
print('已完成:',a+1,'/',id_end)
代码
文本
STEM
AI4S
STEMAI4S
已赞2
推荐阅读
公开
氧掺杂abTEM仿真
AI4S
AI4S
Orange
发布于 2023-11-07
公开
实验:不同pixel size对图像的影响
AI4S
AI4S
OrangeFree
发布于 2023-09-27
1 转存文件
评论
 # 使用ASE的mx2函数创建一个MoS...

OrangeFree

作者
09-23 11:01
不同材料需要改
评论
 # 找出S/Se原子所在序列 S_ind...

OrangeFree

作者
09-23 11:02
不同材料需要改
评论
 # 可视化s/se原子缺失的位置 fig...

OrangeFree

作者
09-23 11:04
不同材料需要改
评论
 # 配置冻结声子模型的参数 sigmas...

OrangeFree

作者
09-23 11:03
不同材料需要改
评论