/// Holds onto values returned when calculating the design /// friction rate for a project. /// /// **NOTE:** This is not stored in the database, it is calculated on the fly. public struct FrictionRate: Codable, Equatable, Sendable { /// The available static pressure is the equipment's design static pressure /// minus the ``ComponentPressureLoss``es for the project. public let availableStaticPressure: Double /// The calculated design friction rate value. public let value: Double /// Whether the design friction rate is within a valid range. public var hasErrors: Bool { error != nil } public init( availableStaticPressure: Double, value: Double ) { self.availableStaticPressure = availableStaticPressure self.value = value } /// The error if the design friction rate is out of a valid range. public var error: FrictionRateError? { if value >= 0.18 { return .init( "Friction rate should be lower than 0.18", resolutions: [ "Decrease the blower speed", "Decrease the blower size", "Increase the Total Equivalent Length", ] ) } else if value <= 0.02 { return .init( "Friction rate should be higher than 0.02", resolutions: [ "Increase the blower speed", "Increase the blower size", "Decrease the Total Equivalent Length", ] ) } return nil } } /// Represents an error when the ``FrictionRate`` is out of a valid range. /// /// This holds onto the reason for the error as well as possible resolutions. public struct FrictionRateError: Error, Equatable, Sendable { /// The reason for the error. public let reason: String /// The possible resolutions to the error. public let resolutions: [String] public init( _ reason: String, resolutions: [String] ) { self.reason = reason self.resolutions = resolutions } } #if DEBUG extension FrictionRate { public static let mock = Self(availableStaticPressure: 0.21, value: 0.11) } #endif