diff --git a/.nvmrc b/.nvmrc index 5edcff0..b6a7d89 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v16 \ No newline at end of file +16 diff --git a/src/health_modules/child/zScoreCalculator.js b/src/health_modules/child/zScoreCalculator.js index a485662..c9ed1fb 100644 --- a/src/health_modules/child/zScoreCalculator.js +++ b/src/health_modules/child/zScoreCalculator.js @@ -14,8 +14,8 @@ const anthropometricReference = { wfh: {Male: wfh_boys, Female: wfh_girls} }; -const roundedHeight = (num) =>{ - return Math.round(num*2)/2; +const roundedHeight = (num) => { + return Math.round(num * 2) / 2; }; const getWfaReference = (gender, ageInMonths) => { @@ -25,7 +25,7 @@ const getWfaReference = (gender, ageInMonths) => { const getWfhReference = (gender, height) => { let wfhReference = _.get(anthropometricReference, ["wfh", gender]); - return _.find(wfhReference,(item) => item.x === roundedHeight(height)); + return _.find(wfhReference, (item) => item.x === roundedHeight(height)); } const getHfaReference = (gender, ageInMonths) => { @@ -33,6 +33,15 @@ const getHfaReference = (gender, ageInMonths) => { return _.find(heightForAgeReference, (item) => item.Month === ageInMonths); } +function calc_sd(reference, sd) { + const {L, M, S} = reference; + return M * ((1 + L * S * sd) ^ (1 / L)); +} + +function roundToOneDecimal(value) { + return Math.round(10 * value) / 10; +} + /** * Uses the LMS formula to calculate zScore. * @@ -45,7 +54,20 @@ const getHfaReference = (gender, ageInMonths) => { const calculate = (value, reference) => { if (!value || value === 0 || !reference) return undefined; - return Math.round(10 * (Math.pow(value / reference.M, reference.L) - 1) / (reference.S * reference.L)) / 10; + // https://github.com/WorldHealthOrganization/anthro/blob/master/R/z-score-helper.R#L28 + const sd3pos = calc_sd(reference, 3); + const sd3neg = calc_sd(reference, -3); + const sd23pos = sd3pos - calc_sd(reference, 2); + const sd23neg = calc_sd(reference, 2) - sd3neg; + + let zScore = roundToOneDecimal((Math.pow(value / reference.M, reference.L) - 1) / (reference.S * reference.L)); + + if (Math.round(zScore) > 3) + zScore = roundToOneDecimal(3 + ((value - sd3pos) / sd23pos)); + else if (Math.round(zScore) < -3) + zScore = roundToOneDecimal(-3 + ((value - sd3neg) / sd23neg)); + + return zScore; }; const calculateZScore = (gender, ageInMonths, weight, height) => { @@ -53,8 +75,6 @@ const calculateZScore = (gender, ageInMonths, weight, height) => { let hfaReference = getHfaReference(gender, ageInMonths); let wfhReference = getWfhReference(gender, height); - //console.log(`weight ${weight} wfa ${JSON.stringify(wfaReference)}`); - return { wfa: calculate(weight, wfaReference), hfa: calculate(height, hfaReference), @@ -66,8 +86,6 @@ const zScore = (individual, asOnDate, weight, height) => { let ageInMonths = individual.getAgeInMonths(asOnDate); let gender = _.get(individual, "gender.name"); - //console.log(`ageInMonths ${ageInMonths} gender ${gender}`); - return calculateZScore(gender, ageInMonths, weight, height); }; @@ -86,4 +104,4 @@ const projectedSD2NegForWeight = (individual, asOnDate) => { return projectedSD2Neg; } -export {zScore as default, projectedSD2NegForWeight}; \ No newline at end of file +export {zScore as default, projectedSD2NegForWeight}; diff --git a/src/test/child/zScoreCalculatorTest.js b/src/test/child/zScoreCalculatorTest.js index 0cd0130..e1c3ac2 100644 --- a/src/test/child/zScoreCalculatorTest.js +++ b/src/test/child/zScoreCalculatorTest.js @@ -5,7 +5,7 @@ import moment from "moment"; describe("zScoreCalculator", () => { describe("zScore()", () => { - var individual, male, female; + let individual, male, female; beforeEach(() => { male = new Gender(); @@ -28,6 +28,9 @@ describe("zScoreCalculator", () => { let zScores, today = new Date(); individual.dateOfBirth = moment(today).subtract(1, 'month'); + zScores = zScore(individual, today, 1.2, 54.7); + assert.equal(zScores.wfa, -6.7); + zScores = zScore(individual, today, 4.5, 54.7); assert.equal(zScores.wfa, 0); @@ -60,7 +63,7 @@ describe("zScoreCalculator", () => { //2 year old girl individual.dateOfBirth = moment(today).subtract(24, 'month'); - assert.equal(zScore(individual, today, 8.1, ).wfa, -3); + assert.equal(zScore(individual, today, 8.1,).wfa, -3); assert.equal(zScore(individual, today, 9).wfa, -2); assert.equal(zScore(individual, today, 10.2).wfa, -1); assert.equal(zScore(individual, today, 11.5).wfa, 0); @@ -186,4 +189,4 @@ describe("zScoreCalculator", () => { assert.approximately(actual, 6.47, 0.01); }); }); -}); \ No newline at end of file +});