Neko-TOP
A portable framework for high-order spectral element flow toplogy optimization.
Loading...
Searching...
No Matches
mma_kernel.h
Go to the documentation of this file.
1
37#ifndef MMA_HIP_KERNEL_H
38#define MMA_HIP_KERNEL_H
39
40#include <cfloat>
41
42// z term of the Hessian of the dip subsolver, Hess -= 10 * a * a^T. The
43// factor 10 is the inverse of the weight 2 * 0.05 of z^2 in L_z.
44template <typename T>
45__global__ void mma_update_hessian_z_kernel(
47 const T* __restrict__ a,
48 const int m)
49{
50 int tid = blockIdx.x * blockDim.x + threadIdx.x;
51 int total = m * m;
52
53 if (tid >= total) return;
54
55 int i = tid % m;
56 int j = tid / m;
57
58 Hess[tid] -= T(10.0) * a[i] * a[j];
59}
60
61template<typename T>
62__global__ void mma_prepare_aa_matrix_kernel(T* __restrict__ AA,
63 const T* __restrict__ s, const T* __restrict__ lambda,
64 const T* __restrict__ d, const T* __restrict__ mu,
65 const T* __restrict__ y, const T* __restrict__ a,
66 const T zeta, const T z, const int m) {
67 const int tj = blockIdx.x * blockDim.x + threadIdx.x;
68 const int matrix_size = m + 1;
69
70 if (tj >= m) return;
71 AA[tj * matrix_size + tj] += s[tj] / lambda[tj] +
72 (T)1.0 / (d[tj] + mu[tj] / y[tj]);
73 AA[tj * matrix_size + m] = a[tj]; // column m+1
74 AA[m * matrix_size + tj] = a[tj];// row m+1
75
76 // Only first thread updates the bottom-right corner element.
77 if (tj == 0)
78 AA[m * matrix_size + m] = -zeta / z;
79}
80
81
82//Update Hessian diagonal elements (y contributions for dip subsolve)
83template<typename T>
84__global__ void mma_update_hessian_diagonal_kernel(T* __restrict__ Hess,
85 const T* __restrict__ y, const T* __restrict__ mu,
86 const T* __restrict__ lambda, const int m) {
87 int tj = blockIdx.x * blockDim.x + threadIdx.x;
88 if (tj >= m) return;
89
90 T diag = Hess[tj * m + tj];
91 // Contribution from y terms (inactive constraints)
92 if (y[tj] > (T)0.0) {
93 diag -= (T)1.0;
94 }
95
96 // Contribution from -mu/lambda (eq 10)
97 diag -= mu[tj] / lambda[tj];
98 Hess[tj * m + tj] = diag;
99}
100
101// Levenberg-Marquardt algorithm (heuristically)
102// Single-block version for m <= 1024
103template<typename T>
104__global__ void mma_stabilize_hessian_single_kernel(T* __restrict__ Hess, const int m) {
105 const int tid = threadIdx.x;
106
107 // Single thread computes trace and LM factor
108 if (tid == 0) {
109 T trace = (T)0.0;
110 for (int j = 0; j < m; j++) {
111 trace += Hess[j * m + j];
112 }
113 T lm_factor = max((T)(-1.0e-4) * trace / m, (T)1.0e-7);
114
115 // Apply to all diagonal elements
116 for (int j = 0; j < m; j++) {
117 Hess[j * m + j] -= lm_factor;
118 }
119 }
120}
121
122// Levenberg-Marquardt algorithm (heuristically)
123// Multi-block version for m > 1024
124template<typename T>
125__global__ void mma_stabilize_hessian_multi_kernel(T* __restrict__ Hess, const T lm_factor, const int m) {
126 const int i = blockIdx.x * blockDim.x + threadIdx.x;
127 if (i < m) {
128 Hess[i * m + i] -= lm_factor;
129 }
130}
131
132// Small linear solver efficient for (n <= 100)
133template<typename T>
134__global__ void mma_small_lu_kernel(T* __restrict__ A, T* __restrict__ b, const int n) {
135 const int tid = threadIdx.x;
136
137 // Handle 1x1 case
138 if (n == 1) {
139 if (tid == 0 && abs(A[0]) > (T)1e-12) b[0] /= A[0];
140 return;
141 }
142
143 // LU decomposition with partial pivoting
144 for (int k = 0; k < n; k++) {
145 // Pivoting - single thread
146 if (tid == 0) {
147 int max_row = k;
148 T max_val = abs(A[k * n + k]);
149 for (int i = k + 1; i < n; i++) {
150 T val = abs(A[i * n + k]);
151 if (val > max_val) {
152 max_val = val;
153 max_row = i;
154 }
155 }
156 if (max_val > (T)1e-12 && max_row != k) {
157 // Swap rows
158 for (int j = k; j < n; j++) {
159 T temp = A[k * n + j];
160 A[k * n + j] = A[max_row * n + j];
161 A[max_row * n + j] = temp;
162 }
163 // Swap rhs
164 T temp_b = b[k];
165 b[k] = b[max_row];
166 b[max_row] = temp_b;
167 }
168 }
170
171 // Parallel elimination
172 T diag = A[k * n + k];
173 if (abs(diag) > (T)1e-12) {
174 for (int i = tid + k + 1; i < n; i += blockDim.x) {
175 T factor = A[i * n + k] / diag;
176 A[i * n + k] = factor;
177 for (int j = k + 1; j < n; j++) {
178 A[i * n + j] -= factor * A[k * n + j];
179 }
180 }
181 }
183 }
184
185 // Parallel forward substitution
186 for (int i = tid; i < n; i += blockDim.x) {
187 T sum = b[i];
188 for (int j = 0; j < i; j++) {
189 sum -= A[i * n + j] * b[j];
190 }
191 b[i] = sum;
192 }
194
195 // Parallel backward substitution
196 for (int i = n - 1 - tid; i >= 0; i -= blockDim.x) {
197 if (i >= 0) {
198 T sum = b[i];
199 for (int j = i + 1; j < n; j++) {
200 sum -= A[i * n + j] * b[j];
201 }
202 if (abs(A[i * n + i]) > (T)1e-12) {
203 b[i] = sum / A[i * n + i];
204 }
205 }
206 }
208}
209
210
211template <typename T>
212__global__ void delta_1dbeam_kernel(T* __restrict__ Delta,
213 const T L_total, const T Le, const int offset, const int n) {
214 int k = blockIdx.x * blockDim.x + threadIdx.x;
215 if (k >= n) return;
216
217 // Convert to 1-based indexing for the calculation
218 int idx = k + 1;
219
220 // Calculate first term: (L_total - Le*(offset+idx-1))^3
221 T x1 = L_total - Le * static_cast<T>(offset + idx - 1);
222 T term1 = x1 * x1 * x1;
223
224 // Calculate second term: (L_total - Le*(offset+idx))^3
225 T x2 = L_total - Le * static_cast<T>(offset + idx);
226 T term2 = x2 * x2 * x2;
227
228 // Final result
229 Delta[k] = (term1 - term2) / static_cast<T>(3.0);
230}
231
232template <typename T>
233__global__ void mma_Ljjxinv_kernel(T* __restrict__ Ljjxinv,
235 const T* __restrict__ x, const T* __restrict__ low, const T* __restrict__ upp,
236 const T* __restrict__ alpha, const T* __restrict__ beta,
237 const int n) {
238 int tj = blockIdx.x * blockDim.x + threadIdx.x;
239 if (tj >= n) return;
240
241 // Load inputs into registers
242 const T xt = x[tj];
243 const T low_j = low[tj];
244 const T upp_j = upp[tj];
245 const T pj = pjlambda[tj];
246 const T qj = qjlambda[tj];
247
248 // Precompute reused differences
249 const T diff_u = upp_j - xt;
250 const T diff_l = xt - low_j;
251
252 // Cube once (avoiding pow for speed)
253 const T diff_u3 = diff_u * diff_u * diff_u;
254 const T diff_l3 = diff_l * diff_l * diff_l;
255
256 // Compute inverse value safely
257 T denom = 2.0 * pj / diff_u3 + 2.0 * qj / diff_l3;
258 T val = -1.0 / denom;
259
260 // Mask out active primal constraints, as mma_subsolve_dip_cpu with
261 // NEKO_EPS = epsilon(1.0_rp)
262 const T eps = (sizeof(T) == sizeof(float)) ?
263 static_cast<T>(FLT_EPSILON) :
264 static_cast<T>(DBL_EPSILON);
265 bool active = (xt - alpha[tj] < eps) || (beta[tj] - xt < eps);
266
267 Ljjxinv[tj] = active ? T(0.0) : val;
268}
269
270template <typename T>
271__global__ void mma_dipsolvesub1_kernel(T* __restrict__ x,
273 const T* __restrict__ low, const T* __restrict__ upp,
274 const T* __restrict__ alpha, const T* __restrict__ beta,
275 const int n) {
276
277 int tj = blockIdx.x * blockDim.x + threadIdx.x;
278 if (tj >= n) return;
279
280 // Load inputs into registers
281 const T pj_sqrt = sqrt(pjlambda[tj]);
282 const T qj_sqrt = sqrt(qjlambda[tj]);
283 const T denom = pj_sqrt + qj_sqrt;
284
285 const T low_j = low[tj];
286 const T upp_j = upp[tj];
287 const T alpha_j = alpha[tj];
288 const T beta_j = beta[tj];
289
290 // Weighted average
291 const T val = (pj_sqrt * low_j + qj_sqrt * upp_j) / denom;
292
293 // Clamp x between alpha and beta using branchless min/max
294 x[tj] = fmin(fmax(val, alpha_j), beta_j);
295}
296
297template <typename T>
298__global__ void mattrans_v_mul_kernel(T* __restrict__ output,
299 const T* __restrict__ pij, const T* __restrict__ lambda,
300 const int m, const int n) {
301
302 int tj = blockIdx.x * blockDim.x + threadIdx.x;
303 if (tj >= n) return;
304
305 T acc = 0.0;
306
307 // Use register accumulation
308 for (int i = 0; i < m; ++i) {
309 acc += pij[i + tj * m] * lambda[i];
310 }
311
312 output[tj] = acc;
313}
314
315
316template <typename T>
317__global__ void mma_sub1_kernel(
320 const T* __restrict__ x,
321 const T* __restrict__ xmin,
322 const T* __restrict__ xmax,
323 const T asyinit,
324 const int n) {
325 int tj = blockIdx.x * blockDim.x + threadIdx.x;
326 if (tj >= n) return;
327
328 // Load values once into registers (global memory is slow)
329 const T xt = x[tj];
330 const T xmin_j = xmin[tj];
331 const T xmax_j = xmax[tj];
332
333 // Reuse xgap calculation
334 const T xgap = xmax_j - xmin_j;
335 const T offset = asyinit * xgap;
336
337 xlow[tj] = xt - offset;
338 xupp[tj] = xt + offset;
339}
340
341template< typename T >
342__global__ void mma_sub2_kernel(T* __restrict__ low, T* __restrict__ upp,
343 const T* __restrict__ x, const T* __restrict__ xold1,
344 const T* __restrict__ xold2, const T* __restrict__ xdiff,
345 const T asydecr, const T asyincr, const int n) {
346 int tj = blockIdx.x * blockDim.x + threadIdx.x;
347 if (tj >= n) return;
348
349 // Load data into registers for faster accessing compare to global memory
350 // when accessing repeatedly)
351 const T xval = x[tj];
352 const T xold1val = xold1[tj];
353 const T xold2val = xold2[tj];
354 const T lowval = low[tj];
355 const T uppval = upp[tj];
356 const T xdiffval = xdiff[tj];
357
358 // Compute the product
359 const T prod = (xval - xold1val) * (xold1val - xold2val);
360
361 // Compute asy_factor without branching
362 T asy_factor = (prod < T(0)) ? asydecr :
363 (prod > T(0)) ? asyincr : T(1);
364
365 // Update low and upp using fma (fused multiply-add) for numerical stability
368
369 // Apply bounds
370 new_low = max(new_low, xval - T(10.0) * xdiffval);
371 new_low = min(new_low, xval - T(0.01) * xdiffval);
372
373 new_upp = min(new_upp, xval + T(10.0) * xdiffval);
374 new_upp = max(new_upp, xval + T(0.01) * xdiffval);
375
376 // Write results back
377 low[tj] = new_low;
378 upp[tj] = new_upp;
379}
380
381template <typename T>
382__global__ void mma_sub3_kernel( const T* __restrict__ x,
383 const T* __restrict__ df0dx, const T* __restrict__ dfdx,
384 T* __restrict__ low, T* __restrict__ upp, const T* __restrict__ xmin,
385 const T* __restrict__ xmax, T* __restrict__ alpha, T* __restrict__ beta,
386 T* __restrict__ p0j, T* __restrict__ q0j, T* __restrict__ pij,
387 T* __restrict__ qij, const int n, const int m) {
388 int tj = blockIdx.x * blockDim.x + threadIdx.x;
389 if (tj >= n) return;
390
391 // Load into registers once
392 const T xt = x[tj];
393 const T xmin_j = xmin[tj];
394 const T xmax_j = xmax[tj];
395 const T low_j = low[tj];
396 const T upp_j = upp[tj];
397 const T df0 = df0dx[tj];
398 const T xgap = xmax_j - xmin_j;
399
400 // Clamp helpers
401 const T tenth_low_diff = T(0.1) * (xt - low_j);
402 const T tenth_upp_diff = T(0.1) * (upp_j - xt);
403
404 // Compute alpha and beta with fused max/min and fewer calls
407
408 alpha[tj] = alpha_val;
409 beta[tj] = beta_val;
410
411 // Avoid multiple pow calls, compute once
412 const T upp_minus_x = upp_j - xt;
413 const T x_minus_low = xt - low_j;
416
417 // Small epsilon for numerical stability
418 const T eps = T(1e-5);
419 const T inv_xgap = T(1.0) / max(eps, xgap);
420
421 // Compute terms reused multiple times
422 const T max_df0_pos = max(df0, T(0));
423 const T max_df0_neg = max(-df0, T(0));
424
425 p0j[tj] = upp_minus_x_sq * (T(1.001) * max_df0_pos +
426 T(0.001) * max_df0_neg + eps * inv_xgap);
427 q0j[tj] = x_minus_low_sq * (T(0.001) * max_df0_pos +
428 T(1.001) * max_df0_neg + eps * inv_xgap);
429
430 // Loop over m for pij and qij
431 for (int i = 0; i < m; ++i) {
432 int idx = i + tj * m;
433
434 T dfdx_val = dfdx[idx];
435 T max_pos = max(dfdx_val, T(0));
436 T max_neg = max(-dfdx_val, T(0));
437
438 pij[idx] = upp_minus_x_sq * (T(1.001) * max_pos +
439 T(0.001) * max_neg + eps * inv_xgap);
440 qij[idx] = x_minus_low_sq * (T(0.001) * max_pos +
441 T(1.001) * max_neg + eps * inv_xgap);
442 }
443}
444
445// As mma_sub3_kernel, but with the p0j, q0j, pij and qij of the dip
446// subsolver (mma_gensub_cpu): following MMA::GenSub in topopt_in_petsc
447// (constraintModification = false), only the objective is regularised,
448// by 0.5e-6/(upp - low).
449template <typename T>
450__global__ void mma_sub3_dip_kernel( const T* __restrict__ x,
451 const T* __restrict__ df0dx, const T* __restrict__ dfdx,
452 T* __restrict__ low, T* __restrict__ upp, const T* __restrict__ xmin,
453 const T* __restrict__ xmax, T* __restrict__ alpha, T* __restrict__ beta,
454 T* __restrict__ p0j, T* __restrict__ q0j, T* __restrict__ pij,
455 T* __restrict__ qij, const int n, const int m) {
456 int tj = blockIdx.x * blockDim.x + threadIdx.x;
457 if (tj >= n) return;
458
459 // Load into registers once
460 const T xt = x[tj];
461 const T xmin_j = xmin[tj];
462 const T xmax_j = xmax[tj];
463 const T low_j = low[tj];
464 const T upp_j = upp[tj];
465 const T df0 = df0dx[tj];
466
467 // Clamp helpers
468 const T tenth_low_diff = T(0.1) * (xt - low_j);
469 const T tenth_upp_diff = T(0.1) * (upp_j - xt);
470
471 // Compute alpha and beta with fused max/min and fewer calls
474
475 alpha[tj] = alpha_val;
476 beta[tj] = beta_val;
477
478 const T upp_minus_x = upp_j - xt;
479 const T x_minus_low = xt - low_j;
482
483 // Regularisation of the objective, a true division as in mma_gensub_cpu
484 const T reg = T(0.5) * T(1.0e-6) / (upp_j - low_j);
485
486 p0j[tj] = upp_minus_x_sq * (max(df0, T(0)) + T(0.001) * abs(df0) + reg);
487 q0j[tj] = x_minus_low_sq * (max(-df0, T(0)) + T(0.001) * abs(df0) + reg);
488
489 // The constraints are not regularised
490 for (int i = 0; i < m; ++i) {
491 const int idx = i + tj * m;
492 const T dfdx_val = dfdx[idx];
493
494 pij[idx] = upp_minus_x_sq * max(dfdx_val, T(0));
495 qij[idx] = x_minus_low_sq * max(-dfdx_val, T(0));
496 }
497}
498
499template <typename T>
500__global__ void mma_sub4_kernel(
501 const T* __restrict__ x,
502 const T* __restrict__ low,
503 const T* __restrict__ upp,
504 const T* __restrict__ pij,
505 const T* __restrict__ qij,
506 T* __restrict__ temp,
507 const int n,
508 const int m) {
509
510 int tj = blockIdx.x * blockDim.x + threadIdx.x;
511 if (tj >= n) return;
512
513 // Register caching
514 const T xt = x[tj];
515 const T low_j = low[tj];
516 const T upp_j = upp[tj];
517
518 const T denom_upp = upp_j - xt;
519 const T denom_low = xt - low_j;
520
521 const T eps = T(1e-12); // Precision-dependent epsilon
522 const T inv_denom_upp = T(1) / max(denom_upp, eps);
523 const T inv_denom_low = T(1) / max(denom_low, eps);
524
525 const int base_idx = tj * m;
526
527 for (int i = 0; i < m; ++i) {
528 int idx = base_idx + i;
529 temp[idx] = pij[idx] * inv_denom_upp + qij[idx] * inv_denom_low;
530 }
531}
532
533
534template <typename T>
535__global__ void mma_max2_kernel(
536 T* __restrict__ xsi,
537 const T* __restrict__ x,
538 const T* __restrict__ alpha,
539 const int n) {
540
541 int tj = blockIdx.x * blockDim.x + threadIdx.x;
542 if (tj >= n) return;
543
544 const T eps = T(1e-12);
545 T denom = max(x[tj] - alpha[tj], eps);
546 xsi[tj] = max(T(1), T(1) / denom);
547}
548
549template <typename T>
550__global__ void relambda_kernel(
551 T* __restrict__ temp,
552 const T* __restrict__ x,
553 const T* __restrict__ xupp,
554 const T* __restrict__ xlow,
555 const T* __restrict__ pij,
556 const T* __restrict__ qij,
557 const int n,
558 const int m) {
559
560 int tj = blockIdx.x * blockDim.x + threadIdx.x;
561 if (tj >= n) return;
562
563 const T xt = x[tj];
564 const T xup = xupp[tj];
565 const T xlo = xlow[tj];
566
567 // Prevent divide-by-zero using small epsilon
568 const T eps = T(1e-12);
569 const T inv_denom_upp = T(1) / max(xup - xt, eps);
570 const T inv_denom_low = T(1) / max(xt - xlo, eps);
571
572 int base_idx = tj * m;
573 for (int i = 0; i < m; ++i) {
574 int idx = base_idx + i;
575 temp[idx] = pij[idx] * inv_denom_upp + qij[idx] * inv_denom_low;
576 }
577}
578
579
580template <typename T>
581__global__ void sub2cons2_kernel(
582 T* __restrict__ a,
583 const T* __restrict__ b,
584 const T* __restrict__ c,
585 const T* __restrict__ d,
586 const T e,
587 const int n) {
588 const int idx = blockIdx.x * blockDim.x + threadIdx.x;
589 if (idx >= n) return;
590
591 const T bt = b[idx];
592 const T ct = c[idx];
593 const T dt = d[idx];
594
595 a[idx] = bt * (ct - dt) - e;
596}
597
598template <typename T>
599__inline__ __device__ T max_reduce_warp(T val) {
600 int w = warpSize;
601 for (int offset = w / 2; offset > 0; offset /= 2)
602 val = max(val, __shfl_down(val, offset, w));
603 return val;
604}
605
606template< typename T >
607__global__ void maxval_kernel(const T* __restrict__ a, T *temp, const int n) {
608
609 const int idx = blockIdx.x * blockDim.x + threadIdx.x;
610 const int str = blockDim.x * gridDim.x;
611
612 const unsigned int lane = threadIdx.x % warpSize;
613 const unsigned int wid = threadIdx.x / warpSize;
614
615 __shared__ T shared[16];
616 T maxval = 0.0;
617 for (int i = idx; i < n; i += str) {
618 maxval = max(maxval, abs(a[i]));
619 }
620
622 if (lane == 0)
623 shared[wid] = maxval;
625
626 maxval = (threadIdx.x < blockDim.x / warpSize) ? shared[lane] : 0.0;
627 if (wid == 0)
629
630 if (threadIdx.x == 0)
631 temp[blockIdx.x] = maxval;
632
633}
634
635
636template <typename T>
637__global__ void max_reduce_kernel(T* __restrict__ bufred, const int n) {
638
639 T maxval = T(0);
640 const int idx = blockIdx.x * blockDim.x + threadIdx.x;
641 const int stride = blockDim.x * gridDim.x;
642
643 // Grid-stride loop to cover all elements
644 for (int i = idx; i < n; i += stride) {
645 maxval = max(maxval, bufred[i]);
646 }
647
648 __shared__ T shared[16]; // One slot per warp (max 1024 threads/block)
649
650 unsigned int lane = threadIdx.x % warpSize;
651 unsigned int wid = threadIdx.x / warpSize;
652
653 // Warp-level max reduction
655
656 // Store each warp's max value in shared memory
657 if (lane == 0) {
658 shared[wid] = maxval;
659 }
661
662 // Let the first warp reduce the warp-level maxima
663 maxval = (threadIdx.x < blockDim.x / warpSize) ? shared[lane] : T(0);
664 if (wid == 0) {
666 }
667
668 // Write the block's maximum value back to bufred[blockIdx.x]
669 if (threadIdx.x == 0) {
671 }
672}
673
674
675template <typename T>
676__global__ void delx_kernel(
678 const T* __restrict__ x,
679 const T* __restrict__ xlow,
680 const T* __restrict__ xupp,
681 const T* __restrict__ pij,
682 const T* __restrict__ qij,
683 const T* __restrict__ p0j,
684 const T* __restrict__ q0j,
685 const T* __restrict__ alpha,
686 const T* __restrict__ beta,
687 const T* __restrict__ lambda,
688 const T epsi,
689 const int n,
690 const int m)
691{
692 int tj = blockIdx.x * blockDim.x + threadIdx.x;
693 if (tj < n) {
694 T xt = x[tj];
695 T xlow_j = xlow[tj];
696 T xupp_j = xupp[tj];
697 T alpha_j = alpha[tj];
698 T beta_j = beta[tj];
699
700 // Precompute denominators squared for better performance
701 T denom_low = xt - xlow_j;
702 T denom_upp = xupp_j - xt;
704 T denom_beta = beta_j - xt;
705
706 const T small_eps = T(1e-12);
711
712 T sum = T(0);
713 for (int i = 0; i < m; i++) {
714 T lambda_i = lambda[i];
715 sum += pij[i + tj * m] * lambda_i / (denom_upp * denom_upp)
716 - qij[i + tj * m] * lambda_i / (denom_low * denom_low);
717 }
718 sum += p0j[tj] / (denom_upp * denom_upp)
719 - q0j[tj] / (denom_low * denom_low)
720 - epsi / denom_alpha
721 + epsi / denom_beta;
722
723 delx[tj] = sum;
724 }
725}
726
727template <typename T>
728__global__ void GG_kernel(
730 const T* __restrict__ x,
731 const T* __restrict__ xlow,
732 const T* __restrict__ xupp,
733 const T* __restrict__ pij,
734 const T* __restrict__ qij,
735 const int n,
736 const int m) {
737
738 int tj = blockIdx.x * blockDim.x + threadIdx.x;
739 if (tj < n) {
740 T xt = x[tj];
741 T xlow_j = xlow[tj];
742 T xupp_j = xupp[tj];
743
744 // Distances from bounds
745 T diff_upper = xupp_j - xt;
746 T diff_lower = xt - xlow_j;
747
748 // Squared distances
751
752 for (int i = 0; i < m; i++) {
753 int idx = i + tj * m;
754 GG[idx] = pij[idx] / diff_upper2 - qij[idx] / diff_lower2;
755 }
756 }
757}
758
759template <typename T>
760__global__ void diagx_kernel(T* __restrict__ diagx, const T* __restrict__ x,
761 const T* __restrict__ xsi, const T* __restrict__ xlow,
762 const T* __restrict__ xupp, const T* __restrict__ p0j,
763 const T* __restrict__ q0j, const T* __restrict__ pij,
764 const T* __restrict__ qij, const T* alpha, const T* beta,
765 const T* eta, const T* lambda, const int n, const int m) {
766 int tj = blockIdx.x * blockDim.x + threadIdx.x;
767 if (tj < n) {
768 T sum = 0;
769 T sum1 = 0;
770 for (int i = 0; i < m; i++) {
771 sum = sum + pij[tj *m+ i] * lambda[i];
772 sum1 = sum1 + qij[tj*m + i] * lambda[i];
773 }
774 diagx[tj] = (p0j[tj] + sum) / pow(xupp[tj] - x[tj], 3) +
775 (q0j[tj] + sum1) / pow(x[tj] - xlow[tj], 3);
776 diagx[tj] = 2.0 * diagx[tj] + xsi[tj] / (x[tj] - alpha[tj]) +
777 eta[tj] / (beta[tj] - x[tj]);
778 }
779}
780
781
782template <typename T>
783__inline__ __device__ T reduce_warp(T val) {
784 int w = warpSize;
785 for (int offset = w / 2; offset > 0; offset /= 2)
786 val += __shfl_down(val, offset, w);
787 return val;
788}
789
790template <typename T>
791__global__ void mmareduce_kernel(T* __restrict__ bufred, const int n) {
792
793 T sum = 0;
794 const int idx = blockIdx.x * blockDim.x + threadIdx.x;
795 const int str = blockDim.x * gridDim.x;
796 for (int i = idx; i < n; i += str)
797 {
798 sum += bufred[i];
799 }
800
801 __shared__ T shared[16];
802 unsigned int lane = threadIdx.x % warpSize;
803 unsigned int wid = threadIdx.x / warpSize;
804
806 if (lane == 0)
807 shared[wid] = sum;
809
810 sum = (threadIdx.x < blockDim.x / warpSize) ? shared[lane] : 0;
811 if (wid == 0)
813
814 if (threadIdx.x == 0)
815 bufred[blockIdx.x] = sum;
816}
817
818
819template< typename T >
820__global__ void mmasum_kernel(const T* __restrict__ a, T* __restrict__ buf_h,
821 const int n, const int m, const int k) {
822
823 const int idx = blockIdx.x * blockDim.x + threadIdx.x;
824 const int str = blockDim.x * gridDim.x;
825
826 const unsigned int lane = threadIdx.x % warpSize;
827 const unsigned int wid = threadIdx.x / warpSize;
828
829 __shared__ T shared[16];
830 T sum = 0;
831 for (int i = idx; i < n; i += str)
832 {
833 sum += a[m * i + k ];
834 }
835
837 if (lane == 0)
838 shared[wid] = sum;
840
841 sum = (threadIdx.x < blockDim.x / warpSize) ? shared[lane] : 0;
842 if (wid == 0)
844
845 if (threadIdx.x == 0)
846 buf_h[blockIdx.x] = sum;
847
848}
849template< typename T >
850__global__ void mmasumbb_kernel(const T* __restrict__ GG,
851 const T* __restrict__ delx, const T* __restrict__ diagx,
852 T* __restrict__ buf_h, const int n, const int m, const int k) {
853
854 const int idx = blockIdx.x * blockDim.x + threadIdx.x;
855 const int str = blockDim.x * gridDim.x;
856
857 const unsigned int lane = threadIdx.x % warpSize;
858 const unsigned int wid = threadIdx.x / warpSize;
859
860 __shared__ T shared[16];
861 T sum = 0;
862 for (int i = idx; i < n; i += str)
863 {
864 sum += GG[ k + i * m] * delx[i] / diagx[i];
865 }
866
868 if (lane == 0)
869 shared[wid] = sum;
871
872 sum = (threadIdx.x < blockDim.x / warpSize) ? shared[lane] : 0;
873 if (wid == 0)
875
876 if (threadIdx.x == 0)
877 buf_h[blockIdx.x] = sum;
878
879}
880
881template <typename T>
882__global__ void mmasumHess_kernel(
883 const T* __restrict__ hijx,
884 const T* __restrict__ Ljjxinv,
886 const int n,
887 const int m,
888 const int k0,
889 const int k1)
890{
891 const int idx = blockIdx.x * blockDim.x + threadIdx.x;
892 const int stride = blockDim.x * gridDim.x;
893
894 // Warp lane and warp id within the block
895 const unsigned int lane = threadIdx.x % warpSize;
896 const unsigned int wid = threadIdx.x / warpSize;
897
898 __shared__ T shared[16];
899
900 T sum = T(0);
901
902 // Grid-stride loop for global reduction
903 for (int i = idx; i < n; i += stride) {
904 // hijx is indexed as hijx[offset + row * m]
905 T val0 = hijx[k0 + i * m];
906 T val1 = hijx[k1 + i * m];
907 sum += val0 * Ljjxinv[i] * val1;
908 }
909
910 // Warp-level reduction using your reduce_warp implementation
912
913 // Write each warp's partial sum to shared memory
914 if (lane == 0) {
915 shared[wid] = sum;
916 }
918
919 // First warp reduces the warp sums in shared memory
920 sum = (threadIdx.x < blockDim.x / warpSize) ? shared[lane] : T(0);
921 if (wid == 0) {
923 }
924
925 // Write final result from first thread of block
926 if (threadIdx.x == 0) {
927 buf_h[blockIdx.x] = sum;
928 }
929}
930
931template< typename T >
932__global__ void mmasumAA_kernel(const T* __restrict__ GG,
933 const T* __restrict__ diagx, T* __restrict__ buf_h, const int n,
934 const int m, const int k0, const int k1) {
935
936 const int idx = blockIdx.x * blockDim.x + threadIdx.x;
937 const int str = blockDim.x * gridDim.x;
938
939 const unsigned int lane = threadIdx.x % warpSize;
940 const unsigned int wid = threadIdx.x / warpSize;
941
942 __shared__ T shared[16];
943 T sum = 0;
944 for (int i = idx; i < n; i += str)
945 {
946 sum += GG[ k0 + i * m] /diagx[i] * GG[ k1 + i * m];
947 }
948
950 if (lane == 0)
951 shared[wid] = sum;
953
954 sum = (threadIdx.x < blockDim.x / warpSize) ? shared[lane] : 0;
955 if (wid == 0)
957
958 if (threadIdx.x == 0)
959 buf_h[blockIdx.x] = sum;
960
961}
962
963
964template <typename T>
965__global__ void mma_copy_kernel(T* __restrict__ a, const T* __restrict__ b,
966 const int n, const int m) {
967 int tj = blockIdx.x * blockDim.x + threadIdx.x;
968 if(tj<n)
969 a[tj+m]=b[tj];
970}
971
972
973
974template <typename T>
975__global__ void AA_kernel(T* __restrict__ temp, const T* __restrict__ GG,
976 const T* __restrict__ diagx, const int n, const int m) {
977 int tj = blockIdx.x * blockDim.x + threadIdx.x;
978 if (tj < n) {
979 for (int i0 = 0; i0 < m; i0++) {
980 for (int i1 = 0; i1 < m; i1++) {
981 temp[tj + i0 * (n + 1) + i1 * (m + 1) * (n + 1)] = GG[i0 * n + tj] *
982 (1.0 / diagx[tj]) * GG[i1 * n + tj];
983 }
984 }
985 }
986}
987
988
989template <typename T>
990__global__ void dx_kernel(T* __restrict__ dx, const T* __restrict__ delx,
991 const T* __restrict__ diagx, const T* __restrict__ GG,
992 const T* __restrict__ dlambda, const int n, const int m) {
993 int tj = blockIdx.x * blockDim.x + threadIdx.x;
994 if (tj < n) {
995 dx[tj] = -delx[tj]/diagx[tj];
996 for(int i=0;i<m;i++){
997 dx[tj] =dx[tj] - GG[tj*m+i]*dlambda[i]/diagx[tj];
998 }
999 }
1000}
1001
1002
1003
1004template <typename T>
1005__global__ void dxsi_kernel(T* __restrict__ dxsi, const T* __restrict__ xsi,
1006 const T* __restrict__ dx, const T* __restrict__ x,
1007 const T* __restrict__ alpha, const T epsi, const int n) {
1008 int tj = blockIdx.x * blockDim.x + threadIdx.x;
1009 if (tj < n) {
1010 dxsi[tj]= -xsi[tj] + (epsi-dx[tj]*xsi[tj])/(x[tj] - alpha[tj]);
1011 }
1012}
1013
1014
1015template <typename T>
1016__global__ void deta_kernel(T* __restrict__ deta, const T* __restrict__ eta,
1017 const T* __restrict__ dx, const T* __restrict__ x,
1018 const T* __restrict__ beta, const T epsi, const int n) {
1019 int tj = blockIdx.x * blockDim.x + threadIdx.x;
1020 if (tj < n) {
1021 deta[tj] = -eta[tj] + (epsi + dx[tj] * eta[tj]) / (beta[tj] - x[tj]);
1022 }
1023}
1024
1025template <typename T>
1026__global__ void RexCalculation_kernel(
1028 const T* __restrict__ x,
1029 const T* __restrict__ xlow,
1030 const T* __restrict__ xupp,
1031 const T* __restrict__ pij,
1032 const T* __restrict__ p0j,
1033 const T* __restrict__ qij,
1034 const T* __restrict__ q0j,
1035 const T* __restrict__ lambda,
1036 const T* __restrict__ xsi,
1037 const T* __restrict__ eta,
1038 const int n,
1039 const int m)
1040{
1041 int tj = blockIdx.x * blockDim.x + threadIdx.x;
1042 if (tj < n) {
1043 T upp_diff = xupp[tj] - x[tj];
1044 T low_diff = x[tj] - xlow[tj];
1047
1048 T sum = 0.0;
1049 for (int i = 0; i < m; ++i) {
1050 sum += pij[i + tj * m] * lambda[i] / upp_diff_sq
1051 - qij[i + tj * m] * lambda[i] / low_diff_sq;
1052 }
1053
1054 rex[tj] = sum
1055 + p0j[tj] / upp_diff_sq
1056 - q0j[tj] / low_diff_sq
1057 - xsi[tj] + eta[tj];
1058 }
1059}
1060
1061template <typename T>
1062__global__ void rey_calculation_kernel(T* __restrict__ rey,
1063 const T* __restrict__ c, const T* __restrict__ d, const T* __restrict__ y,
1064 const T* __restrict__ lambda, const T* __restrict__ mu, const int n) {
1065 int tj = blockIdx.x * blockDim.x + threadIdx.x;
1066 if (tj < n) {
1067 rey[tj] = c[tj] + d[tj] * y[tj] - lambda[tj] - mu[tj];
1068 }
1069}
1070
1071
1072template< typename T >
1073__global__ void norm_kernel(const T* __restrict__ a, T* __restrict__ buf_h,
1074 const int n) {
1075
1076 const int idx = blockIdx.x * blockDim.x + threadIdx.x;
1077 const int str = blockDim.x * gridDim.x;
1078
1079 const unsigned int lane = threadIdx.x % warpSize;
1080 const unsigned int wid = threadIdx.x / warpSize;
1081
1082 __shared__ T shared[16];
1083 T sum = 0;
1084 for (int i = idx; i < n; i += str)
1085 {
1086 sum += pow(a[i], 2);
1087 }
1088
1090 if (lane == 0)
1091 shared[wid] = sum;
1092 __syncthreads();
1093
1094 sum = (threadIdx.x < blockDim.x / warpSize) ? shared[lane] : 0;
1095 if (wid == 0)
1097
1098 if (threadIdx.x == 0)
1099 buf_h[blockIdx.x] = sum;
1100
1101}
1102
1103
1104
1105template <typename T>
1106__global__ void sub2cons_kernel(T* __restrict__ a, const T* __restrict__ b,
1107 const T* __restrict__ c,
1108 const T d, const int n) {
1109 int tj = blockIdx.x * blockDim.x + threadIdx.x;
1110 if (tj < n) {
1111 a[tj] = b[tj]*c[tj]-d;
1112 }
1113}
1114
1115
1116template <typename T>
1117__global__ void dely_kernel(T* __restrict__ dely, const T* __restrict__ c,
1118 const T* __restrict__ d, const T* __restrict__ y,
1119 const T* __restrict__ lambda, const T epsi, const int n) {
1120 int tj = blockIdx.x * blockDim.x + threadIdx.x;
1121 if (tj < n) {
1122 dely[tj] = c[tj] + d[tj]*y[tj] - lambda[tj] - epsi/y[tj];
1123 }
1124}
1125
1126
1127
1128template< typename T >
1129__global__ void maxval2_kernel(const T* __restrict__ a, const T* __restrict__ b,
1130 T* __restrict__ temp, const T cons, const int n) {
1131
1132 const int idx = blockIdx.x * blockDim.x + threadIdx.x;
1133 const int str = blockDim.x * gridDim.x;
1134
1135 const unsigned int lane = threadIdx.x % warpSize;
1136 const unsigned int wid = threadIdx.x / warpSize;
1137
1138 __shared__ T shared[16];
1139 T maxval = cons * a[0] / b[0];
1140 for (int i = idx; i < n; i += str)
1141 {
1142 maxval = max(maxval, cons * a[i] / b[i]);
1143 }
1144
1146 if (lane == 0)
1147 shared[wid] = maxval;
1148 __syncthreads();
1149
1150 maxval = (threadIdx.x < blockDim.x / warpSize) ? shared[lane] : 0.0;
1151 if (wid == 0)
1153
1154 if (threadIdx.x == 0)
1155 temp[blockIdx.x] = maxval;
1156
1157}
1158
1159
1160template< typename T >
1161__global__ void maxval3_kernel(const T* __restrict__ a, const T* __restrict__ b,
1162 const T* __restrict__ c, T* __restrict__ temp, const T cons, const int n) {
1163
1164 const int idx = blockIdx.x * blockDim.x + threadIdx.x;
1165 const int str = blockDim.x * gridDim.x;
1166
1167 const unsigned int lane = threadIdx.x % warpSize;
1168 const unsigned int wid = threadIdx.x / warpSize;
1169
1170 __shared__ T shared[16];
1171 T maxval = cons * a[0] / b[0];
1172 for (int i = idx; i < n; i += str)
1173 {
1174 maxval = max(maxval, cons * a[i] / (b[i] - c[i]));
1175 }
1176
1178 if (lane == 0)
1179 shared[wid] = maxval;
1180 __syncthreads();
1181
1182 maxval = (threadIdx.x < blockDim.x / warpSize) ? shared[lane] : 0;
1183 if (wid == 0)
1185
1186 if (threadIdx.x == 0)
1187 temp[blockIdx.x] = maxval;
1188
1189}
1190
1191
1192template <typename T>
1193__global__ void kkt_rex_kernel(T* __restrict__ rex, const T* __restrict__ df0dx,
1194 const T* __restrict__ dfdx, const T* __restrict__ xsi,
1195 const T* __restrict__ eta, const T* __restrict__ lambda, const int n,
1196 const int m) {
1197 int tj = blockIdx.x * blockDim.x + threadIdx.x;
1198 if (tj < n) {
1199 rex[tj] = 0.0;
1200 for (int i = 0; i < m; i++) {
1201 rex[tj] = rex[tj] + dfdx[i + tj*m] * lambda[i];
1202 }
1203 rex[tj] += df0dx[tj] - xsi[tj] + eta[tj];
1204 }
1205}
1206
1207// KKT residual of the original problem for the dip subsolver, as
1208// mma_dip_KKT_cpu (MMA::KKTresidual in topopt_in_petsc), for each local
1209// design variable j: the stationarity in res[j] and the complementarity
1210// of the lower and upper bounds in res[n + j] and res[2n + j]. The bound
1211// multipliers are estimated where x_j is within 1e-5 of the true bounds.
1212template <typename T>
1213__global__ void mma_dip_kkt_kernel(T* __restrict__ res,
1214 const T* __restrict__ x, const T* __restrict__ df0dx,
1215 const T* __restrict__ dfdx, const T* __restrict__ xmin,
1216 const T* __restrict__ xmax, const T* __restrict__ lambda,
1217 const int n, const int m) {
1218 const int tj = blockIdx.x * blockDim.x + threadIdx.x;
1219 if (tj >= n) return;
1220
1221 const T xt = x[tj];
1222 const T xmin_j = xmin[tj];
1223 const T xmax_j = xmax[tj];
1224
1225 // Gradient of the Lagrangian w.r.t. x_j
1226 T rex = df0dx[tj];
1227 for (int i = 0; i < m; i++) {
1228 rex = rex + lambda[i] * dfdx[i + tj * m];
1229 }
1230
1231 // Estimate the bound multipliers where x_j is at a bound
1232 T xsi = T(0.0);
1233 if (xt < xmin_j + T(1.0e-5) && rex > T(0.0)) xsi = rex;
1234 T eta = T(0.0);
1235 if (xt > xmax_j - T(1.0e-5) && rex < T(0.0)) eta = -rex;
1236 rex = rex + (-xsi + eta);
1237
1238 res[tj] = rex;
1239 res[n + tj] = xsi * (xt - xmin_j);
1240 res[2 * n + tj] = eta * (xmax_j - xt);
1241}
1242
1243
1244template <typename T>
1245__global__ void maxcons_kernel(T* __restrict__ a, const T b,
1246 const T c, const T* __restrict__ d, const int n) {
1247 int tj = blockIdx.x * blockDim.x + threadIdx.x;
1248 if (tj < n) {
1249 a[tj] = max(b, c * d[tj]);
1250 }
1251}
1252
1255 template< typename T >
1256 __global__ void glsum_kernel(const T * a, T * buf_h, const int n) {
1257 const int idx = blockIdx.x * blockDim.x + threadIdx.x;
1258 const int str = blockDim.x * gridDim.x;
1259
1260 const unsigned int lane = threadIdx.x % warpSize;
1261 const unsigned int wid = threadIdx.x / warpSize;
1262
1263 __shared__ T shared[16];
1264 T sum = 0;
1265 for (int i = idx; i<n ; i += str)
1266 {
1267 sum += a[i];
1268 }
1269
1271 if (lane == 0)
1272 shared[wid] = sum;
1273 __syncthreads();
1274
1275 sum = (threadIdx.x < blockDim.x / warpSize) ? shared[lane] : 0;
1276 if (wid == 0)
1278
1279 if (threadIdx.x == 0)
1280 buf_h[blockIdx.x] = sum;
1281
1282 }
1283 template< typename T >
1284__global__ void glsc2_kernel(const T * a,
1285 const T * b,
1286 T * buf_h,
1287 const int n) {
1288
1289 const int idx = blockIdx.x * blockDim.x + threadIdx.x;
1290 const int str = blockDim.x * gridDim.x;
1291
1292 const unsigned int lane = threadIdx.x % warpSize;
1293 const unsigned int wid = threadIdx.x / warpSize;
1294
1295 __shared__ T shared[16];
1296 T sum = 0.0;
1297 for (int i = idx; i < n; i+= str) {
1298 sum += a[i] * b[i];
1299 }
1300
1302 if (lane == 0)
1303 shared[wid] = sum;
1304 __syncthreads();
1305
1306 sum = (threadIdx.x < blockDim.x / warpSize) ? shared[lane] : 0;
1307 if (wid == 0)
1309
1310 if (threadIdx.x == 0)
1311 buf_h[blockIdx.x] = sum;
1312
1313 }
1314
1315
1316
1317
1318
1319template <typename T>
1320__global__ void add2inv2_kernel(T* __restrict__ a, const T* __restrict__ b,
1321 const T c, const int n) {
1322 int tj = blockIdx.x * blockDim.x + threadIdx.x;
1323 if (tj < n) {
1324 a[tj] = a[tj]+c/b[tj];
1325 }
1326}
1327
1328template <typename T>
1329__global__ void max2_kernel(T* __restrict__ a, const T b,
1330 const T* __restrict__ c, const T d, const int n) {
1331 int tj = blockIdx.x * blockDim.x + threadIdx.x;
1332 if (tj < n) {
1333 a[tj]=max(b, d*c[tj]);
1334 }
1335}
1336
1337template <typename T>
1338__global__ void updatebb_kernel(T* __restrict__ bb,
1339 const T* __restrict__ dellambda, const T* __restrict__ dely,
1340 const T* __restrict__ d, const T* __restrict__ mu,
1341 const T* __restrict__ y, const T delz, const int m) {
1342 int tj = blockIdx.x * blockDim.x + threadIdx.x;
1343 if(tj<m)
1344 bb[tj]=dellambda[tj] + dely[tj]/(d[tj] + mu[tj]/y[tj]) - bb[tj];
1345 else if(tj<m+1)
1346 bb[tj]=delz;
1347}
1348
1349
1350
1351template <typename T>
1352__global__ void updateAA_kernel(T* __restrict__ AA,
1353 const T* __restrict__ globaltmp_mm, const T* __restrict__ s,
1354 const T* __restrict__ lambda, const T* __restrict__ d,
1355 const T* __restrict__ mu, const T* __restrict__ y, const T* __restrict__ a,
1356 const T zeta, const T z, const int m) {
1357 int tj = blockIdx.x * blockDim.x + threadIdx.x;
1358 if(tj<m)
1359 {
1360 AA[tj+tj*(m+1)]=globaltmp_mm[tj+tj*m] + (s[tj] / lambda[tj] +
1361 1.0/ (d[tj] + mu[tj] / y[tj]));
1362 AA[tj+m*(m+1)]=a[tj];
1363 AA[m+tj*(m+1)]=a[tj];
1364 }
1365 else if(tj<m+1)
1366 AA[tj+tj*(m+1)]= -zeta/z;
1367}
1368
1369template <typename T>
1370__global__ void dy_kernel(T* __restrict__ dy, const T* __restrict__ dely,
1371 const T* __restrict__ dlambda, const T* __restrict__ d,
1372 const T* __restrict__ mu, const T* __restrict__ y, const int n) {
1373 int tj = blockIdx.x * blockDim.x + threadIdx.x;
1374 if(tj<n)
1375 dy[tj] = (-dely[tj]+dlambda[tj])/(d[tj] + mu[tj]/y[tj]);
1376}
1377
1378#endif
1379
__global__ void Borrvall_Petersson_mapping_apply_kernel(const T f_min, const T f_max, const T q, T *__restrict__ X_out_d, T *__restrict__ X_in_d, const int n)