Просмотр исходного кода

Merge branch 'oref-swift-small-determine-basal-test-fix' into oref-swift

Sam King 10 месяцев назад
Родитель
Сommit
c13803731a

+ 2 - 2
Trio/Sources/APS/OpenAPSSwift/DetermineBasal/DetermineBasal+Helpers.swift

@@ -57,7 +57,7 @@ extension DeterminationGenerator {
             // only use readings >38 mg/dL (to skip code values, <39)
             guard entry.glucose > 38 else { continue }
 
-            let minutesAgo = mostRecentGlucoseDate.timeIntervalSince(entry.date) / 60
+            let minutesAgo = (mostRecentGlucoseDate.timeIntervalSince(entry.date) / 60).rounded()
             guard minutesAgo != 0 else { continue }
             // compute mg/dL per 5 m as a Decimal:
             let change = Decimal(mostRecentGlucoseReading - entry.glucose)
@@ -115,7 +115,7 @@ extension DeterminationGenerator {
 
         let fiveMinuteBlocks = Decimal((2 * 60) / 5)
         let delta = targetGlucose - eventualGlucose
-        return (glucoseImpact + (delta / fiveMinuteBlocks)).rounded(toPlaces: 1)
+        return (glucoseImpact + (delta / fiveMinuteBlocks)).jsRounded(scale: 1)
     }
 
     /// Determines whether SMBs are enabled based on profile settings,

+ 1 - 4
Trio/Sources/APS/OpenAPSSwift/DetermineBasal/DetermineBasalGenerator.swift

@@ -151,7 +151,7 @@ enum DeterminationGenerator {
             withZeroTemp: true
         )
 
-        guard let currentGlucoseImpact = glucoseImpactSeries.first else {
+        guard let currentGlucoseImpact = glucoseImpactSeries.first?.jsRounded(scale: 2) else {
             throw DeterminationError.determinationError
         }
 
@@ -278,9 +278,6 @@ enum DeterminationGenerator {
         if glucoseStatus.glucose < 39 || glucoseStatus.glucose > 600 {
             throw DeterminationError.glucoseOutOfRange(glucose: glucoseStatus.glucose)
         }
-        if glucoseStatus.delta == 0 {
-            throw DeterminationError.noDelta
-        }
         guard let _ = iobData else {
             throw DeterminationError.missingIob
         }

+ 3 - 3
Trio/Sources/APS/OpenAPSSwift/Forecasts/ForecastGenerator.swift

@@ -16,10 +16,10 @@ enum ForecastGenerator {
         threshold: Decimal,
         currentTime: Date
     ) -> ForecastResult {
-        let carbImpact = mealData
-            .currentDeviation * (profile.carbRatio ?? profile.carbRatioFor(time: currentTime)) /
+        let currentDeviation = mealData.currentDeviation ?? 0
+        let carbImpact = currentDeviation * (profile.carbRatio ?? profile.carbRatioFor(time: currentTime)) /
             (profile.sens ?? profile.sensitivityFor(time: currentTime))
-        let deviation = mealData.currentDeviation
+        let deviation = currentDeviation
 
         // JS oref initializes all xxxPredBGs array with current glucose, we do the same, then generate
         let iobForecast = [glucose] + forecastIOB(

+ 6 - 2
Trio/Sources/APS/OpenAPSSwift/Logging/OrefFunction.swift

@@ -72,7 +72,10 @@ enum OrefFunction: String, Codable {
                 // in Swift but not in JS
                 "timestamp",
                 "minGuardBG",
-                "minPredBG"
+                "minPredBG",
+                // We haven't implemented DynamicISF support for forecasting yet
+                "predBGs",
+                "eventualBG"
             ])
         }
     }
@@ -113,7 +116,8 @@ enum OrefFunction: String, Codable {
             ]
         case .determineBasal:
             return [
-                "sensitivityRatio": 0.011 // consistent with Autosens
+                "sensitivityRatio": 0.011,
+                "expectedDelta": 0.11
             ]
         }
     }

+ 34 - 2
Trio/Sources/APS/OpenAPSSwift/Meal/MealTotal.swift

