feat: Begins room-pressure calculator

This commit is contained in:
2025-02-28 16:27:39 -05:00
parent d08e4b0839
commit 49af734a97
15 changed files with 548 additions and 50 deletions

View File

@@ -0,0 +1,31 @@
public enum ClimateZone: String, Codable, Equatable, Sendable {
case dry
case hotHumid
case marine
case moist
public var zoneIdentifiers: [String] {
switch self {
case .dry:
return ["2B", "3B", "4B", "5B", "6B", "7B"]
case .hotHumid:
return ["1A", "2A"]
case .marine:
return ["3C", "4C"]
case .moist:
return ["3A", "4A", "5A", "6A", "7A"]
}
}
public var cfmPerTon: Int {
switch self {
case .dry: return 450
case .hotHumid: return 350
case .marine, .moist: return 400
}
}
public var label: String {
return "\(rawValue.capitalized) (\(zoneIdentifiers.joined(separator: ",")))"
}
}

View File

@@ -0,0 +1,112 @@
public enum FilterPressureDrop {
public enum Request: Codable, Equatable, Sendable {
case basic(Basic)
case fanLaw(FanLaw)
public struct Basic: Codable, Equatable, Sendable {
let systemSize: HVACSystemSize
let climateZone: ClimateZone
let filterType: FilterType
let filterWidth: Double
let filterHeight: Double
public init(
systemSize: HVACSystemSize,
climateZone: ClimateZone,
filterType: FilterPressureDrop.FilterType,
filterWidth: Double,
filterHeight: Double
) {
self.systemSize = systemSize
self.climateZone = climateZone
self.filterType = filterType
self.filterWidth = filterWidth
self.filterHeight = filterHeight
}
}
public struct FanLaw: Codable, Equatable, Sendable {
let filterWidth: Double
let filterHeight: Double
let filterDepth: Double
let ratedAirflow: Double
let ratedPressureDrop: Double
let designAirflow: Double
public init(
filterWidth: Double,
filterHeight: Double,
filterDepth: Double,
ratedAirflow: Double,
ratedPressureDrop: Double,
designAirflow: Double
) {
self.filterWidth = filterWidth
self.filterHeight = filterHeight
self.filterDepth = filterDepth
self.ratedAirflow = ratedAirflow
self.ratedPressureDrop = ratedPressureDrop
self.designAirflow = designAirflow
}
}
}
public enum Result: Codable, Equatable, Sendable {
case basic(Basic)
case fanLaw(FanLaw)
public struct Basic: Codable, Equatable, Sendable {
let filterArea: Double
let feetPerMinute: Double
let initialPressureDrop: Double
let maxPressureDrop: Double
public init(filterArea: Double, feetPerMinute: Double, initialPressureDrop: Double, maxPressureDrop: Double) {
self.filterArea = filterArea
self.feetPerMinute = feetPerMinute
self.initialPressureDrop = initialPressureDrop
self.maxPressureDrop = maxPressureDrop
}
}
public struct FanLaw: Codable, Equatable, Sendable {
public let predictedPressureDrop: Double
public let velocityRatio: Double
public let pressureRatio: Double
public let faceVelocity: Double
public init(
predictedPressureDrop: Double,
velocityRatio: Double,
pressureRatio: Double,
faceVelocity: Double
) {
self.predictedPressureDrop = predictedPressureDrop
self.velocityRatio = velocityRatio
self.pressureRatio = pressureRatio
self.faceVelocity = faceVelocity
}
}
}
public enum FilterType: String, Codable, Equatable, Sendable {
case fiberglass
case pleatedBasic
case pleatedBetter
case pleatedBest
public var label: String {
switch self {
case .fiberglass: return "Fiberglass (MERV 1-4)"
case .pleatedBasic: return "Basic Pleated (MERV 5-8)"
case .pleatedBetter: return "Better Pleated (MERV 9-12)"
case .pleatedBest: return "Best Pleated (MERV 13-16)"
}
}
}
}

View File

