Palabos用戶手冊翻譯及學習(一)基礎數據類型

基礎數據類型

Palabos用戶文檔 的第六章

(一)The BlockXD data structures

原始文檔

The fundamental data structures which hold the variables of a simulation are of type Block2D for 2D simulations, and of type Block3D for simulation (in the following, we use the generic name BlockXD to keep the discussion short, although there exists no type BlockXD in Palabos). From the standpoint of a user, a BlockXD construct represents a regular 2D or 3D array (or matrix) of data. Behind the scenes, they are sometimes really implemented as regular arrays and sometimes as more complicated constructs, which allows for example memory savings through sparse memory implementations, or parallel program executions based on a data-parallel model.
The BlockXD structures are specializes for different areas of application. One type of specializations is used to specify the type of data stored in the blocks. To store the particle populations of a lattice Boltzmann simulation, and potentially other variables such as external forces, you’ll use a specialization in which the name Block is replaced by BlockLattice. To store a spatially extended scalar variable, the data type to use is a variant of the ScalarFieldXD, whereas vector- or tensor-valued fields are stored in a TensorFieldXD or similar. A second type of specialization is applied to specify the nature of the underlying data structure. The AtomicBlockXD data structure stands essentially for a regular data array, whereas the MultiBlockXD is a complex construct in which the space corresponding to a BlockXD is partially or entirely covered by smaller blocks of type AtomicBlockXD. The MultiBlockXD and the AtomicBlockXD have practically the same user interface, and you are urged to systematically use the more general MultiBlockXD in end-user applications. It is almost as efficient as the AtomicBlockXD for regular problems, it can be used to represent irregular domains, and it is automatically parallelizable.

The following figure illustrates the C++ inheritance hierarchy between the various specializations of the BlockXD :

The figure shows, as an example, a few functions implemented at each level of the inheritance hierarchy. For example, all blocks of type “block-lattice” have a method collideAndStream(), no matter if they are implemented as a multi-block or an atomic-block. In the same way, all multi-blocks have a method getComponent(), no matter if they are of type block-lattice, scalar-field, or tensor-field. The situation shown on this figure is referred to as “multiple inheritance”, because end-user classes inherit from BlockXD in two ways: once through the atomic- vs. multi-block path, and once through the block-lattice vs. scalar- vs. tensor-field path. Note that multiple inheritance is often considered as bad practice because it can lead to error-prone code; in the present case however, we’ve had positive experiences so far with the inheritance diagram shown above, because it is easy to use and represents the two facets of a BlockXD in a natural way.

文檔翻譯

保存用於模擬的變量值的基本數據結構有兩種,用於2D仿真的Block2D類型和用於仿真的Block3D類型(在下面,我們使用通用名稱BlockXD來保持簡短的討論,儘管Palabos中不存在類型BlockXD)。從用戶的角度來看,BlockXD結構表示一個常規的2D或3D數組(或矩陣)的數據。在幕後,它們有時作爲常規數組實現,有時作爲更復雜的構造實現,比如通過稀疏內存實現來節省內存,或者基於數據並行模型執行並行程序。
BlockXD結構有專門針對不同作用域的應用,第一種特化類型用於指定存儲在塊中的數據的類型。存儲格玻爾茲曼模擬的粒子羣,以及可能的其他變量,如外力,您將使用一種專門化的BlockXD結構,其中名稱Block將被BlockLattice替換。要存儲空間擴展的標量變量,使用的數據類型是ScalarFieldXD的變體,而向量或張量值字段存儲在TensorFieldXD或類似的數據類型中。第二種特化類型用於指定底層數據結構的性質。AtomicBlockXD數據結構本質上代表一個常規的數據數組,而MultiBlockXD是一個複雜的結構,其中與BlockXD對應的空間由類型爲AtomicBlockXD的較小塊部分或全部覆蓋。MultiBlockXD和AtomicBlockXD實際上具有相同的用戶界面,我們敦促您在最終用戶應用程序中系統地使用更通用的MultiBlockXD。對於常規問題,它幾乎與AtomicBlockXD一樣有效,它可以用來表示不規則域,並且它是自動並行的。

下圖展示了BlockXD不同特化版本之間的C++繼承層次圖:

