|
Neko 1.99.1
A portable framework for high-order spectral element flow simulations
|
In addition to compiling the user file, makeneko can also compile extra .f90 files containing Fortran modules and .cu/.hip files containing CUDA/HIP kernels. A common use of this is to separate out functionality needed by the user file into individual source files. However, you can also use this feature to extend Neko's core functionality.
Specifically, you can write modules that implement custom components such as LES models, wall models, or simulation components. These modules can then be configured directly via the case file's JSON input—just like Neko's built-in components.
Of course, you could also achieve this by modifying Neko's source code directly. But that comes with some drawbacks:
Extending Neko with makeneko is quite easy, but not everything in the code supports this. Here is a list of things you can implement.
les_model_t descendants).wall_model_t descendants).simulation_component_t descendants).source_term_t descendants).point_zone_t descendants).This list will hopefully be extended later. Notable omissions are scalar and fluid schemes, so currently you cannot add new solvers like this.
To implement a new type, the easiest thing is to start by copying over the .f90 of an already existing type, renaming things inside and then adding the functionality you want (e.g. the particular form of the source term). When you are done, two special subroutines have to be added to you module. To make explaining easier, let us assume that your module is called mymodule and the new type mytype.
register_*, where the * is replaced by the name of the type, for example, register_source_term.*_allocate, e.g. source_term_allocate.Both of these routines should be brought into the the new modules with use statements. Then, two routines need to be defined in the module.
One is just an allocator for our new type. The name of the routine is arbitrary.
The second routine uses the one above to register the type with Neko. It has to be called mymodule_register_types, where mymodule coincides with the name of our module.
Note that the *_register_types routine can register maybe types, not necessarily just one.
For custom device kernels, mymodule must define a C interface to a CUDA/HIP routine that launches the kernel.
Furthermore, the CUDA/HIP file must allow for C linkage, hence the routine device_kernel must be inside an extern "C" block.
After compiling with makeneko, you can select your type in the JSON in the appropriate place.
One might wonder whether it's necessary to use this functionality—for example, for source terms—when it's possible to simply use a corresponding user routine in the user file. However, implementing a proper custom type has several advantages:
That said, writing a custom type does take more effort than simply filling in the user routine.