Skip to content

第39章:物理模型接口

物理模型接口简介

带隙(Band Gap)

带隙变窄(Bandgap Narrowing)

有效质量(Effective Mass)

电子亲和能(Electron Affinity)

相与状态转变(Phase and State Transitions)

多态配置相关的表观带边偏移(Multistate Configuration–Dependent Apparent Band-Edge Shift)

多态配置相关的体迁移率(Multistate Configuration–Dependent Bulk Mobility)

多态配置相关的热容(Multistate Configuration–Dependent Heat Capacity)

多态配置相关的热导率(Multistate Configuration–Dependent Thermal Conductivity)

热特性与热量(Thermal Properties and Heat)

分布热阻(Distributed Thermal Resistance)

热容(Heat Capacity)

热产生率(Heat Generation Rate)

金属热电功率(Metal Thermoelectric Power)

热导率(Thermal Conductivity)

热电功率(Thermoelectric Power)

光学(Optics)

复折射率模型接口(Complex Refractive Index Model Interface)

光学量子产率(Optical Quantum Yield)

光线追踪专用接触PMI(Special Contact PMI for Raytracing)

机械应力(Mechanical Stress)

迁移率应力因子(Mobility Stress Factor)

压电极化(Piezoelectric Polarization)

压阻系数(Piezoresistive Coefficients)

应力(Stress)

陷阱与固定电荷(Traps and Fixed Charges)

陷阱捕获与发射率(Trap Capture and Emission Rates)

陷阱能级偏移(Trap Energy Shift)

退化(Degradation)

扩散率(Diffusivity)

eNMP转变率(eNMP Transition Rates)

铁电体与铁磁体(Ferroelectrics and Ferromagnetics)

铁电体(Ferroelectrics)

铁电滞回(Ferroelectrics Hysteresis)

铁磁性与自旋输运(Ferromagnetism and Spin Transport)

电阻率(Electrical Resistivity)

金属电阻率(Metal Resistivity)

肖特基电阻(Schottky Resistance)

仿真控制(Simulation Controls)

电流绘图文件(Current Plot File)

瞬态仿真后处理(Postprocessing for Transient Simulations)

牛顿迭代与牛顿步长的预处理(Preprocessing for Newton Iterations and Newton Step Control)

杂项(Various)

介电常数(Dielectric Permittivity)

能量弛豫时间(Energy Relaxation Times)

密度梯度模型的Gamma因子(Gamma Factor for Density Gradient Model)

重离子空间分布(Heavy Ion Spatial Distribution)

热载流子注入(Hot-Carrier Injection)

不完全电离(Incomplete Ionization)

经典幸运电子注入的平均自由程(Mean Free Path for Classical Lucky Electron Injection)

空间因子(Space Factor)


使用PMI模型

要在Sentaurus Device仿真中使用PMI模型,需要执行以下步骤:

  1. 实现一个C++子程序来计算PMI模型。对于标准接口,还必须编写额外的C++子程序来计算PMI模型相对于所有输入变量的导数。

  2. 使用cmi <pmi_file_name>.C编译实现PMI模型的C++子程序。这将生成<pmi_file_name>.so.<platform>共享对象文件,Sentaurus Device在运行时加载该文件(参见第1282页的共享对象代码)。

注意: PMI模型使用的C++编译器版本必须与编译Sentaurus Device时使用的C++编译器版本完全相同。使用cmi -a命令可以验证编译器版本。

  1. 在命令文件的File部分定义PMIPath变量。该变量定义共享对象文件的搜索路径。PMI模型在命令文件的Physics部分通过指定其名称来激活(参见第1282页的Sentaurus Device命令文件)。

PMI模型的参数可以出现在参数文件中以PMI模型名称命名的部分下(参见第1284页的Sentaurus Device参数文件)。或者,也可以定义在使用该PMI模型的Sentaurus Device命令文件中(参见第1282页的Sentaurus Device命令文件)。

