Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revamped seat placement in cabin #59

Merged
merged 6 commits into from
Jun 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions example/cryo_input.toml
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ name = "TASOPT Model with cryo fuel and HX"
calculate_cabin_length = true

double_decker = false #if true, the fuselage has two passenger decks
floor_distance = "0 in" #Vertical distance between floors if double decker
seat_pitch = "30 in"
seat_width = "19 in"
aisle_halfwidth = "10 in"
Expand Down
1 change: 1 addition & 0 deletions src/IO/default_input.toml
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@
calculate_cabin_length = false

double_decker = false #if true, the fuselage has two passenger decks
floor_distance = "0 in" #Vertical distance between floors if double decker
seat_pitch = "30 in"
seat_width = "19 in"
aisle_halfwidth = "10 in"
Expand Down
23 changes: 9 additions & 14 deletions src/IO/outputs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -449,12 +449,13 @@ function stickfig(ac::aircraft; ax = nothing, label_fs = 16)

pax = parg[igWpay]/parm[imWperpax]

_, xseats, seats_per_row = place_cabin_seats(pax, parg[igRfuse])
wcabin = find_cabin_width(parg[igRfuse], parg[igdRfuse], parg[igwfb], parg[ignfweb], parg[igfloordist]) #Find cabin width
_, xseats, seats_per_row = place_cabin_seats(pax, wcabin)
xseats = xseats .+ xseats0
rows = length(xseats)

println("Seats per row = $seats_per_row, Total rows = $rows")
yseats, symmetric_seats = arrange_seats(seats_per_row, parg[igRfuse])
yseats = arrange_seats(seats_per_row, wcabin)

## Plot
if ax === nothing
Expand Down Expand Up @@ -552,12 +553,9 @@ function stickfig(ac::aircraft; ax = nothing, label_fs = 16)
ax.text(0.5*(parg[igxCGfwd ]+parg[igxCGaft ]), -1.0, "CG", fontsize=label_fs-2.0, ha="center", va="center", zorder = 21)

# Show seats
if symmetric_seats
ax.scatter(ones(length(yseats),1).*xseats, ones(1,rows).* yseats, color = "gray", alpha = 0.1, marker = "s", s=15, zorder = 21)
ax.scatter(ones(length(yseats),1).*xseats, ones(1,rows).*-yseats, color = "gray", alpha = 0.1, marker = "s", s=15, zorder = 21)
else

ax.scatter(ones(length(yseats),1).*xseats, ones(1,rows).* yseats, color = "gray", alpha = 0.1, marker = "s", s=15, zorder = 21)
end

