@hestia-earth/engine-models 0.82.0 → 0.82.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/formulas.d.ts +16 -3
- package/cjs/formulas.js +58 -29
- package/cjs/version.d.ts +1 -1
- package/cjs/version.js +1 -1
- package/esm/formulas.d.ts +16 -3
- package/esm/formulas.js +52 -26
- package/esm/version.d.ts +1 -1
- package/esm/version.js +1 -1
- package/formulas/README.md +32 -9
- package/formulas/index.json +3375 -399
- package/model-links.json +30 -0
- package/package.json +1 -1
- package/formulas/deRuijterEtAl2010/nh3ToAirCropResidueDecomposition.json +0 -30
- package/formulas/emepEea2019/co2ToAirFuelCombustion.json +0 -23
- package/formulas/emepEea2019/nh3ToAirExcreta.json +0 -27
- package/formulas/emepEea2019/pm10ToAirAnimalHousing.json +0 -28
- package/formulas/emepEea2019/pm25ToAirAnimalHousing.json +0 -28
- package/formulas/emepEea2019/tspToAirAnimalHousing.json +0 -28
- package/formulas/hestia/feedConversionRatio/feedConversionRatioCarbon.json +0 -23
- package/formulas/ipcc2019/belowGroundCropResidue.json +0 -31
- package/formulas/ipcc2019/ch4ToAirAquacultureSystems.json +0 -29
- package/formulas/ipcc2019/ch4ToAirEntericFermentation.json +0 -29
- package/formulas/ipcc2019/ch4ToAirExcreta.json +0 -36
- package/formulas/ipcc2019/ch4ToAirFloodedRice.json +0 -31
- package/formulas/ipcc2019/ch4ToAirOrganicSoilCultivation.json +0 -40
- package/formulas/ipcc2019/co2ToAirUreaHydrolysis.json +0 -27
- package/formulas/ipcc2019/emissionsToAirOrganicSoilBurning.json +0 -49
- package/formulas/ipcc2019/n2OToAirAquacultureSystemsIndirect.json +0 -31
- package/formulas/ipcc2019/n2OToAirCropResidueBurningDirect.json +0 -25
- package/formulas/ipcc2019/n2OToAirCropResidueDecompositionDirect.json +0 -28
- package/formulas/ipcc2019/n2OToAirCropResidueDecompositionIndirect.json +0 -35
- package/formulas/ipcc2019/n2OToAirExcretaDirect.json +0 -25
- package/formulas/ipcc2019/n2OToAirExcretaIndirect.json +0 -39
- package/formulas/ipcc2019/n2OToAirFuelCombustionIndirect.json +0 -31
- package/formulas/ipcc2019/n2OToAirInorganicFertiliserDirect.json +0 -28
- package/formulas/ipcc2019/n2OToAirInorganicFertiliserIndirect.json +0 -39
- package/formulas/ipcc2019/n2OToAirNaturalVegetationBurningIndirect.json +0 -31
- package/formulas/ipcc2019/n2OToAirOrganicFertiliserDirect.json +0 -28
- package/formulas/ipcc2019/n2OToAirOrganicFertiliserIndirect.json +0 -39
- package/formulas/ipcc2019/n2OToAirOrganicSoilBurningIndirect.json +0 -31
- package/formulas/ipcc2019/n2OToAirOrganicSoilCultivationIndirect.json +0 -31
- package/formulas/ipcc2019/nh3ToAirInorganicFertiliser.json +0 -31
- package/formulas/ipcc2019/nh3ToAirOrganicFertiliser.json +0 -31
- package/formulas/ipcc2019/no3ToGroundwaterCropResidueDecomposition.json +0 -28
- package/formulas/ipcc2019/no3ToGroundwaterExcreta.json +0 -28
- package/formulas/ipcc2019/no3ToGroundwaterInorganicFertiliser.json +0 -28
- package/formulas/ipcc2019/no3ToGroundwaterOrganicFertiliser.json +0 -28
- package/formulas/ipcc2019/nonCo2EmissionsToAirNaturalVegetationBurning.json +0 -13
- package/formulas/ipcc2019/noxToAirInorganicFertiliser.json +0 -31
- package/formulas/ipcc2019/noxToAirOrganicFertiliser.json +0 -31
- package/formulas/ipcc2019/pastureGrass.json +0 -556
- package/formulas/pooreNemecek2018/ch4ToAirAquacultureSystems.json +0 -88
- package/formulas/pooreNemecek2018/n2OToAirAquacultureSystemsDirect.json +0 -32
- package/formulas/pooreNemecek2018/n2ToAirAquacultureSystems.json +0 -32
- package/formulas/pooreNemecek2018/nh3ToAirAquacultureSystems.json +0 -40
- package/formulas/pooreNemecek2018/no3ToGroundwaterCropResidueDecomposition.json +0 -68
- package/formulas/pooreNemecek2018/no3ToGroundwaterExcreta.json +0 -68
- package/formulas/pooreNemecek2018/no3ToGroundwaterInorganicFertiliser.json +0 -68
- package/formulas/pooreNemecek2018/no3ToGroundwaterOrganicFertiliser.json +0 -68
- package/formulas/pooreNemecek2018/noxToAirAquacultureSystems.json +0 -32
- package/formulas/schererPfister2015/nErosionSoilFlux.json +0 -34
- package/formulas/schererPfister2015/pErosionSoilFlux.json +0 -109
- package/formulas/stehfestBouwman2006/n2OToAirCropResidueDecompositionDirect.json +0 -37
- package/formulas/stehfestBouwman2006/n2OToAirExcretaDirect.json +0 -37
- package/formulas/stehfestBouwman2006/n2OToAirInorganicFertiliserDirect.json +0 -37
- package/formulas/stehfestBouwman2006/n2OToAirOrganicFertiliserDirect.json +0 -37
- package/formulas/stehfestBouwman2006/noxToAirCropResidueDecomposition.json +0 -36
- package/formulas/stehfestBouwman2006/noxToAirExcreta.json +0 -36
- package/formulas/stehfestBouwman2006/noxToAirInorganicFertiliser.json +0 -36
- package/formulas/stehfestBouwman2006/noxToAirOrganicFertiliser.json +0 -36
package/cjs/formulas.d.ts
CHANGED
|
@@ -19,11 +19,24 @@ export interface IFormulaBinding {
|
|
|
19
19
|
*/
|
|
20
20
|
key?: string;
|
|
21
21
|
/**
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
22
|
+
* A value inside a packed `log_as_table` string: the column to read.
|
|
23
|
+
* - with no `match`, the symbol sits under a `\sum` and is expanded once per
|
|
24
|
+
* row (e.g. `\sum_i M_i \times EF_i` → `(32 × 0.166) + (13 × 0.495)`);
|
|
25
|
+
* - with `match`, it resolves to a single row (row selection, see `match`).
|
|
25
26
|
*/
|
|
26
27
|
column?: string;
|
|
28
|
+
/**
|
|
29
|
+
* Row selection: pick the one row of the `key` table whose id (first column)
|
|
30
|
+
* starts with this value, then read `column` from it. Resolves to a single
|
|
31
|
+
* value, e.g. `NH_3\text{-}N` → the `emission-value` of the row `nh3…`.
|
|
32
|
+
*/
|
|
33
|
+
match?: string;
|
|
34
|
+
/**
|
|
35
|
+
* A fixed constant (not logged): the symbol always substitutes to this literal
|
|
36
|
+
* (e.g. `ER` → `2`) and is excluded from coverage. Empty string marks a
|
|
37
|
+
* constant with no display value.
|
|
38
|
+
*/
|
|
39
|
+
constant?: string;
|
|
27
40
|
}
|
|
28
41
|
/**
|
|
29
42
|
* A KaTeX formula extracted from a model's documentation, with the bindings
|
package/cjs/formulas.js
CHANGED
|
@@ -92,8 +92,9 @@ var formatValue = function (value) {
|
|
|
92
92
|
return round4(value);
|
|
93
93
|
return formatNumericString(String(value));
|
|
94
94
|
};
|
|
95
|
-
// `\sum` with an optional index subscript (`_i`, `_{
|
|
96
|
-
|
|
95
|
+
// `\sum` with an optional index subscript (`_i`, `_{s=1}`, ...) and upper bound
|
|
96
|
+
// superscript (`^S`, `^{S}`), and trailing space.
|
|
97
|
+
var SUM_RE = /\\sum(?:_\{[^}]*\}|_[^\s{])?(?:\^\{[^}]*\}|\^[^\s{])?\s*/;
|
|
97
98
|
// Parse a packed `log_as_table` string into rows: rows split on `;`, columns on
|
|
98
99
|
// `_`, each column a `key:value` pair (values never contain `_` or `:`).
|
|
99
100
|
var parseTable = function (packed) {
|
|
@@ -122,35 +123,63 @@ var parseTable = function (packed) {
|
|
|
122
123
|
* (or an array of row objects). Without the table it stays symbolic.
|
|
123
124
|
*/
|
|
124
125
|
var renderFormula = function (formula, values) {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
var
|
|
128
|
-
var
|
|
129
|
-
var
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
126
|
+
// sum: a per-row column under a \sum. point: a single value — a scalar, a row
|
|
127
|
+
// selection (`match` + `column`), or a fixed constant.
|
|
128
|
+
var sumBindings = formula.bindings.filter(function (b) { return b.key && b.column && !b.match; });
|
|
129
|
+
var pointBindings = formula.bindings.filter(function (b) { return (b.key && !(b.column && !b.match)) || b.constant; });
|
|
130
|
+
var toRows = function (source) {
|
|
131
|
+
return Array.isArray(source)
|
|
132
|
+
? source
|
|
133
|
+
: typeof source === 'string'
|
|
134
|
+
? parseTable(source)
|
|
135
|
+
: [];
|
|
136
|
+
};
|
|
137
|
+
var sumMatch = sumBindings.length ? SUM_RE.exec(formula.formula) : null;
|
|
138
|
+
// The summand may draw from several parallel tables (e.g. one for values, one
|
|
139
|
+
// for factors); parse each once and align them by row index.
|
|
140
|
+
var tableRows = {};
|
|
141
|
+
if (sumMatch) {
|
|
142
|
+
sumBindings.forEach(function (b) {
|
|
143
|
+
var key = b.key;
|
|
144
|
+
if (!(key in tableRows))
|
|
145
|
+
tableRows[key] = toRows(values[key]);
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
var rowCount = sumMatch
|
|
149
|
+
? Math.max.apply(Math, __spreadArray([0], __read(sumBindings.map(function (b) { return tableRows[b.key].length; })), false)) : 0;
|
|
150
|
+
// Resolve a point binding to a single value: a fixed constant, a scalar lookup,
|
|
151
|
+
// or the selected row's column for a row selection (`match` = id prefix).
|
|
152
|
+
var pointValue = function (b) {
|
|
153
|
+
if (b.constant !== undefined)
|
|
154
|
+
return b.constant || undefined;
|
|
155
|
+
if (!b.match)
|
|
156
|
+
return values[b.key];
|
|
157
|
+
var row = toRows(values[b.key]).find(function (r) { var _a; return String((_a = Object.values(r)[0]) !== null && _a !== void 0 ? _a : '').startsWith(b.match); });
|
|
158
|
+
return row ? row[b.column] : undefined;
|
|
159
|
+
};
|
|
160
|
+
// How a binding is referenced in the `data-key` attribute.
|
|
161
|
+
var ref = function (b) {
|
|
162
|
+
return b.constant !== undefined
|
|
163
|
+
? 'const'
|
|
164
|
+
: "".concat(b.key).concat(b.match ? '@' + b.match : '').concat(b.column ? ':' + b.column : '');
|
|
165
|
+
};
|
|
138
166
|
// Expand the `\sum` inline, wrapping each row value with `wrapRow`. Returns the
|
|
139
167
|
// original formula when there is no table to expand over.
|
|
140
168
|
var expand = function (wrapRow) {
|
|
141
|
-
if (!sumMatch || !
|
|
169
|
+
if (!sumMatch || !rowCount)
|
|
142
170
|
return formula.formula;
|
|
143
171
|
var before = formula.formula.slice(0, sumMatch.index);
|
|
144
172
|
var summand = formula.formula.slice(sumMatch.index + sumMatch[0].length);
|
|
145
|
-
var symbols =
|
|
146
|
-
var terms =
|
|
173
|
+
var symbols = sumBindings.map(function (b) { return b.symbol; });
|
|
174
|
+
var terms = Array.from({ length: rowCount }, function (_, i) {
|
|
147
175
|
return '(' +
|
|
148
176
|
splitOnSymbols(summand, symbols)
|
|
149
177
|
.map(function (seg) {
|
|
150
178
|
if (seg.text !== undefined)
|
|
151
179
|
return seg.text;
|
|
152
|
-
var b =
|
|
153
|
-
var
|
|
180
|
+
var b = sumBindings.find(function (x) { return x.symbol === seg.symbol; });
|
|
181
|
+
var row = tableRows[b.key][i];
|
|
182
|
+
var value = row ? formatValue(row[b.column]) : null;
|
|
154
183
|
return value === null ? seg.symbol : wrapRow(b, value);
|
|
155
184
|
})
|
|
156
185
|
.join('') +
|
|
@@ -158,22 +187,22 @@ var renderFormula = function (formula, values) {
|
|
|
158
187
|
});
|
|
159
188
|
return before + terms.join(' + ');
|
|
160
189
|
};
|
|
161
|
-
// Substitute the
|
|
162
|
-
var
|
|
163
|
-
return splitOnSymbols(working,
|
|
190
|
+
// Substitute the point (single-value) symbols over a working string.
|
|
191
|
+
var substitutePoints = function (working, wrap) {
|
|
192
|
+
return splitOnSymbols(working, pointBindings.map(function (b) { return b.symbol; }))
|
|
164
193
|
.map(function (seg) {
|
|
165
194
|
if (seg.text !== undefined)
|
|
166
195
|
return seg.text;
|
|
167
|
-
var b =
|
|
168
|
-
return wrap(b, seg.symbol, formatValue(
|
|
196
|
+
var b = pointBindings.find(function (x) { return x.symbol === seg.symbol; });
|
|
197
|
+
return wrap(b, seg.symbol, formatValue(pointValue(b)));
|
|
169
198
|
})
|
|
170
199
|
.join('');
|
|
171
200
|
};
|
|
172
|
-
var substituted =
|
|
173
|
-
return value === null ? symbol : "\\htmlData{key=".concat(b
|
|
201
|
+
var substituted = substitutePoints(expand(function (b, v) { return "\\htmlData{key=".concat(ref(b), "}{").concat(v, "}"); }), function (b, symbol, value) {
|
|
202
|
+
return value === null ? symbol : "\\htmlData{key=".concat(ref(b), "}{").concat(value, "}");
|
|
174
203
|
});
|
|
175
|
-
var annotated =
|
|
176
|
-
return "\\htmlData{key=".concat(b
|
|
204
|
+
var annotated = substitutePoints(expand(function (b, v) { return "\\htmlData{key=".concat(ref(b), ", value=").concat(v, "}{").concat(v, "}"); }), function (b, symbol, value) {
|
|
205
|
+
return "\\htmlData{key=".concat(ref(b), ", value=").concat(value === null ? 'na' : value, "}{").concat(symbol, "}");
|
|
177
206
|
});
|
|
178
207
|
return { symbolic: formula.formula, substituted: substituted, annotated: annotated };
|
|
179
208
|
};
|
package/cjs/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const ENGINE_VERSION = "0.82.
|
|
1
|
+
export declare const ENGINE_VERSION = "0.82.1";
|
package/cjs/version.js
CHANGED
package/esm/formulas.d.ts
CHANGED
|
@@ -19,11 +19,24 @@ export interface IFormulaBinding {
|
|
|
19
19
|
*/
|
|
20
20
|
key?: string;
|
|
21
21
|
/**
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
22
|
+
* A value inside a packed `log_as_table` string: the column to read.
|
|
23
|
+
* - with no `match`, the symbol sits under a `\sum` and is expanded once per
|
|
24
|
+
* row (e.g. `\sum_i M_i \times EF_i` → `(32 × 0.166) + (13 × 0.495)`);
|
|
25
|
+
* - with `match`, it resolves to a single row (row selection, see `match`).
|
|
25
26
|
*/
|
|
26
27
|
column?: string;
|
|
28
|
+
/**
|
|
29
|
+
* Row selection: pick the one row of the `key` table whose id (first column)
|
|
30
|
+
* starts with this value, then read `column` from it. Resolves to a single
|
|
31
|
+
* value, e.g. `NH_3\text{-}N` → the `emission-value` of the row `nh3…`.
|
|
32
|
+
*/
|
|
33
|
+
match?: string;
|
|
34
|
+
/**
|
|
35
|
+
* A fixed constant (not logged): the symbol always substitutes to this literal
|
|
36
|
+
* (e.g. `ER` → `2`) and is excluded from coverage. Empty string marks a
|
|
37
|
+
* constant with no display value.
|
|
38
|
+
*/
|
|
39
|
+
constant?: string;
|
|
27
40
|
}
|
|
28
41
|
/**
|
|
29
42
|
* A KaTeX formula extracted from a model's documentation, with the bindings
|
package/esm/formulas.js
CHANGED
|
@@ -55,8 +55,9 @@ const formatValue = (value) => {
|
|
|
55
55
|
return round4(value);
|
|
56
56
|
return formatNumericString(String(value));
|
|
57
57
|
};
|
|
58
|
-
// `\sum` with an optional index subscript (`_i`, `_{
|
|
59
|
-
|
|
58
|
+
// `\sum` with an optional index subscript (`_i`, `_{s=1}`, ...) and upper bound
|
|
59
|
+
// superscript (`^S`, `^{S}`), and trailing space.
|
|
60
|
+
const SUM_RE = /\\sum(?:_\{[^}]*\}|_[^\s{])?(?:\^\{[^}]*\}|\^[^\s{])?\s*/;
|
|
60
61
|
// Parse a packed `log_as_table` string into rows: rows split on `;`, columns on
|
|
61
62
|
// `_`, each column a `key:value` pair (values never contain `_` or `:`).
|
|
62
63
|
const parseTable = (packed) => packed
|
|
@@ -81,50 +82,75 @@ const parseTable = (packed) => packed
|
|
|
81
82
|
* (or an array of row objects). Without the table it stays symbolic.
|
|
82
83
|
*/
|
|
83
84
|
export const renderFormula = (formula, values) => {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
const
|
|
87
|
-
const
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
85
|
+
// sum: a per-row column under a \sum. point: a single value — a scalar, a row
|
|
86
|
+
// selection (`match` + `column`), or a fixed constant.
|
|
87
|
+
const sumBindings = formula.bindings.filter((b) => b.key && b.column && !b.match);
|
|
88
|
+
const pointBindings = formula.bindings.filter((b) => (b.key && !(b.column && !b.match)) || b.constant);
|
|
89
|
+
const toRows = (source) => Array.isArray(source)
|
|
90
|
+
? source
|
|
91
|
+
: typeof source === 'string'
|
|
92
|
+
? parseTable(source)
|
|
93
|
+
: [];
|
|
94
|
+
const sumMatch = sumBindings.length ? SUM_RE.exec(formula.formula) : null;
|
|
95
|
+
// The summand may draw from several parallel tables (e.g. one for values, one
|
|
96
|
+
// for factors); parse each once and align them by row index.
|
|
97
|
+
const tableRows = {};
|
|
98
|
+
if (sumMatch) {
|
|
99
|
+
sumBindings.forEach((b) => {
|
|
100
|
+
const key = b.key;
|
|
101
|
+
if (!(key in tableRows))
|
|
102
|
+
tableRows[key] = toRows(values[key]);
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
const rowCount = sumMatch
|
|
106
|
+
? Math.max(0, ...sumBindings.map((b) => tableRows[b.key].length))
|
|
107
|
+
: 0;
|
|
108
|
+
// Resolve a point binding to a single value: a fixed constant, a scalar lookup,
|
|
109
|
+
// or the selected row's column for a row selection (`match` = id prefix).
|
|
110
|
+
const pointValue = (b) => {
|
|
111
|
+
if (b.constant !== undefined)
|
|
112
|
+
return b.constant || undefined;
|
|
113
|
+
if (!b.match)
|
|
114
|
+
return values[b.key];
|
|
115
|
+
const row = toRows(values[b.key]).find((r) => { var _a; return String((_a = Object.values(r)[0]) !== null && _a !== void 0 ? _a : '').startsWith(b.match); });
|
|
116
|
+
return row ? row[b.column] : undefined;
|
|
117
|
+
};
|
|
118
|
+
// How a binding is referenced in the `data-key` attribute.
|
|
119
|
+
const ref = (b) => b.constant !== undefined
|
|
120
|
+
? 'const'
|
|
121
|
+
: `${b.key}${b.match ? '@' + b.match : ''}${b.column ? ':' + b.column : ''}`;
|
|
97
122
|
// Expand the `\sum` inline, wrapping each row value with `wrapRow`. Returns the
|
|
98
123
|
// original formula when there is no table to expand over.
|
|
99
124
|
const expand = (wrapRow) => {
|
|
100
|
-
if (!sumMatch || !
|
|
125
|
+
if (!sumMatch || !rowCount)
|
|
101
126
|
return formula.formula;
|
|
102
127
|
const before = formula.formula.slice(0, sumMatch.index);
|
|
103
128
|
const summand = formula.formula.slice(sumMatch.index + sumMatch[0].length);
|
|
104
|
-
const symbols =
|
|
105
|
-
const terms =
|
|
129
|
+
const symbols = sumBindings.map((b) => b.symbol);
|
|
130
|
+
const terms = Array.from({ length: rowCount }, (_, i) => '(' +
|
|
106
131
|
splitOnSymbols(summand, symbols)
|
|
107
132
|
.map((seg) => {
|
|
108
133
|
if (seg.text !== undefined)
|
|
109
134
|
return seg.text;
|
|
110
|
-
const b =
|
|
111
|
-
const
|
|
135
|
+
const b = sumBindings.find((x) => x.symbol === seg.symbol);
|
|
136
|
+
const row = tableRows[b.key][i];
|
|
137
|
+
const value = row ? formatValue(row[b.column]) : null;
|
|
112
138
|
return value === null ? seg.symbol : wrapRow(b, value);
|
|
113
139
|
})
|
|
114
140
|
.join('') +
|
|
115
141
|
')');
|
|
116
142
|
return before + terms.join(' + ');
|
|
117
143
|
};
|
|
118
|
-
// Substitute the
|
|
119
|
-
const
|
|
144
|
+
// Substitute the point (single-value) symbols over a working string.
|
|
145
|
+
const substitutePoints = (working, wrap) => splitOnSymbols(working, pointBindings.map((b) => b.symbol))
|
|
120
146
|
.map((seg) => {
|
|
121
147
|
if (seg.text !== undefined)
|
|
122
148
|
return seg.text;
|
|
123
|
-
const b =
|
|
124
|
-
return wrap(b, seg.symbol, formatValue(
|
|
149
|
+
const b = pointBindings.find((x) => x.symbol === seg.symbol);
|
|
150
|
+
return wrap(b, seg.symbol, formatValue(pointValue(b)));
|
|
125
151
|
})
|
|
126
152
|
.join('');
|
|
127
|
-
const substituted =
|
|
128
|
-
const annotated =
|
|
153
|
+
const substituted = substitutePoints(expand((b, v) => `\\htmlData{key=${ref(b)}}{${v}}`), (b, symbol, value) => value === null ? symbol : `\\htmlData{key=${ref(b)}}{${value}}`);
|
|
154
|
+
const annotated = substitutePoints(expand((b, v) => `\\htmlData{key=${ref(b)}, value=${v}}{${v}}`), (b, symbol, value) => `\\htmlData{key=${ref(b)}, value=${value === null ? 'na' : value}}{${symbol}}`);
|
|
129
155
|
return { symbolic: formula.formula, substituted, annotated };
|
|
130
156
|
};
|
package/esm/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const ENGINE_VERSION = "0.82.
|
|
1
|
+
export declare const ENGINE_VERSION = "0.82.1";
|
package/esm/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const ENGINE_VERSION = '0.82.
|
|
1
|
+
export const ENGINE_VERSION = '0.82.1';
|
package/formulas/README.md
CHANGED
|
@@ -6,16 +6,15 @@ to a value logged at runtime (the "jlog"). With these you can render a model's
|
|
|
6
6
|
formula and *substitute* its symbols with the actual values from a given
|
|
7
7
|
execution — so a user can see exactly where a result came from.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
`npm run build:models`). Do not edit
|
|
9
|
+
`index.json` is generated by `scripts/generate-formulas.js` (run as part of
|
|
10
|
+
`npm run build:models`). Do not edit it by hand — edit the model's `.md`
|
|
11
11
|
documentation instead (see [Authoring bindings](#authoring-bindings)).
|
|
12
12
|
|
|
13
13
|
## Contents
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
| `index.json` | Aggregate of every formula, keyed by `docPath`. This is what the package imports. |
|
|
15
|
+
`index.json` holds every formula, keyed by the same `docPath` used in
|
|
16
|
+
`model-links.json`: `{ [docPath]: IFormula[] }`. It is the single file the
|
|
17
|
+
package imports.
|
|
19
18
|
|
|
20
19
|
## Data shape
|
|
21
20
|
|
|
@@ -24,7 +23,9 @@ interface IFormulaBinding {
|
|
|
24
23
|
symbol: string; // the KaTeX symbol as written, e.g. "E_{CH4}", "GE"
|
|
25
24
|
description?: string; // the "Where:" list description text
|
|
26
25
|
key?: string; // the jlog field this symbol resolves to (absent for constants)
|
|
27
|
-
column?: string; //
|
|
26
|
+
column?: string; // a column of a packed table (per-row under a \sum, or with `match`)
|
|
27
|
+
match?: string; // row selection: the row whose id starts with this, read `column`
|
|
28
|
+
constant?: string; // a fixed constant (not logged), substituted as-is
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
interface IFormula {
|
|
@@ -162,13 +163,20 @@ Where:
|
|
|
162
163
|
- $E_{CH4}$ = Methane emissions (in kg $CH_4$) `[value]`
|
|
163
164
|
- $GE$ = Gross Energy intake (in MJ). `[total_feed_in_MJ]`
|
|
164
165
|
- $Y_m$ = Methane conversion factor. `[enteric_factor]`
|
|
165
|
-
- $55.65$ = The energy content of methane.
|
|
166
|
+
- $55.65$ = The energy content of methane. `[const]`
|
|
166
167
|
```
|
|
167
168
|
|
|
168
169
|
- Bind the result (left-hand side) to `` `[value]` ``.
|
|
169
170
|
- Bind every other symbol to the jlog field it corresponds to — the `key` passed
|
|
170
171
|
to `debugValues` / `logRequirements` in the model's `.py` (e.g. `enteric_factor`).
|
|
171
|
-
-
|
|
172
|
+
- **Every symbol in the `Where:` list must be annotated.** Tag display-only
|
|
173
|
+
constants (conversion factors, physical constants, e.g. `55.65`, `\frac{17}{14}`)
|
|
174
|
+
with `` `[const]` ``: they render as-is and are excluded from coverage. An
|
|
175
|
+
untagged, unbound symbol is treated as a *genuine missing binding*, not a
|
|
176
|
+
constant — this is what lets the coverage report tell the two apart.
|
|
177
|
+
- Tag a **named** constant with `` `[const:<value>]` `` (e.g. `ER` → `` `[const:2]` ``):
|
|
178
|
+
it substitutes to the literal value (rather than rendering as-is) without being
|
|
179
|
+
logged, and is excluded from coverage.
|
|
172
180
|
|
|
173
181
|
For a `\sum` over inputs, bind each summand symbol to a **table column** with
|
|
174
182
|
`` `[<table key>:<column>]` `` — the log key of the packed `log_as_table` value
|
|
@@ -184,6 +192,21 @@ Where:
|
|
|
184
192
|
- $EF_i$ = product-specific CO<sub>2</sub> emission factor `[urea_values:factor]`
|
|
185
193
|
```
|
|
186
194
|
|
|
195
|
+
When a symbol is a single value living in a specific row of a packed table (not a
|
|
196
|
+
`\sum`), select the row with `` `[<table key>@<id prefix>:<column>]` `` — the row
|
|
197
|
+
whose id (first column) starts with `<id prefix>`, reading `<column>`:
|
|
198
|
+
|
|
199
|
+
```markdown
|
|
200
|
+
$$N_2O_{indirect} = [(NH_3\text{-}N + NO_x\text{-}N) \times EF_4] \times \frac{44}{28}$$
|
|
201
|
+
|
|
202
|
+
Where:
|
|
203
|
+
|
|
204
|
+
- $N_2O_{indirect}$ = indirect N<sub>2</sub>O emission `[value]`
|
|
205
|
+
- $NH_3\text{-}N$ = nitrogen volatilised as ammonia (kg N) `[values@nh3:emission-value]`
|
|
206
|
+
- $NO_x\text{-}N$ = nitrogen volatilised as nitrogen oxides (kg N) `[values@nox:emission-value]`
|
|
207
|
+
- $EF_4$ = emission factor for deposition of volatilised N `[values@nh3:ef4-factor]`
|
|
208
|
+
```
|
|
209
|
+
|
|
187
210
|
`scripts/validate-documentation.js` validates these on every build: it errors if a
|
|
188
211
|
bound symbol is not in the formula or a symbol is bound twice. It warns (without
|
|
189
212
|
failing) when there is no `` `[value]` `` result, several results, or a key is not
|