本章示例的源代码位于以下目录:

$STROOT/tcad/$STRELEASE/Applications_Library/GettingStarted/sdevice/pmi

可用接口

对于大多数模型,Sentaurus Device提供两个等效的接口:

标准C++接口基于double数据类型。需要编写单独的子程序来计算模型及其导数。该接口提供的性能与Sentaurus Device内置模型相当(参见标准C++接口)。

简化C++接口基于pmi_float数据类型。只需实现一个子程序来计算模型(参见简化C++接口)。对于局部模型,模型的导数通过自动微分获得。该接口还支持扩展精度浮点运算(参见扩展精度)。

还存在一个额外的接口,其中值基于输入变量的非局部值计算(参见非局部接口)。

标准C++接口

对于每个PMI模型,必须实现一个C++子程序来计算模型。还需要额外的子程序来计算模型相对于所有输入变量的导数。具体来说,必须实现一个从头文件PMIModels.h中声明的基类派生的C++类。此外,必须提供一个虚拟构造函数函数,用于分配派生类实例。

示例:将俄歇复合实现为新PMI模型

考虑将俄歇复合实现为一个新的PMI模型。(内置的俄歇复合模型在俄歇复合模型中讨论。)在最简单的情况下,俄歇复合可以写为:

Sentaurus Device需要计算的值和导数:

在头文件PMIModels.h中,为复合模型定义了以下基类:

cpp
class PMI_Recombination : public PMI_Vertex_Interface {
public:
    PMI_Recombination (const PMI_Environment& env);
    virtual ~PMI_Recombination ();
    virtual void Compute_r
        (const double t, const double n, const double p,
        const double nie, const double f, double& r) = 0;
    virtual void Compute_drdt
        (const double t, const double n, const double p,
        const double nie, const double f, double& drdt) = 0;
    virtual void Compute_drdn
        (const double t, const double n, const double p,
        const double nie, const double f, double& drdn) = 0;
    virtual void Compute_drdp
        (const double t, const double n, const double p,
        const double nie, const double f, double& drdp) = 0;
    virtual void Compute_drdnie
        (const double t, const double n, const double p,
        const double nie, const double f, double& drdnie) = 0;
    virtual void Compute_drdf
        (const double t, const double n, const double p,
        const double nie, const double f, double& drdf) = 0;
};

要实现俄歇复合的PMI模型,必须声明一个派生类:

cpp
#include "PMIModels.h"
class Auger_Recombination : public PMI_Recombination {
    double C;
public:
    Auger_Recombination (const PMI_Environment& env);
    ~Auger_Recombination ();
    void Compute_r
        (const double t, const double n, const double p,
        const double nie, const double f, double& r);
    void Compute_drdt
        (const double t, const double n, const double p,
        const double nie, const double f, double& drdt);
    void Compute_drdn
        (const double t, const double n, const double p,
        const double nie, const double f, double& drdn);
    void Compute_drdp
        (const double t, const double n, const double p,
        const double nie, const double f, double& drdp);
    void Compute_drdnie
        (const double t, const double n, const double p,
        const double nie, const double f, double& drdnie);
    void Compute_drdf
        (const double t, const double n, const double p,
        const double nie, const double f, double& drdf);
};

派生类的构造函数为设备的每个区域调用。

在这个例子中,变量C从参数文件初始化:

cpp
Auger_Recombination::
Auger_Recombination (const PMI_Environment& env) :
PMI_Recombination (env)
{ C = InitParameter ("C", 1e-30);
}

如果参数文件中未找到参数C,则使用默认值10⁻³⁰。在牛顿迭代期间,Sentaurus Device为每个网格顶点计算PMI模型。方法Compute_r()计算给定顶点的复合率。根据参数列表,复合率可以依赖于以下变量:

t:晶格温度

n:电子密度

p:空穴密度

nie:有效本征密度

f:电场绝对值

函数的结果存储在参数r中:

