Skip to content

Commit 7569479

Browse files
committed
refactor numerical_flux.py
reworked numerical_flux.recompute_advective_fluxes function too; all tests passed.
1 parent cfcc62c commit 7569479

File tree

4 files changed

+110
-87
lines changed

4 files changed

+110
-87
lines changed

src/pybella/flow_solver/physics/gas_dynamics/explicit.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ def _compute_flux_and_recovery(mem, ud, lmbda, split_step, tag=None):
100100

101101
Lefts, Rights = gd_recovery.do(mem, ud, lmbda, split_step, tag)
102102

103-
flux = gd_flux.hll_solver(flux, Lefts, Rights, mem.sol, lmbda, ud, mem.th)
103+
flux = gd_flux.hll_solver(mem, flux, Lefts, Rights)
104104

105105
return flux
106106

Lines changed: 58 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,104 +1,85 @@
11
# -*- coding: utf-8 -*-
22
import numpy as np
33

4-
from ....utils.operators import create_convolution_kernels, apply_convolution_kernel, apply_u_kernel_convolution, apply_v_kernel_convolution_3d
5-
from ....utils.slices import get_inner_slice
4+
from ....utils.operators import create_convolution_kernels, apply_directional_convolution
5+
from ....utils.slices import get_inner_slice, get_interface_indices, get_last_dim_inner_slice
66

77
def recompute_advective_fluxes(flux, Sol, **kwargs):
8-
"""Recompute the advective fluxes at the cell interfaces."""
8+
"""Recompute the advective fluxes at the cell interfaces.
9+
10+
Parameters
11+
----------
12+
flux : list
13+
List of flux objects for each direction
14+
Sol : object
15+
Solution object containing rho, rhoY, rhou, rhov, rhow fields
16+
**kwargs
17+
Optional pre-computed velocity components ('u', 'v', 'w')
18+
"""
919
ndim = Sol.rho.ndim
1020
inner_idx = get_inner_slice(ndim)
1121
kernels = create_convolution_kernels(ndim)
1222

13-
# Handle 3D w-component first
14-
if ndim == 3:
15-
rhoYw = Sol.rhoY * Sol.rhow / Sol.rho
16-
flux[2].rhoY[inner_idx] = apply_convolution_kernel(rhoYw, kernels['w'])
23+
# Define the component order and corresponding flux indices
24+
components = ['u', 'v'] if ndim == 2 else ['u', 'v', 'w']
25+
rho_components = ['rhou', 'rhov'] if ndim == 2 else ['rhou', 'rhov', 'rhow']
1726

18-
# u-component (all dimensions)
19-
rhoYu = kwargs.get("u", Sol.rhoY * Sol.rhou / Sol.rho)
20-
flux[0].rhoY[inner_idx] = apply_u_kernel_convolution(rhoYu, kernels['u'])
21-
22-
# v-component (all dimensions)
23-
rhoYv = kwargs.get("v", Sol.rhoY * Sol.rhov / Sol.rho)
24-
if ndim == 2:
25-
flux[1].rhoY[inner_idx] = apply_convolution_kernel(rhoYv, kernels['v'])
26-
elif ndim == 3:
27-
flux[1].rhoY[inner_idx] = apply_v_kernel_convolution_3d(rhoYv, kernels['v'])
28-
27+
for i, (comp, rho_comp) in enumerate(zip(components, rho_components)):
28+
# Use provided velocity or compute from momentum
29+
if comp in kwargs:
30+
rhoY_vel = kwargs[comp]
31+
else:
32+
momentum = getattr(Sol, rho_comp)
33+
rhoY_vel = Sol.rhoY * momentum / Sol.rho
34+
35+
# Apply directional convolution
36+
flux[i].rhoY[inner_idx] = apply_directional_convolution(
37+
rhoY_vel, kernels[comp], comp, ndim
38+
)
2939

