创建 CAE 插件——了解点状网格模型 API(第 2 部分)


发表于 2012 年 6 月 14 日, 大卫·加利施

这篇文章将介绍结构化逐点网格模型 (PWGM)。在了解逐点网格模型 API的第 1 部分中,我介绍了非结构化逐点网格模型。如果您还没有这样做,我建议您在继续之前阅读第 1 部分。

本讨论假定您已经熟悉结构化网格使用的 ijk 坐标系。此讨论还假定您熟悉结构化块的六个面。PWGM 将它们称为 i-min、j-min、k-min、i-max、j-max 和 k-max 块面。如果您不了解结构化块,您可能需要先做一些功课。

网格手柄

在这篇文章中,我将指代句柄。句柄是一种在不使用指针的情况下唯一标识 PWGM 对象的紧凑方式。对于那些熟悉 C/C++ 的人来说,Handle 可以被认为是 SDK 的 C++ this指针。非结构化 PWGM 支持五种句柄类型:

  • PWGM_HGRIDMODEL

  • PWGM_HBLOCK

  • PWGM_HBNDRY

  • PWGM_HCNXN

每种 Handle 类型都有一个或多个 SDK 函数,用于查询 Handle 代表的实体。您还可以使用各种 SDK 宏从句柄中提取信息。有关详细信息,请参阅CAE 插件 SDK 文档的模块/PWGM-API 不透明数据处理类型部分。

网格维数

与 Pointwise 本身一样,结构化 PWGM 支持 2D 和 3D 网格。但是,有一个关键区别:结构化 PWGM 为网格数据提供相同的接口,而不管其 2D 或 3D 维度如何。PWGM 的一致性是使用五个通用实体实现的;块、连接、边界、顶点和条件。具体来说,从结构化PWGM的角度来看:

  • 块是块顶点、连接和边界的集合。每个块都分配有一个卷条件,并由一个唯一的整数索引标识。索引范围从 0 到模型中的块数 (Nb) 减去 1 (0 … Nb-1)。

  • 连接定义了与相邻块共享”的块周边顶点的矩形部分。一个块可以有多个连接。顶级连接由唯一的整数索引标识。索引范围从 0 到模型中的连接数 (Nc) 减去 1 (0 … Nc-1)。块级连接由每个块内唯一的整数索引标识。索引范围从 0 到块中的连接数 (Ncb) 减去 1 (0 … Ncb-1)。

  • 边界定义了块的周边顶点的矩形部分,该矩形部分对于块是唯一的并且不相邻块“共享” 每个边界都被分配了一个边界条件。顶级边界由唯一的整数索引标识。指数范围从 0 到模型中的边界数 (Nd) 减去 1 (0 … Nd-1)。块级边界由每个块内唯一的整数索引标识。索引范围从 0 到块中的边界数 (Ndb) 减去 1 (0 … Ndb-1)。

  • 顶点是由值标识的单个 XYZ 块坐标PWGM_INDEX3。一个 PWGM_INDEX3值表示顶点在块中的 [i, j, k] 索引。ijk 分量值的范围从零到 ijk 点数减 1([0,0,0] 到 [Ni-1,Nj-1,Nk-1])。2D 和 3D 网格使用相同的数据类型。但是,对于二维网格,索引的 k 分量始终为零。

  • 条件是一组两个用户定义的属性和两个求解器定义的属性

插件使用相同的函数调用访问此实体层次结构。2D 和 3D 之间的区别仅在处理顶点、连接和边界时才会发挥作用。

网格层次结构

结构化 PWGM 以层次结构排列。这个层次结构的根是网格模型本身。在导出时,网格模型的句柄runtimeWrite()使用参数传递给插件的函数 PWGM_HGRIDMODEL model

[sourcecode language=”cpp” gutter=”true” toolbar=”false” wraplines=”false”]
PWP_BOOL runtimeWrite(CAEP_RTITEM *pRti, PWGM_HGRIDMODEL model, const CAEP_WRITEINFO *pWriteInfo);
// model 和 pWriteInfo 也可以使用 pRti->model 和 pRti->pWriteInfo
[/sourcecode]

结构化 PWGM 提供了一个单一的、以块为中心的网格数据视图。这个视图包括

  • 一个顶级连接数组。

  • 一个顶级边界数组。

  • 一个顶级块数组,其中每个块包含

    • 该数组是顶级 Boundaries 数组的子集。

    • 每个数组条目代表此块与自身或其他块建立的连接。

    • 该数组是顶级 Connections 数组的子集。

    • 一个PWGM_BLOCKDATA实例。

    • 一组块顶点

    • 一组块连接。

    • 一组块边界。