cpp
void Auger_Recombination::
Compute_r (const double t, const double n, const double p,
            const double nie, const double f, double& r)
{ r = C * (n + p) * (n*p - nie*nie);
    if (r < 0.0) {
        r = 0.0;
    }
}

除了Compute_r()之外,还必须实现其他方法来计算复合率相对于输入变量tnpnief的偏导数。Compute_drdn()的实现(用于计算∂R/∂n的值):

cpp
void Auger_Recombination::
Compute_drdn (const double t, const double n, const double p,
                const double nie, const double f, double& drdn)
{ double r = C * (n + p) * (n*p - nie*nie);
    if (r < 0.0) {
        drdn = 0.0;
    } else {
        drdn = C * ((n*p - nie*nie) + (n + p) * p);
    }
}

最后,必须提供一个虚拟构造函数函数,用于分配新类变量:

cpp
extern "C"
PMI_Recombination* new_PMI_Recombination (const PMI_Environment& env)
{ return new Auger_Recombination (env);
}

注意: 此函数必须具有C链接,且名称必须与头文件PMIModels.h中声明的名称完全相同。

简化C++接口

使用简化C++接口的PMI模型称为简化PMI模型,它们只需要实现一个函数来计算仿真网格实际顶点处感兴趣量的数值。相对于输入量的导数可以自动提取。

以下C++类型提供适当的接口:

• 简化PMI模型使用特殊的数值数据类型pmi_float(参见数值数据类型pmi_float)。

• 简化PMI模型派生自PMI_Vertex_Common_Base类,在PMI模型范围内提供接口(参见模型范围支持)。

• 简化PMI模型的主要函数称为compute,其形式为:

cpp
void compute ( const Input& input, Output& output )

其中Input是从PMI_Vertex_Input_Base类派生的类,在计算范围内提供运行时支持(参见计算范围支持)。

数值数据类型pmi_float

简化接口基于数据类型pmi_float,它的行为类似于double,支持所有常规算术运算:

赋值:

cpp
pmi_float x = 2;
pmi_float y (x);

一元运算符:

cpp
+x; -y;

二元运算符:

cpp
x + y; x - y; x * y; x / y;

比较运算:

cpp
x == y; x != y; x < y; x <= y; x > y; x >= y;

数学函数:

cpp
abs(x); acos(x); acosh(x); asin(x); asinh(x); atan(x); atanh(x);
atan2(y,x); cos(x); cosh(x); erf(x); erfc(x); exp(x); expm1(x);
hypot(x,y); isinf(x); isnan(x); ldexp(x,exp); log(x); log1p(x);
log10(x); pow(x,y); pow_int(x,n); sin(x); sinh(x); sqrt(x);
tan(x); tanh(x);

输出:

cpp
std::cout << x;

以下静态函数返回浮点运算的精度:

cpp
pmi_e_precision pmi_float::get_precision ()

结果表示为枚举类型:

cpp
enum pmi_e_precision {
    pmi_c_np, // 正常精度(double): -ExtendedPrecision
    pmi_c_xp, // 扩展精度(long double): ExtendedPrecision
    pmi_c_dd, // 双双精度: ExtendedPrecision(128)
    pmi_c_qd, // 四四精度: ExtendedPrecision(256)
    pmi_c_mp  // 任意精度: ExtendedPrecision(Digits=...)
};

因为类pmi_float支持自动微分,它必须存储变量的值和相对于独立变量的导数梯度向量。以下方法可用于读取变量值、梯度向量的大小和梯度向量的分量:

cpp
template <class des_t_float> des_t_float get_value ();
size_t size_gradient ();
template <class des_t_float> des_t_float get_gradient (size_t i);

还有额外的方法来设置变量或其梯度的值:

cpp
template <class des_t_float> void set_value (const des_t_float a);
template <class des_t_float> void set_gradient (size_t i, const des_t_float a);

注意: 这些用于读写变量值和梯度的方法对于大多数模型不是必需的。它们在自动微分产生不正确结果的情况下可能有用。

