創建 CAE 插件——了解點狀網格模型 API(第 1 部分)

CAE 插件的主要目的是導出網格模型。為此,插件必須將 Pointwise 表示的網格數據轉換為插件所針對的求解器支持的格式。要正確進行此轉換,您必須對點狀網格模型 (PWGM) 有透徹的了解。

對于這篇文章,我將重點關注非結構化 PWGM。結構化 PWGM 將在以后的帖子中介紹。雖然結構化 PWGM 和非結構化 PWGM 之間有很多共同點,但也存在一些根本性差異,因此兩篇文章比一篇文章更好地介紹了它們。

網格手柄

在這篇文章中,我將提到句柄。句柄是一種無需使用指針即可唯一標識任何 PWGM 實體或元素的緊湊方式。對于那些熟悉 C/C++ 的人來說,Handle 可以被認為是 SDK 的 C++ this指針。非結構化 PWGM 支持五種句柄類型:

  • PWGM_HGRIDMODEL

  • PWGM_HBLOCK

  • PWGM_HDOMAIN

  • PWGM_HVERTEX

  • PWGM_HELEMENT

每種 Handle 類型都有一個或多個 SDK 函數,用于查詢 Handle 代表的實體。SDK 使用函數命名方案,其中名稱的前綴反映了被查詢的實體句柄。例如,所有以 a 開頭的函數都將PwDomaPWGM_HDOMAIN作為它們的第一個參數(域的this指針)。

使用 Handles 還可以減少 SDK 函數所需的參數數量。它們的使用還允許在您的插件代碼中進行更簡單的函數調用。例如,如果沒有句柄,塊元素函數將需要三個參數來唯一標識給定的 PWGM 塊元素:

[sourcecode language=”cpp” gutter=”true” toolbar=”false”]
elementFunction(model, blkIndex, elementIndex, otherArgsHere);
[/源代碼]

但是,使用句柄,函數調用變為:

[sourcecode language=”cpp” gutter=”true” toolbar=”false”]
elementFunction(hElement, otherArgsHere);
[/源代碼]

您還可以使用各種 SDK 宏從句柄中提取信息。有關詳細信息,請參閱CAE 插件 SDK 文檔的模塊/PWGM-API 不透明數據處理類型部分。

網格層次結構

非結構化 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 分為兩個不同但相關的視圖。第一個視圖提供對網格模型的以單元格為中心的訪問。第二個視圖提供以面為中心的網格模型訪問。

當前 1.0 R3 版本的插件 SDK 中不提供以人臉為中心的視圖 API。但是,編碼已完成并正在測試中。我希望在接下來的幾周內發布它

更新:以人臉為中心的視圖 API 現在可用于 Pointwise v17.1 + Plugin SDK v1.0 R4!

在以細胞為中心的視圖中,網格模型包括

  • 一組塊,每個塊都有一組單元格元素和一個條件。

  • 一組域,每個域都有一組面元素和一個條件。

  • 一組頂點。

在以面為中心的視圖中,網格模型包括

  • 所有塊單元格元素的一個數組。

  • 所有單元面元素的一個數組,包括位于網格邊界上的面和網格內部的面。

  • 一組頂點。

重要的是要注意,以單元為中心的視圖和以面為中心的視圖都使用相同的頂點數組。如上所述,頂點是將兩種觀點聯系在一起的共同關系。完整的網格模型層次結構如下圖所示。

創建 CAE 插件——了解點狀網格模型 API(第 1 部分)的圖1

網格模型層次結構

網格維數

對于注意到上面的討論沒有提到 2D 網格與 3D 網格的人來說,這是一顆金星。這是因為 PWGM 使訪問網格數據(大部分)獨立于網格的維度。

