Skip to content

Commit

Permalink
check units for ODE
Browse files Browse the repository at this point in the history
  • Loading branch information
Evgeny Metelkin committed Jan 24, 2024
1 parent fa08628 commit f599d0e
Show file tree
Hide file tree
Showing 10 changed files with 307 additions and 6 deletions.
34 changes: 34 additions & 0 deletions cases/25-units-check/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
### Basic .gitattributes for a Heta repo.
# Note that binary is a macro for -text -diff.

* text=auto

# main files
# to have heta files in linux style line endings
*.heta text eol=lf
*.xlsx binary

# auxilary files
*.bash text eol=lf
*.sh text eol=lf
*.xlsm binary
*.xls binary
*.pptx binary
*.ppt binary

# code
*.md text
*.m text
# -diff
*.slv text eol=crlf diff=slv
*.dat text eol=crlf diff=dat
*.cpp text
*.svg text diff=xml
*.xml text diff=xml
*.sbml text diff=xml

# LFS (large files)
large/* filter=lfs diff=lfs merge=lfs -text
literature/* filter=lfs diff=lfs merge=lfs -text
*.zip filter=lfs diff=lfs merge=lfs -text
*.rar filter=lfs diff=lfs merge=lfs -text
11 changes: 11 additions & 0 deletions cases/25-units-check/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
### Heta specific files and dirs
/dist
/draft
/drafts
/meta

### temporal files
*.tmp
~$*.*
*.log
.Rhistory
14 changes: 14 additions & 0 deletions cases/25-units-check/platform.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"builderVersion": "*",
"id": "template",
"notes": "platform notes",
"version": "v0.1.0",
"license": "UNLICENSED",
"options": {
"unitsCheck": true
},
"importModule": {
"type": "heta",
"source": "src/index.heta"
}
}
35 changes: 35 additions & 0 deletions cases/25-units-check/src/index.heta
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
template file for creating platform
*/
// add qsp units
include ./qsp-units.heta;
t {units: h};

p1 @Record .= 1 {units: uM};
c1 @Compartment .= 3 {units: L};
c2 @Compartment .= 4 {units: mL};
c3 @Compartment .= 5 {units: m};

s1 @Species {compartment: c1, units: mM} .= 10;
s2 @Species {compartment: c2, units: mM} .= 10;
s3 @Species {compartment: c3, units: mmole/m} .= 10;

r1 @Reaction {actors: s1=>s2, units: mmole/h} := k1 * s1 * c1;
/*
d(s1*c1)/dt = - r1; left: mMole*L/minute, right: 1/h*mMole*h !!!
d(s2*c2)/dt = r1; left: mMole*mL/minute, right: 1/h*mMole*h !!!
*/

k1 @Const = 1e-3 {units: 1/h};

// exports
#export { format: JSON, filepath: output };
//#export { format: YAML };
//#export { format: XLSX, omitRows: 3, splitByClass: true };
//#export { format: SBML, version: L2V4 };
//#export { format: SLV, eventsOff: false };
//#export { format: DBSolve };
//#export { format: Simbio };
//#export { format: Mrgsolve };
//#export { format: Matlab };
//#export { format: Julia };
153 changes: 153 additions & 0 deletions cases/25-units-check/src/qsp-units.heta
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
fmole #defineUnit {
units: [ { kind: mole, multiplier: 1e-15 } ]
};
pmole #defineUnit {
units: [ { kind: mole, multiplier: 1e-12 } ]
};
nmole #defineUnit {
units: [ { kind: mole, multiplier: 1e-9 } ]
};
umole #defineUnit {
units: [ { kind: mole, multiplier: 1e-6 } ]
};
mmole #defineUnit {
units: [ { kind: mole, multiplier: 1e-3 } ]
};
fM #defineUnit {
units: [ { kind: mole, multiplier: 1e-15 }, { kind: litre, exponent: -1} ]
};

