Neko
1.99.1
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
fields_vectors_math.f90
Go to the documentation of this file.
1
! This tutorial demonstrates how to work with fields and vectors in Neko. It
2
! covers the following key points:
3
!
4
! - Initializing and working with `field_t` and `vector_t` types.
5
! - Performing mathematical operations on fields and vectors, including:
6
! - Using overloaded operators for basic operations.
7
! - Accessing and modifying field data directly on the CPU.
8
! - Using low-level math routines for device and CPU compatibility.
9
! - Leveraging the `field_math` module for backend-agnostic computations.
10
! - Demonstrating the lifecycle of user-defined objects:
11
! - Initializing fields and vectors in `user_init_modules`.
12
! - Performing custom calculations in `user_check`.
13
! - Cleaning up allocated resources in `user_finalize_modules`.
14
!
15
! This tutorial highlights the flexibility of Neko's field and vector types,
16
! as well as the tools provided for efficient and portable numerical
17
! computations across different backends.
18
module
user
19
use
neko
20
implicit none
21
22
23
! One of the most important types in Neko is the field_t type. It is used to
24
! represent the solution fields in the simulation.
25
type
(field_t) ::
my_field
26
27
! A vector is essentially a 1D array that handles the storage and association
28
! between data on the host and the device.
29
type
(vector_t) ::
vec
30
31
contains
32
33
! Register user-defined functions (see user_intf.f90)
34
subroutine
user_setup
(user)
35
type
(user_t),
intent(inout)
:: user
36
37
user
%startup =>
startup
38
user
%initialize =>
initialize
39
user
%compute =>
compute
40
user
%finalize =>
finalize
41
end subroutine
user_setup
42
43
! We will use the user_startup routine to manipulate the end time.
44
subroutine
startup
(params)
45
type
(json_file),
intent(inout)
:: params
46
47
call
params%add(
"case.end_time"
, 0.0_rp)
48
end subroutine
startup
49
50
! The user_init_modules routine is called after all the objects used to run
51
! the simulation are created. Thus, we can initialize user variables that,
52
! for example, depend on the mesh or the fluid solver.
53
subroutine
initialize
(time)
54
type
(time_state_t),
intent(in)
:: time
55
56
! Like almost all other Neko types, the field_t has an init method that is
57
! effectively a constructor. Typically, we use a dofmap_t object and a
58
! a name to call the init method. The dofmap_t is usually fetched from the
59
! solver, like a `fluid_scheme_t`. To do this, we make use of the special
60
! neko_user_access object, which is a singleton that provides access to
61
! various objects used in the simulation.
62
call
my_field
%init(neko_user_access%case%fluid%dm_Xh,
"my_field"
)
63
64
! The actual values of the field are stored in the x array or the x_d
65
! pointer. The x_d pointer is used to access the data on the GPU. The x
66
! array has a rank of 4, corresponding to GLL points in 3 dimensions, and
67
! the number of elements in the mesh (i,j,k,e).
68
69
! Some operators are overloaded for the field_t type. For example, we can
70
! assign it to a scalar. At construction, the values are set to zero.
71
my_field
= 1.0_rp
72
73
74
! The situation for vector is similar, but we only need to provide the size
75
! of the array we want in the constructor.
76
call
vec
%init(50)
77
78
vec
= 1.0_rp
79
80
end subroutine
initialize
81
82
! This routine is run at the end of each time step. It is mean to hold
83
! arbitrary calculations that the user wants to do.
84
subroutine
compute
(time)
85
type
(time_state_t),
intent(in)
:: time
86
integer
:: i
87
88
! Let us consider doing some simple math on our field. Here we just add 1
89
! to the value at each GLL point. Note that we use a linear index to loop
90
! over the entire field, and use %x(i,1,1,1). This is very common in Neko,
91
! and relies on contiguous memory layout. Sometimes you will see 4D arrays
92
! passed to dummy arguments that are 1D, 2D, etc. This is possible for the
93
! same reason.
94
do
i = 1,
my_field
%size()
! <- Number of GLL points.
95
my_field
%x(i,1,1,1) =
my_field
%x(i,1,1,1) * 2.0_rp
96
end do
97
98
! There is an issue with the above code: it only works on the CPU. You can
99
! not write GPU kernels as a user. Therefore, Neko has a whole range of
100
! low-level math functions that can be used. You can find them in math.f90.
101
! Corresponding routines for the GPU are in device_math.f90, and
102
! field_math.f90 contains wrappers that dispatch correctly to either a CPU
103
! or device routine based on the current backend. The names of the routines
104
! are taken from Nek5000, so if you are familiar with that code, you will
105
! find it easy to use.
106
107
! A generic way to perform the computation above would be
108
if
(neko_bcknd_device .eq. 1)
then
! <- Check if we are on the device.
109
call
device_cmult(
my_field
%x_d, 2.0_rp,
my_field
%size())
110
else
111
call
cmult(
my_field
%x, 2.0_rp,
my_field
%size())
112
end if
113
114
! Alternatively, (and more concisely) we can use the field_math module,
115
call
field_cmult(
my_field
, 2.0_rp)
116
117
! For vector_t there are no math wrappers, so the latter approach is the
118
! one to go for. The vector_t does overload some operators though, so use
119
! those when possible.
120
121
end subroutine
compute
122
123
! If you declare objects at module scope that need to be destroyed, you can
124
! do it here. In our case it is the my_field field.
125
subroutine
finalize
(time)
126
type
(time_state_t),
intent(in)
:: time
127
128
! All types the allocate memory in Neko have a free method, which is a
129
! destructor.
130
call
my_field
%free()
131
132
end subroutine
finalize
133
134
end module
user
neko
Master module.
Definition
neko.f90:34
user
Definition
fields_vectors_math.f90:18
user::vec
type(vector_t) vec
Definition
fields_vectors_math.f90:29
user::initialize
subroutine initialize(time)
Definition
fields_vectors_math.f90:54
user::user_setup
subroutine user_setup(user)
Definition
fields_vectors_math.f90:35
user::compute
subroutine compute(time)
Definition
fields_vectors_math.f90:85
user::startup
subroutine startup(params)
Definition
fields_vectors_math.f90:45
user::my_field
type(field_t) my_field
Definition
fields_vectors_math.f90:25
user::finalize
subroutine finalize(time)
Definition
fields_vectors_math.f90:126
examples
programming
fields_vectors_math.f90
Generated on Mon Sep 1 2025 03:49:14 for Neko by
1.9.8