與 Pointwise 本身一樣,PWGM 支持 2D 和 3D 網格。但是,有一個關鍵區別。PWGM 獨立于其 2D 或 3D 維度為網格數據提供相同的接口。PWGM 的一致性是使用五個通用實體實現的;塊、域、元素、頂點和條件。具體來說,從 PWGM 的角度來看:

  • 一個是塊元素的集合,所有元素都被分配了一個共同的體積條件。每個塊都由一個唯一的整數索引標識。索引范圍從 0 到模型中的塊數 (Nb) 減去 1 (0 … Nb-1)。

  • 域是域元素的集合,所有域元素都分配了一個公共邊界條件每個域都由一個唯一的整數索引標識。指數范圍從 0 到模型中的域數 (Nd) 減去 1 (0 … Nd-1)。

  • 頂點是由唯一整數索引標識的單個 XYZ 坐標。索引范圍從 0 到模型中的頂點數 (Nv) 減去 1 (0 … Nv-1)。

  • 元素是頂點索引的有序集合索引順序定義了元素的連接性(請參閱模塊/單元連接性)。

  • 條件是一組兩個用戶定義的屬性和兩個求解器定義的屬性

插件使用相同的函數調用訪問此實體層次結構。2D 和 3D 之間的區別僅在元素中發揮作用。例如,3D 塊的元素是六邊形、棱柱、金字塔和四邊形。3D 邊界域的元素是三邊形和四邊形。同樣,二維塊的元素是三邊形和四邊形。二維邊界域的元素是條(線)。下表總結了 PWGM 網格實體、它們的元素和相應的逐點網格實體之間的關系。

創建 CAE 插件——了解點狀網格模型 API(第 1 部分)的圖2

按維度劃分的網格模型元素類型和 Pointwise 實體類型

在將您在 Pointwise 中創建的網格傳遞給插件之前,共享相同邊界條件的 Pointwise 邊界實體(3D 域或 2D 連接器)被合并到一個 PWGM 域中。因此,PWGM 域的數量可能與點邊界實體的數量不同,具體取決于點邊界條件應用于網格的方式。

相反,共享共同體積條件的逐點體積(3D 中的塊或 2D 中的域)不會合并。這意味著 PWGM 塊的數量始終等于 Pointwise 體積實體的數量。下圖說明了 2D Pointwise 網格如何出現在以單元為中心的視圖的插件中。

創建 CAE 插件——了解點狀網格模型 API(第 1 部分)的圖3

邊界合并如何在將點狀網格傳遞給插件(以單元為中心的視圖)之前更改點狀網格。

在以面為中心的視圖中,邊界和體積條件的合并沒有意義,因為塊和域僅作為單元和面元素訪問。下圖說明了相同的 2D Pointwise 網格如何出現在以面為中心的視圖的插件中。

創建 CAE 插件——了解點狀網格模型 API(第 1 部分)的圖4

在以面為中心的視圖中,Pointwise 網格如何呈現給插件。

枚舉實體

PWGM 提供對所有網格實體及其相應元素的枚舉、隨機訪問,但以面為中心的視圖中的面除外。使用此方案,為每個實體或實體元素提供一個 SDK 功能以確定網格模型中存在的項目數。然后將計數與其他相關的枚舉 SDK 函數一起使用,以逐一遍歷項目層次結構。例如,網格模型塊的數量是使用該PwModBlockCount()函數確定的。有了這個計數,您就可以使用該函數枚舉塊PwModEnumBlocks()。PWGM 枚舉函數返回請求項的句柄。頂部的模型級函數名稱以PwMod字首。這些函數都將網格模型句柄作為其輸入,并向枚舉的網格模型實體返回計數或句柄。非結構化 PWGM 目前支持的頂級模型級功能是

