Browse Source

Added most of the logging infrastructure with some FIXMEs left there to finish it up

Sam King 11 months ago
parent
commit
1b8440db81

+ 107 - 30
Trio/Sources/APS/OpenAPS/OpenAPS.swift

@@ -371,7 +371,8 @@ final class OpenAPS {
             pumpHistory: pumpHistoryJSON,
             preferences: preferences,
             basalProfile: basalProfile,
-            trioCustomOrefVariables: trioCustomOrefVariables
+            trioCustomOrefVariables: trioCustomOrefVariables,
+            useSwiftOref: useSwiftOref
         )
 
         debug(.openAPS, "\(simulation ? "[SIMULATION]" : "") OREF DETERMINATION: \(orefDetermination)")
@@ -777,40 +778,116 @@ final class OpenAPS {
         pumpHistory: JSON,
         preferences: JSON,
         basalProfile: JSON,
-        trioCustomOrefVariables: JSON
+        trioCustomOrefVariables: JSON,
+        useSwiftOref: Bool
     ) async throws -> RawJSON {
-        try await withCheckedThrowingContinuation { continuation in
-            jsWorker.inCommonContext { worker in
-                worker.evaluateBatch(scripts: [
-                    Script(name: Prepare.log),
-                    Script(name: Prepare.determineBasal),
-                    Script(name: Bundle.basalSetTemp),
-                    Script(name: Bundle.getLastGlucose),
-                    Script(name: Bundle.determineBasal)
-                ])
+        let clock = Date()
+        let startJavascriptAt = Date()
+        let jsResult = await determineBasalJavascript(
+            glucose: glucose,
+            currentTemp: currentTemp,
+            iob: iob,
+            profile: profile,
+            autosens: autosens,
+            meal: meal,
+            microBolusAllowed: microBolusAllowed,
+            reservoir: reservoir,
+            pumpHistory: pumpHistory,
+            preferences: preferences,
+            basalProfile: basalProfile,
+            trioCustomOrefVariables: trioCustomOrefVariables,
+            clock: clock
+        )
+        let javascriptDuration = Date().timeIntervalSince(startJavascriptAt)
 
-                if let middleware = self.middlewareScript(name: OpenAPS.Middleware.determineBasal) {
-                    worker.evaluate(script: middleware)
-                }
+        // Important: we want to make sure that this flag ensures that none
+        // of the native code runs
+        guard useSwiftOref else {
+            return try jsResult.returnOrThrow()
+        }
 
-                let result = worker.call(function: Function.generate, with: [
-                    iob,
-                    currentTemp,
-                    glucose,
-                    profile,
-                    autosens,
-                    meal,
-                    microBolusAllowed,
-                    reservoir,
-                    Date(),
-                    pumpHistory,
-                    preferences,
-                    basalProfile,
-                    trioCustomOrefVariables
-                ])
+        let startSwiftAt = Date()
+        let (swiftResult, determineBasalInputs) = OpenAPSSwift.determineBasal(
+            glucose: glucose,
+            currentTemp: currentTemp,
+            iob: iob,
+            profile: profile,
+            autosens: autosens,
+            meal: meal,
+            microBolusAllowed: microBolusAllowed,
+            reservoir: reservoir,
+            pumpHistory: pumpHistory,
+            preferences: preferences,
+            basalProfile: basalProfile,
+            trioCustomOrefVariables: trioCustomOrefVariables,
+            clock: clock
+        )
+        let swiftDuration = Date().timeIntervalSince(startSwiftAt)
 
-                continuation.resume(returning: result)
+        JSONCompare.logDifferences(
+            function: .determineBasal,
+            swift: swiftResult,
+            swiftDuration: swiftDuration,
+            javascript: jsResult,
+            javascriptDuration: javascriptDuration,
+            determineBasalInputs: determineBasalInputs
+        )
+
+        return try jsResult.returnOrThrow()
+    }
+
+    private func determineBasalJavascript(
+        glucose: JSON,
+        currentTemp: JSON,
+        iob: JSON,
+        profile: JSON,
+        autosens: JSON,
+        meal: JSON,
+        microBolusAllowed: Bool,
+        reservoir: JSON,
+        pumpHistory: JSON,
+        preferences: JSON,
+        basalProfile: JSON,
+        trioCustomOrefVariables: JSON,
+        clock: Date
+    ) async -> OrefFunctionResult {
+        do {
+            let result = try await withCheckedThrowingContinuation { continuation in
+                jsWorker.inCommonContext { worker in
+                    worker.evaluateBatch(scripts: [
+                        Script(name: Prepare.log),
+                        Script(name: Prepare.determineBasal),
+                        Script(name: Bundle.basalSetTemp),
+                        Script(name: Bundle.getLastGlucose),
+                        Script(name: Bundle.determineBasal)
+                    ])
+
+                    if let middleware = self.middlewareScript(name: OpenAPS.Middleware.determineBasal) {
+                        worker.evaluate(script: middleware)
+                    }
+
+                    let result = worker.call(function: Function.generate, with: [
+                        iob,
+                        currentTemp,
+                        glucose,
+                        profile,
+                        autosens,
+                        meal,
+                        microBolusAllowed,
+                        reservoir,
+                        clock,
+                        pumpHistory,
+                        preferences,
+                        basalProfile,
+                        trioCustomOrefVariables
+                    ])
+
+                    continuation.resume(returning: result)
+                }
             }
+            return .success(result)
+        } catch {
+            return .failure(error)
         }
     }
 

+ 8 - 0
Trio/Sources/APS/OpenAPSSwift/JSONBridge.swift

@@ -52,6 +52,10 @@ enum JSONBridge {
         try JSONBridge.from(string: from.rawJSON)
     }
 
+    static func iobResult(from: JSON) throws -> [IobResult] {
+        try JSONBridge.from(string: from.rawJSON)
+    }
+
     static func pumpHistory(from: JSON) throws -> [PumpHistoryEvent] {
         do {
             return try JSONBridge.from(string: from.rawJSON)
@@ -75,6 +79,10 @@ enum JSONBridge {
         try JSONBridge.from(string: from.rawJSON)
     }
 
+    static func computedCarbs(from: JSON) throws -> ComputedCarbs? {
+        try JSONBridge.from(string: from.rawJSON)
+    }
+
     static func autosens(from: JSON) throws -> Autosens? {
         try JSONBridge.from(string: from.rawJSON)
     }

+ 21 - 1
Trio/Sources/APS/OpenAPSSwift/Logging/AlgorithmComparison.swift

@@ -81,6 +81,23 @@ struct MealInputs: Codable {
     let glucose: [BloodGlucose]
 }
 
+struct DetermineBasalInputs: Codable {
+    // FIXME: Fill in the rest of these properties
+    let glucose: [BloodGlucose]
+    // currentTemp
+    let iob: [IobResult]
+    let profile: Profile
+    let autosens: Autosens?
+    let meal: ComputedCarbs?
+    let microBolusAllowed: Bool
+    // reservoir: JSON
+    let pumpHistory: [PumpHistoryEvent]
+    let preferences: Preferences
+    let basalProfile: [BasalProfileEntry]
+    // trioCustomOrefVariables: JSON
+    let clock: Date
+}
+
 /// Represents a complete comparison between JS and Swift implementations
 struct AlgorithmComparison: Codable {
     let id: UUID
@@ -107,6 +124,7 @@ struct AlgorithmComparison: Codable {
     // Inputs for mismatches
     let iobInput: IobInputs?
     let mealInput: MealInputs?
+    let determineBasalInput: DetermineBasalInputs?
 
     init(
         function: OrefFunction,
@@ -119,6 +137,7 @@ struct AlgorithmComparison: Codable {
         comparisonError: AlgorithmException? = nil,
         iobInputs: IobInputs? = nil,
         mealInputs: MealInputs? = nil,
+        determineBasalInputs: DetermineBasalInputs? = nil,
         id: UUID = UUID(),
         createdAt: Date = Date()
     ) {
@@ -134,8 +153,9 @@ struct AlgorithmComparison: Codable {
         self.comparisonError = comparisonError
         iobInput = iobInputs
         mealInput = mealInputs
+        determineBasalInput = determineBasalInputs
         timezone = TimeZone.current.identifier
-        version = "3"
+        version = "4"
 
         #if targetEnvironment(simulator)
             isSimulator = true

+ 12 - 6
Trio/Sources/APS/OpenAPSSwift/Logging/JSONCompare.swift

@@ -85,7 +85,8 @@ enum JSONCompare {
         javascript: OrefFunctionResult,
         javascriptDuration: TimeInterval,
         iobInputs: IobInputs? = nil,
-        mealInputs: MealInputs? = nil
+        mealInputs: MealInputs? = nil,
+        determineBasalInputs: DetermineBasalInputs? = nil
     ) {
         let comparison = createComparison(
             function: function,
@@ -94,7 +95,8 @@ enum JSONCompare {
             javascript: javascript,
             javascriptDuration: javascriptDuration,
             iobInputs: iobInputs,
-            mealInputs: mealInputs
+            mealInputs: mealInputs,
+            determineBasalInputs: determineBasalInputs
         )
 
         Task {
@@ -113,7 +115,8 @@ enum JSONCompare {
         javascript: OrefFunctionResult,
         javascriptDuration: TimeInterval,
         iobInputs: IobInputs?,
-        mealInputs: MealInputs?
+        mealInputs: MealInputs?,
+        determineBasalInputs: DetermineBasalInputs?
     ) -> AlgorithmComparison {
         switch (swift, javascript) {
         case let (.success(swiftJson), .success(javascriptJson)):
@@ -127,7 +130,8 @@ enum JSONCompare {
                     swiftDuration: swiftDuration,
                     differences: differences.isEmpty ? nil : differences,
                     iobInputs: differences.isEmpty ? nil : iobInputs,
-                    mealInputs: differences.isEmpty ? nil : mealInputs
+                    mealInputs: differences.isEmpty ? nil : mealInputs,
+                    determineBasalInputs: differences.isEmpty ? nil : determineBasalInputs
                 )
             } catch {
                 return AlgorithmComparison(
@@ -154,7 +158,8 @@ enum JSONCompare {
                 jsDuration: javascriptDuration,
                 swiftException: AlgorithmException(error: swiftError),
                 iobInputs: iobInputs,
-                mealInputs: mealInputs
+                mealInputs: mealInputs,
+                determineBasalInputs: determineBasalInputs
             )
 
         case let (.success, .failure(jsError)):
@@ -164,7 +169,8 @@ enum JSONCompare {
                 swiftDuration: swiftDuration,
                 jsException: AlgorithmException(error: jsError),
                 iobInputs: iobInputs,
-                mealInputs: mealInputs
+                mealInputs: mealInputs,
+                determineBasalInputs: determineBasalInputs
             )
         }
     }

+ 8 - 0
Trio/Sources/APS/OpenAPSSwift/Logging/OrefFunction.swift

@@ -24,6 +24,7 @@ enum OrefFunction: String, Codable {
     case makeProfile
     case iob
     case meal
+    case determineBasal
 
     // since we're removing some keys from our Profile that exist in Javascript
     // we need to let the difference function know which keys to ignore when
@@ -39,6 +40,9 @@ enum OrefFunction: String, Codable {
             // These aren't used by downstream calculations, so we
             // can ignore them in our comparison
             return Set(["maxDeviation", "minDeviation", "allDeviations", "bwCarbs", "bwFound", "journalCarbs", "nsCarbs"])
+        case .determineBasal:
+            // FIXME: Fill in the properties we don't check here
+            return Set()
         }
     }
 
@@ -71,6 +75,8 @@ enum OrefFunction: String, Codable {
                 "slopeFromMinDeviation": 0.25,
                 "lastCarbTime": 1
             ]
+        case .determineBasal:
+            return [:]
         }
     }
 
@@ -82,6 +88,8 @@ enum OrefFunction: String, Codable {
             return .array
         case .meal:
             return .dictionary
+        case .determineBasal:
+            return .dictionary
         }
     }
 }

+ 58 - 0
Trio/Sources/APS/OpenAPSSwift/OpenAPSSwift.swift

@@ -41,6 +41,64 @@ struct OpenAPSSwift {
         }
     }
 
+    static func determineBasal(
+        glucose: JSON,
+        currentTemp _: JSON,
+        iob: JSON,
+        profile: JSON,
+        autosens: JSON,
+        meal: JSON,
+        microBolusAllowed: Bool,
+        reservoir _: JSON,
+        pumpHistory: JSON,
+        preferences: JSON,
+        basalProfile: JSON,
+        trioCustomOrefVariables _: JSON,
+        clock: Date
+    ) -> (OrefFunctionResult, DetermineBasalInputs?) {
+        var determineBasalInputs: DetermineBasalInputs?
+
+        do {
+            // FIXME: figure out the types for the commented out vars
+            let glucose = try JSONBridge.glucose(from: glucose)
+            // currentTemp: JSON,
+            let iob = try JSONBridge.iobResult(from: iob)
+            let profile = try JSONBridge.profile(from: profile)
+            let autosens = try JSONBridge.autosens(from: autosens)
+            let meal = try JSONBridge.computedCarbs(from: meal)
+            let microBolusAllowed = microBolusAllowed
+            // reservoir: JSON
+            let pumpHistory = try JSONBridge.pumpHistory(from: pumpHistory)
+            let preferences = try JSONBridge.preferences(from: preferences)
+            let basalProfile = try JSONBridge.basalProfile(from: basalProfile)
+            // trioCustomOrefVariables: JSON
+
+            determineBasalInputs = DetermineBasalInputs(
+                glucose: glucose,
+                iob: iob,
+                profile: profile,
+                autosens: autosens,
+                meal: meal,
+                microBolusAllowed: microBolusAllowed,
+                pumpHistory: pumpHistory,
+                preferences: preferences,
+                basalProfile: basalProfile,
+                clock: clock
+            )
+
+            /*
+             let result = DeterminationGenerator.generate(profile: profile, currentTemp: <#T##TempBasal#>, iobData: iob, mealData: meal, autosensData: autosens, reservoirData: <#T##Reservoir#>, glucoseStatus: <#T##GlucoseStatus?#>, currentTime: clock)
+              */
+
+            // FIXME: fill in with result once we have it
+            // return (.success(JSONBridge.to(result)), determineBasalInputs)
+            return (.success(RawJSON.null), determineBasalInputs)
+
+        } catch {
+            return (.failure(error), determineBasalInputs)
+        }
+    }
+
     static func meal(
         pumphistory: JSON,
         profile: JSON,

+ 4 - 2
TrioTests/OpenAPSSwiftTests/IobJsonTests.swift

@@ -90,7 +90,8 @@ import Testing
             javascript: iobResultJavascript,
             javascriptDuration: 0.1,
             iobInputs: nil,
-            mealInputs: nil
+            mealInputs: nil,
+            determineBasalInputs: nil
         )
 
         if comparison.resultType == .valueDifference {
@@ -127,7 +128,8 @@ import Testing
             javascript: iobResultJavascript,
             javascriptDuration: 0.1,
             iobInputs: nil,
-            mealInputs: nil
+            mealInputs: nil,
+            determineBasalInputs: nil
         )
 
         if comparison.resultType != .valueDifference {

+ 2 - 1
TrioTests/OpenAPSSwiftTests/MealJsonTests.swift

@@ -78,7 +78,8 @@ import Testing
             javascript: mealResultJavascript,
             javascriptDuration: 0.1,
             iobInputs: nil,
-            mealInputs: nil
+            mealInputs: nil,
+            determineBasalInputs: nil
         )
 
         if comparison.resultType == .valueDifference {

+ 2 - 1
TrioTests/OpenAPSSwiftTests/ProfileJavascriptTests.swift

@@ -328,7 +328,8 @@ struct ProfileGeneratorTests {
             javascript: jsResult,
             javascriptDuration: 1.0,
             iobInputs: nil,
-            mealInputs: nil
+            mealInputs: nil,
+            determineBasalInputs: nil
         )
 
         if comparison.resultType == .valueDifference {

+ 14 - 7
TrioTests/OpenAPSSwiftTests/ProfileJsNativeCompareTests.swift

@@ -96,7 +96,8 @@ import Testing
             javascript: profileJs,
             javascriptDuration: 0.1,
             iobInputs: nil,
-            mealInputs: nil
+            mealInputs: nil,
+            determineBasalInputs: nil
         )
 
         #expect(comparison.resultType == .matching)
@@ -127,7 +128,8 @@ import Testing
             javascript: .success(matchingJSON),
             javascriptDuration: 0.2,
             iobInputs: nil,
-            mealInputs: nil
+            mealInputs: nil,
+            determineBasalInputs: nil
         )
 
         #expect(comparison.resultType == .matching)
@@ -147,7 +149,8 @@ import Testing
             javascript: .success(matchingJSON),
             javascriptDuration: 0.2,
             iobInputs: nil,
-            mealInputs: nil
+            mealInputs: nil,
+            determineBasalInputs: nil
         )
 
         #expect(comparison.resultType == .valueDifference)
@@ -169,7 +172,8 @@ import Testing
             javascript: .failure(error),
             javascriptDuration: 0.2,
             iobInputs: nil,
-            mealInputs: nil
+            mealInputs: nil,
+            determineBasalInputs: nil
         )
 
         #expect(comparison.resultType == .matchingExceptions)
@@ -188,7 +192,8 @@ import Testing
             javascript: .success(matchingJSON),
             javascriptDuration: 0.2,
             iobInputs: nil,
-            mealInputs: nil
+            mealInputs: nil,
+            determineBasalInputs: nil
         )
 
         #expect(comparison.resultType == .swiftOnlyException)
@@ -209,7 +214,8 @@ import Testing
             javascript: .failure(error),
             javascriptDuration: 0.2,
             iobInputs: nil,
-            mealInputs: nil
+            mealInputs: nil,
+            determineBasalInputs: nil
         )
 
         #expect(comparison.resultType == .jsOnlyException)
@@ -229,7 +235,8 @@ import Testing
             javascript: .success(matchingJSON),
             javascriptDuration: 0.2,
             iobInputs: nil,
-            mealInputs: nil
+            mealInputs: nil,
+            determineBasalInputs: nil
         )
 
         #expect(comparison.resultType == .comparisonError)