feat: Cleans up / renames some manual-d client routes.

This commit is contained in:
2026-01-16 12:10:33 -05:00
parent 13c4bb33b5
commit 761ba29c1e
5 changed files with 22 additions and 200 deletions

View File

@@ -13,7 +13,7 @@ extension ManualDClient: DependencyKey {
let finalSize = try roundSize(ductulatorSize) let finalSize = try roundSize(ductulatorSize)
let flexSize = try flexSize(request) let flexSize = try flexSize(request)
return .init( return .init(
ductulatorSize: ductulatorSize, calculatedSize: ductulatorSize,
finalSize: finalSize, finalSize: finalSize,
flexSize: flexSize, flexSize: flexSize,
velocity: velocity(cfm: request.designCFM, roundSize: finalSize) velocity: velocity(cfm: request.designCFM, roundSize: finalSize)
@@ -30,13 +30,13 @@ extension ManualDClient: DependencyKey {
let frictionRate = availableStaticPressure * 100.0 / Double(request.totalEffectiveLength) let frictionRate = availableStaticPressure * 100.0 / Double(request.totalEffectiveLength)
return .init(availableStaticPressure: availableStaticPressure, frictionRate: frictionRate) return .init(availableStaticPressure: availableStaticPressure, frictionRate: frictionRate)
}, },
totalEffectiveLength: { request in totalEquivalentLength: { request in
let trunkLengths = request.trunkLengths.reduce(0) { $0 + $1 } let trunkLengths = request.trunkLengths.reduce(0) { $0 + $1 }
let runoutLengths = request.runoutLengths.reduce(0) { $0 + $1 } let runoutLengths = request.runoutLengths.reduce(0) { $0 + $1 }
let groupLengths = request.effectiveLengthGroups.totalEffectiveLength let groupLengths = request.effectiveLengthGroups.totalEffectiveLength
return trunkLengths + runoutLengths + groupLengths return trunkLengths + runoutLengths + groupLengths
}, },
equivalentRectangularDuct: { request in rectangularSize: { request in
let width = (Double.pi * (pow(Double(request.roundSize) / 2.0, 2.0))) / Double(request.height) let width = (Double.pi * (pow(Double(request.roundSize) / 2.0, 2.0))) / Double(request.height)
return .init(height: request.height, width: Int(width.rounded(.toNearestOrEven))) return .init(height: request.height, width: Int(width.rounded(.toNearestOrEven)))
} }

View File

@@ -10,163 +10,16 @@ extension DependencyValues {
} }
} }
/// Performs manual-d duct sizing calculations.
///
///
@DependencyClient @DependencyClient
public struct ManualDClient: Sendable { public struct ManualDClient: Sendable {
public var ductSize: @Sendable (DuctSizeRequest) async throws -> DuctSizeResponse public var ductSize: @Sendable (DuctSizeRequest) async throws -> DuctSizeResponse
public var frictionRate: @Sendable (FrictionRateRequest) async throws -> FrictionRateResponse public var frictionRate: @Sendable (FrictionRateRequest) async throws -> FrictionRateResponse
public var totalEffectiveLength: @Sendable (TotalEffectiveLengthRequest) async throws -> Int public var totalEquivalentLength: @Sendable (TotalEquivalentLengthRequest) async throws -> Int
public var equivalentRectangularDuct: public var rectangularSize:
@Sendable (EquivalentRectangularDuctRequest) async throws -> EquivalentRectangularDuctResponse @Sendable (RectangularSizeRequest) async throws -> RectangularSizeResponse
// TODO: add (Project.ID) async throws -> ProjectResponse
// TODO: Move to helpers.
// public func calculateSizes(
// rooms: [Room],
// trunks: [DuctSizing.TrunkSize],
// equipmentInfo: EquipmentInfo,
// maxSupplyLength: EffectiveLength,
// maxReturnLength: EffectiveLength,
// designFrictionRate: Double,
// projectSHR: Double,
// logger: Logger? = nil
// ) async throws -> ProjectResponse {
// try await .init(
// rooms: calculateRoomSizes(
// rooms: rooms,
// equipmentInfo: equipmentInfo,
// maxSupplyLength: maxSupplyLength,
// maxReturnLength: maxReturnLength,
// designFrictionRate: designFrictionRate,
// projectSHR: projectSHR
// ),
// trunks: calculateTrunkSizes(
// rooms: rooms,
// trunks: trunks,
// equipmentInfo: equipmentInfo,
// maxSupplyLength: maxSupplyLength,
// maxReturnLength: maxReturnLength,
// designFrictionRate: designFrictionRate,
// projectSHR: projectSHR
// )
// )
// }
//
// func calculateRoomSizes(
// rooms: [Room],
// equipmentInfo: EquipmentInfo,
// maxSupplyLength: EffectiveLength,
// maxReturnLength: EffectiveLength,
// designFrictionRate: Double,
// projectSHR: Double,
// logger: Logger? = nil
// ) async throws -> [DuctSizing.RoomContainer] {
//
// var retval: [DuctSizing.RoomContainer] = []
// let totalHeatingLoad = rooms.totalHeatingLoad
// let totalCoolingSensible = rooms.totalCoolingSensible(shr: projectSHR)
//
// for room in rooms {
// let heatingLoad = room.heatingLoadPerRegister
// let coolingLoad = room.coolingSensiblePerRegister(projectSHR: projectSHR)
// let heatingPercent = heatingLoad / totalHeatingLoad
// let coolingPercent = coolingLoad / totalCoolingSensible
// let heatingCFM = heatingPercent * Double(equipmentInfo.heatingCFM)
// let coolingCFM = coolingPercent * Double(equipmentInfo.coolingCFM)
// let designCFM = DuctSizing.DesignCFM(heating: heatingCFM, cooling: coolingCFM)
// let sizes = try await self.ductSize(
// .init(designCFM: Int(designCFM.value), frictionRate: designFrictionRate)
// )
//
// for n in 1...room.registerCount {
//
// var rectangularWidth: Int? = nil
// let rectangularSize = room.rectangularSizes?
// .first(where: { $0.register == nil || $0.register == n })
//
// if let rectangularSize {
// let response = try await self.equivalentRectangularDuct(
// .init(round: sizes.finalSize, height: rectangularSize.height)
// )
// rectangularWidth = response.width
// }
//
// retval.append(
// .init(
// roomID: room.id,
// roomName: "\(room.name)-\(n)",
// roomRegister: n,
// heatingLoad: heatingLoad,
// coolingLoad: coolingLoad,
// heatingCFM: heatingCFM,
// coolingCFM: coolingCFM,
// designCFM: designCFM,
// roundSize: sizes.ductulatorSize,
// finalSize: sizes.finalSize,
// velocity: sizes.velocity,
// flexSize: sizes.flexSize,
// rectangularSize: rectangularSize,
// rectangularWidth: rectangularWidth
// )
// )
// }
// }
//
// return retval
// }
//
// func calculateTrunkSizes(
// rooms: [Room],
// trunks: [DuctSizing.TrunkSize],
// equipmentInfo: EquipmentInfo,
// maxSupplyLength: EffectiveLength,
// maxReturnLength: EffectiveLength,
// designFrictionRate: Double,
// projectSHR: Double,
// logger: Logger? = nil
// ) async throws -> [DuctSizing.TrunkContainer] {
//
// var retval = [DuctSizing.TrunkContainer]()
// let totalHeatingLoad = rooms.totalHeatingLoad
// let totalCoolingSensible = rooms.totalCoolingSensible(shr: projectSHR)
//
// for trunk in trunks {
// let heatingLoad = trunk.totalHeatingLoad
// let coolingLoad = trunk.totalCoolingSensible(projectSHR: projectSHR)
// let heatingPercent = heatingLoad / totalHeatingLoad
// let coolingPercent = coolingLoad / totalCoolingSensible
// let heatingCFM = heatingPercent * Double(equipmentInfo.heatingCFM)
// let coolingCFM = coolingPercent * Double(equipmentInfo.coolingCFM)
// let designCFM = DuctSizing.DesignCFM(heating: heatingCFM, cooling: coolingCFM)
// let sizes = try await self.ductSize(
// .init(designCFM: Int(designCFM.value), frictionRate: designFrictionRate)
// )
// var width: Int? = nil
// if let height = trunk.height {
// let rectangularSize = try await self.equivalentRectangularDuct(
// .init(round: sizes.finalSize, height: height)
// )
// width = rectangularSize.width
// }
//
// retval.append(
// .init(
// trunk: trunk,
// ductSize: .init(
// designCFM: designCFM,
// roundSize: sizes.ductulatorSize,
// finalSize: sizes.finalSize,
// velocity: sizes.velocity,
// flexSize: sizes.flexSize,
// height: trunk.height,
// width: width
// )
// )
// )
// }
//
// return retval
// }
} }
@@ -174,25 +27,6 @@ extension ManualDClient: TestDependencyKey {
public static let testValue = Self() public static let testValue = Self()
} }
// MARK: Project Response
// extension ManualDClient {
//
// public struct ProjectResponse: Codable, Equatable, Sendable {
// public let rooms: [DuctSizing.RoomContainer]
// public let trunks: [DuctSizing.TrunkContainer]
//
// public init(
// rooms: [DuctSizing.RoomContainer],
// trunks: [DuctSizing.TrunkContainer]
// ) {
// self.rooms = rooms
// self.trunks = trunks
// }
// }
//
// }
// MARK: Duct Size
extension ManualDClient { extension ManualDClient {
public struct DuctSizeRequest: Codable, Equatable, Sendable { public struct DuctSizeRequest: Codable, Equatable, Sendable {
@@ -210,27 +44,24 @@ extension ManualDClient {
public struct DuctSizeResponse: Codable, Equatable, Sendable { public struct DuctSizeResponse: Codable, Equatable, Sendable {
public let ductulatorSize: Double public let calculatedSize: Double
public let finalSize: Int public let finalSize: Int
public let flexSize: Int public let flexSize: Int
public let velocity: Int public let velocity: Int
public init( public init(
ductulatorSize: Double, calculatedSize: Double,
finalSize: Int, finalSize: Int,
flexSize: Int, flexSize: Int,
velocity: Int velocity: Int
) { ) {
self.ductulatorSize = ductulatorSize self.calculatedSize = calculatedSize
self.finalSize = finalSize self.finalSize = finalSize
self.flexSize = flexSize self.flexSize = flexSize
self.velocity = velocity self.velocity = velocity
} }
} }
}
// MARK: - Friction Rate
extension ManualDClient {
public struct FrictionRateRequest: Codable, Equatable, Sendable { public struct FrictionRateRequest: Codable, Equatable, Sendable {
public let externalStaticPressure: Double public let externalStaticPressure: Double
@@ -258,11 +89,8 @@ extension ManualDClient {
self.frictionRate = frictionRate self.frictionRate = frictionRate
} }
} }
}
// MARK: Total Effective Length public struct TotalEquivalentLengthRequest: Codable, Equatable, Sendable {
extension ManualDClient {
public struct TotalEffectiveLengthRequest: Codable, Equatable, Sendable {
public let trunkLengths: [Int] public let trunkLengths: [Int]
public let runoutLengths: [Int] public let runoutLengths: [Int]
@@ -278,11 +106,8 @@ extension ManualDClient {
self.effectiveLengthGroups = effectiveLengthGroups self.effectiveLengthGroups = effectiveLengthGroups
} }
} }
}
// MARK: Equivalent Rectangular Duct public struct RectangularSizeRequest: Codable, Equatable, Sendable {
extension ManualDClient {
public struct EquivalentRectangularDuctRequest: Codable, Equatable, Sendable {
public let roundSize: Int public let roundSize: Int
public let height: Int public let height: Int
@@ -292,7 +117,7 @@ extension ManualDClient {
} }
} }
public struct EquivalentRectangularDuctResponse: Codable, Equatable, Sendable { public struct RectangularSizeResponse: Codable, Equatable, Sendable {
public let height: Int public let height: Int
public let width: Int public let width: Int

View File

@@ -105,9 +105,6 @@ extension DuctSizes {
} }
} }
} }
}
extension DuctSizes {
// Represents the database model that the duct sizes have been calculated // Represents the database model that the duct sizes have been calculated
// for. // for.

View File

@@ -62,7 +62,7 @@ extension ManualDClient {
.first(where: { $0.register == nil || $0.register == n }) .first(where: { $0.register == nil || $0.register == n })
if let rectangularSize { if let rectangularSize {
let response = try await self.equivalentRectangularDuct( let response = try await self.rectangularSize(
.init(round: sizes.finalSize, height: rectangularSize.height) .init(round: sizes.finalSize, height: rectangularSize.height)
) )
rectangularWidth = response.width rectangularWidth = response.width
@@ -115,7 +115,7 @@ extension ManualDClient {
) )
var width: Int? = nil var width: Int? = nil
if let height = trunk.height { if let height = trunk.height {
let rectangularSize = try await self.equivalentRectangularDuct( let rectangularSize = try await self.rectangularSize(
.init(round: sizes.finalSize, height: height) .init(round: sizes.finalSize, height: height)
) )
width = rectangularSize.width width = rectangularSize.width
@@ -149,7 +149,7 @@ extension DuctSizes.SizeContainer {
self.init( self.init(
rectangularID: nil, rectangularID: nil,
designCFM: designCFM, designCFM: designCFM,
roundSize: sizes.ductulatorSize, roundSize: sizes.calculatedSize,
finalSize: sizes.finalSize, finalSize: sizes.finalSize,
velocity: sizes.velocity, velocity: sizes.velocity,
flexSize: sizes.flexSize, flexSize: sizes.flexSize,
@@ -167,7 +167,7 @@ extension DuctSizes.SizeContainer {
self.init( self.init(
rectangularID: rectangularSize?.id, rectangularID: rectangularSize?.id,
designCFM: designCFM, designCFM: designCFM,
roundSize: sizes.ductulatorSize, roundSize: sizes.calculatedSize,
finalSize: sizes.finalSize, finalSize: sizes.finalSize,
velocity: sizes.velocity, velocity: sizes.velocity,
flexSize: sizes.flexSize, flexSize: sizes.flexSize,

View File

@@ -27,7 +27,7 @@ struct ManualDClientTests {
let response = try await manualD.ductSize( let response = try await manualD.ductSize(
.init(designCFM: 88, frictionRate: 0.06) .init(designCFM: 88, frictionRate: 0.06)
) )
#expect(numberFormatter.string(for: response.ductulatorSize) == "6.07") #expect(numberFormatter.string(for: response.calculatedSize) == "6.07")
#expect(response.finalSize == 7) #expect(response.finalSize == 7)
#expect(response.flexSize == 7) #expect(response.flexSize == 7)
#expect(response.velocity == 329) #expect(response.velocity == 329)
@@ -61,7 +61,7 @@ struct ManualDClientTests {
@Test @Test
func totalEffectiveLength() async throws { func totalEffectiveLength() async throws {
let response = try await manualD.totalEffectiveLength( let response = try await manualD.totalEquivalentLength(
.init( .init(
trunkLengths: [25], trunkLengths: [25],
runoutLengths: [10], runoutLengths: [10],
@@ -79,7 +79,7 @@ struct ManualDClientTests {
@Test @Test
func equivalentRectangularDuct() async throws { func equivalentRectangularDuct() async throws {
let response = try await manualD.equivalentRectangularDuct(.init(round: 7, height: 8)) let response = try await manualD.rectangularSize(.init(round: 7, height: 8))
#expect(response.height == 8) #expect(response.height == 8)
#expect(response.width == 5) #expect(response.width == 5)
} }