@@ -0,0 +1,126 @@
public enum RoomPressure {
public enum Mode: String, CaseIterable, Codable, Equatable, Sendable {
case knownAirflow
case measuredPressure
public var label: String {
switch self {
case .knownAirflow: return "Known Airflow"
case .measuredPressure: return "Measured Pressure"
}
}
}
public enum Request: Codable, Equatable, Sendable {
case knownAirflow(KnownAirflow)
case measuredPressure(MeasuredPressure)
public struct KnownAirflow: Codable, Equatable, Sendable {
public let targetRoomPressure: Double
public let doorWidth: Double
public let doorHeight: Double
public let doorUndercut: Double
public let supplyAirflow: Double
public let preferredGrilleHeight: CommonReturnGrilleHeight
public init(
targetRoomPressure: Double,
doorWidth: Double,
doorHeight: Double,
doorUndercut: Double,
supplyAirflow: Double,
preferredGrilleHeight: RoomPressure.CommonReturnGrilleHeight
) {
self.targetRoomPressure = targetRoomPressure
self.doorWidth = doorWidth
self.doorHeight = doorHeight
self.doorUndercut = doorUndercut
self.supplyAirflow = supplyAirflow
self.preferredGrilleHeight = preferredGrilleHeight
}
}
public struct MeasuredPressure: Codable, Equatable, Sendable {
public let measuredRoomPressure: Double // pascals.
public let doorWidth: Double
public let doorHeight: Double
public let doorUndercut: Double
public let preferredGrilleHeight: CommonReturnGrilleHeight
public init(
measuredRoomPressure: Double,
doorWidth: Double,
doorHeight: Double,
doorUndercut: Double,
preferredGrilleHeight: RoomPressure.CommonReturnGrilleHeight
) {
self.measuredRoomPressure = measuredRoomPressure
self.doorWidth = doorWidth
self.doorHeight = doorHeight
self.doorUndercut = doorUndercut
self.preferredGrilleHeight = preferredGrilleHeight
}
}
}
public struct Response: Codable, Equatable, Sendable {
public let grilleSize: GrilleSize
public let ductSize: DuctSize
public let calculatedAirflow: Double?
public let warnings: [String]
public init(
grilleSize: RoomPressure.Response.GrilleSize,
ductSize: RoomPressure.Response.DuctSize,
calculatedAirflow: Double? = nil,
warnings: [String]
) {
self.grilleSize = grilleSize
self.ductSize = ductSize
self.calculatedAirflow = calculatedAirflow
self.warnings = warnings
}
public struct DuctSize: Codable, Equatable, Sendable {
public let diameter: Double
public let velocity: Double
public init(diameter: Double, velocity: Double) {
self.diameter = diameter
self.velocity = velocity
}
}
public struct GrilleSize: Codable, Equatable, Sendable {
public let width: Double
public let height: Double
public let area: Double
public init(width: Double, height: Double, area: Double) {
self.width = width
self.height = height
self.area = area
}
}
}
public enum CommonReturnGrilleHeight: Int, CaseIterable, Codable, Equatable, Sendable {
case four = 4
case six = 6
case eight = 8
case ten = 10
case twelve = 12
case fourteen = 14
case twenty = 20
public var label: String { "\(rawValue)\"" }
}
}

View File

@@ -56,6 +56,7 @@ public extension SiteRoute {
case dehumidifierSize(DehumidifierSize)
case hvacSystemPerformance(HVACSystemPerformance)
case moldRisk(MoldRisk)
case roomPressure(RoomPressure)
public static let router = OneOf {
Route(.case(Self.index)) {
@@ -70,6 +71,9 @@ public extension SiteRoute {
Route(.case(Self.moldRisk)) {
MoldRisk.router
}
Route(.case(Self.roomPressure)) {
RoomPressure.router
}
}
public enum DehumidifierSize: Equatable, Sendable {
@@ -157,5 +161,23 @@ public extension SiteRoute {
}
}
}
public enum RoomPressure: Equatable, Sendable {
case index(mode: Routes.RoomPressure.Mode? = nil)
public static var index: Self { .index() }
static let rootPath = "room-pressure"
public static let router = OneOf {
Route(.case(Self.index)) {
Path { rootPath }
Method.get
Query {
Optionally { Field("form") { Routes.RoomPressure.Mode.parser() } }
}
}
}
}
}
}