@@ -3,13 +3,43 @@ import Foundation
 struct ComputedCarbs: Codable {
     var carbs: Decimal
     var mealCOB: Decimal
-    var currentDeviation: Decimal
+    var currentDeviation: Decimal?
     var maxDeviation: Decimal
     var minDeviation: Decimal
     var slopeFromMaxDeviation: Decimal
     var slopeFromMinDeviation: Decimal
     var allDeviations: [Decimal]
     var lastCarbTime: TimeInterval
+
+    enum CodingKeys: String, CodingKey {
+        case carbs
+        case mealCOB
+        case currentDeviation
+        case maxDeviation
+        case minDeviation
+        case slopeFromMaxDeviation
+        case slopeFromMinDeviation
+        case allDeviations
+        case lastCarbTime
+    }
+
+    func encode(to encoder: Encoder) throws {
+        var container = encoder.container(keyedBy: CodingKeys.self)
+        try container.encode(carbs, forKey: .carbs)
+        try container.encode(mealCOB, forKey: .mealCOB)
+        try container.encode(maxDeviation, forKey: .maxDeviation)
+        try container.encode(minDeviation, forKey: .minDeviation)
+        try container.encode(slopeFromMaxDeviation, forKey: .slopeFromMaxDeviation)
+        try container.encode(slopeFromMinDeviation, forKey: .slopeFromMinDeviation)
+        try container.encode(allDeviations, forKey: .allDeviations)
+        try container.encode(lastCarbTime, forKey: .lastCarbTime)
+
+        if let currentDeviation = currentDeviation {
+            try container.encode(currentDeviation, forKey: .currentDeviation)
+        } else {
+            try container.encodeNil(forKey: .currentDeviation)
+        }
+    }
 }
 
 struct IOBInput {
@@ -165,10 +195,12 @@ enum MealTotal {
             mealCOB = 0
         }
 
+        let currentDeviation = finalCobResult.allDeviations.isEmpty ? nil : finalCobResult.currentDeviation.rounded(scale: 2)
+
         return ComputedCarbs(
             carbs: carbs,
             mealCOB: mealCOB,
-            currentDeviation: finalCobResult.currentDeviation.rounded(scale: 2),
+            currentDeviation: currentDeviation,
             maxDeviation: finalCobResult.maxDeviation.rounded(scale: 2),
             minDeviation: finalCobResult.minDeviation.rounded(scale: 2),
             slopeFromMaxDeviation: finalCobResult.slopeFromMaxDeviation.rounded(scale: 3),

+ 5 - 5
TrioTests/OpenAPSSwiftTests/MealTotalTests.swift

@@ -97,7 +97,7 @@ import Testing
         #expect(result!.mealCOB.isWithin(0.5, of: 10) == true, "mealCOB: \(result!.mealCOB.description)")
         #expect(
             result!.currentDeviation == 3.6,
-            "currentDeviation: \(result!.currentDeviation.description)"
+            "currentDeviation: \(result!.currentDeviation!.description)"
         )
     }
 
@@ -172,8 +172,8 @@ import Testing
         #expect(result != nil)
         #expect(result!.carbs == 20)
         #expect(
-            result!.currentDeviation.isWithin(0.02, of: 0.67) == true,
-            "currentDeviation: \(result!.currentDeviation.description)"
+            result!.currentDeviation!.isWithin(0.02, of: 0.67) == true,
+            "currentDeviation: \(result!.currentDeviation!.description)"
         )
         #expect(result!.mealCOB.isWithin(0.25, of: 14) == true, "mealCOB: \(result!.mealCOB.description)")
     }
@@ -226,8 +226,8 @@ import Testing
         #expect(result?.carbs == 0)
         #expect(result?.mealCOB == 0)
         #expect(
-            result?.currentDeviation.isWithin(0.02, of: 0.67) == true,
-            "currentDeviation: \(result!.currentDeviation.description)"
+            result?.currentDeviation!.isWithin(0.02, of: 0.67) == true,
+            "currentDeviation: \(result!.currentDeviation!.description)"
         )
     }
 

+ 31 - 29
TrioTests/OpenAPSSwiftTests/utils/OpenAPSFixed.swift

@@ -42,38 +42,40 @@ final class OpenAPSFixed {
         clock: Date
     ) async throws -> OrefFunctionResult {
         do {
-            let worker = JavaScriptWorker(poolSize: 1)
+            let jsWorker = JavaScriptWorker(poolSize: 1)
             let testBundle = Bundle(for: OpenAPSFixed.self)
             let result = try await withCheckedThrowingContinuation { continuation in
-                worker.evaluateBatch(scripts: [
-                    Script(name: "prepare/log.js"),
-                    Script.fromTestingBundle(name: "determine-basal-prepare.js", bundle: testBundle),
-                    Script.fromTestingBundle(name: "basal-set-temp.js", bundle: testBundle),
-                    Script.fromTestingBundle(name: "glucose-get-last.js", bundle: testBundle),
-                    Script.fromTestingBundle(name: "determine-basal.js", bundle: testBundle)
-                ])
-
-                if let middleware = self.middlewareScript(name: OpenAPS.Middleware.determineBasal) {
-                    worker.evaluate(script: middleware)
+                jsWorker.inCommonContext { worker in
+                    worker.evaluateBatch(scripts: [
+                        Script(name: "prepare/log.js"),
+                        Script.fromTestingBundle(name: "determine-basal-prepare.js", bundle: testBundle),
+                        Script.fromTestingBundle(name: "basal-set-temp.js", bundle: testBundle),
+                        Script.fromTestingBundle(name: "glucose-get-last.js", bundle: testBundle),
+                        Script.fromTestingBundle(name: "determine-basal.js", bundle: testBundle)
+                    ])
+                    
+                    if let middleware = self.middlewareScript(name: OpenAPS.Middleware.determineBasal) {
+                        worker.evaluate(script: middleware)
+                    }
+                    
+                    let result = worker.call(function: "generate", with: [
+                        iob,
+                        currentTemp,
+                        glucose,
+                        profile,
+                        autosens,
+                        meal,
+                        microBolusAllowed,
+                        reservoir,
+                        clock,
+                        pumpHistory,
+                        preferences,
+                        basalProfile,
+                        trioCustomOrefVariables
+                    ])
+                    
+                    continuation.resume(returning: result)
                 }
-
-                let result = worker.call(function: "generate", with: [
-                    iob,
-                    currentTemp,
-                    glucose,
-                    profile,
-                    autosens,
-                    meal,
-                    microBolusAllowed,
-                    reservoir,
-                    clock,
-                    pumpHistory,
-                    preferences,
-                    basalProfile,
-                    trioCustomOrefVariables
-                ])
-
-                continuation.resume(returning: result)
             }
             return .success(result)
         } catch {