|
DNDSR 0.1.0.dev1+gcd065ad
Distributed Numeric Data Structure for CFV
|
DNDS is designed to be a set of commonly used infrastructure that can be used in CFD-like code. When organizing data and algorithms in CFD code, the programmer has to cope with geometry and field data, which correspond to mesh/grid related code and field related code. When the CFD scheme involves unstructured mesh and high order discretization, the grid and field code could become rather complex. Therefore, it is a natural thing to put some levels of abstraction here, and cover up the raw data types using C++ features.
There has been countless C++ involved computational applications in the field of computer graphics and CG designing (like blender), CAD (like FreeCAD), CAE mesh generation (like gmsh) that involve very complex unstructured and polymorphic geometry data. And massive computational applications including deep learning architectures (like PyTorch) use high levels of abstraction directly on fully structured and homogeneously organized data arrays.
Unstructured CFD applications are different from both types of computational models, where both complex geometry and massive homogeneous numeric operations are required but easier to cover. Unstructured CFD code only involve limited types of geometry elements and connection type, which can be nearly hard-coded; while while global high-rank structured arrays are mostly not needed, only rank 2 to 5 arrays with potentially non-uniform sizes could be utilized.
So, how do we design the interface used in implementing CFD (By CFD, I mean math formulae of discrete schemes)? Here we inspect some references of famous open cfd code chunks:
It seems concerning basic data arrangement, the OpenFOAM and SU2 both require the data to be able to be accessed with random accessors (random_iterator, pointer, subscript or similar):
OpenFOAM's gradient calculation:
And their directly operating data objects seem to be defined on a whole (zone of) mesh:
OpenFOAM's gradient calculation:
Actually, SU2's CVertex is a polymorphic class:
CDualGrid stores the adjacency information, geometric information and auxiliary information in the class, and overrides base's methods for calculating some useful geometric information. So is SU2's CPrimalGrid class.
However, OpenFOAM seems to maintain a primitive data array for mesh topology and geometry in primitiveMesh class:
And OpenFOAM wraps these data with methods to access mesh topo and geom with inheritance.
DNDS does not intend to directly apply such methods at first, but intend to simplify the MPI communications on some limited types of data arrays. Communication for any complex object is secondary in DNDS, for most of the communication is needed only for arrays of basic types like int64_t and double (or the project aliases DNDS::index and DNDS::real) and their simple composite c-like-struct, which is implemented in Array and ArrayTransformer classes. Any communication on general objects would be a concept requiring the objects being able to serialize/deserialize themselves to a buffer in a given method and given order (which is closer to the communication model in PHengLEI).
The first application of DNDS, the simple CFV euler solver, does only invoke basic type communications in ArrayTransformer, and has yet to come up with any MPI-related bug (data corruption, dead lock...) since no hard MPI operation is needed outside the DNDS wrapping.
Also, DNDS recommends the user to put different kinds of data in different arrays instead of combining them at first, like in OpenFOAM:
Using DNDS provided data structure, one can consider std::vector<simple_type> to be able to manage its own communication pattern, somewhat like a PETSC Vector.
The reasoning behind this, is to separate different data genres, which may need different arrangements of communication, access and combination. For example, if one uses combined data:
then Write and Read would only involve the conserved variables. However, if one extends this to:
and both X and X_1 variables need to be communicated through MPI, but at different phases of computation, then the WriteStream and ReadStream would not be sufficient for communicating; but in a polymorphic design, like using concept of templates or using virtual inheritance, the top level of abstraction must be general enough to take these matters into account. Also, it is a burden to add new communicated components to the class.
Therefore, in DNDS, it is recommended that the abstraction is delayed out of the arrays of data, or the abstraction should not be nested into the raw data arrays. Actually, DNDS is only dedicated to providing a means of using c-like random-access large arrays without the concern of communication, and any higher level of abstraction is left for the user.