结构化网格模型层次结构如下图所示。

创建 CAE 插件——了解点状网格模型 API(第 2 部分)的图1

结构化网格模型层次结构

结构化数据类型

使用 [i,j,k] 索引访问结构化块的类数组布局中的每个顶点。PWGM 使用PWGM_INDEX3数据类型来表示 [i,j,k] 索引。该PwBlkNdxVertData()函数用于获取顶点的PWGM_VERTDATA信息。

[sourcecode language=”cpp” gutter=”true” toolbar=”false” wraplines=”false”]
typedef struct PWGM_INDEX3_t {
PWP_INT32 i; // 用于 3D 和 2D 网格的 i 坐标
PWP_INT32 j; // 用于 3D 和 2D 网格的 j 坐标
PWP_INT32 k; // k 坐标仅用于 3D 网格
}
PWGM_INDEX3;

PWP_BOOL PwBlkNdxVertData(PWGM_HBLOCK 块,PWGM_INDEX3 ndx3,PWGM_VERTDATA *pVertData);
[/源代码]

类似地,PWGM_STR_SIZE数据类型用于表示块的 [i,j,k] 顶点大小。A PWGM_STR_SIZE用于 2D 和 3D 网格。但是,对于二维网格,尺寸的 k 分量始终为 1。该PwBlkSize()函数用于获取块的大小。

[sourcecode language=”cpp” gutter=”true” toolbar=”false” wraplines=”false”]
typedef PWGM_INDEX3 PWGM_STR_SIZE;

PWP_BOOL PwBlkSize(PWGM_HBLOCK 块,PWGM_STR_SIZE *pSize);
[/源代码]

数据类型PWGM_STR_RANGE表示块子区域。范围由其对角线开始 ( beg) 和结束 ( end) 索引定义。

[sourcecode language=”cpp” gutter=”true” toolbar=”false” wraplines=”false”]
typedef struct PWGM_STR_RANGE_t {
PWGM_INDEX3 beg; // 开始索引
PWGM_INDEX3 结束;// 结束索引
}
PWGM_STR_RANGE;
[/源代码]

要有效,范围的开始索引必须小于或等于结束索引。

  • 开始.i <= 结束.i

  • 开始.j <= 结束.j

  • 开始.k <= 结束.k

在 PWGM 中,范围主要用于处理边界和连接。

一切都与连接有关

在 PWGM 中,每个结构化 Block 都有自己的局部 ijk 坐标系。因此,可以使用多个PWGM_INDEX3索引访问两个相邻块之间的连接中的每个顶点。这也可能发生在块与自身建立连接时(例如 C、O 或 H 拓扑)。使用多个本地坐标系通常会使导出连接成为结构化插件中最复杂的部分。

下图显示了一个简单的二维模型,其中包含两个相连的块。每个 Block 都有不同的 ij 方向。根据需要,每个 2D 块的右手法线(i 交叉 j)指向网格模型的同一“侧”(在本例中位于屏幕之外)。

创建 CAE 插件——了解点状网格模型 API(第 2 部分)的图2

两个带有顶点索引标记的 2D 结构化块。

这些块中的每一个都有一个连接。这两个单独的块级连接也存在于顶层连接数组中。下面列出了这两个连接。

  • Block[0] 从它的 i-max 面到 Block[1] 的 j-max 面

  • Block[1] 从它的 j-max 面到 Block[0] 的 i-max 面

如您所见,此连接的顶点通过 Block[0] 的索引与通过 Block[1] 的索引不同。假设二维网格的 k 为 0,

  • Block[0] 中的 Vertex[2,0,0] 与 Block[1] 中的 Vertex[0,2,0] 相同

  • Block[0] 中的 Vertex[2,1,0] 与 Block[1] 中的 Vertex[1,2,0] 相同

  • Block[0] 中的 Vertex[2,2,0] 与 Block[1] 中的 Vertex[2,2,0] 相同

PWGM 使用转换矩阵来转换块之间的连接 ijk 索引。使用这个矩阵以及一些 SDK 矩阵实用函数,一个块中的连接 ijk 索引可以转换为相邻块中的等效 ijk 索引。连接是使用PWGM_CNXNDATA数据类型定义的。

