Skip to content

Commit

Permalink
fix units check and add autotest
Browse files Browse the repository at this point in the history
  • Loading branch information
Evgeny Metelkin committed Jan 31, 2024
1 parent 2f68f41 commit 253730a
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 9 deletions.
11 changes: 8 additions & 3 deletions cases/25-units-check/src/index.heta
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
16 changes: 11 additions & 5 deletions src/core/math-calc-unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
30 changes: 30 additions & 0 deletions test/check-units/calc-unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand All @@ -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;
});
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit 253730a

Please sign in to comment.