作爲一個例子,圖中顯示了在繼承層次結構的每一層實現的幾個函數。例如,所有類型爲“block-lattice”的塊都有一個collideAndStream()方法,不管它們是作爲多塊還是原子塊實現的。同樣,所有多塊都有一個getComponent()方法,不管它們是塊格、標量字段還是張量字段類型。該圖中顯示的情況被稱爲“多重繼承”,因爲最終用戶類以兩種方式從BlockXD繼承:一次通過原子與多塊路徑,一次通過塊格與標量與張量字段路徑。注意,多重繼承通常被認爲是不好的做法,因爲它會導致容易出錯的代碼;然而,在目前的情況下,我們對上面所示的繼承關係圖已經有了積極的體驗,因爲它易於使用,並且以自然的方式表示了BlockXD的兩個方面。

解釋說明

每一個案例都需要新建BlockXD下屬的Block-Lattice類,其中BlockLatticeXD爲單塊格的計算格子域,無法並行,並行版本爲MultiBlockLatticeXD類,並行由計算域分塊來實現,類中按照程序設定的並行核數,會在每次聲明對象時在類內部生成相應的BlockLatticeXD指針列表。一般情況下,在使用MultiBlockLatticeXD類時,你只需要,爲它提供計算域尺寸和背景動態類(也就是默認動態類),爲了使動態類可以共享,減少內存消耗,所以在類內部是以指針的方式存儲動態類的一個引用地址,在聲明時初始化MultiBlockLatticeXD對象時,應在堆區新建一個動態類對象,也就是new一個動態類對象,把指針地址傳入。
以下爲聲明對象的一個語法,Nx,Ny分別爲計算域的尺寸,堆區新建了一個BGKdynamics類,並將指針作爲實參交給lattice對象。<T, DESCRIPTOR>爲模板參數,將在下一節予以介紹。

MultiBlockLattice2D<T, DESCRIPTOR> lattice(Nx, Ny, new BGKdynamics<T,DESCRIPTOR>);

類繼承圖上的類只有標顏色的終端類可以使用,其他的類都不可以使用,都是屬於抽象類,無法實例化。

(二) Lattice descriptors

原始文檔

All BlockXD constructs are templatized with respect to the underlying data type. In practice, this feature is used to switch between single-precision and double-precision arithmetics by changing just one word in the end-user program:

// Construct a 100x100 scalar-field with double-precision floating point values.
MultiScalarField2D<double> a(100,100);
// Construct a 100x100 scalar-field with single-precision floating point values.
MultiScalarField2D<float> b(100,100);

Block-lattices additionally have a template parameter, the lattice descriptor, which specifies a few topological properties of the lattice (the number of particle populations, the discrete velocities, the weights of the directions, and other lattice constants). It is therefore easy to try out different lattices in an application:

// Construct a 100x100 block-lattice using the D3Q19 structure.
MultiBlockLattice2D<double, D3Q19Descriptor> lattice1(100,100);
// Construct a 100x100 block-lattice using the D3Q27 structure.
MultiBlockLattice2D<double, D3Q27Descriptor> lattice2(100,100);

It is also easy to write a new lattice descriptor (this is currently not documented, but you can check out the files in the directory src/latticeBoltzmann/nearestNeighborLattices2D.h to see how it works). This is extremely useful, because it means that you don’t need to re-write the lengthy code parts for the implementation of a BlockLatticeXD when you switch to a new type of lattice. This argument is part of a general concept described in the section Non-intrusive program development with Palabos.

文檔翻譯

所有BlockXD構造都是根據底層數據類型進行模板化的。在實踐中,這個功能是用來切換單精度和雙精度算術,只需在最終用戶程序中改變一個單詞:

// 構建一個 100x100 的雙精度浮點值的標量場
MultiScalarField2D<double> a(100,100);
// 構建一個 100x100 的單精度浮點值的標量場
MultiScalarField2D<float> b(100,100);

Block-Lattice還有一個模板參數,格子描述符descriptor,它指定了格的一些拓撲屬性(粒子的數量,離散速度,方向的權重,和其他格子常數)。在一個應用程序中嘗試不同的格是很容易的:

// 構建一個 100x100 塊格結構使用 D3Q19 描述符
MultiBlockLattice2D<double, D3Q19Descriptor> lattice1(100,100);
// 構建一個 100x100 塊格結構使用 D3Q27 描述符
MultiBlockLattice2D<double, D3Q27Descriptor> lattice2(100,100);

編寫一個新的晶格描述符也很容易(目前還沒有文檔說明,但是您可以查看src/latticeBoltzmann/nearestNeighborLattices2D.h目錄中的文件,瞭解它是如何工作的)。這是非常有用的,因爲這意味着當您切換到一種新類型的格時,您不需要爲BlockLatticeXD的實現重寫冗長的代碼部分。這個是Palabos的非介入式程序開發一節中描述的一般概念的一部分。

解釋說明

這部分就是說格子描述符,你需要在聲明計算域塊格結構對象時爲你的指定格子描述符,格子描述符,是規定CELL也就是元胞裏的數據結構的描述符,裏面包含了,元胞所包含的數據量的數量以及不同數據的偏移值,一般在應用當中都是通過偏移值來選定所需的元胞數據值。描述符其實就是規定了元胞中一個連續表結構,以表的方式來存儲數據值。
一般情況下,基礎的,如上面的那兩個可以隨便改着玩,但更高級的模型都是有自己的格子描述符的,在開新模型時,要看看格子描述符,以便於大致瞭解你所計算的塊格數據結構,大致由哪幾部分組成,用現成的簡單模型,只要按照原有方式匹配格子描述符,動態類以及數據處理器,一般不會有問題。
這個格子描述符可以自己寫,但是,嗯,我還沒有時間嘗試,我大致看了一下,一般都是浸入式開發的三個一塊寫,也就是格子描述符、動態類以及數據處理器。

(三)The dynamics classes

原始文檔

During a time iteration of a lattice Boltzmann simulation, all cells of a block-lattice perform a local collision step, followed by a streaming step. The streaming step is hardcoded and can be influenced only by defining the discrete velocities in a lattice descriptor. The collision step on the other hand can be fully customized and can be different from one cell to another. In this way, the nature of the physics simulated on the lattice can be adjusted locally, and specific areas such as the boundaries can get an individual treatment.
Each cell of a block-lattice holds, additionally to the variables of the simulation, a pointer to an object of type Dynamics.
在這裏插入圖片描述
To learn how to define a new dynamics class, it is easiest to look at one of the classes defined in Palabos. For example, the BGK dynamics is defined in the file src/basicDynamics/isoThermalDynamics.hh. A good example for composite dynamics (a class which modifies the behavior of another, existing dynamics class) is the Smagorinsky dynamics, defined in src/complexDynamics/smagorinskyDynamics.hh.
For the implementation of the collision, the dynamics object gets a reference to a single cell; the collision step is therefore necessarily local. Non-local ingredients of a simulation are implemented with data processors, as shown in the next section.
Like the block-lattice, a dynamics object is dependent on two template parameters, one for the floating-point representation, and one for the lattice descriptor. By using the information provided in the lattice descriptor, the collision step should be written in a generic, lattice-independent way. There is obviously an efficiency trade-off in writing the algorithms in a generic way, because it is possible to formulate optimizations for specific lattices which the compiler fails to find. This problem can be circumvented by using template specializations for a given lattice. As an example, take again the implementation of the class BGKdynamics. The implementation of collision step refers to a generic object dynamicsTemplates, which is defined in the file src/latticeBoltzmann/dynamicsTemplates.h. Efficient specializations of this class for various 2D and 3D lattices are found in the files dynamicsTemplates2D.h and dynamicsTemplates3D.h.

文檔翻譯