[sourcecode language=”cpp” gutter=”true” toolbar=”false”]
PWP_UINT32 PwModBlockCount (PWGM_HGRIDMODEL 模型);
PWGM_HBLOCK PwModEnumBlocks(PWGM_HGRIDMODEL 模型,PWP_UINT32 ndx);
PWP_UINT32 PwModDomainCount(PWGM_HGRIDMODEL 模型);
PWGM_HDOMAIN PwModEnumDomains(PWGM_HGRIDMODEL 模型,PWP_UINT32 ndx);
PWP_UINT32 PwModVertexCount(PWGM_HGRIDMODEL 模型);
PWGM_HVERTEX PwModEnumVertices(PWGM_HGRIDMODEL 模型,PWP_UINT32 ndx);
[/源代碼]

枚舉塊或域的元素以類似的方式完成。首先,您使用適當的塊或域句柄(使用上述函數獲得)獲得實體的元素計數。然后,使用計數,逐個枚舉元素,獲得每個元素的句柄。元素的句柄用于獲取元素的數據。PWGM 目前支持的 Block 和 Domain Element 功能是

[sourcecode language=”cpp” gutter=”true” toolbar=”false”]
PWP_UINT32 PwBlkElementCount (PWGM_HBLOCK block, PWGM_ELEMCOUNTS *pCounts);
PWGM_HELEMENT PwBlkEnumElements(PWGM_HBLOCK 塊,PWP_UINT32 ndx);
PWP_UINT32 PwDomElementCount(PWGM_HDOMAIN 域,PWGM_ELEMCOUNTS *pCounts);
PWGM_HELEMENT PwDomEnumElements(PWGM_HDOMAIN 域,PWP_UINT32 ndx);
[/源代碼]

使用兩個函數獲取元素的數據:

[sourcecode language=”cpp” gutter=”true” toolbar=”false”]
PWP_BOOL PwElemDataMod (PWGM_HELEMENT element, PWGM_ELEMDATA *pData);
PWP_BOOL PwEnumElemDataMod(PWGM_HELEMENT 元素,PWGM_ENUMELEMDATA *pData);
[/源代碼]

除了元素之外,每個塊和域都有一個關聯的條件。條件表示塊的體積條件或域的邊界條件。使用下面列出的函數獲取條件數據:

[sourcecode language=”cpp” gutter=”true” toolbar=”false”]
PWP_BOOL PwBlkCondition (PWGM_HBLOCK block, PWGM_CONDDATA *pCondData);
PWP_BOOL PwDomCondition(PWGM_HDOMAIN 域,PWGM_CONDDATA *pCondData);
[/源代碼]

網格模型的 XYZ 頂點數據是使用下面列出的函數獲得的。特定導出格式的細節將決定使用哪些功能。有關詳細信息,請參閱插件文檔。

[sourcecode language=”cpp” gutter=”true” toolbar=”false”]
PWP_BOOL PwVertDataMod (PWGM_HVERTEX vertex, PWGM_VERTDATA *pVertData);
PWP_BOOL PwVertIndexMod (PWGM_HVERTEX 頂點, PWP_UINT32 *pIndex);
PWP_BOOL PwVertXyzVal (PWGM_HVERTEX 頂點, PWGM_ENUM_XYZ 其中, PWGM_XYZVAL *pVal);
[/源代碼]

流媒體實體

PWGM 提供對以人臉為中心的視圖的人臉的“流式”訪問。從某種意義上說,它們是流式傳輸的,一次可以讓一個插件使用這些面孔。一旦插件完成了面部元素,它就無法再次訪問面部元素,除非從頭開始重新啟動流(除非您在插件中制作面部數據的本地副本)。

我們決定在 PWGM 中使用人臉流,以最大限度地減少導出過程中消耗的額外內存量。Pointwise 沒有明確存儲網格面信息。因此,為了提供以面部為中心的視圖,PWGM 需要處理以細胞為中心的數據并將其轉換為以面部為中心的表示。為枚舉、隨機訪問存儲完整的、以面部為中心的視圖可以使以細胞為中心的視圖已經需要的 RAM 量增加一倍以上。而且,正如我們的許多客戶已經知道的那樣,大型網格模型可能會超出許多現代計算機的 RAM 限制。添加非流式面部元素數據可能會超過計算機可用的 RAM,并且根本無法導出一些大網格!

