305 lines
9.3 KiB
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
|
|
}
|
|
}
|
|
}
|