pM #defineUnit {
units: [ { kind: mole, multiplier: 1e-12 }, { kind: litre, exponent: -1} ]
};
nM #defineUnit {
units: [ { kind: mole, multiplier: 1e-9 }, { kind: litre, exponent: -1} ]
};
uM #defineUnit {
units: [ { kind: mole, multiplier: 1e-6 }, { kind: litre, exponent: -1} ]
};
mM #defineUnit {
units: [ { kind: mole, multiplier: 1e-3 }, { kind: litre, exponent: -1} ]
};
M #defineUnit {
units: [ { kind: mole }, { kind: litre, exponent: -1} ]
};
kM #defineUnit {
units: [ { kind: mole, multiplier: 1e3 }, { kind: litre, exponent: -1 } ]
};

fL #defineUnit {
units: [ { kind: litre, multiplier: 1e-15 } ]
};
pL #defineUnit {
units: [ { kind: litre, multiplier: 1e-12 } ]
};
nL #defineUnit {
units: [ { kind: litre, multiplier: 1e-9 } ]
};
uL #defineUnit {
units: [ { kind: litre, multiplier: 1e-6 } ]
};
mL #defineUnit {
units: [ { kind: litre, multiplier: 1e-3 } ]
};
dL #defineUnit {
units: [ { kind: litre, multiplier: 1e-1 } ]
};
L #defineUnit {
units: [ { kind: litre } ]
};

fs #defineUnit {
units: [ { kind: second, multiplier: 1e-15 } ]
};
ps #defineUnit {
units: [ { kind: second, multiplier: 1e-12 } ]
};
ns #defineUnit {
units: [ { kind: second, multiplier: 1e-9 } ]
};
us #defineUnit {
units: [ { kind: second, multiplier: 1e-6 } ]
};
ms #defineUnit {
units: [ { kind: second, multiplier: 1e-3 } ]
};
s #defineUnit {
units: [ { kind: second } ]
};
h #defineUnit {
units: [ { kind: hour, multiplier: 1 } ]
};
week #defineUnit {
units: [ { kind: day, multiplier: 7 } ]
};

fg #defineUnit {
units: [ { kind: kilogram, multiplier: 1e-18 } ]
};
pg #defineUnit {
units: [ { kind: kilogram, multiplier: 1e-15 } ]
};
ng #defineUnit {
units: [ { kind: kilogram, multiplier: 1e-12 } ]
};
ug #defineUnit {
units: [ { kind: kilogram, multiplier: 1e-9 } ]
};
mg #defineUnit {
units: [ { kind: kilogram, multiplier: 1e-6 } ]
};
g #defineUnit {
units: [ { kind: kilogram, multiplier: 1e-3 } ]
};
kg #defineUnit {
units: [ { kind: kilogram } ]
};

kat #defineUnit {
units: [ { kind: katal } ]
};

cell #defineUnit {
units: [ { kind: item } ]
};
kcell #defineUnit {
units: [ { kind: item, multiplier: 1e3 } ]
};

cal #defineUnit {
units: [ { kind: joule, multiplier: 4.1868 } ]
};
kcal #defineUnit {
units: [ { kind: joule, multiplier: 4.1868e3 } ]
};

fm #defineUnit {
units: [ { kind: metre, multiplier: 1e-15 } ]
};
pm #defineUnit {
units: [ { kind: metre, multiplier: 1e-12 } ]
};
nm #defineUnit {
units: [ { kind: metre, multiplier: 1e-9 } ]
};
um #defineUnit {
units: [ { kind: metre, multiplier: 1e-6 } ]
};
mm #defineUnit {
units: [ { kind: metre, multiplier: 1e-13 } ]
};
cm #defineUnit {
units: [ { kind: metre, multiplier: 1e-2 } ]
};
m #defineUnit {
units: [ { kind: metre } ]
};

