Line data Source code
1 : /**
2 : * Outlet Boundary Conditions - Common Definitions
3 : *
4 : * Shared helper functions and data structures used by all outlet BC
5 : * backend implementations (scalar, OMP, AVX2, NEON).
6 : *
7 : * This header is internal and should only be included by outlet BC
8 : * implementation files.
9 : */
10 :
11 : #ifndef CFD_BOUNDARY_CONDITIONS_OUTLET_COMMON_H
12 : #define CFD_BOUNDARY_CONDITIONS_OUTLET_COMMON_H
13 :
14 : #include "boundary_conditions_internal.h"
15 : #include "cfd/core/indexing.h"
16 :
17 : /* ============================================================================
18 : * Edge validation
19 : *
20 : * bc_edge_t uses bit flags (0x01..0x20) for potential combining.
21 : * We convert these to sequential indices (0-5) for array lookup.
22 : * ============================================================================ */
23 :
24 : /**
25 : * Check if edge value is valid (exactly one of the six valid edges).
26 : */
27 61 : static inline bool bc_outlet_is_valid_edge(bc_edge_t edge) {
28 61 : return edge == BC_EDGE_LEFT || edge == BC_EDGE_RIGHT ||
29 : edge == BC_EDGE_BOTTOM || edge == BC_EDGE_TOP ||
30 : edge == BC_EDGE_FRONT || edge == BC_EDGE_BACK;
31 : }
32 :
33 : /**
34 : * Check if outlet type is valid.
35 : */
36 : static inline bool bc_outlet_is_valid_type(bc_outlet_type_t type) {
37 : return type == BC_OUTLET_ZERO_GRADIENT || type == BC_OUTLET_CONVECTIVE;
38 : }
39 :
40 : /* ============================================================================
41 : * Index computation functions for each edge
42 : *
43 : * For zero-gradient outlet: boundary = adjacent interior value
44 : * Left: field[j*nx + 0] = field[j*nx + 1]
45 : * Right: field[j*nx + nx-1] = field[j*nx + nx-2]
46 : * Bottom: field[i] = field[nx + i]
47 : * Top: field[(ny-1)*nx + i] = field[(ny-2)*nx + i]
48 : * Back: field[k=0 plane] = field[k=1 plane] (3D only)
49 : * Front: field[k=nz-1 plane] = field[k=nz-2 plane] (3D only)
50 : * ============================================================================ */
51 :
52 : typedef size_t (*bc_outlet_idx_func_t)(size_t i, size_t nx, size_t ny);
53 :
54 : /* Destination index functions (boundary) */
55 107 : static inline size_t bc_outlet_dst_left(size_t j, size_t nx, size_t ny) {
56 107 : (void)ny;
57 107 : return IDX_2D(0, j, nx);
58 : }
59 :
60 347 : static inline size_t bc_outlet_dst_right(size_t j, size_t nx, size_t ny) {
61 347 : (void)ny;
62 347 : return IDX_2D(nx - 1, j, nx);
63 : }
64 :
65 107 : static inline size_t bc_outlet_dst_bottom(size_t i, size_t nx, size_t ny) {
66 107 : (void)nx; (void)ny;
67 107 : return i;
68 : }
69 :
70 107 : static inline size_t bc_outlet_dst_top(size_t i, size_t nx, size_t ny) {
71 107 : return IDX_2D(i, ny - 1, nx);
72 : }
73 :
74 : /* Source index functions (adjacent interior) */
75 107 : static inline size_t bc_outlet_src_left(size_t j, size_t nx, size_t ny) {
76 107 : (void)ny;
77 107 : return IDX_2D(1, j, nx);
78 : }
79 :
80 347 : static inline size_t bc_outlet_src_right(size_t j, size_t nx, size_t ny) {
81 347 : (void)ny;
82 347 : return IDX_2D(nx - 2, j, nx);
83 : }
84 :
85 107 : static inline size_t bc_outlet_src_bottom(size_t i, size_t nx, size_t ny) {
86 107 : (void)ny;
87 107 : return nx + i;
88 : }
89 :
90 107 : static inline size_t bc_outlet_src_top(size_t i, size_t nx, size_t ny) {
91 107 : return IDX_2D(i, ny - 2, nx);
92 : }
93 :
94 : /**
95 : * Edge loop configuration for table-driven boundary application.
96 : */
97 : typedef struct {
98 : bc_outlet_idx_func_t dst_fn; /* Boundary index computation (NULL for z-faces) */
99 : bc_outlet_idx_func_t src_fn; /* Interior index computation (NULL for z-faces) */
100 : int use_ny_for_count; /* 1 if loop count is ny, 0 if nx (ignored for z-faces) */
101 : int is_z_face; /* 1 for front/back z-face edges */
102 : } bc_outlet_edge_loop_t;
103 :
104 : /**
105 : * Edge loop configuration indexed 0-5 (left, right, bottom, top, front, back).
106 : */
107 : static const bc_outlet_edge_loop_t bc_outlet_edge_loops[6] = {
108 : { .dst_fn = bc_outlet_dst_left, .src_fn = bc_outlet_src_left, .use_ny_for_count = 1, .is_z_face = 0 },
109 : { .dst_fn = bc_outlet_dst_right, .src_fn = bc_outlet_src_right, .use_ny_for_count = 1, .is_z_face = 0 },
110 : { .dst_fn = bc_outlet_dst_bottom, .src_fn = bc_outlet_src_bottom, .use_ny_for_count = 0, .is_z_face = 0 },
111 : { .dst_fn = bc_outlet_dst_top, .src_fn = bc_outlet_src_top, .use_ny_for_count = 0, .is_z_face = 0 },
112 : { .dst_fn = NULL, .src_fn = NULL, .use_ny_for_count = 0, .is_z_face = 1 }, /* FRONT */
113 : { .dst_fn = NULL, .src_fn = NULL, .use_ny_for_count = 0, .is_z_face = 1 }, /* BACK */
114 : };
115 :
116 : /**
117 : * Convert bc_edge_t bit flag to sequential array index (0-5).
118 : * BC_EDGE_LEFT (0x01) -> 0, BC_EDGE_RIGHT (0x02) -> 1,
119 : * BC_EDGE_BOTTOM (0x04) -> 2, BC_EDGE_TOP (0x08) -> 3,
120 : * BC_EDGE_FRONT (0x10) -> 4, BC_EDGE_BACK (0x20) -> 5
121 : *
122 : * Uses bit manipulation to find the position of the least significant set bit
123 : * by counting trailing zeros in the bit flag (clamped to the range 0-5).
124 : * The behavior is only defined for valid, single-bit edges; callers must
125 : * ensure validity via bc_outlet_is_valid_edge() before calling.
126 : */
127 : static inline int bc_outlet_edge_to_index(bc_edge_t edge) {
128 : int idx = 0;
129 : unsigned int e = (unsigned int)edge;
130 143 : while ((e & 1) == 0 && idx < 5) {
131 87 : e >>= 1;
132 87 : idx++;
133 : }
134 56 : return idx;
135 : }
136 :
137 : #endif /* CFD_BOUNDARY_CONDITIONS_OUTLET_COMMON_H */
|