Line data Source code
1 : /**
2 : * Time-Varying Inlet Boundary Conditions - Scalar (CPU) Implementation
3 : *
4 : * Baseline scalar implementation of time-varying inlet velocity boundary
5 : * conditions. Extends the standard inlet BC with time modulation support.
6 : *
7 : * Supports:
8 : * - All standard inlet profiles (uniform, parabolic, custom)
9 : * - Time modulation: sinusoidal, ramp, step
10 : * - Custom time-varying profile callback
11 : * - 3D z-face inlets (FRONT/BACK edges)
12 : */
13 :
14 : #include "../boundary_conditions_inlet_common.h"
15 : #include "../boundary_conditions_time.h"
16 :
17 : /**
18 : * Compute inlet velocity with time modulation at given position.
19 : *
20 : * This combines the spatial profile (uniform, parabolic, custom) with
21 : * time modulation (sinusoidal, ramp, step, custom).
22 : *
23 : * @param config Inlet configuration with time settings
24 : * @param position Normalized position along the edge [0, 1]
25 : * @param time Current simulation time
26 : * @param dt Current time step
27 : * @param u_out Output: u velocity component
28 : * @param v_out Output: v velocity component
29 : */
30 240 : static void bc_inlet_compute_velocity_time(const bc_inlet_config_t* config,
31 : double position,
32 : double time, double dt,
33 : double* u_out, double* v_out) {
34 : /* Check for custom time-varying profile callback first */
35 240 : if (config->custom_profile_time != NULL) {
36 16 : config->custom_profile_time(position, time, dt, u_out, v_out,
37 16 : config->custom_profile_time_user_data);
38 16 : return;
39 : }
40 :
41 : /* Compute base velocity from spatial profile */
42 224 : double u_base, v_base;
43 224 : bc_inlet_compute_velocity(config, position, &u_base, &v_base);
44 :
45 : /* Apply time modulation */
46 224 : double modulator = bc_time_get_modulator(&config->time_config, time, dt);
47 224 : *u_out = u_base * modulator;
48 224 : *v_out = v_base * modulator;
49 : }
50 :
51 19 : cfd_status_t bc_apply_inlet_time_scalar_impl(double* u, double* v, double* w,
52 : size_t nx, size_t ny,
53 : size_t nz, size_t stride_z,
54 : const bc_inlet_config_t* config,
55 : const bc_time_context_t* time_ctx) {
56 19 : if (!u || !v || !config || nx < 3 || ny < 3) {
57 : return CFD_ERROR_INVALID;
58 : }
59 16 : if (nz == 0 || nz == 2 || (nz > 1 && stride_z < nx * ny)) {
60 : return CFD_ERROR_INVALID;
61 : }
62 :
63 16 : if (!time_ctx) {
64 : /* If no time context provided, use time=0, dt=0 */
65 1 : bc_time_context_t default_ctx = {0.0, 0.0};
66 1 : return bc_apply_inlet_time_scalar_impl(u, v, w, nx, ny, nz, stride_z,
67 : config, &default_ctx);
68 : }
69 :
70 30 : if (!bc_inlet_is_valid_edge(config->edge)) {
71 : return CFD_ERROR_INVALID;
72 : }
73 :
74 15 : int edge_idx = bc_inlet_edge_to_index(config->edge);
75 15 : const bc_inlet_edge_loop_t* loop = &bc_inlet_edge_loops[edge_idx];
76 :
77 15 : if (loop->is_z_face) {
78 : /* Z-face inlet (FRONT or BACK): loop over the full xy-plane */
79 0 : if (nz <= 1 || !w) {
80 0 : return CFD_ERROR_INVALID;
81 : }
82 0 : size_t z_plane = (config->edge == BC_EDGE_FRONT)
83 0 : ? (nz - 1) * stride_z
84 0 : : 0;
85 0 : double w_val = bc_inlet_compute_w(config);
86 : /* Apply time modulation to w as well */
87 0 : double modulator = bc_time_get_modulator(&config->time_config,
88 0 : time_ctx->time, time_ctx->dt);
89 0 : w_val *= modulator;
90 :
91 : /* Velocity is uniform across the z-face — compute once. */
92 0 : double u_val, v_val;
93 0 : bc_inlet_compute_velocity_time(config, 0.5,
94 0 : time_ctx->time, time_ctx->dt,
95 : &u_val, &v_val);
96 :
97 0 : for (size_t j = 0; j < ny; j++) {
98 0 : for (size_t i = 0; i < nx; i++) {
99 0 : size_t idx = z_plane + IDX_2D(i, j, nx);
100 0 : u[idx] = u_val;
101 0 : v[idx] = v_val;
102 0 : w[idx] = w_val;
103 : }
104 : }
105 : } else {
106 : /* X/Y-face inlet: loop over each z-plane */
107 15 : size_t count = loop->use_ny_for_count ? ny : nx;
108 15 : double pos_denom = (count > 1) ? (double)(count - 1) : 1.0;
109 :
110 30 : for (size_t k = 0; k < nz; k++) {
111 15 : size_t base = k * stride_z;
112 255 : for (size_t i = 0; i < count; i++) {
113 240 : double position = (count > 1) ? (double)i / pos_denom : 0.5;
114 240 : double u_val, v_val;
115 240 : bc_inlet_compute_velocity_time(config, position,
116 240 : time_ctx->time, time_ctx->dt,
117 : &u_val, &v_val);
118 :
119 240 : size_t idx = base + loop->idx_fn(i, nx, ny);
120 240 : u[idx] = u_val;
121 240 : v[idx] = v_val;
122 240 : if (w) {
123 0 : w[idx] = 0.0;
124 : }
125 : }
126 : }
127 : }
128 :
129 : return CFD_SUCCESS;
130 : }
|