[sourcecode language=”cpp” gutter=”true” toolbar=”false” wraplines=”false”]
typedef struct PWGM_CNXNDATA_t {
const char *name; // 连接名称
PWGM_HBLOCK block1; // 连接块 1(源)
PWGM_FACE_ID face1;// 块 1 上的面 ID
PWGM_STR_RANGE range1; // block1 索引空间中的 ijk 连接范围
PWGM_INDEX_XFORM from1to2; // 将 block1 索引转换为 block2 索引
PWGM_HBLOCK block2; // 连接块 2(捐赠者)
PWGM_FACE_ID face2;// block2 上的面 ID
PWGM_STR_RANGE range2; // block2 索引空间中的 ijk 连接范围
PWGM_INDEX_XFORM from2to1; // 将 block2 索引转换为 block1 索引 (== inverse(from1to2)
}
PWGM_CNXNDATA;
[/源代码]

在 PWGM_CNXNDATA上面,PWGM_INDEX_XFORM from1to2PWGM_INDEX_XFORM from2to1矩阵是 3D 变换。如果您的求解器需要二维矩阵 ( PWGM_INDEX_XFORM2),则可以使用矩阵转换实用函数(见下文)。

以下 PWGM 函数用于访问有关连接的信息:

[sourcecode language=”cpp” gutter=”true” toolbar=”false” wraplines=”false”]
// 顶级连接函数
PWP_UINT32 PwModConnectionCount(PWGM_HGRIDMODEL 模型);
PWGM_HCNXN PwModEnumConnections(PWGM_HGRIDMODEL 模型,PWP_UINT32 ndx);
PWP_BOOL PwModNdxConnection(PWGM_HGRIDMODEL 模型,PWP_UINT32 ndx,PWGM_CNXNDATA *pCnxnData);

// 块级连接函数
PWP_UINT32 PwBlkConnectionCount (PWGM_HBLOCK block);
PWGM_HCNXN PwBlkEnumConnections(PWGM_HBLOCK 块,PWP_UINT32 ndx);
PWP_BOOL PwBlkNdxConnection(PWGM_HBLOCK 块,PWP_UINT32 ndx,PWGM_CNXNDATA *pCnxnData);

// 获取句柄的连接数据
PWP_BOOL PwConnection (PWGM_HCNXN connection, PWGM_CNXNDATA *pCnxnData);
[/源代码]

为了使用矩阵,PWGM 提供了以下结构化网格效用函数。

[sourcecode language=”cpp” gutter=”true” toolbar=”false” wraplines=”false”]

PWP_BOOL PwXform2to3 (const PWGM_INDEX_XFORM2 *pX2, PWGM_INDEX_XFORM *pX3);
PWP_BOOL PwXform3to2 (const PWGM_INDEX_XFORM *pX3, PWGM_INDEX_XFORM2 *pX2);

PWGM_INDEX3 PwXformApply (const PWGM_INDEX_XFORM *pX3, PWGM_INDEX3 ijk);
PWGM_ENUM_IJK PwXformFollows (const PWGM_INDEX_XFORM *pX3, PWGM_ENUM_IJK localAxis, PWP_BOOL *pFlipped);

PWGM_INDEX3 PwXform2Apply (const PWGM_INDEX_XFORM2 *pX2, PWGM_INDEX3 ijk);
PWGM_ENUM_IJK PwXform2Follows (const PWGM_INDEX_XFORM2 *pX2, PWGM_ENUM_IJK localAxis, PWP_BOOL *pFlipped);

PWP_BOOL PwInRange (PWGM_INDEX3 ijk, const PWGM_STR_RANGE *pRange);

[/源代码]

这个例子引用了上面的二维网格模型,并展示了如何使用索引转换函数。

[sourcecode language=”cpp” gutter=”true” toolbar=”false” wraplines=”false”]
// 获取 Block[0] 的句柄
PWGM_HBLOCK blk0 = PwModEnumBlocks(model, 0);

// 获取块[0].连接[0]
PWGM_CNXNDATA cnxnData;
if (PwBlkNdxConnection(blk0, 0, &cnxnData)) {
// 使用 Block[0] 的 ijk 空间初始化索引 blk0Ndx
PWGM_INDEX3 blk0Ndx = {2, 1, 0};

// 将 blk0Ndx 映射到 blk1Ndx 的 ijk 空间中的相同索引
PWGM_INDEX3 blk1Ndx = PwXformApply(&cnxnData.from1to2, blk0Ndx);

// blk1Ndx 现在设置为 {1, 2, 0}
}
[/sourcecode]

