This repository has been archived on 2026-02-12. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
swift-duct-calc/Sources/ManualDClient/ManualDClient.swift

305 lines
9.3 KiB
Swift

import Dependencies
import DependenciesMacros
import Logging
import ManualDCore
extension DependencyValues {
public var manualD: ManualDClient {
get { self[ManualDClient.self] }
set { self[ManualDClient.self] = newValue }
}
}
@DependencyClient
public struct ManualDClient: Sendable {
public var ductSize: @Sendable (DuctSizeRequest) async throws -> DuctSizeResponse
public var frictionRate: @Sendable (FrictionRateRequest) async throws -> FrictionRateResponse
public var totalEffectiveLength: @Sendable (TotalEffectiveLengthRequest) async throws -> Int
public var equivalentRectangularDuct:
@Sendable (EquivalentRectangularDuctRequest) async throws -> EquivalentRectangularDuctResponse
// 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
// }
}
extension ManualDClient: TestDependencyKey {
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 {
public struct DuctSizeRequest: Codable, Equatable, Sendable {
public let designCFM: Int
public let frictionRate: Double
public init(
designCFM: Int,
frictionRate: Double
) {
self.designCFM = designCFM
self.frictionRate = frictionRate
}
}
public struct DuctSizeResponse: Codable, Equatable, Sendable {
public let ductulatorSize: Double
public let finalSize: Int
public let flexSize: Int
public let velocity: Int
public init(
ductulatorSize: Double,
finalSize: Int,
flexSize: Int,
velocity: Int
) {
self.ductulatorSize = ductulatorSize
self.finalSize = finalSize
self.flexSize = flexSize
self.velocity = velocity
}
}
}
// MARK: - Friction Rate
extension ManualDClient {
public struct FrictionRateRequest: Codable, Equatable, Sendable {
public let externalStaticPressure: Double
public let componentPressureLosses: [ComponentPressureLoss]
public let totalEffectiveLength: Int
public init(
externalStaticPressure: Double,
componentPressureLosses: [ComponentPressureLoss],
totalEffectiveLength: Int
) {
self.externalStaticPressure = externalStaticPressure
self.componentPressureLosses = componentPressureLosses
self.totalEffectiveLength = totalEffectiveLength
}
}
public struct FrictionRateResponse: Codable, Equatable, Sendable {
public let availableStaticPressure: Double
public let frictionRate: Double
public init(availableStaticPressure: Double, frictionRate: Double) {
self.availableStaticPressure = availableStaticPressure
self.frictionRate = frictionRate
}
}
}
// MARK: Total Effective Length
extension ManualDClient {
public struct TotalEffectiveLengthRequest: Codable, Equatable, Sendable {
public let trunkLengths: [Int]
public let runoutLengths: [Int]
public let effectiveLengthGroups: [EffectiveLengthGroup]
public init(
trunkLengths: [Int],
runoutLengths: [Int],
effectiveLengthGroups: [EffectiveLengthGroup]
) {
self.trunkLengths = trunkLengths
self.runoutLengths = runoutLengths
self.effectiveLengthGroups = effectiveLengthGroups
}
}
}
// MARK: Equivalent Rectangular Duct
extension ManualDClient {
public struct EquivalentRectangularDuctRequest: Codable, Equatable, Sendable {
public let roundSize: Int
public let height: Int
public init(round roundSize: Int, height: Int) {
self.roundSize = roundSize
self.height = height
}
}
public struct EquivalentRectangularDuctResponse: Codable, Equatable, Sendable {
public let height: Int
public let width: Int
public init(height: Int, width: Int) {
self.height = height
self.width = width
}
}
}