Skip to content

Commit e91aa2b

Browse files
committed
Canonicalize unified geometry IDs at input read; restore strict cylinder checks
The unified/legacy geometry IDs are now collapsed to one canonical ID per dimensionality (f_canonical_geometry) right after the case file is read, in both pre_process and simulation. This makes the unification hold across the whole pipeline (checks, ICPP application, IB markers, levelsets, moments of inertia) instead of only in the pre-process checkers, and extends it to the airfoil (4/11) and STL model (5/12) IB pairs from #1543. - Revert the m_icpp_patches dispatch changes: with canonical IDs the original dispatch is already correct, and the icpp 4/11 (line/plane sweep) merge was unreachable since the checkers still enforce their dimensionality. - Restore the cylinder strictness lost in the previous commit: geometry 10 requires exactly one positive length again (a cylinder with no or negative lengths is a hard error, not a silent sphere), keyed on the canonical ID. - Extend the toolchain bounding-box z-check to unified ID 3 and update the patch-type tables in the docs. - Add two golden tests: a 3D IB sphere and cylinder declared via unified geometry 2 (the sphere golden is bit-identical to the legacy geometry-8 sphere case).
1 parent 04555a4 commit e91aa2b

13 files changed

Lines changed: 493 additions & 84 deletions

File tree

