diff --git a/.vscode/settings.json b/.vscode/settings.json index ee8b0de..1d78024 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -67,5 +67,9 @@ "editor.formatOnSave": true, "editor.detectIndentation": false, "prettier.trailingComma": "all", - "prettier.printWidth": 140 + "prettier.printWidth": 140, + "sonarlint.connectedMode.project": { + "connectionId": "https://sonar.beta.cgmsim.com", + "projectKey": "lsandini_cgmsim-lib_dcb733af-979c-4bcd-88af-267d99139342" + } } diff --git a/src/CGMSIMsimulator.ts b/src/CGMSIMsimulator.ts index 9f1fdd4..e03fe1a 100644 --- a/src/CGMSIMsimulator.ts +++ b/src/CGMSIMsimulator.ts @@ -38,6 +38,7 @@ const simulator = (params: MainParams): SimulationResult => { const isfConstant = patient.ISF; const age = patient.AGE; const gender = patient.GENDER; + const tz = patient?.TZ || 'UTC'; let isfActivityDependent = isfConstant; let activityFactor = 1; @@ -72,10 +73,16 @@ const simulator = (params: MainParams): SimulationResult => { const carbsActivity = carbs(treatments, carbsAbs, isfActivityDependent, cr); //activity calc carb - const liverActivity = liverRun(isfConstant, cr, { - physical: activityFactor, - alcohol: alcoholActivity, - }); + const liverActivity = liverRun( + isfConstant, + cr, + { + physical: activityFactor, + alcohol: alcoholActivity, + }, + weight, + tz, + ); const now = moment(); const orderedEntries = entries diff --git a/src/Types.ts b/src/Types.ts index b8d4edb..352511f 100644 --- a/src/Types.ts +++ b/src/Types.ts @@ -239,6 +239,8 @@ type PatientInfoBase = { AGE: number; /** Gender of the simulated user ('Male' or 'Female'). */ GENDER: GenderType; + /** Timezone of the user. */ + TZ: string; }; /** diff --git a/src/liver.ts b/src/liver.ts index 19d7194..aec8c37 100644 --- a/src/liver.ts +++ b/src/liver.ts @@ -5,25 +5,23 @@ export default function ( isfConstant: number, cr: number, activities: { physical: number; alcohol: number }, + weight: number, + timeZone: string, ): number { const _ISF = isfConstant / 18; const _CR = cr; logger.debug('ISF:', isfConstant, 'CR: %o', cr); const activityFactor = activities?.physical >= 0 ? activities.physical : 1; - const alcoholFactor = - activities?.alcohol >= 1 - ? 1 - : activities?.alcohol >= 0 - ? activities.alcohol - : 0; - + let alcoholFactor = 1 - Math.max(0, Math.min(1, activities?.alcohol || 0)); // the sinus and cosinus numbers vary around 1, from 0.5 to 1.5: // sin starts at 1.0 at midnight, is max at 6AM, is again 1 at 12 AM, and minimums at 0.5 a 6 PM // cosin starts at 1.5 at midnight, is 1 at 6AM, is minimus at 0.5 12 AM, and is 1 again at 6 PM - const { sinus, cosinus } = sinusRun(Date.now()); + + const { sinus, cosinus } = sinusRun(timeZone); logger.debug('sinus: %o', sinus); logger.debug('cosinus: %o', cosinus); + const CF = _ISF / _CR; // let's simulate the carb impact of the liver, producing 10g of carbs / hour // if the ISF is 2 mmol/l/U, // and the CR is 10g/U, @@ -34,8 +32,8 @@ export default function ( // by multiplying the liver_bgi by the sin function, the liver loog glucose production varies in a sinusoidal // form, being maximal at 6 AM and minimal ad 6 PM - - const liver = (1 - alcoholFactor) * activityFactor * (_ISF / _CR) * (10 / 60); //(mmol/l)/min + const glucosePerMinute = 0.002 * weight; + const liver = alcoholFactor * activityFactor * CF * glucosePerMinute; //(mmols/l)/min const liver_sin = liver * sinus; logger.debug('liver: %o', liver); diff --git a/src/sinus.ts b/src/sinus.ts index 157a9ae..09f984f 100644 --- a/src/sinus.ts +++ b/src/sinus.ts @@ -3,36 +3,25 @@ import logger from './utils'; //const logger = pino(); -export default function (now: number) { - //timestamp in milliseconds; - logger.debug('timestamp in milliseconds %o', now); - - // timestamp in days; - logger.debug('timestamp in days %o', now / 86400000); - - // timestamp in days rounded; - logger.debug('timestamp in days rounded %o', Math.floor(now / 86400000)); - - //timestamp in fraction of a day; - logger.debug( - 'timestamp in fraction of a day %o', - now / 86400000 - Math.floor(now / 86400000), - ); - - //fraction of a day in hours; - logger.debug( - 'fraction of a day in hours %o', - (now / 86400000 - Math.floor(now / 86400000)) * 24, - ); - - //fraction of a day in hours adding 2 for UTC+2; - logger.debug( - 'fraction of a day in hours adding 2 for UTC+2 %o', - (now / 86400000 - Math.floor(now / 86400000)) * 24 + 2, - ); +function getCurrentHourDecimalInTimezone(timezone) { + const now = Date.now(); + const hours = new Date(now).toLocaleString('en-US', { + timeZone: timezone, + hour: 'numeric', + hour12: false, + }); + const minutes = new Date(now).toLocaleString('en-US', { + timeZone: timezone, + minute: 'numeric', + }); + return parseFloat(hours) + parseFloat(minutes) / 60; +} +export default function (timezone: string) { // time of the day in hours - decimals, not minutes - const hours = (now / 86400000 - Math.floor(now / 86400000)) * 24 + 2; + const hours = getCurrentHourDecimalInTimezone(timezone); + const hours2 = + (Date.now() / 86400000 - Math.floor(Date.now() / 86400000)) * 24 + 2; logger.debug( 'time of the day in hours - using decimals, not minutes: %o', hours.toFixed(2), diff --git a/src/utils.ts b/src/utils.ts index 6ef533d..4697f02 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -44,14 +44,15 @@ const logger = pino({ export default logger; export function isHttps(url: string | null | undefined): boolean { - if (!url) { - return false; // Return false for null or undefined input - } + if (!url) { + return false; // Return false for null or undefined input + } - // Rest of the function remains the same - const pattern = /^https:\/\//i; - return pattern.test(url); + // Rest of the function remains the same + const pattern = /^https:\/\//i; + return pattern.test(url); } +// export function removeTrailingSlash(str) { return str.endsWith('/') ? str.slice(0, -1) : str; diff --git a/test/__image_snapshots__/__diff_output__/simulator-alcohol-test-ts-simulator-alcohol-test-start-from-100-12-00-z-with-deg-22-6-h-alc-1-u-1-h-alc-4-u-2-h-3-snap-diff.png b/test/__image_snapshots__/__diff_output__/simulator-alcohol-test-ts-simulator-alcohol-test-start-from-100-12-00-z-with-deg-22-6-h-alc-1-u-1-h-alc-4-u-2-h-3-snap-diff.png new file mode 100644 index 0000000..be91536 Binary files /dev/null and b/test/__image_snapshots__/__diff_output__/simulator-alcohol-test-ts-simulator-alcohol-test-start-from-100-12-00-z-with-deg-22-6-h-alc-1-u-1-h-alc-4-u-2-h-3-snap-diff.png differ diff --git a/test/__image_snapshots__/__diff_output__/simulator-alcohol-test-ts-simulator-alcohol-test-start-from-100-12-00-z-with-deg-23-4-h-alc-2-u-1-h-3-snap-diff.png b/test/__image_snapshots__/__diff_output__/simulator-alcohol-test-ts-simulator-alcohol-test-start-from-100-12-00-z-with-deg-23-4-h-alc-2-u-1-h-3-snap-diff.png new file mode 100644 index 0000000..c95659c Binary files /dev/null and b/test/__image_snapshots__/__diff_output__/simulator-alcohol-test-ts-simulator-alcohol-test-start-from-100-12-00-z-with-deg-23-4-h-alc-2-u-1-h-3-snap-diff.png differ diff --git a/test/__image_snapshots__/__diff_output__/simulator-cortisone-test-ts-simulator-cortisone-test-start-from-150-12-00-z-with-deg-22-4-h-cor-40-mg-1-h-bolus-3-u-3-h-2-snap-diff.png b/test/__image_snapshots__/__diff_output__/simulator-cortisone-test-ts-simulator-cortisone-test-start-from-150-12-00-z-with-deg-22-4-h-cor-40-mg-1-h-bolus-3-u-3-h-2-snap-diff.png new file mode 100644 index 0000000..baad005 Binary files /dev/null and b/test/__image_snapshots__/__diff_output__/simulator-cortisone-test-ts-simulator-cortisone-test-start-from-150-12-00-z-with-deg-22-4-h-cor-40-mg-1-h-bolus-3-u-3-h-2-snap-diff.png differ diff --git a/test/__image_snapshots__/__diff_output__/simulator-test-ts-simulator-test-start-from-100-13-00-z-with-deg-23-cor-40-mg-14-00-bolus-5-u-14-30-3-snap-diff.png b/test/__image_snapshots__/__diff_output__/simulator-test-ts-simulator-test-start-from-100-13-00-z-with-deg-23-cor-40-mg-14-00-bolus-5-u-14-30-3-snap-diff.png new file mode 100644 index 0000000..cfe8161 Binary files /dev/null and b/test/__image_snapshots__/__diff_output__/simulator-test-ts-simulator-test-start-from-100-13-00-z-with-deg-23-cor-40-mg-14-00-bolus-5-u-14-30-3-snap-diff.png differ diff --git a/test/__image_snapshots__/__diff_output__/simulator-test-ts-simulator-test-start-from-124-15-00-50-g-tou-14-1-snap-diff.png b/test/__image_snapshots__/__diff_output__/simulator-test-ts-simulator-test-start-from-124-15-00-50-g-tou-14-1-snap-diff.png new file mode 100644 index 0000000..542e31d Binary files /dev/null and b/test/__image_snapshots__/__diff_output__/simulator-test-ts-simulator-test-start-from-124-15-00-50-g-tou-14-1-snap-diff.png differ diff --git a/test/__image_snapshots__/__diff_output__/simulator-test-ts-simulator-test-start-from-250-13-00-z-and-tou-14-u-bolus-8-u-14-00-3-snap-diff.png b/test/__image_snapshots__/__diff_output__/simulator-test-ts-simulator-test-start-from-250-13-00-z-and-tou-14-u-bolus-8-u-14-00-3-snap-diff.png new file mode 100644 index 0000000..64459ab Binary files /dev/null and b/test/__image_snapshots__/__diff_output__/simulator-test-ts-simulator-test-start-from-250-13-00-z-and-tou-14-u-bolus-8-u-14-00-3-snap-diff.png differ diff --git a/test/inputTest.ts b/test/inputTest.ts index dd344fc..5abb4df 100644 --- a/test/inputTest.ts +++ b/test/inputTest.ts @@ -270,9 +270,10 @@ export const testGenerator = ( DIA: 6, ISF: 30, TP: 75, - WEIGHT: 80, + WEIGHT: 250 / 3, AGE: 51, GENDER: 'Male', + TZ: 'Europe/Helsinki', }; const noiseActivities = []; const basalActivities = []; diff --git a/test/liver.test.ts b/test/liver.test.ts index 35afe0b..5c39d9f 100644 --- a/test/liver.test.ts +++ b/test/liver.test.ts @@ -9,7 +9,13 @@ describe('Liver test', () => { jest.useRealTimers(); }); it.each([[[30, 10]], [[20, 8]], [[40, 14]]])('test liver %p', ([isf, cr]) => { - const r = liver(isf, cr, { physical: 1, alcohol: 0 }); + const r = liver( + isf, + cr, + { physical: 1, alcohol: 0 }, + 250 / 3, + 'Europe/Helsinki', + ); expect(r).toMatchSnapshot(); }); }); diff --git a/test/simulator.test.ts b/test/simulator.test.ts index 4da2e76..efb5650 100644 --- a/test/simulator.test.ts +++ b/test/simulator.test.ts @@ -68,10 +68,10 @@ describe('simulator test', () => { DIA: 6, ISF: 32, TP: 75, - WEIGHT: 80, + WEIGHT: 250 / 3, AGE: 51, - GENDER: 'Male', + TZ: 'Europe/Rome', }; const log = []; @@ -156,10 +156,11 @@ describe('simulator test', () => { DIA: 6, ISF: 32, TP: 75, - WEIGHT: 80, + WEIGHT: 250 / 3, AGE: 51, GENDER: 'Male', + TZ: 'Europe/Helsinki', }; const log = []; @@ -291,9 +292,10 @@ describe('simulator test', () => { DIA: 6, ISF: 32, TP: 75, - WEIGHT: 80, + WEIGHT: 250 / 3, AGE: 51, GENDER: 'Male', + TZ: 'Europe/Helsinki', }; const log = []; @@ -433,9 +435,10 @@ describe('simulator test', () => { DIA: 6, ISF: 32, TP: 75, - WEIGHT: 80, + WEIGHT: 250 / 3, AGE: 51, GENDER: 'Male', + TZ: 'Europe/Rome', }; const log = []; @@ -527,9 +530,10 @@ describe('Simulator', () => { DIA: 6, ISF: 32, TP: 75, - WEIGHT: 80, + WEIGHT: 250 / 3, AGE: 51, GENDER: 'Male', + TZ: 'Europe/Helsinki', }; // Arrange const paramsWithoutTreatments = { @@ -590,9 +594,10 @@ describe('Simulator', () => { DIA: 6, ISF: 32, TP: 75, - WEIGHT: 80, + WEIGHT: 250 / 3, AGE: 51, GENDER: 'Male', + TZ: 'Europe/Helsinki', }; // Arrange const paramsWithoutProfiles = { @@ -642,9 +647,10 @@ describe('Simulator', () => { DIA: 6, ISF: 8, TP: 75, - WEIGHT: 80, + WEIGHT: 250 / 3, AGE: 51, GENDER: 'Male', + TZ: 'Europe/Helsinki', }; const paramsWithLowIsf = { patient, diff --git a/test/uva.test.ts b/test/uva.test.ts index 43063ab..96328aa 100644 --- a/test/uva.test.ts +++ b/test/uva.test.ts @@ -35,7 +35,8 @@ describe('uva test default PATIENT', () => { const patient: MainParamsUVA['patient'] = { AGE: 40, GENDER: 'Male', - WEIGHT: 80, + WEIGHT: 250 / 3, + TZ: 'Europe/Rome', }; test('basal with gla 30 should generate flat sgv', async () => {