201 lines
5.7 KiB
Swift
201 lines
5.7 KiB
Swift
import DatabaseClient
|
|
import Dependencies
|
|
import ManualDClient
|
|
import ManualDCore
|
|
|
|
extension DatabaseClient {
|
|
|
|
func calculateDuctSizes(
|
|
details: Project.Detail
|
|
) async throws -> (DuctSizes, DuctSizeSharedRequest) {
|
|
let (rooms, shared) = try await calculateRoomDuctSizes(details: details)
|
|
let (trunks, _) = try await calculateTrunkDuctSizes(details: details)
|
|
return (.init(rooms: rooms, trunks: trunks), shared)
|
|
}
|
|
|
|
func calculateDuctSizes(
|
|
projectID: Project.ID
|
|
) async throws -> (DuctSizes, DuctSizeSharedRequest, [Room]) {
|
|
@Dependency(\.manualD) var manualD
|
|
|
|
let shared = try await sharedDuctRequest(projectID)
|
|
let rooms = try await rooms.fetch(projectID)
|
|
|
|
return try await (
|
|
manualD.calculateDuctSizes(
|
|
rooms: rooms,
|
|
trunks: trunkSizes.fetch(projectID),
|
|
sharedRequest: shared
|
|
),
|
|
shared,
|
|
rooms
|
|
)
|
|
}
|
|
|
|
func calculateRoomDuctSizes(
|
|
details: Project.Detail
|
|
) async throws -> ([DuctSizes.RoomContainer], DuctSizeSharedRequest) {
|
|
@Dependency(\.manualD) var manualD
|
|
|
|
let shared = try sharedDuctRequest(details: details)
|
|
let rooms = try await manualD.calculateRoomSizes(rooms: details.rooms, sharedRequest: shared)
|
|
return (rooms, shared)
|
|
}
|
|
|
|
func calculateRoomDuctSizes(
|
|
projectID: Project.ID
|
|
) async throws -> ([DuctSizes.RoomContainer], DuctSizeSharedRequest) {
|
|
@Dependency(\.manualD) var manualD
|
|
|
|
let shared = try await sharedDuctRequest(projectID)
|
|
|
|
return try await (
|
|
manualD.calculateRoomSizes(
|
|
rooms: rooms.fetch(projectID),
|
|
sharedRequest: shared
|
|
),
|
|
shared
|
|
)
|
|
}
|
|
|
|
func calculateTrunkDuctSizes(
|
|
details: Project.Detail
|
|
) async throws -> ([DuctSizes.TrunkContainer], DuctSizeSharedRequest) {
|
|
@Dependency(\.manualD) var manualD
|
|
|
|
let shared = try sharedDuctRequest(details: details)
|
|
let trunks = try await manualD.calculateTrunkSizes(
|
|
rooms: details.rooms,
|
|
trunks: details.trunks,
|
|
sharedRequest: shared
|
|
)
|
|
return (trunks, shared)
|
|
}
|
|
|
|
func calculateTrunkDuctSizes(
|
|
projectID: Project.ID
|
|
) async throws -> ([DuctSizes.TrunkContainer], DuctSizeSharedRequest) {
|
|
@Dependency(\.manualD) var manualD
|
|
|
|
let shared = try await sharedDuctRequest(projectID)
|
|
|
|
return try await (
|
|
manualD.calculateTrunkSizes(
|
|
rooms: rooms.fetch(projectID),
|
|
trunks: trunkSizes.fetch(projectID),
|
|
sharedRequest: shared
|
|
),
|
|
shared
|
|
)
|
|
}
|
|
|
|
func sharedDuctRequest(details: Project.Detail) throws -> DuctSizeSharedRequest {
|
|
guard
|
|
let dfrResponse = designFrictionRate(
|
|
componentLosses: details.componentLosses,
|
|
equipmentInfo: details.equipmentInfo,
|
|
equivalentLengths: details.maxContainer
|
|
)
|
|
else {
|
|
throw ProjectClientError("Project not complete.")
|
|
}
|
|
|
|
guard let projectSHR = details.project.sensibleHeatRatio else {
|
|
throw ProjectClientError("Project sensible heat ratio not set.")
|
|
}
|
|
|
|
let ensuredTEL = try dfrResponse.ensureMaxContainer()
|
|
|
|
return .init(
|
|
equipmentInfo: dfrResponse.equipmentInfo,
|
|
maxSupplyLength: ensuredTEL.supply,
|
|
maxReturnLenght: ensuredTEL.return,
|
|
designFrictionRate: dfrResponse.designFrictionRate,
|
|
projectSHR: projectSHR
|
|
)
|
|
}
|
|
|
|
func sharedDuctRequest(_ projectID: Project.ID) async throws -> DuctSizeSharedRequest {
|
|
|
|
guard let dfrResponse = try await designFrictionRate(projectID: projectID) else {
|
|
throw ProjectClientError("Project not complete.")
|
|
}
|
|
|
|
let ensuredTEL = try dfrResponse.ensureMaxContainer()
|
|
|
|
return try await .init(
|
|
equipmentInfo: dfrResponse.equipmentInfo,
|
|
maxSupplyLength: ensuredTEL.supply,
|
|
maxReturnLenght: ensuredTEL.return,
|
|
designFrictionRate: dfrResponse.designFrictionRate,
|
|
projectSHR: ensuredSHR(projectID)
|
|
)
|
|
|
|
}
|
|
|
|
// Fetches the project sensible heat ratio or throws an error if it's nil.
|
|
func ensuredSHR(_ projectID: Project.ID) async throws -> Double {
|
|
guard let projectSHR = try await projects.getSensibleHeatRatio(projectID) else {
|
|
throw ProjectClientError("Project sensible heat ratio not set.")
|
|
}
|
|
return projectSHR
|
|
}
|
|
|
|
// Internal container.
|
|
struct DesignFrictionRateResponse: Equatable, Sendable {
|
|
|
|
typealias EnsuredTEL = (supply: EquivalentLength, return: EquivalentLength)
|
|
|
|
let designFrictionRate: Double
|
|
let equipmentInfo: EquipmentInfo
|
|
let telMaxContainer: EquivalentLength.MaxContainer
|
|
|
|
func ensureMaxContainer() throws -> EnsuredTEL {
|
|
|
|
guard let maxSupplyLength = telMaxContainer.supply else {
|
|
throw ProjectClientError("Max supply TEL not found")
|
|
}
|
|
guard let maxReturnLength = telMaxContainer.return else {
|
|
throw ProjectClientError("Max supply TEL not found")
|
|
}
|
|
|
|
return (maxSupplyLength, maxReturnLength)
|
|
|
|
}
|
|
}
|
|
|
|
func designFrictionRate(
|
|
componentLosses: [ComponentPressureLoss],
|
|
equipmentInfo: EquipmentInfo,
|
|
equivalentLengths: EquivalentLength.MaxContainer
|
|
) -> DesignFrictionRateResponse? {
|
|
guard let tel = equivalentLengths.totalEquivalentLength,
|
|
componentLosses.count > 0
|
|
else { return nil }
|
|
|
|
let availableStaticPressure = equipmentInfo.staticPressure - componentLosses.total
|
|
|
|
return .init(
|
|
designFrictionRate: (availableStaticPressure * 100) / tel,
|
|
equipmentInfo: equipmentInfo,
|
|
telMaxContainer: equivalentLengths
|
|
)
|
|
|
|
}
|
|
|
|
func designFrictionRate(
|
|
projectID: Project.ID
|
|
) async throws -> DesignFrictionRateResponse? {
|
|
|
|
guard let equipmentInfo = try await equipment.fetch(projectID) else {
|
|
return nil
|
|
}
|
|
|
|
return try await designFrictionRate(
|
|
componentLosses: componentLosses.fetch(projectID),
|
|
equipmentInfo: equipmentInfo,
|
|
equivalentLengths: equivalentLengths.fetchMax(projectID)
|
|
)
|
|
}
|
|
}
|