docs/documentation/case.md

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1150,15 +1150,15 @@ This boundary condition can be used for subsonic inflow (`bc_[x,y,z]%[beg,end]`
11501150
| # | Name | Dim. | Smooth | Description |
11511151
| ---: | :----: | :---: | :---: | :--- |
11521152
| 1 | Line segment | 1 | N | Requires `x_centroid` and `length_x`. |
1153-
| 2 | Circle | 2 | Y | Requires `[x,y]_centroid` and `radius`. |
1154-
| 3 | Rectangle | 2 | N | Coordinate-aligned. Requires `[x,y]_centroid` and `length_[x,y]`. |
1153+
| 2 | Circle | 2 & 3 | Y | Requires `[x,y]_centroid` and `radius`. In 3D, equivalent to 10 (cylinder) if a `length_[x,y,z]` is set and to 8 (sphere) otherwise. |
1154+
| 3 | Rectangle | 2 & 3 | N | Coordinate-aligned. Requires `[x,y]_centroid` and `length_[x,y]`. In 3D, equivalent to 9 (cuboid). |
11551155
| 4 | Sweep line | 2 | Y | Not coordinate aligned. Requires `[x,y]_centroid` and `normal(i)`. |
11561156
| 5 | Ellipse | 2 | Y | Requires `[x,y]_centroid` and `radii(i)`. |
11571157
| 6 | N/A | N/A | N/A | No longer exists. Empty. |
11581158
| 7 | N/A | N/A | N/A | No longer exists. Empty. |
1159-
| 8 | Sphere | 3 | Y | Requires `[x,y,z]_centroid` and `radius` |
1160-
| 9 | Cuboid | 3 | N | Coordinate-aligned. Requires `[x,y,z]_centroid` and `length_[x,y,z]`. |
1161-
| 10 | Cylinder | 3 | Y | Requires `[x,y,z]_centroid`, `radius`, and `length_[x,y,z]`. |
1159+
| 8 | Sphere | 2 & 3 | Y | Requires `[x,y,z]_centroid` and `radius`. In 2D, equivalent to 2 (circle). |
1160+
| 9 | Cuboid | 2 & 3 | N | Coordinate-aligned. Requires `[x,y,z]_centroid` and `length_[x,y,z]`. In 2D, equivalent to 3 (rectangle). |
1161+
| 10 | Cylinder | 2 & 3 | Y | Requires `[x,y,z]_centroid`, `radius`, and exactly one of `length_[x,y,z]`. In 2D, equivalent to 2 (circle). |
11621162
| 11 | Sweep plane | 3 | Y | Not coordinate-aligned. Requires `x[y,z]_centroid` and `normal(i)`. |
11631163
| 12 | Ellipsoid | 3 | Y | Requires `[x,y,z]_centroid` and `radii(i)`. |
11641164
| 13 | 2D modal (Fourier) | 2 | Y | Requires `x_centroid`, `y_centroid`, `radius`. Optional: `fourier_cos(n)`, `fourier_sin(n)` (n=1..10), `modal_clip_r_to_min`, `modal_r_min`, `modal_use_exp_form`. |
@@ -1191,14 +1191,19 @@ Boundary is at polar angle \f$\theta = \mathrm{atan2}(y - y_{\mathrm{centroid}},
11911191

11921192
### Immersed Boundary Patch Types {#immersed-boundary-patch-types}
11931193

1194-
| # | Name | Dim. |
1195-
| ---: | :----: | :--- |
1196-
| 2 | 2D Circle | 2 |
1197-
| 3 | 2D Rectangle | 2 |
1198-
| 4 | 2D Airfoil | 2 |
1199-
| 8 | 3D Sphere | 3 |
1200-
| 10 | 3D Cylinder | 3 |
1201-
| 11 | 3D Airfoil | 3 |
1194+
| # | Name | Dim. |
1195+
| ---: | :----: | :--- |
1196+
| 2 | Circle / Sphere / Cylinder | 2 & 3 |
1197+
| 3 | Rectangle / Cuboid | 2 & 3 |
1198+
| 4 | Airfoil | 2 & 3 |
1199+
| 5 | Model (STL/OBJ) | 2 & 3 |
1200+
| 8 | 3D Sphere (alias of 2) | 3 |
1201+
| 9 | 3D Cuboid (alias of 3) | 3 |
1202+
| 10 | 3D Cylinder (alias of 2) | 3 |
1203+
| 11 | 3D Airfoil (alias of 4) | 3 |
1204+
| 12 | 3D Model (alias of 5) | 3 |
1205+
1206+
Geometry IDs are dimension-agnostic: in 3D, geometry 2 produces a cylinder when exactly one `length_[x,y,z]` is set and a sphere otherwise, and the legacy 3D-specific IDs (8-12) remain supported as aliases.
12021207

12031208
### Acoustic Supports {#acoustic-supports}
12041209

src/common/m_helper_basic.fpp

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ module m_helper_basic
1313
implicit none
1414

1515
private
16-
public :: f_approx_equal, f_approx_in_array, f_is_default, f_all_default, f_is_integer, s_configure_coordinate_bounds, &
17-
& s_update_cell_bounds
16+
public :: f_approx_equal, f_approx_in_array, f_is_default, f_all_default, f_is_integer, f_canonical_geometry, &
17+
& s_configure_coordinate_bounds, s_update_cell_bounds
1818

1919
contains
2020

@@ -98,6 +98,36 @@ contains
9898

9999
end function f_all_default
100100

101+
!> Maps the dimension-agnostic patch geometry IDs and their legacy 2D/3D counterparts to the canonical ID for the grid
102+
!! dimensionality, so all downstream dispatch (checks, patch application, IBM) sees one value.
103+
!! @param geometry geometry ID as read from the case file
104+
!! @param three_d true for 3D grids (p > 0)
105+
!! @param has_length true if any of the patch's length_[x,y,z] is set
106+
!! @param ib true for patch_ib IDs (also maps airfoils and models)
107+
integer elemental function f_canonical_geometry(geometry, three_d, has_length, ib) result(canon)
108+
109+
integer, intent(in) :: geometry
110+
logical, intent(in) :: three_d, has_length, ib
111+
112+
canon = geometry
113+
if (three_d) then
114+
select case (geometry)
115+
case (2); canon = merge(10, 8, has_length) ! circle -> cylinder if extruded, sphere otherwise
116+
case (3); canon = 9 ! rectangle -> cuboid
117+
case (4); if (ib) canon = 11 ! airfoil -> 3D airfoil
118+
case (5); if (ib) canon = 12 ! model -> 3D model
119+
end select
120+
else
121+
select case (geometry)
122+
case (8, 10); canon = 2 ! sphere/cylinder -> circle
123+
case (9); canon = 3 ! cuboid -> rectangle
124+
case (11); if (ib) canon = 4 ! 3D airfoil -> airfoil
125+
case (12); if (ib) canon = 5 ! 3D model -> model
126+
end select
127+
end if
128+
129+
end function f_canonical_geometry
130+
101131
!> Checks if a real(wp) variable is an integer.
102132
logical elemental function f_is_integer(var) result(res)
103133

src/pre_process/m_check_ib_patches.fpp

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -73,18 +73,23 @@ contains
7373
call s_int_to_str(patch_id, iStr)
7474

7575
@:PROHIBIT(n == 0 .or. patch_ib(patch_id)%radius <= 0._wp .or. f_is_default(patch_ib(patch_id)%x_centroid) &
76-
& .or. f_is_default(patch_ib(patch_id)%y_centroid), 'in circle/cylinder/sphere IB patch ' // trim(iStr))
77-
! Additional checks strictly for 3D shapes (Spheres and Cylinders)
76+
& .or. f_is_default(patch_ib(patch_id)%y_centroid), 'in circle/sphere/cylinder IB patch ' // trim(iStr))
77+
78+
! Spheres and cylinders (3D) additionally require a z-centroid
7879
if (p > 0) then
79-
! Both Spheres and Cylinder require Z centroid
80-
@:PROHIBIT(f_is_default(patch_ib(patch_id)%z_centroid), 'in 3D sphere/cylinder IB patch ' //trim(iStr))
81-
82-
! If any length is defined, it is a Cylinder. Ensure exactly ONE length is defined.
83-
if ((.not. f_is_default(patch_ib(patch_id)%length_x)) .or. (.not. f_is_default(patch_ib(patch_id)%length_y)) &
84-
& .or. (.not. f_is_default(patch_ib(patch_id)%length_z))) then
85-
@:PROHIBIT(count([patch_ib(patch_id)%length_x > 0._wp, patch_ib(patch_id)%length_y > 0._wp, &
86-
& patch_ib(patch_id)%length_z > 0._wp]) /= 1, 'in cylinder IB patch ' // trim(iStr))
87-
end if
80+
@:PROHIBIT(f_is_default(patch_ib(patch_id)%z_centroid), 'in 3D sphere/cylinder IB patch ' // trim(iStr))
81+
end if
82+
83+
! Cylinders are extruded along exactly one positive length
84+
if (patch_ib(patch_id)%geometry == 10) then
85+
@:PROHIBIT(count([patch_ib(patch_id)%length_x > 0._wp, patch_ib(patch_id)%length_y > 0._wp, &
86+
& patch_ib(patch_id)%length_z > 0._wp]) /= 1, &
87+
& 'in cylinder IB patch ' // trim(iStr) &
88+
& // ': exactly one of length_x, length_y, or length_z must be defined and positive')
89+
@:PROHIBIT((.not. f_is_default(patch_ib(patch_id)%length_x) .and. patch_ib(patch_id)%length_x <= 0._wp) &
90+
& .or. (.not. f_is_default(patch_ib(patch_id)%length_y) .and. patch_ib(patch_id)%length_y <= 0._wp) &
91+
& .or. (.not. f_is_default(patch_ib(patch_id)%length_z) .and. patch_ib(patch_id)%length_z <= 0._wp), &
92+
& 'in cylinder IB patch ' // trim(iStr) // ': the defined lengths must be greater than zero')
8893
end if
8994

9095
end subroutine s_check_circle_ib_patch_geometry
@@ -125,8 +130,6 @@ contains
125130

126131
end subroutine s_check_airfoil_ib_patch_geometry
127132

128-
!> Verify that the geometric parameters of the 3D airfoil patch have been consistently inputted.
129-
130133
!> Verify that the geometric parameters of the rectangle patch have been consistently inputted.
131134

132135
impure subroutine s_check_rectangle_ib_patch_geometry(patch_id)

src/pre_process/m_check_patches.fpp

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -142,29 +142,30 @@ contains
142142
call s_int_to_str(patch_id, iStr)
143143

144144
! Core checks for all (Circle, Sphere, Cylinder)
145-
@:PROHIBIT(n == 0, "Circle patch "//trim(iStr)//": n must be greater than zero")
145+
@:PROHIBIT(n == 0, "Circle/Sphere/Cylinder patch "//trim(iStr)//": n must be greater than zero")
146146
@:PROHIBIT(f_is_default(patch_icpp(patch_id)%x_centroid), &
147147
& "Circle/Sphere/Cylinder patch "//trim(iStr)//": x_centroid must be set")
148148
@:PROHIBIT(f_is_default(patch_icpp(patch_id)%y_centroid), &
149149
& "Circle/Sphere/Cylinder patch "//trim(iStr)//": y_centroid must be set")
150150
@:PROHIBIT(patch_icpp(patch_id)%radius <= 0._wp, &
151151
& "Circle/Sphere/Cylinder patch "//trim(iStr)//": radius must be greater than zero")
152152

153-
! 3D-specific checks (Spheres and Cylinders)
153+
! Spheres and cylinders (3D) additionally require a z-centroid
154154
if (p > 0) then
155155
@:PROHIBIT(f_is_default(patch_icpp(patch_id)%z_centroid), &
156156
& "3D Sphere/Cylinder patch "//trim(iStr)//": z_centroid must be set")
157+
end if
157158

158-
! If any extrusion length is set, it's a Cylinder. Verify exactly ONE length axis is defined.
159-
if (patch_icpp(patch_id)%length_x > 0._wp .or. patch_icpp(patch_id)%length_y > 0._wp &
160-
& .or. patch_icpp(patch_id)%length_z > 0._wp) then
161-
@:PROHIBIT((patch_icpp(patch_id)%length_x > 0._wp .and. ((.not. f_is_default(patch_icpp(patch_id)%length_y)) &
162-
& .or. (.not. f_is_default(patch_icpp(patch_id)%length_z)))) &
163-
& .or. (patch_icpp(patch_id)%length_y > 0._wp .and. ((.not. f_is_default(patch_icpp(patch_id)%length_x) &
164-
& ) .or. (.not. f_is_default(patch_icpp(patch_id)%length_z)))) &
165-
& .or. (patch_icpp(patch_id)%length_z > 0._wp .and. ((.not. f_is_default(patch_icpp(patch_id)%length_x) &
166-
& ) .or. (.not. f_is_default(patch_icpp(patch_id)%length_y)))), 'in cylinder patch ' // trim(iStr))
167-
end if
159+
! Cylinders are extruded along exactly one positive length
160+
if (patch_icpp(patch_id)%geometry == 10) then
161+
@:PROHIBIT(count([patch_icpp(patch_id)%length_x > 0._wp, patch_icpp(patch_id)%length_y > 0._wp, &
162+
& patch_icpp(patch_id)%length_z > 0._wp]) /= 1, &
163+
& "Cylinder patch " // trim(iStr) &
164+
& // ": Exactly one of length_x, length_y, or length_z must be defined and positive")
165+
@:PROHIBIT((.not. f_is_default(patch_icpp(patch_id)%length_x) .and. patch_icpp(patch_id)%length_x <= 0._wp) &
166+
& .or. (.not. f_is_default(patch_icpp(patch_id)%length_y) .and. patch_icpp(patch_id)%length_y <= 0._wp) &
167+
& .or. (.not. f_is_default(patch_icpp(patch_id)%length_z) .and. patch_icpp(patch_id)%length_z <= 0._wp), &
168+
& "Cylinder patch " // trim(iStr) // ": The defined length_{} must be greater than zero")
168169
end if
169170

170171
end subroutine s_check_circle_patch_geometry

src/pre_process/m_icpp_patches.fpp

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -60,19 +60,17 @@ contains
6060

6161
!> ICPP Patches
6262
!> @{
63-
! Spherical / Cylindrical patch (Unified IDs 2, 8, 10)
64-
if (patch_icpp(i)%geometry == 2 .or. patch_icpp(i)%geometry == 8 .or. patch_icpp(i)%geometry == 10) then
65-
! If any extrusion length is set, it is a cylinder. Otherwise, it is a sphere.
66-
if (patch_icpp(i)%length_x > 0._wp .or. patch_icpp(i)%length_y > 0._wp .or. patch_icpp(i)%length_z > 0._wp) then
67-
call s_icpp_cylinder(i, patch_id_fp, q_prim_vf)
68-
else
69-
call s_icpp_sphere(i, patch_id_fp, q_prim_vf)
70-
end if
71-
! Cuboidal patch (Unified IDs 3, 9)
72-
else if (patch_icpp(i)%geometry == 3 .or. patch_icpp(i)%geometry == 9) then
63+
! Spherical patch
64+
if (patch_icpp(i)%geometry == 8) then
65+
call s_icpp_sphere(i, patch_id_fp, q_prim_vf)
66+
! Cuboidal patch
67+
else if (patch_icpp(i)%geometry == 9) then
7368
call s_icpp_cuboid(i, patch_id_fp, q_prim_vf)
74-
! Swept plane patch (Unified IDs 4, 11)
75-
else if (patch_icpp(i)%geometry == 4 .or. patch_icpp(i)%geometry == 11) then
69+
! Cylindrical patch
70+
else if (patch_icpp(i)%geometry == 10) then
71+
call s_icpp_cylinder(i, patch_id_fp, q_prim_vf)
72+
! Swept plane patch
73+
else if (patch_icpp(i)%geometry == 11) then
7674
call s_icpp_sweep_plane(i, patch_id_fp, q_prim_vf)
7775
! Ellipsoidal patch
7876
else if (patch_icpp(i)%geometry == 12) then
@@ -99,14 +97,14 @@ contains
9997

10098
!> ICPP Patches
10199
!> @{
102-
! Circular patch (Unified IDs 2, 8, 10)
103-
if (patch_icpp(i)%geometry == 2 .or. patch_icpp(i)%geometry == 8 .or. patch_icpp(i)%geometry == 10) then
100+
! Circular patch
101+
if (patch_icpp(i)%geometry == 2) then
104102
call s_icpp_circle(i, patch_id_fp, q_prim_vf)
105-
! Rectangular patch (Unified IDs 3, 9)
106-
else if (patch_icpp(i)%geometry == 3 .or. patch_icpp(i)%geometry == 9) then
103+
! Rectangular patch
104+
else if (patch_icpp(i)%geometry == 3) then
107105
call s_icpp_rectangle(i, patch_id_fp, q_prim_vf)
108-
! Swept line patch (Unified IDs 4, 11)
109-
else if (patch_icpp(i)%geometry == 4 .or. patch_icpp(i)%geometry == 11) then
106+
! Swept line patch
107+
else if (patch_icpp(i)%geometry == 4) then
110108
call s_icpp_sweep_line(i, patch_id_fp, q_prim_vf)
111109
! Elliptical patch
112110
else if (patch_icpp(i)%geometry == 5) then

src/pre_process/m_start_up.fpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ contains
7171

7272
character(LEN=name_len) :: file_loc
7373
logical :: file_check
74-
integer :: iostatus
74+
integer :: iostatus, i
7575
character(len=1000) :: line
7676

7777
#:include 'generated_namelist.fpp'
@@ -90,6 +90,17 @@ contains
9090
end if
9191
close (1)
9292

93+
! Collapse the dimension-agnostic / legacy patch geometry IDs to
94+
! the canonical ID for this dimensionality (see f_canonical_geometry)
95+
do i = 1, num_patches_max
96+
patch_icpp(i)%geometry = f_canonical_geometry(patch_icpp(i)%geometry, p > 0, &
97+
& .not. f_all_default([patch_icpp(i)%length_x, patch_icpp(i)%length_y, patch_icpp(i)%length_z]), .false.)
98+
end do
99+
do i = 1, min(num_ibs, size(patch_ib))
100+
patch_ib(i)%geometry = f_canonical_geometry(patch_ib(i)%geometry, p > 0, &
101+
& .not. f_all_default([patch_ib(i)%length_x, patch_ib(i)%length_y, patch_ib(i)%length_z]), .true.)
102+
end do
103+
93104
call s_update_cell_bounds(cells_bounds, m, n, p)
94105

95106
m_glb = m

src/simulation/m_start_up.fpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ contains
8181

8282
character(LEN=name_len), parameter :: file_path = './simulation.inp'
8383
logical :: file_exist !< Logical used to check the existence of the input file
84-
integer :: iostatus
84+
integer :: iostatus, i
8585
! Integer to check iostat of file read
8686

8787
character(len=1000) :: line
@@ -103,6 +103,13 @@ contains
103103

104104
close (1)
105105

106+
! Collapse the dimension-agnostic / legacy patch geometry IDs to
107+
! the canonical ID for this dimensionality (see f_canonical_geometry)
108+
do i = 1, min(num_ibs, size(patch_ib))
109+
patch_ib(i)%geometry = f_canonical_geometry(patch_ib(i)%geometry, p > 0, &
110+
& .not. f_all_default([patch_ib(i)%length_x, patch_ib(i)%length_y, patch_ib(i)%length_z]), .true.)
111+
end do
112+
106113
if ((bf_x) .or. (bf_y) .or. (bf_z)) then
107114
bodyForces = .true.
108115
end if

0 commit comments

Comments
 (0)