cuwave 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
File without changes
@@ -0,0 +1,174 @@
1
+ // Prepended by wave.compile_kernels: stencils.preamble, then common.cuh.
2
+ // Compile-time configuration this file responds to:
3
+ // NDIM = 1 | 2 | 3
4
+ // USE_DAMPING
5
+
6
+ #ifndef RADIUS
7
+ #define RADIUS 1 // default order 2
8
+ #endif
9
+
10
+ // the node block a full-radius cell reaches, and the cells a node borders
11
+ #define BLK (2 * RADIUS)
12
+ #if NDIM == 1
13
+ #define CELLS BLK
14
+ #elif NDIM == 2
15
+ #define CELLS (BLK * BLK)
16
+ #else
17
+ #define CELLS (BLK * BLK * BLK)
18
+ #endif
19
+ #define NLOC (CELLS * NDIM)
20
+
21
+ // position along axis d of the block entry m, axis 0 running fastest
22
+ __device__ __forceinline__ int block_axis(int m, const int d) {
23
+ #pragma unroll
24
+ for (int k = 0; k < NDIM; ++k)
25
+ if (k < d)
26
+ m /= BLK;
27
+ return m % BLK;
28
+ }
29
+
30
+ // ----------------------------- cell assembly helpers
31
+ #if NDIM == 1
32
+ #define AXIS_PARAMS const real_t f0, const int N0
33
+ #define INTERIOR_OR_RETURN \
34
+ const int a0 = blockIdx.x * blockDim.x + threadIdx.x; \
35
+ if (!(a0 > 0 && a0 < N0 - 1)) \
36
+ return; \
37
+ const int idx = a0
38
+ #define AXIS_GEOM const int A[1] = {a0}, S[1] = {1}, NN[1] = {N0}
39
+ #elif NDIM == 2
40
+ #define AXIS_PARAMS \
41
+ const real_t f0, const int N0, const real_t f1, const int N1, const int s0
42
+ #define INTERIOR_OR_RETURN \
43
+ const int a1 = blockIdx.x * blockDim.x + threadIdx.x; \
44
+ const int a0 = blockIdx.y * blockDim.y + threadIdx.y; \
45
+ if (!(a0 > 0 && a0 < N0 - 1 && a1 > 0 && a1 < N1 - 1)) \
46
+ return; \
47
+ const int idx = a0 * s0 + a1
48
+ #define AXIS_GEOM \
49
+ const int A[2] = {a0, a1}, S[2] = {s0, 1}, NN[2] = {N0, N1}
50
+ #elif NDIM == 3
51
+ #define AXIS_PARAMS \
52
+ const real_t f0, const int N0, const real_t f1, const int N1, const int s0, \
53
+ const real_t f2, const int N2, const int s1
54
+ #define INTERIOR_OR_RETURN \
55
+ const int a2 = blockIdx.x * blockDim.x + threadIdx.x; \
56
+ const int a1 = blockIdx.y * blockDim.y + threadIdx.y; \
57
+ const int a0 = blockIdx.z * blockDim.z + threadIdx.z; \
58
+ if (!(a0 > 0 && a0 < N0 - 1 && a1 > 0 && a1 < N1 - 1 && a2 > 0 && \
59
+ a2 < N2 - 1)) \
60
+ return; \
61
+ const int idx = a0 * s0 + a1 * s1 + a2
62
+ #define AXIS_GEOM \
63
+ const int A[3] = {a0, a1, a2}, S[3] = {s0, s1, 1}, NN[3] = {N0, N1, N2}
64
+ #endif
65
+
66
+ // A cell sits inside the domain when both its own corners do. Its radius
67
+ // grades down towards a wall so the stencil never passes a ghost node, and
68
+ // the gathering node must fall inside that graded support to take from it.
69
+ __device__ __forceinline__ bool cell_inside(const int c, const int *A,
70
+ const int *NN, const int *S,
71
+ int &base, int &radius,
72
+ int &self) {
73
+ base = 0;
74
+ self = 0;
75
+ radius = RADIUS;
76
+ bool inside = true;
77
+ int power = 1;
78
+ #pragma unroll
79
+ for (int d = 0; d < NDIM; ++d) {
80
+ const int e = block_axis(c, d) - RADIUS; // low corner, from the node
81
+ const int low = A[d] + e;
82
+ inside &= (low >= 1 && low <= NN[d] - 3);
83
+ radius = min(radius, min(RADIUS, min(low, NN[d] - 2 - low)));
84
+ base += e * S[d];
85
+ self += (RADIUS - 1 - e) * power;
86
+ power *= BLK;
87
+ }
88
+ #pragma unroll
89
+ for (int d = 0; d < NDIM; ++d) {
90
+ const int e = block_axis(c, d) - RADIUS;
91
+ inside &= (e >= -radius && e <= radius - 1);
92
+ }
93
+ return inside;
94
+ }
95
+
96
+ // offset of block entry l of cell c from the gathering node, and whether
97
+ // that entry falls inside the cell's graded support at all
98
+ __device__ __forceinline__ bool block_offset(const int c, const int l,
99
+ const int radius, const int *S,
100
+ int &off) {
101
+ off = 0;
102
+ bool carries = true;
103
+ #pragma unroll
104
+ for (int d = 0; d < NDIM; ++d) {
105
+ const int m = block_axis(l, d);
106
+ carries &= (m >= RADIUS - radius && m <= RADIUS + radius - 1);
107
+ off += (block_axis(c, d) - RADIUS + m - RADIUS + 1) * S[d];
108
+ }
109
+ return carries;
110
+ }
111
+
112
+ // -------------------------------------- kernels
113
+ extern "C" {
114
+
115
+ // ------------------------------------------------------------------------------------
116
+ __global__ void
117
+ fd_kernel(const real_t *__restrict__ u0, const real_t *__restrict__ u1,
118
+ real_t *__restrict__ u2, const real_t *__restrict__ minv,
119
+ const real_t *__restrict__ cell, const real_t *__restrict__ stencil,
120
+ #ifdef USE_DAMPING
121
+ const real_t *__restrict__ damping, const real_t dt,
122
+ #endif
123
+ const int cs, AXIS_PARAMS) {
124
+ INTERIOR_OR_RETURN;
125
+ AXIS_GEOM;
126
+
127
+ real_t force[NDIM];
128
+ #pragma unroll
129
+ for (int i = 0; i < NDIM; ++i)
130
+ force[i] = (real_t)0;
131
+
132
+ #pragma unroll
133
+ for (int c = 0; c < CELLS; ++c) {
134
+ int base, radius, self;
135
+ if (!cell_inside(c, A, NN, S, base, radius, self))
136
+ continue;
137
+ const real_t gc = cell[idx + base];
138
+ const real_t *__restrict__ table = stencil + (radius - 1) * NLOC * NLOC;
139
+ #pragma unroll
140
+ for (int l = 0; l < CELLS; ++l) {
141
+ int off;
142
+ if (!block_offset(c, l, radius, S, off))
143
+ continue;
144
+ #pragma unroll
145
+ for (int j = 0; j < NDIM; ++j) {
146
+ const real_t uj = u1[j * cs + idx + off];
147
+ #pragma unroll
148
+ for (int i = 0; i < NDIM; ++i)
149
+ force[i] -=
150
+ gc * table[(self * NDIM + i) * NLOC + l * NDIM + j] * uj;
151
+ }
152
+ }
153
+ }
154
+
155
+ const real_t mi = minv[idx];
156
+ #ifdef USE_DAMPING
157
+ const real_t beta = 0.5f * mi * damping[idx] * dt;
158
+ #pragma unroll
159
+ for (int i = 0; i < NDIM; ++i) {
160
+ const int n = i * cs + idx;
161
+ u2[n] = (2.f * u1[n] - u0[n] * (1.f - beta) + f0 * mi * force[i]) /
162
+ (1.f + beta);
163
+ }
164
+ #else
165
+ #pragma unroll
166
+ for (int i = 0; i < NDIM; ++i) {
167
+ const int n = i * cs + idx;
168
+ u2[n] = -u0[n] + 2.f * u1[n] + f0 * mi * force[i];
169
+ }
170
+ #endif
171
+ }
172
+
173
+
174
+ } // extern "C"
@@ -0,0 +1,226 @@
1
+ // Prepended by wave.compile_kernels: stencils.preamble, then common.cuh.
2
+ // Compile-time configuration this file responds to:
3
+ // NDIM = 1 | 2 | 3
4
+
5
+ #ifndef RADIUS
6
+ #define RADIUS 1 // default order 2
7
+ #endif
8
+
9
+ #define BLK (2 * RADIUS)
10
+ #if NDIM == 1
11
+ #define CELLS BLK
12
+ #elif NDIM == 2
13
+ #define CELLS (BLK * BLK)
14
+ #else
15
+ #define CELLS (BLK * BLK * BLK)
16
+ #endif
17
+ #define NLOC (CELLS * NDIM)
18
+ #define CORNERS (1 << NDIM)
19
+
20
+ // position along axis d of the block entry m, axis 0 running fastest
21
+ __device__ __forceinline__ int block_axis(int m, const int d) {
22
+ #pragma unroll
23
+ for (int k = 0; k < NDIM; ++k)
24
+ if (k < d)
25
+ m /= BLK;
26
+ return m % BLK;
27
+ }
28
+
29
+ // ----------------------------- cell assembly helpers
30
+ #if NDIM == 1
31
+ #define AXIS_PARAMS const int N0
32
+ #define INTERIOR_OR_RETURN \
33
+ const int a0 = blockIdx.x * blockDim.x + threadIdx.x; \
34
+ if (!(a0 > 0 && a0 < N0 - 1)) \
35
+ return; \
36
+ const int idx = a0
37
+ #define AXIS_GEOM const int A[1] = {a0}, S[1] = {1}, NN[1] = {N0}
38
+ #elif NDIM == 2
39
+ #define AXIS_PARAMS const int N0, const int N1, const int s0
40
+ #define INTERIOR_OR_RETURN \
41
+ const int a1 = blockIdx.x * blockDim.x + threadIdx.x; \
42
+ const int a0 = blockIdx.y * blockDim.y + threadIdx.y; \
43
+ if (!(a0 > 0 && a0 < N0 - 1 && a1 > 0 && a1 < N1 - 1)) \
44
+ return; \
45
+ const int idx = a0 * s0 + a1
46
+ #define AXIS_GEOM \
47
+ const int A[2] = {a0, a1}, S[2] = {s0, 1}, NN[2] = {N0, N1}
48
+ #elif NDIM == 3
49
+ #define AXIS_PARAMS \
50
+ const int N0, const int N1, const int s0, const int N2, const int s1
51
+ #define INTERIOR_OR_RETURN \
52
+ const int a2 = blockIdx.x * blockDim.x + threadIdx.x; \
53
+ const int a1 = blockIdx.y * blockDim.y + threadIdx.y; \
54
+ const int a0 = blockIdx.z * blockDim.z + threadIdx.z; \
55
+ if (!(a0 > 0 && a0 < N0 - 1 && a1 > 0 && a1 < N1 - 1 && a2 > 0 && \
56
+ a2 < N2 - 1)) \
57
+ return; \
58
+ const int idx = a0 * s0 + a1 * s1 + a2
59
+ #define AXIS_GEOM \
60
+ const int A[3] = {a0, a1, a2}, S[3] = {s0, s1, 1}, NN[3] = {N0, N1, N2}
61
+ #endif
62
+
63
+ // the cell this node is the low corner of, where its density accumulates, plus
64
+ // the radius that cell carries once graded down towards a wall
65
+ __device__ __forceinline__ bool own_cell(const int *A, const int *NN,
66
+ int &radius) {
67
+ radius = RADIUS;
68
+ bool inside = true;
69
+ #pragma unroll
70
+ for (int d = 0; d < NDIM; ++d) {
71
+ inside &= (A[d] >= 1 && A[d] <= NN[d] - 3);
72
+ radius = min(radius, min(RADIUS, min(A[d], NN[d] - 2 - A[d])));
73
+ }
74
+ return inside;
75
+ }
76
+
77
+ // block entry l of that cell, and whether it falls inside the graded support
78
+ __device__ __forceinline__ bool own_offset(const int l, const int radius,
79
+ const int *S, int &off) {
80
+ off = 0;
81
+ bool carries = true;
82
+ #pragma unroll
83
+ for (int d = 0; d < NDIM; ++d) {
84
+ const int m = block_axis(l, d);
85
+ carries &= (m >= RADIUS - radius && m <= RADIUS + radius - 1);
86
+ off += (m - RADIUS + 1) * S[d];
87
+ }
88
+ return carries;
89
+ }
90
+
91
+ // the 2**NDIM cells a node is a corner of: the material stays cell local,
92
+ // so the design chain rule runs over those, not the wide stencil block
93
+ __device__ __forceinline__ bool corner_cell(const int c, const int *A,
94
+ const int *NN, const int *S,
95
+ int &base) {
96
+ base = 0;
97
+ bool inside = true;
98
+ #pragma unroll
99
+ for (int d = 0; d < NDIM; ++d) {
100
+ const int bit = (c >> d) & 1;
101
+ inside &= bit ? (A[d] < NN[d] - 2) : (A[d] > 1);
102
+ base += (bit - 1) * S[d];
103
+ }
104
+ return inside;
105
+ }
106
+
107
+ // -------------------------------------- kernels
108
+ extern "C" {
109
+
110
+ // ------------------------------------------------------------------------------------
111
+ __global__ void
112
+ gradient_kernel(real_t *__restrict__ g_mass, real_t *__restrict__ g_cell,
113
+ const real_t *__restrict__ u0, const real_t *__restrict__ u1,
114
+ const real_t *__restrict__ u2, const real_t *__restrict__ l1,
115
+ const real_t *__restrict__ stencil, const real_t mass_factor,
116
+ const int cs, AXIS_PARAMS) {
117
+ INTERIOR_OR_RETURN;
118
+ AXIS_GEOM;
119
+
120
+ // dJ/dmass: no neighbour and no material load
121
+ real_t acc = (real_t)0;
122
+ #pragma unroll
123
+ for (int i = 0; i < NDIM; ++i) {
124
+ const int n = i * cs + idx;
125
+ acc += l1[n] * (u2[n] - 2.f * u1[n] + u0[n]);
126
+ }
127
+ g_mass[idx] -= mass_factor * acc;
128
+
129
+ // dJ/dcell: the cell stencil paired between the forward and adjoint fields
130
+ int radius;
131
+ if (!own_cell(A, NN, radius))
132
+ return;
133
+ const real_t *__restrict__ table = stencil + (radius - 1) * NLOC * NLOC;
134
+ real_t bilinear = (real_t)0;
135
+ #pragma unroll
136
+ for (int l = 0; l < CELLS; ++l) {
137
+ int lo;
138
+ if (!own_offset(l, radius, S, lo))
139
+ continue;
140
+ #pragma unroll
141
+ for (int m = 0; m < CELLS; ++m) {
142
+ int mo;
143
+ if (!own_offset(m, radius, S, mo))
144
+ continue;
145
+ #pragma unroll
146
+ for (int i = 0; i < NDIM; ++i)
147
+ #pragma unroll
148
+ for (int j = 0; j < NDIM; ++j)
149
+ bilinear += l1[i * cs + idx + lo] *
150
+ table[(l * NDIM + i) * NLOC + m * NDIM + j] *
151
+ u1[j * cs + idx + mo];
152
+ }
153
+ }
154
+ g_cell[idx] -= bilinear;
155
+ }
156
+
157
+ // ------------------------------------------------------------------------------------
158
+ __global__ void
159
+ frechet_kernel(real_t *__restrict__ acc_mass, real_t *__restrict__ acc_cell,
160
+ const real_t *__restrict__ u0, const real_t *__restrict__ u1,
161
+ const real_t *__restrict__ u2,
162
+ const real_t *__restrict__ stencil, const real_t ft,
163
+ const real_t fs, const int cs, AXIS_PARAMS) {
164
+ INTERIOR_OR_RETURN;
165
+ AXIS_GEOM;
166
+
167
+ real_t acc = (real_t)0;
168
+ #pragma unroll
169
+ for (int i = 0; i < NDIM; ++i) {
170
+ const int n = i * cs + idx;
171
+ const real_t dudt = u2[n] - u0[n];
172
+ acc += dudt * dudt;
173
+ }
174
+ acc_mass[idx] += ft * acc;
175
+
176
+ int radius;
177
+ if (!own_cell(A, NN, radius))
178
+ return;
179
+ const real_t *__restrict__ table = stencil + (radius - 1) * NLOC * NLOC;
180
+ real_t bilinear = (real_t)0;
181
+ #pragma unroll
182
+ for (int l = 0; l < CELLS; ++l) {
183
+ int lo;
184
+ if (!own_offset(l, radius, S, lo))
185
+ continue;
186
+ #pragma unroll
187
+ for (int m = 0; m < CELLS; ++m) {
188
+ int mo;
189
+ if (!own_offset(m, radius, S, mo))
190
+ continue;
191
+ #pragma unroll
192
+ for (int i = 0; i < NDIM; ++i)
193
+ #pragma unroll
194
+ for (int j = 0; j < NDIM; ++j)
195
+ bilinear += u1[i * cs + idx + lo] *
196
+ table[(l * NDIM + i) * NLOC + m * NDIM + j] *
197
+ u1[j * cs + idx + mo];
198
+ }
199
+ }
200
+ acc_cell[idx] += fs * bilinear;
201
+ }
202
+
203
+ // ------------------------------------------------------------------------------------
204
+ __global__ void cell_to_node_kernel(real_t *__restrict__ g_stiff,
205
+ const real_t *__restrict__ g_cell,
206
+ const real_t *__restrict__ cell,
207
+ const real_t *__restrict__ gamma,
208
+ const real_t share, AXIS_PARAMS) {
209
+ INTERIOR_OR_RETURN;
210
+ AXIS_GEOM;
211
+
212
+ // d(harmonic cell mean)/d(corner) is (cell / corner)^2 over the corner count
213
+ const real_t gn = gamma[idx];
214
+ real_t acc = (real_t)0;
215
+ #pragma unroll
216
+ for (int c = 0; c < CORNERS; ++c) {
217
+ int base;
218
+ if (corner_cell(c, A, NN, S, base)) {
219
+ const real_t ratio = cell[idx + base] / gn;
220
+ acc += g_cell[idx + base] * ratio * ratio;
221
+ }
222
+ }
223
+ g_stiff[idx] += share * acc;
224
+ }
225
+
226
+ } // extern "C"
@@ -0,0 +1,95 @@
1
+ // Prelude prepended to every .cu by compile_kernels, after the stencil table.
2
+ // Compile-time configuration (set via -D flags and stencils.preamble):
3
+ // USE_FLOAT
4
+ // NDIM = 1 | 2 | 3
5
+ // STENCIL_RADIUS
6
+ // OP_COEFFS
7
+ // STAG_COEFFS
8
+
9
+ #ifdef USE_FLOAT
10
+ typedef float real_t;
11
+ #else
12
+ typedef double real_t;
13
+ #endif
14
+
15
+ // ----------------------------- finite difference helpers
16
+ #ifndef STENCIL_RADIUS
17
+ #define STENCIL_RADIUS 1 // default order 2
18
+ #endif
19
+
20
+ #if STENCIL_RADIUS == 1
21
+ #define OP_W(r, k) ((real_t)1)
22
+ #define CLOSURE(a, N) 1
23
+ #define SG_W(r, k) ((real_t)1)
24
+ #else
25
+ // cache
26
+ __constant__ real_t OP_C[STENCIL_RADIUS][STENCIL_RADIUS] = OP_COEFFS;
27
+ #define OP_W(r, k) OP_C[(r) - 1][(k) - 1] // 1-indexed adjustment
28
+ // grade radius down towards wall so the stencil never reaches past ghost nodes
29
+ #define CLOSURE(a, N) min(STENCIL_RADIUS, min(a, (N) - 1 - (a)))
30
+ __constant__ real_t SG_C[STENCIL_RADIUS][STENCIL_RADIUS] = STAG_COEFFS;
31
+ #define SG_W(r, k) SG_C[(r) - 1][(k) - 1] // 1-indexed adjustment
32
+ #endif
33
+
34
+ // --------------------------------- staggered lattice
35
+ #define NPAIRS (NDIM * (NDIM - 1) / 2)
36
+ #define NVOIGT (NDIM + NPAIRS)
37
+ #if NDIM == 3
38
+ #define PAIR_ROW(k, l) (NDIM + 3 - (k) - (l))
39
+ #else
40
+ #define PAIR_ROW(k, l) 2
41
+ #endif
42
+
43
+ // radius of the node-centred derivative of a staggered field, zero on the wall
44
+ __device__ __forceinline__ int rad_node(const int a, const int N) {
45
+ return min(STENCIL_RADIUS, min(a - 1, N - 2 - a));
46
+ }
47
+
48
+ // radius of a half-point derivative, whose taps may sit on the wall
49
+ __device__ __forceinline__ int rad_half(const int a, const int N) {
50
+ return min(STENCIL_RADIUS, min(a, N - 2 - a));
51
+ }
52
+
53
+ __device__ __forceinline__ bool clamped_face(const int clamped, const int d,
54
+ const int side) {
55
+ return (clamped >> (2 * d + side)) & 1;
56
+ }
57
+
58
+ // ---------------------------------- transfer kernels
59
+ extern "C" {
60
+
61
+ // ------------------------------------------------------------------------------------
62
+ __global__ void
63
+ excitation_kernel(real_t *__restrict__ u, const real_t *__restrict__ source,
64
+ const int offset, const int *__restrict__ lin_index,
65
+ const int num_sources, const real_t *__restrict__ weight) {
66
+ const int idx = blockIdx.x * blockDim.x + threadIdx.x;
67
+ if (idx < num_sources) {
68
+ atomicAdd(&u[lin_index[idx]], weight[idx] * source[offset + idx]);
69
+ }
70
+ }
71
+
72
+ // ------------------------------------------------------------------------------------
73
+ __global__ void get_signal_kernel(const real_t *__restrict__ u,
74
+ real_t *__restrict__ um, const int offset,
75
+ const int *__restrict__ lin_index,
76
+ const int num_sensors) {
77
+ const int idx = blockIdx.x * blockDim.x + threadIdx.x;
78
+ if (idx < num_sensors) {
79
+ um[offset + idx] = u[lin_index[idx]];
80
+ }
81
+ }
82
+
83
+ // ------------------------------------------------------------------------------------
84
+ __global__ void set_signal_kernel(real_t *__restrict__ u,
85
+ const real_t *__restrict__ um,
86
+ const int offset,
87
+ const int *__restrict__ lin_index,
88
+ const int num_sensors) {
89
+ const int idx = blockIdx.x * blockDim.x + threadIdx.x;
90
+ if (idx < num_sensors) {
91
+ u[lin_index[idx]] = um[offset + idx];
92
+ }
93
+ }
94
+
95
+ } // extern "C"