diff --git a/cases/25-units-check/src/index.heta b/cases/25-units-check/src/index.heta index 76e36385..42c7bc5b 100644 --- a/cases/25-units-check/src/index.heta +++ b/cases/25-units-check/src/index.heta @@ -21,12 +21,17 @@ d(s2*c2)/dt = r1; left: mMole*mL/minute, right: 1/h*mMole*h !!! */ #defineFunction pow7 {arguments: [x, y], math: "2*(x*pow(x, 7))"}; -#defineFunction xxx {arguments: [x, y], math: "x^8 + pow7(x, 1)"}; -p2 @Record {units: mM*h^7} := 23*s1/xxx(k1, 3); - +#defineFunction xx {arguments: [x, y], math: "x^8 + pow7(x, 1)"}; +p2 @Record {units: mM*h^7} := 23*s1/xx(k1, 3); k1 @Const = 1e-3 {units: 1/h}; k2 @Const = 1.1 {units: UL}; +xxx #defineFunction {arguments: [x, y], math: "sin(x)*pow(y*1.2, 3)cos(x)"}; +yyy #defineFunction {arguments: [x, y], math: "1 + sin(x) + y^3 + cos(x)"}; +k21 @Const = 1 {units: metre}; +k22 @Const = 1 {units: mole}; +y21 @Record {units: metre^3} := k21^3 + xxx(1.1*2.2, k21); + // exports #export { format: JSON, filepath: output }; //#export { format: YAML }; diff --git a/package.json b/package.json index cd7ad24c..c321c7a7 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "Programming platform for Quantitative Systems Pharmacology modeling in NodeJS", "main": "src/index.js", "scripts": { - "test:dev": "mocha test/define-function/bind --config=./test/.mocharc.json", + "test:dev": "mocha test/check-units/calc-unit --config=./test/.mocharc.json", "test": "mocha test --config=./test/.mocharc.json", "jsdoc": "jsdoc -r -c .jsdoc.json --readme api-references.md -d docs/dev src", "test:cov": "nyc --reporter=lcov npm run test", diff --git a/src/core/math-calc-unit.js b/src/core/math-calc-unit.js index 2c251d20..8efdb008 100644 --- a/src/core/math-calc-unit.js +++ b/src/core/math-calc-unit.js @@ -209,23 +209,29 @@ function _calcUnit(_this, record) { } return firstUnit; } - if (_this.fn.name === 'exp' || _this.fn.name === 'factorial') { // first argument must be dimensionless, result is dimensionless + let simpleFunctions = [ + 'exp', 'factorial', + 'acos', 'acot', 'acsc', 'asec', 'asin', 'atan', 'cos', 'cot', 'csc', 'sec', 'sin', 'tan', + 'acosh', 'acoth', 'acsch', 'asech', 'asinh', 'atanh', 'cosh', 'coth', 'csch', 'sech', 'sinh', 'tanh' + ]; + if (simpleFunctions.indexOf(_this.fn.name) >=0 ) { // first argument must be dimensionless, result is dimensionless if (!argUnitDimensionless[0]) { logger.warn(`Units inconsistency for "${record.index}": the argument must be dimensionless here "${_this.toString()}", got "${argUnit[0]}"`); } return new Unit(); - } // user-defined functions + } if (_this.fnObj && _this.fnObj.math) { // user-defined functions // set units for internal FunctionDef arguments let newNode = _this.fnObj.math.exprParsed.clone(); newNode.traverse((node, path) => { if (node.isSymbolNode && path !== 'fn') { - let ind = _this.fnObj.arguments.indexOf(node.name); - let u = _this.args[ind].nameObj.unitsParsed; // unit of argument + let ind = _this.fnObj.arguments.indexOf(node.name); // [x, y].indexOf(y) + + let u = argUnit[ind]; node.nameObj = { unitsParsed: u }; } }); - + return _calcUnit(newNode, record); } // else diff --git a/test/check-units/calc-unit.js b/test/check-units/calc-unit.js index 374ab941..3de3bd6a 100644 --- a/test/check-units/calc-unit.js +++ b/test/check-units/calc-unit.js @@ -38,6 +38,14 @@ let qArr = [ {id: 'x6', class: 'Record', units: 'metre^3', assignments: {start_: '1'}}, {id: 'y15', class: 'Record', assignments: {start_: 'x6^(2/3)'}}, {id: 'y16', class: 'Record', assignments: {start_: 'pow(x6, 2/3)'}}, + // define function + {id: 'xxx', action: 'defineFunction', arguments: ['x', 'y'], math: 'sin(x)*pow(y, 3)'}, + {id: 'yyy', action: 'defineFunction', arguments: ['x', 'y'], math: '1 * sin(x) * y^3'}, + {id: 'k21', class: 'Const', num: 1, units: 'metre'}, + {id: 'k22', class: 'Const', num: 1, units: 'mole'}, + {id: 'y21', class: 'Record', units: 'metre^3', assignments: {ode_: 'k21^3 + xxx(1, k21)'}}, + {id: 'y22', class: 'Record', units: 'mole^3', assignments: {ode_: 'k22^3 + xxx(1, k22)'}}, + {id: 'y23', class: 'Record', units: 'metre^3', assignments: {ode_: 'k21^3 + yyy(1.1*2.2, k21)'}}, ]; describe('Testing checkUnits() for components', () => { @@ -46,6 +54,7 @@ describe('Testing checkUnits() for components', () => { it('Create and knit', () => { p = new Container(); p.loadMany(qArr); + //p.checkCircFunctionDef(); p.knitMany(); expect(p.logger).to.have.property('hasErrors').false; }); @@ -218,6 +227,27 @@ describe('Testing checkUnits() for components', () => { expect(unit).to.be.equal('metre^2'); }); + it('FunctionDef 1', () => { + let y21 = p.namespaceStorage.get('nameless').get('y21'); + let expr = y21.assignments.ode_; + let unit = expr.calcUnit(y21).toString(); + expect(unit).to.be.equal('metre^3'); + }); + + it('FunctionDef 2', () => { + let y22 = p.namespaceStorage.get('nameless').get('y22'); + let expr = y22.assignments.ode_; + let unit = expr.calcUnit(y22).toString(); + expect(unit).to.be.equal('mole^3'); + }); + + it('FunctionDef 3', () => { + let y23 = p.namespaceStorage.get('nameless').get('y23'); + let expr = y23.assignments.ode_; + let unit = expr.calcUnit(y23).toString(); + expect(unit).to.be.equal('metre^3'); + }); + it('No warnings', () => { let warnings = p.defaultLogs.filter(x=>x.level==='warn'); //console.log(p.defaultLogs)