在格子Boltzmann模擬的時間迭代中,block-lattice的所有單元執行局部碰撞步驟,然後執行流動步驟。流動步驟是硬編碼的,只能通過在格子描述符中定義離散速度來影響。另一方面,碰撞步驟可以完全定製,並且可以根據不同的單元格而有所不同。這樣,在格子上模擬的物理性質可以局部調整,特定的區域如邊界可以得到單獨的處理。
除了模擬的變量數據值外,塊格的每個單元格還持有一個指向類型爲Dynamics的對象的指針。
在這裏插入圖片描述
要了解如何定義一個新的動態類,最簡單的方法是查看Palabos中定義的類之一。例如,BGK動態在src/basicDynamics/isoThermalDynamics.hh文件中定義。複合動力學(修改另一個現有動力學類的行爲的類)的一個很好的例子是Smagorinsky dynamics,它在src/complexDynamics/smagorinskyDynamics.hh中定義。
對於碰撞的實現,dynamics對象獲取對單個單元的引用;因此,衝突步驟必然是局部的。模擬的非本地成分是用數據處理器實現的,如下一節所示。
與block-lattice一樣,動態對象依賴於兩個模板參數,一個用於浮點表示,另一個用於格子描述符。通過使用格子描述符中提供的信息,碰撞步驟應該以一種通用的、與晶格無關的方式編寫。顯然,以通用的方式編寫算法是一種效率權衡,因爲可以對編譯器無法找到的特定格點進行優化。這個問題可以通過使用給定晶格的模板專門化來解決。以BGKdynamics類的實現爲例。衝突步驟的實現涉及到一個通用對象dynamicsTemplates,它在文件src/latticeBoltzmann/dynamicsTemplates.h中定義。在dynamicsTemplates2D.h和dynamicsTemplates3D.h文件中可以找到該類對各種2D和3D格子的有效團版本。

解釋說明

這個動態類是作用於碰撞遷移步驟當中的,用於規範格點上的碰撞與遷移過程,所有的與碰撞遷移相關的動態類,包裹邊界節點上所施加的反彈之類的碰撞,皆來自於這個類,一般在初始化階段通過指針的形式引入塊格計算域結構(在上一節解釋中有說明),可以重複設置,後一次設置會將前一次設置的設定清除,只要最後計算時,能確定所有的格點都有相應的動態類,這部分的計算就沒有問題。
動態類只適用於本地操作,也就是說,在格子點本地進行操作,並不能引用除當前格點以外的值來作爲本格點碰撞遷移計算的引用值,如果想對格點進行外推之類的操作,應該在後一部分的數據處理器部分進行編寫。(這段存疑,記得應該是這樣,以後我可能會修改)
同樣,只有在繼承類末端的類,纔是用戶使用類,其他的父類,都是數據抽象類或半抽象類,無法實例化。

(四)Data processors

原始文檔

Data processors define an operation to be performed on the entire domain, or on parts of a block. On a block-lattice, they are used to implement all operation which cannot be formulated in terms of dynamics objects. These consist most notably of non-local operations, such as the evaluation of finite difference stencils for the implementation of boundary conditions. On scalar-fields and tensor-fields, data processors provide the only (sufficiently efficient and parallelizable) way to perform an operation on a spatially extended domain.
Furthermore, data processors have the ability to exchange information between several blocks, either of the same type or of different type (example: coupling between a block-lattice and scalar-field). This is for example used for the implementation of physical couplings (multi-component fluids, thermal fluids with Boussinesq approximation), for the setup of initial conditions (initialization of the velocity from the values in a vector-field), or the execution of classical array-based operations (element-wise addition of two scalar-fields).
Finally, data processors are used to perform reduction operations, on the entire block or on sub-domains. Examples range from the computation of the average kinetic energy in a simulation to the computation of the drag force acting on an obstacle.
Two different point of views are adopted for the definition and for the application of a data processor. At the application level, the user specifies an area (which can be rectangular or irregular) of a given block, on which to execute the data processor. If the block has internally a multi-block structure, the data processor is subdivided into several more specific data processors, one for each atomic-block inside the multi-block which intersects with the specified area. At the execution level, a data processor therefore always acts on an atomic-block, on an area which was previously determined by intersecting the original area with the domain of the atomic-block.
It should be mentioned that while the raw data processors are somewhat awkward to use, you are likely to never be in contact with them. Instead, Palabos offers a simplified interface through so-called data processing functionals, which hide technical details and let you concentrate on the essential parts. The rest of the user guides concentrates exclusively on these functionals, which will be called data processors for short.
In the end, it is quite easy to define new data processors. All you need to do is write a function which receives an atomic-block and the coordinates of a sub-domain as parameters, and executes an algorithm on this sub-domain. All complex operations, like the sub-division of the operations in presence of a multi-block, or the parallelization of the code, are automatic.
An educative example of a data processor is found in the example file examples/codeByTopics/couplings. It shows how to initialize a block-lattice with a velocity from a vector field by writing a data processor for block-lattice vs. 2D tensor-field coupling.
More definitions of data-processors acting on block-lattices can be found in the files src/simulationSetup/latticeInitializerXD.h and .hh, and data-processors acting on scalar- or tensor-fields are defined in the files src/simulationSetup/dataFieldInitializerXD.h and .hh. Examples for the evaluation of reduction operations are provided in the files src/core/dataAnalysisXD.h and .hh.
All these data-processors are wrapped up in convenience functions, which are summarized in the Appendix: partial function/class reference.

