feat: Cleaning up shared models.
This commit is contained in:
@@ -27,7 +27,10 @@ public struct BudgetedPercentEnvelope: Equatable {
|
||||
coilBudget + filterBudget + supplyPlenumBudget + returnPlenumBudget
|
||||
}
|
||||
|
||||
public init(equipmentType: EquipmentType, fanType: FanType) {
|
||||
public init(
|
||||
equipmentType: EquipmentMeasurement.EquipmentType,
|
||||
fanType: EquipmentMetadata.FanType
|
||||
) {
|
||||
switch equipmentType {
|
||||
case .furnaceAndCoil:
|
||||
switch fanType {
|
||||
|
||||
@@ -1,43 +1,2 @@
|
||||
import Foundation
|
||||
|
||||
public enum CoolingCapacity: Double, Hashable, CaseIterable, Identifiable, CustomStringConvertible {
|
||||
case half = 0.5
|
||||
case threeQuarter = 0.75
|
||||
case one = 1
|
||||
case oneAndAHalf = 1.5
|
||||
case two = 2
|
||||
case twoAndAHalf = 2.5
|
||||
case three = 3
|
||||
case threeAndAHalf = 3.5
|
||||
case four = 4
|
||||
case five = 5
|
||||
|
||||
public var id: Self { self }
|
||||
|
||||
public static var `default`: Self { .three }
|
||||
|
||||
public var description: String {
|
||||
switch self {
|
||||
case .half:
|
||||
return "1/2 Ton"
|
||||
case .threeQuarter:
|
||||
return "3/4 Ton"
|
||||
case .one:
|
||||
return "1 Ton"
|
||||
case .oneAndAHalf:
|
||||
return "1.5 Tons"
|
||||
case .two:
|
||||
return "2 Tons"
|
||||
case .twoAndAHalf:
|
||||
return "2.5 Tons"
|
||||
case .three:
|
||||
return "3 Tons"
|
||||
case .threeAndAHalf:
|
||||
return "3.5 Tons"
|
||||
case .four:
|
||||
return "4 Tons"
|
||||
case .five:
|
||||
return "5 Tons"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ public enum EquipmentMeasurement: Equatable {
|
||||
|
||||
case airHandler(AirHandler)
|
||||
case furnaceAndCoil(FurnaceAndCoil)
|
||||
|
||||
|
||||
public var equipmentType: EquipmentType {
|
||||
switch self {
|
||||
case .airHandler:
|
||||
@@ -25,7 +25,7 @@ public enum EquipmentMeasurement: Equatable {
|
||||
return furnaceAndCoil.externalStaticPressure
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public struct AirHandler: Equatable {
|
||||
|
||||
@Positive
|
||||
@@ -70,6 +70,144 @@ public enum EquipmentMeasurement: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
public enum EquipmentType: Equatable, CaseIterable, CustomStringConvertible, Identifiable {
|
||||
case airHandler
|
||||
case furnaceAndCoil
|
||||
|
||||
public var id: Self { self }
|
||||
|
||||
public var description: String {
|
||||
switch self {
|
||||
case .airHandler:
|
||||
return "Air Handler"
|
||||
|
||||
case .furnaceAndCoil:
|
||||
return "Furnace & Coil"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Needs updated for when forms are using `minmal` values.
|
||||
public struct FlaggedMeasurement: Equatable {
|
||||
public var airflow: Flagged
|
||||
public var coilPressureDrop: Flagged
|
||||
public var externalStaticPressure: Flagged
|
||||
public var filterPressureDrop: Flagged
|
||||
public var returnPlenumPressure: Flagged
|
||||
public var supplyPlenumPressure: Flagged
|
||||
|
||||
public init(
|
||||
airflow: Flagged,
|
||||
coilPressureDrop: Flagged,
|
||||
externalStaticPressure: Flagged,
|
||||
filterPressureDrop: Flagged,
|
||||
returnPlenumPressure: Flagged,
|
||||
supplyPlenumPressure: Flagged
|
||||
) {
|
||||
self.airflow = airflow
|
||||
self.coilPressureDrop = coilPressureDrop
|
||||
self.externalStaticPressure = externalStaticPressure
|
||||
self.filterPressureDrop = filterPressureDrop
|
||||
self.returnPlenumPressure = returnPlenumPressure
|
||||
self.supplyPlenumPressure = supplyPlenumPressure
|
||||
}
|
||||
|
||||
public init(
|
||||
budgets: BudgetedPercentEnvelope,
|
||||
measurement: EquipmentMeasurement,
|
||||
ratedPressures: RatedStaticPressures,
|
||||
tons: EquipmentMetadata.CoolingCapacity?
|
||||
) {
|
||||
switch measurement {
|
||||
case let .airHandler(airHandler):
|
||||
self = .airHandler(
|
||||
budgets: budgets,
|
||||
measurement: airHandler,
|
||||
ratedPressures: ratedPressures,
|
||||
tons: tons
|
||||
)
|
||||
case let .furnaceAndCoil(furnaceAndCoil):
|
||||
self = .furnaceAndCoil(
|
||||
budgets: budgets,
|
||||
measurement: furnaceAndCoil,
|
||||
ratedPressures: ratedPressures,
|
||||
tons: tons
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
public static func airHandler(
|
||||
budgets: BudgetedPercentEnvelope,
|
||||
measurement: EquipmentMeasurement.AirHandler,
|
||||
ratedPressures: RatedStaticPressures,
|
||||
tons: EquipmentMetadata.CoolingCapacity?
|
||||
) -> Self {
|
||||
.init(
|
||||
airflow: checkAirflow(value: measurement.airflow, tons: tons),
|
||||
coilPressureDrop: .init(
|
||||
wrappedValue: (measurement.$postCoilPressure.positiveValue - measurement.$postFilterPressure.positiveValue) ?? 0,
|
||||
.result(.good())
|
||||
),
|
||||
externalStaticPressure: checkExternalStaticPressure(
|
||||
value: measurement.externalStaticPressure,
|
||||
ratedPressures: ratedPressures
|
||||
),
|
||||
filterPressureDrop: .init(
|
||||
value: measurement.$postFilterPressure.positiveValue - measurement.$returnPlenumPressure.positiveValue,
|
||||
budget: budgets.filterBudget,
|
||||
ratedPressures: ratedPressures
|
||||
),
|
||||
returnPlenumPressure: .init(
|
||||
value: measurement.$returnPlenumPressure.positiveValue,
|
||||
budget: budgets.returnPlenumBudget,
|
||||
ratedPressures: ratedPressures
|
||||
),
|
||||
supplyPlenumPressure: .init(
|
||||
value: measurement.$supplyPlenumPressure.positiveValue ?? 0,
|
||||
budget: budgets.supplyPlenumBudget,
|
||||
ratedPressures: ratedPressures
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
public static func furnaceAndCoil(
|
||||
budgets: BudgetedPercentEnvelope,
|
||||
measurement: EquipmentMeasurement.FurnaceAndCoil,
|
||||
ratedPressures: RatedStaticPressures,
|
||||
tons: EquipmentMetadata.CoolingCapacity?
|
||||
) -> Self {
|
||||
.init(
|
||||
airflow: checkAirflow(value: measurement.airflow, tons: tons),
|
||||
coilPressureDrop: .init(
|
||||
value: measurement.$preCoilPressure.positiveValue - measurement.$supplyPlenumPressure.positiveValue,
|
||||
budget: budgets.coilBudget,
|
||||
ratedPressures: ratedPressures
|
||||
),
|
||||
externalStaticPressure: checkExternalStaticPressure(
|
||||
value: measurement.externalStaticPressure,
|
||||
ratedPressures: ratedPressures
|
||||
),
|
||||
filterPressureDrop: .init(
|
||||
value: measurement.$postFilterPressure.positiveValue - measurement.$returnPlenumPressure.positiveValue,
|
||||
budget: budgets.filterBudget,
|
||||
ratedPressures: ratedPressures,
|
||||
ignoreMinimum: true
|
||||
),
|
||||
returnPlenumPressure: .init(
|
||||
value: measurement.$returnPlenumPressure.positiveValue,
|
||||
budget: budgets.returnPlenumBudget,
|
||||
ratedPressures: ratedPressures
|
||||
),
|
||||
supplyPlenumPressure: .init(
|
||||
value: measurement.$supplyPlenumPressure.positiveValue,
|
||||
budget: budgets.supplyPlenumBudget,
|
||||
ratedPressures: ratedPressures
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public struct FurnaceAndCoil: Equatable {
|
||||
|
||||
@Positive
|
||||
@@ -128,6 +266,62 @@ public enum EquipmentMeasurement: Equatable {
|
||||
// case airflow
|
||||
// }
|
||||
//}
|
||||
fileprivate extension Flagged {
|
||||
|
||||
init(
|
||||
value: Double,
|
||||
budget: Percentage,
|
||||
ratedPressures: RatedStaticPressures,
|
||||
ignoreMinimum: Bool = false
|
||||
) {
|
||||
let minimum = ignoreMinimum ? 0 : ratedPressures.minimum * budget.fraction
|
||||
let maximum = ratedPressures.maximum * budget.fraction
|
||||
let rated = ratedPressures.rated * budget.fraction
|
||||
self.init(
|
||||
wrappedValue: value,
|
||||
.using(maximum: maximum, minimum: minimum, rated: rated)
|
||||
)
|
||||
}
|
||||
|
||||
init(
|
||||
value: Double?,
|
||||
budget: Percentage,
|
||||
ratedPressures: RatedStaticPressures,
|
||||
ignoreMinimum: Bool = false
|
||||
) {
|
||||
guard let value else {
|
||||
self = .error(message: "Value is not set.")
|
||||
return
|
||||
}
|
||||
self.init(
|
||||
value: value,
|
||||
budget: budget,
|
||||
ratedPressures: ratedPressures,
|
||||
ignoreMinimum: ignoreMinimum
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func checkExternalStaticPressure(
|
||||
value: Double,
|
||||
ratedPressures: RatedStaticPressures
|
||||
) -> Flagged {
|
||||
.init(
|
||||
wrappedValue: value,
|
||||
.rated(ratedPressures)
|
||||
)
|
||||
}
|
||||
|
||||
fileprivate func checkAirflow(
|
||||
value: Double?,
|
||||
tons: EquipmentMetadata.CoolingCapacity?
|
||||
) -> Flagged {
|
||||
guard let value, let tons else {
|
||||
return .init(wrappedValue: value ?? 0, .result(.good()))
|
||||
}
|
||||
return .init(wrappedValue: value, .airflow(tons: tons))
|
||||
}
|
||||
|
||||
|
||||
#if DEBUG
|
||||
extension EquipmentMeasurement {
|
||||
@@ -153,4 +347,15 @@ extension EquipmentMeasurement {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension EquipmentMeasurement.FlaggedMeasurement {
|
||||
public static func mock(type equipmentType: EquipmentMeasurement.EquipmentType) -> Self {
|
||||
.init(
|
||||
budgets: .init(equipmentType: equipmentType, fanType: .variableSpeed),
|
||||
measurement: .mock(type: equipmentType),
|
||||
ratedPressures: .init(),
|
||||
tons: .default
|
||||
)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
76
Sources/SharedModels/EquipmentMetadata.swift
Normal file
76
Sources/SharedModels/EquipmentMetadata.swift
Normal file
@@ -0,0 +1,76 @@
|
||||
import Foundation
|
||||
|
||||
public struct EquipmentMetadata: Equatable {
|
||||
public var coolingCapacity: CoolingCapacity
|
||||
public var fanType: FanType
|
||||
public var ratedStaticPressure: RatedStaticPressures
|
||||
|
||||
public init(
|
||||
coolingCapacity: CoolingCapacity = .three,
|
||||
fanType: FanType = .constantSpeed,
|
||||
ratedStaticPressure: RatedStaticPressures = .init()
|
||||
) {
|
||||
self.coolingCapacity = coolingCapacity
|
||||
self.fanType = fanType
|
||||
self.ratedStaticPressure = ratedStaticPressure
|
||||
}
|
||||
|
||||
public enum CoolingCapacity: Double, Equatable, CaseIterable, Identifiable, CustomStringConvertible {
|
||||
case half = 0.5
|
||||
case threeQuarter = 0.75
|
||||
case one = 1
|
||||
case oneAndAHalf = 1.5
|
||||
case two = 2
|
||||
case twoAndAHalf = 2.5
|
||||
case three = 3
|
||||
case threeAndAHalf = 3.5
|
||||
case four = 4
|
||||
case five = 5
|
||||
|
||||
public var id: Self { self }
|
||||
|
||||
public static var `default`: Self { .three }
|
||||
|
||||
public var description: String {
|
||||
switch self {
|
||||
case .half:
|
||||
return "1/2 Ton"
|
||||
case .threeQuarter:
|
||||
return "3/4 Ton"
|
||||
case .one:
|
||||
return "1 Ton"
|
||||
case .oneAndAHalf:
|
||||
return "1.5 Tons"
|
||||
case .two:
|
||||
return "2 Tons"
|
||||
case .twoAndAHalf:
|
||||
return "2.5 Tons"
|
||||
case .three:
|
||||
return "3 Tons"
|
||||
case .threeAndAHalf:
|
||||
return "3.5 Tons"
|
||||
case .four:
|
||||
return "4 Tons"
|
||||
case .five:
|
||||
return "5 Tons"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum FanType: Hashable, Equatable, CaseIterable, CustomStringConvertible, Identifiable {
|
||||
case constantSpeed
|
||||
case variableSpeed
|
||||
|
||||
public var id: Self { self }
|
||||
public static var `default`: Self { .constantSpeed }
|
||||
|
||||
public var description: String {
|
||||
switch self {
|
||||
case .constantSpeed:
|
||||
return "Constant Speed"
|
||||
case .variableSpeed:
|
||||
return "Variable Speed"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import Foundation
|
||||
|
||||
public enum EquipmentType: Equatable, CaseIterable, CustomStringConvertible, Identifiable {
|
||||
case airHandler
|
||||
case furnaceAndCoil
|
||||
|
||||
public var id: Self { self }
|
||||
|
||||
public var description: String {
|
||||
switch self {
|
||||
case .airHandler:
|
||||
return "Air Handler"
|
||||
|
||||
case .furnaceAndCoil:
|
||||
return "Furnace & Coil"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
import Foundation
|
||||
|
||||
public enum FanType: Hashable, Equatable, CaseIterable, CustomStringConvertible, Identifiable {
|
||||
case constantSpeed
|
||||
case variableSpeed
|
||||
|
||||
public var id: Self { self }
|
||||
|
||||
public var description: String {
|
||||
switch self {
|
||||
case .constantSpeed:
|
||||
return "Constant Speed"
|
||||
case .variableSpeed:
|
||||
return "Variable Speed"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -151,11 +151,11 @@ extension Flagged.CheckHandler {
|
||||
}
|
||||
|
||||
public static func airflow(
|
||||
tons: CoolingCapacity,
|
||||
tons: EquipmentMetadata.CoolingCapacity,
|
||||
ratings: RatedAirflowPerTon = .init(),
|
||||
goodMessage: Flagged.GoodMessageHandler? = nil
|
||||
) -> Self {
|
||||
.rated(RatedAirflowLimits(tons: tons, using: ratings), goodMessage: goodMessage)
|
||||
.rated(RatedAirflowLimits(tons: tons, airflowPerTon: ratings), goodMessage: goodMessage)
|
||||
}
|
||||
|
||||
public static func percent(
|
||||
|
||||
@@ -1,190 +0,0 @@
|
||||
import Foundation
|
||||
|
||||
// TODO: Needs updated for when forms are using `minmal` values.
|
||||
public struct FlaggedEquipmentMeasurement: Equatable {
|
||||
public var airflow: Flagged
|
||||
public var coilPressureDrop: Flagged
|
||||
public var externalStaticPressure: Flagged
|
||||
public var filterPressureDrop: Flagged
|
||||
public var returnPlenumPressure: Flagged
|
||||
public var supplyPlenumPressure: Flagged
|
||||
|
||||
public init(
|
||||
airflow: Flagged,
|
||||
coilPressureDrop: Flagged,
|
||||
externalStaticPressure: Flagged,
|
||||
filterPressureDrop: Flagged,
|
||||
returnPlenumPressure: Flagged,
|
||||
supplyPlenumPressure: Flagged
|
||||
) {
|
||||
self.airflow = airflow
|
||||
self.coilPressureDrop = coilPressureDrop
|
||||
self.externalStaticPressure = externalStaticPressure
|
||||
self.filterPressureDrop = filterPressureDrop
|
||||
self.returnPlenumPressure = returnPlenumPressure
|
||||
self.supplyPlenumPressure = supplyPlenumPressure
|
||||
}
|
||||
|
||||
public init(
|
||||
budgets: BudgetedPercentEnvelope,
|
||||
measurement: EquipmentMeasurement,
|
||||
ratedPressures: RatedStaticPressures,
|
||||
tons: CoolingCapacity?
|
||||
) {
|
||||
switch measurement {
|
||||
case let .airHandler(airHandler):
|
||||
self = .airHandler(
|
||||
budgets: budgets,
|
||||
measurement: airHandler,
|
||||
ratedPressures: ratedPressures,
|
||||
tons: tons
|
||||
)
|
||||
case let .furnaceAndCoil(furnaceAndCoil):
|
||||
self = .furnaceAndCoil(
|
||||
budgets: budgets,
|
||||
measurement: furnaceAndCoil,
|
||||
ratedPressures: ratedPressures,
|
||||
tons: tons
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
public static func airHandler(
|
||||
budgets: BudgetedPercentEnvelope,
|
||||
measurement: EquipmentMeasurement.AirHandler,
|
||||
ratedPressures: RatedStaticPressures,
|
||||
tons: CoolingCapacity?
|
||||
) -> Self {
|
||||
.init(
|
||||
airflow: checkAirflow(value: measurement.airflow, tons: tons),
|
||||
coilPressureDrop: .init(
|
||||
wrappedValue: (measurement.$postCoilPressure.positiveValue - measurement.$postFilterPressure.positiveValue) ?? 0,
|
||||
.result(.good())
|
||||
),
|
||||
externalStaticPressure: checkExternalStaticPressure(
|
||||
value: measurement.externalStaticPressure,
|
||||
ratedPressures: ratedPressures
|
||||
),
|
||||
filterPressureDrop: .init(
|
||||
value: measurement.$postFilterPressure.positiveValue - measurement.$returnPlenumPressure.positiveValue,
|
||||
budget: budgets.filterBudget,
|
||||
ratedPressures: ratedPressures
|
||||
),
|
||||
returnPlenumPressure: .init(
|
||||
value: measurement.$returnPlenumPressure.positiveValue,
|
||||
budget: budgets.returnPlenumBudget,
|
||||
ratedPressures: ratedPressures
|
||||
),
|
||||
supplyPlenumPressure: .init(
|
||||
value: measurement.$supplyPlenumPressure.positiveValue ?? 0,
|
||||
budget: budgets.supplyPlenumBudget,
|
||||
ratedPressures: ratedPressures
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
public static func furnaceAndCoil(
|
||||
budgets: BudgetedPercentEnvelope,
|
||||
measurement: EquipmentMeasurement.FurnaceAndCoil,
|
||||
ratedPressures: RatedStaticPressures,
|
||||
tons: CoolingCapacity?
|
||||
) -> Self {
|
||||
.init(
|
||||
airflow: checkAirflow(value: measurement.airflow, tons: tons),
|
||||
coilPressureDrop: .init(
|
||||
value: measurement.$preCoilPressure.positiveValue - measurement.$supplyPlenumPressure.positiveValue,
|
||||
budget: budgets.coilBudget,
|
||||
ratedPressures: ratedPressures
|
||||
),
|
||||
externalStaticPressure: checkExternalStaticPressure(
|
||||
value: measurement.externalStaticPressure,
|
||||
ratedPressures: ratedPressures
|
||||
),
|
||||
filterPressureDrop: .init(
|
||||
value: measurement.$postFilterPressure.positiveValue - measurement.$returnPlenumPressure.positiveValue,
|
||||
budget: budgets.filterBudget,
|
||||
ratedPressures: ratedPressures,
|
||||
ignoreMinimum: true
|
||||
),
|
||||
returnPlenumPressure: .init(
|
||||
value: measurement.$returnPlenumPressure.positiveValue,
|
||||
budget: budgets.returnPlenumBudget,
|
||||
ratedPressures: ratedPressures
|
||||
),
|
||||
supplyPlenumPressure: .init(
|
||||
value: measurement.$supplyPlenumPressure.positiveValue,
|
||||
budget: budgets.supplyPlenumBudget,
|
||||
ratedPressures: ratedPressures
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Helpers
|
||||
#if DEBUG
|
||||
extension FlaggedEquipmentMeasurement {
|
||||
public static func mock(type equipmentType: EquipmentType) -> Self {
|
||||
.init(
|
||||
budgets: .init(equipmentType: equipmentType, fanType: .variableSpeed),
|
||||
measurement: .mock(type: equipmentType),
|
||||
ratedPressures: .init(),
|
||||
tons: .default
|
||||
)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
fileprivate extension Flagged {
|
||||
|
||||
init(
|
||||
value: Double,
|
||||
budget: Percentage,
|
||||
ratedPressures: RatedStaticPressures,
|
||||
ignoreMinimum: Bool = false
|
||||
) {
|
||||
let minimum = ignoreMinimum ? 0 : ratedPressures.minimum * budget.fraction
|
||||
let maximum = ratedPressures.maximum * budget.fraction
|
||||
let rated = ratedPressures.rated * budget.fraction
|
||||
self.init(
|
||||
wrappedValue: value,
|
||||
.using(maximum: maximum, minimum: minimum, rated: rated)
|
||||
)
|
||||
}
|
||||
|
||||
init(
|
||||
value: Double?,
|
||||
budget: Percentage,
|
||||
ratedPressures: RatedStaticPressures,
|
||||
ignoreMinimum: Bool = false
|
||||
) {
|
||||
guard let value else {
|
||||
self = .error(message: "Value is not set.")
|
||||
return
|
||||
}
|
||||
self.init(
|
||||
value: value,
|
||||
budget: budget,
|
||||
ratedPressures: ratedPressures,
|
||||
ignoreMinimum: ignoreMinimum
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func checkExternalStaticPressure(
|
||||
value: Double,
|
||||
ratedPressures: RatedStaticPressures
|
||||
) -> Flagged {
|
||||
.init(
|
||||
wrappedValue: value,
|
||||
.rated(ratedPressures)
|
||||
)
|
||||
}
|
||||
|
||||
fileprivate func checkAirflow(
|
||||
value: Double?,
|
||||
tons: CoolingCapacity?
|
||||
) -> Flagged {
|
||||
guard let value, let tons else {
|
||||
return .init(wrappedValue: value ?? 0, .result(.good()))
|
||||
}
|
||||
return .init(wrappedValue: value, .airflow(tons: tons))
|
||||
}
|
||||
@@ -40,7 +40,10 @@ extension RatedAirflowPerTon {
|
||||
// MARK: - Airflow Limits
|
||||
public typealias RatedAirflowLimits = RatedEnvelope<AirflowLimits>
|
||||
extension RatedAirflowLimits {
|
||||
public init(tons: CoolingCapacity, using airflowPerTon: RatedAirflowPerTon = .init()) {
|
||||
public init(
|
||||
tons: EquipmentMetadata.CoolingCapacity,
|
||||
airflowPerTon: RatedAirflowPerTon = .init()
|
||||
) {
|
||||
self.init(
|
||||
maximum: airflowPerTon.maximum * tons.rawValue,
|
||||
minimum: airflowPerTon.minimum * tons.rawValue,
|
||||
|
||||
Reference in New Issue
Block a user