# diagnostic marks
# ax.scatter(parg[igxftank] - l/2, 0.0, color = "k", marker="o", zorder = 21)
# ax.scatter(parg[igxftank], 0.0, color = "b", marker="o", zorder = 21)
Expand Down Expand Up @@ -1392,12 +1390,13 @@ function high_res_airplane_plot(ac; ax = nothing, label_fs = 16, save_name = not

#Seats
pax = parg[igWpay]/parm[imWperpax]
_, xseats, seats_per_row = place_cabin_seats(pax, parg[igRfuse])
wcabin = find_cabin_width(parg[igRfuse], parg[igdRfuse], parg[igwfb], parg[ignfweb], parg[igfloordist]) #Find cabin width
_, xseats, seats_per_row = place_cabin_seats(pax, wcabin)
xseats = xseats .+ xseats0
rows = length(xseats)

println("Seats per row = $seats_per_row, Total rows = $rows")
yseats, symmetric_seats = arrange_seats(seats_per_row, parg[igRfuse])
yseats = arrange_seats(seats_per_row, wcabin)

## Plot
if ax === nothing
Expand Down Expand Up @@ -1504,12 +1503,8 @@ function high_res_airplane_plot(ac; ax = nothing, label_fs = 16, save_name = not
ax.text(0.5*(parg[igxCGfwd ]+parg[igxCGaft ]), -1.0, "CG", fontsize=label_fs-2.0, ha="center", va="center", zorder = 21)

# Show seats
if symmetric_seats
ax.scatter(ones(length(yseats),1).*xseats, ones(1,rows).* yseats, color = "gray", alpha = 0.1, marker = "s", s=15, zorder = 21)
ax.scatter(ones(length(yseats),1).*xseats, ones(1,rows).*-yseats, color = "gray", alpha = 0.1, marker = "s", s=15, zorder = 21)
else
ax.scatter(ones(length(yseats),1).*xseats, ones(1,rows).* yseats, color = "gray", alpha = 0.1, marker = "s", s=15, zorder = 21)
end

# diagnostic marks
# ax.scatter(parg[igxftank] - l/2, 0.0, color = "k", marker="o", zorder = 21)
# ax.scatter(parg[igxftank], 0.0, color = "b", marker="o", zorder = 21)
Expand Down
4 changes: 4 additions & 0 deletions src/IO/read_input.jl
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,10 @@ readgeom(x) = read_input(x, geom, dgeom)
calculate_cabin = readgeom("calculate_cabin_length")
pari[iidoubledeck] = readgeom("double_decker")

if pari[iidoubledeck] == 1 #If aircraft is a double decker
parg[igfloordist] = Distance(readgeom("floor_distance")) #read vertical distance between floors
end

parg[igseatpitch] = Distance(readgeom("seat_pitch"))
parg[igseatwidth] = Distance(readgeom("seat_width"))
parg[igaislehalfwidth] = Distance(readgeom("aisle_halfwidth"))
Expand Down
148 changes: 91 additions & 57 deletions src/IO/size_cabin.jl
Original file line number Diff line number Diff line change
@@ -1,26 +1,40 @@
"""
place_cabin_seats(pax, Rfuse)
place_cabin_seats(pax, cabin_width, seat_pitch = 30.0*in_to_m,
seat_width = 19.0*in_to_m, aisle_halfwidth = 10.0*in_to_m, fuse_offset = 6.0*in_to_m)

Function to calculate the seat arrangement in the cabin and, therefore, the required cabin
length.

!!! details "🔃 Inputs and Outputs"
**Inputs:**
- `pax::Float64`: design number of passengers
- `Rfuse::Float64`: fuselage radius (m).
- `cabin_width::Float64`: width of cabin (m).
- `seat_width::Float64`: width of one seat (m).
- `aisle_halfwidth::Float64`: half the width of an aisle (m).
- `fuse_offset::Float64`: distance from outside of fuselage to edge of closest window seat (m).

**Outputs:**
- `lcabin::Float64`: cabin length (m).
- `xseats::Vector{Float64}`: longitudinal coordinate of each row of seats, measured from front of cabin (m).
- `seats_per_row::Float64`: number of seats per row.
"""
function place_cabin_seats(pax, Rfuse, seat_pitch = 30.0*in_to_m,
seat_width = 19.0*in_to_m, aisle_halfwidth = 10.0*in_to_m)
function place_cabin_seats(pax, cabin_width, seat_pitch = 30.0*in_to_m,
seat_width = 19.0*in_to_m, aisle_halfwidth = 10.0*in_to_m, fuse_offset = 6.0*in_to_m)

cabin_offset = 10 * ft_to_m #Distance to the front and back of seats
#TODO the hardcoded 10 ft is not elegant

seats_per_row = Int(2*Rfuse÷ (seat_width + aisle_halfwidth/3))
#Calculate the maximum number of seats per row
seats_per_row = 1
Dmin = seats_per_row*seat_width + 2*aisle_halfwidth + 2*fuse_offset #Minimum diameter for one passenger
while (cabin_width > Dmin) || (cabin_width ≈ Dmin) #While the required diameter is smaller than the fuselage diameter
seats_per_row = seats_per_row + 1 #Add one more seat
layout = seat_layouts[seats_per_row] #Find corresponding seat layour from seat dict
Dmin = seats_per_row*seat_width + (length(layout) - 1)*2*aisle_halfwidth + 2*fuse_offset #New minimum diameter
end

seats_per_row = seats_per_row - 1 #Subtract 1 seat to find maximum number of seats per row such that cabin_width > Dmin

rows = Int(ceil(pax / seats_per_row))

if seats_per_row <= 10
Expand All @@ -44,76 +58,96 @@ function place_cabin_seats(pax, Rfuse, seat_pitch = 30.0*in_to_m,
end # function place_cabin_seats

"""
arrange_seats(seats_per_row, Rfuse,
arrange_seats(seats_per_row, cabin_width,
seat_width = 19.0 * in_to_m,
aisle_halfwidth = 10.0 * in_to_m)
aisle_halfwidth = 10.0 * in_to_m,
fuse_offset = 6.0*in_to_m)

Helper function to arrange seats given a number of `seats_per_row`
and fuselage radius. Assumes default `seat_width = 19"` and `aisle_halfwidth = 10"`,
and cabin width. Assumes default `seat_width = 19"` and `aisle_halfwidth = 10"`,
but can be supplied by the user.
!!! details "🔃 Inputs and Outputs"
**Inputs:**
- `seats_per_row::Float64`: number of seats per row.
- `Rfuse::Float64`: fuselage radius (m).
- `cabin_width::Float64`: width of cabin (m).
- `seat_width::Float64`: width of one seat (m).
- `aisle_halfwidth::Float64`: half the width of an aisle (m).
- `fuse_offset::Float64`: distance from outside of fuselage to edge of closest window seat (m).

**Outputs:**
- `yseats::Vector{Float64}`: transverse coordinate of each column of seats, measured from centerline (m).
- `symmetric_seats::Boolean`: flag for symmetry of seat arrangement
"""
function arrange_seats(seats_per_row, Rfuse,
function arrange_seats(seats_per_row, cabin_width,
seat_width = 19.0 * in_to_m,
aisle_halfwidth = 10.0 * in_to_m)
aisle_halfwidth = 10.0 * in_to_m,
fuse_offset = 6.0*in_to_m)

#Seats
# Conditions:
# - No more than 2 seats between any seat and the aisle
seats_per_row % 2 == 0 ? symmetric_seats = true : symmetric_seats = false

if symmetric_seats # seating can be symmetric
half_seats_per_row = seats_per_row ÷ 2
yseats = zeros(half_seats_per_row)

if half_seats_per_row <= 3 #Single aisle
yseats[1] = aisle_halfwidth + seat_width/2 #Aisle in the center
for col = 2:half_seats_per_row
yseats[col] = yseats[col-1] + seat_width #offset every seat by width
end
else # twin aisle
#If symmetric no more than 2 seats next to each other at the
# centerline (I'm not evil enough to create a x-6-x seating arrangement even if "technically" allowed)
yseats[1] = seat_width/2.0
yseats[2] = yseats[1] + seat_width
#Aisle
half_seats_remaining = half_seats_per_row - 2
if half_seats_remaining > 4
@warn "Potentially trying to design a 3 aisle aircraft?
Seating arrangement not (yet) automatically handled, so check carefully."
end
yseats[3] = yseats[2] + aisle_halfwidth*2 + seat_width
for col = 4:half_seats_per_row
yseats[col] = yseats[col-1] + seat_width
end
end

layout = seat_layouts[seats_per_row] #find seat layout from dictionary
n_aisles = length(layout) - 1 #Number of aisles
Dmin = seats_per_row*seat_width + n_aisles*2*aisle_halfwidth + 2*fuse_offset #Minimum required diameter

exp_aisle_halfwidth = aisle_halfwidth + (cabin_width - Dmin)/(2*n_aisles) #Expanded aisle to take up all available space

yseats = zeros(seats_per_row)
yseats[1] = fuse_offset + seat_width/2 #First seat is window seat
for i = 2:seats_per_row
flag_aisle = aisle_flag(i, layout) #1 if there is an aise to the left of seat, 0 if not
yseats[i] = yseats[i - 1] + seat_width + flag_aisle*2*exp_aisle_halfwidth
end

#Shift seat coordinates to start in centerline
yseats = yseats .- cabin_width/2

return yseats
end # function arrange_seats

"""
aisle_flag(idx, layout)

Helper function to find if there is an aisle to the left of a given seat.
!!! details "🔃 Inputs and Outputs"
**Inputs:**
- `idx::Int64`: seat index.
- `layout::Vector{Int64}`: seat layout map.

**Outputs:**
- `flag::Float64`: 1.0 if there is an aise to the left of seat, 0.0 if not.
"""
function aisle_flag(idx, layout)
#Use cumulative sum to find total number of seats to the left of a given aisle.
#If the difference between the cumsum and the index is exactly 1, the seat has an aisle to the left.
if 1 in (idx .- cumsum(layout))
flag = 1.0
else
@info "Asymmetric seating only deals with 3 or 5 seats at the moment"
seating_excess_space = 2*Rfuse - seats_per_row*seat_width - 2*aisle_halfwidth
yseats = zeros(seats_per_row)
# Start from edge and give some space based on the excess space available.
ind = 1
yseats[ind] = -Rfuse + seating_excess_space/2 + seat_width/2
ind+=1
if seats_per_row > 3
yseats[ind] = yseats[ind-1] + seat_width
ind+=1
end
yseats[ind] = yseats[ind-1] + aisle_halfwidth*2 + seat_width
ind+=1
for col = ind:seats_per_row
yseats[col] = yseats[col-1] + seat_width
end
flag = 0.0
end
return yseats, symmetric_seats
end # function arrange_seats
return flag
end

"""
find_cabin_width(Rfuse::Float64, dRfuse::Float64, wfb::Float64, nfweb, ΔH::Float64 = 0.0)

This function can be used to calculate the width of the passenger cabin from the double-bubble parameters.
It has an optional parameter `ΔH`, which represents the distance between two floors if the aircraft is a double decker.
If the aircraft is a double decker, the floors are assumed to be symmetric.
!!! details "🔃 Inputs and Outputs"
**Inputs:**
- `Rfuse::Float64`: fuselage exterior radius (m)
- `dRfuse::Float64`: downward shift of double bubble (m)
- `wfb::Float64`: lateral shift of double bubble (m)
- `nfweb::Float64`: number of vertical webs in fuselage
- `ΔH::Float64`: distance between floors (m)

**Outputs:**
- `w::Float64`: width of cabin (m).
"""
function find_cabin_width(Rfuse::Float64, dRfuse::Float64, wfb::Float64, nfweb::Float64, ΔH::Float64 = 0.0)
#Subtract dRfuse from ΔH when there is a lower bubble; fuselage is taller
θ = max(asin((ΔH - dRfuse)/(2*Rfuse)), 0.0) #This assumes that floors are symmetrically distributed in fuselage
w = nfweb*2*wfb + 2*Rfuse*cos(θ)
return w
end
21 changes: 20 additions & 1 deletion src/misc/constants.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,23 @@ const pref = 101320.0
const Tref = 288.2
const σ_SB = 5.670374419e-8
const p_atm = 101325.0 #Pa in one atm
const t_h = 3600.0 #s in one hour
const t_h = 3600.0 #s in one hour

const seat_layouts = Dict{Int64, Vector{Int64}}(
1 => [1, 0],
2 => [1, 1],
3 => [2, 1],
4 => [2, 2],
5 => [3, 2],
6 => [3, 3],
7 => [2, 3, 2],
8 => [2, 4, 2],
9 => [3, 3, 3],
10 => [3, 4, 3],
11 => [3, 5, 3],
12 => [3, 3, 3, 3],
13 => [3, 4, 3, 3],
14 => [3, 4, 4, 3],
15 => [3, 5, 4, 3],
16 => [3, 5, 5, 3]
)
5 changes: 3 additions & 2 deletions src/misc/index.inc
Original file line number Diff line number Diff line change
Expand Up @@ -385,10 +385,11 @@
const igseatpitch = 306
const igseatwidth = 307
const igaislehalfwidth = 308
const igfloordist = 309

const igWfvent = 309
const igWfvent = 310

const igtotal = 309
const igtotal = 310

# indices for turbo-electric systems - really just the electrical machines
const ite_ratSM = 1
Expand Down
2 changes: 1 addition & 1 deletion src/structures/structures.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ required to size an aircraft

module structures

import ..TASOPT: __TASOPTindices__, __TASOPTroot__, place_cabin_seats
import ..TASOPT: __TASOPTindices__, __TASOPTroot__, place_cabin_seats, find_cabin_width

export surfw, surfdx, fusew, tailpo, update_fuse!, update_fuse_for_pax!

Expand Down
3 changes: 2 additions & 1 deletion src/structures/update_fuse.jl
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@ function update_fuse_for_pax!(pari, parg, parm, fuse_tank)
wbox_cabin_frac = (parg[igxwbox]- parg[igxblend1] )/(parg[igxblend2] - parg[igxblend1])

#Find new cabin length
lcyl, _, _ = place_cabin_seats(paxsize, parg[igRfuse], seat_pitch, seat_width, aisle_halfwidth) #Size for max pax count
wcabin = find_cabin_width(parg[igRfuse], parg[igdRfuse], parg[igwfb], parg[ignfweb], parg[igfloordist]) #Find cabin width
lcyl, _, _ = place_cabin_seats(paxsize, wcabin, seat_pitch, seat_width, aisle_halfwidth) #Size for max pax count

#When there is a fuel tank at the back of the fuselage, there is no offset between the end of the seat rows
#and the start of the tank. For this reason, leave a 5ft offset at back
Expand Down
Loading
Loading