diff --git a/lib/sensiplan.js b/lib/sensiplan.js index 94f7b4353f932a9b51e81f7295ee20e70c85198d..8a1e7cd3159e761dc49426f9360ad72968782d3c 100644 --- a/lib/sensiplan.js +++ b/lib/sensiplan.js @@ -2,32 +2,42 @@ function detectTemperatureShift(temperaturesOfCycle) { // sensiplan rounds temps to the nearest 0.05 const tempValues = temperaturesOfCycle.map(val => rounded(val, 0.05)) - return tempValues.reduce((acc, curr) => { - // if we don't yet have 6 lower temps, we just collect - // if no shift has been detected, we collect low temps - // after the shift has been detected, we count them as part - // of the higher temperature phase - if (acc.low.length < 6) { - acc.low.push(curr) - acc.ltl = Math.max(...acc.low) - // TODO these are the same - } else if (curr <= acc.ltl && !acc.potentialHigh && !acc.shiftDetected) { - acc.low.push(curr) - acc.low.shift(curr) - acc.ltl = Math.max(...acc.low) - } else if (!acc.shiftDetected){ - if (!acc.potentialHigh) acc.potentialHigh = [] - acc.potentialHigh.push(curr) - checkRules(acc, curr) - } else { - acc.high.push(curr) + function getLtl(i) { + const sixTempsBefore = getSixTempsBefore(i) + return Math.max(...sixTempsBefore) + } + function getSixTempsBefore(i) { + return tempValues.slice(0, i).slice(-6) + } + + return tempValues.reduce((acc, temp, i) => { + // need at least 6 low temps before we can detect a first high measurement + if (i < 6) return acc + + // if we've already detected a shift, we put it with the other high level temps + if(acc.detected) { + acc.high.push(temp) + return acc } + // is the temp a candidate for a first high measurement? + const ltl = getLtl(i) + if (temp <= ltl) return acc + + const checkResult = checkIfFirstHighMeasurement(temp, i, tempValues, ltl) + // if we don't have a winner, keep going + if (!checkResult.isFirstHighMeasurement) return acc + + // if we do, remember the details and start collecting the high level temps + acc.detected = true + acc.high = [temp] + acc.rules = checkResult.rules + acc.ltl = ltl + acc.low = getSixTempsBefore(i) + return acc }, { - low: [], - ltl: null, - shiftDetected: false + detected: false }) } @@ -36,22 +46,53 @@ function rounded(val, step) { return Math.round(val * inverted) / inverted } -function checkRules(acc, curr) { - function regularRuleApplies() { - // we round the difference because of JS decimal weirdness - return acc.potentialHigh.length === 3 && rounded(curr - acc.ltl, 0.01) >= 0.2 +function checkIfFirstHighMeasurement(temp, i, temps, ltl) { + // need at least 3 high temps to form a high temperature level + if (i > temps.length - 3) { + return { isFirstHighMeasurement: false } + } + const nextTemps = temps.slice(i + 1, i + 4) + + if (regularRuleApplies(temp, nextTemps, ltl)) { + return { + isFirstHighMeasurement: true, + rules: { + regular: true, + }, + ltl + } } - function firstExceptionRuleApplies() { - return acc.potentialHigh.length === 4 && curr > acc.ltl + + if (firstExceptionRuleApplies(temp, nextTemps, ltl)) { + return { + isFirstHighMeasurement: true, + rules: { + firstException: true, + }, + ltl + } } - if (regularRuleApplies() || firstExceptionRuleApplies()) { - acc.shiftDetected = true - acc.high = acc.potentialHigh - delete acc.potentialHigh + return { + isFirstHighMeasurement: false } } +function regularRuleApplies(temp, nextTemps, ltl) { + if (!nextTemps.every(temp => temp > ltl)) return false + const thirdTemp = nextTemps[1] + // we round the difference because of JS decimal weirdness + if (rounded(thirdTemp - ltl, 0.1) < 0.2) return false + return true +} + +function firstExceptionRuleApplies(temp, nextTemps, ltl) { + if (!nextTemps.every(temp => temp > ltl)) return false + const fourthTemp = nextTemps[2] + if (fourthTemp > ltl) return true + return false +} + export { detectTemperatureShift } \ No newline at end of file diff --git a/test/sensiplan.spec.js b/test/sensiplan.spec.js index dd9b5836260e5cab923db588c6983ae811269d98..51945ed9bdf092a59f45312a5c4c7c2d0f64aaf0 100644 --- a/test/sensiplan.spec.js +++ b/test/sensiplan.spec.js @@ -4,16 +4,12 @@ import { detectTemperatureShift } from '../lib/sensiplan' const expect = chai.expect describe.only('sensiplan', () => { - describe('getTemperatureStatus', () => { + describe('detect temperature shift', () => { describe('regular rule', () => { it('reports lower temperature status before shift', function () { const lowerTemps = [36.7, 36.57, 36.47, 36.49, 36.57] const status = detectTemperatureShift(lowerTemps) - expect(status).to.eql({ - low: [36.7, 36.55, 36.45, 36.5, 36.55], - ltl: 36.7, - shiftDetected: false, - }) + expect(status).to.eql({ detected: false }) }) it('detects temperature shift correctly', function () { @@ -23,41 +19,27 @@ describe.only('sensiplan', () => { low: [36.55, 36.45, 36.5, 36.55, 36.6, 36.55], ltl: 36.6, high: [36.8, 36.85, 36.8], - shiftDetected: true + detected: true, + rules: { regular: true } }) }) it('detects no temperature shift when there are no 6 low temps', function () { const tempShift = [36.47, 36.49, 36.57, 36.62, 36.55, 36.8, 36.86, 36.8] const status = detectTemperatureShift(tempShift) - expect(status).to.eql({ - low: [36.45, 36.5, 36.55, 36.6, 36.55, 36.8], - ltl: 36.8, - potentialHigh: [36.85, 36.8], - shiftDetected: false - }) + expect(status).to.eql({ detected: false }) }) it('detects no temperature shift if the shift is not high enough', function () { const tempShift = [36.57, 36.7, 36.47, 36.49, 36.57, 36.62, 36.55, 36.8, 36.86, 36.8] const status = detectTemperatureShift(tempShift) - expect(status).to.eql({ - low: [36.7, 36.45, 36.5, 36.55, 36.6, 36.55], - ltl: 36.7, - potentialHigh: [36.8, 36.85, 36.8], - shiftDetected: false - }) + expect(status).to.eql({ detected: false }) }) it('detects missing temperature shift correctly', function () { const noTempShift = [36.7, 36.57, 36.47, 36.49, 36.57, 36.62, 36.55, 36.8, 36.86, 36.77] const status = detectTemperatureShift(noTempShift) - expect(status).to.eql({ - low: [36.55, 36.45, 36.5, 36.55, 36.6, 36.55], - ltl: 36.6, - potentialHigh: [36.8, 36.85, 36.75], - shiftDetected: false - }) + expect(status).to.eql({ detected: false }) }) }) @@ -69,18 +51,15 @@ describe.only('sensiplan', () => { low: [36.55, 36.45, 36.5, 36.55, 36.6, 36.55], ltl: 36.6, high: [36.8, 36.85, 36.75, 36.65], - shiftDetected: true + detected: true, + rules: { firstException: true } }) }) - it.skip('detects missing temperature shift correctly', function () { + it('detects missing temperature shift correctly', function () { const firstExceptionNoShift = [36.7, 36.57, 36.47, 36.49, 36.57, 36.62, 36.55, 36.8, 36.86, 36.77, 36.57] const status = detectTemperatureShift(firstExceptionNoShift) - expect(status).to.eql({ - low: [36.7, 36.55, 36.45, 36.5, 36.55, 36.6, 36.55, 36.8, 36.85, 36.75, 36.55], - ltl: 36.85, - shiftDetected: false - }) + expect(status).to.eql({ detected: false }) }) }) })