import Models import Validations extension FurnaceInterpolation.Request { private static let undersizingLimit = 90 private static let oversizingLimit = 140 func respond() async throws -> FurnaceInterpolation.Response { try await validate() let altitudeDerating = try await altitudeDerating() let outputCapacity = Int( (Double(inputRating) * (altitudeDerating ?? 1.0)) * (afue / 100) ) let capacityAsPercentOfLoad = normalizePercentage(outputCapacity, heatLoss) var failures = [String]() if capacityAsPercentOfLoad < Self.undersizingLimit { failures.append("Undersizing failure.") } if capacityAsPercentOfLoad > Self.oversizingLimit { failures.append("Oversizing failure.") } return .init( failures: failures.isEmpty ? nil : failures, altitudeAdjustmentMultiplier: altitudeDerating, capacityAsPercentOfLoad: capacityAsPercentOfLoad, oversizingLimit: Self.oversizingLimit, undersizingLimit: Self.undersizingLimit, outputCapacity: outputCapacity ) } func altitudeDerating() async throws -> Double? { guard let elevation else { return nil } let response = try await Derating.Request( elevation: elevation, systemType: .heatingOnly(type: .furnace) ).respond() return response.heating } } extension FurnaceInterpolation.Request: AsyncValidatable { public var body: some AsyncValidation { AsyncValidator.accumulating { AsyncValidator.greaterThan(\.heatLoss, 0) AsyncValidator.greaterThan(\.inputRating, 0) AsyncValidator.greaterThan(\.afue, 0) AsyncValidator.lessThan(\.afue, 100) } } }