插件通過調用 PwModStreamFaces()SDK 函數啟動人臉流會話。此函數接受一個PWGM_ENUM_FACEORDER值、三個回調函數和一個用戶數據指針。

[sourcecode language=”cpp” gutter=”true” toolbar=”false”]
PWP_BOOL PwModStreamFaces(PWGM_HGRIDMODEL model, PWGM_ENUM_FACEORDER order,
PWGM_BEGINSTREAMCB beginCB, PWGM_FACESTREAMCB faceCB,
PWGM_ENDSTREAMCB endCB, void *userData);
[/源代碼]

可選的用戶數據指針可以設置為 null 或者它可以用于將插件特定的運行時信息傳遞給流會話的所有階段。用戶數據指針被傳遞給三個回調中的每一個。

面部順序值控制面部在流式傳輸期間的分組方式。下面列出了支持的訂單。

[sourcecode language=”cpp” gutter=”true” toolbar=”false”]
typedef enum PWGM_ENUM_FCEORDER_e {
PWGM_FACEORDER_DONTCARE, // 任意順序的所有單元面
PWGM_FACEORDER_BOUNDARYFIRST, // 邊界內的所有單元面,內部順序
PWGM_FACEORDER_INTERIORFIRST, // 所有單元內部面,邊界順序
PWGM_FACEORDER_BOUNDARYONLY, // 只有邊界單元面
PWGM_FCEORDER_INTERIORONLY, // 只有內部單元面
PWGM_FCEORDER_BCGROUPSFIRST, // BoundaryFirst 按 BCs 分組
PWGM_FACEORDER_BCGROUPSLAST, // InteriorFirst 按 BCs
分組 PWGM_FACEORDER_BCGROUPSONLY, //
Boundary_UM_WORDER
}
[/源代碼]

使用三個回調函數將面孔流式傳輸到插件。beginCB()PWGM 在流會話開始時調用一次回調。此回調接收將流式傳輸的邊界、內部和總面數。

[sourcecode language=”cpp” gutter=”true” toolbar=”false”]
PWP_BOOL beginCB(PWGM_BEGINSTREAM_DATA *data);

typedef struct PWGM_BEGINSTREAM_DATA_t {
PWGM_ENUM_FACEORDER 命令;//請求的單元格面流序列順序。
PWP_UINT32 totalNumFaces;// 模型中的總面數(= #Boundary + #Interior)。
PWP_UINT32 numBoundaryFaces;// # totalNumFaces 中的面位于模型的邊界上。
PWP_UINT32 numInteriorFaces;// # totalNumFaces 中位于模型內部的面。
PWGM_ELEMCOUNTS 計數;// 模型的總元素數。
PWGM_HGRIDMODEL 模型;// 網格模型句柄
void *userData; // 指針傳遞給 PwModStreamFaces(…, void *userData)
}
PWGM_BEGINSTREAM_DATA;
[/源代碼]

當插件從 返回時beginCB(),PWGM 開始處理以單元格為中心的數據。面完成后,它們將傳遞給faceCB()回調。傳遞給此回調的信息包括面類型(內部或邊界)、面頂點和面任一側的塊單元格元素。

[sourcecode language=”cpp” gutter=”true” toolbar=”false”]
PWP_BOOL faceCB(PWGM_FACESTREAM_DATA *data);

typedef struct PWGM_FACESTREAM_DATA_t {
PWGM_HGRIDMODEL 模型;// 網格模型句柄
PWP_UINT32 面;// 人臉在模型索引空間中的索引
PWGM_ELEMDATA elemData; // 人臉的元素數據。
PWGM_ENUM_FACETYPE 類型;// PWGM_FACETYPE_XXX 類型之一。
PWGM_FACEREF_DATA 所有者;// 擁有面的塊元素。
PWGM_FACEREF_DATA 鄰居;// 面另一側的塊元素。// 如果類型為 PWGM_FACETYPE_BOUNDARY,則此值
未定義。
無效*用戶數據;// 指針傳遞給 PwModStreamFaces(…, void *userData)
}
PWGM_FACESTREAM_DATA;
[/源代碼]