如果您的插件导出到的解算器也使用连接矩阵,您会感到很幸运。但是,如果您的求解器使用不同的映射方法,您的插件必须将每个 PWGM 连接矩阵转换为适合求解器的形式。遗憾的是,将 PWGM 连接矩阵转换为求解器的非矩阵映射方案的细节可能很复杂,超出了本文的范围。

界限是有限的

边界是位于网格模型周边的块面的任何部分,与相邻块没有任何共同的顶点使用句柄访问边界PWGM_HBNDRYPWGM_BNDRYDATA使用此句柄,您可以使用和数据类型获取边界的形状和条件信息PWGM_CONDDATA。边界 API 数据类型和函数如下所列:

[sourcecode language=”cpp” gutter=”true” toolbar=”false” wraplines=”false”]
typedef enum PWGM_FACE_ID_e {
PWGM_FACE_KMIN, // 最小 K
PWGM_FACE_KMAX, // 最大 K
PWGM_FACE_IMIN, // 最小 I
PWGM_FACE_IMAX, // 最大I
PWGM_FACE_JMIN, // 最小 J
PWGM_FACE_JMAX, // 最大 J
}
PWGM_FACE_ID;

typedef struct PWGM_BNDRYDATA_t {
const char *name; // 边界名称
PWGM_HBLOCK 块;// 边界块
PWGM_FACE_ID 人脸;// 边界面 id
PWGM_STR_RANGE 范围;// 边界 ijk 范围
}
PWGM_BNDRYDATA;

typedef struct PWGM_CONDDATA_t {
const char *name; // 网格定义的条件名称
PWP_UINT32 id; // 网格定义条件 id
const char *type; // cae 定义的条件物理类型名称
PWP_UINT32 tid; // cae 定义的条件 id
}
PWGM_CONDDATA;

PWP_BOOL PwModNdxBoundary(PWGM_HGRIDMODEL 模型,PWP_UINT32 ndx,PWGM_BNDRYDATA *pBndryData);
PWP_BOOL PwModNdxBoundaryAndCondition(PWGM_HGRIDMODEL 模型,PWP_UINT32 ndx,PWGM_BNDRYDATA *pBndryData,PWGM_CONDDATA *pCondData);

PWP_BOOL PwBlkNdxBoundary(PWGM_HBLOCK 块,PWP_UINT32 ndx,PWGM_BNDRYDATA *pBndryData);
PWP_BOOL PwBlkNdxBoundaryAndCondition(PWGM_HBLOCK 块,PWP_UINT32 ndx,PWGM_BNDRYDATA *pBndryData,PWGM_CONDDATA *pCondData);

PWP_BOOL PwBoundary (PWGM_HBNDRY 边界, PWGM_BNDRYDATA *pBndryData);
PWP_BOOL PwBndryCondition (PWGM_HBNDRY 边界, PWGM_CONDDATA *pCondData);
[/源代码]

枚举实体

PWGM 提供对所有网格实体的枚举、随机访问。使用此方案,为每个实体提供一个 SDK 功能以确定网格模型中存在的项目数。然后将计数与其他相关的枚举 SDK 函数一起使用,以逐一遍历项目层次结构。例如,网格模型块的数量是使用该PwModBlockCount()函数确定的。有了这个计数,您就可以使用该函数枚举块PwModEnumBlocks()。PWGM 枚举函数返回请求项的句柄。顶级模型级函数名称以PwMod前缀开头。这些函数都将网格模型句柄作为输入,并向枚举的网格模型实体返回计数或句柄。结构化 PWGM 目前支持的顶级模型级功能是

[sourcecode language=”cpp” gutter=”true” toolbar=”false” wraplines=”false”]
PWP_UINT32 PwModBlockCount(PWGM_HGRIDMODEL 模型)
PWGM_HBLOCK PwModEnumBlocks(PWGM_HGRIDMODEL 模型,PWP_UINT32 ndx)

PWP_UINT32 PwModConnectionCount(PWGM_HGRIDMODEL 模型);
PWGM_HCNXN PwModEnumConnections(PWGM_HGRIDMODEL 模型,PWP_UINT32 ndx);

PWP_UINT32 PwModBoundaryCount(PWGM_HGRIDMODEL 模型);
PWGM_HBNDRY PwModEnumBoundaries(PWGM_HGRIDMODEL 模型,PWP_UINT32 ndx);
PWP_BOOL PwModNdxBoundary(PWGM_HGRIDMODEL 模型,PWP_UINT32 ndx,PWGM_BNDRYDATA *pBndryData);
PWP_BOOL PwModNdxBoundaryAndCondition(PWGM_HGRIDMODEL 模型,PWP_UINT32 ndx,PWGM_BNDRYDATA *pBndryData,PWGM_CONDDATA *pCondData);
[/源代码]