简化PMI模型的伪实现

与标准C++接口相比,简化C++接口只需要实现一个子程序来计算模型。本节讨论如何将俄歇复合实现为PMI模型。

头文件PMI.h为复合模型定义了以下基类:

cpp
class PMI_Recombination_Base : public PMI_Vertex_Base {
public:
    class Input : public PMI_Vertex_Input_Base {
    public:
        pmi_float t;        // 晶格温度
        pmi_float n;        // 电子密度
        pmi_float p;        // 空穴密度
        pmi_float nie;      // 有效本征密度
        pmi_float f;        // 电场绝对值
    };
    class Output {
    public:
        pmi_float r;        // 复合率
    };

    PMI_Recombination_Base (const PMI_Environment& env);
    virtual ~PMI_Recombination_Base ();
    virtual void compute (const Input& input, Output& output) = 0;
};

要实现用户模型,必须首先声明一个派生类:

cpp
#include "PMI.h"
class Auger_Recombination : public PMI_Recombination_Base {
private:
    double C;
public:
    Auger_Recombination (const PMI_Environment& env);
    ~Auger_Recombination ();
    virtual void compute (const Input& input, Output& output);
};

在构造函数中,变量C从参数文件初始化:

cpp
Auger_Recombination::
Auger_Recombination (const PMI_Environment& env) :
PMI_Recombination_Base (env)
{ C = InitParameter ("C", 1e-30);
}

构造函数为设备的每个区域调用,以确保区域参数被正确处理。

接下来,必须实现实际的Compute函数。它依赖于辅助类InputOutput来读取输入变量并存储复合率:

cpp
void Auger_Recombination::
compute (const Input& input, Output& output)
{ output.r = C * (input.n + input.p) *
        (input.n*input.p - input.nie*input.nie);
    if (output.r < 0.0) {
        output.r = 0.0;
    }
}

最后,必须提供一个虚拟构造函数来分配类Auger_Recombination的实例:

cpp
extern "C"
PMI_Recombination_Base* new_PMI_Recombination_Base
(const PMI_Environment& env)
{ return new Auger_Recombination (env);
}

注意: 此函数必须具有C链接,且名称必须与头文件PMI.h中声明的名称完全相同。

可以在同一文件中同时使用标准和简化接口实现模型。在这种情况下,Sentaurus Device根据浮点精度选择版本:

• 对于正常精度(64位),选择标准接口,确保与内置模型相当的性能。

• 对于扩展精度浮点运算,选择简化接口。调用PMI模型时不会丢失精度。

注意: 简化接口非常适合原型设计新模型。无需实现导数,这加速了开发周期。模型验证后,可以轻松将其转换为标准接口以用于性能关键的应用。

由于简化接口会为您计算导数,因此很容易忽略表达式本身定义良好但其导数未定义的情况。例如,假设模型计算n – n₀,并且已确保n – n₀不能变为负数。当n = n₀时,这还不够,因为导数变为无穷大。

注意: 确保不仅使用的表达式,而且它们的导数始终有效。

非局部接口

使用非局部接口模型,值基于输入变量的非局部值计算。例如,顶点处的产生-复合率可能依赖于远程顶点处观察到的载流子密度。

非局部接口提供更大的灵活性,但反过来需要用户PMI代码中的额外功能。必须为以下目的实现单独的C++函数:

依赖项:必须声明模型所依赖的变量,例如静电势或载流子密度。

雅可比矩阵的结构:对于每个输入变量,必须声明相应雅可比矩阵的结构(模板)。例如:

顶点17处的模型值依赖于:
    顶点22处的静电势
    顶点55处的电子密度
顶点18处的模型值依赖于:
    顶点35处的空穴密度
    顶点44处的晶格温度

模型值及其导数:代码必须计算模型值及其相对于所有依赖项的导数。

