MPI-AMRVAC 3.2
The MPI - Adaptive Mesh Refinement - Versatile Advection Code (development version)
Loading...
Searching...
No Matches
mod_wb_atmosphere.t
Go to the documentation of this file.
1!> Well-balanced atmosphere module.
2!>
3!> Builds grid-aligned hydrostatic equilibrium tables at the finest AMR
4!> resolution from a user-provided fine 1D reference profile. Provides
5!> routines for setting the initial condition and boundary conditions
6!> from these tables.
7!>
8!> The module is EoS-independent: it receives p(s) and rho(s) and never
9!> calls EoS routines. The multiplicative HSE recurrence uses T = p/rho
10!> which is valid for any equation of state.
11!>
12!> Usage:
13!> 1. User integrates HSE to produce fine pa(:), ra(:) arrays
14!> 2. call wb_atmos_init(pa, ra, grav, jmax, ds, gzone, grav_dir)
15!> 3. call wb_atmos_set_w(ixI^L, ixO^L, w, x) in IC and BC routines
16!> 4. call phys_to_conserved(...) after set_w (user's responsibility)
19 use mod_comm_lib, only: mpistop
20
21 implicit none
22 private
23
24 !> Variable indices for density and pressure — set during wb_atmos_init
25 !> to avoid depending on a specific physics module.
26 integer :: wb_iw_rho = -1
27 integer :: wb_iw_p = -1
28
29 !> Grid-aligned discrete HSE (built at finest AMR resolution)
30 double precision, allocatable, public :: wb_pa(:) !< equilibrium pressure
31 double precision, allocatable, public :: wb_ra(:) !< equilibrium density
32 integer, public :: wb_n_grid = 0 !< table size
33
34 !> Grid parameters
35 integer :: wb_grav_dir = 1 !< gravity direction (1, 2, or 3)
36 double precision :: wb_dx_grid !< cell spacing at Lmax
37 double precision :: wb_x_lo !< coordinate of first cell centre
38 integer :: wb_n_ghost !< ghost cells at Lmax resolution
39 logical :: wb_initialised = .false.
40
41 public :: wb_atmos_init
42 public :: wb_atmos_set_w
43 public :: wb_atmos_get_eq
44
45contains
46
47 !> Build grid-aligned HSE tables from a fine 1D reference profile.
48 !>
49 !> The fine table (pa, ra) spans [xmin - gzone, xmax + gzone] along the
50 !> gravity direction, evenly spaced at ds. The gravity array grav(jmax)
51 !> gives the gravitational acceleration at each fine table point.
52 !>
53 !> The grid-aligned table is built at the finest AMR resolution using the
54 !> multiplicative trapezoidal recurrence, which matches the discrete HSE
55 !> that the WB reconstruction preserves.
56 subroutine wb_atmos_init(pa, ra, grav, jmax, ds, gzone, grav_dir, irho, ip)
57 double precision, intent(in) :: pa(:) !< fine pressure table
58 double precision, intent(in) :: ra(:) !< fine density table
59 double precision, intent(in) :: grav(:) !< fine gravity table
60 integer, intent(in) :: jmax !< fine table size
61 double precision, intent(in) :: ds !< fine table spacing
62 double precision, intent(in) :: gzone !< ghost zone width (code units)
63 integer, intent(in) :: grav_dir !< gravity direction (1, 2, or 3)
64 integer, intent(in) :: irho !< w-array index for density
65 integer, intent(in) :: ip !< w-array index for pressure
66
67 double precision :: x_g, t_lo, t_hi, g_lo, g_hi, res
68 double precision :: alpha_prev, alpha_curr
69 double precision :: x_min, x_max, p_dev, max_dev
70 integer :: ig, na, n_cells, level_factor
71
72 wb_grav_dir = grav_dir
73 wb_iw_rho = irho
74 wb_iw_p = ip
75
76 ! Grid parameters at finest AMR level
77 level_factor = 2**(refine_max_level - 1)
78 select case(grav_dir)
79 case(1)
80 n_cells = domain_nx1 * level_factor
81 x_min = xprobmin1; x_max = xprobmax1
82 {^iftwod
83 case(2)
84 n_cells = domain_nx2 * level_factor
85 x_min = xprobmin2; x_max = xprobmax2
86 }
87 {^ifthreed
88 case(2)
89 n_cells = domain_nx2 * level_factor
90 x_min = xprobmin2; x_max = xprobmax2
91 case(3)
92 n_cells = domain_nx3 * level_factor
93 x_min = xprobmin3; x_max = xprobmax3
94 }
95 case default
96 call mpistop('wb_atmos_init: invalid grav_dir')
97 end select
98
99 wb_n_ghost = nghostcells * level_factor
100 wb_n_grid = n_cells + 2 * wb_n_ghost
101 wb_dx_grid = (x_max - x_min) / dble(n_cells)
102 wb_x_lo = x_min - (dble(wb_n_ghost) - 0.5d0) * wb_dx_grid
103
104 allocate(wb_pa(wb_n_grid), wb_ra(wb_n_grid))
105
106 ! Interpolate T = p/rho and g from fine table at each grid cell centre,
107 ! then build grid-aligned table via multiplicative HSE recurrence.
108 !
109 ! Seed the first cell: interpolate p and T from fine table.
110 x_g = wb_x_lo
111 call interp_fine(x_g, x_min, gzone, ds, jmax, pa, ra, grav, t_lo, g_lo)
112 ! Use same indexing for seed pressure
113 na = floor((x_g - (x_min - gzone)) / ds + 0.5d0)
114 na = max(1, min(na, jmax - 1))
115 res = (x_g - (x_min - gzone)) / ds - (dble(na) - 0.5d0)
116 res = max(0.0d0, min(1.0d0, res))
117 wb_pa(1) = pa(na) + res * (pa(na + 1) - pa(na))
118 wb_ra(1) = wb_pa(1) / t_lo
119
120 ! Forward recurrence
121 do ig = 2, wb_n_grid
122 x_g = wb_x_lo + dble(ig - 1) * wb_dx_grid
123 call interp_fine(x_g, x_min, gzone, ds, jmax, pa, ra, grav, t_hi, g_hi)
124
125 alpha_prev = 0.5d0 * wb_dx_grid * g_lo / t_lo
126 alpha_curr = 0.5d0 * wb_dx_grid * g_hi / t_hi
127
128 wb_pa(ig) = wb_pa(ig - 1) * (1.0d0 + alpha_prev) &
129 / (1.0d0 - alpha_curr)
130 wb_ra(ig) = wb_pa(ig) / t_hi
131
132 t_lo = t_hi
133 g_lo = g_hi
134 end do
135
136 ! Diagnostic: max deviation from fine table
137 max_dev = 0.0d0
138 do ig = 1, wb_n_grid
139 x_g = wb_x_lo + dble(ig - 1) * wb_dx_grid
140 na = max(1, min(nint((x_g - (x_min - gzone))/ds) + 1, jmax))
141 if (pa(na) > 0.0d0) then
142 p_dev = dabs(wb_pa(ig) - pa(na)) / pa(na)
143 max_dev = max(max_dev, p_dev)
144 end if
145 end do
146
147 if (mype == 0) then
148 write(*,'(A,I7,A,ES10.3,A,I1)') &
149 ' WB atmosphere: ', wb_n_grid, ' cells, max p deviation = ', &
150 max_dev, ', grav_dir = ', wb_grav_dir
151 end if
152
153 wb_initialised = .true.
154
155 end subroutine wb_atmos_init
156
157 !> Set w to the equilibrium state (rho, v=0, p) at each cell position.
158 !>
159 !> Point-value sample of the trap-rule-built grid table at cell centres.
160 !> Consistent with the legacy_trap WB transform which expects point-value
161 !> IC matching its own trap-rule recurrence at L_max.
162 !>
163 !> On exit: w(rho_) = rho_eq, w(mom(:)) = 0, w(p_) = p_eq.
164 !> The caller must call phys_to_conserved afterwards.
165 subroutine wb_atmos_set_w(ixI^L, ixO^L, w, x)
166 integer, intent(in) :: ixi^l, ixo^l
167 double precision, intent(inout) :: w(ixi^s, 1:nw)
168 double precision, intent(in) :: x(ixi^s, 1:ndim)
169
170 double precision :: s
171 integer :: ig
172 integer :: ix^d
173
174 if (.not. wb_initialised) &
175 call mpistop('wb_atmos_set_w: call wb_atmos_init first')
176
177 ! Zero all conserved/primitive variables first
178 w(ixo^s, 1:nw) = 0.0d0
179
180 ! Set density and pressure from the equilibrium table
181 {do ix^db = ixomin^db, ixomax^db\}
182 s = x(ix^d, wb_grav_dir)
183 ig = nint((s - wb_x_lo) / wb_dx_grid) + 1
184 ig = max(1, min(ig, wb_n_grid))
185
186 w(ix^d, wb_iw_rho) = wb_ra(ig)
187 w(ix^d, wb_iw_p) = wb_pa(ig)
188 {end do\}
189
190 end subroutine wb_atmos_set_w
191
192 !> Look up equilibrium (rho, p) at an arbitrary coordinate along the
193 !> gravity direction. Uses nearest-cell lookup from the grid-aligned table.
194 subroutine wb_atmos_get_eq(x_grav, rho_eq, p_eq)
195 double precision, intent(in) :: x_grav
196 double precision, intent(out) :: rho_eq, p_eq
197
198 integer :: ig
199
200 if (.not. wb_initialised) &
201 call mpistop('wb_atmos_get_eq: call wb_atmos_init first')
202
203 ig = nint((x_grav - wb_x_lo) / wb_dx_grid) + 1
204 ig = max(1, min(ig, wb_n_grid))
205
206 rho_eq = wb_ra(ig)
207 p_eq = wb_pa(ig)
208
209 end subroutine wb_atmos_get_eq
210
211 ! ── Private helpers ──────────────────────────────────────────────
212
213 !> Interpolate T = p/rho and g from the fine table at position x_g.
214 subroutine interp_fine(x_g, x_min, gzone, ds, jmax, pa, ra, grav, T_out, g_out)
215 double precision, intent(in) :: x_g, x_min, gzone, ds
216 integer, intent(in) :: jmax
217 double precision, intent(in) :: pa(:), ra(:), grav(:)
218 double precision, intent(out) :: t_out, g_out
219
220 integer :: na
221 double precision :: frac
222
223 ! Cell-centred indexing matching inithdstatic convention:
224 ! na = floor((x + gzone)/ds + 0.5), res = remainder within cell
225 na = floor((x_g - (x_min - gzone)) / ds + 0.5d0)
226 na = max(1, min(na, jmax - 1))
227 frac = (x_g - (x_min - gzone)) / ds - (dble(na) - 0.5d0)
228 frac = frac / 1.0d0 ! already normalised to ds
229 frac = max(0.0d0, min(1.0d0, frac))
230
231 ! Interpolate T = p/rho ratio directly (NOT p and rho separately).
232 t_out = pa(na)/ra(na) + frac * (pa(na+1)/ra(na+1) - pa(na)/ra(na))
233
234 g_out = grav(na) + frac * (grav(na + 1) - grav(na))
235
236 end subroutine interp_fine
237
238end module mod_wb_atmosphere
subroutine, public mpistop(message)
Exit MPI-AMRVAC with an error message.
This module contains definitions of global parameters and variables and some generic functions/subrou...
integer, parameter ndim
Number of spatial dimensions for grid variables.
integer mype
The rank of the current MPI task.
double precision, dimension(:), allocatable, parameter d
integer nghostcells
Number of ghost cells surrounding a grid.
integer refine_max_level
Maximal number of AMR levels.
Well-balanced atmosphere module.
integer, public wb_n_grid
table size
double precision, dimension(:), allocatable, public wb_ra
equilibrium density
double precision, dimension(:), allocatable, public wb_pa
Grid-aligned discrete HSE (built at finest AMR resolution)
subroutine, public wb_atmos_set_w(ixil, ixol, w, x)
Set w to the equilibrium state (rho, v=0, p) at each cell position.
subroutine, public wb_atmos_init(pa, ra, grav, jmax, ds, gzone, grav_dir, irho, ip)
Build grid-aligned HSE tables from a fine 1D reference profile.
subroutine, public wb_atmos_get_eq(x_grav, rho_eq, p_eq)
Look up equilibrium (rho, p) at an arbitrary coordinate along the gravity direction....