最后一張臉傳遞給 后faceCB(),PWGM 對回調進行最后一次調用endCB()

[sourcecode language=”cpp” gutter=”true” toolbar=”false”]
PWP_BOOL endCB(PWGM_ENDSTREAM_DATA *data);

typedef struct PWGM_ENDSTREAM_DATA_t {
PWGM_HGRIDMODEL 模型;// 網格模型句柄
PWP_BOOL ok; // PWP_TRUE 如果流式傳輸成功完成
void *userData; // 指針傳遞給 PwModStreamFaces(…, void *userData)
}
PWGM_ENDSTREAM_DATA;
[/源代碼]

以下示例 C++ 代碼顯示了正在使用的流式 API。

[sourcecode language=”cpp” collapse=”true”]
/*************************************** **/
PWP_UINT32
beginCB(PWGM_BEGINSTREAM_DATA *data)
{
// 將用戶數據指針轉換為 CAEP_RTITEM*
CAEP_RTITEM *pRti = (CAEP_RTITEM*)data->userData;

// 在這里進行初始化

// 設置開始進度步數
 return caeuProgressBeginStep(pRti, data->totalNumFaces);
}

/******************************************/
PWP_UINT32
faceCB(PWGM_FACESTREAM_DATA *data)
{
//將用戶數據指針轉換為 CAEP_RTITEM*
CAEP_RTITEM *pRti = (CAEP_RTITEM*)data->userData;

// 處理這張臉
if (PWGM_FACETYPE_INTERIOR == data->type) {
// 做點什么
}
else if (PWGM_FACETYPE_BOUNDARY == data->type) {
// 做點別的
 }

// 遞增進度
return caeuProgressIncr(pRti);
}

/******************************************/
PWP_UINT32
endCB(PWGM_ENDSTREAM_DATA *data)
{
//將用戶數據指針轉換為 CAEP_RTITEM*
CAEP_RTITEM *pRti = (CAEP_RTITEM*)data->userData;

// 在這里執行最后的清理

// 結束進度步驟
return caeuProgressEndStep(pRti);
}

/******************************************/
PWP_BOOL
runtimeWrite(CAEP_RTITEM *pRti,PWGM_HGRIDMODEL 模型,
const CAEP_WRITEINFO * /*pWriteInfo*/)
{
PWP_BOOL ret = PWP_FALSE;
if (caeuProgressInit(pRti, 2) && writePointsFile(*pRti)) {
// 在此示例中,將 pRti 作為 PwModStreamFaces(…, void *userData) 參數傳遞。
// 但是,可以使用任何特定于實現的值。
ret = PwModStreamFaces(模型,PWGM_FACEORDER_BCGROUPSLAST,beginCB,faceCB,endCB,pRti);
}
caeuProgressEnd(pRti, ret);
返還;
}
[/源代碼]

了解 Pointwise CAE 插件 SDK 中可用的非結構化網格模型后,您應該能夠創建一個插件,將您選擇的求解器添加到 Pointwise。與往常一樣,如果您有任何其他問題,請隨時聯系 Pointwise 支持。我們隨時為您提供幫助!

我將在下一篇文章中介紹結構化網格模型。

文章來源:pointwise博客
原文:https://blog.pointwise.com/2012/05/23/creating-a-cae-plugin-understanding-the-pointwise-grid-model-api-part-1/

登錄后免費查看全文
立即登錄
App下載
技術鄰APP
工程師必備
  • 項目客服
  • 培訓客服
  • 平臺客服

TOP