雅可比矩阵的更新:PMI可能需要更新雅可比矩阵的结构。如果模型没有纯几何依赖项,而是依赖于解的值,则会发生这种情况。在这种情况下,Sentaurus Device调用PMI来请求更新后的雅可比矩阵结构。

非局部PMI同时支持double数据类型和pmi_float数据类型。但是,数据类型pmi_float仅用于支持扩展精度浮点运算,不用于自动微分目的。

雅可比矩阵

Sentaurus Device提供了类des_jacobian(标准C++接口)和sdevice_jacobian(简化C++接口)来表示雅可比矩阵。这些类用于:

• 定义雅可比矩阵的结构,即模型值相对于输入变量的依赖关系

• 存储模型值相对于输入变量的导数

雅可比矩阵的大小取决于模型的位置和输入变量的位置。行数由模型的位置决定。例如,对于基于顶点的模型,行数由网格顶点的数量给出。

支持的位置由类型des_data::des_location给出(对于标准C++接口):

cpp
typedef enum { vertex, edge, element, rivertex, element_vertex } des_location;

以及类型sdevice_data::sdevice_location(对于简化C++接口):

cpp
typedef enum { vertex, edge, element, rivertex, element_vertex } sdevice_location;

类似地,雅可比矩阵的列数由输入变量的位置决定。例如,对于基于边的输入变量,列数由网格边的数量给出。

对于依赖于标量输入变量的标量模型,每个雅可比条目也是一个简单的标量。然而,Sentaurus Device还支持模型值或输入变量(或两者)都是向量的一般情况。在这种情况下,雅可比矩阵中的每个条目变成一个大小为内部行数乘以内数列的小密集矩阵。内部行数由模型值的数量给出(标量为1,向量为网格维度)。类似地,内列数由变量值的数量决定(标量为1,向量为网格维度)。

des_jacobian提供以下方法:

cpp
des_jacobian (int rows, int cols, int inner_rows, int inner_cols);
int size_rows () const;
int size_cols () const;
int size_inner_rows () const;
int size_inner_cols () const;
int size_matrix () const;
void define_element (int row, int col);
double* element (int row, int col);
des_jacobian_iterator begin ();
des_jacobian_iterator end ();
des_jacobian_iterator lower_bound (int row, int col);
des_jacobian_iterator upper_bound (int row, int col);
void set (double value);

注意: 对于简化C++接口,类sdevice_jacobian提供相同的方法,只是使用pmi_float数据类型代替double

构造函数创建一个具有给定维数的新空雅可比矩阵。方法size_rows()size_cols()分别返回行数和列数。类似地,方法size_inner_rows()size_inner_cols()分别返回内部行数和内列数。方法size_matrix()返回雅可比矩阵中的非零元素数量。

使用方法define_element()来定义非零矩阵元素的位置。此时非零条目的值仍未指定。但是,所需存储已被分配。

方法element()返回雅可比矩阵条目的指针。对于不存在的条目返回NULL指针。该指针定义大小为内部行数乘以内列数的密集矩阵的起始位置。该矩阵中的条目按行主序(C风格)存储。

函数begin()end()返回遍历雅可比矩阵非零元素的迭代器。典型循环:

cpp
des_jacobian J;
for (des_jacobian_iterator it = J.begin(); it != J.end(); it++) {
    int row = it.row();
    int col = it.col();
    double* value = it.val();
    // 处理元素(row,col)
}

函数lower_bound()upper_bound()提供了一种快速查找非零元素范围的方法。

以下代码片段访问第25行的所有非零元素:

cpp
des_jacobian J;
des_jacobian_iterator it_begin = J.lower_bound (25, 0);
des_jacobian_iterator it_end = J.lower_bound (26, 0);
for (des_jacobian_iterator it = it_begin; it != it_end; it++) {
    int row = it.row();
    int col = it.col();
    double* value = it.val();
    // 处理元素(row,col)
}

方法set()可用于使用给定值初始化所有矩阵元素。