30-
def hll_solver(flux, Lefts, Rights, Sol, lmbda, ud, th):
40+
def hll_solver(mem, flux, Lefts, Rights):
3141
"""
3242
HLL solver for the Riemann problem. Chooses the advected quantities from `Lefts` or `Rights` based on the direction given by `flux`.
3343
34-
Parameters
35-
----------
36-
flux : :py:class:`management.variable.States`
37-
Data container for fluxes.
38-
Lefts : :py:class:`management.variable.States`
39-
Container for the quantities on the left of the cell interfaces.
40-
Rights : :py:class:`management.variable.States`
41-
Container for the quantities on the right of the cell interfaces.
42-
Sol : :py:class:`management.variable.Vars`
43-
Solution data container.
44-
lmbda : float
45-
:math:`\\frac{dt}{dx}`, where :math:`dx` is the grid-size in the direction of the substep.
46-
ud : :py:class:`inputs.user_data.UserDataInit`
47-
Class container for the initial condition.
48-
th : :py:class:`physics.gas_dynamics.thermodynamic.init`
49-
Class container for the thermodynamical constants.
50-
5144
Returns
5245
-------
5346
:py:class:`management.variable.States`
5447
`flux` data container with the solution of the Riemann problem.
48+
5549
"""
56-
# flux: index 1 to end = Left[inner_idx]: index 0 to -1 = Right[inner_idx]: index 1 to end
50+
def _compute_flux_component(flux_attr, state_attr=None, state_value=1.0):
51+
"""Helper function to compute a single flux component."""
52+
left_weight = upl[left_idx] / Lefts.Y[left_idx]
53+
right_weight = upr[right_idx] / Rights.Y[right_idx]
54+
55+
if state_attr is not None:
56+
left_val = getattr(Lefts, state_attr)[left_idx]
57+
right_val = getattr(Rights, state_attr)[right_idx]
58+
else:
59+
left_val = right_val = state_value
60+
61+
getattr(flux, flux_attr)[remove_cols_idx] = flux.rhoY[remove_cols_idx] * (
62+
left_weight * left_val + right_weight * right_val
63+
)
5764

58-
ndim = Sol.rho.ndim
59-
left_idx, right_idx, remove_cols_idx = (
60-
[slice(None)] * ndim,
61-
[slice(None)] * ndim,
62-
[slice(None)] * ndim,
63-
)
65+
ndim = mem.sol.rho.ndim
66+
left_idx, right_idx, _ = get_interface_indices(ndim)
67+
remove_cols_idx = get_last_dim_inner_slice(ndim)
6468

65-
remove_cols_idx[-1] = slice(1, -1)
66-
left_idx[-1] = slice(0, -1)
67-
right_idx[-1] = slice(1, None)
68-
69-
left_idx, right_idx, remove_cols_idx = (
70-
tuple(left_idx),
71-
tuple(right_idx),
72-
tuple(remove_cols_idx),
73-
)
74-
75-
Lefts.primitives(th)
76-
Rights.primitives(th)
69+
# Compute primitive variables
70+
Lefts.primitives(mem.th)
71+
Rights.primitives(mem.th)
7772

73+
# Compute upwind weights
7874
upwind = 0.5 * (1.0 + np.sign(flux.rhoY))
7975
upl = upwind[right_idx]
8076
upr = 1.0 - upwind[left_idx]
8177

82-
flux.rhou[remove_cols_idx] = flux.rhoY[remove_cols_idx] * (
83-
upl[left_idx] / Lefts.Y[left_idx] * Lefts.u[left_idx]
84-
+ upr[right_idx] / Rights.Y[right_idx] * Rights.u[right_idx]
85-
)
86-
flux.rho[remove_cols_idx] = flux.rhoY[remove_cols_idx] * (
87-
upl[left_idx] / Lefts.Y[left_idx] * 1.0
88-
+ upr[right_idx] / Rights.Y[right_idx] * 1.0
89-
)
90-
91-
flux.rhov[remove_cols_idx] = flux.rhoY[remove_cols_idx] * (
92-
upl[left_idx] / Lefts.Y[left_idx] * Lefts.v[left_idx]
93-
+ upr[right_idx] / Rights.Y[right_idx] * Rights.v[right_idx]
94-
)
95-
flux.rhow[remove_cols_idx] = flux.rhoY[remove_cols_idx] * (
96-
upl[left_idx] / Lefts.Y[left_idx] * Lefts.w[left_idx]
97-
+ upr[right_idx] / Rights.Y[right_idx] * Rights.w[right_idx]
98-
)
99-
flux.rhoX[remove_cols_idx] = flux.rhoY[remove_cols_idx] * (
100-
upl[left_idx] / Lefts.Y[left_idx] * Lefts.X[left_idx]
101-
+ upr[right_idx] / Rights.Y[right_idx] * Rights.X[right_idx]
102-
)
78+
# Compute all flux components
79+
_compute_flux_component('rhou', 'u')
80+
_compute_flux_component('rho') # Uses default state_value=1.0
81+
_compute_flux_component('rhov', 'v')
82+
_compute_flux_component('rhow', 'w')
83+
_compute_flux_component('rhoX', 'X')
10384

