Line data Source code
1 : /**
2 : * Outlet Boundary Conditions - OpenMP Implementation
3 : *
4 : * OpenMP parallelized outlet boundary condition implementation.
5 : * Parallelizes over rows for left/right boundaries and
6 : * over columns for top/bottom boundaries.
7 : *
8 : * Supports:
9 : * - Zero-gradient (Neumann) outlet
10 : * - Convective outlet (advection-based)
11 : * - 3D z-face outlets (FRONT/BACK edges)
12 : */
13 :
14 : #include "../boundary_conditions_outlet_common.h"
15 :
16 : #ifdef CFD_ENABLE_OPENMP
17 : #include <omp.h>
18 :
19 13 : cfd_status_t bc_apply_outlet_omp_impl(double* field, size_t nx, size_t ny,
20 : size_t nz, size_t stride_z,
21 : const bc_outlet_config_t* config) {
22 13 : if (!field || !config || nx < 3 || ny < 3) {
23 : return CFD_ERROR_INVALID;
24 : }
25 :
26 25 : if (!bc_outlet_is_valid_edge(config->edge)) {
27 : return CFD_ERROR_INVALID;
28 : }
29 :
30 12 : if (!bc_outlet_is_valid_type(config->type)) {
31 : return CFD_ERROR_INVALID;
32 : }
33 :
34 12 : int edge_idx = bc_outlet_edge_to_index(config->edge);
35 12 : const bc_outlet_edge_loop_t* loop = &bc_outlet_edge_loops[edge_idx];
36 :
37 12 : switch (config->type) {
38 : case BC_OUTLET_ZERO_GRADIENT:
39 : case BC_OUTLET_CONVECTIVE:
40 : /* Both types use zero-gradient for now.
41 : * Full convective BC would require temporal information. */
42 12 : if (loop->is_z_face) {
43 : /* Z-face outlet (FRONT or BACK): copy entire xy-plane */
44 1 : if (nz <= 1) {
45 : return CFD_ERROR_INVALID;
46 : }
47 1 : size_t dst_plane, src_plane;
48 1 : if (config->edge == BC_EDGE_FRONT) {
49 0 : dst_plane = (nz - 1) * stride_z;
50 0 : src_plane = (nz - 2) * stride_z;
51 : } else { /* BC_EDGE_BACK */
52 : dst_plane = 0;
53 : src_plane = stride_z;
54 : }
55 1 : int plane_size_int = (int)(nx * ny);
56 1 : int idx;
57 1 : #pragma omp parallel for schedule(static)
58 : for (idx = 0; idx < plane_size_int; idx++) {
59 : field[dst_plane + (size_t)idx] = field[src_plane + (size_t)idx];
60 : }
61 : } else {
62 : /* X/Y-face outlet: loop over each z-plane */
63 11 : size_t count = loop->use_ny_for_count ? ny : nx;
64 11 : int count_int = (int)count;
65 22 : for (size_t k = 0; k < nz; k++) {
66 11 : size_t base = k * stride_z;
67 11 : int i;
68 11 : #pragma omp parallel for schedule(static)
69 : for (i = 0; i < count_int; i++) {
70 : size_t dst_idx = base + loop->dst_fn((size_t)i, nx, ny);
71 : size_t src_idx = base + loop->src_fn((size_t)i, nx, ny);
72 : field[dst_idx] = field[src_idx];
73 : }
74 : }
75 : }
76 : break;
77 :
78 : default:
79 : return CFD_ERROR_INVALID;
80 : }
81 :
82 : return CFD_SUCCESS;
83 : }
84 :
85 : #else /* !CFD_ENABLE_OPENMP */
86 :
87 : cfd_status_t bc_apply_outlet_omp_impl(double* field, size_t nx, size_t ny,
88 : size_t nz, size_t stride_z,
89 : const bc_outlet_config_t* config) {
90 : (void)field; (void)nx; (void)ny; (void)nz; (void)stride_z; (void)config;
91 : return CFD_ERROR_UNSUPPORTED;
92 : }
93 :
94 : #endif /* CFD_ENABLE_OPENMP */
|