示例:点对点隧穿

对于非局部产生-复合模型,考虑两个顶点v₁v₂之间的简单点对点隧穿模型。该模型比较这两个顶点中的电子和空穴准费米势。如果Φ_{n,1} < Φ_{p,2},则隧穿率r计算为:

其中E_C是导带能量,E_V是价带能量,且Δ = Φ_{p,2} - Φ_{n,1}。非局部输运通过在顶点1中使用r作为电子复合率,在顶点2中使用空穴复合率来建模。

类似地,如果Φ_{p,1} > Φ_{n,2},则隧穿率r计算为:

其中Δ = Φ_{p,1} - Φ_{n,2}。在这种情况下,r在顶点1中用作空穴复合率,在顶点2中用作电子复合率。

在头文件PMIModels.h中,为非局部产生-复合模型定义了以下基类:

cpp
class PMI_NonLocal_Recombination : public PMI_Device_Interface {
public:
    class Input {
    public:
        const des_region* region; // 所有顶点属于此区域
        const std::vector<int>& vertices; // 顶点列表
    };
    class Output {
    public:
        std::vector<double>& elec; // 非局部复合率(电子)
        std::vector<double>& hole; // 非局部复合率(空穴)
        des_id_to_jacobian_map& J_elec; // 导数(电子)
        des_id_to_jacobian_map& J_hole; // 导数(空穴)
    };

    PMI_NonLocal_Recombination (const PMI_Device_Environment& env);
    virtual ~PMI_NonLocal_Recombination ();
    virtual void DefineDependencies (std::vector<des_data::des_id>& dependencies) = 0;
    virtual void DefineJacobians (des_id_to_jacobian_map& J_elec,
                                   des_id_to_jacobian_map& J_hole) = 0;
    virtual void Compute_parallel (const Input& input, Output& output) = 0;
    virtual bool NeedNewEdges () { return false; }
};

要实现点对点隧穿模型,必须声明一个派生类:

cpp
#include "PMIModels.h"
class P2P_Recombination : public PMI_NonLocal_Recombination {
private:
    double A, B;              // 模型参数
    int v1, v2;               // 顶点1,顶点2
    double measure1, measure2; // 顶点1和2的半导体节点度量

public:
    P2P_Recombination (const PMI_Device_Environment& env);
    void DefineDependencies (std::vector<des_data::des_id>& dependencies);
    void DefineJacobians (des_id_to_jacobian_map& J_elec,
                          des_id_to_jacobian_map& J_hole);
    void Compute_parallel (const PMI_NonLocal_Recombination::Input& input,
                           PMI_NonLocal_Recombination::Output& output);
    bool NeedNewEdges ();
};

方法DefineDependencies()定义稍后在调用Compute_parallel()时将读取的变量:

cpp
void P2P_Recombination::
DefineDependencies (std::vector<des_data::des_id>& dependencies)
{ dependencies.push_back (des_data::des_id (des_data::scalar,
                                              des_data::vertex,
                                              "eQuasiFermiPotential"));
    dependencies.push_back (des_data::des_id (des_data::scalar,
                                              des_data::vertex,
                                              "hQuasiFermiPotential"));
    dependencies.push_back (des_data::des_id (des_data::scalar,
                                              des_data::vertex,
                                              "ConductionBandEnergy"));
    dependencies.push_back (des_data::des_id (des_data::scalar,
                                              des_data::vertex,
                                              "ValenceBandEnergy"));
}

表195:非局部PMI模型可用的依赖于解的数据