UL #defineUnit {
units: [ { kind: dimensionless } ]
};
percent #defineUnit {
units: [ { kind: dimensionless, multiplier: 1e-2 } ]
};
3 changes: 1 addition & 2 deletions src/builder/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class Builder {
* 3. Loading integrated structures into `Platform`.
* 4. Setting cross-references in platform's elements.
* 5. Checking circular references in mathematical expressions.
* 6. Checking circular unitDef references.
* 6. Checking circular unitDef references. Checking circular functionDef rferences.
* 7. Checking left and right side units compatibility for mathematical expressions.
* 8. Checking unit\'s terms.
* 9. Export of a platform to series of formats.
Expand Down Expand Up @@ -116,7 +116,6 @@ class Builder {

// 3. Translation
this.container.loadMany(qArr, false);
//console.log([...this.container.unitDefStorage]); // XXX: debugging

// 4. Binding
this.logger.info('Setting references in elements, total length ' + this.container.length);
Expand Down
5 changes: 5 additions & 0 deletions src/container/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,11 @@ class Container {
checkUnits(){
this.namespaceStorage.forEach((ns) => {
if (!ns.isAbstract) {
// check units for t
let timeUnits = ns.get('t').unitsParsed;
if (!timeUnits) {
this.logger.warn('No units set for "t", cannot check ODE units.');
}
// check Record.assignments
ns.selectByInstanceOf('Record')
.forEach((rec) => rec.checkUnits());
Expand Down
4 changes: 2 additions & 2 deletions src/core/expression.js
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,8 @@ class Expression {

return isBooleanOperator || isBooleanValue;
}
calcUnit(record){
return _calcUnit(this.exprParsed, record);
calcUnit(component) { // component here is used for logger and index
return _calcUnit(this.exprParsed, component);
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/core/math-calc-unit.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
/*
This module calculates units based on expressions
Records of the expressions must be bound before running this method
Records of the expressions must be bound before running the method
*/
const { Unit } = require('./unit');

/*
_this : Node
record : Record
*/
function _calcUnit(_this, record){
function _calcUnit(_this, record) {
const logger = record.namespace.container.logger;

if (_this.type === 'ParenthesisNode') {
Expand Down
50 changes: 50 additions & 0 deletions src/core/species.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,56 @@ class Species extends Record {
return super._references()
.concat(classSpecificRefs);
}
/*
Check units for left and right side of ODE
Works only for bound records
*/
checkUnits() {
super.checkUnits();

let logger = this.namespace?.container?.logger;

// if not in processes do not check
let processes = this.backReferences.map(x => x._process_);
if (!processes.length) {
return; // BRAKE
}

// if no units for t skip check, message in Container.checkUnits()
let timeUnits = this.namespace.get('t').unitsParsed;
if (!timeUnits) {
return; // BRAKE
}

let compartmentUnits = this.compartmentObj?.unitsParsed;
if (!compartmentUnits && !this.isAmount) {
logger.warn(`No units set for compartment "${this.compartment}", cannot check units for "${this.index}" associated ODE.`);
return; // BRAKE
}

let speciesUnits = this.unitsParsed;
if (!speciesUnits) {
logger.warn(`No units set for "${this.index}", cannot check units for associated ODE.`);
return; // BRAKE
}

// d(s*c)/dt
let leftSideUnits = speciesUnits
.multiply(compartmentUnits)
.divide(timeUnits)
.simplify();
// r1 + r2 + r3
processes.forEach((proc) => {
let processUnits = proc.unitsParsed;
if (!processUnits) {
// message was in Process.checkUnits
return; // BRAKE
}
if (!leftSideUnits.equal(processUnits, true)) {
logger.warn(`Unit inconsistency for ${this.id} associated ODE. Left: ${leftSideUnits.toString()}. Right: ${processUnits.toString()} (${proc.id})`);
}
});
}
get legalTerms() {
let actualCompartmentTerm = this.compartmentObj?.unitsParsed?.toTerm();

Expand Down

0 comments on commit f599d0e

Please sign in to comment.