104-
return flux
85+
return flux

src/pybella/utils/operators.py

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
from numba import njit
44
from functools import lru_cache
55

6-
76
@lru_cache(maxsize=2)
87
def create_convolution_kernels(ndim):
98
"""Create convolution kernels for advective flux computation.
@@ -127,12 +126,49 @@ def apply_convolution_kernel(data, kernel, normalize=True, axis_swap=None, use_n
127126
return result
128127

129128

130-
# Convenience functions for specific operations
131-
def apply_u_kernel_convolution(data, kernel_u, normalize=True):
132-
"""Apply u-direction kernel with standard axis swap."""
133-
return apply_convolution_kernel(data, kernel_u, normalize=normalize, axis_swap=(0, -1))
134-
129+
# Configuration for directional convolutions
130+
DIRECTION_CONFIG = {
131+
2: {
132+
'u': {'axis_swap': (0, -1)},
133+
'v': {'axis_swap': None}
134+
},
135+
3: {
136+
'u': {'axis_swap': (0, -1)},
137+
'v': {'axis_swap': (-1, 0)},
138+
'w': {'axis_swap': None}
139+
}
140+
}
135141

136-
def apply_v_kernel_convolution_3d(data, kernel_v, normalize=True):
137-
"""Apply v-direction kernel for 3D with standard axis swap."""
138-
return apply_convolution_kernel(data, kernel_v, normalize=normalize, axis_swap=(-1, 0))
142+
def apply_directional_convolution(data, kernel, direction, ndim, normalize=True, use_numba=True):
143+
"""Apply convolution kernel for a specific direction with appropriate axis swapping.
144+
145+
Parameters
146+
----------
147+
data : np.ndarray
148+
Input data array
149+
kernel : np.ndarray
150+
Convolution kernel for the direction
151+
direction : str
152+
Direction ('u', 'v', or 'w')
153+
ndim : int
154+
Number of dimensions (2 or 3)
155+
normalize : bool, default=True
156+
Whether to normalize by kernel sum
157+
use_numba : bool, default=True
158+
Whether to use Numba-compiled convolution
159+
160+
Returns
161+
-------
162+
np.ndarray
163+
Convolved result with appropriate axis swapping
164+
"""
165+
if direction not in DIRECTION_CONFIG[ndim]:
166+
raise ValueError(f"Direction '{direction}' not supported for {ndim}D")
167+
168+
config = DIRECTION_CONFIG[ndim][direction]
169+
return apply_convolution_kernel(
170+
data, kernel,
171+
normalize=normalize,
172+
axis_swap=config['axis_swap'],
173+
use_numba=use_numba
174+
)

src/pybella/utils/slices.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ def get_inner_slice(ndim):
1414
"""Get slice tuple for inner cells (excluding outermost ghost cells)."""
1515
return tuple([slice(1, -1)] * ndim)
1616

17+
def get_last_dim_inner_slice(ndim):
18+
"""Get slice for inner faces in the last dimension only."""
19+
idx = [slice(None)] * ndim
20+
idx[-1] = slice(1, -1)
21+
return tuple(idx)
22+
1723

1824
def get_interface_indices(ndim):
1925
"""

0 commit comments

Comments
 (0)