数据名称类型位置描述
BandGap标量顶点本征带隙
BandgapNarrowing标量顶点带隙变窄
ConductionBandEnergy标量元素_顶点导带能量
eDensity标量顶点电子密度
eEffectiveStateDensity标量顶点导带态密度(DOS)
EffectiveIntrinsicDensity标量顶点有效本征密度
ElectricField标量元素电场
ElectronAffinity标量顶点电子亲和能
ElectrostaticPotential标量顶点静电势
eQuasiFermiPotential标量顶点电子准费米势
eRelativeEffectiveMass标量顶点电子DOS质量
eTemperature标量顶点电子温度
hDensity标量顶点空穴密度
hEffectiveStateDensity标量顶点价带DOS
hQuasiFermiPotential标量顶点空穴准费米势
hRelativeEffectiveMass标量顶点空穴DOS质量
hTemperature标量顶点空穴温度
InsulatorElectricField标量顶点绝缘体上的电场
IntrinsicDensity标量顶点本征密度
LatticeTemperature标量顶点晶格温度
SemiconductorElectricField标量顶点半导体上的电场
SemiconductorGradValencebandEnergy标量元素价带能量梯度
ValenceBandEnergy标量元素_顶点价带能量

方法Compute_parallel()计算电子和空穴复合率及其导数。它可以在Sentaurus Device的并行组装期间调用。因此,它必须以线程安全的方式实现。

最后,必须提供一个虚拟构造函数来分配新类变量:

cpp
extern "C"
PMI_NonLocal_Recombination*
new_PMI_NonLocal_Recombination (const PMI_Device_Environment& env)
{ return new P2P_Recombination (env);
}

注意: 此函数必须具有C链接,且名称必须与头文件PMIModels.h中声明的名称完全相同。

共享对象代码

Sentaurus Device假设对应于PMI模型的共享对象代码可以在文件modelname.so.arch中找到。此文件的基名必须与PMI模型的名称相同。扩展名.arch取决于硬件架构。

脚本cmi(也是CMI的一部分)可用于生成共享对象文件。

Sentaurus Device命令文件

要将PMI模型加载到Sentaurus Device,必须在命令文件的File部分定义PMIPath搜索路径。PMIPath的值由一系列目录组成。例如:

File { PMIPath = ". /home/joe/lib /home/mary/sdevice/lib" }

对于Physics部分中出现的每个PMI模型,会在给定目录中搜索相应的共享对象文件modelname.so.arch

Sentaurus Device中的PMI提供对您指定的基于网格的标量字段的访问。这些字段必须在单独的TDR(.tdr)数据文件中定义在设备网格上。最多可以定义300个数据集(PMIUserField0, ..., PMIUserField299)。

Sentaurus Device在命令文件中提供相应文件名时读取用户定义字段:

File { PMIUserFields = "fields" }

通过在命令文件的Physics部分指定PMI模型的名称来激活PMI模型。不同类型PMI模型的示例:

产生-复合模型:

Physics { Recombination (pmi_model_name ...) }

雪崩产生:

Physics { Recombination (Avalanche (pmi_model_name ...)) }

迁移率模型:

Physics {
    Mobility (
        DopingDependence (pmi_model_name)
        Enormal (pmi_model_name)
        ToCurrentEnormal (pmi_model_name)
        HighFieldSaturation (pmi_model_name driving_force)
    )
}

PMI模型名称只能由字母数字字符和下划线(_)组成。第一个字符必须是字母或下划线。PMI模型名称也可以用引号引起来为"model_name"以避免与Sentaurus Device关键字冲突。

所有PMI模型都可以按区域或按材料指定。例如:

Physics (region = "Region.1") { ... }
Physics (material = "AlGaAs") { ... }

PMI模型也识别命令文件中的参数。通常,命令文件参数列在模型名称后面的括号中。

某些PMI模型的值可以在命令文件的Plot部分中绘制。识别以下标识符:

产生-复合模型:

Plot {
    PMIRecombination
    PMIeNonLocalRecombination
    PMIhNonLocalRecombination
}

用户定义字段:

Plot { PMIUserField0 PMIUserField1 ... PMIUserField299 }

压电极化:

Plot { PE_Polarization/vector PE_Charge }

金属电导率:

Plot { MetalConductivity }

电流绘图PMI可用于向电流绘图文件添加条目:

