Companion formats
Three documents sit beside the language, each versioned on its own. Tying them to the language version would force a language revision every time a results file gained a field.
Intermediate representation 1.3
What a front end produces and an engine consumes:
model.iglir.json. It is the lowered form of a model, with names
resolved to indices, units canonicalised, and provenance attached.
The boundary matters more than the encoding. An engine that reads this file and writes a results file is conforming whatever language it is written in, and the conformance suite measures a binary on disk rather than a library, precisely so that a second implementation can be measured at all.
{
"ir_version": "1.3",
"provenance": {
"source_path": "model.igl",
"source_sha256": "bc8abdb...",
"databases": [
{ "path": "cr_53cr_52cr.igdb",
"resolved": "C:/Program Files/IGL/databases/cr_53cr_52cr.igdb",
"sha256": "d20ee19..." }
],
"generator": "igl 0.1.0"
},
"species": [ ... ], "reservoirs": [ ... ], "processes": [ ... ]
}
resolved records where a database name was answered from, because
a bare name may be met by a file beside the model or by one an installation
provides, and a record naming only what the model wrote leaves a reader unable
to tell which.
Results format 1.1
What an engine writes: results.json. Columns are declared with
their unit, rows are values in column order, and an undefined value is
null rather than zero, because a pool that does not exist yet has
no composition and writing zero there would be a measurement nobody made.
{
"format_version": "1.1",
"engine": { "name": "igl-engine", "version": "0.1.0" },
"model": { "ir_version": "1.3", "source_sha256": "bc8abdb...", "simulation": "Closed" },
"columns": [
{ "name": "Groundwater.Cr(VI).delta53Cr", "kind": "pool_composition",
"unit": "permil", "reservoir": "Groundwater",
"species": "Cr(VI)", "isotope": "53Cr/52Cr" }
],
"rows": [ [0.0], [3.212165544] ],
"diagnostics": [ ],
"backends": [ ]
}
engine.name names what computed the numbers, not what invoked it:
a command line tool, a graphical front end and a batch job driving the same
library all report that library, because a reader comparing two results files
is asking which code produced them.
backends describes the chemistry engines that fed the run, one
entry per declared backend, each naming the executable, the thermodynamic
database with its digest, and the values that crossed into the model. Written
whether or not the model also outputs those values, and written on a failed run
too: a run a chemistry engine refused is exactly the one whose reader most
needs to know which engine that was.
IGDB 1.1
A fractionation database: standards, factors, and the citations that justify them. Every numeric value carries a citation, without exception, which is what makes a database auditable rather than merely convenient.
[[fractionation]] ratio = "53Cr/52Cr" process = "reduction" reactant = "Cr(VI)" product = "Cr(III)" regime = "kinetic" context = "natural" epsilon = -3.5 ph_range = [6.5, 8.5] citation = "Basu et al., 2014" doi = "10.1016/..." notation = "epsilon53Cr(III)-Cr(VI)"
A query names the ratio, the mechanism and the two species; the entry answering it is the one that covers the model's conditions and states the most. A tie is an error and not a coin toss: two entries equally applicable to one query mean the database has not decided, and an engine that picked one would hide a disagreement in the literature behind a lookup.
notation is for human readers. No engine reads it, and none
should: the quantity is already given by ratio,
reactant and product, and parsing a caption to
recover it would be recovering by guesswork what is stated next to it.
The published databases are available for download.