枚举块的连接和边界以类似的方式完成。首先,您使用适当的块句柄(使用 )获得所需的块连接或边界计数PwModEnumBlocks。然后,使用计数,逐个枚举每个连接或边界,获得它的句柄。最后通过Handle获取对应的Connection或Boundary数据。PWGM目前支持的Block功能有

[sourcecode language=”cpp” gutter=”true” toolbar=”false” wraplines=”false”]
PWP_BOOL PwBlkSize (PWGM_HBLOCK block, PWGM_STR_SIZE *pSize);
PWP_BOOL PwBlock(PWGM_HBLOCK 块,PWGM_BLOCKDATA *pBlockData);

PWP_UINT32 PwBlkBoundaryCount(PWGM_HBLOCK 块);
PWGM_HBNDRY PwBlkEnumBoundaries(PWGM_HBLOCK 块,PWP_UINT32 ndx);
PWP_BOOL PwBlkNdxBoundary(PWGM_HBLOCK 块,PWP_UINT32 ndx,PWGM_BNDRYDATA *pBndryData);
PWP_BOOL PwBlkNdxBoundaryAndCondition(PWGM_HBLOCK 块,PWP_UINT32 ndx,PWGM_BNDRYDATA *pBndryData,PWGM_CONDDATA *pCondData);

PWP_UINT32 PwBlkConnectionCount(PWGM_HBLOCK 块);
PWGM_HCNXN PwBlkEnumConnections(PWGM_HBLOCK 块,PWP_UINT32 ndx);
PWP_BOOL PwBlkNdxConnection(PWGM_HBLOCK 块,PWP_UINT32 ndx,PWGM_CNXNDATA *pCnxnData);
[/源代码]

每个块都有一个关联的PWGM_BLOCKDATA实例。数据类型PWGM_BLOCKDATA定义为:

[sourcecode language=”cpp” gutter=”true” toolbar=”false” wraplines=”false”]
typedef struct PWGM_BLOCKDATA_t {
const char *name; // 命名
PWGM_HBLOCK 块;// 处理
PWGM_ENUM_GRIDTYPE 网格类型;// 网格类型
PWGM_STR_SIZE 大小;// 顶点大小
}
PWGM_BLOCKDATA;
[/源代码]

不要被愚弄

上面使用的简单 2D 示例网格非常适合解释想法。然而,它的简单性具有欺骗性。一个典型的结构化网格模型会有很多块、连接和边界。此外,任何给定的块面通常连接到多个相邻块,如下面稍微复杂的 3D 示例所示。

创建 CAE 插件——了解点状网格模型 API(第 2 部分)的图3

3D 网格模型示例和 i-min 面部细节

在这个例子中,大块的 i-min 面被分成两个连接(灰色)和五个边界。大量的 i-min 边界是由结构化网格模型中范围的矩形性质引起的。

退化的六边形

除了巫术,Pointwise 支持创建极网格实体。那是

  • 连接器可以折叠成单点杆。

  • 域可以折叠为边缘或单点极点。

这意味着网格模型中可能存在退化(也称为折叠)六角形单元格。PWGM 不区分包含极点和不包含极点的网格模型。PWGM 假设结构化求解器可以处理这些类型的网格。因此,如果不比较物理 XYZ 坐标,就没有找到折叠连接或边界的有效方法。如果 PWGM 中的此限制阻止您为求解器创建插件,请告知 Pointwise 支持。

当我开始写这篇文章时,我低估了清楚地描述结构化 PWGM 的难度。许多小时和修改后,我希望你觉得解释有用。有了这些信息,您将能够利用 Pointwise CAE 插件 SDK 创建一个插件,将您的结构化求解器添加到 Pointwise。与往常一样,如果您有任何其他问题,请随时联系 Pointwise 支持。我们随时为您提供帮助!

我还不确定下一篇文章的主题是什么。如果您有任何建议,请让我知道。同时,您可以通过单击下面的按钮了解有关 Pointwise CAE 插件 SDK 和 PWGM 的更多信息。

文章来源:pointwise博客

原文链接:https://blog.pointwise.com/2012/06/14/creating-a-cae-plugin-understanding-the-pointwise-grid-model-api-part-2/

默认 最新
当前暂无评论,小编等你评论哦!
点赞 评论 收藏
关注