CurrentPlot { pmi_CurrentPlot }

Sentaurus Device参数文件

对于每个PMI模型,参数文件中可以出现具有相同名称的相应部分:

PMI_model_name {
    par1 = value
    par2 = value
    ...
}

注意: 参数名称只能由字母数字字符和下划线(_)组成。第一个字符必须是字母或下划线。

参数可以是数字、字符串或数字或字符串数组:

PMI_model_name {
    a = 1
    b = "string"
    c = (1.2 3.4 5.6 7.8)
    d = ("red" "blue" "green")
}

注意: 数组必须只包含数字或字符串。不支持同时包含数字和字符串的混合数组。空数组(如c=())被视为大小为0的数字数组。

参数可以按区域和材料指定:

Region = "Region.1" {
    PMI_model_name {
        ...
    }
}
Material = "AlGaAs" {
    PMI_model_name {
        ...
    }
}

可以使用ReadParameter()方法获取参数的值。对于实数标量参数,方法InitParameter()检查参数是否已在参数文件中指定:

cpp
double value = InitParameter ("pi", 3.14159);

如果已指定参数,则使用给定值。否则,使用默认值。

注意: PMI模型参数也可以在命令文件中指定。命令文件中的参数优先于参数文件中的参数。

并行化

在并行仿真期间,Sentaurus Device可以从不同线程同时调用PMI模型。因此,计算函数必须以线程安全的方式实现。

以下规则保证线程安全的PMI:

• 不要使用全局变量。

• 类变量只在构造函数和析构函数中修改。类变量可以在计算函数中读取,但不能修改。

• 在计算函数中,所有临时变量都分配为自动变量或使用new和delete运算符动态分配。

线程本地存储

线程本地存储模板类PMI_TLS提供了一种为每个线程存储数据的机制。这可用于优化PMI的运行时性能。

模板类PMI_TLS声明如下:

cpp
template <typename T> class PMI_TLS {
public:
    T& local (bool& exists);
    T& local ();
    size_t size () const;
    T& operator [] (size_t index);
};

调试物理模型接口

打印语句是调试PMI的最简单方法。它们可以插入到代码中的任何位置来打印变量的值。

也可以使用调试器来捕获PMI子程序中的错误。以下说明适用于gdb(GNU调试器):

  1. 使用-g选项在调试模式下编译PMI源代码:
cmi -g pmi_Auger.C
  1. 确定Sentaurus Device二进制文件的名称:
sdevice -@ldd
  1. 在Sentaurus Device二进制文件上启动调试器:
gdb /usr/sentaurus/tcad/W-2024.09/linux64/bin/sdevice-35.0.1098
  1. 验证环境变量的设置:
show environment
  1. 运行仿真以加载共享对象文件,然后使用Ctrl+C中断:
run pp1_des.cmd
  1. 在PMI源代码中定义断点:
break pmi_Auger.C:100
  1. 恢复仿真:
continue

基于顶点的PMI模型的运行时支持

在基于顶点的PMI模型内部,您可以访问几种函数。它们分为两组,即在PMI模型范围内有效的函数和仅在计算函数范围内有效的函数。

模型范围支持

标准基于顶点的PMI派生自基类PMI_Vertex_Interface;而简化基于顶点的PMI派生自基类PMI_Vertex_Base。两个基类都派生自PMI_Vertex_Common_Base类并提供以下共享功能:

Name():返回命令文件中指定的PMI模型名称。

Filename():返回相应共享对象文件的名称。

ReadRegionName():返回当前区域的名称。

ReadRegionMaterial():返回区域材料的名称。

ReadRegionMaterialGroup():查找材料组。可能的值:

  • PMI_Vertex_Common_Base::conductor
  • PMI_Vertex_Common_Base::insulator
  • PMI_Vertex_Common_Base::semiconductor
  • PMI_Vertex_Common_Base::unknown

基于 Sentaurus TCAD 官方文档构建

代码块