![]() |
KIDS
ver-0.0.1
KIDS : Kernel Integrated Dynamics Simulator
|
Basic Develop Models Develop Solvers
In addition to possessing knowledge in their respective fields and proficiency in the code and algorithms they work with, developers are expected to adhere to the following principles:
Developers' Responsibilities:
The basic types in kids are kids_bool
, kids_int
, kids_real
, kids_complex
, kids_str
, kids_param
and kids_dataset
.
The KIDS framework is divided into the following four basic components: Paramizer, Dataizer, Algorithmizer, Taskizer.
The JSON library has good implementations in C++, and we can simply encapsulate its usage.
The Dimen class is based on dynamic dimensions of integers, such as Dimen ndofs
. Operations implemented include bidirectional assignment, comparison operations, etc.
The Dimen class records each reference to its array shape, and updates the shape information promptly when Dimen values change.
The Shape class represents the shape of an array. It records a series of pointers to Dimens and precomputes additional information (such as the size of the primary dimension for each tensor index) for subsequent calculations. The design of the Shape class aims to facilitate the use of the Tensor class.
The Node class is an interface class designed to facilitate the hierarchical combination and management of a series of Tensors. Based on the Node class interface, memory management and tree-like directory indexing of the DataSet class (non-root nodes) and the Tensor class (root nodes) are performed using unique_ptr and polymorphism.
The DataSet provides three operations: def()
, at()
, and undef()
, used to define a root Tensor based on a path in the DataSet. In addition to these, DataSet also defines functional functions such as repr()
, dump()
, and load()
for structure representation, transfer, and loading.
To better pseudo-bind namespaces and DataSet structures in C++, we also introduce the following auxiliary class and macro functions:
Here is an example of managing computational data structures:
The ds file format is linear, with read/write complexity of O(N*H), where N is the data volume and H is the maximum depth of the tree. It's a simple hdf5-like format.
The Algorithmizer, relative to the Dataizer and Paramizer, aims to separate algorithms from data itself.
The interface of Algorithmizer is Kernel (allowing empty Kernels to be built from scratch). A Kernel has a dynamic array of pointers to other Kernel, managed by shared_ptr for dynamic memory management, forming a tree-like calling structure. For example:
Kernel provides two calling functions:
Note: In the old approach, we divided the computation into four levels, namely
read_param(), init_data(), init_calc(), exec_kernel()
four functions, but this greatly limited the extensibility of the algorithm core. We define the execution of data transfer as the first-class calling interface, soread_param(), init_data()
are respectivelyexec_kernel<Param>()
andexec_kernel<DataSet>()
, completing the interaction between Paramizer and Dataizer. The levels of calculation, such as sampling as pre-calculation, dynamics as main calculation, etc., can be controlled through the level.
Under the new interface structure, an instantiated dynamics calculation can be expressed as follows:
Reasons for abandoning object orientation in favor of Algorithmizer:
1) Effective separation of data and algorithms favors efficient program reuse. 2) Algorithmizer follows a functional programming approach, although its implementation in C++ also relies on polymorphism, it effectively truncates to subclass inheritance. The implementation of complex algorithms depends on the combination of Algorithmizers, rather than the hierarchical inheritance of objects. Excessive object encapsulation is not the essence of algorithm abstraction. 3) Atomicity of Algorithmizers facilitates maintenance tracking. For example, if the same algorithm has multiple implementations, Kernel_Algo1_Impl1_1995, Kernel_Algo1_Impl2_2008
, the formal algorithm only needs to define using Kernel_Algo1_Recommend = Kernel_Algo1_Impl2_2008
. 4) Facilitates modification, replacement, or new development. A Kernel can be replaced with a user-defined Kernel, such as
5) The construction of the algorithm tree is one-time and done before formal invocation, with minimal overhead and avoiding a large number of branch statements. It is highly efficient during formal invocation. 6) More straightforward and friendly interface with scripting languages; it can be exported to a Python module via pybind11.
Priority container: Adjusts the priority of algorithms. Model container: Recognizing that the computing system is based on the Model class, which is essentially a derivative of the Kernel class. Collector container: XXX
As mentioned above, the collector is a special type of Kernel. It contains functions for processing data inside the DataSet and is used to create intermediate information, etc.
Taskizer, combined with the collector, can be used for general computing tasks (Applications). First, the collector determines the required intermediate information (default) based on the type of the Taskizer, and of course, additional intermediate information can be added by the user. During base calculation, information is collected.
Note that due to the differences in MPI between C++ and Python, Application in C++ and Python are implemented separately.