文檔翻譯

數據處理器是定義在整個域或塊的部分上執行的操作。在block-lattice上,它們用於實現所有不能用動態對象表示的操作。這些包括最顯著的非局部操作,如邊界條件實現的有限差分模板的評估。在標量域和張量域上,數據處理器提供了在空間擴展域上執行操作的惟一可行的方法(足夠有效且可並行化)。
此外,數據處理器能夠在幾個塊之間交換信息,這些塊可以是同一類型的,也可以是不同類型的(例如:塊格和標量場之間的耦合)。這是例如用於物理耦合的實現(與Boussinesq近似多組分的流體、熱流體),初始條件的設置(初始化的速度值向量場),或古典的執行基於數組的操作(元素方式添加兩個標量場)。
最後,使用數據處理器對整個塊或子域執行約簡操作。例子範圍涵括從模擬中平均動能的計算到作用於障礙物上的阻力的計算。
數據處理器的定義和應用採用了兩種不同的觀點。在應用程序級別,用戶指定給定塊的一個區域(可以是矩形或不規則的),在該區域上執行數據處理器。如果數據塊內部有一個多塊結構,那麼數據處理器就被細分爲幾個更具體的數據處理器,每個數據處理器對應一個與指定區域相交的多塊內部的原子塊。因此,在執行級別上,數據處理器總是作用於一個原子塊,即先前通過將原始區域與原子塊的域相交確定的區域。
應該提到的是,雖然原始數據處理器使用起來有些笨拙,但是您可能永遠不會與它們接觸。相反,Palabos通過所謂的數據處理函數提供了一個簡化的接口,這些函數隱藏了技術細節,讓您可以集中精力處理關鍵部分。其餘的用戶指南專門關注這些函數,簡稱爲數據處理器。
最後,定義新的數據處理器非常容易。您所需要做的就是編寫一個函數,該函數接收一個原子塊和一個子域的座標作爲參數,並在這個子域上執行一個算法。所有複雜的操作,比如存在多塊的操作的細分,或者代碼的並行化,都是自動的。
在示例文件examples/codeByTopics/couplings中可以找到一個數據處理器的可教育性示例。它通過編寫塊晶格與二維張量場耦合的數據處理器,展示瞭如何用向量場的速度初始化塊晶格。
在src/simulationSetup/latticeInitializerXD.h和.hh文件中可以找到更多作用於塊格的數據處理器的定義,而作用於標量或張量字段的數據處理器定義在src/simulationSetup/dataFieldInitializerXD.h和.hh文件中。src/core/ dataAnalysisx.h和.hh文件中提供了評估還原操作的示例。
所有這些數據處理器都封裝在方便的函數中,這些函數在手冊文檔附錄:partial function/class reference部分中進行了總結。

解釋說明

此處爲數據處理器,作用於每次碰撞與遷移之後的,宏觀量統計部分,用的比較多,傳入的數據爲塊格數據,每一個數據點,都由一個信封來包裹,信封內爲想要操作數據點及周圍對應信封大小的數據包,我自己還沒有完全改寫過數據處理器,但是大致看過,需要改寫由數據處理器父類繼承而來的execute函數,來實現自己所需要的對塊格數據進行改寫以及統計的相關操作。

(五)總結

以上四種,爲Palabos中最基礎的數據吧類型,其中改寫Descriptor,Dynamics class,Data processors爲高階,通過改寫這三個,可以做出Palabos中不存在的模型以及邊界條件,新手不推薦改寫,還是在瞭解的基礎上,儘可能的調用原有類來實現自己的模擬計算目的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章