diff --git a/SPECIFICATION.md b/SPECIFICATION.md index 8a87e5a..50f8d7c 100644 --- a/SPECIFICATION.md +++ b/SPECIFICATION.md @@ -209,7 +209,7 @@ Each `//v1.0.0/` folder normally contains exactly: Every `schema.json`'s `required` array carries a sibling `x-required-rule-ids` object mapping each required field's name to the numbered validation rule that documents its presence requirement, and any property whose own constraint - a `_type` discriminator `const`, or a type/shape check beyond bare presence - has a matching numbered rule carries a sibling `x-rule-id` alongside that constraint (as a sibling of `$ref` where the property is declared that way); `x-rule-id` is a single rule-ID string, or an array of them when more than one rule governs the same property (most commonly an `OrRef` field's separate direct-value and reference-form rules, e.g. `AbstractODESimulation.forcePhysicalCorrectness`). A bare `SIdRef` property that must resolve to a particular kind of thing also carries `"x-ref-target": "model"` (SEDBase-0016) or `"x-ref-target": "annotatedData"` (SEDBase-0017). All of these are inert to any JSON Schema validator (unknown keywords are ignored) and exist purely as generator-only metadata - see Design.md's Validation section - so the generator can wire each hand-written `validate()` check straight to the schema location it corresponds to rather than re-deriving that mapping itself. Not every numbered rule has a schema-visible home this way: most are semantic (cross-reference resolution, math well-formedness, tolerance interactions, and the like) with no single JSON Schema keyword to attach to; only presence, discriminator, and simple type/shape constraints get one. A class whose own requiredness is disjunctive rather than a flat list - so far, only `Repeat`, whose subclasses need at least one of `outputVariableMap` or `aggregateOutputVariables` rather than a fixed set - expresses that as an `anyOf` of single-field `required` objects at the class's own top level (sibling to `properties`), with a sibling `x-anyof-required-rule-id` naming the one rule documenting the whole disjunction, rather than forcing it into `x-required-rule-ids`'s per-field mapping. A `oneOf` discriminator built via `x-generated-oneOf` (see Design.md's Classes section) can similarly carry a sibling `x-missing-type-rule-id`, naming a rule for the narrower case where `_type` is absent from the instance entirely, rather than present but unrecognized - a more specific error than the discriminator's own catch-all, for whichever discriminators want to distinguish it (e.g. `AbstractTask-0002`). -**Task output shapes (`outputs.json`).** Every concrete `tasks/` class (one with its own `_type`) additionally carries an `outputs.json`, machine-describing what each output suffix (`[id]`, `[id].model`, `[id].strings`, and any class-specific suffix like `Loop`'s `[id].aggregates`/`[id].range`/`[id].index`) resolves to - replacing the free-text "Valid"/"Invalid"/"Dimensions:" bullets that used to be the only record of this. Each suffix entry has a `valid` flag (`true`/`false`, or a boolean expression string over the task's own fields, e.g. `"outputModel == true"`, `"provided(range)"`), a `type` (`annotatedData`/`model`/`stringList`) when valid, and for `annotatedData` a `dimensions` list. Every place a size, a label set, or a whole shape needs stating, it's tagged with where that knowledge actually comes from - `"static"` (an `expr` computed from the task's own fields: `len(outputVariables)`, `independentVariableRange.numberOfSteps`, `keys(data)`, `[independentVariable] + outputVariables` as an array-literal-plus-concatenation, `shapeOf(input)` to inherit another reference's whole shape, optionally minus a dropped dimension via `- dim(...)`), `"input-file"` (knowable only by reading whatever external resource a field like `model` or `location` points to - `JacobianFull`'s species count, `CsvImport`'s column headers - tagged with `from`/`extract`/`note` rather than a formula, since the actual parsing is format-specific generator work, not something this file does itself), or `"runtime"` (genuinely not derivable without executing the simulation, e.g. `BoundedODESimulation`'s solver-chosen row count under variable step size, or `Loop`'s iteration count - always paired with a `note` explaining why). A `"runtime"` size may also carry an optional `min`, a guaranteed lower bound when one is actually known (e.g. "at least 2 rows"); an index or range that requires more entries than `min` guarantees is flagged by `SEDBase-0014` as a warning rather than an error, since it may still be valid once the simulation actually runs. `dimensions` itself is either a fixed array of per-dimension entries - an ordinary entry, or a `repeat` entry that expands to one dimension per entry of a named array-valued attribute (e.g. `ParameterScan`'s one dimension per entry of `parameterRanges`) - when the shape is decomposable dimension-by-dimension, or a single sourced object describing the whole shape's derivation, for the genuinely non-decomposable cases (`shapeOf(x)` whole-shape inheritance, or a `"runtime"`/`"input-file"` source where the dimension count itself isn't knowable ahead of time). `schema/outputs-meta.schema.json` validates every class's `outputs.json` envelope (the object shapes above); it does not parse `expr`/`note` string contents, which stay documentation for whoever implements the generator's shape-inference step. Abstract/mixin classes (`AbstractSimulation` and friends, `Repeat`) carry no `outputs.json` of their own, the same reasoning as why they carry no `_type` - nothing is ever instantiated as one directly, so "what does referencing this task's output produce" has no meaning until a concrete leaf class answers it, flatly, the same way those classes already flatten every other inherited constraint into their own `schema.json`. +**Task output shapes (`outputs.json`).** Every concrete `tasks/` class (one with its own `_type`) additionally carries an `outputs.json`, machine-describing what each output suffix (`[id]`, `[id].model`, `[id].strings`, and any class-specific suffix like `Loop`'s `[id].aggregates`/`[id].range`/`[id].index`) resolves to - replacing the free-text "Valid"/"Invalid"/"Dimensions:" bullets that used to be the only record of this. A suffix that is listed is valid, and a suffix that is not listed is not valid (a class with no valid suffixes, such as `Span`, lists none). A listed entry may carry an optional `valid` field meaning "valid if": a boolean expression string over the task's own fields, e.g. `"outputModel == true"`, `"provided(range)"`; with no `valid` field the entry is always valid. Each entry has a `type` (`annotatedData`/`model`/`stringList`), and for `annotatedData` a `dimensions` list. Every place a size, a label set, or a whole shape needs stating, it's tagged with where that knowledge actually comes from - `"static"` (an `expr` computed from the task's own fields: `len(outputVariables)`, `independentVariableRange.numberOfSteps`, `keys(data)`, `[independentVariable] + outputVariables` as an array-literal-plus-concatenation, `shapeOf(input)` to inherit another reference's whole shape, optionally minus a dropped dimension via `- dim(...)`), `"input-file"` (knowable only by reading whatever external resource a field like `model` or `location` points to - `JacobianFull`'s species count, `CsvImport`'s column headers - tagged with `from`/`extract`/`note` rather than a formula, since the actual parsing is format-specific generator work, not something this file does itself), or `"runtime"` (genuinely not derivable without executing the simulation, e.g. `BoundedODESimulation`'s solver-chosen row count under variable step size, or `Loop`'s iteration count - always paired with a `note` explaining why). A `"runtime"` size may also carry an optional `min`, a guaranteed lower bound when one is actually known (e.g. "at least 2 rows"); an index or range that requires more entries than `min` guarantees is flagged by `SEDBase-0014` as a warning rather than an error, since it may still be valid once the simulation actually runs. `dimensions` itself is either a fixed array of per-dimension entries - an ordinary entry, or a `repeat` entry that expands to one dimension per entry of a named array-valued attribute (e.g. `ParameterScan`'s one dimension per entry of `parameterRanges`) - when the shape is decomposable dimension-by-dimension, or a single sourced object describing the whole shape's derivation, for the genuinely non-decomposable cases (`shapeOf(x)` whole-shape inheritance, or a `"runtime"`/`"input-file"` source where the dimension count itself isn't knowable ahead of time). `schema/outputs-meta.schema.json` validates every class's `outputs.json` envelope (the object shapes above); it does not parse `expr`/`note` string contents, which stay documentation for whoever implements the generator's shape-inference step. Abstract/mixin classes (`AbstractSimulation` and friends, `Repeat`) carry no `outputs.json` of their own, the same reasoning as why they carry no `_type` - nothing is ever instantiated as one directly, so "what does referencing this task's output produce" has no meaning until a concrete leaf class answers it, flatly, the same way those classes already flatten every other inherited constraint into their own `schema.json`. **The `expr`/`valid` notation.** Both fields reuse one small expression language, evaluated against the task's own attribute values at generate/validate time - never against runtime data, and not the SED2 math grammar `Types-0001` through `Types-0004` validate (see this section's `x-rule-id` paragraph above and `Design.md`'s Math section for that separate grammar): `outputs.json` describes shape, `math` describes computation. A bare identifier names one of the task's own attributes and evaluates to its value (`outputVariables`); a dotted path reaches into a nested attribute the same way (`independentVariableRange.numberOfSteps`). `[x]` is an array literal (`[independentVariable]`); JSON numbers and `true`/`false` are literals too. Five functions: `len(x)` - the length of an array-valued `x`; or, when `x` is a Range-family value (a `RangeInline`/`NumericRangeInline`/`ParameterRangeInline`-typed field, or the reserved identifier `self` inside a `repeat` entry - see below), the number of points it resolves to, dispatched on `x`'s own discriminated type: `len(x.values) if provided(x.values) else x.numberOfSteps + 1` for `NumericRange`/`ParameterRange`, or just `len(x.values)` for a bare `Range` (which has no `numberOfSteps` alternative); `keys(x)` - the keys of an object-valued `x`, as an array; `shapeOf(x)` - the whole `dimensions` shape of a referenced AnnotatedData value; `dim(x)` - the dimension(s) named by `x` (a single name or a list of names) within a shape, meaningful only as the right operand of `-`; `provided(x)` - `true` iff attribute `x` was given a value in the document. Operators, at ordinary precedence: `!x` (boolean negation); `x == y` (equality); `x + y` (numeric addition when both operands are numbers, array concatenation when both are arrays - `1 + len(outputVariables)` vs. `[independentVariable] + outputVariables`); `shapeOf(x) - dim(y)` (a shape with the named dimension(s) removed - the only place `-` appears); `x or y` (`x`'s value when `provided(x)` holds, else the literal `y` - used for a field with a documented default, e.g. `dim(appliedDimensions or outermost)`, where `outermost` is a sentinel meaning the shape's own first dimension); and a conditional `x if provided(y) else z` for a value with two different derivations depending on whether an alternate field was given instead (e.g. `NumericRange`'s `len(values) if provided(values) else numberOfSteps + 1`). This is the only formal definition of the notation - `schema/outputs-meta.schema.json` does not parse it, as noted above - so a generator's shape-inference step implements it by hand. Inside a `dimensions` array's `repeat` entry (see above), this same notation applies to that entry's own `size`/`labels`, with two scoping additions: a bare identifier there resolves against the current array entry's own fields, not the task's top-level attributes; and the reserved identifier `self` refers to the current entry as a whole (for taking its `len()`, per above) rather than one of its fields. `ParameterScan`'s `repeat` over `parameterRanges` uses `size: len(self)`, letting each entry's own type (`Range`/`NumericRange`/`ParameterRange`) determine its own length the same way `Scatter`'s `len(range)` and `ExplicitODESimulation`'s `len(independentVariableRange)` do for their own named Range-family fields. @@ -226,7 +226,7 @@ tasks/Range/v1.0.0/ tasks/NumericRange/v1.0.0/ task `Range` and `NumericRange` carry an extra `common.schema.json` that `ParameterRange` and `Span` don't need: `Range` is both directly instantiable and the parent of `NumericRange`, and `NumericRange` is in turn both directly instantiable and the parent of `ParameterRange` - so each contributes a `RangeCommon`/`NumericRangeCommon` mixin (composed via `allOf`) carrying the fields its subclass inherits, alongside its own `schema.json` for the standalone-task form. `ParameterRange` and `Span` are leaves - nothing subclasses them - so they need no such split. Each mixin composes the next one up in turn (`NumericRangeCommon` composes `RangeCommon`, which composes `AbstractTaskCommon`), so a concrete class's own `allOf` names only its one most specific ancestor mixin - `ParameterRange` lists just `NumericRangeCommon`, not `RangeCommon` and `NumericRangeCommon` side by side - mirroring the UML chain directly rather than flattening every ancestor into each leaf; see `Design.md`'s Classes section for why. -Each `description.md` in these four folders explains all of that folder's schema files. Everything else in the document - including every cross-reference into these four classes from other Data Sheets' `schema.json` files - still resolves correctly; this was verified by validating real SED2 example documents against the split schemas after the merge. All four live under `tasks/` rather than `auxiliary/`, so each also carries the ordinary `outputs.json` every concrete `tasks/` class does - `Range`, `NumericRange`, and `ParameterRange` describe their `[id]` output for when they're used as a standalone `tasks` entry, and `Span`'s marks every suffix invalid, matching its own `description.md` (`Span` can never be a standalone `tasks` entry, only ever an embedded child, so it has no output of its own). +Each `description.md` in these four folders explains all of that folder's schema files. Everything else in the document - including every cross-reference into these four classes from other Data Sheets' `schema.json` files - still resolves correctly; this was verified by validating real SED2 example documents against the split schemas after the merge. All four live under `tasks/` rather than `auxiliary/`, so each also carries the ordinary `outputs.json` every concrete `tasks/` class does - `Range`, `NumericRange`, and `ParameterRange` describe their `[id]` output for when they're used as a standalone `tasks` entry, and `Span`'s lists no suffixes at all (so every suffix is invalid), matching its own `description.md` (`Span` can never be a standalone `tasks` entry, only ever an embedded child, so it has no output of its own). **Exception - the two `*Common` mixins.** `AbstractTaskCommon` and `AbstractOutputCommon` are schema-only mixins (composed via `allOf`) rather than modeled classes with their own UML box: they contribute the fields every concrete Task (or Output) picks up beyond `SEDBase` - `taskParameters`/`outputParameters` - but have no `_type` of their own and are never instantiated directly. Rather than give them placeholder folders, each is merged into its family's base-class folder as a second schema file: @@ -371,9 +371,10 @@ Every element inherits `SEDBase`, but whether `[id]`, `[id].model`, or `[id].str **`SEDBase-0008`** (error) - A dot-accessor in a reference must be one the target declares valid. ([source](specsheets/core/SEDBase/v1.0.0/validation/SEDBase-0008.md)) -> For a task target, the accessor must appear in that task class's outputs.json, -> and its "valid" field must be true, or be an expression that evaluates to true -> against the target's own fields. When the expression cannot be evaluated +> For a task target, the accessor must be listed in that task class's outputs.json +> (a suffix that is not listed is not valid), and, if the entry has a "valid" +> field, that field's expression must evaluate to true against the target's own +> fields. An entry with no "valid" field is always valid. When the expression cannot be evaluated > statically (it depends on a reference that resolves only at run time), the > rule does not fire. > @@ -1076,7 +1077,7 @@ There is no output rule for `AbstractODESimulation` itself - see `ExplicitODESim ##### What it does -`AbstractSimulation` is a schema-only mixin (composed via `allOf`, not instantiated directly, no `_type` or diagram box of its own beyond the one shown here) contributing the fields shared by every ODE or stochastic simulation task, by way of `AbstractODESimulation` and `AbstractStochasticSimulation`. It replaces the earlier `SimulationCommon`, and (unlike `SimulationCommon`) is no longer used by `SteadyState` or `FluxBalanceAnalysis`, which now declare their own fields directly. +`AbstractSimulation` is a schema-only mixin (composed via `allOf`, not instantiated directly, no `_type` or diagram box of its own beyond the one shown here) contributing the fields shared by every ODE or stochastic simulation task, by way of `AbstractODESimulation` and `AbstractStochasticSimulation`. It replaces the earlier `SimulationCommon`, and (unlike `SimulationCommon`) is no longer used by `SteadyState` or `FluxBalanceAnalysis`, which now declare their own fields directly (including their own `workingAlgorithms` lists). Beyond the fields it inherits from `AbstractTask`, it contributes `model`, `independentVariable`, `independentVariableInit`, `outputVariables`, and `workingAlgorithms` - a list of `WorkingAlgorithm` entries describing the algorithm(s) used internally by the simulation. @@ -2404,7 +2405,7 @@ A 2D matrix of numbers, accessible as `[id]`: the first column is `independentVa Uses an objective function and reaction rate bounds (both defined within the model itself) to determine the set of reaction rates that maximizes the objective function. Unlike the other simulation tasks, FBA has no independent variable. -This is an implementation of KISAO:0000437 (FBA). +This is an implementation of KISAO:0000437 (FBA). The algorithm(s) it uses internally may be listed in the optional `workingAlgorithms` (see `WorkingAlgorithm`). ##### Attributes @@ -2415,7 +2416,7 @@ All classes additionally inherit the optional `name`, `description`, `notes`, an | `taskParameters` | array of TaskParameter | no | | | `model` | SIdRef | yes | | | `outputVariables` | ListOfStringsOrRef | yes | | -| `outputModel` | BooleanOrRef | no | | +| `workingAlgorithms` | array of WorkingAlgorithm | no | | ###### Attribute details @@ -2425,20 +2426,18 @@ All classes additionally inherit the optional `name`, `description`, `notes`, an **`outputVariables`** (ListOfStringsOrRef, required) - _(no description yet - placeholder, needs to be filled in)_ -**`outputModel`** (BooleanOrRef, optional) - _(no description yet - placeholder, needs to be filled in)_ +**`workingAlgorithms`** (array of WorkingAlgorithm, optional) - _(no description yet - placeholder, needs to be filled in)_ ##### Outputs -A dictionary of model variables (usually fluxes) to their final values, accessible via `outputVariables` as `[id]` - analogous to a `SteadyState` result. If `outputModel` is `true`, the resulting model state is also available as `[id].model`. +A dictionary of model variables (usually fluxes) to their final values, accessible via `outputVariables` as `[id]` - analogous to a `SteadyState` result. The resulting model state is always also available as `[id].model`. - `[id]`: **Valid** - Dimensions: 1D: one value per entry of `outputVariables` (typically reaction fluxes) - length depends on how many variables are named there. - `[id].model`: **Valid** - `[id].strings`: **Invalid** -`[id].model` is only produced when `outputModel` is `true`. - ##### Validation Rules **`FluxBalanceAnalysis-0000`** (error) - The element fails a JSON Schema constraint attributable to FluxBalanceAnalysis that does not match any other numbered rule. ([source](specsheets/tasks/FluxBalanceAnalysis/v1.0.0/validation/FluxBalanceAnalysis-0000.md)) @@ -2467,14 +2466,6 @@ A dictionary of model variables (usually fluxes) to their final values, accessib > `outputVariables` is `ListOfStringsOrRef`: when the value is a reference, it must resolve to an array of strings. -**`FluxBalanceAnalysis-0006`** (error) - When the value of outputModel of a FluxBalanceAnalysis is provided directly, it must be a boolean. ([source](specsheets/tasks/FluxBalanceAnalysis/v1.0.0/validation/FluxBalanceAnalysis-0006.md)) - -> `outputModel` is `BooleanOrRef`: the value, when not a reference, must be a boolean. - -**`FluxBalanceAnalysis-0007`** (error) - When the value of outputModel of a FluxBalanceAnalysis is a reference, it must be a reference to a boolean. ([source](specsheets/tasks/FluxBalanceAnalysis/v1.0.0/validation/FluxBalanceAnalysis-0007.md)) - -> `outputModel` is `BooleanOrRef`: when the value is a reference, it must resolve to a boolean. - **`FluxBalanceAnalysis-0008`** (error) - The _type attribute of a FluxBalanceAnalysis must be "fluxBalanceAnalysis". ([source](specsheets/tasks/FluxBalanceAnalysis/v1.0.0/validation/FluxBalanceAnalysis-0008.md)) > `_type` is the discriminator field. For `FluxBalanceAnalysis` it must always equal `"fluxBalanceAnalysis"`. @@ -2616,7 +2607,7 @@ The reduced Jacobian as a list of lists, accessible as `[id]`, with axis labels ##### What it does -A `Repeat` whose iterations are chained: each depends on the output of the previous one. This is expressed with `loopVariables` - named `LoopVariable` entries whose value equals `initialValue` on the first iteration and thereafter equals `subsequentValues` (an output of one of the loop's `subTasks`). A subTask references a loop variable as `#tasks:[loop_id]:loopVariables:[loopvar_id]`. +A `Repeat` whose iterations are chained: each depends on the output of the previous one, with one iteration per element of its required `range` (a `Range`/`NumericRange`/`ParameterRange`), taken in order; a `Loop` always runs all of them and cannot end early. The chaining is expressed with `loopVariables` - named `LoopVariable` entries whose value equals `initialValue` on the first iteration and thereafter equals `subsequentValues` (an output of one of the loop's `subTasks`). A subTask references a loop variable as `#tasks:[loop_id]:loopVariables:[loopvar_id]`. ##### Attributes @@ -2628,7 +2619,7 @@ All classes additionally inherit the optional `name`, `description`, `notes`, an | `subTasks` | object (values: AbstractTask) | yes | | | `outputVariableMap` | object (values: SIdRef) or SIdRef | no | | | `aggregateOutputVariables` | object (values: AggregationCalculation) | no | | -| `range` | RangeInline | no | | +| `range` | RangeInline | yes | | | `loopVariables` | object (values: LoopVariable) | yes | | ###### Attribute details @@ -2641,7 +2632,7 @@ All classes additionally inherit the optional `name`, `description`, `notes`, an **`aggregateOutputVariables`** (object (values: AggregationCalculation), optional) - _(no description yet - placeholder, needs to be filled in)_ -**`range`** (RangeInline, optional) - _(no description yet - placeholder, needs to be filled in)_ +**`range`** (RangeInline, required) - _(no description yet - placeholder, needs to be filled in)_ **`loopVariables`** (object (values: LoopVariable), required) - _(no description yet - placeholder, needs to be filled in)_ @@ -2651,7 +2642,7 @@ All classes additionally inherit the optional `name`, `description`, `notes`, an `[id]`: an `AnnotatedData` whose first column is the range values and whose subsequent columns follow `outputVariableMap`. `[id].aggregates`: an `AnnotatedData` following `aggregateOutputVariables`, when defined. - `[id]`: **Valid** - - Dimensions: 2D (or more): first dimension = one row per iteration; remaining dimension(s) = one column per entry of `outputVariableMap`. Unlike `Scatter`, the row count isn't known in advance from a `range` - it's however many iterations the loop actually runs. _(Exact termination condition for a Loop's iteration count - placeholder, needs to be filled in from the spec.)_ + - Dimensions: 2D (or more): first dimension = one row per value in `range`; remaining dimension(s) = one column per entry of `outputVariableMap` (or just the range-values column alone, if `outputVariableMap` is empty). As with `Scatter`, the row count is known in advance from `range`. A column whose subTask output is itself multi-dimensional would add further dimensions - not pinned down further here. - `[id].model`: **Invalid** - `[id].strings`: **Invalid** @@ -2660,9 +2651,9 @@ Additional possible outputs beyond the three standard ones: - `[id].aggregates`: An `AnnotatedData` following `aggregateOutputVariables`, when that attribute is defined. - Dimensions: 1D: one entry per `aggregateOutputVariables` mapping, each collapsing the iteration dimension of `[id]` down to a single value (per `Repeat`, the applied dimension defaults to the Repeat's own iterations) - unless the underlying subTask output was itself multi-dimensional, in which case that dimensionality carries through per entry. -- `[id].range`: Within the loop, the current value of `range`, when `range` is defined (see `Repeat`). +- `[id].range`: Within the loop, the current value of `range`. Always valid, since `range` is required. - Dimensions: Scalar (0-D) per iteration. -- `[id].index`: Within the loop, the current index into `range`, when `range` is defined. +- `[id].index`: Within the loop, the current index into `range`. Always valid. - Dimensions: Scalar (0-D) per iteration. ##### Validation Rules @@ -3485,7 +3476,7 @@ Only valid when `ParameterRange` is used directly as a `tasks` dictionary entry. ##### What it does -Runs simulations/analyses over several systematically-varied versions of a model: a `Repeat` subclass that adds a `model` child (the model to scan) and one or more `ParameterRange` children (`parameterRanges`) - each scanned element adds a dimension to the output. Each `ParameterRange` must target a distinct `modelElement`, which must be an id within the child `model`. One of the `subTasks` must reference the scan's `model` child (`#tasks:[scanid]:model`) as its own input; the model is initialized with every combination of values across all the ranges. Mechanically it's otherwise identical to `Scatter`, and could in principle be reproduced with nested `Scatter`s plus careful `ModelChange` tasks. +Runs simulations/analyses over several systematically-varied versions of a model: a `Repeat` subclass that adds a `model` child (the model to scan) and one or more `ParameterRange` children (`parameterRanges`) - each scanned element adds a dimension to the output. Each `ParameterRange` must target a distinct `modelElement` (ParameterScan-0007), which must be an id within the child `model`; the `modelElement` also serves as the entry's name in `[id].ranges` and `[id].indexes`. One of the `subTasks` must reference the scan's `model` child (`#tasks:[scanid]:model`) as its own input; the model is initialized with every combination of values across all the ranges. Mechanically it's otherwise identical to `Scatter`, and could in principle be reproduced with nested `Scatter`s plus careful `ModelChange` tasks. Within the loop, the current value and index of each range are available as `[id].ranges` and `[id].indexes` (see Outputs below). ##### Attributes @@ -3512,7 +3503,7 @@ All classes additionally inherit the optional `name`, `description`, `notes`, an **`model`** (SIdRef, required) - _(no description yet - placeholder, needs to be filled in)_ -**`parameterRanges`** (array of ParameterRangeInline, required) - _(no description yet - placeholder, needs to be filled in)_ +**`parameterRanges`** (array of ParameterRangeInline, required) - The ranges to scan; at least one. The `modelElement` of each entry must be distinct within the scan (ParameterScan-0007), and labels that entry in `[id].ranges` and `[id].indexes`. ##### Outputs @@ -3520,7 +3511,7 @@ All classes additionally inherit the optional `name`, `description`, `notes`, an `[id]`: an `AnnotatedData` with one dimension per entry of `parameterRanges`, plus one further dimension sized by the number of entries in `outputVariableMap`. `[id].aggregates`: an `AnnotatedData` following `aggregateOutputVariables`, when defined. - `[id]`: **Valid** - - Dimensions: N-D: one dimension per entry in `parameterRanges` (each sized by that range's own number of steps), plus one further dimension sized by the number of entries in `outputVariableMap` - dimensionality grows with the number of ranges scanned. + - Dimensions: N-D: one dimension per entry in `parameterRanges` (each sized by that range's own number of steps, and each labeled with that range's `modelElement`), plus one further dimension sized by the number of entries in `outputVariableMap` - dimensionality grows with the number of ranges scanned. - `[id].model`: **Invalid** - `[id].strings`: **Invalid** @@ -3529,6 +3520,11 @@ Additional possible outputs beyond the three standard ones: - `[id].aggregates`: An `AnnotatedData` following `aggregateOutputVariables`, when that attribute is defined. - Dimensions: 1D: one entry per `aggregateOutputVariables` mapping. Each entry's aggregation collapses *all* of `[id]`'s scanned-range dimensions together (per `Repeat`, the applied dimension defaults to 'the Repeat' itself - here, the whole combined scan) down to a single value - unless the underlying subTask output was itself multi-dimensional, in which case that dimensionality carries through per entry. +- `[id].ranges`: Within the loop only, the current value of each of the scan's `parameterRanges`. + - Dimensions: 1D `AnnotatedData`: one entry per `ParameterRange` child, in order, labeled with that child's `modelElement`. For example, with children whose `modelElement`s are `calc`, `phos`, and `ant`, it holds the current values of `calc`, `phos`, and `ant`, in that order, labeled accordingly. +- `[id].indexes`: Within the loop only, the current index into each of the scan's `parameterRanges`. + - Dimensions: 1D `AnnotatedData`: one entry per `ParameterRange` child, in order, labeled with that child's `modelElement` - the current index of `calc`, `phos`, and `ant`, in that order, in the example above. + ##### Validation Rules **`ParameterScan-0000`** (error) - The element fails a JSON Schema constraint attributable to ParameterScan that does not match any other numbered rule. ([source](specsheets/tasks/ParameterScan/v1.0.0/validation/ParameterScan-0000.md)) @@ -3724,11 +3720,11 @@ The relabeled `AnnotatedData`, accessible as `[id]`. Like SED-ML Level 1's RepeatedTask, SED2 needs to repeat a group of tasks multiple times. `Repeat` is the set of fields shared by all three concrete subclasses (`Scatter`, `Loop`, `ParameterScan`), composed via `allOf` rather than instantiated on its own - the prose spec calls this abstract concept simply "Repeat". -The repeat's `subTasks` are true children (not references) of the parent, and may depend on each other, on outputs of tasks outside the repeat, or on the repeat's own `range`/`index` (the current iteration's range value and position, available as `[id].range`/`[id].index` - see Outputs below). `outputVariableMap` defines the columns of the repeat's own `[id]` output: the first column is always the range values, and each further named entry maps an output column name to a value produced by a subTask; if empty, `[id]` contains only the range values. `aggregateOutputVariables` defines the columns of `[id].aggregates` - used to efficiently collect running summary statistics (e.g. mean/stdev) across a very large number of repeats without keeping every individual run's output; entries here may not define their own `appliedDimensions` (the applied dimension is always 'the Repeat' itself), and each `input` must reference a subTask's output. +The repeat's `subTasks` are true children (not references) of the parent, and may depend on each other, on outputs of tasks outside the repeat, or on the repeat's own per-iteration outputs (the current iteration's range value and position: `[id].range`/`[id].index` for `Scatter` and `Loop`, `[id].ranges`/`[id].indexes` for `ParameterScan` - see those classes). `outputVariableMap` (optional) defines the columns of the repeat's own `[id]` output: each named entry maps an output column name to a value produced by a subTask. `Scatter` and `Loop` additionally make the first column the range values, so for them `[id]` contains only the range values if `outputVariableMap` is omitted; see each subclass for its exact `[id]` shape. `aggregateOutputVariables` defines the columns of `[id].aggregates` - used to efficiently collect running summary statistics (e.g. mean/stdev) across a very large number of repeats without keeping every individual run's output; entries here may not define their own `appliedDimensions` (the applied dimension is always 'the Repeat' itself), and each `input` must reference a subTask's output. A `Repeat`-derived task must define at least one of `outputVariableMap` or `aggregateOutputVariables`. -`range` (a `Range`/`NumericRange`/`ParameterRange`) is shared here rather than being redefined separately on each subclass - `Loop` and `Scatter` both use it directly; `ParameterScan` does not (it uses `parameterRanges` instead). +`Repeat` itself has no `range`: `Loop` and `Scatter` each define their own required `range` child (a `Range`/`NumericRange`/`ParameterRange`), and `ParameterScan` uses `parameterRanges` instead. ##### Attributes @@ -3737,9 +3733,8 @@ All classes additionally inherit the optional `name`, `description`, `notes`, an | Attribute | Type | Required | Notes | |---|---|---|---| | `subTasks` | object (values: AbstractTask) | no | | -| `outputVariableMap` | object (values: SIdRef) or SIdRef | no | | +| `outputVariableMap` | object (values: SIdRef) or SIdRef | no | Optional, but at least one of this or `aggregateOutputVariables` must be provided (Repeat-0006). | | `aggregateOutputVariables` | object (values: AggregationCalculation) | no | | -| `range` | RangeInline | no | Used by `Loop`/`Scatter`; not used by `ParameterScan` (see `parameterRanges` there instead). | ###### Attribute details @@ -3749,15 +3744,10 @@ All classes additionally inherit the optional `name`, `description`, `notes`, an **`aggregateOutputVariables`** (object (values: AggregationCalculation), optional) - _(no description yet - placeholder, needs to be filled in)_ -**`range`** (RangeInline, optional) - _(no description yet - placeholder, needs to be filled in)_ - ##### Outputs -Not applicable on its own - see `Scatter`, `Loop`, and `ParameterScan` for their concrete output shapes (`[id]` per `outputVariableMap`, `[id].aggregates` per `aggregateOutputVariables`). - -- `[id].range`: Within the loop, the current value of `range`. _(No description yet - placeholder, needs to be filled in: exact reference form and availability when `range` is unset.)_ -- `[id].index`: Within the loop, the current index into `range`. _(No description yet - placeholder, needs to be filled in.)_ +Not applicable on its own - see `Scatter`, `Loop`, and `ParameterScan` for their concrete output shapes (`[id]` per `outputVariableMap`, `[id].aggregates` per `aggregateOutputVariables`). The per-iteration range outputs (`[id].range`/`[id].index` on `Scatter` and `Loop`, `[id].ranges`/`[id].indexes` on `ParameterScan`) belong to those subclasses, not to `Repeat`. Shared mixin for the three `Repeat` subclasses - not instantiated on its own; see `Scatter`, `Loop`, `ParameterScan`. @@ -3785,10 +3775,6 @@ Shared mixin for the three `Repeat` subclasses - not instantiated on its own; se > `aggregateOutputVariables` is `object (values: AggregationCalculation)` in Repeat: it must be an object whose values are AggregationCalculation. -**`Repeat-0005`** (error) - The range attribute of a Repeat, if present, must be a RangeInline object. ([source](specsheets/tasks/Repeat/v1.0.0/validation/Repeat-0005.md)) - -> `range` is optional; when present, it must be a `Range`/`NumericRange`/`ParameterRange` object in its embedded `RangeInline` form. - **`Repeat-0006`** (error) - A Repeat must provide at least one of outputVariableMap or aggregateOutputVariables. ([source](specsheets/tasks/Repeat/v1.0.0/validation/Repeat-0006.md)) > Repeat's schema expresses this as an `anyOf` of two single-field `required` @@ -3828,7 +3814,7 @@ Shared mixin for the three `Repeat` subclasses - not instantiated on its own; se ##### What it does -A `Repeat` whose iterations are guaranteed fully independent of one another - no subTask output from one iteration feeds into another - so a conforming interpreter may execute the iterations in parallel if it chooses. `range` (a `Range`/`NumericRange`/`ParameterRange`) defines one iteration per element. +A `Repeat` whose iterations are guaranteed fully independent of one another - no subTask output from one iteration feeds into another - so a conforming interpreter may execute the iterations in parallel if it chooses. `range` (a required `Range`/`NumericRange`/`ParameterRange` child) defines one iteration per element. ##### Attributes @@ -3840,7 +3826,7 @@ All classes additionally inherit the optional `name`, `description`, `notes`, an | `subTasks` | object (values: AbstractTask) | yes | | | `outputVariableMap` | object (values: SIdRef) or SIdRef | no | | | `aggregateOutputVariables` | object (values: AggregationCalculation) | no | | -| `range` | RangeInline | no | | +| `range` | RangeInline | yes | | ###### Attribute details @@ -3852,7 +3838,7 @@ All classes additionally inherit the optional `name`, `description`, `notes`, an **`aggregateOutputVariables`** (object (values: AggregationCalculation), optional) - _(no description yet - placeholder, needs to be filled in)_ -**`range`** (RangeInline, optional) - _(no description yet - placeholder, needs to be filled in)_ +**`range`** (RangeInline, required) - _(no description yet - placeholder, needs to be filled in)_ ##### Outputs @@ -3869,9 +3855,9 @@ Additional possible outputs beyond the three standard ones: - `[id].aggregates`: An `AnnotatedData` following `aggregateOutputVariables`, when that attribute is defined. - Dimensions: 1D: one entry per `aggregateOutputVariables` mapping. Each entry's aggregation function collapses the `range` dimension of `[id]` (per `Repeat`, the applied dimension defaults to 'the Repeat' itself, i.e. this one) down to a single value - unless the underlying subTask output was itself multi-dimensional, in which case that dimensionality carries through per entry. -- `[id].range`: Within each iteration, the current value of `range` (see `Repeat`). +- `[id].range`: Within each iteration, the current value of `range`. Always valid, since `range` is required. - Dimensions: Scalar (0-D) per iteration. -- `[id].index`: Within each iteration, the current index into `range`. +- `[id].index`: Within each iteration, the current index into `range`. Always valid. - Dimensions: Scalar (0-D) per iteration. ##### Validation Rules @@ -3986,7 +3972,7 @@ Not independently referenceable - a `Span` only exists as a named child of the t Computes the steady state of a model: where dX/dt = 0 for every varying element X of the model, with respect to the independent variable (usually time). `independentVariable` follows the same rules as the simulation tasks (either the model's own variable, or an implicit URN such as `urn:sedml:symbol:time`). -This is an implementation of KISAO:0000407 (steady-state root-finding method). +This is an implementation of KISAO:0000407 (steady-state root-finding method). The algorithm(s) it uses internally may be listed in the optional `workingAlgorithms` (see `WorkingAlgorithm`). ##### Attributes @@ -3998,7 +3984,7 @@ All classes additionally inherit the optional `name`, `description`, `notes`, an | `model` | SIdRef | yes | | | `independentVariable` | StringOrRef | no | | | `outputVariables` | ListOfStringsOrRef | yes | | -| `outputModel` | BooleanOrRef | no | | +| `workingAlgorithms` | array of WorkingAlgorithm | no | | ###### Attribute details @@ -4010,20 +3996,18 @@ All classes additionally inherit the optional `name`, `description`, `notes`, an **`outputVariables`** (ListOfStringsOrRef, required) - _(no description yet - placeholder, needs to be filled in)_ -**`outputModel`** (BooleanOrRef, optional) - _(no description yet - placeholder, needs to be filled in)_ +**`workingAlgorithms`** (array of WorkingAlgorithm, optional) - _(no description yet - placeholder, needs to be filled in)_ ##### Outputs -The steady-state values of `outputVariables`, accessible as `[id]`. If `outputModel` is `true`, the resulting model state is also available as `[id].model`. +The steady-state values of `outputVariables`, accessible as `[id]`. The resulting model state is always also available as `[id].model`. - `[id]`: **Valid** - Dimensions: 1D: one value per entry of `outputVariables`, at steady state. - `[id].model`: **Valid** - `[id].strings`: **Invalid** -`[id].model` is only produced when `outputModel` is `true`. - ##### Validation Rules **`SteadyState-0000`** (error) - The element fails a JSON Schema constraint attributable to SteadyState that does not match any other numbered rule. ([source](specsheets/tasks/SteadyState/v1.0.0/validation/SteadyState-0000.md)) @@ -4048,14 +4032,6 @@ The steady-state values of `outputVariables`, accessible as `[id]`. If `outputMo > `independentVariable` is `StringOrRef`, which resolves to a plain string type; when present, it must be a string. -**`SteadyState-0005`** (error) - When the value of outputModel of a SteadyState is provided directly, it must be a boolean. ([source](specsheets/tasks/SteadyState/v1.0.0/validation/SteadyState-0005.md)) - -> `outputModel` is `BooleanOrRef`: the value, when not a reference, must be a boolean. - -**`SteadyState-0006`** (error) - When the value of outputModel of a SteadyState is a reference, it must be a reference to a boolean. ([source](specsheets/tasks/SteadyState/v1.0.0/validation/SteadyState-0006.md)) - -> `outputModel` is `BooleanOrRef`: when the value is a reference, it must resolve to a boolean. - #### StringFormation *Source: [specsheets/tasks/StringFormation/v1.0.0/description.md](specsheets/tasks/StringFormation/v1.0.0/description.md)* @@ -5020,9 +4996,7 @@ Not independently referenceable - only exists as a named child within a `Plot2D` *Source: [specsheets/auxiliary/LoopVariable/v1.0.0/description.md](specsheets/auxiliary/LoopVariable/v1.0.0/description.md)* -![LoopVariable UML diagram](specsheets/tasks/Loop/v1.0.0/Loop.png) - -*(`LoopVariable` has no standalone diagram of its own - the image above is `Loop`'s diagram, reused here because `LoopVariable` is drawn fully within it as a linked box, right next to `Loop`. Look for the `LoopVariable` box.)* +![LoopVariable UML diagram](specsheets/auxiliary/LoopVariable/v1.0.0/LoopVariable.png) **Category:** auxiliary **Version:** v1 @@ -5200,9 +5174,7 @@ Not independently referenceable - only exists as an entry in its parent task's ` *Source: [specsheets/auxiliary/WorkingAlgorithm/v1.0.0/description.md](specsheets/auxiliary/WorkingAlgorithm/v1.0.0/description.md)* -![WorkingAlgorithm UML diagram](specsheets/tasks/AbstractSimulation/v1.0.0/AbstractSimulation.png) - -*(`WorkingAlgorithm` has no standalone diagram of its own - the image above is `AbstractSimulation`'s diagram, reused here because `WorkingAlgorithm` is drawn fully within it as a linked box, right next to `AbstractSimulation`. Look for the `workingAlgorithm` box.)* +![WorkingAlgorithm UML diagram](specsheets/auxiliary/WorkingAlgorithm/v1.0.0/WorkingAlgorithm.png) **Category:** auxiliary **Version:** v1 @@ -5210,7 +5182,7 @@ Not independently referenceable - only exists as an entry in its parent task's ` ##### What it does -An algorithm used internally by a simulation task, attached via `AbstractSimulation`'s `workingAlgorithms` list. Beyond the fields it inherits from `SEDBase`, it carries a required `algorithm`. +An algorithm used internally by a task, attached via a `workingAlgorithms` list: the one `AbstractSimulation` defines (and so every ODE/stochastic simulation task has), or the one `SteadyState` and `FluxBalanceAnalysis` each declare directly. Beyond the fields it inherits from `SEDBase`, it carries a required `algorithm`. _(No description yet - placeholder. It's not yet clear from the diagram alone how `algorithm` relates to the task's own `_type` discriminator and `taskParameters`, or how multiple `workingAlgorithms` entries on one task are meant to be distinguished/used - needs updating once that's settled.)_ diff --git a/core-spec.md b/core-spec.md index 147fe4c..a42a08c 100644 --- a/core-spec.md +++ b/core-spec.md @@ -102,7 +102,7 @@ Each `//v1.0.0/` folder normally contains exactly: Every `schema.json`'s `required` array carries a sibling `x-required-rule-ids` object mapping each required field's name to the numbered validation rule that documents its presence requirement, and any property whose own constraint - a `_type` discriminator `const`, or a type/shape check beyond bare presence - has a matching numbered rule carries a sibling `x-rule-id` alongside that constraint (as a sibling of `$ref` where the property is declared that way); `x-rule-id` is a single rule-ID string, or an array of them when more than one rule governs the same property (most commonly an `OrRef` field's separate direct-value and reference-form rules, e.g. `AbstractODESimulation.forcePhysicalCorrectness`). A bare `SIdRef` property that must resolve to a particular kind of thing also carries `"x-ref-target": "model"` (SEDBase-0016) or `"x-ref-target": "annotatedData"` (SEDBase-0017). All of these are inert to any JSON Schema validator (unknown keywords are ignored) and exist purely as generator-only metadata - see Design.md's Validation section - so the generator can wire each hand-written `validate()` check straight to the schema location it corresponds to rather than re-deriving that mapping itself. Not every numbered rule has a schema-visible home this way: most are semantic (cross-reference resolution, math well-formedness, tolerance interactions, and the like) with no single JSON Schema keyword to attach to; only presence, discriminator, and simple type/shape constraints get one. A class whose own requiredness is disjunctive rather than a flat list - so far, only `Repeat`, whose subclasses need at least one of `outputVariableMap` or `aggregateOutputVariables` rather than a fixed set - expresses that as an `anyOf` of single-field `required` objects at the class's own top level (sibling to `properties`), with a sibling `x-anyof-required-rule-id` naming the one rule documenting the whole disjunction, rather than forcing it into `x-required-rule-ids`'s per-field mapping. A `oneOf` discriminator built via `x-generated-oneOf` (see Design.md's Classes section) can similarly carry a sibling `x-missing-type-rule-id`, naming a rule for the narrower case where `_type` is absent from the instance entirely, rather than present but unrecognized - a more specific error than the discriminator's own catch-all, for whichever discriminators want to distinguish it (e.g. `AbstractTask-0002`). -**Task output shapes (`outputs.json`).** Every concrete `tasks/` class (one with its own `_type`) additionally carries an `outputs.json`, machine-describing what each output suffix (`[id]`, `[id].model`, `[id].strings`, and any class-specific suffix like `Loop`'s `[id].aggregates`/`[id].range`/`[id].index`) resolves to - replacing the free-text "Valid"/"Invalid"/"Dimensions:" bullets that used to be the only record of this. Each suffix entry has a `valid` flag (`true`/`false`, or a boolean expression string over the task's own fields, e.g. `"outputModel == true"`, `"provided(range)"`), a `type` (`annotatedData`/`model`/`stringList`) when valid, and for `annotatedData` a `dimensions` list. Every place a size, a label set, or a whole shape needs stating, it's tagged with where that knowledge actually comes from - `"static"` (an `expr` computed from the task's own fields: `len(outputVariables)`, `independentVariableRange.numberOfSteps`, `keys(data)`, `[independentVariable] + outputVariables` as an array-literal-plus-concatenation, `shapeOf(input)` to inherit another reference's whole shape, optionally minus a dropped dimension via `- dim(...)`), `"input-file"` (knowable only by reading whatever external resource a field like `model` or `location` points to - `JacobianFull`'s species count, `CsvImport`'s column headers - tagged with `from`/`extract`/`note` rather than a formula, since the actual parsing is format-specific generator work, not something this file does itself), or `"runtime"` (genuinely not derivable without executing the simulation, e.g. `BoundedODESimulation`'s solver-chosen row count under variable step size, or `Loop`'s iteration count - always paired with a `note` explaining why). A `"runtime"` size may also carry an optional `min`, a guaranteed lower bound when one is actually known (e.g. "at least 2 rows"); an index or range that requires more entries than `min` guarantees is flagged by `SEDBase-0014` as a warning rather than an error, since it may still be valid once the simulation actually runs. `dimensions` itself is either a fixed array of per-dimension entries - an ordinary entry, or a `repeat` entry that expands to one dimension per entry of a named array-valued attribute (e.g. `ParameterScan`'s one dimension per entry of `parameterRanges`) - when the shape is decomposable dimension-by-dimension, or a single sourced object describing the whole shape's derivation, for the genuinely non-decomposable cases (`shapeOf(x)` whole-shape inheritance, or a `"runtime"`/`"input-file"` source where the dimension count itself isn't knowable ahead of time). `schema/outputs-meta.schema.json` validates every class's `outputs.json` envelope (the object shapes above); it does not parse `expr`/`note` string contents, which stay documentation for whoever implements the generator's shape-inference step. Abstract/mixin classes (`AbstractSimulation` and friends, `Repeat`) carry no `outputs.json` of their own, the same reasoning as why they carry no `_type` - nothing is ever instantiated as one directly, so "what does referencing this task's output produce" has no meaning until a concrete leaf class answers it, flatly, the same way those classes already flatten every other inherited constraint into their own `schema.json`. +**Task output shapes (`outputs.json`).** Every concrete `tasks/` class (one with its own `_type`) additionally carries an `outputs.json`, machine-describing what each output suffix (`[id]`, `[id].model`, `[id].strings`, and any class-specific suffix like `Loop`'s `[id].aggregates`/`[id].range`/`[id].index`) resolves to - replacing the free-text "Valid"/"Invalid"/"Dimensions:" bullets that used to be the only record of this. A suffix that is listed is valid, and a suffix that is not listed is not valid (a class with no valid suffixes, such as `Span`, lists none). A listed entry may carry an optional `valid` field meaning "valid if": a boolean expression string over the task's own fields, e.g. `"outputModel == true"`, `"provided(range)"`; with no `valid` field the entry is always valid. Each entry has a `type` (`annotatedData`/`model`/`stringList`), and for `annotatedData` a `dimensions` list. Every place a size, a label set, or a whole shape needs stating, it's tagged with where that knowledge actually comes from - `"static"` (an `expr` computed from the task's own fields: `len(outputVariables)`, `independentVariableRange.numberOfSteps`, `keys(data)`, `[independentVariable] + outputVariables` as an array-literal-plus-concatenation, `shapeOf(input)` to inherit another reference's whole shape, optionally minus a dropped dimension via `- dim(...)`), `"input-file"` (knowable only by reading whatever external resource a field like `model` or `location` points to - `JacobianFull`'s species count, `CsvImport`'s column headers - tagged with `from`/`extract`/`note` rather than a formula, since the actual parsing is format-specific generator work, not something this file does itself), or `"runtime"` (genuinely not derivable without executing the simulation, e.g. `BoundedODESimulation`'s solver-chosen row count under variable step size, or `Loop`'s iteration count - always paired with a `note` explaining why). A `"runtime"` size may also carry an optional `min`, a guaranteed lower bound when one is actually known (e.g. "at least 2 rows"); an index or range that requires more entries than `min` guarantees is flagged by `SEDBase-0014` as a warning rather than an error, since it may still be valid once the simulation actually runs. `dimensions` itself is either a fixed array of per-dimension entries - an ordinary entry, or a `repeat` entry that expands to one dimension per entry of a named array-valued attribute (e.g. `ParameterScan`'s one dimension per entry of `parameterRanges`) - when the shape is decomposable dimension-by-dimension, or a single sourced object describing the whole shape's derivation, for the genuinely non-decomposable cases (`shapeOf(x)` whole-shape inheritance, or a `"runtime"`/`"input-file"` source where the dimension count itself isn't knowable ahead of time). `schema/outputs-meta.schema.json` validates every class's `outputs.json` envelope (the object shapes above); it does not parse `expr`/`note` string contents, which stay documentation for whoever implements the generator's shape-inference step. Abstract/mixin classes (`AbstractSimulation` and friends, `Repeat`) carry no `outputs.json` of their own, the same reasoning as why they carry no `_type` - nothing is ever instantiated as one directly, so "what does referencing this task's output produce" has no meaning until a concrete leaf class answers it, flatly, the same way those classes already flatten every other inherited constraint into their own `schema.json`. **The `expr`/`valid` notation.** Both fields reuse one small expression language, evaluated against the task's own attribute values at generate/validate time - never against runtime data, and not the SED2 math grammar `Types-0001` through `Types-0004` validate (see this section's `x-rule-id` paragraph above and `Design.md`'s Math section for that separate grammar): `outputs.json` describes shape, `math` describes computation. A bare identifier names one of the task's own attributes and evaluates to its value (`outputVariables`); a dotted path reaches into a nested attribute the same way (`independentVariableRange.numberOfSteps`). `[x]` is an array literal (`[independentVariable]`); JSON numbers and `true`/`false` are literals too. Five functions: `len(x)` - the length of an array-valued `x`; or, when `x` is a Range-family value (a `RangeInline`/`NumericRangeInline`/`ParameterRangeInline`-typed field, or the reserved identifier `self` inside a `repeat` entry - see below), the number of points it resolves to, dispatched on `x`'s own discriminated type: `len(x.values) if provided(x.values) else x.numberOfSteps + 1` for `NumericRange`/`ParameterRange`, or just `len(x.values)` for a bare `Range` (which has no `numberOfSteps` alternative); `keys(x)` - the keys of an object-valued `x`, as an array; `shapeOf(x)` - the whole `dimensions` shape of a referenced AnnotatedData value; `dim(x)` - the dimension(s) named by `x` (a single name or a list of names) within a shape, meaningful only as the right operand of `-`; `provided(x)` - `true` iff attribute `x` was given a value in the document. Operators, at ordinary precedence: `!x` (boolean negation); `x == y` (equality); `x + y` (numeric addition when both operands are numbers, array concatenation when both are arrays - `1 + len(outputVariables)` vs. `[independentVariable] + outputVariables`); `shapeOf(x) - dim(y)` (a shape with the named dimension(s) removed - the only place `-` appears); `x or y` (`x`'s value when `provided(x)` holds, else the literal `y` - used for a field with a documented default, e.g. `dim(appliedDimensions or outermost)`, where `outermost` is a sentinel meaning the shape's own first dimension); and a conditional `x if provided(y) else z` for a value with two different derivations depending on whether an alternate field was given instead (e.g. `NumericRange`'s `len(values) if provided(values) else numberOfSteps + 1`). This is the only formal definition of the notation - `schema/outputs-meta.schema.json` does not parse it, as noted above - so a generator's shape-inference step implements it by hand. Inside a `dimensions` array's `repeat` entry (see above), this same notation applies to that entry's own `size`/`labels`, with two scoping additions: a bare identifier there resolves against the current array entry's own fields, not the task's top-level attributes; and the reserved identifier `self` refers to the current entry as a whole (for taking its `len()`, per above) rather than one of its fields. `ParameterScan`'s `repeat` over `parameterRanges` uses `size: len(self)`, letting each entry's own type (`Range`/`NumericRange`/`ParameterRange`) determine its own length the same way `Scatter`'s `len(range)` and `ExplicitODESimulation`'s `len(independentVariableRange)` do for their own named Range-family fields. @@ -119,7 +119,7 @@ tasks/Range/v1.0.0/ tasks/NumericRange/v1.0.0/ task `Range` and `NumericRange` carry an extra `common.schema.json` that `ParameterRange` and `Span` don't need: `Range` is both directly instantiable and the parent of `NumericRange`, and `NumericRange` is in turn both directly instantiable and the parent of `ParameterRange` - so each contributes a `RangeCommon`/`NumericRangeCommon` mixin (composed via `allOf`) carrying the fields its subclass inherits, alongside its own `schema.json` for the standalone-task form. `ParameterRange` and `Span` are leaves - nothing subclasses them - so they need no such split. Each mixin composes the next one up in turn (`NumericRangeCommon` composes `RangeCommon`, which composes `AbstractTaskCommon`), so a concrete class's own `allOf` names only its one most specific ancestor mixin - `ParameterRange` lists just `NumericRangeCommon`, not `RangeCommon` and `NumericRangeCommon` side by side - mirroring the UML chain directly rather than flattening every ancestor into each leaf; see `Design.md`'s Classes section for why. -Each `description.md` in these four folders explains all of that folder's schema files. Everything else in the document - including every cross-reference into these four classes from other Data Sheets' `schema.json` files - still resolves correctly; this was verified by validating real SED2 example documents against the split schemas after the merge. All four live under `tasks/` rather than `auxiliary/`, so each also carries the ordinary `outputs.json` every concrete `tasks/` class does - `Range`, `NumericRange`, and `ParameterRange` describe their `[id]` output for when they're used as a standalone `tasks` entry, and `Span`'s marks every suffix invalid, matching its own `description.md` (`Span` can never be a standalone `tasks` entry, only ever an embedded child, so it has no output of its own). +Each `description.md` in these four folders explains all of that folder's schema files. Everything else in the document - including every cross-reference into these four classes from other Data Sheets' `schema.json` files - still resolves correctly; this was verified by validating real SED2 example documents against the split schemas after the merge. All four live under `tasks/` rather than `auxiliary/`, so each also carries the ordinary `outputs.json` every concrete `tasks/` class does - `Range`, `NumericRange`, and `ParameterRange` describe their `[id]` output for when they're used as a standalone `tasks` entry, and `Span`'s lists no suffixes at all (so every suffix is invalid), matching its own `description.md` (`Span` can never be a standalone `tasks` entry, only ever an embedded child, so it has no output of its own). **Exception - the two `*Common` mixins.** `AbstractTaskCommon` and `AbstractOutputCommon` are schema-only mixins (composed via `allOf`) rather than modeled classes with their own UML box: they contribute the fields every concrete Task (or Output) picks up beyond `SEDBase` - `taskParameters`/`outputParameters` - but have no `_type` of their own and are never instantiated directly. Rather than give them placeholder folders, each is merged into its family's base-class folder as a second schema file: diff --git a/fixtures/handwritten/LoopVariable-0004-fail-01-constant-target.sed2.json b/fixtures/handwritten/LoopVariable-0004-fail-01-constant-target.sed2.json index 4337ebd..f275140 100644 --- a/fixtures/handwritten/LoopVariable-0004-fail-01-constant-target.sed2.json +++ b/fixtures/handwritten/LoopVariable-0004-fail-01-constant-target.sed2.json @@ -31,6 +31,14 @@ }, "outputVariableMap": { "col": "#tasks:loop1:subTasks:sub1.model" + }, + "range": { + "_type": "numericRange", + "values": [ + 1, + 2, + 3 + ] } } } diff --git a/fixtures/handwritten/LoopVariable-0004-fail-01-scalar-constant-target.sed2.json b/fixtures/handwritten/LoopVariable-0004-fail-01-scalar-constant-target.sed2.json index c36f384..2ebe3c6 100644 --- a/fixtures/handwritten/LoopVariable-0004-fail-01-scalar-constant-target.sed2.json +++ b/fixtures/handwritten/LoopVariable-0004-fail-01-scalar-constant-target.sed2.json @@ -31,6 +31,14 @@ }, "outputVariableMap": { "col": "#tasks:loop1:subTasks:sub1.model" + }, + "range": { + "_type": "numericRange", + "values": [ + 1, + 2, + 3 + ] } } } diff --git a/fixtures/handwritten/Repeat-0008-fail-01-constant-target.sed2.json b/fixtures/handwritten/Repeat-0008-fail-01-constant-target.sed2.json index ff3f614..0054c00 100644 --- a/fixtures/handwritten/Repeat-0008-fail-01-constant-target.sed2.json +++ b/fixtures/handwritten/Repeat-0008-fail-01-constant-target.sed2.json @@ -31,6 +31,14 @@ }, "outputVariableMap": { "col": "#constants:myNumberArray" + }, + "range": { + "_type": "numericRange", + "values": [ + 1, + 2, + 3 + ] } } } diff --git a/fixtures/handwritten/Repeat-0008-pass-00-subtask-target.sed2.json b/fixtures/handwritten/Repeat-0008-pass-00-subtask-target.sed2.json index f91a3c7..0626665 100644 --- a/fixtures/handwritten/Repeat-0008-pass-00-subtask-target.sed2.json +++ b/fixtures/handwritten/Repeat-0008-pass-00-subtask-target.sed2.json @@ -31,6 +31,14 @@ }, "outputVariableMap": { "col": "#tasks:loop1:subTasks:sub1.model" + }, + "range": { + "_type": "numericRange", + "values": [ + 1, + 2, + 3 + ] } } } diff --git a/fixtures/handwritten/Repeat-0009-fail-01-constant-input.sed2.json b/fixtures/handwritten/Repeat-0009-fail-01-constant-input.sed2.json index d0cd4ba..c502985 100644 --- a/fixtures/handwritten/Repeat-0009-fail-01-constant-input.sed2.json +++ b/fixtures/handwritten/Repeat-0009-fail-01-constant-input.sed2.json @@ -37,6 +37,14 @@ "_type": "aggregationCalculation", "input": "#constants:mynumber" } + }, + "range": { + "_type": "numericRange", + "values": [ + 1, + 2, + 3 + ] } } } diff --git a/fixtures/handwritten/SEDBase-0006-fail-01-missing-loop-variable.sed2.json b/fixtures/handwritten/SEDBase-0006-fail-01-missing-loop-variable.sed2.json index 5716b91..750f4ed 100644 --- a/fixtures/handwritten/SEDBase-0006-fail-01-missing-loop-variable.sed2.json +++ b/fixtures/handwritten/SEDBase-0006-fail-01-missing-loop-variable.sed2.json @@ -55,6 +55,14 @@ "location": "model.xml", "language": "urn:sedml:language:sbml" } + }, + "range": { + "_type": "numericRange", + "values": [ + 1, + 2, + 3 + ] } }, "r1": { diff --git a/fixtures/handwritten/SEDBase-0006-fail-01-missing-subtask.sed2.json b/fixtures/handwritten/SEDBase-0006-fail-01-missing-subtask.sed2.json index 3a82b6e..eae4b45 100644 --- a/fixtures/handwritten/SEDBase-0006-fail-01-missing-subtask.sed2.json +++ b/fixtures/handwritten/SEDBase-0006-fail-01-missing-subtask.sed2.json @@ -55,6 +55,14 @@ "location": "model.xml", "language": "urn:sedml:language:sbml" } + }, + "range": { + "_type": "numericRange", + "values": [ + 1, + 2, + 3 + ] } }, "r1": { diff --git a/fixtures/handwritten/SEDBase-0006-pass-00-deep-reference-from-inside-repeat.sed2.json b/fixtures/handwritten/SEDBase-0006-pass-00-deep-reference-from-inside-repeat.sed2.json index 3c8b7e9..a7d84bd 100644 --- a/fixtures/handwritten/SEDBase-0006-pass-00-deep-reference-from-inside-repeat.sed2.json +++ b/fixtures/handwritten/SEDBase-0006-pass-00-deep-reference-from-inside-repeat.sed2.json @@ -73,6 +73,14 @@ ] } } + }, + "range": { + "_type": "numericRange", + "values": [ + 1, + 2, + 3 + ] } } } diff --git a/fixtures/handwritten/SEDBase-0008-fail-01-conditional-accessor-false.sed2.json b/fixtures/handwritten/SEDBase-0008-fail-01-conditional-accessor-false.sed2.json index f12d48b..b0ac684 100644 --- a/fixtures/handwritten/SEDBase-0008-fail-01-conditional-accessor-false.sed2.json +++ b/fixtures/handwritten/SEDBase-0008-fail-01-conditional-accessor-false.sed2.json @@ -41,31 +41,47 @@ ] } }, - "ss1": { - "_type": "steadyState", - "model": "#tasks:m1.model", - "outputVariables": [ - "S1" - ], - "outputModel": false - }, - "s2": { - "_type": "explicitODESimulation", - "model": "#tasks:ss1.model", - "independentVariable": "time", - "outputVariables": [ - "S1", - "S2" - ], - "independentVariableRange": { + "loop1": { + "_type": "loop", + "loopVariables": { + "lv1": { + "initialValue": 0, + "subsequentValues": "#tasks:loop1:subTasks:s1" + } + }, + "subTasks": { + "s1": { + "_type": "explicitODESimulation", + "model": "#tasks:m1.model", + "independentVariable": "time", + "outputVariables": [ + "S1", + "S2" + ], + "independentVariableRange": { + "_type": "numericRange", + "values": [ + 0, + 1, + 2, + 3 + ] + } + } + }, + "range": { "_type": "numericRange", "values": [ - 0, 1, 2, 3 ] } + }, + "r1": { + "_type": "relabelData", + "input": "#tasks:loop1.aggregates", + "labels": "#constants:k_strings" } } } diff --git a/fixtures/handwritten/SEDBase-0008-pass-00-conditional-accessor-depends-on-reference.sed2.json b/fixtures/handwritten/SEDBase-0008-pass-00-conditional-accessor-depends-on-reference.sed2.json deleted file mode 100644 index c6c89c8..0000000 --- a/fixtures/handwritten/SEDBase-0008-pass-00-conditional-accessor-depends-on-reference.sed2.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "version": "v1.0.0", - "constants": { - "k_num": 1.5, - "k_strings": [ - "a", - "b" - ], - "k_array": [ - 10, - 20, - 30 - ], - "k_obj": { - "a": 1, - "b": 2 - }, - "k_str": "hello", - "k_bool": false - }, - "tasks": { - "m1": { - "_type": "modelImport", - "location": "model.xml", - "language": "urn:sedml:language:sbml" - }, - "sim1": { - "_type": "explicitODESimulation", - "model": "#tasks:m1.model", - "independentVariable": "time", - "outputVariables": [ - "S1", - "S2" - ], - "independentVariableRange": { - "_type": "numericRange", - "values": [ - 0, - 1, - 2, - 3 - ] - } - }, - "ss1": { - "_type": "steadyState", - "model": "#tasks:m1.model", - "outputVariables": [ - "S1" - ], - "outputModel": "#constants:k_bool" - }, - "s2": { - "_type": "explicitODESimulation", - "model": "#tasks:ss1.model", - "independentVariable": "time", - "outputVariables": [ - "S1", - "S2" - ], - "independentVariableRange": { - "_type": "numericRange", - "values": [ - 0, - 1, - 2, - 3 - ] - } - } - } -} diff --git a/fixtures/handwritten/SEDBase-0008-pass-00-conditional-accessor-true.sed2.json b/fixtures/handwritten/SEDBase-0008-pass-00-conditional-accessor-true.sed2.json index 8f9c822..0e3c333 100644 --- a/fixtures/handwritten/SEDBase-0008-pass-00-conditional-accessor-true.sed2.json +++ b/fixtures/handwritten/SEDBase-0008-pass-00-conditional-accessor-true.sed2.json @@ -41,31 +41,53 @@ ] } }, - "ss1": { - "_type": "steadyState", - "model": "#tasks:m1.model", - "outputVariables": [ - "S1" - ], - "outputModel": true - }, - "s2": { - "_type": "explicitODESimulation", - "model": "#tasks:ss1.model", - "independentVariable": "time", - "outputVariables": [ - "S1", - "S2" - ], - "independentVariableRange": { + "loop1": { + "_type": "loop", + "loopVariables": { + "lv1": { + "initialValue": 0, + "subsequentValues": "#tasks:loop1:subTasks:s1" + } + }, + "subTasks": { + "s1": { + "_type": "explicitODESimulation", + "model": "#tasks:m1.model", + "independentVariable": "time", + "outputVariables": [ + "S1", + "S2" + ], + "independentVariableRange": { + "_type": "numericRange", + "values": [ + 0, + 1, + 2, + 3 + ] + } + } + }, + "range": { "_type": "numericRange", "values": [ - 0, 1, 2, 3 ] + }, + "aggregateOutputVariables": { + "a1": { + "_type": "aggregationCalculation", + "input": "#tasks:loop1:subTasks:s1" + } } + }, + "r1": { + "_type": "relabelData", + "input": "#tasks:loop1.aggregates", + "labels": "#constants:k_strings" } } } diff --git a/fixtures/handwritten/SEDBase-0009-pass-00-runtime-dimension-never-fires.sed2.json b/fixtures/handwritten/SEDBase-0009-pass-00-runtime-dimension-never-fires.sed2.json index bf15a16..5ae18bb 100644 --- a/fixtures/handwritten/SEDBase-0009-pass-00-runtime-dimension-never-fires.sed2.json +++ b/fixtures/handwritten/SEDBase-0009-pass-00-runtime-dimension-never-fires.sed2.json @@ -41,25 +41,13 @@ ] } }, - "loop1": { - "_type": "loop", - "loopVariables": { - "lv1": { - "initialValue": 0, - "subsequentValues": "#tasks:loop1:subTasks:s1.model" - } - }, - "subTasks": { - "s1": { - "_type": "modelImport", - "location": "model.xml", - "language": "urn:sedml:language:sbml" - } - } + "calc1": { + "_type": "calculation", + "math": "1 + 1" }, "r1": { "_type": "relabelData", - "input": "#tasks:loop1[0][1][2]", + "input": "#tasks:calc1[0][1][2]", "labels": "#constants:k_strings" } } diff --git a/fixtures/handwritten/SEDBase-0011-pass-00-runtime-size-never-fires.sed2.json b/fixtures/handwritten/SEDBase-0011-pass-00-runtime-size-never-fires.sed2.json index 61f4456..ee19e67 100644 --- a/fixtures/handwritten/SEDBase-0011-pass-00-runtime-size-never-fires.sed2.json +++ b/fixtures/handwritten/SEDBase-0011-pass-00-runtime-size-never-fires.sed2.json @@ -41,25 +41,23 @@ ] } }, - "loop1": { - "_type": "loop", - "loopVariables": { - "lv1": { - "initialValue": 0, - "subsequentValues": "#tasks:loop1:subTasks:s1.model" - } - }, - "subTasks": { - "s1": { - "_type": "modelImport", - "location": "model.xml", - "language": "urn:sedml:language:sbml" - } + "b1": { + "_type": "boundedODESimulation", + "model": "#tasks:m1.model", + "independentVariable": "time", + "outputVariables": [ + "S1", + "S2" + ], + "independentVariableSpan": { + "_type": "span", + "start": 0, + "end": 10 } }, "r1": { "_type": "relabelData", - "input": "#tasks:loop1[1000]", + "input": "#tasks:b1[1000]", "labels": "#constants:k_strings" } } diff --git a/fixtures/handwritten/SEDBase-0013-pass-00-nested-subtask-uses-outer-index.sed2.json b/fixtures/handwritten/SEDBase-0013-pass-00-nested-subtask-uses-outer-index.sed2.json index af6e664..f986a9f 100644 --- a/fixtures/handwritten/SEDBase-0013-pass-00-nested-subtask-uses-outer-index.sed2.json +++ b/fixtures/handwritten/SEDBase-0013-pass-00-nested-subtask-uses-outer-index.sed2.json @@ -100,6 +100,14 @@ "input": "#tasks:loop1.index", "labels": "#constants:k_strings" } + }, + "range": { + "_type": "numericRange", + "values": [ + 1, + 2, + 3 + ] } } }, diff --git a/generated/cpp/include/libsed2/GeneratedModel.hpp b/generated/cpp/include/libsed2/GeneratedModel.hpp index 76d98a5..903a67c 100644 --- a/generated/cpp/include/libsed2/GeneratedModel.hpp +++ b/generated/cpp/include/libsed2/GeneratedModel.hpp @@ -208,7 +208,7 @@ class AggregationCalculation : public SedBase { std::string class_name() const override { return "AggregationCalculation"; } const Json* outputs_json() const override { static const Json j = Json::parse( - "{\"outputs\":{\"[id]\":{\"valid\":true,\"type\":\"annotatedData\",\"dimensions\":{\"source\":\"static\",\"expr\":\"shapeOf(input) - dim(appliedDimensions or outermost)\"}},\"[id].model\":{\"valid\":false},\"[id].strings\":{\"valid\":false}}}"); + "{\"outputs\":{\"[id]\":{\"type\":\"annotatedData\",\"dimensions\":{\"source\":\"static\",\"expr\":\"shapeOf(input) - dim(appliedDimensions or outermost)\"}}}}"); return &j; } std::optional get_type_value() const override { return std::string("aggregationCalculation"); } @@ -329,7 +329,7 @@ class BoundedODESimulation : public SedBase { std::string class_name() const override { return "BoundedODESimulation"; } const Json* outputs_json() const override { static const Json j = Json::parse( - "{\"outputs\":{\"[id]\":{\"valid\":true,\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"runtime\"},\"labels\":null},{\"size\":{\"source\":\"static\",\"expr\":\"1 + len(outputVariables)\"},\"labels\":{\"source\":\"static\",\"expr\":\"[independentVariable] + outputVariables\"}}]},\"[id].model\":{\"valid\":true,\"type\":\"model\"},\"[id].strings\":{\"valid\":false}}}"); + "{\"outputs\":{\"[id]\":{\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"runtime\"},\"labels\":null},{\"size\":{\"source\":\"static\",\"expr\":\"1 + len(outputVariables)\"},\"labels\":{\"source\":\"static\",\"expr\":\"[independentVariable] + outputVariables\"}}]},\"[id].model\":{\"type\":\"model\"}}}"); return &j; } std::optional get_type_value() const override { return std::string("boundedODESimulation"); } @@ -644,7 +644,7 @@ class BoundedStochasticSimulation : public SedBase { std::string class_name() const override { return "BoundedStochasticSimulation"; } const Json* outputs_json() const override { static const Json j = Json::parse( - "{\"outputs\":{\"[id]\":{\"valid\":true,\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"runtime\"},\"labels\":null},{\"size\":{\"source\":\"static\",\"expr\":\"1 + len(outputVariables)\"},\"labels\":{\"source\":\"static\",\"expr\":\"[independentVariable] + outputVariables\"}}]},\"[id].model\":{\"valid\":true,\"type\":\"model\"},\"[id].strings\":{\"valid\":false}}}"); + "{\"outputs\":{\"[id]\":{\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"runtime\"},\"labels\":null},{\"size\":{\"source\":\"static\",\"expr\":\"1 + len(outputVariables)\"},\"labels\":{\"source\":\"static\",\"expr\":\"[independentVariable] + outputVariables\"}}]},\"[id].model\":{\"type\":\"model\"}}}"); return &j; } std::optional get_type_value() const override { return std::string("boundedStochasticSimulation"); } @@ -856,7 +856,7 @@ class Calculation : public SedBase { std::string class_name() const override { return "Calculation"; } const Json* outputs_json() const override { static const Json j = Json::parse( - "{\"outputs\":{\"[id]\":{\"valid\":true,\"type\":\"annotatedData\",\"dimensions\":{\"source\":\"runtime\"}},\"[id].model\":{\"valid\":false}}}"); + "{\"outputs\":{\"[id]\":{\"type\":\"annotatedData\",\"dimensions\":{\"source\":\"runtime\"}}}}"); return &j; } std::optional get_type_value() const override { return std::string("calculation"); } @@ -948,7 +948,7 @@ class CreateDataBlock : public SedBase { std::string class_name() const override { return "CreateDataBlock"; } const Json* outputs_json() const override { static const Json j = Json::parse( - "{\"outputs\":{\"[id]\":{\"valid\":true,\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"static\",\"expr\":\"len(data)\"},\"labels\":{\"source\":\"static\",\"expr\":\"keys(data)\"}}]},\"[id].model\":{\"valid\":false}}}"); + "{\"outputs\":{\"[id]\":{\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"static\",\"expr\":\"len(data)\"},\"labels\":{\"source\":\"static\",\"expr\":\"keys(data)\"}}]}}}"); return &j; } std::optional get_type_value() const override { return std::string("createDataBlock"); } @@ -1047,7 +1047,7 @@ class CsvImport : public SedBase { std::string class_name() const override { return "CsvImport"; } const Json* outputs_json() const override { static const Json j = Json::parse( - "{\"outputs\":{\"[id]\":{\"valid\":true,\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"input-file\",\"from\":\"location\",\"extract\":\"rowCount\"},\"labels\":null},{\"size\":{\"source\":\"input-file\",\"from\":\"location\",\"extract\":\"columnCount\"},\"labels\":{\"source\":\"input-file\",\"from\":\"location\",\"extract\":\"columnHeaders\"}}]},\"[id].model\":{\"valid\":false},\"[id].strings\":{\"valid\":false}}}"); + "{\"outputs\":{\"[id]\":{\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"input-file\",\"from\":\"location\",\"extract\":\"rowCount\"},\"labels\":null},{\"size\":{\"source\":\"input-file\",\"from\":\"location\",\"extract\":\"columnCount\"},\"labels\":{\"source\":\"input-file\",\"from\":\"location\",\"extract\":\"columnHeaders\"}}]}}}"); return &j; } std::optional get_type_value() const override { return std::string("csvImport"); } @@ -1203,7 +1203,7 @@ class DataImport : public SedBase { std::string class_name() const override { return "DataImport"; } const Json* outputs_json() const override { static const Json j = Json::parse( - "{\"outputs\":{\"[id]\":{\"valid\":true,\"type\":\"annotatedData\",\"dimensions\":{\"source\":\"input-file\",\"from\":\"location\",\"extract\":\"shape\"}},\"[id].model\":{\"valid\":false}}}"); + "{\"outputs\":{\"[id]\":{\"type\":\"annotatedData\",\"dimensions\":{\"source\":\"input-file\",\"from\":\"location\",\"extract\":\"shape\"}}}}"); return &j; } std::optional get_type_value() const override { return std::string("dataImport"); } @@ -1306,7 +1306,7 @@ class DrawFromDistribution : public SedBase { std::string class_name() const override { return "DrawFromDistribution"; } const Json* outputs_json() const override { static const Json j = Json::parse( - "{\"outputs\":{\"[id]\":{\"valid\":true,\"type\":\"annotatedData\",\"dimensions\":[]},\"[id].model\":{\"valid\":false},\"[id].strings\":{\"valid\":false}}}"); + "{\"outputs\":{\"[id]\":{\"type\":\"annotatedData\",\"dimensions\":[]}}}"); return &j; } std::optional get_type_value() const override { return std::string("drawFromDistribution"); } @@ -1439,7 +1439,7 @@ class ExplicitODESimulation : public SedBase { std::string class_name() const override { return "ExplicitODESimulation"; } const Json* outputs_json() const override { static const Json j = Json::parse( - "{\"outputs\":{\"[id]\":{\"valid\":true,\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"static\",\"expr\":\"len(independentVariableRange)\"},\"labels\":null},{\"size\":{\"source\":\"static\",\"expr\":\"1 + len(outputVariables)\"},\"labels\":{\"source\":\"static\",\"expr\":\"[independentVariable] + outputVariables\"}}]},\"[id].model\":{\"valid\":true,\"type\":\"model\"},\"[id].strings\":{\"valid\":false}}}"); + "{\"outputs\":{\"[id]\":{\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"static\",\"expr\":\"len(independentVariableRange)\"},\"labels\":null},{\"size\":{\"source\":\"static\",\"expr\":\"1 + len(outputVariables)\"},\"labels\":{\"source\":\"static\",\"expr\":\"[independentVariable] + outputVariables\"}}]},\"[id].model\":{\"type\":\"model\"}}}"); return &j; } std::optional get_type_value() const override { return std::string("explicitODESimulation"); } @@ -1754,7 +1754,7 @@ class ExplicitStochasticSimulation : public SedBase { std::string class_name() const override { return "ExplicitStochasticSimulation"; } const Json* outputs_json() const override { static const Json j = Json::parse( - "{\"outputs\":{\"[id]\":{\"valid\":true,\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"static\",\"expr\":\"independentVariableRange.numberOfSteps\"},\"labels\":null},{\"size\":{\"source\":\"static\",\"expr\":\"1 + len(outputVariables)\"},\"labels\":{\"source\":\"static\",\"expr\":\"[independentVariable] + outputVariables\"}}]},\"[id].model\":{\"valid\":true,\"type\":\"model\"},\"[id].strings\":{\"valid\":false}}}"); + "{\"outputs\":{\"[id]\":{\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"static\",\"expr\":\"independentVariableRange.numberOfSteps\"},\"labels\":null},{\"size\":{\"source\":\"static\",\"expr\":\"1 + len(outputVariables)\"},\"labels\":{\"source\":\"static\",\"expr\":\"[independentVariable] + outputVariables\"}}]},\"[id].model\":{\"type\":\"model\"}}}"); return &j; } std::optional get_type_value() const override { return std::string("explicitStochasticSimulation"); } @@ -1948,8 +1948,8 @@ class FluxBalanceAnalysis : public SedBase { static const std::vector specs = { FieldSpec{"model", "SIdRef", true, std::string("FluxBalanceAnalysis-0002"), std::string("FluxBalanceAnalysis-0001"), "FluxBalanceAnalysis-0000", std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt, false, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::string("model")}, FieldSpec{"outputVariables", "ArrayOrRef", true, std::string("FluxBalanceAnalysis-0004"), std::string("FluxBalanceAnalysis-0003"), "FluxBalanceAnalysis-0000", std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt, false, std::nullopt, std::nullopt, std::string("FluxBalanceAnalysis-0005"), std::string("string"), std::nullopt}, - FieldSpec{"outputModel", "BooleanOrRef", false, std::string("FluxBalanceAnalysis-0006"), std::nullopt, "FluxBalanceAnalysis-0000", std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt, false, std::nullopt, std::nullopt, std::string("FluxBalanceAnalysis-0007"), std::nullopt, std::nullopt}, FieldSpec{"notes", "any", false, std::string("SEDBase-0003"), std::nullopt, "SEDBase-0000", std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt, false, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt}, + FieldSpec{"workingAlgorithms", "array", false, std::string("FluxBalanceAnalysis-0009"), std::nullopt, "FluxBalanceAnalysis-0000", std::nullopt, std::nullopt, std::nullopt, std::string("WorkingAlgorithm"), std::nullopt, false, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt}, FieldSpec{"taskParameters", "array", false, std::string("AbstractTask-0001"), std::nullopt, "AbstractTask-0000", std::nullopt, std::nullopt, std::nullopt, std::string("TaskParameter"), std::nullopt, false, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt}, FieldSpec{"annotations", "array", false, std::string("SEDBase-0004"), std::nullopt, "SEDBase-0000", std::nullopt, std::nullopt, std::nullopt, std::string("Annotation"), std::nullopt, false, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt} }; @@ -1968,7 +1968,7 @@ class FluxBalanceAnalysis : public SedBase { std::string class_name() const override { return "FluxBalanceAnalysis"; } const Json* outputs_json() const override { static const Json j = Json::parse( - "{\"outputs\":{\"[id]\":{\"valid\":true,\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"static\",\"expr\":\"len(outputVariables)\"},\"labels\":{\"source\":\"static\",\"expr\":\"outputVariables\"}}]},\"[id].model\":{\"valid\":\"outputModel == true\",\"type\":\"model\"},\"[id].strings\":{\"valid\":false}}}"); + "{\"outputs\":{\"[id]\":{\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"static\",\"expr\":\"len(outputVariables)\"},\"labels\":{\"source\":\"static\",\"expr\":\"outputVariables\"}}]},\"[id].model\":{\"type\":\"model\"}}}"); return &j; } std::optional get_type_value() const override { return std::string("fluxBalanceAnalysis"); } @@ -1987,19 +1987,16 @@ class FluxBalanceAnalysis : public SedBase { bool is_set_outputVariables() const { return values_.count("outputVariables") > 0; } void unset_outputVariables() { values_.erase("outputVariables"); or_ref_is_ref_.erase("outputVariables"); } - bool get_outputModel_value() const { return get_or_ref_value_node("outputModel").as(); } - std::string get_outputModel_ref() const { return get_or_ref_ref_node("outputModel").as(); } - void set_outputModel_value(bool value) { set_or_ref_value_node("outputModel", Json(value)); } - void set_outputModel_ref(const std::string& ref) { set_or_ref_ref_node("outputModel", ref); } - bool is_outputModel_ref() const { return is_or_ref_ref("outputModel"); } - bool is_set_outputModel() const { return values_.count("outputModel") > 0; } - void unset_outputModel() { values_.erase("outputModel"); or_ref_is_ref_.erase("outputModel"); } - Json get_notes() const { auto it = values_.find("notes"); if (it == values_.end()) throw ApiError(std::string("notes") + " is not set"); return it->second; } void set_notes(const Json& value) { values_["notes"] = value; } bool is_set_notes() const { return values_.count("notes") > 0; } void unset_notes() { values_.erase("notes"); } + std::vector get_workingAlgorithms() const { return workingAlgorithms_.items(); } + void add_workingAlgorithms(std::unique_ptr obj) { SedBase* raw = obj.get(); workingAlgorithms_.add(std::move(obj)); raw->attach(this, get_document()); } + void insert_workingAlgorithms(size_t index, std::unique_ptr obj) { SedBase* raw = obj.get(); workingAlgorithms_.insert(index, std::move(obj)); raw->attach(this, get_document()); } + void remove_workingAlgorithms(size_t index) { workingAlgorithms_.remove(index); } + std::vector get_taskParameters() const { return taskParameters_.items(); } void add_taskParameters(std::unique_ptr obj) { SedBase* raw = obj.get(); taskParameters_.add(std::move(obj)); raw->attach(this, get_document()); } void insert_taskParameters(size_t index, std::unique_ptr obj) { SedBase* raw = obj.get(); taskParameters_.insert(index, std::move(obj)); raw->attach(this, get_document()); } @@ -2012,6 +2009,7 @@ class FluxBalanceAnalysis : public SedBase { std::vector children() override { std::vector kids; + for (auto* item : workingAlgorithms_.items()) kids.push_back(item); for (auto* item : taskParameters_.items()) kids.push_back(item); for (auto* item : annotations_.items()) kids.push_back(item); return kids; @@ -2019,12 +2017,14 @@ class FluxBalanceAnalysis : public SedBase { std::vector children_with_locations() override { std::vector out; + { size_t idx = 0; for (auto* item : workingAlgorithms_.items()) { out.push_back(ChildLoc{item, "/workingAlgorithms/" + std::to_string(idx)}); idx++; } } { size_t idx = 0; for (auto* item : taskParameters_.items()) { out.push_back(ChildLoc{item, "/taskParameters/" + std::to_string(idx)}); idx++; } } { size_t idx = 0; for (auto* item : annotations_.items()) { out.push_back(ChildLoc{item, "/annotations/" + std::to_string(idx)}); idx++; } } return out; } ListCollection& get_list_collection(const std::string& field_name) override { + if (field_name == "workingAlgorithms") return workingAlgorithms_; if (field_name == "taskParameters") return taskParameters_; if (field_name == "annotations") return annotations_; return SedBase::get_list_collection(field_name); @@ -2037,8 +2037,8 @@ class FluxBalanceAnalysis : public SedBase { d["_type"] = values_.count("_type") ? values_.at("_type") : Json("fluxBalanceAnalysis"); if (values_.count("model")) d["model"] = values_.at("model"); if (values_.count("outputVariables")) d["outputVariables"] = values_.at("outputVariables"); - if (values_.count("outputModel")) d["outputModel"] = values_.at("outputModel"); if (values_.count("notes")) d["notes"] = values_.at("notes"); + if (workingAlgorithms_.size() > 0) { Json arr = Json::array(); for (auto* item : workingAlgorithms_.items()) arr.push_back(item->to_json_value()); d["workingAlgorithms"] = arr; } if (taskParameters_.size() > 0) { Json arr = Json::array(); for (auto* item : taskParameters_.items()) arr.push_back(item->to_json_value()); d["taskParameters"] = arr; } if (annotations_.size() > 0) { Json arr = Json::array(); for (auto* item : annotations_.items()) arr.push_back(item->to_json_value()); d["annotations"] = arr; } for (const auto& kv : ns_attrs_) d[kv.first] = kv.second; @@ -2046,6 +2046,7 @@ class FluxBalanceAnalysis : public SedBase { } private: + ListCollection workingAlgorithms_; ListCollection taskParameters_; ListCollection annotations_; }; @@ -2075,7 +2076,7 @@ class JacobianFull : public SedBase { std::string class_name() const override { return "JacobianFull"; } const Json* outputs_json() const override { static const Json j = Json::parse( - "{\"outputs\":{\"[id]\":{\"valid\":true,\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"input-file\",\"from\":\"model\",\"extract\":\"floatingSpeciesIds\"},\"labels\":{\"source\":\"input-file\",\"from\":\"model\",\"extract\":\"floatingSpeciesIds\"}},{\"size\":{\"source\":\"input-file\",\"from\":\"model\",\"extract\":\"floatingSpeciesIds\"},\"labels\":{\"source\":\"input-file\",\"from\":\"model\",\"extract\":\"floatingSpeciesIds\"}}]},\"[id].model\":{\"valid\":false},\"[id].strings\":{\"valid\":false}}}"); + "{\"outputs\":{\"[id]\":{\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"input-file\",\"from\":\"model\",\"extract\":\"floatingSpeciesIds\"},\"labels\":{\"source\":\"input-file\",\"from\":\"model\",\"extract\":\"floatingSpeciesIds\"}},{\"size\":{\"source\":\"input-file\",\"from\":\"model\",\"extract\":\"floatingSpeciesIds\"},\"labels\":{\"source\":\"input-file\",\"from\":\"model\",\"extract\":\"floatingSpeciesIds\"}}]}}}"); return &j; } std::optional get_type_value() const override { return std::string("jacobianFull"); } @@ -2164,7 +2165,7 @@ class JacobianReduced : public SedBase { std::string class_name() const override { return "JacobianReduced"; } const Json* outputs_json() const override { static const Json j = Json::parse( - "{\"outputs\":{\"[id]\":{\"valid\":true,\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"input-file\",\"from\":\"model\",\"extract\":\"reducedFloatingSpeciesIds\"},\"labels\":{\"source\":\"input-file\",\"from\":\"model\",\"extract\":\"reducedFloatingSpeciesIds\"}},{\"size\":{\"source\":\"input-file\",\"from\":\"model\",\"extract\":\"reducedFloatingSpeciesIds\"},\"labels\":{\"source\":\"input-file\",\"from\":\"model\",\"extract\":\"reducedFloatingSpeciesIds\"}}]},\"[id].model\":{\"valid\":false},\"[id].strings\":{\"valid\":false}}}"); + "{\"outputs\":{\"[id]\":{\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"input-file\",\"from\":\"model\",\"extract\":\"reducedFloatingSpeciesIds\"},\"labels\":{\"source\":\"input-file\",\"from\":\"model\",\"extract\":\"reducedFloatingSpeciesIds\"}},{\"size\":{\"source\":\"input-file\",\"from\":\"model\",\"extract\":\"reducedFloatingSpeciesIds\"},\"labels\":{\"source\":\"input-file\",\"from\":\"model\",\"extract\":\"reducedFloatingSpeciesIds\"}}]}}}"); return &j; } std::optional get_type_value() const override { return std::string("jacobianReduced"); } @@ -2240,12 +2241,12 @@ class Loop : public SedBase { FieldSpec{"aggregateOutputVariables", "dict", false, std::string("Repeat-0004"), std::nullopt, "Repeat-0000", std::nullopt, std::nullopt, std::nullopt, std::string("AggregationCalculation"), std::nullopt, false, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt}, FieldSpec{"taskParameters", "array", false, std::string("AbstractTask-0001"), std::nullopt, "AbstractTask-0000", std::nullopt, std::nullopt, std::nullopt, std::string("TaskParameter"), std::nullopt, false, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt}, FieldSpec{"annotations", "array", false, std::string("SEDBase-0004"), std::nullopt, "SEDBase-0000", std::nullopt, std::nullopt, std::nullopt, std::string("Annotation"), std::nullopt, false, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt}, - FieldSpec{"range", "ref-discriminator", false, std::string("Repeat-0005"), std::nullopt, "Repeat-0000", std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::string("RangeInline"), false, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt} + FieldSpec{"range", "ref-discriminator", true, std::string("Loop-0007"), std::string("Loop-0006"), "Loop-0000", std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::string("RangeInline"), false, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt} }; return specs; } const std::set& required_names() const override { - static const std::set names = {"loopVariables"}; + static const std::set names = {"loopVariables", "range"}; return names; } std::optional type_const() const override { return std::string("loop"); } @@ -2264,7 +2265,7 @@ class Loop : public SedBase { std::vector id_collection_names() const override { return {"loopVariables", "subTasks", "aggregateOutputVariables"}; } const Json* outputs_json() const override { static const Json j = Json::parse( - "{\"outputs\":{\"[id]\":{\"valid\":true,\"type\":\"annotatedData\",\"dimensions\":{\"source\":\"runtime\"}},\"[id].model\":{\"valid\":false},\"[id].strings\":{\"valid\":false},\"[id].aggregates\":{\"valid\":\"provided(aggregateOutputVariables)\",\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"static\",\"expr\":\"len(aggregateOutputVariables)\"},\"labels\":null}]},\"[id].range\":{\"valid\":\"provided(range)\",\"type\":\"annotatedData\",\"dimensions\":[]},\"[id].index\":{\"valid\":\"provided(range)\",\"type\":\"annotatedData\",\"dimensions\":[]}}}"); + "{\"outputs\":{\"[id]\":{\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"static\",\"expr\":\"len(range)\"},\"labels\":null},{\"size\":{\"source\":\"static\",\"expr\":\"len(outputVariableMap)\"},\"labels\":null}]},\"[id].aggregates\":{\"valid\":\"provided(aggregateOutputVariables)\",\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"static\",\"expr\":\"len(aggregateOutputVariables)\"},\"labels\":null}]},\"[id].range\":{\"type\":\"annotatedData\",\"dimensions\":[]},\"[id].index\":{\"type\":\"annotatedData\",\"dimensions\":[]}}}"); return &j; } std::optional get_type_value() const override { return std::string("loop"); } @@ -2414,7 +2415,7 @@ class ModelChange : public SedBase { std::string class_name() const override { return "ModelChange"; } const Json* outputs_json() const override { static const Json j = Json::parse( - "{\"outputs\":{\"[id]\":{\"valid\":false},\"[id].model\":{\"valid\":true,\"type\":\"model\"},\"[id].strings\":{\"valid\":false}}}"); + "{\"outputs\":{\"[id].model\":{\"type\":\"model\"}}}"); return &j; } std::optional get_type_value() const override { return std::string("modelChange"); } @@ -2543,7 +2544,7 @@ class ModelElementList : public SedBase { std::string class_name() const override { return "ModelElementList"; } const Json* outputs_json() const override { static const Json j = Json::parse( - "{\"outputs\":{\"[id]\":{\"valid\":false},\"[id].model\":{\"valid\":false},\"[id].strings\":{\"valid\":true,\"type\":\"stringList\",\"dimensions\":[{\"size\":{\"source\":\"input-file\",\"from\":\"model\",\"extract\":\"matchedElementIds\"},\"labels\":{\"source\":\"input-file\",\"from\":\"model\",\"extract\":\"matchedElementIds\"}}]}}}"); + "{\"outputs\":{\"[id].strings\":{\"type\":\"stringList\",\"dimensions\":[{\"size\":{\"source\":\"input-file\",\"from\":\"model\",\"extract\":\"matchedElementIds\"},\"labels\":{\"source\":\"input-file\",\"from\":\"model\",\"extract\":\"matchedElementIds\"}}]}}}"); return &j; } std::optional get_type_value() const override { return std::string("modelElementList"); } @@ -2669,7 +2670,7 @@ class ModelImport : public SedBase { std::string class_name() const override { return "ModelImport"; } const Json* outputs_json() const override { static const Json j = Json::parse( - "{\"outputs\":{\"[id]\":{\"valid\":false},\"[id].model\":{\"valid\":true,\"type\":\"model\"},\"[id].strings\":{\"valid\":false}}}"); + "{\"outputs\":{\"[id].model\":{\"type\":\"model\"}}}"); return &j; } std::optional get_type_value() const override { return std::string("modelImport"); } @@ -2772,7 +2773,7 @@ class NumericRange : public SedBase { std::string class_name() const override { return "NumericRange"; } const Json* outputs_json() const override { static const Json j = Json::parse( - "{\"outputs\":{\"[id]\":{\"valid\":true,\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"static\",\"expr\":\"len(values) if provided(values) else numberOfSteps + 1\"},\"labels\":null}]},\"[id].model\":{\"valid\":false},\"[id].strings\":{\"valid\":false}}}"); + "{\"outputs\":{\"[id]\":{\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"static\",\"expr\":\"len(values) if provided(values) else numberOfSteps + 1\"},\"labels\":null}]}}}"); return &j; } std::optional get_type_value() const override { return std::string("numericRange"); } @@ -2932,7 +2933,7 @@ class OneStepODESimulation : public SedBase { std::string class_name() const override { return "OneStepODESimulation"; } const Json* outputs_json() const override { static const Json j = Json::parse( - "{\"outputs\":{\"[id]\":{\"valid\":true,\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"static\",\"expr\":\"len(outputVariables)\"},\"labels\":{\"source\":\"static\",\"expr\":\"outputVariables\"}}]},\"[id].model\":{\"valid\":true,\"type\":\"model\"},\"[id].strings\":{\"valid\":false}}}"); + "{\"outputs\":{\"[id]\":{\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"static\",\"expr\":\"len(outputVariables)\"},\"labels\":{\"source\":\"static\",\"expr\":\"outputVariables\"}}]},\"[id].model\":{\"type\":\"model\"}}}"); return &j; } std::optional get_type_value() const override { return std::string("oneStepODE"); } @@ -3238,7 +3239,7 @@ class OneStepStochasticSimulation : public SedBase { std::string class_name() const override { return "OneStepStochasticSimulation"; } const Json* outputs_json() const override { static const Json j = Json::parse( - "{\"outputs\":{\"[id]\":{\"valid\":true,\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"static\",\"expr\":\"len(outputVariables)\"},\"labels\":{\"source\":\"static\",\"expr\":\"outputVariables\"}}]},\"[id].model\":{\"valid\":true,\"type\":\"model\"},\"[id].strings\":{\"valid\":false},\"[id].independentStep\":{\"valid\":\"!provided(independentStep)\",\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"static\",\"expr\":\"1\"},\"labels\":null}]}}}"); + "{\"outputs\":{\"[id]\":{\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"static\",\"expr\":\"len(outputVariables)\"},\"labels\":{\"source\":\"static\",\"expr\":\"outputVariables\"}}]},\"[id].model\":{\"type\":\"model\"},\"[id].independentStep\":{\"valid\":\"!provided(independentStep)\",\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"static\",\"expr\":\"1\"},\"labels\":null}]}}}"); return &j; } std::optional get_type_value() const override { return std::string("oneStepStochastic"); } @@ -3452,7 +3453,7 @@ class ParameterRange : public SedBase { std::string class_name() const override { return "ParameterRange"; } const Json* outputs_json() const override { static const Json j = Json::parse( - "{\"outputs\":{\"[id]\":{\"valid\":true,\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"static\",\"expr\":\"len(values) if provided(values) else numberOfSteps + 1\"},\"labels\":null}]},\"[id].model\":{\"valid\":false},\"[id].strings\":{\"valid\":false}}}"); + "{\"outputs\":{\"[id]\":{\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"static\",\"expr\":\"len(values) if provided(values) else numberOfSteps + 1\"},\"labels\":null}]}}}"); return &j; } std::optional get_type_value() const override { return std::string("parameterRange"); } @@ -3585,8 +3586,7 @@ class ParameterScan : public SedBase { FieldSpec{"subTasks", "dict", false, std::string("Repeat-0001"), std::nullopt, "Repeat-0000", std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::string("AbstractTask"), false, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt}, FieldSpec{"aggregateOutputVariables", "dict", false, std::string("Repeat-0004"), std::nullopt, "Repeat-0000", std::nullopt, std::nullopt, std::nullopt, std::string("AggregationCalculation"), std::nullopt, false, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt}, FieldSpec{"taskParameters", "array", false, std::string("AbstractTask-0001"), std::nullopt, "AbstractTask-0000", std::nullopt, std::nullopt, std::nullopt, std::string("TaskParameter"), std::nullopt, false, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt}, - FieldSpec{"annotations", "array", false, std::string("SEDBase-0004"), std::nullopt, "SEDBase-0000", std::nullopt, std::nullopt, std::nullopt, std::string("Annotation"), std::nullopt, false, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt}, - FieldSpec{"range", "ref-discriminator", false, std::string("Repeat-0005"), std::nullopt, "Repeat-0000", std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::string("RangeInline"), false, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt} + FieldSpec{"annotations", "array", false, std::string("SEDBase-0004"), std::nullopt, "SEDBase-0000", std::nullopt, std::nullopt, std::nullopt, std::string("Annotation"), std::nullopt, false, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt} }; return specs; } @@ -3609,7 +3609,7 @@ class ParameterScan : public SedBase { std::vector id_collection_names() const override { return {"subTasks", "aggregateOutputVariables"}; } const Json* outputs_json() const override { static const Json j = Json::parse( - "{\"outputs\":{\"[id]\":{\"valid\":true,\"type\":\"annotatedData\",\"dimensions\":[{\"repeat\":{\"over\":\"parameterRanges\",\"size\":{\"source\":\"static\",\"expr\":\"len(self)\"},\"labels\":null}},{\"size\":{\"source\":\"static\",\"expr\":\"len(outputVariableMap)\"},\"labels\":null}]},\"[id].model\":{\"valid\":false},\"[id].strings\":{\"valid\":false},\"[id].aggregates\":{\"valid\":\"provided(aggregateOutputVariables)\",\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"static\",\"expr\":\"len(aggregateOutputVariables)\"},\"labels\":null}]}}}"); + "{\"outputs\":{\"[id]\":{\"type\":\"annotatedData\",\"dimensions\":[{\"repeat\":{\"over\":\"parameterRanges\",\"size\":{\"source\":\"static\",\"expr\":\"len(self)\"},\"labels\":{\"source\":\"static\",\"expr\":\"modelElement\"}}},{\"size\":{\"source\":\"static\",\"expr\":\"len(outputVariableMap)\"},\"labels\":null}]},\"[id].aggregates\":{\"valid\":\"provided(aggregateOutputVariables)\",\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"static\",\"expr\":\"len(aggregateOutputVariables)\"},\"labels\":null}]},\"[id].ranges\":{\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"static\",\"expr\":\"len(parameterRanges)\"},\"labels\":{\"source\":\"static\",\"expr\":\"parameterRanges.modelElement\"}}]},\"[id].indexes\":{\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"static\",\"expr\":\"len(parameterRanges)\"},\"labels\":{\"source\":\"static\",\"expr\":\"parameterRanges.modelElement\"}}]}}}"); return &j; } std::optional get_type_value() const override { return std::string("parameterScan"); } @@ -3662,11 +3662,6 @@ class ParameterScan : public SedBase { void insert_annotations(size_t index, std::unique_ptr obj) { SedBase* raw = obj.get(); annotations_.insert(index, std::move(obj)); raw->attach(this, get_document()); } void remove_annotations(size_t index) { annotations_.remove(index); } - SedBase* get_range() const { if (!range_) throw ApiError(std::string("range") + " is not set"); return range_.get(); } - void set_range(std::unique_ptr obj) { SedBase* raw = obj.get(); range_ = std::move(obj); raw->attach(this, get_document()); } - bool is_set_range() const { return range_ != nullptr; } - void unset_range() { range_.reset(); } - std::vector children() override { std::vector kids; for (const auto& i : subTasks_.ids()) kids.push_back(subTasks_.get(i)); @@ -3674,7 +3669,6 @@ class ParameterScan : public SedBase { for (auto* item : parameterRanges_.items()) kids.push_back(item); for (auto* item : taskParameters_.items()) kids.push_back(item); for (auto* item : annotations_.items()) kids.push_back(item); - if (range_) kids.push_back(range_.get()); return kids; } @@ -3685,7 +3679,6 @@ class ParameterScan : public SedBase { { size_t idx = 0; for (auto* item : parameterRanges_.items()) { out.push_back(ChildLoc{item, "/parameterRanges/" + std::to_string(idx)}); idx++; } } { size_t idx = 0; for (auto* item : taskParameters_.items()) { out.push_back(ChildLoc{item, "/taskParameters/" + std::to_string(idx)}); idx++; } } { size_t idx = 0; for (auto* item : annotations_.items()) { out.push_back(ChildLoc{item, "/annotations/" + std::to_string(idx)}); idx++; } } - if (range_) out.push_back(ChildLoc{range_.get(), "/range"}); return out; } @@ -3702,11 +3695,6 @@ class ParameterScan : public SedBase { return SedBase::get_list_collection(field_name); } - void set_child_field(const std::string& field_name, std::unique_ptr child) override { - if (field_name == "range") { range_ = std::move(child); return; } - SedBase::set_child_field(field_name, std::move(child)); - } - Json own_json_value() const override { Json d = Json::object(); if (name_node_) d["name"] = *name_node_; @@ -3720,7 +3708,6 @@ class ParameterScan : public SedBase { if (parameterRanges_.size() > 0) { Json arr = Json::array(); for (auto* item : parameterRanges_.items()) arr.push_back(item->to_json_value()); d["parameterRanges"] = arr; } if (taskParameters_.size() > 0) { Json arr = Json::array(); for (auto* item : taskParameters_.items()) arr.push_back(item->to_json_value()); d["taskParameters"] = arr; } if (annotations_.size() > 0) { Json arr = Json::array(); for (auto* item : annotations_.items()) arr.push_back(item->to_json_value()); d["annotations"] = arr; } - if (range_) d["range"] = range_->to_json_value(); for (const auto& kv : ns_attrs_) d[kv.first] = kv.second; return d; } @@ -3731,7 +3718,6 @@ class ParameterScan : public SedBase { IdKeyedCollection aggregateOutputVariables_; ListCollection taskParameters_; ListCollection annotations_; - std::unique_ptr range_; }; /// Generated from test-specsheets/tasks/Range/. @@ -3755,7 +3741,7 @@ class Range : public SedBase { std::string class_name() const override { return "Range"; } const Json* outputs_json() const override { static const Json j = Json::parse( - "{\"outputs\":{\"[id]\":{\"valid\":true,\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"static\",\"expr\":\"len(values)\"},\"labels\":null}]},\"[id].model\":{\"valid\":false},\"[id].strings\":{\"valid\":false}}}"); + "{\"outputs\":{\"[id]\":{\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"static\",\"expr\":\"len(values)\"},\"labels\":null}]}}}"); return &j; } std::optional get_type_value() const override { return std::string("range"); } @@ -3848,7 +3834,7 @@ class RelabelData : public SedBase { std::string class_name() const override { return "RelabelData"; } const Json* outputs_json() const override { static const Json j = Json::parse( - "{\"outputs\":{\"[id]\":{\"valid\":true,\"type\":\"annotatedData\",\"dimensions\":{\"source\":\"static\",\"expr\":\"shapeOf(input)\"}},\"[id].model\":{\"valid\":false}}}"); + "{\"outputs\":{\"[id]\":{\"type\":\"annotatedData\",\"dimensions\":{\"source\":\"static\",\"expr\":\"shapeOf(input)\"}}}}"); return &j; } std::optional get_type_value() const override { return std::string("relabelData"); } @@ -3932,10 +3918,14 @@ class Scatter : public SedBase { FieldSpec{"aggregateOutputVariables", "dict", false, std::string("Repeat-0004"), std::nullopt, "Repeat-0000", std::nullopt, std::nullopt, std::nullopt, std::string("AggregationCalculation"), std::nullopt, false, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt}, FieldSpec{"taskParameters", "array", false, std::string("AbstractTask-0001"), std::nullopt, "AbstractTask-0000", std::nullopt, std::nullopt, std::nullopt, std::string("TaskParameter"), std::nullopt, false, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt}, FieldSpec{"annotations", "array", false, std::string("SEDBase-0004"), std::nullopt, "SEDBase-0000", std::nullopt, std::nullopt, std::nullopt, std::string("Annotation"), std::nullopt, false, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt}, - FieldSpec{"range", "ref-discriminator", false, std::string("Repeat-0005"), std::nullopt, "Repeat-0000", std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::string("RangeInline"), false, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt} + FieldSpec{"range", "ref-discriminator", true, std::string("Scatter-0005"), std::string("Scatter-0004"), "Scatter-0000", std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::string("RangeInline"), false, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt} }; return specs; } + const std::set& required_names() const override { + static const std::set names = {"range"}; + return names; + } std::optional type_const() const override { return std::string("scatter"); } std::optional type_rule_id() const override { return std::string("Scatter-0003"); } std::string own_catchall() const override { return "Scatter-0000"; } @@ -3951,7 +3941,7 @@ class Scatter : public SedBase { std::vector id_collection_names() const override { return {"subTasks", "aggregateOutputVariables"}; } const Json* outputs_json() const override { static const Json j = Json::parse( - "{\"outputs\":{\"[id]\":{\"valid\":true,\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"static\",\"expr\":\"len(range)\"},\"labels\":null},{\"size\":{\"source\":\"static\",\"expr\":\"len(outputVariableMap)\"},\"labels\":null}]},\"[id].model\":{\"valid\":false},\"[id].strings\":{\"valid\":false},\"[id].aggregates\":{\"valid\":\"provided(aggregateOutputVariables)\",\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"static\",\"expr\":\"len(aggregateOutputVariables)\"},\"labels\":null}]},\"[id].range\":{\"valid\":\"provided(range)\",\"type\":\"annotatedData\",\"dimensions\":[]},\"[id].index\":{\"valid\":\"provided(range)\",\"type\":\"annotatedData\",\"dimensions\":[]}}}"); + "{\"outputs\":{\"[id]\":{\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"static\",\"expr\":\"len(range)\"},\"labels\":null},{\"size\":{\"source\":\"static\",\"expr\":\"len(outputVariableMap)\"},\"labels\":null}]},\"[id].aggregates\":{\"valid\":\"provided(aggregateOutputVariables)\",\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"static\",\"expr\":\"len(aggregateOutputVariables)\"},\"labels\":null}]},\"[id].range\":{\"type\":\"annotatedData\",\"dimensions\":[]},\"[id].index\":{\"type\":\"annotatedData\",\"dimensions\":[]}}}"); return &j; } std::optional get_type_value() const override { return std::string("scatter"); } @@ -4085,7 +4075,7 @@ class Span : public SedBase { std::string class_name() const override { return "Span"; } const Json* outputs_json() const override { static const Json j = Json::parse( - "{\"outputs\":{\"[id]\":{\"valid\":false},\"[id].model\":{\"valid\":false},\"[id].strings\":{\"valid\":false}}}"); + "{\"outputs\":{}}"); return &j; } std::optional get_type_value() const override { return std::string("span"); } @@ -4159,8 +4149,8 @@ class SteadyState : public SedBase { FieldSpec{"model", "SIdRef", true, std::nullopt, std::string("SteadyState-0001"), "SteadyState-0000", std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt, false, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::string("model")}, FieldSpec{"independentVariable", "StringOrRef", false, std::string("SteadyState-0004"), std::nullopt, "SteadyState-0000", std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt, false, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt}, FieldSpec{"outputVariables", "ArrayOrRef", true, std::nullopt, std::string("SteadyState-0002"), "SteadyState-0000", std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt, false, std::nullopt, std::nullopt, std::nullopt, std::string("string"), std::nullopt}, - FieldSpec{"outputModel", "BooleanOrRef", false, std::string("SteadyState-0005"), std::nullopt, "SteadyState-0000", std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt, false, std::nullopt, std::nullopt, std::string("SteadyState-0006"), std::nullopt, std::nullopt}, FieldSpec{"notes", "any", false, std::string("SEDBase-0003"), std::nullopt, "SEDBase-0000", std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt, false, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt}, + FieldSpec{"workingAlgorithms", "array", false, std::string("SteadyState-0007"), std::nullopt, "SteadyState-0000", std::nullopt, std::nullopt, std::nullopt, std::string("WorkingAlgorithm"), std::nullopt, false, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt}, FieldSpec{"taskParameters", "array", false, std::string("AbstractTask-0001"), std::nullopt, "AbstractTask-0000", std::nullopt, std::nullopt, std::nullopt, std::string("TaskParameter"), std::nullopt, false, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt}, FieldSpec{"annotations", "array", false, std::string("SEDBase-0004"), std::nullopt, "SEDBase-0000", std::nullopt, std::nullopt, std::nullopt, std::string("Annotation"), std::nullopt, false, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt} }; @@ -4179,7 +4169,7 @@ class SteadyState : public SedBase { std::string class_name() const override { return "SteadyState"; } const Json* outputs_json() const override { static const Json j = Json::parse( - "{\"outputs\":{\"[id]\":{\"valid\":true,\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"static\",\"expr\":\"len(outputVariables)\"},\"labels\":{\"source\":\"static\",\"expr\":\"outputVariables\"}}]},\"[id].model\":{\"valid\":\"outputModel == true\",\"type\":\"model\"},\"[id].strings\":{\"valid\":false}}}"); + "{\"outputs\":{\"[id]\":{\"type\":\"annotatedData\",\"dimensions\":[{\"size\":{\"source\":\"static\",\"expr\":\"len(outputVariables)\"},\"labels\":{\"source\":\"static\",\"expr\":\"outputVariables\"}}]},\"[id].model\":{\"type\":\"model\"}}}"); return &j; } std::optional get_type_value() const override { return std::string("steadyState"); } @@ -4206,19 +4196,16 @@ class SteadyState : public SedBase { bool is_set_outputVariables() const { return values_.count("outputVariables") > 0; } void unset_outputVariables() { values_.erase("outputVariables"); or_ref_is_ref_.erase("outputVariables"); } - bool get_outputModel_value() const { return get_or_ref_value_node("outputModel").as(); } - std::string get_outputModel_ref() const { return get_or_ref_ref_node("outputModel").as(); } - void set_outputModel_value(bool value) { set_or_ref_value_node("outputModel", Json(value)); } - void set_outputModel_ref(const std::string& ref) { set_or_ref_ref_node("outputModel", ref); } - bool is_outputModel_ref() const { return is_or_ref_ref("outputModel"); } - bool is_set_outputModel() const { return values_.count("outputModel") > 0; } - void unset_outputModel() { values_.erase("outputModel"); or_ref_is_ref_.erase("outputModel"); } - Json get_notes() const { auto it = values_.find("notes"); if (it == values_.end()) throw ApiError(std::string("notes") + " is not set"); return it->second; } void set_notes(const Json& value) { values_["notes"] = value; } bool is_set_notes() const { return values_.count("notes") > 0; } void unset_notes() { values_.erase("notes"); } + std::vector get_workingAlgorithms() const { return workingAlgorithms_.items(); } + void add_workingAlgorithms(std::unique_ptr obj) { SedBase* raw = obj.get(); workingAlgorithms_.add(std::move(obj)); raw->attach(this, get_document()); } + void insert_workingAlgorithms(size_t index, std::unique_ptr obj) { SedBase* raw = obj.get(); workingAlgorithms_.insert(index, std::move(obj)); raw->attach(this, get_document()); } + void remove_workingAlgorithms(size_t index) { workingAlgorithms_.remove(index); } + std::vector get_taskParameters() const { return taskParameters_.items(); } void add_taskParameters(std::unique_ptr obj) { SedBase* raw = obj.get(); taskParameters_.add(std::move(obj)); raw->attach(this, get_document()); } void insert_taskParameters(size_t index, std::unique_ptr obj) { SedBase* raw = obj.get(); taskParameters_.insert(index, std::move(obj)); raw->attach(this, get_document()); } @@ -4231,6 +4218,7 @@ class SteadyState : public SedBase { std::vector children() override { std::vector kids; + for (auto* item : workingAlgorithms_.items()) kids.push_back(item); for (auto* item : taskParameters_.items()) kids.push_back(item); for (auto* item : annotations_.items()) kids.push_back(item); return kids; @@ -4238,12 +4226,14 @@ class SteadyState : public SedBase { std::vector children_with_locations() override { std::vector out; + { size_t idx = 0; for (auto* item : workingAlgorithms_.items()) { out.push_back(ChildLoc{item, "/workingAlgorithms/" + std::to_string(idx)}); idx++; } } { size_t idx = 0; for (auto* item : taskParameters_.items()) { out.push_back(ChildLoc{item, "/taskParameters/" + std::to_string(idx)}); idx++; } } { size_t idx = 0; for (auto* item : annotations_.items()) { out.push_back(ChildLoc{item, "/annotations/" + std::to_string(idx)}); idx++; } } return out; } ListCollection& get_list_collection(const std::string& field_name) override { + if (field_name == "workingAlgorithms") return workingAlgorithms_; if (field_name == "taskParameters") return taskParameters_; if (field_name == "annotations") return annotations_; return SedBase::get_list_collection(field_name); @@ -4257,8 +4247,8 @@ class SteadyState : public SedBase { if (values_.count("model")) d["model"] = values_.at("model"); if (values_.count("independentVariable")) d["independentVariable"] = values_.at("independentVariable"); if (values_.count("outputVariables")) d["outputVariables"] = values_.at("outputVariables"); - if (values_.count("outputModel")) d["outputModel"] = values_.at("outputModel"); if (values_.count("notes")) d["notes"] = values_.at("notes"); + if (workingAlgorithms_.size() > 0) { Json arr = Json::array(); for (auto* item : workingAlgorithms_.items()) arr.push_back(item->to_json_value()); d["workingAlgorithms"] = arr; } if (taskParameters_.size() > 0) { Json arr = Json::array(); for (auto* item : taskParameters_.items()) arr.push_back(item->to_json_value()); d["taskParameters"] = arr; } if (annotations_.size() > 0) { Json arr = Json::array(); for (auto* item : annotations_.items()) arr.push_back(item->to_json_value()); d["annotations"] = arr; } for (const auto& kv : ns_attrs_) d[kv.first] = kv.second; @@ -4266,6 +4256,7 @@ class SteadyState : public SedBase { } private: + ListCollection workingAlgorithms_; ListCollection taskParameters_; ListCollection annotations_; }; @@ -4295,7 +4286,7 @@ class StringFormation : public SedBase { std::string class_name() const override { return "StringFormation"; } const Json* outputs_json() const override { static const Json j = Json::parse( - "{\"outputs\":{\"[id]\":{\"valid\":true,\"type\":\"annotatedData\",\"dimensions\":{\"source\":\"runtime\"}},\"[id].model\":{\"valid\":false},\"[id].strings\":{\"valid\":true,\"type\":\"stringList\",\"dimensions\":{\"source\":\"runtime\"}}}}"); + "{\"outputs\":{\"[id]\":{\"type\":\"annotatedData\",\"dimensions\":{\"source\":\"runtime\"}},\"[id].strings\":{\"type\":\"stringList\",\"dimensions\":{\"source\":\"runtime\"}}}}"); return &j; } std::optional get_type_value() const override { return std::string("stringFormation"); } diff --git a/generated/cpp/include/libsed2/OutputsShape.hpp b/generated/cpp/include/libsed2/OutputsShape.hpp index 5756523..816fe5c 100644 --- a/generated/cpp/include/libsed2/OutputsShape.hpp +++ b/generated/cpp/include/libsed2/OutputsShape.hpp @@ -615,12 +615,15 @@ inline OptDims apply_index_chain(const OptDims& dims, const std::vector eval_valid(const Json& entry, const Scope& scope, const ShapeOf& shape_of) { const Json* valid = member(entry, "valid"); - if (valid && valid->is_bool()) return valid->as(); - if (valid && valid->is_string()) { + if (!valid) return true; + if (valid->is_string()) { try { return val_truthy(eval_expr(*parse_expr(valid->as()), scope, shape_of)); } catch (const NotStatic&) { diff --git a/generated/cpp/include/libsed2/RulesData.hpp b/generated/cpp/include/libsed2/RulesData.hpp index 1ec61d4..7bed217 100644 --- a/generated/cpp/include/libsed2/RulesData.hpp +++ b/generated/cpp/include/libsed2/RulesData.hpp @@ -204,8 +204,6 @@ inline void register_rules() { RuleCatalog::catalog()["FluxBalanceAnalysis-0003"] = RuleCatalog::Entry{"The outputVariables attribute of a FluxBalanceAnalysis is required.", "Required attribute '{attr}' is missing from {class} '{id}'.", "error"}; RuleCatalog::catalog()["FluxBalanceAnalysis-0004"] = RuleCatalog::Entry{"When the value of outputVariables of a FluxBalanceAnalysis is provided directly, it must be an array of strings.", "Attribute '{attr}' of {class} '{id}' has value '{value}', which is not an array of strings.", "error"}; RuleCatalog::catalog()["FluxBalanceAnalysis-0005"] = RuleCatalog::Entry{"When the value of outputVariables of a FluxBalanceAnalysis is a reference, it must be a reference to an array of strings.", "Attribute '{attr}' of {class} '{id}' is the reference '{value}', which resolves to '{resolved-value}', not an array of strings.", "error"}; - RuleCatalog::catalog()["FluxBalanceAnalysis-0006"] = RuleCatalog::Entry{"When the value of outputModel of a FluxBalanceAnalysis is provided directly, it must be a boolean.", "Attribute '{attr}' of {class} '{id}' has value '{value}', which is not a boolean.", "error"}; - RuleCatalog::catalog()["FluxBalanceAnalysis-0007"] = RuleCatalog::Entry{"When the value of outputModel of a FluxBalanceAnalysis is a reference, it must be a reference to a boolean.", "Attribute '{attr}' of {class} '{id}' is the reference '{value}', which resolves to '{resolved-value}', not a boolean.", "error"}; RuleCatalog::catalog()["FluxBalanceAnalysis-0008"] = RuleCatalog::Entry{"The _type attribute of a FluxBalanceAnalysis must be \"fluxBalanceAnalysis\".", "Attribute '{attr}' of {class} '{id}' has value '{value}', which does not match the required value '{allowed}'.", "error"}; RuleCatalog::catalog()["JacobianFull-0000"] = RuleCatalog::Entry{"The element fails a JSON Schema constraint attributable to JacobianFull that does not match any other numbered rule.", "{schema-message} (at {location})", "error"}; RuleCatalog::catalog()["JacobianFull-0001"] = RuleCatalog::Entry{"The model attribute of a JacobianFull is required.", "Required attribute '{attr}' is missing from {class} '{id}'.", "error"}; @@ -336,7 +334,6 @@ inline void register_rules() { RuleCatalog::catalog()["Repeat-0002"] = RuleCatalog::Entry{"When the value of outputVariableMap of a Repeat is provided directly, it must be an object whose values are SIdRef.", "Attribute '{attr}' of {class} '{id}' has value '{value}', which is not an object whose values are SIdRef.", "error"}; RuleCatalog::catalog()["Repeat-0003"] = RuleCatalog::Entry{"When the value of outputVariableMap of a Repeat is a reference, it must be a reference to an object whose values are SIdRef.", "Attribute '{attr}' of {class} '{id}' is the reference '{value}', which resolves to '{resolved-value}', not an object whose values are SIdRef.", "error"}; RuleCatalog::catalog()["Repeat-0004"] = RuleCatalog::Entry{"The aggregateOutputVariables attribute of a Repeat must be an object whose values are AggregationCalculation.", "Attribute '{attr}' of {class} '{id}' has value '{value}', which is not an object whose values are AggregationCalculation.", "error"}; - RuleCatalog::catalog()["Repeat-0005"] = RuleCatalog::Entry{"The range attribute of a Repeat, if present, must be a RangeInline object.", "Attribute '{attr}' of {class} '{id}' has value '{value}', which is not a RangeInline object.", "error"}; RuleCatalog::catalog()["Repeat-0006"] = RuleCatalog::Entry{"A Repeat must provide at least one of outputVariableMap or aggregateOutputVariables.", "{class} '{id}' must provide at least one of 'outputVariableMap' or 'aggregateOutputVariables'.", "error"}; RuleCatalog::catalog()["Repeat-0008"] = RuleCatalog::Entry{"Every value in a Repeat's outputVariableMap must reference one of that Repeat's own subTasks, or an output of one.", "Entry '{attr}' of the outputVariableMap of {class} '{id}' references '{value}', which is not one of its own subTasks.", "error"}; RuleCatalog::catalog()["Repeat-0009"] = RuleCatalog::Entry{"The input of every entry in a Repeat's aggregateOutputVariables must reference one of that Repeat's own subTasks, or an output of one.", "Entry '{attr}' of the aggregateOutputVariables of {class} '{id}' has input '{value}', which is not one of its own subTasks.", "error"}; @@ -393,8 +390,6 @@ inline void register_rules() { RuleCatalog::catalog()["SteadyState-0002"] = RuleCatalog::Entry{"The outputVariables attribute of a SteadyState is required.", "Required attribute '{attr}' is missing from {class} '{id}'.", "error"}; RuleCatalog::catalog()["SteadyState-0003"] = RuleCatalog::Entry{"The _type attribute of a SteadyState must be \"steadyState\".", "Attribute '{attr}' of {class} '{id}' has value '{value}', which does not match the required value '{allowed}'.", "error"}; RuleCatalog::catalog()["SteadyState-0004"] = RuleCatalog::Entry{"The independentVariable attribute of a SteadyState, if present, must be a string.", "Attribute '{attr}' of {class} '{id}' has value '{value}', which is not a string.", "error"}; - RuleCatalog::catalog()["SteadyState-0005"] = RuleCatalog::Entry{"When the value of outputModel of a SteadyState is provided directly, it must be a boolean.", "Attribute '{attr}' of {class} '{id}' has value '{value}', which is not a boolean.", "error"}; - RuleCatalog::catalog()["SteadyState-0006"] = RuleCatalog::Entry{"When the value of outputModel of a SteadyState is a reference, it must be a reference to a boolean.", "Attribute '{attr}' of {class} '{id}' is the reference '{value}', which resolves to '{resolved-value}', not a boolean.", "error"}; RuleCatalog::catalog()["StringFormation-0000"] = RuleCatalog::Entry{"The element fails a JSON Schema constraint attributable to StringFormation that does not match any other numbered rule.", "{schema-message} (at {location})", "error"}; RuleCatalog::catalog()["StringFormation-0001"] = RuleCatalog::Entry{"The concatenate attribute of a StringFormation is required.", "Required attribute '{attr}' is missing from {class} '{id}'.", "error"}; RuleCatalog::catalog()["StringFormation-0002"] = RuleCatalog::Entry{"When the value of concatenate of a StringFormation is provided directly, it must be an array of values.", "Attribute '{attr}' of {class} '{id}' has value '{value}', which is not an array of values.", "error"}; diff --git a/generated/java/src/main/java/org/sedml/libsed2/AggregationCalculation.java b/generated/java/src/main/java/org/sedml/libsed2/AggregationCalculation.java index 2303891..d8b1769 100644 --- a/generated/java/src/main/java/org/sedml/libsed2/AggregationCalculation.java +++ b/generated/java/src/main/java/org/sedml/libsed2/AggregationCalculation.java @@ -38,7 +38,7 @@ public final class AggregationCalculation extends SedBase { @Override public String descRuleId() { return "SEDBase-0002"; } @Override public String baseCatchall() { return "SEDBase-0000"; } public String getType() { return "aggregationCalculation"; } - private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"valid\": true, \"type\": \"annotatedData\", \"dimensions\": {\"source\": \"static\", \"expr\": \"shapeOf(input) - dim(appliedDimensions or outermost)\", \"note\": \"shape is input's shape with the dimension(s) named in appliedDimensions removed (or the outermost dimension, if appliedDimensions is unset); dimension count/sizes are therefore only as knowable as input's own shape is\"}}, \"[id].model\": {\"valid\": false}, \"[id].strings\": {\"valid\": false}}}"); + private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"type\": \"annotatedData\", \"dimensions\": {\"source\": \"static\", \"expr\": \"shapeOf(input) - dim(appliedDimensions or outermost)\", \"note\": \"shape is input's shape with the dimension(s) named in appliedDimensions removed (or the outermost dimension, if appliedDimensions is unset); dimension count/sizes are therefore only as knowable as input's own shape is\"}}}}"); @Override public JsonNode outputsJson() { return OUTPUTS_JSON; } public JsonNode getInput() { if (!values.containsKey("input")) throw new ApiError("input" + " is not set"); return values.get("input"); } diff --git a/generated/java/src/main/java/org/sedml/libsed2/BoundedODESimulation.java b/generated/java/src/main/java/org/sedml/libsed2/BoundedODESimulation.java index 25c72f2..799388d 100644 --- a/generated/java/src/main/java/org/sedml/libsed2/BoundedODESimulation.java +++ b/generated/java/src/main/java/org/sedml/libsed2/BoundedODESimulation.java @@ -62,7 +62,7 @@ public final class BoundedODESimulation extends SedBase { @Override public String descRuleId() { return "SEDBase-0002"; } @Override public String baseCatchall() { return "SEDBase-0000"; } public String getType() { return "boundedODESimulation"; } - private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"valid\": true, \"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"runtime\", \"note\": \"row count is chosen by the solver/simulator at run time under variable step size, not fixed by independentVariableSpan (only its start/end bound the range)\"}, \"labels\": null}, {\"size\": {\"source\": \"static\", \"expr\": \"1 + len(outputVariables)\"}, \"labels\": {\"source\": \"static\", \"expr\": \"[independentVariable] + outputVariables\"}}]}, \"[id].model\": {\"valid\": true, \"type\": \"model\"}, \"[id].strings\": {\"valid\": false}}}"); + private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"runtime\", \"note\": \"row count is chosen by the solver/simulator at run time under variable step size, not fixed by independentVariableSpan (only its start/end bound the range)\"}, \"labels\": null}, {\"size\": {\"source\": \"static\", \"expr\": \"1 + len(outputVariables)\"}, \"labels\": {\"source\": \"static\", \"expr\": \"[independentVariable] + outputVariables\"}}]}, \"[id].model\": {\"type\": \"model\"}}}"); @Override public JsonNode outputsJson() { return OUTPUTS_JSON; } public double getRelativeToleranceValue() { return getOrRefValueNode("relativeTolerance").asDouble(); } diff --git a/generated/java/src/main/java/org/sedml/libsed2/BoundedStochasticSimulation.java b/generated/java/src/main/java/org/sedml/libsed2/BoundedStochasticSimulation.java index 9aa57ab..39b3284 100644 --- a/generated/java/src/main/java/org/sedml/libsed2/BoundedStochasticSimulation.java +++ b/generated/java/src/main/java/org/sedml/libsed2/BoundedStochasticSimulation.java @@ -52,7 +52,7 @@ public final class BoundedStochasticSimulation extends SedBase { @Override public String descRuleId() { return "SEDBase-0002"; } @Override public String baseCatchall() { return "SEDBase-0000"; } public String getType() { return "boundedStochasticSimulation"; } - private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"valid\": true, \"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"runtime\", \"note\": \"row count is chosen by the solver/simulator at run time under variable step size, not fixed by independentVariableSpan (only its start/end bound the range)\"}, \"labels\": null}, {\"size\": {\"source\": \"static\", \"expr\": \"1 + len(outputVariables)\"}, \"labels\": {\"source\": \"static\", \"expr\": \"[independentVariable] + outputVariables\"}}]}, \"[id].model\": {\"valid\": true, \"type\": \"model\"}, \"[id].strings\": {\"valid\": false}}}"); + private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"runtime\", \"note\": \"row count is chosen by the solver/simulator at run time under variable step size, not fixed by independentVariableSpan (only its start/end bound the range)\"}, \"labels\": null}, {\"size\": {\"source\": \"static\", \"expr\": \"1 + len(outputVariables)\"}, \"labels\": {\"source\": \"static\", \"expr\": \"[independentVariable] + outputVariables\"}}]}, \"[id].model\": {\"type\": \"model\"}}}"); @Override public JsonNode outputsJson() { return OUTPUTS_JSON; } public double getSeedValue() { return getOrRefValueNode("seed").asDouble(); } diff --git a/generated/java/src/main/java/org/sedml/libsed2/Calculation.java b/generated/java/src/main/java/org/sedml/libsed2/Calculation.java index 8c741d6..d7ee6bc 100644 --- a/generated/java/src/main/java/org/sedml/libsed2/Calculation.java +++ b/generated/java/src/main/java/org/sedml/libsed2/Calculation.java @@ -37,7 +37,7 @@ public final class Calculation extends SedBase { @Override public String descRuleId() { return "SEDBase-0002"; } @Override public String baseCatchall() { return "SEDBase-0000"; } public String getType() { return "calculation"; } - private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"valid\": true, \"type\": \"annotatedData\", \"dimensions\": {\"source\": \"runtime\", \"note\": \"shape matches the evaluated math expression: scalar if every operand is scalar, otherwise broadcasts across the shape of any AnnotatedData operand(s); not derivable without evaluating math against the operands' actual values\"}}, \"[id].model\": {\"valid\": false}}}"); + private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"type\": \"annotatedData\", \"dimensions\": {\"source\": \"runtime\", \"note\": \"shape matches the evaluated math expression: scalar if every operand is scalar, otherwise broadcasts across the shape of any AnnotatedData operand(s); not derivable without evaluating math against the operands' actual values\"}}}}"); @Override public JsonNode outputsJson() { return OUTPUTS_JSON; } public String getMathValue() { return getOrRefValueNode("math").asText(); } diff --git a/generated/java/src/main/java/org/sedml/libsed2/CreateDataBlock.java b/generated/java/src/main/java/org/sedml/libsed2/CreateDataBlock.java index 478e0a3..fc29a4b 100644 --- a/generated/java/src/main/java/org/sedml/libsed2/CreateDataBlock.java +++ b/generated/java/src/main/java/org/sedml/libsed2/CreateDataBlock.java @@ -37,7 +37,7 @@ public final class CreateDataBlock extends SedBase { @Override public String descRuleId() { return "SEDBase-0002"; } @Override public String baseCatchall() { return "SEDBase-0000"; } public String getType() { return "createDataBlock"; } - private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"valid\": true, \"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"static\", \"expr\": \"len(data)\"}, \"labels\": {\"source\": \"static\", \"expr\": \"keys(data)\"}, \"note\": \"base case: one entry per key in the data dictionary. If a value in data is itself multi-dimensional (a list or AnnotatedData), that entry's own dimensions carry through instead - how mixed-dimension entries combine into one overall shape is an open design question (see core-spec.md Section 10), so this formula covers only the uniform-scalar-values case\"}]}, \"[id].model\": {\"valid\": false}}}"); + private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"static\", \"expr\": \"len(data)\"}, \"labels\": {\"source\": \"static\", \"expr\": \"keys(data)\"}, \"note\": \"base case: one entry per key in the data dictionary. If a value in data is itself multi-dimensional (a list or AnnotatedData), that entry's own dimensions carry through instead - how mixed-dimension entries combine into one overall shape is an open design question (see core-spec.md Section 10), so this formula covers only the uniform-scalar-values case\"}]}}}"); @Override public JsonNode outputsJson() { return OUTPUTS_JSON; } public JsonNode getDataValue() { return getOrRefValueNode("data"); } diff --git a/generated/java/src/main/java/org/sedml/libsed2/CsvImport.java b/generated/java/src/main/java/org/sedml/libsed2/CsvImport.java index ab7603f..66dfdb3 100644 --- a/generated/java/src/main/java/org/sedml/libsed2/CsvImport.java +++ b/generated/java/src/main/java/org/sedml/libsed2/CsvImport.java @@ -44,7 +44,7 @@ public final class CsvImport extends SedBase { @Override public String descRuleId() { return "SEDBase-0002"; } @Override public String baseCatchall() { return "SEDBase-0000"; } public String getType() { return "csvImport"; } - private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"valid\": true, \"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"input-file\", \"from\": \"location\", \"extract\": \"rowCount\", \"note\": \"row count, read from the CSV file at location\"}, \"labels\": null}, {\"size\": {\"source\": \"input-file\", \"from\": \"location\", \"extract\": \"columnCount\", \"note\": \"column count, read from the CSV file at location together with organization/headers/ncols\"}, \"labels\": {\"source\": \"input-file\", \"from\": \"location\", \"extract\": \"columnHeaders\", \"note\": \"column labels, read from the CSV header row when headers is true, else from columnNames\"}}]}, \"[id].model\": {\"valid\": false}, \"[id].strings\": {\"valid\": false}}}"); + private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"input-file\", \"from\": \"location\", \"extract\": \"rowCount\", \"note\": \"row count, read from the CSV file at location\"}, \"labels\": null}, {\"size\": {\"source\": \"input-file\", \"from\": \"location\", \"extract\": \"columnCount\", \"note\": \"column count, read from the CSV file at location together with organization/headers/ncols\"}, \"labels\": {\"source\": \"input-file\", \"from\": \"location\", \"extract\": \"columnHeaders\", \"note\": \"column labels, read from the CSV header row when headers is true, else from columnNames\"}}]}}}"); @Override public JsonNode outputsJson() { return OUTPUTS_JSON; } public String getLocationValue() { return getOrRefValueNode("location").asText(); } diff --git a/generated/java/src/main/java/org/sedml/libsed2/DataImport.java b/generated/java/src/main/java/org/sedml/libsed2/DataImport.java index f529397..6249621 100644 --- a/generated/java/src/main/java/org/sedml/libsed2/DataImport.java +++ b/generated/java/src/main/java/org/sedml/libsed2/DataImport.java @@ -38,7 +38,7 @@ public final class DataImport extends SedBase { @Override public String descRuleId() { return "SEDBase-0002"; } @Override public String baseCatchall() { return "SEDBase-0000"; } public String getType() { return "dataImport"; } - private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"valid\": true, \"type\": \"annotatedData\", \"dimensions\": {\"source\": \"input-file\", \"from\": \"location\", \"extract\": \"shape\", \"note\": \"shape is whatever the imported file itself has; depends on format and the file at location - extraction is format-specific (format names how to parse it)\"}}, \"[id].model\": {\"valid\": false}}}"); + private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"type\": \"annotatedData\", \"dimensions\": {\"source\": \"input-file\", \"from\": \"location\", \"extract\": \"shape\", \"note\": \"shape is whatever the imported file itself has; depends on format and the file at location - extraction is format-specific (format names how to parse it)\"}}}}"); @Override public JsonNode outputsJson() { return OUTPUTS_JSON; } public String getLocationValue() { return getOrRefValueNode("location").asText(); } diff --git a/generated/java/src/main/java/org/sedml/libsed2/DrawFromDistribution.java b/generated/java/src/main/java/org/sedml/libsed2/DrawFromDistribution.java index e42b6f1..7f75c1f 100644 --- a/generated/java/src/main/java/org/sedml/libsed2/DrawFromDistribution.java +++ b/generated/java/src/main/java/org/sedml/libsed2/DrawFromDistribution.java @@ -39,7 +39,7 @@ public final class DrawFromDistribution extends SedBase { @Override public String descRuleId() { return "SEDBase-0002"; } @Override public String baseCatchall() { return "SEDBase-0000"; } public String getType() { return "drawFromDistribution"; } - private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"valid\": true, \"type\": \"annotatedData\", \"dimensions\": [], \"note\": \"currently always a single scalar value (0-D), indexed historically as [id][0]; the type is multidimensional AnnotatedData to leave room for future correlated multi-value draws (shape of that future case is not yet designed - see core-spec.md Section 10)\"}, \"[id].model\": {\"valid\": false}, \"[id].strings\": {\"valid\": false}}}"); + private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"type\": \"annotatedData\", \"dimensions\": [], \"note\": \"currently always a single scalar value (0-D), indexed historically as [id][0]; the type is multidimensional AnnotatedData to leave room for future correlated multi-value draws (shape of that future case is not yet designed - see core-spec.md Section 10)\"}}}"); @Override public JsonNode outputsJson() { return OUTPUTS_JSON; } public String getDistributionValue() { return getOrRefValueNode("distribution").asText(); } diff --git a/generated/java/src/main/java/org/sedml/libsed2/ExplicitODESimulation.java b/generated/java/src/main/java/org/sedml/libsed2/ExplicitODESimulation.java index 9bdaf60..fbd0bb6 100644 --- a/generated/java/src/main/java/org/sedml/libsed2/ExplicitODESimulation.java +++ b/generated/java/src/main/java/org/sedml/libsed2/ExplicitODESimulation.java @@ -62,7 +62,7 @@ public final class ExplicitODESimulation extends SedBase { @Override public String descRuleId() { return "SEDBase-0002"; } @Override public String baseCatchall() { return "SEDBase-0000"; } public String getType() { return "explicitODESimulation"; } - private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"valid\": true, \"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"static\", \"expr\": \"len(independentVariableRange)\"}, \"labels\": null}, {\"size\": {\"source\": \"static\", \"expr\": \"1 + len(outputVariables)\"}, \"labels\": {\"source\": \"static\", \"expr\": \"[independentVariable] + outputVariables\"}}]}, \"[id].model\": {\"valid\": true, \"type\": \"model\"}, \"[id].strings\": {\"valid\": false}}}"); + private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"static\", \"expr\": \"len(independentVariableRange)\"}, \"labels\": null}, {\"size\": {\"source\": \"static\", \"expr\": \"1 + len(outputVariables)\"}, \"labels\": {\"source\": \"static\", \"expr\": \"[independentVariable] + outputVariables\"}}]}, \"[id].model\": {\"type\": \"model\"}}}"); @Override public JsonNode outputsJson() { return OUTPUTS_JSON; } public double getRelativeToleranceValue() { return getOrRefValueNode("relativeTolerance").asDouble(); } diff --git a/generated/java/src/main/java/org/sedml/libsed2/ExplicitStochasticSimulation.java b/generated/java/src/main/java/org/sedml/libsed2/ExplicitStochasticSimulation.java index 647a6ad..dbc013e 100644 --- a/generated/java/src/main/java/org/sedml/libsed2/ExplicitStochasticSimulation.java +++ b/generated/java/src/main/java/org/sedml/libsed2/ExplicitStochasticSimulation.java @@ -52,7 +52,7 @@ public final class ExplicitStochasticSimulation extends SedBase { @Override public String descRuleId() { return "SEDBase-0002"; } @Override public String baseCatchall() { return "SEDBase-0000"; } public String getType() { return "explicitStochasticSimulation"; } - private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"valid\": true, \"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"static\", \"expr\": \"independentVariableRange.numberOfSteps\"}, \"labels\": null}, {\"size\": {\"source\": \"static\", \"expr\": \"1 + len(outputVariables)\"}, \"labels\": {\"source\": \"static\", \"expr\": \"[independentVariable] + outputVariables\"}}]}, \"[id].model\": {\"valid\": true, \"type\": \"model\"}, \"[id].strings\": {\"valid\": false}}}"); + private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"static\", \"expr\": \"independentVariableRange.numberOfSteps\"}, \"labels\": null}, {\"size\": {\"source\": \"static\", \"expr\": \"1 + len(outputVariables)\"}, \"labels\": {\"source\": \"static\", \"expr\": \"[independentVariable] + outputVariables\"}}]}, \"[id].model\": {\"type\": \"model\"}}}"); @Override public JsonNode outputsJson() { return OUTPUTS_JSON; } public double getSeedValue() { return getOrRefValueNode("seed").asDouble(); } diff --git a/generated/java/src/main/java/org/sedml/libsed2/FluxBalanceAnalysis.java b/generated/java/src/main/java/org/sedml/libsed2/FluxBalanceAnalysis.java index b832128..1626199 100644 --- a/generated/java/src/main/java/org/sedml/libsed2/FluxBalanceAnalysis.java +++ b/generated/java/src/main/java/org/sedml/libsed2/FluxBalanceAnalysis.java @@ -21,12 +21,13 @@ public final class FluxBalanceAnalysis extends SedBase { private static final List FIELD_SPECS = List.of( new FieldSpec("model", "SIdRef", true, "FluxBalanceAnalysis-0002", "FluxBalanceAnalysis-0001", "FluxBalanceAnalysis-0000", null, null, null, null, null, false, null, null, null, null, "model"), new FieldSpec("outputVariables", "ArrayOrRef", true, "FluxBalanceAnalysis-0004", "FluxBalanceAnalysis-0003", "FluxBalanceAnalysis-0000", null, null, null, null, null, false, null, null, "FluxBalanceAnalysis-0005", "string", null), - new FieldSpec("outputModel", "BooleanOrRef", false, "FluxBalanceAnalysis-0006", null, "FluxBalanceAnalysis-0000", null, null, null, null, null, false, null, null, "FluxBalanceAnalysis-0007", null, null), new FieldSpec("notes", "any", false, "SEDBase-0003", null, "SEDBase-0000", null, null, null, null, null, false, null, null, null, null, null), + new FieldSpec("workingAlgorithms", "array", false, "FluxBalanceAnalysis-0009", null, "FluxBalanceAnalysis-0000", null, null, null, "WorkingAlgorithm", null, false, null, null, null, null, null), new FieldSpec("taskParameters", "array", false, "AbstractTask-0001", null, "AbstractTask-0000", null, null, null, "TaskParameter", null, false, null, null, null, null, null), new FieldSpec("annotations", "array", false, "SEDBase-0004", null, "SEDBase-0000", null, null, null, "Annotation", null, false, null, null, null, null, null) ); private static final Set REQUIRED_NAMES = Set.of("model", "outputVariables"); + private final ListCollection workingAlgorithms = new ListCollection<>(); private final ListCollection taskParameters = new ListCollection<>(); private final ListCollection annotations = new ListCollection<>(); @@ -39,7 +40,7 @@ public final class FluxBalanceAnalysis extends SedBase { @Override public String descRuleId() { return "SEDBase-0002"; } @Override public String baseCatchall() { return "SEDBase-0000"; } public String getType() { return "fluxBalanceAnalysis"; } - private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"valid\": true, \"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"static\", \"expr\": \"len(outputVariables)\"}, \"labels\": {\"source\": \"static\", \"expr\": \"outputVariables\"}}]}, \"[id].model\": {\"valid\": \"outputModel == true\", \"type\": \"model\"}, \"[id].strings\": {\"valid\": false}}}"); + private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"static\", \"expr\": \"len(outputVariables)\"}, \"labels\": {\"source\": \"static\", \"expr\": \"outputVariables\"}}]}, \"[id].model\": {\"type\": \"model\"}}}"); @Override public JsonNode outputsJson() { return OUTPUTS_JSON; } public String getModel() { if (!values.containsKey("model")) throw new ApiError("model" + " is not set"); return values.get("model").asText(); } @@ -55,19 +56,16 @@ public final class FluxBalanceAnalysis extends SedBase { public boolean isSetOutputVariables() { return values.containsKey("outputVariables"); } public void unsetOutputVariables() { values.remove("outputVariables"); orRefIsRef.remove("outputVariables"); } - public boolean getOutputModelValue() { return getOrRefValueNode("outputModel").asBoolean(); } - public String getOutputModelRef() { return getOrRefRefNode("outputModel").asText(); } - public void setOutputModelValue(boolean value) { setOrRefValueNode("outputModel", BooleanNode.valueOf(value)); } - public void setOutputModelRef(String ref) { setOrRefRefNode("outputModel", ref); } - public boolean isOutputModelRef() { return isOrRefRef("outputModel"); } - public boolean isSetOutputModel() { return values.containsKey("outputModel"); } - public void unsetOutputModel() { values.remove("outputModel"); orRefIsRef.remove("outputModel"); } - public JsonNode getNotes() { if (!values.containsKey("notes")) throw new ApiError("notes" + " is not set"); return values.get("notes"); } public void setNotes(JsonNode value) { values.put("notes", value); } public boolean isSetNotes() { return values.containsKey("notes"); } public void unsetNotes() { values.remove("notes"); } + public List getWorkingAlgorithms() { return workingAlgorithms.items(); } + public void addWorkingAlgorithms(SedBase obj) { workingAlgorithms.add(obj); obj.attach(this, getDocument()); } + public void insertWorkingAlgorithms(int index, SedBase obj) { workingAlgorithms.insert(index, obj); obj.attach(this, getDocument()); } + public void removeWorkingAlgorithms(int index) { workingAlgorithms.remove(index); } + public List getTaskParameters() { return taskParameters.items(); } public void addTaskParameters(SedBase obj) { taskParameters.add(obj); obj.attach(this, getDocument()); } public void insertTaskParameters(int index, SedBase obj) { taskParameters.insert(index, obj); obj.attach(this, getDocument()); } @@ -81,6 +79,7 @@ public final class FluxBalanceAnalysis extends SedBase { @Override public List children() { List kids = new ArrayList<>(); + kids.addAll(workingAlgorithms.items()); kids.addAll(taskParameters.items()); kids.addAll(annotations.items()); return kids; @@ -89,6 +88,7 @@ public List children() { @Override public List childrenWithLocations() { List out = new ArrayList<>(); + { int idx = 0; for (SedBase item : workingAlgorithms.items()) { out.add(new ChildLoc(item, "/workingAlgorithms/" + idx)); idx++; } } { int idx = 0; for (SedBase item : taskParameters.items()) { out.add(new ChildLoc(item, "/taskParameters/" + idx)); idx++; } } { int idx = 0; for (SedBase item : annotations.items()) { out.add(new ChildLoc(item, "/annotations/" + idx)); idx++; } } return out; @@ -97,6 +97,7 @@ public List childrenWithLocations() { @Override protected ListCollection getListCollection(String fieldName) { switch (fieldName) { + case "workingAlgorithms": return workingAlgorithms; case "taskParameters": return taskParameters; case "annotations": return annotations; default: return super.getListCollection(fieldName); @@ -111,8 +112,8 @@ public ObjectNode ownJsonValue() { d.set("_type", values.containsKey("_type") ? values.get("_type") : TextNode.valueOf("fluxBalanceAnalysis")); if (values.containsKey("model")) d.set("model", values.get("model")); if (values.containsKey("outputVariables")) d.set("outputVariables", values.get("outputVariables")); - if (values.containsKey("outputModel")) d.set("outputModel", values.get("outputModel")); if (values.containsKey("notes")) d.set("notes", values.get("notes")); + if (workingAlgorithms.size() > 0) { ArrayNode arr = d.putArray("workingAlgorithms"); for (SedBase item : workingAlgorithms.items()) arr.add(item.toJsonValue()); } if (taskParameters.size() > 0) { ArrayNode arr = d.putArray("taskParameters"); for (SedBase item : taskParameters.items()) arr.add(item.toJsonValue()); } if (annotations.size() > 0) { ArrayNode arr = d.putArray("annotations"); for (SedBase item : annotations.items()) arr.add(item.toJsonValue()); } for (Map.Entry e : nsAttrs.entrySet()) d.set(e.getKey(), e.getValue()); diff --git a/generated/java/src/main/java/org/sedml/libsed2/JacobianFull.java b/generated/java/src/main/java/org/sedml/libsed2/JacobianFull.java index 85c4849..f6eb345 100644 --- a/generated/java/src/main/java/org/sedml/libsed2/JacobianFull.java +++ b/generated/java/src/main/java/org/sedml/libsed2/JacobianFull.java @@ -37,7 +37,7 @@ public final class JacobianFull extends SedBase { @Override public String descRuleId() { return "SEDBase-0002"; } @Override public String baseCatchall() { return "SEDBase-0000"; } public String getType() { return "jacobianFull"; } - private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"valid\": true, \"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"input-file\", \"from\": \"model\", \"extract\": \"floatingSpeciesIds\", \"note\": \"row count = number of species in the referenced model\"}, \"labels\": {\"source\": \"input-file\", \"from\": \"model\", \"extract\": \"floatingSpeciesIds\", \"note\": \"row labels = the model's ordered species list\"}}, {\"size\": {\"source\": \"input-file\", \"from\": \"model\", \"extract\": \"floatingSpeciesIds\", \"note\": \"column count = number of species in the referenced model\"}, \"labels\": {\"source\": \"input-file\", \"from\": \"model\", \"extract\": \"floatingSpeciesIds\", \"note\": \"column labels = the model's ordered species list\"}}]}, \"[id].model\": {\"valid\": false}, \"[id].strings\": {\"valid\": false}}}"); + private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"input-file\", \"from\": \"model\", \"extract\": \"floatingSpeciesIds\", \"note\": \"row count = number of species in the referenced model\"}, \"labels\": {\"source\": \"input-file\", \"from\": \"model\", \"extract\": \"floatingSpeciesIds\", \"note\": \"row labels = the model's ordered species list\"}}, {\"size\": {\"source\": \"input-file\", \"from\": \"model\", \"extract\": \"floatingSpeciesIds\", \"note\": \"column count = number of species in the referenced model\"}, \"labels\": {\"source\": \"input-file\", \"from\": \"model\", \"extract\": \"floatingSpeciesIds\", \"note\": \"column labels = the model's ordered species list\"}}]}}}"); @Override public JsonNode outputsJson() { return OUTPUTS_JSON; } public String getModel() { if (!values.containsKey("model")) throw new ApiError("model" + " is not set"); return values.get("model").asText(); } diff --git a/generated/java/src/main/java/org/sedml/libsed2/JacobianReduced.java b/generated/java/src/main/java/org/sedml/libsed2/JacobianReduced.java index e6da2f6..855d243 100644 --- a/generated/java/src/main/java/org/sedml/libsed2/JacobianReduced.java +++ b/generated/java/src/main/java/org/sedml/libsed2/JacobianReduced.java @@ -37,7 +37,7 @@ public final class JacobianReduced extends SedBase { @Override public String descRuleId() { return "SEDBase-0002"; } @Override public String baseCatchall() { return "SEDBase-0000"; } public String getType() { return "jacobianReduced"; } - private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"valid\": true, \"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"input-file\", \"from\": \"model\", \"extract\": \"reducedFloatingSpeciesIds\", \"note\": \"row count = number of species in the referenced model's reduced species set\"}, \"labels\": {\"source\": \"input-file\", \"from\": \"model\", \"extract\": \"reducedFloatingSpeciesIds\", \"note\": \"row labels = the model's ordered, reduced species list\"}}, {\"size\": {\"source\": \"input-file\", \"from\": \"model\", \"extract\": \"reducedFloatingSpeciesIds\", \"note\": \"column count = number of species in the referenced model's reduced species set\"}, \"labels\": {\"source\": \"input-file\", \"from\": \"model\", \"extract\": \"reducedFloatingSpeciesIds\", \"note\": \"column labels = the model's ordered, reduced species list\"}}]}, \"[id].model\": {\"valid\": false}, \"[id].strings\": {\"valid\": false}}}"); + private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"input-file\", \"from\": \"model\", \"extract\": \"reducedFloatingSpeciesIds\", \"note\": \"row count = number of species in the referenced model's reduced species set\"}, \"labels\": {\"source\": \"input-file\", \"from\": \"model\", \"extract\": \"reducedFloatingSpeciesIds\", \"note\": \"row labels = the model's ordered, reduced species list\"}}, {\"size\": {\"source\": \"input-file\", \"from\": \"model\", \"extract\": \"reducedFloatingSpeciesIds\", \"note\": \"column count = number of species in the referenced model's reduced species set\"}, \"labels\": {\"source\": \"input-file\", \"from\": \"model\", \"extract\": \"reducedFloatingSpeciesIds\", \"note\": \"column labels = the model's ordered, reduced species list\"}}]}}}"); @Override public JsonNode outputsJson() { return OUTPUTS_JSON; } public String getModel() { if (!values.containsKey("model")) throw new ApiError("model" + " is not set"); return values.get("model").asText(); } diff --git a/generated/java/src/main/java/org/sedml/libsed2/Loop.java b/generated/java/src/main/java/org/sedml/libsed2/Loop.java index e8d8418..785c08f 100644 --- a/generated/java/src/main/java/org/sedml/libsed2/Loop.java +++ b/generated/java/src/main/java/org/sedml/libsed2/Loop.java @@ -26,9 +26,9 @@ public final class Loop extends SedBase { new FieldSpec("aggregateOutputVariables", "dict", false, "Repeat-0004", null, "Repeat-0000", null, null, null, "AggregationCalculation", null, false, null, null, null, null, null), new FieldSpec("taskParameters", "array", false, "AbstractTask-0001", null, "AbstractTask-0000", null, null, null, "TaskParameter", null, false, null, null, null, null, null), new FieldSpec("annotations", "array", false, "SEDBase-0004", null, "SEDBase-0000", null, null, null, "Annotation", null, false, null, null, null, null, null), - new FieldSpec("range", "ref-discriminator", false, "Repeat-0005", null, "Repeat-0000", null, null, null, null, "RangeInline", false, null, null, null, null, null) + new FieldSpec("range", "ref-discriminator", true, "Loop-0007", "Loop-0006", "Loop-0000", null, null, null, null, "RangeInline", false, null, null, null, null, null) ); - private static final Set REQUIRED_NAMES = Set.of("loopVariables"); + private static final Set REQUIRED_NAMES = Set.of("loopVariables", "range"); private final IdKeyedCollection loopVariables = new IdKeyedCollection<>(); private final IdKeyedCollection subTasks = new IdKeyedCollection<>(); private final IdKeyedCollection aggregateOutputVariables = new IdKeyedCollection<>(); @@ -45,7 +45,7 @@ public final class Loop extends SedBase { @Override public String descRuleId() { return "SEDBase-0002"; } @Override public String baseCatchall() { return "SEDBase-0000"; } public String getType() { return "loop"; } - private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"valid\": true, \"type\": \"annotatedData\", \"dimensions\": {\"source\": \"runtime\", \"note\": \"2D or more: first dimension = one row per iteration (iteration count is not knowable ahead of the loop actually running - Loop's exact termination condition is an open design question, see core-spec.md Section 10); remaining dimension(s) = one column per entry of outputVariableMap\"}}, \"[id].model\": {\"valid\": false}, \"[id].strings\": {\"valid\": false}, \"[id].aggregates\": {\"valid\": \"provided(aggregateOutputVariables)\", \"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"static\", \"expr\": \"len(aggregateOutputVariables)\"}, \"labels\": null, \"note\": \"each entry collapses the iteration dimension of [id] to a single value (per Repeat, the applied dimension defaults to this Loop's own iterations), unless the underlying subTask output was itself multi-dimensional, in which case that dimensionality carries through per entry\"}]}, \"[id].range\": {\"valid\": \"provided(range)\", \"type\": \"annotatedData\", \"dimensions\": [], \"note\": \"the current value of range, within the loop\"}, \"[id].index\": {\"valid\": \"provided(range)\", \"type\": \"annotatedData\", \"dimensions\": [], \"note\": \"the current index into range, within the loop\"}}}"); + private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"static\", \"expr\": \"len(range)\"}, \"labels\": null, \"note\": \"one row per value in range; len(range) dispatches on range's actual Range/NumericRange/ParameterRange type\"}, {\"size\": {\"source\": \"static\", \"expr\": \"len(outputVariableMap)\"}, \"labels\": null, \"note\": \"one column per entry of outputVariableMap, or just the range-values column alone if outputVariableMap is empty; a column whose subTask output is itself multi-dimensional would add further dimensions beyond this, not captured here\"}]}, \"[id].aggregates\": {\"valid\": \"provided(aggregateOutputVariables)\", \"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"static\", \"expr\": \"len(aggregateOutputVariables)\"}, \"labels\": null, \"note\": \"each entry collapses the iteration dimension of [id] to a single value (per Repeat, the applied dimension defaults to this Loop's own iterations), unless the underlying subTask output was itself multi-dimensional, in which case that dimensionality carries through per entry\"}]}, \"[id].range\": {\"type\": \"annotatedData\", \"dimensions\": [], \"note\": \"the current value of range, within the loop\"}, \"[id].index\": {\"type\": \"annotatedData\", \"dimensions\": [], \"note\": \"the current index into range, within the loop\"}}}"); @Override public JsonNode outputsJson() { return OUTPUTS_JSON; } public JsonNode getOutputVariableMapValue() { return getOrRefValueNode("outputVariableMap"); } diff --git a/generated/java/src/main/java/org/sedml/libsed2/ModelChange.java b/generated/java/src/main/java/org/sedml/libsed2/ModelChange.java index d37debd..8b29b8f 100644 --- a/generated/java/src/main/java/org/sedml/libsed2/ModelChange.java +++ b/generated/java/src/main/java/org/sedml/libsed2/ModelChange.java @@ -41,7 +41,7 @@ public final class ModelChange extends SedBase { @Override public String descRuleId() { return "SEDBase-0002"; } @Override public String baseCatchall() { return "SEDBase-0000"; } public String getType() { return "modelChange"; } - private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"valid\": false}, \"[id].model\": {\"valid\": true, \"type\": \"model\"}, \"[id].strings\": {\"valid\": false}}}"); + private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id].model\": {\"type\": \"model\"}}}"); @Override public JsonNode outputsJson() { return OUTPUTS_JSON; } public String getInputModel() { if (!values.containsKey("inputModel")) throw new ApiError("inputModel" + " is not set"); return values.get("inputModel").asText(); } diff --git a/generated/java/src/main/java/org/sedml/libsed2/ModelElementList.java b/generated/java/src/main/java/org/sedml/libsed2/ModelElementList.java index 198abb2..9f78091 100644 --- a/generated/java/src/main/java/org/sedml/libsed2/ModelElementList.java +++ b/generated/java/src/main/java/org/sedml/libsed2/ModelElementList.java @@ -41,7 +41,7 @@ public final class ModelElementList extends SedBase { @Override public String descRuleId() { return "SEDBase-0002"; } @Override public String baseCatchall() { return "SEDBase-0000"; } public String getType() { return "modelElementList"; } - private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"valid\": false}, \"[id].model\": {\"valid\": false}, \"[id].strings\": {\"valid\": true, \"type\": \"stringList\", \"dimensions\": [{\"size\": {\"source\": \"input-file\", \"from\": \"model\", \"extract\": \"matchedElementIds\", \"note\": \"length = number of elements in the referenced model matched after includeElements/includeTypes/excludeElements/excludeTypes filtering\"}, \"labels\": {\"source\": \"input-file\", \"from\": \"model\", \"extract\": \"matchedElementIds\", \"note\": \"the matched element ids themselves\"}}]}}}"); + private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id].strings\": {\"type\": \"stringList\", \"dimensions\": [{\"size\": {\"source\": \"input-file\", \"from\": \"model\", \"extract\": \"matchedElementIds\", \"note\": \"length = number of elements in the referenced model matched after includeElements/includeTypes/excludeElements/excludeTypes filtering\"}, \"labels\": {\"source\": \"input-file\", \"from\": \"model\", \"extract\": \"matchedElementIds\", \"note\": \"the matched element ids themselves\"}}]}}}"); @Override public JsonNode outputsJson() { return OUTPUTS_JSON; } public String getModel() { if (!values.containsKey("model")) throw new ApiError("model" + " is not set"); return values.get("model").asText(); } diff --git a/generated/java/src/main/java/org/sedml/libsed2/ModelImport.java b/generated/java/src/main/java/org/sedml/libsed2/ModelImport.java index d7c2f0a..5a95803 100644 --- a/generated/java/src/main/java/org/sedml/libsed2/ModelImport.java +++ b/generated/java/src/main/java/org/sedml/libsed2/ModelImport.java @@ -38,7 +38,7 @@ public final class ModelImport extends SedBase { @Override public String descRuleId() { return "SEDBase-0002"; } @Override public String baseCatchall() { return "SEDBase-0000"; } public String getType() { return "modelImport"; } - private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"valid\": false}, \"[id].model\": {\"valid\": true, \"type\": \"model\"}, \"[id].strings\": {\"valid\": false}}}"); + private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id].model\": {\"type\": \"model\"}}}"); @Override public JsonNode outputsJson() { return OUTPUTS_JSON; } public String getLocationValue() { return getOrRefValueNode("location").asText(); } diff --git a/generated/java/src/main/java/org/sedml/libsed2/NumericRange.java b/generated/java/src/main/java/org/sedml/libsed2/NumericRange.java index 2091c25..37c7f4d 100644 --- a/generated/java/src/main/java/org/sedml/libsed2/NumericRange.java +++ b/generated/java/src/main/java/org/sedml/libsed2/NumericRange.java @@ -43,7 +43,7 @@ public final class NumericRange extends SedBase { @Override public String descRuleId() { return "SEDBase-0002"; } @Override public String baseCatchall() { return "SEDBase-0000"; } public String getType() { return "numericRange"; } - private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"valid\": true, \"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"static\", \"expr\": \"len(values) if provided(values) else numberOfSteps + 1\"}, \"labels\": null}]}, \"[id].model\": {\"valid\": false}, \"[id].strings\": {\"valid\": false}}}"); + private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"static\", \"expr\": \"len(values) if provided(values) else numberOfSteps + 1\"}, \"labels\": null}]}}}"); @Override public JsonNode outputsJson() { return OUTPUTS_JSON; } public double getStartValue() { return getOrRefValueNode("start").asDouble(); } diff --git a/generated/java/src/main/java/org/sedml/libsed2/OneStepODESimulation.java b/generated/java/src/main/java/org/sedml/libsed2/OneStepODESimulation.java index 0605f6d..3e099a0 100644 --- a/generated/java/src/main/java/org/sedml/libsed2/OneStepODESimulation.java +++ b/generated/java/src/main/java/org/sedml/libsed2/OneStepODESimulation.java @@ -61,7 +61,7 @@ public final class OneStepODESimulation extends SedBase { @Override public String descRuleId() { return "SEDBase-0002"; } @Override public String baseCatchall() { return "SEDBase-0000"; } public String getType() { return "oneStepODE"; } - private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"valid\": true, \"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"static\", \"expr\": \"len(outputVariables)\"}, \"labels\": {\"source\": \"static\", \"expr\": \"outputVariables\"}, \"note\": \"a single point, not a series\"}]}, \"[id].model\": {\"valid\": true, \"type\": \"model\"}, \"[id].strings\": {\"valid\": false}}}"); + private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"static\", \"expr\": \"len(outputVariables)\"}, \"labels\": {\"source\": \"static\", \"expr\": \"outputVariables\"}, \"note\": \"a single point, not a series\"}]}, \"[id].model\": {\"type\": \"model\"}}}"); @Override public JsonNode outputsJson() { return OUTPUTS_JSON; } public double getIndependentStepValue() { return getOrRefValueNode("independentStep").asDouble(); } diff --git a/generated/java/src/main/java/org/sedml/libsed2/OneStepStochasticSimulation.java b/generated/java/src/main/java/org/sedml/libsed2/OneStepStochasticSimulation.java index 25b3a5f..9b5efd2 100644 --- a/generated/java/src/main/java/org/sedml/libsed2/OneStepStochasticSimulation.java +++ b/generated/java/src/main/java/org/sedml/libsed2/OneStepStochasticSimulation.java @@ -51,7 +51,7 @@ public final class OneStepStochasticSimulation extends SedBase { @Override public String descRuleId() { return "SEDBase-0002"; } @Override public String baseCatchall() { return "SEDBase-0000"; } public String getType() { return "oneStepStochastic"; } - private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"valid\": true, \"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"static\", \"expr\": \"len(outputVariables)\"}, \"labels\": {\"source\": \"static\", \"expr\": \"outputVariables\"}, \"note\": \"a single point, not a series\"}]}, \"[id].model\": {\"valid\": true, \"type\": \"model\"}, \"[id].strings\": {\"valid\": false}, \"[id].independentStep\": {\"valid\": \"!provided(independentStep)\", \"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"static\", \"expr\": \"1\"}, \"labels\": null}], \"note\": \"the actual elapsed step; present only when independentStep was NOT given as input\"}}}"); + private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"static\", \"expr\": \"len(outputVariables)\"}, \"labels\": {\"source\": \"static\", \"expr\": \"outputVariables\"}, \"note\": \"a single point, not a series\"}]}, \"[id].model\": {\"type\": \"model\"}, \"[id].independentStep\": {\"valid\": \"!provided(independentStep)\", \"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"static\", \"expr\": \"1\"}, \"labels\": null}], \"note\": \"the actual elapsed step; present only when independentStep was NOT given as input\"}}}"); @Override public JsonNode outputsJson() { return OUTPUTS_JSON; } public double getIndependentStepValue() { return getOrRefValueNode("independentStep").asDouble(); } diff --git a/generated/java/src/main/java/org/sedml/libsed2/OutputsShape.java b/generated/java/src/main/java/org/sedml/libsed2/OutputsShape.java index 85bccb9..a65bd83 100644 --- a/generated/java/src/main/java/org/sedml/libsed2/OutputsShape.java +++ b/generated/java/src/main/java/org/sedml/libsed2/OutputsShape.java @@ -704,13 +704,16 @@ static List applyIndexChain(List dims, List indexAccessors) return result; } - /** entry["valid"] is true/false, or a boolean expr string over the - * task's own fields. Returns TRUE/FALSE, or null when a string expr - * couldn't be evaluated statically ("the rule does not fire"). */ + /** A suffix entry that is listed in outputs.json is valid; one that isn't + * listed is not (resolveOutput handles that). An entry's optional "valid" + * field is a boolean expr string over the task's own fields meaning + * "valid if"; no "valid" field means always valid. Returns TRUE/FALSE, or + * null when the expr couldn't be evaluated statically ("the rule does not + * fire"). */ static Boolean evalValid(JsonNode entry, Scope scope, Function> shapeOf) { JsonNode valid = entry.get("valid"); - if (valid != null && valid.isBoolean()) return valid.booleanValue(); - if (valid != null && valid.isTextual()) { + if (valid == null) return Boolean.TRUE; + if (valid.isTextual()) { try { return truthy(eval(parseExpr(valid.textValue()), scope, shapeOf)); } catch (NotStatic e) { @@ -722,8 +725,9 @@ static Boolean evalValid(JsonNode entry, Scope scope, Function /** The result of resolveOutput: see that method. */ public static final class Resolution { - /** TRUE (suffix exists and its "valid" evaluated true), FALSE (absent - * or evaluates false), or null (couldn't be determined statically). */ + /** TRUE (suffix is listed and has no "valid" field, or its "valid" + * ("valid if") expr evaluated true), FALSE (not listed, or the expr + * evaluates false), or null (couldn't be determined statically). */ public final Boolean ok; public final JsonNode entry; // the raw outputEntry, or null when the suffix key is absent public final List dimsBefore; // null unless ok == TRUE and the entry has resolvable "dimensions" diff --git a/generated/java/src/main/java/org/sedml/libsed2/ParameterRange.java b/generated/java/src/main/java/org/sedml/libsed2/ParameterRange.java index 8939718..a3279e6 100644 --- a/generated/java/src/main/java/org/sedml/libsed2/ParameterRange.java +++ b/generated/java/src/main/java/org/sedml/libsed2/ParameterRange.java @@ -44,7 +44,7 @@ public final class ParameterRange extends SedBase { @Override public String descRuleId() { return "SEDBase-0002"; } @Override public String baseCatchall() { return "SEDBase-0000"; } public String getType() { return "parameterRange"; } - private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"valid\": true, \"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"static\", \"expr\": \"len(values) if provided(values) else numberOfSteps + 1\", \"note\": \"same derivation as NumericRange, inherited via NumericRangeCommon\"}, \"labels\": null}]}, \"[id].model\": {\"valid\": false}, \"[id].strings\": {\"valid\": false}}}"); + private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"static\", \"expr\": \"len(values) if provided(values) else numberOfSteps + 1\", \"note\": \"same derivation as NumericRange, inherited via NumericRangeCommon\"}, \"labels\": null}]}}}"); @Override public JsonNode outputsJson() { return OUTPUTS_JSON; } public String getModelElementValue() { return getOrRefValueNode("modelElement").asText(); } diff --git a/generated/java/src/main/java/org/sedml/libsed2/ParameterScan.java b/generated/java/src/main/java/org/sedml/libsed2/ParameterScan.java index 2799918..0d3e0b1 100644 --- a/generated/java/src/main/java/org/sedml/libsed2/ParameterScan.java +++ b/generated/java/src/main/java/org/sedml/libsed2/ParameterScan.java @@ -26,8 +26,7 @@ public final class ParameterScan extends SedBase { new FieldSpec("subTasks", "dict", false, "Repeat-0001", null, "Repeat-0000", null, null, null, null, "AbstractTask", false, null, null, null, null, null), new FieldSpec("aggregateOutputVariables", "dict", false, "Repeat-0004", null, "Repeat-0000", null, null, null, "AggregationCalculation", null, false, null, null, null, null, null), new FieldSpec("taskParameters", "array", false, "AbstractTask-0001", null, "AbstractTask-0000", null, null, null, "TaskParameter", null, false, null, null, null, null, null), - new FieldSpec("annotations", "array", false, "SEDBase-0004", null, "SEDBase-0000", null, null, null, "Annotation", null, false, null, null, null, null, null), - new FieldSpec("range", "ref-discriminator", false, "Repeat-0005", null, "Repeat-0000", null, null, null, null, "RangeInline", false, null, null, null, null, null) + new FieldSpec("annotations", "array", false, "SEDBase-0004", null, "SEDBase-0000", null, null, null, "Annotation", null, false, null, null, null, null, null) ); private static final Set REQUIRED_NAMES = Set.of("model", "parameterRanges"); private final ListCollection parameterRanges = new ListCollection<>(); @@ -35,7 +34,6 @@ public final class ParameterScan extends SedBase { private final IdKeyedCollection aggregateOutputVariables = new IdKeyedCollection<>(); private final ListCollection taskParameters = new ListCollection<>(); private final ListCollection annotations = new ListCollection<>(); - private SedBase range; @Override public List fieldSpecs() { return FIELD_SPECS; } @Override public Set requiredNames() { return REQUIRED_NAMES; } @@ -46,7 +44,7 @@ public final class ParameterScan extends SedBase { @Override public String descRuleId() { return "SEDBase-0002"; } @Override public String baseCatchall() { return "SEDBase-0000"; } public String getType() { return "parameterScan"; } - private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"valid\": true, \"type\": \"annotatedData\", \"dimensions\": [{\"repeat\": {\"over\": \"parameterRanges\", \"size\": {\"source\": \"static\", \"expr\": \"len(self)\"}, \"labels\": null, \"note\": \"one dimension per entry of parameterRanges, each sized by that entry's own length; len(self) dispatches on the entry's actual Range/NumericRange/ParameterRange type - see core-spec.md Section 8\"}}, {\"size\": {\"source\": \"static\", \"expr\": \"len(outputVariableMap)\"}, \"labels\": null}]}, \"[id].model\": {\"valid\": false}, \"[id].strings\": {\"valid\": false}, \"[id].aggregates\": {\"valid\": \"provided(aggregateOutputVariables)\", \"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"static\", \"expr\": \"len(aggregateOutputVariables)\"}, \"labels\": null}]}}}"); + private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"type\": \"annotatedData\", \"dimensions\": [{\"repeat\": {\"over\": \"parameterRanges\", \"size\": {\"source\": \"static\", \"expr\": \"len(self)\"}, \"labels\": {\"source\": \"static\", \"expr\": \"modelElement\"}, \"note\": \"one dimension per entry of parameterRanges, each sized by that entry's own length; len(self) dispatches on the entry's actual Range/NumericRange/ParameterRange type - see core-spec.md Section 8; each dimension is labeled with (identified by) that entry's modelElement, in parameterRanges order\"}}, {\"size\": {\"source\": \"static\", \"expr\": \"len(outputVariableMap)\"}, \"labels\": null}]}, \"[id].aggregates\": {\"valid\": \"provided(aggregateOutputVariables)\", \"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"static\", \"expr\": \"len(aggregateOutputVariables)\"}, \"labels\": null}]}, \"[id].ranges\": {\"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"static\", \"expr\": \"len(parameterRanges)\"}, \"labels\": {\"source\": \"static\", \"expr\": \"parameterRanges.modelElement\"}, \"note\": \"one entry per ParameterRange child, in order, labeled with that child's modelElement (parameterRanges.modelElement is the modelElement of each entry, in order)\"}], \"note\": \"the current value of each entry of parameterRanges, within the loop only\"}, \"[id].indexes\": {\"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"static\", \"expr\": \"len(parameterRanges)\"}, \"labels\": {\"source\": \"static\", \"expr\": \"parameterRanges.modelElement\"}, \"note\": \"one entry per ParameterRange child, in order, labeled with that child's modelElement (parameterRanges.modelElement is the modelElement of each entry, in order)\"}], \"note\": \"the current index into each entry of parameterRanges, within the loop only\"}}}"); @Override public JsonNode outputsJson() { return OUTPUTS_JSON; } public String getModel() { if (!values.containsKey("model")) throw new ApiError("model" + " is not set"); return values.get("model").asText(); } @@ -96,11 +94,6 @@ public final class ParameterScan extends SedBase { public void insertAnnotations(int index, SedBase obj) { annotations.insert(index, obj); obj.attach(this, getDocument()); } public void removeAnnotations(int index) { annotations.remove(index); } - public SedBase getRange() { if (range == null) throw new ApiError("range" + " is not set"); return range; } - public void setRange(SedBase obj) { range = obj; obj.attach(this, getDocument()); } - public boolean isSetRange() { return range != null; } - public void unsetRange() { range = null; } - @Override public List children() { List kids = new ArrayList<>(); @@ -109,7 +102,6 @@ public List children() { kids.addAll(parameterRanges.items()); kids.addAll(taskParameters.items()); kids.addAll(annotations.items()); - if (range != null) kids.add(range); return kids; } @@ -121,7 +113,6 @@ public List childrenWithLocations() { { int idx = 0; for (SedBase item : parameterRanges.items()) { out.add(new ChildLoc(item, "/parameterRanges/" + idx)); idx++; } } { int idx = 0; for (SedBase item : taskParameters.items()) { out.add(new ChildLoc(item, "/taskParameters/" + idx)); idx++; } } { int idx = 0; for (SedBase item : annotations.items()) { out.add(new ChildLoc(item, "/annotations/" + idx)); idx++; } } - if (range != null) out.add(new ChildLoc(range, "/range")); return out; } @@ -156,14 +147,6 @@ protected ListCollection getListCollection(String fieldName) { } } - @Override - protected void setChildField(String fieldName, SedBase child) { - switch (fieldName) { - case "range": range = child; return; - default: super.setChildField(fieldName, child); - } - } - @Override public ObjectNode ownJsonValue() { ObjectNode d = JsonNodeFactory.instance.objectNode(); @@ -178,7 +161,6 @@ public ObjectNode ownJsonValue() { if (parameterRanges.size() > 0) { ArrayNode arr = d.putArray("parameterRanges"); for (SedBase item : parameterRanges.items()) arr.add(item.toJsonValue()); } if (taskParameters.size() > 0) { ArrayNode arr = d.putArray("taskParameters"); for (SedBase item : taskParameters.items()) arr.add(item.toJsonValue()); } if (annotations.size() > 0) { ArrayNode arr = d.putArray("annotations"); for (SedBase item : annotations.items()) arr.add(item.toJsonValue()); } - if (range != null) d.set("range", range.toJsonValue()); for (Map.Entry e : nsAttrs.entrySet()) d.set(e.getKey(), e.getValue()); return d; } diff --git a/generated/java/src/main/java/org/sedml/libsed2/Range.java b/generated/java/src/main/java/org/sedml/libsed2/Range.java index 3794d95..a2bee85 100644 --- a/generated/java/src/main/java/org/sedml/libsed2/Range.java +++ b/generated/java/src/main/java/org/sedml/libsed2/Range.java @@ -37,7 +37,7 @@ public final class Range extends SedBase { @Override public String descRuleId() { return "SEDBase-0002"; } @Override public String baseCatchall() { return "SEDBase-0000"; } public String getType() { return "range"; } - private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"valid\": true, \"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"static\", \"expr\": \"len(values)\"}, \"labels\": null}]}, \"[id].model\": {\"valid\": false}, \"[id].strings\": {\"valid\": false}}}"); + private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"static\", \"expr\": \"len(values)\"}, \"labels\": null}]}}}"); @Override public JsonNode outputsJson() { return OUTPUTS_JSON; } public JsonNode getValuesValue() { return getOrRefValueNode("values"); } diff --git a/generated/java/src/main/java/org/sedml/libsed2/RelabelData.java b/generated/java/src/main/java/org/sedml/libsed2/RelabelData.java index b3c1c93..eb3a4c6 100644 --- a/generated/java/src/main/java/org/sedml/libsed2/RelabelData.java +++ b/generated/java/src/main/java/org/sedml/libsed2/RelabelData.java @@ -38,7 +38,7 @@ public final class RelabelData extends SedBase { @Override public String descRuleId() { return "SEDBase-0002"; } @Override public String baseCatchall() { return "SEDBase-0000"; } public String getType() { return "relabelData"; } - private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"valid\": true, \"type\": \"annotatedData\", \"dimensions\": {\"source\": \"static\", \"expr\": \"shapeOf(input)\", \"note\": \"same dimensions as the referenced input AnnotatedData - this task only replaces the topmost dimension's labels (from labels), not the shape\"}}, \"[id].model\": {\"valid\": false}}}"); + private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"type\": \"annotatedData\", \"dimensions\": {\"source\": \"static\", \"expr\": \"shapeOf(input)\", \"note\": \"same dimensions as the referenced input AnnotatedData - this task only replaces the topmost dimension's labels (from labels), not the shape\"}}}}"); @Override public JsonNode outputsJson() { return OUTPUTS_JSON; } public String getInput() { if (!values.containsKey("input")) throw new ApiError("input" + " is not set"); return values.get("input").asText(); } diff --git a/generated/java/src/main/java/org/sedml/libsed2/RulesData.java b/generated/java/src/main/java/org/sedml/libsed2/RulesData.java index 42a14a6..eab241a 100644 --- a/generated/java/src/main/java/org/sedml/libsed2/RulesData.java +++ b/generated/java/src/main/java/org/sedml/libsed2/RulesData.java @@ -200,8 +200,6 @@ public static void register() { RuleCatalog.CATALOG.put("FluxBalanceAnalysis-0003", new RuleCatalog.Entry("The outputVariables attribute of a FluxBalanceAnalysis is required.", "Required attribute '{attr}' is missing from {class} '{id}'.", "error")); RuleCatalog.CATALOG.put("FluxBalanceAnalysis-0004", new RuleCatalog.Entry("When the value of outputVariables of a FluxBalanceAnalysis is provided directly, it must be an array of strings.", "Attribute '{attr}' of {class} '{id}' has value '{value}', which is not an array of strings.", "error")); RuleCatalog.CATALOG.put("FluxBalanceAnalysis-0005", new RuleCatalog.Entry("When the value of outputVariables of a FluxBalanceAnalysis is a reference, it must be a reference to an array of strings.", "Attribute '{attr}' of {class} '{id}' is the reference '{value}', which resolves to '{resolved-value}', not an array of strings.", "error")); - RuleCatalog.CATALOG.put("FluxBalanceAnalysis-0006", new RuleCatalog.Entry("When the value of outputModel of a FluxBalanceAnalysis is provided directly, it must be a boolean.", "Attribute '{attr}' of {class} '{id}' has value '{value}', which is not a boolean.", "error")); - RuleCatalog.CATALOG.put("FluxBalanceAnalysis-0007", new RuleCatalog.Entry("When the value of outputModel of a FluxBalanceAnalysis is a reference, it must be a reference to a boolean.", "Attribute '{attr}' of {class} '{id}' is the reference '{value}', which resolves to '{resolved-value}', not a boolean.", "error")); RuleCatalog.CATALOG.put("FluxBalanceAnalysis-0008", new RuleCatalog.Entry("The _type attribute of a FluxBalanceAnalysis must be \"fluxBalanceAnalysis\".", "Attribute '{attr}' of {class} '{id}' has value '{value}', which does not match the required value '{allowed}'.", "error")); RuleCatalog.CATALOG.put("JacobianFull-0000", new RuleCatalog.Entry("The element fails a JSON Schema constraint attributable to JacobianFull that does not match any other numbered rule.", "{schema-message} (at {location})", "error")); RuleCatalog.CATALOG.put("JacobianFull-0001", new RuleCatalog.Entry("The model attribute of a JacobianFull is required.", "Required attribute '{attr}' is missing from {class} '{id}'.", "error")); @@ -332,7 +330,6 @@ public static void register() { RuleCatalog.CATALOG.put("Repeat-0002", new RuleCatalog.Entry("When the value of outputVariableMap of a Repeat is provided directly, it must be an object whose values are SIdRef.", "Attribute '{attr}' of {class} '{id}' has value '{value}', which is not an object whose values are SIdRef.", "error")); RuleCatalog.CATALOG.put("Repeat-0003", new RuleCatalog.Entry("When the value of outputVariableMap of a Repeat is a reference, it must be a reference to an object whose values are SIdRef.", "Attribute '{attr}' of {class} '{id}' is the reference '{value}', which resolves to '{resolved-value}', not an object whose values are SIdRef.", "error")); RuleCatalog.CATALOG.put("Repeat-0004", new RuleCatalog.Entry("The aggregateOutputVariables attribute of a Repeat must be an object whose values are AggregationCalculation.", "Attribute '{attr}' of {class} '{id}' has value '{value}', which is not an object whose values are AggregationCalculation.", "error")); - RuleCatalog.CATALOG.put("Repeat-0005", new RuleCatalog.Entry("The range attribute of a Repeat, if present, must be a RangeInline object.", "Attribute '{attr}' of {class} '{id}' has value '{value}', which is not a RangeInline object.", "error")); RuleCatalog.CATALOG.put("Repeat-0006", new RuleCatalog.Entry("A Repeat must provide at least one of outputVariableMap or aggregateOutputVariables.", "{class} '{id}' must provide at least one of 'outputVariableMap' or 'aggregateOutputVariables'.", "error")); RuleCatalog.CATALOG.put("Repeat-0008", new RuleCatalog.Entry("Every value in a Repeat's outputVariableMap must reference one of that Repeat's own subTasks, or an output of one.", "Entry '{attr}' of the outputVariableMap of {class} '{id}' references '{value}', which is not one of its own subTasks.", "error")); RuleCatalog.CATALOG.put("Repeat-0009", new RuleCatalog.Entry("The input of every entry in a Repeat's aggregateOutputVariables must reference one of that Repeat's own subTasks, or an output of one.", "Entry '{attr}' of the aggregateOutputVariables of {class} '{id}' has input '{value}', which is not one of its own subTasks.", "error")); @@ -389,8 +386,6 @@ public static void register() { RuleCatalog.CATALOG.put("SteadyState-0002", new RuleCatalog.Entry("The outputVariables attribute of a SteadyState is required.", "Required attribute '{attr}' is missing from {class} '{id}'.", "error")); RuleCatalog.CATALOG.put("SteadyState-0003", new RuleCatalog.Entry("The _type attribute of a SteadyState must be \"steadyState\".", "Attribute '{attr}' of {class} '{id}' has value '{value}', which does not match the required value '{allowed}'.", "error")); RuleCatalog.CATALOG.put("SteadyState-0004", new RuleCatalog.Entry("The independentVariable attribute of a SteadyState, if present, must be a string.", "Attribute '{attr}' of {class} '{id}' has value '{value}', which is not a string.", "error")); - RuleCatalog.CATALOG.put("SteadyState-0005", new RuleCatalog.Entry("When the value of outputModel of a SteadyState is provided directly, it must be a boolean.", "Attribute '{attr}' of {class} '{id}' has value '{value}', which is not a boolean.", "error")); - RuleCatalog.CATALOG.put("SteadyState-0006", new RuleCatalog.Entry("When the value of outputModel of a SteadyState is a reference, it must be a reference to a boolean.", "Attribute '{attr}' of {class} '{id}' is the reference '{value}', which resolves to '{resolved-value}', not a boolean.", "error")); RuleCatalog.CATALOG.put("StringFormation-0000", new RuleCatalog.Entry("The element fails a JSON Schema constraint attributable to StringFormation that does not match any other numbered rule.", "{schema-message} (at {location})", "error")); RuleCatalog.CATALOG.put("StringFormation-0001", new RuleCatalog.Entry("The concatenate attribute of a StringFormation is required.", "Required attribute '{attr}' is missing from {class} '{id}'.", "error")); RuleCatalog.CATALOG.put("StringFormation-0002", new RuleCatalog.Entry("When the value of concatenate of a StringFormation is provided directly, it must be an array of values.", "Attribute '{attr}' of {class} '{id}' has value '{value}', which is not an array of values.", "error")); diff --git a/generated/java/src/main/java/org/sedml/libsed2/Scatter.java b/generated/java/src/main/java/org/sedml/libsed2/Scatter.java index 06401fa..f8112cb 100644 --- a/generated/java/src/main/java/org/sedml/libsed2/Scatter.java +++ b/generated/java/src/main/java/org/sedml/libsed2/Scatter.java @@ -25,9 +25,9 @@ public final class Scatter extends SedBase { new FieldSpec("aggregateOutputVariables", "dict", false, "Repeat-0004", null, "Repeat-0000", null, null, null, "AggregationCalculation", null, false, null, null, null, null, null), new FieldSpec("taskParameters", "array", false, "AbstractTask-0001", null, "AbstractTask-0000", null, null, null, "TaskParameter", null, false, null, null, null, null, null), new FieldSpec("annotations", "array", false, "SEDBase-0004", null, "SEDBase-0000", null, null, null, "Annotation", null, false, null, null, null, null, null), - new FieldSpec("range", "ref-discriminator", false, "Repeat-0005", null, "Repeat-0000", null, null, null, null, "RangeInline", false, null, null, null, null, null) + new FieldSpec("range", "ref-discriminator", true, "Scatter-0005", "Scatter-0004", "Scatter-0000", null, null, null, null, "RangeInline", false, null, null, null, null, null) ); - private static final Set REQUIRED_NAMES = Set.of(); + private static final Set REQUIRED_NAMES = Set.of("range"); private final IdKeyedCollection subTasks = new IdKeyedCollection<>(); private final IdKeyedCollection aggregateOutputVariables = new IdKeyedCollection<>(); private final ListCollection taskParameters = new ListCollection<>(); @@ -43,7 +43,7 @@ public final class Scatter extends SedBase { @Override public String descRuleId() { return "SEDBase-0002"; } @Override public String baseCatchall() { return "SEDBase-0000"; } public String getType() { return "scatter"; } - private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"valid\": true, \"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"static\", \"expr\": \"len(range)\"}, \"labels\": null, \"note\": \"one row per value in range; len(range) dispatches on range's actual Range/NumericRange/ParameterRange type\"}, {\"size\": {\"source\": \"static\", \"expr\": \"len(outputVariableMap)\"}, \"labels\": null, \"note\": \"one column per entry of outputVariableMap, or just the range-values column alone if outputVariableMap is empty; a column whose subTask output is itself multi-dimensional would add further dimensions beyond this, not captured here\"}]}, \"[id].model\": {\"valid\": false}, \"[id].strings\": {\"valid\": false}, \"[id].aggregates\": {\"valid\": \"provided(aggregateOutputVariables)\", \"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"static\", \"expr\": \"len(aggregateOutputVariables)\"}, \"labels\": null, \"note\": \"each entry collapses the range dimension of [id] to a single value (per Repeat, the applied dimension defaults to this Scatter's own range), unless the underlying subTask output was itself multi-dimensional, in which case that dimensionality carries through per entry\"}]}, \"[id].range\": {\"valid\": \"provided(range)\", \"type\": \"annotatedData\", \"dimensions\": [], \"note\": \"the current value of range, within each iteration\"}, \"[id].index\": {\"valid\": \"provided(range)\", \"type\": \"annotatedData\", \"dimensions\": [], \"note\": \"the current index into range, within each iteration\"}}}"); + private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"static\", \"expr\": \"len(range)\"}, \"labels\": null, \"note\": \"one row per value in range; len(range) dispatches on range's actual Range/NumericRange/ParameterRange type\"}, {\"size\": {\"source\": \"static\", \"expr\": \"len(outputVariableMap)\"}, \"labels\": null, \"note\": \"one column per entry of outputVariableMap, or just the range-values column alone if outputVariableMap is empty; a column whose subTask output is itself multi-dimensional would add further dimensions beyond this, not captured here\"}]}, \"[id].aggregates\": {\"valid\": \"provided(aggregateOutputVariables)\", \"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"static\", \"expr\": \"len(aggregateOutputVariables)\"}, \"labels\": null, \"note\": \"each entry collapses the range dimension of [id] to a single value (per Repeat, the applied dimension defaults to this Scatter's own range), unless the underlying subTask output was itself multi-dimensional, in which case that dimensionality carries through per entry\"}]}, \"[id].range\": {\"type\": \"annotatedData\", \"dimensions\": [], \"note\": \"the current value of range, within each iteration\"}, \"[id].index\": {\"type\": \"annotatedData\", \"dimensions\": [], \"note\": \"the current index into range, within each iteration\"}}}"); @Override public JsonNode outputsJson() { return OUTPUTS_JSON; } public JsonNode getOutputVariableMapValue() { return getOrRefValueNode("outputVariableMap"); } diff --git a/generated/java/src/main/java/org/sedml/libsed2/Span.java b/generated/java/src/main/java/org/sedml/libsed2/Span.java index f9f6f5b..5fe98bc 100644 --- a/generated/java/src/main/java/org/sedml/libsed2/Span.java +++ b/generated/java/src/main/java/org/sedml/libsed2/Span.java @@ -36,7 +36,7 @@ public final class Span extends SedBase { @Override public String descRuleId() { return "SEDBase-0002"; } @Override public String baseCatchall() { return "SEDBase-0000"; } public String getType() { return "span"; } - private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"valid\": false}, \"[id].model\": {\"valid\": false}, \"[id].strings\": {\"valid\": false}}}"); + private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {}}"); @Override public JsonNode outputsJson() { return OUTPUTS_JSON; } public double getStartValue() { return getOrRefValueNode("start").asDouble(); } diff --git a/generated/java/src/main/java/org/sedml/libsed2/SteadyState.java b/generated/java/src/main/java/org/sedml/libsed2/SteadyState.java index 7f2e14d..1c6b44e 100644 --- a/generated/java/src/main/java/org/sedml/libsed2/SteadyState.java +++ b/generated/java/src/main/java/org/sedml/libsed2/SteadyState.java @@ -22,12 +22,13 @@ public final class SteadyState extends SedBase { new FieldSpec("model", "SIdRef", true, null, "SteadyState-0001", "SteadyState-0000", null, null, null, null, null, false, null, null, null, null, "model"), new FieldSpec("independentVariable", "StringOrRef", false, "SteadyState-0004", null, "SteadyState-0000", null, null, null, null, null, false, null, null, null, null, null), new FieldSpec("outputVariables", "ArrayOrRef", true, null, "SteadyState-0002", "SteadyState-0000", null, null, null, null, null, false, null, null, null, "string", null), - new FieldSpec("outputModel", "BooleanOrRef", false, "SteadyState-0005", null, "SteadyState-0000", null, null, null, null, null, false, null, null, "SteadyState-0006", null, null), new FieldSpec("notes", "any", false, "SEDBase-0003", null, "SEDBase-0000", null, null, null, null, null, false, null, null, null, null, null), + new FieldSpec("workingAlgorithms", "array", false, "SteadyState-0007", null, "SteadyState-0000", null, null, null, "WorkingAlgorithm", null, false, null, null, null, null, null), new FieldSpec("taskParameters", "array", false, "AbstractTask-0001", null, "AbstractTask-0000", null, null, null, "TaskParameter", null, false, null, null, null, null, null), new FieldSpec("annotations", "array", false, "SEDBase-0004", null, "SEDBase-0000", null, null, null, "Annotation", null, false, null, null, null, null, null) ); private static final Set REQUIRED_NAMES = Set.of("model", "outputVariables"); + private final ListCollection workingAlgorithms = new ListCollection<>(); private final ListCollection taskParameters = new ListCollection<>(); private final ListCollection annotations = new ListCollection<>(); @@ -40,7 +41,7 @@ public final class SteadyState extends SedBase { @Override public String descRuleId() { return "SEDBase-0002"; } @Override public String baseCatchall() { return "SEDBase-0000"; } public String getType() { return "steadyState"; } - private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"valid\": true, \"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"static\", \"expr\": \"len(outputVariables)\"}, \"labels\": {\"source\": \"static\", \"expr\": \"outputVariables\"}}]}, \"[id].model\": {\"valid\": \"outputModel == true\", \"type\": \"model\"}, \"[id].strings\": {\"valid\": false}}}"); + private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"type\": \"annotatedData\", \"dimensions\": [{\"size\": {\"source\": \"static\", \"expr\": \"len(outputVariables)\"}, \"labels\": {\"source\": \"static\", \"expr\": \"outputVariables\"}}]}, \"[id].model\": {\"type\": \"model\"}}}"); @Override public JsonNode outputsJson() { return OUTPUTS_JSON; } public String getModel() { if (!values.containsKey("model")) throw new ApiError("model" + " is not set"); return values.get("model").asText(); } @@ -64,19 +65,16 @@ public final class SteadyState extends SedBase { public boolean isSetOutputVariables() { return values.containsKey("outputVariables"); } public void unsetOutputVariables() { values.remove("outputVariables"); orRefIsRef.remove("outputVariables"); } - public boolean getOutputModelValue() { return getOrRefValueNode("outputModel").asBoolean(); } - public String getOutputModelRef() { return getOrRefRefNode("outputModel").asText(); } - public void setOutputModelValue(boolean value) { setOrRefValueNode("outputModel", BooleanNode.valueOf(value)); } - public void setOutputModelRef(String ref) { setOrRefRefNode("outputModel", ref); } - public boolean isOutputModelRef() { return isOrRefRef("outputModel"); } - public boolean isSetOutputModel() { return values.containsKey("outputModel"); } - public void unsetOutputModel() { values.remove("outputModel"); orRefIsRef.remove("outputModel"); } - public JsonNode getNotes() { if (!values.containsKey("notes")) throw new ApiError("notes" + " is not set"); return values.get("notes"); } public void setNotes(JsonNode value) { values.put("notes", value); } public boolean isSetNotes() { return values.containsKey("notes"); } public void unsetNotes() { values.remove("notes"); } + public List getWorkingAlgorithms() { return workingAlgorithms.items(); } + public void addWorkingAlgorithms(SedBase obj) { workingAlgorithms.add(obj); obj.attach(this, getDocument()); } + public void insertWorkingAlgorithms(int index, SedBase obj) { workingAlgorithms.insert(index, obj); obj.attach(this, getDocument()); } + public void removeWorkingAlgorithms(int index) { workingAlgorithms.remove(index); } + public List getTaskParameters() { return taskParameters.items(); } public void addTaskParameters(SedBase obj) { taskParameters.add(obj); obj.attach(this, getDocument()); } public void insertTaskParameters(int index, SedBase obj) { taskParameters.insert(index, obj); obj.attach(this, getDocument()); } @@ -90,6 +88,7 @@ public final class SteadyState extends SedBase { @Override public List children() { List kids = new ArrayList<>(); + kids.addAll(workingAlgorithms.items()); kids.addAll(taskParameters.items()); kids.addAll(annotations.items()); return kids; @@ -98,6 +97,7 @@ public List children() { @Override public List childrenWithLocations() { List out = new ArrayList<>(); + { int idx = 0; for (SedBase item : workingAlgorithms.items()) { out.add(new ChildLoc(item, "/workingAlgorithms/" + idx)); idx++; } } { int idx = 0; for (SedBase item : taskParameters.items()) { out.add(new ChildLoc(item, "/taskParameters/" + idx)); idx++; } } { int idx = 0; for (SedBase item : annotations.items()) { out.add(new ChildLoc(item, "/annotations/" + idx)); idx++; } } return out; @@ -106,6 +106,7 @@ public List childrenWithLocations() { @Override protected ListCollection getListCollection(String fieldName) { switch (fieldName) { + case "workingAlgorithms": return workingAlgorithms; case "taskParameters": return taskParameters; case "annotations": return annotations; default: return super.getListCollection(fieldName); @@ -121,8 +122,8 @@ public ObjectNode ownJsonValue() { if (values.containsKey("model")) d.set("model", values.get("model")); if (values.containsKey("independentVariable")) d.set("independentVariable", values.get("independentVariable")); if (values.containsKey("outputVariables")) d.set("outputVariables", values.get("outputVariables")); - if (values.containsKey("outputModel")) d.set("outputModel", values.get("outputModel")); if (values.containsKey("notes")) d.set("notes", values.get("notes")); + if (workingAlgorithms.size() > 0) { ArrayNode arr = d.putArray("workingAlgorithms"); for (SedBase item : workingAlgorithms.items()) arr.add(item.toJsonValue()); } if (taskParameters.size() > 0) { ArrayNode arr = d.putArray("taskParameters"); for (SedBase item : taskParameters.items()) arr.add(item.toJsonValue()); } if (annotations.size() > 0) { ArrayNode arr = d.putArray("annotations"); for (SedBase item : annotations.items()) arr.add(item.toJsonValue()); } for (Map.Entry e : nsAttrs.entrySet()) d.set(e.getKey(), e.getValue()); diff --git a/generated/java/src/main/java/org/sedml/libsed2/StringFormation.java b/generated/java/src/main/java/org/sedml/libsed2/StringFormation.java index 0fd34bb..bc92984 100644 --- a/generated/java/src/main/java/org/sedml/libsed2/StringFormation.java +++ b/generated/java/src/main/java/org/sedml/libsed2/StringFormation.java @@ -37,7 +37,7 @@ public final class StringFormation extends SedBase { @Override public String descRuleId() { return "SEDBase-0002"; } @Override public String baseCatchall() { return "SEDBase-0000"; } public String getType() { return "stringFormation"; } - private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"valid\": true, \"type\": \"annotatedData\", \"dimensions\": {\"source\": \"runtime\", \"note\": \"scalar when no element of concatenate is itself a list; otherwise N-D matching the shape of the list element(s) within concatenate (1D for one list element, higher-D when several list elements are combined pairwise, all sharing the same length/shape per dimension) - not derivable without evaluating concatenate's actual element values\"}}, \"[id].model\": {\"valid\": false}, \"[id].strings\": {\"valid\": true, \"type\": \"stringList\", \"dimensions\": {\"source\": \"runtime\", \"note\": \"same as [id]'s dimensions above; not derivable without evaluating concatenate\"}}}}"); + private static final JsonNode OUTPUTS_JSON = OutputsShape.parseJson("{\"outputs\": {\"[id]\": {\"type\": \"annotatedData\", \"dimensions\": {\"source\": \"runtime\", \"note\": \"scalar when no element of concatenate is itself a list; otherwise N-D matching the shape of the list element(s) within concatenate (1D for one list element, higher-D when several list elements are combined pairwise, all sharing the same length/shape per dimension) - not derivable without evaluating concatenate's actual element values\"}}, \"[id].strings\": {\"type\": \"stringList\", \"dimensions\": {\"source\": \"runtime\", \"note\": \"same as [id]'s dimensions above; not derivable without evaluating concatenate\"}}}}"); @Override public JsonNode outputsJson() { return OUTPUTS_JSON; } public JsonNode getConcatenateValue() { return getOrRefValueNode("concatenate"); } diff --git a/generated/python/src/libsed2/model.py b/generated/python/src/libsed2/model.py index e846338..c5196b6 100644 --- a/generated/python/src/libsed2/model.py +++ b/generated/python/src/libsed2/model.py @@ -353,7 +353,7 @@ class AggregationCalculation(SedBase): _NAME_RULE_ID = 'SEDBase-0001' _DESC_RULE_ID = 'SEDBase-0002' _BASE_CATCHALL = 'SEDBase-0000' - _OUTPUTS_JSON = {'outputs': {'[id]': {'valid': True, 'type': 'annotatedData', 'dimensions': {'source': 'static', 'expr': 'shapeOf(input) - dim(appliedDimensions or outermost)', 'note': "shape is input's shape with the dimension(s) named in appliedDimensions removed (or the outermost dimension, if appliedDimensions is unset); dimension count/sizes are therefore only as knowable as input's own shape is"}}, '[id].model': {'valid': False}, '[id].strings': {'valid': False}}} + _OUTPUTS_JSON = {'outputs': {'[id]': {'type': 'annotatedData', 'dimensions': {'source': 'static', 'expr': 'shapeOf(input) - dim(appliedDimensions or outermost)', 'note': "shape is input's shape with the dimension(s) named in appliedDimensions removed (or the outermost dimension, if appliedDimensions is unset); dimension count/sizes are therefore only as knowable as input's own shape is"}}}} _NAMESPACE_FIELDS = {} _NAMESPACE_CATCHALL = {} @@ -484,7 +484,7 @@ class BoundedODESimulation(SedBase): _NAME_RULE_ID = 'SEDBase-0001' _DESC_RULE_ID = 'SEDBase-0002' _BASE_CATCHALL = 'SEDBase-0000' - _OUTPUTS_JSON = {'outputs': {'[id]': {'valid': True, 'type': 'annotatedData', 'dimensions': [{'size': {'source': 'runtime', 'note': 'row count is chosen by the solver/simulator at run time under variable step size, not fixed by independentVariableSpan (only its start/end bound the range)'}, 'labels': None}, {'size': {'source': 'static', 'expr': '1 + len(outputVariables)'}, 'labels': {'source': 'static', 'expr': '[independentVariable] + outputVariables'}}]}, '[id].model': {'valid': True, 'type': 'model'}, '[id].strings': {'valid': False}}} + _OUTPUTS_JSON = {'outputs': {'[id]': {'type': 'annotatedData', 'dimensions': [{'size': {'source': 'runtime', 'note': 'row count is chosen by the solver/simulator at run time under variable step size, not fixed by independentVariableSpan (only its start/end bound the range)'}, 'labels': None}, {'size': {'source': 'static', 'expr': '1 + len(outputVariables)'}, 'labels': {'source': 'static', 'expr': '[independentVariable] + outputVariables'}}]}, '[id].model': {'type': 'model'}}} _NAMESPACE_FIELDS = {} _NAMESPACE_CATCHALL = {} @@ -1089,7 +1089,7 @@ class BoundedStochasticSimulation(SedBase): _NAME_RULE_ID = 'SEDBase-0001' _DESC_RULE_ID = 'SEDBase-0002' _BASE_CATCHALL = 'SEDBase-0000' - _OUTPUTS_JSON = {'outputs': {'[id]': {'valid': True, 'type': 'annotatedData', 'dimensions': [{'size': {'source': 'runtime', 'note': 'row count is chosen by the solver/simulator at run time under variable step size, not fixed by independentVariableSpan (only its start/end bound the range)'}, 'labels': None}, {'size': {'source': 'static', 'expr': '1 + len(outputVariables)'}, 'labels': {'source': 'static', 'expr': '[independentVariable] + outputVariables'}}]}, '[id].model': {'valid': True, 'type': 'model'}, '[id].strings': {'valid': False}}} + _OUTPUTS_JSON = {'outputs': {'[id]': {'type': 'annotatedData', 'dimensions': [{'size': {'source': 'runtime', 'note': 'row count is chosen by the solver/simulator at run time under variable step size, not fixed by independentVariableSpan (only its start/end bound the range)'}, 'labels': None}, {'size': {'source': 'static', 'expr': '1 + len(outputVariables)'}, 'labels': {'source': 'static', 'expr': '[independentVariable] + outputVariables'}}]}, '[id].model': {'type': 'model'}}} _NAMESPACE_FIELDS = {} _NAMESPACE_CATCHALL = {} @@ -1474,7 +1474,7 @@ class Calculation(SedBase): _NAME_RULE_ID = 'SEDBase-0001' _DESC_RULE_ID = 'SEDBase-0002' _BASE_CATCHALL = 'SEDBase-0000' - _OUTPUTS_JSON = {'outputs': {'[id]': {'valid': True, 'type': 'annotatedData', 'dimensions': {'source': 'runtime', 'note': "shape matches the evaluated math expression: scalar if every operand is scalar, otherwise broadcasts across the shape of any AnnotatedData operand(s); not derivable without evaluating math against the operands' actual values"}}, '[id].model': {'valid': False}}} + _OUTPUTS_JSON = {'outputs': {'[id]': {'type': 'annotatedData', 'dimensions': {'source': 'runtime', 'note': "shape matches the evaluated math expression: scalar if every operand is scalar, otherwise broadcasts across the shape of any AnnotatedData operand(s); not derivable without evaluating math against the operands' actual values"}}}} _NAMESPACE_FIELDS = {} _NAMESPACE_CATCHALL = {} @@ -1591,7 +1591,7 @@ class CreateDataBlock(SedBase): _NAME_RULE_ID = 'SEDBase-0001' _DESC_RULE_ID = 'SEDBase-0002' _BASE_CATCHALL = 'SEDBase-0000' - _OUTPUTS_JSON = {'outputs': {'[id]': {'valid': True, 'type': 'annotatedData', 'dimensions': [{'size': {'source': 'static', 'expr': 'len(data)'}, 'labels': {'source': 'static', 'expr': 'keys(data)'}, 'note': "base case: one entry per key in the data dictionary. If a value in data is itself multi-dimensional (a list or AnnotatedData), that entry's own dimensions carry through instead - how mixed-dimension entries combine into one overall shape is an open design question (see core-spec.md Section 10), so this formula covers only the uniform-scalar-values case"}]}, '[id].model': {'valid': False}}} + _OUTPUTS_JSON = {'outputs': {'[id]': {'type': 'annotatedData', 'dimensions': [{'size': {'source': 'static', 'expr': 'len(data)'}, 'labels': {'source': 'static', 'expr': 'keys(data)'}, 'note': "base case: one entry per key in the data dictionary. If a value in data is itself multi-dimensional (a list or AnnotatedData), that entry's own dimensions carry through instead - how mixed-dimension entries combine into one overall shape is an open design question (see core-spec.md Section 10), so this formula covers only the uniform-scalar-values case"}]}}} _NAMESPACE_FIELDS = {} _NAMESPACE_CATCHALL = {} @@ -1708,7 +1708,7 @@ class CsvImport(SedBase): _NAME_RULE_ID = 'SEDBase-0001' _DESC_RULE_ID = 'SEDBase-0002' _BASE_CATCHALL = 'SEDBase-0000' - _OUTPUTS_JSON = {'outputs': {'[id]': {'valid': True, 'type': 'annotatedData', 'dimensions': [{'size': {'source': 'input-file', 'from': 'location', 'extract': 'rowCount', 'note': 'row count, read from the CSV file at location'}, 'labels': None}, {'size': {'source': 'input-file', 'from': 'location', 'extract': 'columnCount', 'note': 'column count, read from the CSV file at location together with organization/headers/ncols'}, 'labels': {'source': 'input-file', 'from': 'location', 'extract': 'columnHeaders', 'note': 'column labels, read from the CSV header row when headers is true, else from columnNames'}}]}, '[id].model': {'valid': False}, '[id].strings': {'valid': False}}} + _OUTPUTS_JSON = {'outputs': {'[id]': {'type': 'annotatedData', 'dimensions': [{'size': {'source': 'input-file', 'from': 'location', 'extract': 'rowCount', 'note': 'row count, read from the CSV file at location'}, 'labels': None}, {'size': {'source': 'input-file', 'from': 'location', 'extract': 'columnCount', 'note': 'column count, read from the CSV file at location together with organization/headers/ncols'}, 'labels': {'source': 'input-file', 'from': 'location', 'extract': 'columnHeaders', 'note': 'column labels, read from the CSV header row when headers is true, else from columnNames'}}]}}} _NAMESPACE_FIELDS = {} _NAMESPACE_CATCHALL = {} @@ -1979,7 +1979,7 @@ class DataImport(SedBase): _NAME_RULE_ID = 'SEDBase-0001' _DESC_RULE_ID = 'SEDBase-0002' _BASE_CATCHALL = 'SEDBase-0000' - _OUTPUTS_JSON = {'outputs': {'[id]': {'valid': True, 'type': 'annotatedData', 'dimensions': {'source': 'input-file', 'from': 'location', 'extract': 'shape', 'note': 'shape is whatever the imported file itself has; depends on format and the file at location - extraction is format-specific (format names how to parse it)'}}, '[id].model': {'valid': False}}} + _OUTPUTS_JSON = {'outputs': {'[id]': {'type': 'annotatedData', 'dimensions': {'source': 'input-file', 'from': 'location', 'extract': 'shape', 'note': 'shape is whatever the imported file itself has; depends on format and the file at location - extraction is format-specific (format names how to parse it)'}}}} _NAMESPACE_FIELDS = {} _NAMESPACE_CATCHALL = {} @@ -2118,7 +2118,7 @@ class DrawFromDistribution(SedBase): _NAME_RULE_ID = 'SEDBase-0001' _DESC_RULE_ID = 'SEDBase-0002' _BASE_CATCHALL = 'SEDBase-0000' - _OUTPUTS_JSON = {'outputs': {'[id]': {'valid': True, 'type': 'annotatedData', 'dimensions': [], 'note': 'currently always a single scalar value (0-D), indexed historically as [id][0]; the type is multidimensional AnnotatedData to leave room for future correlated multi-value draws (shape of that future case is not yet designed - see core-spec.md Section 10)'}, '[id].model': {'valid': False}, '[id].strings': {'valid': False}}} + _OUTPUTS_JSON = {'outputs': {'[id]': {'type': 'annotatedData', 'dimensions': [], 'note': 'currently always a single scalar value (0-D), indexed historically as [id][0]; the type is multidimensional AnnotatedData to leave room for future correlated multi-value draws (shape of that future case is not yet designed - see core-spec.md Section 10)'}}} _NAMESPACE_FIELDS = {} _NAMESPACE_CATCHALL = {} @@ -2279,7 +2279,7 @@ class ExplicitODESimulation(SedBase): _NAME_RULE_ID = 'SEDBase-0001' _DESC_RULE_ID = 'SEDBase-0002' _BASE_CATCHALL = 'SEDBase-0000' - _OUTPUTS_JSON = {'outputs': {'[id]': {'valid': True, 'type': 'annotatedData', 'dimensions': [{'size': {'source': 'static', 'expr': 'len(independentVariableRange)'}, 'labels': None}, {'size': {'source': 'static', 'expr': '1 + len(outputVariables)'}, 'labels': {'source': 'static', 'expr': '[independentVariable] + outputVariables'}}]}, '[id].model': {'valid': True, 'type': 'model'}, '[id].strings': {'valid': False}}} + _OUTPUTS_JSON = {'outputs': {'[id]': {'type': 'annotatedData', 'dimensions': [{'size': {'source': 'static', 'expr': 'len(independentVariableRange)'}, 'labels': None}, {'size': {'source': 'static', 'expr': '1 + len(outputVariables)'}, 'labels': {'source': 'static', 'expr': '[independentVariable] + outputVariables'}}]}, '[id].model': {'type': 'model'}}} _NAMESPACE_FIELDS = {} _NAMESPACE_CATCHALL = {} @@ -2884,7 +2884,7 @@ class ExplicitStochasticSimulation(SedBase): _NAME_RULE_ID = 'SEDBase-0001' _DESC_RULE_ID = 'SEDBase-0002' _BASE_CATCHALL = 'SEDBase-0000' - _OUTPUTS_JSON = {'outputs': {'[id]': {'valid': True, 'type': 'annotatedData', 'dimensions': [{'size': {'source': 'static', 'expr': 'independentVariableRange.numberOfSteps'}, 'labels': None}, {'size': {'source': 'static', 'expr': '1 + len(outputVariables)'}, 'labels': {'source': 'static', 'expr': '[independentVariable] + outputVariables'}}]}, '[id].model': {'valid': True, 'type': 'model'}, '[id].strings': {'valid': False}}} + _OUTPUTS_JSON = {'outputs': {'[id]': {'type': 'annotatedData', 'dimensions': [{'size': {'source': 'static', 'expr': 'independentVariableRange.numberOfSteps'}, 'labels': None}, {'size': {'source': 'static', 'expr': '1 + len(outputVariables)'}, 'labels': {'source': 'static', 'expr': '[independentVariable] + outputVariables'}}]}, '[id].model': {'type': 'model'}}} _NAMESPACE_FIELDS = {} _NAMESPACE_CATCHALL = {} @@ -3261,7 +3261,7 @@ def to_json_value(self): class FluxBalanceAnalysis(SedBase): """Generated from test-specsheets/tasks/FluxBalanceAnalysis/.""" - _FIELDS = [FieldSpec('model', 'SIdRef', True, 'FluxBalanceAnalysis-0002', 'FluxBalanceAnalysis-0001', 'FluxBalanceAnalysis-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target='model'), FieldSpec('outputVariables', 'ArrayOrRef', True, 'FluxBalanceAnalysis-0004', 'FluxBalanceAnalysis-0003', 'FluxBalanceAnalysis-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id='FluxBalanceAnalysis-0005', item_kind='string', ref_target=None), FieldSpec('outputModel', 'BooleanOrRef', False, 'FluxBalanceAnalysis-0006', None, 'FluxBalanceAnalysis-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id='FluxBalanceAnalysis-0007', item_kind=None, ref_target=None), FieldSpec('notes', 'any', False, 'SEDBase-0003', None, 'SEDBase-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('taskParameters', 'array', False, 'AbstractTask-0001', None, 'AbstractTask-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class='TaskParameter', item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('annotations', 'array', False, 'SEDBase-0004', None, 'SEDBase-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class='Annotation', item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None)] + _FIELDS = [FieldSpec('model', 'SIdRef', True, 'FluxBalanceAnalysis-0002', 'FluxBalanceAnalysis-0001', 'FluxBalanceAnalysis-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target='model'), FieldSpec('outputVariables', 'ArrayOrRef', True, 'FluxBalanceAnalysis-0004', 'FluxBalanceAnalysis-0003', 'FluxBalanceAnalysis-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id='FluxBalanceAnalysis-0005', item_kind='string', ref_target=None), FieldSpec('notes', 'any', False, 'SEDBase-0003', None, 'SEDBase-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('workingAlgorithms', 'array', False, 'FluxBalanceAnalysis-0009', None, 'FluxBalanceAnalysis-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class='WorkingAlgorithm', item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('taskParameters', 'array', False, 'AbstractTask-0001', None, 'AbstractTask-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class='TaskParameter', item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('annotations', 'array', False, 'SEDBase-0004', None, 'SEDBase-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class='Annotation', item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None)] _REQUIRED_NAMES = {'model', 'outputVariables'} _TYPE_CONST = 'fluxBalanceAnalysis' _TYPE_RULE_ID = 'FluxBalanceAnalysis-0008' @@ -3269,12 +3269,13 @@ class FluxBalanceAnalysis(SedBase): _NAME_RULE_ID = 'SEDBase-0001' _DESC_RULE_ID = 'SEDBase-0002' _BASE_CATCHALL = 'SEDBase-0000' - _OUTPUTS_JSON = {'outputs': {'[id]': {'valid': True, 'type': 'annotatedData', 'dimensions': [{'size': {'source': 'static', 'expr': 'len(outputVariables)'}, 'labels': {'source': 'static', 'expr': 'outputVariables'}}]}, '[id].model': {'valid': 'outputModel == true', 'type': 'model'}, '[id].strings': {'valid': False}}} + _OUTPUTS_JSON = {'outputs': {'[id]': {'type': 'annotatedData', 'dimensions': [{'size': {'source': 'static', 'expr': 'len(outputVariables)'}, 'labels': {'source': 'static', 'expr': 'outputVariables'}}]}, '[id].model': {'type': 'model'}}} _NAMESPACE_FIELDS = {} _NAMESPACE_CATCHALL = {} def __init__(self): super().__init__() + self._working_algorithms = ListCollection() self._task_parameters = ListCollection() self._annotations = ListCollection() @@ -3315,27 +3316,6 @@ def is_set_output_variables(self): def unset_output_variables(self): self._values.pop('outputVariables', None); self._orref_is_ref.pop('outputVariables', None) - def get_output_model_value(self): - return self._get_orref_value('outputModel') - - def get_output_model_ref(self): - return self._get_orref_ref('outputModel') - - def set_output_model_value(self, value): - self._set_orref_value('outputModel', value) - - def set_output_model_ref(self, ref): - self._set_orref_ref('outputModel', ref) - - def is_output_model_ref(self): - return self._is_orref_ref('outputModel') - - def is_set_output_model(self): - return 'outputModel' in self._values - - def unset_output_model(self): - self._values.pop('outputModel', None); self._orref_is_ref.pop('outputModel', None) - def get_notes(self): if 'notes' not in self._values: raise ApiError('notes is not set') return self._values['notes'] @@ -3349,6 +3329,18 @@ def is_set_notes(self): def unset_notes(self): self._values.pop('notes', None) + def get_working_algorithms(self): + return self._working_algorithms.items() + + def add_working_algorithms(self, obj): + self._working_algorithms.add(obj); obj._attach(self, self.get_document()) + + def insert_working_algorithms(self, index, obj): + self._working_algorithms.insert(index, obj); obj._attach(self, self.get_document()) + + def remove_working_algorithms(self, index): + self._working_algorithms.remove(index) + def get_task_parameters(self): return self._task_parameters.items() @@ -3375,6 +3367,7 @@ def remove_annotations(self, index): def _children(self): kids = [] + kids.extend(self._working_algorithms.items()) kids.extend(self._task_parameters.items()) kids.extend(self._annotations.items()) return kids @@ -3384,6 +3377,8 @@ def _get_id_collection(self, field_name): def _children_with_locations(self): out = [] + for idx, item in enumerate(self._working_algorithms.items()): + out.append((item, '/workingAlgorithms/%d' % idx)) for idx, item in enumerate(self._task_parameters.items()): out.append((item, '/taskParameters/%d' % idx)) for idx, item in enumerate(self._annotations.items()): @@ -3400,8 +3395,8 @@ def _own_json_value(self): d['_type'] = self._values.get('_type', 'fluxBalanceAnalysis') if 'model' in self._values: d['model'] = self._values['model'] if 'outputVariables' in self._values: d['outputVariables'] = self._values['outputVariables'] - if 'outputModel' in self._values: d['outputModel'] = self._values['outputModel'] if 'notes' in self._values: d['notes'] = self._values['notes'] + if len(self._working_algorithms): d['workingAlgorithms'] = [it.to_json_value() for it in self._working_algorithms.items()] if len(self._task_parameters): d['taskParameters'] = [it.to_json_value() for it in self._task_parameters.items()] if len(self._annotations): d['annotations'] = [it.to_json_value() for it in self._annotations.items()] for (pfx, key), value in self._ns_attrs.items(): @@ -3422,7 +3417,7 @@ class JacobianFull(SedBase): _NAME_RULE_ID = 'SEDBase-0001' _DESC_RULE_ID = 'SEDBase-0002' _BASE_CATCHALL = 'SEDBase-0000' - _OUTPUTS_JSON = {'outputs': {'[id]': {'valid': True, 'type': 'annotatedData', 'dimensions': [{'size': {'source': 'input-file', 'from': 'model', 'extract': 'floatingSpeciesIds', 'note': 'row count = number of species in the referenced model'}, 'labels': {'source': 'input-file', 'from': 'model', 'extract': 'floatingSpeciesIds', 'note': "row labels = the model's ordered species list"}}, {'size': {'source': 'input-file', 'from': 'model', 'extract': 'floatingSpeciesIds', 'note': 'column count = number of species in the referenced model'}, 'labels': {'source': 'input-file', 'from': 'model', 'extract': 'floatingSpeciesIds', 'note': "column labels = the model's ordered species list"}}]}, '[id].model': {'valid': False}, '[id].strings': {'valid': False}}} + _OUTPUTS_JSON = {'outputs': {'[id]': {'type': 'annotatedData', 'dimensions': [{'size': {'source': 'input-file', 'from': 'model', 'extract': 'floatingSpeciesIds', 'note': 'row count = number of species in the referenced model'}, 'labels': {'source': 'input-file', 'from': 'model', 'extract': 'floatingSpeciesIds', 'note': "row labels = the model's ordered species list"}}, {'size': {'source': 'input-file', 'from': 'model', 'extract': 'floatingSpeciesIds', 'note': 'column count = number of species in the referenced model'}, 'labels': {'source': 'input-file', 'from': 'model', 'extract': 'floatingSpeciesIds', 'note': "column labels = the model's ordered species list"}}]}}} _NAMESPACE_FIELDS = {} _NAMESPACE_CATCHALL = {} @@ -3531,7 +3526,7 @@ class JacobianReduced(SedBase): _NAME_RULE_ID = 'SEDBase-0001' _DESC_RULE_ID = 'SEDBase-0002' _BASE_CATCHALL = 'SEDBase-0000' - _OUTPUTS_JSON = {'outputs': {'[id]': {'valid': True, 'type': 'annotatedData', 'dimensions': [{'size': {'source': 'input-file', 'from': 'model', 'extract': 'reducedFloatingSpeciesIds', 'note': "row count = number of species in the referenced model's reduced species set"}, 'labels': {'source': 'input-file', 'from': 'model', 'extract': 'reducedFloatingSpeciesIds', 'note': "row labels = the model's ordered, reduced species list"}}, {'size': {'source': 'input-file', 'from': 'model', 'extract': 'reducedFloatingSpeciesIds', 'note': "column count = number of species in the referenced model's reduced species set"}, 'labels': {'source': 'input-file', 'from': 'model', 'extract': 'reducedFloatingSpeciesIds', 'note': "column labels = the model's ordered, reduced species list"}}]}, '[id].model': {'valid': False}, '[id].strings': {'valid': False}}} + _OUTPUTS_JSON = {'outputs': {'[id]': {'type': 'annotatedData', 'dimensions': [{'size': {'source': 'input-file', 'from': 'model', 'extract': 'reducedFloatingSpeciesIds', 'note': "row count = number of species in the referenced model's reduced species set"}, 'labels': {'source': 'input-file', 'from': 'model', 'extract': 'reducedFloatingSpeciesIds', 'note': "row labels = the model's ordered, reduced species list"}}, {'size': {'source': 'input-file', 'from': 'model', 'extract': 'reducedFloatingSpeciesIds', 'note': "column count = number of species in the referenced model's reduced species set"}, 'labels': {'source': 'input-file', 'from': 'model', 'extract': 'reducedFloatingSpeciesIds', 'note': "column labels = the model's ordered, reduced species list"}}]}}} _NAMESPACE_FIELDS = {} _NAMESPACE_CATCHALL = {} @@ -3632,15 +3627,15 @@ def to_json_value(self): class Loop(SedBase): """Generated from test-specsheets/tasks/Loop/.""" - _FIELDS = [FieldSpec('outputVariableMap', 'DictOrRef', False, 'Repeat-0002', None, 'Repeat-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id='Repeat-0003', item_kind='ref', ref_target=None), FieldSpec('notes', 'any', False, 'SEDBase-0003', None, 'SEDBase-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('loopVariables', 'dict', True, 'Loop-0003', 'Loop-0002', 'Loop-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class='LoopVariable', item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('subTasks', 'dict', False, 'Repeat-0001', None, 'Repeat-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator='AbstractTask', is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('aggregateOutputVariables', 'dict', False, 'Repeat-0004', None, 'Repeat-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class='AggregationCalculation', item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('taskParameters', 'array', False, 'AbstractTask-0001', None, 'AbstractTask-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class='TaskParameter', item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('annotations', 'array', False, 'SEDBase-0004', None, 'SEDBase-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class='Annotation', item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('range', 'ref-discriminator', False, 'Repeat-0005', None, 'Repeat-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator='RangeInline', is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None)] - _REQUIRED_NAMES = {'loopVariables'} + _FIELDS = [FieldSpec('outputVariableMap', 'DictOrRef', False, 'Repeat-0002', None, 'Repeat-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id='Repeat-0003', item_kind='ref', ref_target=None), FieldSpec('notes', 'any', False, 'SEDBase-0003', None, 'SEDBase-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('loopVariables', 'dict', True, 'Loop-0003', 'Loop-0002', 'Loop-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class='LoopVariable', item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('subTasks', 'dict', False, 'Repeat-0001', None, 'Repeat-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator='AbstractTask', is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('aggregateOutputVariables', 'dict', False, 'Repeat-0004', None, 'Repeat-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class='AggregationCalculation', item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('taskParameters', 'array', False, 'AbstractTask-0001', None, 'AbstractTask-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class='TaskParameter', item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('annotations', 'array', False, 'SEDBase-0004', None, 'SEDBase-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class='Annotation', item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('range', 'ref-discriminator', True, 'Loop-0007', 'Loop-0006', 'Loop-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator='RangeInline', is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None)] + _REQUIRED_NAMES = {'loopVariables', 'range'} _TYPE_CONST = 'loop' _TYPE_RULE_ID = 'Loop-0005' _OWN_CATCHALL = 'Loop-0000' _NAME_RULE_ID = 'SEDBase-0001' _DESC_RULE_ID = 'SEDBase-0002' _BASE_CATCHALL = 'SEDBase-0000' - _OUTPUTS_JSON = {'outputs': {'[id]': {'valid': True, 'type': 'annotatedData', 'dimensions': {'source': 'runtime', 'note': "2D or more: first dimension = one row per iteration (iteration count is not knowable ahead of the loop actually running - Loop's exact termination condition is an open design question, see core-spec.md Section 10); remaining dimension(s) = one column per entry of outputVariableMap"}}, '[id].model': {'valid': False}, '[id].strings': {'valid': False}, '[id].aggregates': {'valid': 'provided(aggregateOutputVariables)', 'type': 'annotatedData', 'dimensions': [{'size': {'source': 'static', 'expr': 'len(aggregateOutputVariables)'}, 'labels': None, 'note': "each entry collapses the iteration dimension of [id] to a single value (per Repeat, the applied dimension defaults to this Loop's own iterations), unless the underlying subTask output was itself multi-dimensional, in which case that dimensionality carries through per entry"}]}, '[id].range': {'valid': 'provided(range)', 'type': 'annotatedData', 'dimensions': [], 'note': 'the current value of range, within the loop'}, '[id].index': {'valid': 'provided(range)', 'type': 'annotatedData', 'dimensions': [], 'note': 'the current index into range, within the loop'}}} + _OUTPUTS_JSON = {'outputs': {'[id]': {'type': 'annotatedData', 'dimensions': [{'size': {'source': 'static', 'expr': 'len(range)'}, 'labels': None, 'note': "one row per value in range; len(range) dispatches on range's actual Range/NumericRange/ParameterRange type"}, {'size': {'source': 'static', 'expr': 'len(outputVariableMap)'}, 'labels': None, 'note': 'one column per entry of outputVariableMap, or just the range-values column alone if outputVariableMap is empty; a column whose subTask output is itself multi-dimensional would add further dimensions beyond this, not captured here'}]}, '[id].aggregates': {'valid': 'provided(aggregateOutputVariables)', 'type': 'annotatedData', 'dimensions': [{'size': {'source': 'static', 'expr': 'len(aggregateOutputVariables)'}, 'labels': None, 'note': "each entry collapses the iteration dimension of [id] to a single value (per Repeat, the applied dimension defaults to this Loop's own iterations), unless the underlying subTask output was itself multi-dimensional, in which case that dimensionality carries through per entry"}]}, '[id].range': {'type': 'annotatedData', 'dimensions': [], 'note': 'the current value of range, within the loop'}, '[id].index': {'type': 'annotatedData', 'dimensions': [], 'note': 'the current index into range, within the loop'}}} _NAMESPACE_FIELDS = {} _NAMESPACE_CATCHALL = {} @@ -3846,7 +3841,7 @@ class ModelChange(SedBase): _NAME_RULE_ID = 'SEDBase-0001' _DESC_RULE_ID = 'SEDBase-0002' _BASE_CATCHALL = 'SEDBase-0000' - _OUTPUTS_JSON = {'outputs': {'[id]': {'valid': False}, '[id].model': {'valid': True, 'type': 'model'}, '[id].strings': {'valid': False}}} + _OUTPUTS_JSON = {'outputs': {'[id].model': {'type': 'model'}}} _NAMESPACE_FIELDS = {} _NAMESPACE_CATCHALL = {} @@ -4043,7 +4038,7 @@ class ModelElementList(SedBase): _NAME_RULE_ID = 'SEDBase-0001' _DESC_RULE_ID = 'SEDBase-0002' _BASE_CATCHALL = 'SEDBase-0000' - _OUTPUTS_JSON = {'outputs': {'[id]': {'valid': False}, '[id].model': {'valid': False}, '[id].strings': {'valid': True, 'type': 'stringList', 'dimensions': [{'size': {'source': 'input-file', 'from': 'model', 'extract': 'matchedElementIds', 'note': 'length = number of elements in the referenced model matched after includeElements/includeTypes/excludeElements/excludeTypes filtering'}, 'labels': {'source': 'input-file', 'from': 'model', 'extract': 'matchedElementIds', 'note': 'the matched element ids themselves'}}]}}} + _OUTPUTS_JSON = {'outputs': {'[id].strings': {'type': 'stringList', 'dimensions': [{'size': {'source': 'input-file', 'from': 'model', 'extract': 'matchedElementIds', 'note': 'length = number of elements in the referenced model matched after includeElements/includeTypes/excludeElements/excludeTypes filtering'}, 'labels': {'source': 'input-file', 'from': 'model', 'extract': 'matchedElementIds', 'note': 'the matched element ids themselves'}}]}}} _NAMESPACE_FIELDS = {} _NAMESPACE_CATCHALL = {} @@ -4240,7 +4235,7 @@ class ModelImport(SedBase): _NAME_RULE_ID = 'SEDBase-0001' _DESC_RULE_ID = 'SEDBase-0002' _BASE_CATCHALL = 'SEDBase-0000' - _OUTPUTS_JSON = {'outputs': {'[id]': {'valid': False}, '[id].model': {'valid': True, 'type': 'model'}, '[id].strings': {'valid': False}}} + _OUTPUTS_JSON = {'outputs': {'[id].model': {'type': 'model'}}} _NAMESPACE_FIELDS = {} _NAMESPACE_CATCHALL = {} @@ -4379,7 +4374,7 @@ class NumericRange(SedBase): _NAME_RULE_ID = 'SEDBase-0001' _DESC_RULE_ID = 'SEDBase-0002' _BASE_CATCHALL = 'SEDBase-0000' - _OUTPUTS_JSON = {'outputs': {'[id]': {'valid': True, 'type': 'annotatedData', 'dimensions': [{'size': {'source': 'static', 'expr': 'len(values) if provided(values) else numberOfSteps + 1'}, 'labels': None}]}, '[id].model': {'valid': False}, '[id].strings': {'valid': False}}} + _OUTPUTS_JSON = {'outputs': {'[id]': {'type': 'annotatedData', 'dimensions': [{'size': {'source': 'static', 'expr': 'len(values) if provided(values) else numberOfSteps + 1'}, 'labels': None}]}}} _NAMESPACE_FIELDS = {} _NAMESPACE_CATCHALL = {} @@ -4628,7 +4623,7 @@ class OneStepODESimulation(SedBase): _NAME_RULE_ID = 'SEDBase-0001' _DESC_RULE_ID = 'SEDBase-0002' _BASE_CATCHALL = 'SEDBase-0000' - _OUTPUTS_JSON = {'outputs': {'[id]': {'valid': True, 'type': 'annotatedData', 'dimensions': [{'size': {'source': 'static', 'expr': 'len(outputVariables)'}, 'labels': {'source': 'static', 'expr': 'outputVariables'}, 'note': 'a single point, not a series'}]}, '[id].model': {'valid': True, 'type': 'model'}, '[id].strings': {'valid': False}}} + _OUTPUTS_JSON = {'outputs': {'[id]': {'type': 'annotatedData', 'dimensions': [{'size': {'source': 'static', 'expr': 'len(outputVariables)'}, 'labels': {'source': 'static', 'expr': 'outputVariables'}, 'note': 'a single point, not a series'}]}, '[id].model': {'type': 'model'}}} _NAMESPACE_FIELDS = {} _NAMESPACE_CATCHALL = {} @@ -5238,7 +5233,7 @@ class OneStepStochasticSimulation(SedBase): _NAME_RULE_ID = 'SEDBase-0001' _DESC_RULE_ID = 'SEDBase-0002' _BASE_CATCHALL = 'SEDBase-0000' - _OUTPUTS_JSON = {'outputs': {'[id]': {'valid': True, 'type': 'annotatedData', 'dimensions': [{'size': {'source': 'static', 'expr': 'len(outputVariables)'}, 'labels': {'source': 'static', 'expr': 'outputVariables'}, 'note': 'a single point, not a series'}]}, '[id].model': {'valid': True, 'type': 'model'}, '[id].strings': {'valid': False}, '[id].independentStep': {'valid': '!provided(independentStep)', 'type': 'annotatedData', 'dimensions': [{'size': {'source': 'static', 'expr': '1'}, 'labels': None}], 'note': 'the actual elapsed step; present only when independentStep was NOT given as input'}}} + _OUTPUTS_JSON = {'outputs': {'[id]': {'type': 'annotatedData', 'dimensions': [{'size': {'source': 'static', 'expr': 'len(outputVariables)'}, 'labels': {'source': 'static', 'expr': 'outputVariables'}, 'note': 'a single point, not a series'}]}, '[id].model': {'type': 'model'}, '[id].independentStep': {'valid': '!provided(independentStep)', 'type': 'annotatedData', 'dimensions': [{'size': {'source': 'static', 'expr': '1'}, 'labels': None}], 'note': 'the actual elapsed step; present only when independentStep was NOT given as input'}}} _NAMESPACE_FIELDS = {} _NAMESPACE_CATCHALL = {} @@ -5628,7 +5623,7 @@ class ParameterRange(SedBase): _NAME_RULE_ID = 'SEDBase-0001' _DESC_RULE_ID = 'SEDBase-0002' _BASE_CATCHALL = 'SEDBase-0000' - _OUTPUTS_JSON = {'outputs': {'[id]': {'valid': True, 'type': 'annotatedData', 'dimensions': [{'size': {'source': 'static', 'expr': 'len(values) if provided(values) else numberOfSteps + 1', 'note': 'same derivation as NumericRange, inherited via NumericRangeCommon'}, 'labels': None}]}, '[id].model': {'valid': False}, '[id].strings': {'valid': False}}} + _OUTPUTS_JSON = {'outputs': {'[id]': {'type': 'annotatedData', 'dimensions': [{'size': {'source': 'static', 'expr': 'len(values) if provided(values) else numberOfSteps + 1', 'note': 'same derivation as NumericRange, inherited via NumericRangeCommon'}, 'labels': None}]}}} _NAMESPACE_FIELDS = {} _NAMESPACE_CATCHALL = {} @@ -5891,7 +5886,7 @@ def to_json_value(self): class ParameterScan(SedBase): """Generated from test-specsheets/tasks/ParameterScan/.""" - _FIELDS = [FieldSpec('model', 'SIdRef', True, 'ParameterScan-0002', 'ParameterScan-0001', 'ParameterScan-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target='model'), FieldSpec('outputVariableMap', 'DictOrRef', False, 'Repeat-0002', None, 'Repeat-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id='Repeat-0003', item_kind='ref', ref_target=None), FieldSpec('notes', 'any', False, 'SEDBase-0003', None, 'SEDBase-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('parameterRanges', 'array', True, 'ParameterScan-0004', 'ParameterScan-0003', 'ParameterScan-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class='ParameterRange', item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('subTasks', 'dict', False, 'Repeat-0001', None, 'Repeat-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator='AbstractTask', is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('aggregateOutputVariables', 'dict', False, 'Repeat-0004', None, 'Repeat-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class='AggregationCalculation', item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('taskParameters', 'array', False, 'AbstractTask-0001', None, 'AbstractTask-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class='TaskParameter', item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('annotations', 'array', False, 'SEDBase-0004', None, 'SEDBase-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class='Annotation', item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('range', 'ref-discriminator', False, 'Repeat-0005', None, 'Repeat-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator='RangeInline', is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None)] + _FIELDS = [FieldSpec('model', 'SIdRef', True, 'ParameterScan-0002', 'ParameterScan-0001', 'ParameterScan-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target='model'), FieldSpec('outputVariableMap', 'DictOrRef', False, 'Repeat-0002', None, 'Repeat-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id='Repeat-0003', item_kind='ref', ref_target=None), FieldSpec('notes', 'any', False, 'SEDBase-0003', None, 'SEDBase-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('parameterRanges', 'array', True, 'ParameterScan-0004', 'ParameterScan-0003', 'ParameterScan-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class='ParameterRange', item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('subTasks', 'dict', False, 'Repeat-0001', None, 'Repeat-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator='AbstractTask', is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('aggregateOutputVariables', 'dict', False, 'Repeat-0004', None, 'Repeat-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class='AggregationCalculation', item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('taskParameters', 'array', False, 'AbstractTask-0001', None, 'AbstractTask-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class='TaskParameter', item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('annotations', 'array', False, 'SEDBase-0004', None, 'SEDBase-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class='Annotation', item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None)] _REQUIRED_NAMES = {'model', 'parameterRanges'} _TYPE_CONST = 'parameterScan' _TYPE_RULE_ID = 'ParameterScan-0006' @@ -5899,7 +5894,7 @@ class ParameterScan(SedBase): _NAME_RULE_ID = 'SEDBase-0001' _DESC_RULE_ID = 'SEDBase-0002' _BASE_CATCHALL = 'SEDBase-0000' - _OUTPUTS_JSON = {'outputs': {'[id]': {'valid': True, 'type': 'annotatedData', 'dimensions': [{'repeat': {'over': 'parameterRanges', 'size': {'source': 'static', 'expr': 'len(self)'}, 'labels': None, 'note': "one dimension per entry of parameterRanges, each sized by that entry's own length; len(self) dispatches on the entry's actual Range/NumericRange/ParameterRange type - see core-spec.md Section 8"}}, {'size': {'source': 'static', 'expr': 'len(outputVariableMap)'}, 'labels': None}]}, '[id].model': {'valid': False}, '[id].strings': {'valid': False}, '[id].aggregates': {'valid': 'provided(aggregateOutputVariables)', 'type': 'annotatedData', 'dimensions': [{'size': {'source': 'static', 'expr': 'len(aggregateOutputVariables)'}, 'labels': None}]}}} + _OUTPUTS_JSON = {'outputs': {'[id]': {'type': 'annotatedData', 'dimensions': [{'repeat': {'over': 'parameterRanges', 'size': {'source': 'static', 'expr': 'len(self)'}, 'labels': {'source': 'static', 'expr': 'modelElement'}, 'note': "one dimension per entry of parameterRanges, each sized by that entry's own length; len(self) dispatches on the entry's actual Range/NumericRange/ParameterRange type - see core-spec.md Section 8; each dimension is labeled with (identified by) that entry's modelElement, in parameterRanges order"}}, {'size': {'source': 'static', 'expr': 'len(outputVariableMap)'}, 'labels': None}]}, '[id].aggregates': {'valid': 'provided(aggregateOutputVariables)', 'type': 'annotatedData', 'dimensions': [{'size': {'source': 'static', 'expr': 'len(aggregateOutputVariables)'}, 'labels': None}]}, '[id].ranges': {'type': 'annotatedData', 'dimensions': [{'size': {'source': 'static', 'expr': 'len(parameterRanges)'}, 'labels': {'source': 'static', 'expr': 'parameterRanges.modelElement'}, 'note': "one entry per ParameterRange child, in order, labeled with that child's modelElement (parameterRanges.modelElement is the modelElement of each entry, in order)"}], 'note': 'the current value of each entry of parameterRanges, within the loop only'}, '[id].indexes': {'type': 'annotatedData', 'dimensions': [{'size': {'source': 'static', 'expr': 'len(parameterRanges)'}, 'labels': {'source': 'static', 'expr': 'parameterRanges.modelElement'}, 'note': "one entry per ParameterRange child, in order, labeled with that child's modelElement (parameterRanges.modelElement is the modelElement of each entry, in order)"}], 'note': 'the current index into each entry of parameterRanges, within the loop only'}}} _NAMESPACE_FIELDS = {} _NAMESPACE_CATCHALL = {} @@ -5910,7 +5905,6 @@ def __init__(self): self._aggregate_output_variables = IdKeyedCollection(lambda tv, _cls=AggregationCalculation: (_cls, False)) self._task_parameters = ListCollection() self._annotations = ListCollection() - self._range = None def get_type(self): return 'parameterScan' @@ -6034,19 +6028,6 @@ def insert_annotations(self, index, obj): def remove_annotations(self, index): self._annotations.remove(index) - def get_range(self): - if self._range is None: raise ApiError('range is not set') - return self._range - - def set_range(self, obj): - self._range = obj; obj._attach(self, self.get_document()) - - def is_set_range(self): - return self._range is not None - - def unset_range(self): - self._range = None - def _children(self): kids = [] kids.extend(self._parameter_ranges.items()) @@ -6054,7 +6035,6 @@ def _children(self): kids.extend(self._aggregate_output_variables.get(i) for i in self._aggregate_output_variables.ids()) kids.extend(self._task_parameters.items()) kids.extend(self._annotations.items()) - if self._range is not None: kids.append(self._range) return kids def _get_id_collection(self, field_name): @@ -6074,7 +6054,6 @@ def _children_with_locations(self): out.append((item, '/taskParameters/%d' % idx)) for idx, item in enumerate(self._annotations.items()): out.append((item, '/annotations/%d' % idx)) - if self._range is not None: out.append((self._range, '/range')) return out def _id_collection_names(self): @@ -6093,7 +6072,6 @@ def _own_json_value(self): if len(self._aggregate_output_variables): d['aggregateOutputVariables'] = {i: self._aggregate_output_variables.get(i).to_json_value() for i in self._aggregate_output_variables.ids()} if len(self._task_parameters): d['taskParameters'] = [it.to_json_value() for it in self._task_parameters.items()] if len(self._annotations): d['annotations'] = [it.to_json_value() for it in self._annotations.items()] - if self._range is not None: d['range'] = self._range.to_json_value() for (pfx, key), value in self._ns_attrs.items(): d[f'{pfx}@{key}'] = value return d @@ -6112,7 +6090,7 @@ class Range(SedBase): _NAME_RULE_ID = 'SEDBase-0001' _DESC_RULE_ID = 'SEDBase-0002' _BASE_CATCHALL = 'SEDBase-0000' - _OUTPUTS_JSON = {'outputs': {'[id]': {'valid': True, 'type': 'annotatedData', 'dimensions': [{'size': {'source': 'static', 'expr': 'len(values)'}, 'labels': None}]}, '[id].model': {'valid': False}, '[id].strings': {'valid': False}}} + _OUTPUTS_JSON = {'outputs': {'[id]': {'type': 'annotatedData', 'dimensions': [{'size': {'source': 'static', 'expr': 'len(values)'}, 'labels': None}]}}} _NAMESPACE_FIELDS = {} _NAMESPACE_CATCHALL = {} @@ -6229,7 +6207,7 @@ class RelabelData(SedBase): _NAME_RULE_ID = 'SEDBase-0001' _DESC_RULE_ID = 'SEDBase-0002' _BASE_CATCHALL = 'SEDBase-0000' - _OUTPUTS_JSON = {'outputs': {'[id]': {'valid': True, 'type': 'annotatedData', 'dimensions': {'source': 'static', 'expr': 'shapeOf(input)', 'note': "same dimensions as the referenced input AnnotatedData - this task only replaces the topmost dimension's labels (from labels), not the shape"}}, '[id].model': {'valid': False}}} + _OUTPUTS_JSON = {'outputs': {'[id]': {'type': 'annotatedData', 'dimensions': {'source': 'static', 'expr': 'shapeOf(input)', 'note': "same dimensions as the referenced input AnnotatedData - this task only replaces the topmost dimension's labels (from labels), not the shape"}}}} _NAMESPACE_FIELDS = {} _NAMESPACE_CATCHALL = {} @@ -6352,15 +6330,15 @@ def to_json_value(self): class Scatter(SedBase): """Generated from test-specsheets/tasks/Scatter/.""" - _FIELDS = [FieldSpec('outputVariableMap', 'DictOrRef', False, 'Repeat-0002', None, 'Repeat-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id='Repeat-0003', item_kind='ref', ref_target=None), FieldSpec('notes', 'any', False, 'SEDBase-0003', None, 'SEDBase-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('subTasks', 'dict', False, 'Repeat-0001', None, 'Repeat-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator='AbstractTask', is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('aggregateOutputVariables', 'dict', False, 'Repeat-0004', None, 'Repeat-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class='AggregationCalculation', item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('taskParameters', 'array', False, 'AbstractTask-0001', None, 'AbstractTask-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class='TaskParameter', item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('annotations', 'array', False, 'SEDBase-0004', None, 'SEDBase-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class='Annotation', item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('range', 'ref-discriminator', False, 'Repeat-0005', None, 'Repeat-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator='RangeInline', is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None)] - _REQUIRED_NAMES = {} + _FIELDS = [FieldSpec('outputVariableMap', 'DictOrRef', False, 'Repeat-0002', None, 'Repeat-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id='Repeat-0003', item_kind='ref', ref_target=None), FieldSpec('notes', 'any', False, 'SEDBase-0003', None, 'SEDBase-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('subTasks', 'dict', False, 'Repeat-0001', None, 'Repeat-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator='AbstractTask', is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('aggregateOutputVariables', 'dict', False, 'Repeat-0004', None, 'Repeat-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class='AggregationCalculation', item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('taskParameters', 'array', False, 'AbstractTask-0001', None, 'AbstractTask-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class='TaskParameter', item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('annotations', 'array', False, 'SEDBase-0004', None, 'SEDBase-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class='Annotation', item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('range', 'ref-discriminator', True, 'Scatter-0005', 'Scatter-0004', 'Scatter-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator='RangeInline', is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None)] + _REQUIRED_NAMES = {'range'} _TYPE_CONST = 'scatter' _TYPE_RULE_ID = 'Scatter-0003' _OWN_CATCHALL = 'Scatter-0000' _NAME_RULE_ID = 'SEDBase-0001' _DESC_RULE_ID = 'SEDBase-0002' _BASE_CATCHALL = 'SEDBase-0000' - _OUTPUTS_JSON = {'outputs': {'[id]': {'valid': True, 'type': 'annotatedData', 'dimensions': [{'size': {'source': 'static', 'expr': 'len(range)'}, 'labels': None, 'note': "one row per value in range; len(range) dispatches on range's actual Range/NumericRange/ParameterRange type"}, {'size': {'source': 'static', 'expr': 'len(outputVariableMap)'}, 'labels': None, 'note': 'one column per entry of outputVariableMap, or just the range-values column alone if outputVariableMap is empty; a column whose subTask output is itself multi-dimensional would add further dimensions beyond this, not captured here'}]}, '[id].model': {'valid': False}, '[id].strings': {'valid': False}, '[id].aggregates': {'valid': 'provided(aggregateOutputVariables)', 'type': 'annotatedData', 'dimensions': [{'size': {'source': 'static', 'expr': 'len(aggregateOutputVariables)'}, 'labels': None, 'note': "each entry collapses the range dimension of [id] to a single value (per Repeat, the applied dimension defaults to this Scatter's own range), unless the underlying subTask output was itself multi-dimensional, in which case that dimensionality carries through per entry"}]}, '[id].range': {'valid': 'provided(range)', 'type': 'annotatedData', 'dimensions': [], 'note': 'the current value of range, within each iteration'}, '[id].index': {'valid': 'provided(range)', 'type': 'annotatedData', 'dimensions': [], 'note': 'the current index into range, within each iteration'}}} + _OUTPUTS_JSON = {'outputs': {'[id]': {'type': 'annotatedData', 'dimensions': [{'size': {'source': 'static', 'expr': 'len(range)'}, 'labels': None, 'note': "one row per value in range; len(range) dispatches on range's actual Range/NumericRange/ParameterRange type"}, {'size': {'source': 'static', 'expr': 'len(outputVariableMap)'}, 'labels': None, 'note': 'one column per entry of outputVariableMap, or just the range-values column alone if outputVariableMap is empty; a column whose subTask output is itself multi-dimensional would add further dimensions beyond this, not captured here'}]}, '[id].aggregates': {'valid': 'provided(aggregateOutputVariables)', 'type': 'annotatedData', 'dimensions': [{'size': {'source': 'static', 'expr': 'len(aggregateOutputVariables)'}, 'labels': None, 'note': "each entry collapses the range dimension of [id] to a single value (per Repeat, the applied dimension defaults to this Scatter's own range), unless the underlying subTask output was itself multi-dimensional, in which case that dimensionality carries through per entry"}]}, '[id].range': {'type': 'annotatedData', 'dimensions': [], 'note': 'the current value of range, within each iteration'}, '[id].index': {'type': 'annotatedData', 'dimensions': [], 'note': 'the current index into range, within each iteration'}}} _NAMESPACE_FIELDS = {} _NAMESPACE_CATCHALL = {} @@ -6542,7 +6520,7 @@ class Span(SedBase): _NAME_RULE_ID = 'SEDBase-0001' _DESC_RULE_ID = 'SEDBase-0002' _BASE_CATCHALL = 'SEDBase-0000' - _OUTPUTS_JSON = {'outputs': {'[id]': {'valid': False}, '[id].model': {'valid': False}, '[id].strings': {'valid': False}}} + _OUTPUTS_JSON = {'outputs': {}} _NAMESPACE_FIELDS = {} _NAMESPACE_CATCHALL = {} @@ -6656,7 +6634,7 @@ def to_json_value(self): class SteadyState(SedBase): """Generated from test-specsheets/tasks/SteadyState/.""" - _FIELDS = [FieldSpec('model', 'SIdRef', True, None, 'SteadyState-0001', 'SteadyState-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target='model'), FieldSpec('independentVariable', 'StringOrRef', False, 'SteadyState-0004', None, 'SteadyState-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('outputVariables', 'ArrayOrRef', True, None, 'SteadyState-0002', 'SteadyState-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind='string', ref_target=None), FieldSpec('outputModel', 'BooleanOrRef', False, 'SteadyState-0005', None, 'SteadyState-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id='SteadyState-0006', item_kind=None, ref_target=None), FieldSpec('notes', 'any', False, 'SEDBase-0003', None, 'SEDBase-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('taskParameters', 'array', False, 'AbstractTask-0001', None, 'AbstractTask-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class='TaskParameter', item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('annotations', 'array', False, 'SEDBase-0004', None, 'SEDBase-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class='Annotation', item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None)] + _FIELDS = [FieldSpec('model', 'SIdRef', True, None, 'SteadyState-0001', 'SteadyState-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target='model'), FieldSpec('independentVariable', 'StringOrRef', False, 'SteadyState-0004', None, 'SteadyState-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('outputVariables', 'ArrayOrRef', True, None, 'SteadyState-0002', 'SteadyState-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind='string', ref_target=None), FieldSpec('notes', 'any', False, 'SEDBase-0003', None, 'SEDBase-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class=None, item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('workingAlgorithms', 'array', False, 'SteadyState-0007', None, 'SteadyState-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class='WorkingAlgorithm', item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('taskParameters', 'array', False, 'AbstractTask-0001', None, 'AbstractTask-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class='TaskParameter', item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None), FieldSpec('annotations', 'array', False, 'SEDBase-0004', None, 'SEDBase-0000', minimum=None, exclusive_minimum=None, pattern=None, item_class='Annotation', item_discriminator=None, is_math=False, min_length=None, enum=None, ref_type_rule_id=None, item_kind=None, ref_target=None)] _REQUIRED_NAMES = {'model', 'outputVariables'} _TYPE_CONST = 'steadyState' _TYPE_RULE_ID = 'SteadyState-0003' @@ -6664,12 +6642,13 @@ class SteadyState(SedBase): _NAME_RULE_ID = 'SEDBase-0001' _DESC_RULE_ID = 'SEDBase-0002' _BASE_CATCHALL = 'SEDBase-0000' - _OUTPUTS_JSON = {'outputs': {'[id]': {'valid': True, 'type': 'annotatedData', 'dimensions': [{'size': {'source': 'static', 'expr': 'len(outputVariables)'}, 'labels': {'source': 'static', 'expr': 'outputVariables'}}]}, '[id].model': {'valid': 'outputModel == true', 'type': 'model'}, '[id].strings': {'valid': False}}} + _OUTPUTS_JSON = {'outputs': {'[id]': {'type': 'annotatedData', 'dimensions': [{'size': {'source': 'static', 'expr': 'len(outputVariables)'}, 'labels': {'source': 'static', 'expr': 'outputVariables'}}]}, '[id].model': {'type': 'model'}}} _NAMESPACE_FIELDS = {} _NAMESPACE_CATCHALL = {} def __init__(self): super().__init__() + self._working_algorithms = ListCollection() self._task_parameters = ListCollection() self._annotations = ListCollection() @@ -6731,27 +6710,6 @@ def is_set_output_variables(self): def unset_output_variables(self): self._values.pop('outputVariables', None); self._orref_is_ref.pop('outputVariables', None) - def get_output_model_value(self): - return self._get_orref_value('outputModel') - - def get_output_model_ref(self): - return self._get_orref_ref('outputModel') - - def set_output_model_value(self, value): - self._set_orref_value('outputModel', value) - - def set_output_model_ref(self, ref): - self._set_orref_ref('outputModel', ref) - - def is_output_model_ref(self): - return self._is_orref_ref('outputModel') - - def is_set_output_model(self): - return 'outputModel' in self._values - - def unset_output_model(self): - self._values.pop('outputModel', None); self._orref_is_ref.pop('outputModel', None) - def get_notes(self): if 'notes' not in self._values: raise ApiError('notes is not set') return self._values['notes'] @@ -6765,6 +6723,18 @@ def is_set_notes(self): def unset_notes(self): self._values.pop('notes', None) + def get_working_algorithms(self): + return self._working_algorithms.items() + + def add_working_algorithms(self, obj): + self._working_algorithms.add(obj); obj._attach(self, self.get_document()) + + def insert_working_algorithms(self, index, obj): + self._working_algorithms.insert(index, obj); obj._attach(self, self.get_document()) + + def remove_working_algorithms(self, index): + self._working_algorithms.remove(index) + def get_task_parameters(self): return self._task_parameters.items() @@ -6791,6 +6761,7 @@ def remove_annotations(self, index): def _children(self): kids = [] + kids.extend(self._working_algorithms.items()) kids.extend(self._task_parameters.items()) kids.extend(self._annotations.items()) return kids @@ -6800,6 +6771,8 @@ def _get_id_collection(self, field_name): def _children_with_locations(self): out = [] + for idx, item in enumerate(self._working_algorithms.items()): + out.append((item, '/workingAlgorithms/%d' % idx)) for idx, item in enumerate(self._task_parameters.items()): out.append((item, '/taskParameters/%d' % idx)) for idx, item in enumerate(self._annotations.items()): @@ -6817,8 +6790,8 @@ def _own_json_value(self): if 'model' in self._values: d['model'] = self._values['model'] if 'independentVariable' in self._values: d['independentVariable'] = self._values['independentVariable'] if 'outputVariables' in self._values: d['outputVariables'] = self._values['outputVariables'] - if 'outputModel' in self._values: d['outputModel'] = self._values['outputModel'] if 'notes' in self._values: d['notes'] = self._values['notes'] + if len(self._working_algorithms): d['workingAlgorithms'] = [it.to_json_value() for it in self._working_algorithms.items()] if len(self._task_parameters): d['taskParameters'] = [it.to_json_value() for it in self._task_parameters.items()] if len(self._annotations): d['annotations'] = [it.to_json_value() for it in self._annotations.items()] for (pfx, key), value in self._ns_attrs.items(): @@ -6839,7 +6812,7 @@ class StringFormation(SedBase): _NAME_RULE_ID = 'SEDBase-0001' _DESC_RULE_ID = 'SEDBase-0002' _BASE_CATCHALL = 'SEDBase-0000' - _OUTPUTS_JSON = {'outputs': {'[id]': {'valid': True, 'type': 'annotatedData', 'dimensions': {'source': 'runtime', 'note': "scalar when no element of concatenate is itself a list; otherwise N-D matching the shape of the list element(s) within concatenate (1D for one list element, higher-D when several list elements are combined pairwise, all sharing the same length/shape per dimension) - not derivable without evaluating concatenate's actual element values"}}, '[id].model': {'valid': False}, '[id].strings': {'valid': True, 'type': 'stringList', 'dimensions': {'source': 'runtime', 'note': "same as [id]'s dimensions above; not derivable without evaluating concatenate"}}}} + _OUTPUTS_JSON = {'outputs': {'[id]': {'type': 'annotatedData', 'dimensions': {'source': 'runtime', 'note': "scalar when no element of concatenate is itself a list; otherwise N-D matching the shape of the list element(s) within concatenate (1D for one list element, higher-D when several list elements are combined pairwise, all sharing the same length/shape per dimension) - not derivable without evaluating concatenate's actual element values"}}, '[id].strings': {'type': 'stringList', 'dimensions': {'source': 'runtime', 'note': "same as [id]'s dimensions above; not derivable without evaluating concatenate"}}}} _NAMESPACE_FIELDS = {} _NAMESPACE_CATCHALL = {} diff --git a/generated/python/src/libsed2/outputs_shape.py b/generated/python/src/libsed2/outputs_shape.py index db4c30a..f8766e0 100644 --- a/generated/python/src/libsed2/outputs_shape.py +++ b/generated/python/src/libsed2/outputs_shape.py @@ -530,13 +530,15 @@ def _apply_index_chain(dims, index_accessors): def eval_valid(entry, scope, shape_of): - """entry["valid"] is True/False, or a boolean expr string over the - task's own fields. Returns True/False, or None when a string expr - couldn't be evaluated statically (SEDBase-0008: "the rule does not - fire" in that case).""" + """A suffix entry that is listed in outputs.json is valid; one that + isn't listed is not (resolve_output handles that). An entry's optional + "valid" field is a boolean expr string over the task's own fields + meaning "valid if". No "valid" field: always valid. Returns True/False, + or None when the expr couldn't be evaluated statically (SEDBase-0008: + "the rule does not fire" in that case).""" valid = entry.get("valid") - if valid is True or valid is False: - return valid + if valid is None: + return True if isinstance(valid, str): try: return bool(eval_expr(parse_expr(valid), scope, shape_of)) @@ -552,8 +554,9 @@ def resolve_output(outputs_json, fields, accessors, shape_of): `fields` is the referenced task's own _own_json_value() dict; `accessors` is a ParsedReference's own .accessors list. Returns (accessor_ok, entry, dims_before, dims_after, dot_name, index_accessors): - - accessor_ok: True (the suffix exists and its "valid" evaluated - true), False (suffix absent or "valid" is/evaluates false), or None + - accessor_ok: True (the suffix is listed and has no "valid" field, + or its "valid" ("valid if") expr evaluated true), False (suffix + not listed, or its "valid" expr evaluated false), or None (couldn't be determined statically - every caller treats this the same as False for "don't fire a positive claim" but ALSO suppresses every rule that would need to know for sure, per the "only fires diff --git a/generated/python/src/libsed2/rules_data.py b/generated/python/src/libsed2/rules_data.py index 8ec50f6..6b18b7d 100644 --- a/generated/python/src/libsed2/rules_data.py +++ b/generated/python/src/libsed2/rules_data.py @@ -196,8 +196,6 @@ 'FluxBalanceAnalysis-0003': ('The outputVariables attribute of a FluxBalanceAnalysis is required.', "Required attribute '{attr}' is missing from {class} '{id}'.", 'error'), 'FluxBalanceAnalysis-0004': ('When the value of outputVariables of a FluxBalanceAnalysis is provided directly, it must be an array of strings.', "Attribute '{attr}' of {class} '{id}' has value '{value}', which is not an array of strings.", 'error'), 'FluxBalanceAnalysis-0005': ('When the value of outputVariables of a FluxBalanceAnalysis is a reference, it must be a reference to an array of strings.', "Attribute '{attr}' of {class} '{id}' is the reference '{value}', which resolves to '{resolved-value}', not an array of strings.", 'error'), - 'FluxBalanceAnalysis-0006': ('When the value of outputModel of a FluxBalanceAnalysis is provided directly, it must be a boolean.', "Attribute '{attr}' of {class} '{id}' has value '{value}', which is not a boolean.", 'error'), - 'FluxBalanceAnalysis-0007': ('When the value of outputModel of a FluxBalanceAnalysis is a reference, it must be a reference to a boolean.', "Attribute '{attr}' of {class} '{id}' is the reference '{value}', which resolves to '{resolved-value}', not a boolean.", 'error'), 'FluxBalanceAnalysis-0008': ('The _type attribute of a FluxBalanceAnalysis must be "fluxBalanceAnalysis".', "Attribute '{attr}' of {class} '{id}' has value '{value}', which does not match the required value '{allowed}'.", 'error'), 'JacobianFull-0000': ('The element fails a JSON Schema constraint attributable to JacobianFull that does not match any other numbered rule.', '{schema-message} (at {location})', 'error'), 'JacobianFull-0001': ('The model attribute of a JacobianFull is required.', "Required attribute '{attr}' is missing from {class} '{id}'.", 'error'), @@ -328,7 +326,6 @@ 'Repeat-0002': ('When the value of outputVariableMap of a Repeat is provided directly, it must be an object whose values are SIdRef.', "Attribute '{attr}' of {class} '{id}' has value '{value}', which is not an object whose values are SIdRef.", 'error'), 'Repeat-0003': ('When the value of outputVariableMap of a Repeat is a reference, it must be a reference to an object whose values are SIdRef.', "Attribute '{attr}' of {class} '{id}' is the reference '{value}', which resolves to '{resolved-value}', not an object whose values are SIdRef.", 'error'), 'Repeat-0004': ('The aggregateOutputVariables attribute of a Repeat must be an object whose values are AggregationCalculation.', "Attribute '{attr}' of {class} '{id}' has value '{value}', which is not an object whose values are AggregationCalculation.", 'error'), - 'Repeat-0005': ('The range attribute of a Repeat, if present, must be a RangeInline object.', "Attribute '{attr}' of {class} '{id}' has value '{value}', which is not a RangeInline object.", 'error'), 'Repeat-0006': ('A Repeat must provide at least one of outputVariableMap or aggregateOutputVariables.', "{class} '{id}' must provide at least one of 'outputVariableMap' or 'aggregateOutputVariables'.", 'error'), 'Repeat-0008': ("Every value in a Repeat's outputVariableMap must reference one of that Repeat's own subTasks, or an output of one.", "Entry '{attr}' of the outputVariableMap of {class} '{id}' references '{value}', which is not one of its own subTasks.", 'error'), 'Repeat-0009': ("The input of every entry in a Repeat's aggregateOutputVariables must reference one of that Repeat's own subTasks, or an output of one.", "Entry '{attr}' of the aggregateOutputVariables of {class} '{id}' has input '{value}', which is not one of its own subTasks.", 'error'), @@ -385,8 +382,6 @@ 'SteadyState-0002': ('The outputVariables attribute of a SteadyState is required.', "Required attribute '{attr}' is missing from {class} '{id}'.", 'error'), 'SteadyState-0003': ('The _type attribute of a SteadyState must be "steadyState".', "Attribute '{attr}' of {class} '{id}' has value '{value}', which does not match the required value '{allowed}'.", 'error'), 'SteadyState-0004': ('The independentVariable attribute of a SteadyState, if present, must be a string.', "Attribute '{attr}' of {class} '{id}' has value '{value}', which is not a string.", 'error'), - 'SteadyState-0005': ('When the value of outputModel of a SteadyState is provided directly, it must be a boolean.', "Attribute '{attr}' of {class} '{id}' has value '{value}', which is not a boolean.", 'error'), - 'SteadyState-0006': ('When the value of outputModel of a SteadyState is a reference, it must be a reference to a boolean.', "Attribute '{attr}' of {class} '{id}' is the reference '{value}', which resolves to '{resolved-value}', not a boolean.", 'error'), 'StringFormation-0000': ('The element fails a JSON Schema constraint attributable to StringFormation that does not match any other numbered rule.', '{schema-message} (at {location})', 'error'), 'StringFormation-0001': ('The concatenate attribute of a StringFormation is required.', "Required attribute '{attr}' is missing from {class} '{id}'.", 'error'), 'StringFormation-0002': ('When the value of concatenate of a StringFormation is provided directly, it must be an array of values.', "Attribute '{attr}' of {class} '{id}' has value '{value}', which is not an array of values.", 'error'), diff --git a/generated/rules-v1.0.0.json b/generated/rules-v1.0.0.json index dbd393d..06d4d07 100644 --- a/generated/rules-v1.0.0.json +++ b/generated/rules-v1.0.0.json @@ -1551,22 +1551,6 @@ "status": "active", "check": "ref-type" }, - "FluxBalanceAnalysis-0006": { - "class": "FluxBalanceAnalysis", - "rule": "When the value of outputModel of a FluxBalanceAnalysis is provided directly, it must be a boolean.", - "message": "Attribute '{attr}' of {class} '{id}' has value '{value}', which is not a boolean.", - "severity": "error", - "status": "active", - "check": "schema" - }, - "FluxBalanceAnalysis-0007": { - "class": "FluxBalanceAnalysis", - "rule": "When the value of outputModel of a FluxBalanceAnalysis is a reference, it must be a reference to a boolean.", - "message": "Attribute '{attr}' of {class} '{id}' is the reference '{value}', which resolves to '{resolved-value}', not a boolean.", - "severity": "error", - "status": "active", - "check": "ref-type" - }, "FluxBalanceAnalysis-0008": { "class": "FluxBalanceAnalysis", "rule": "The _type attribute of a FluxBalanceAnalysis must be \"fluxBalanceAnalysis\".", @@ -2607,14 +2591,6 @@ "status": "active", "check": "schema" }, - "Repeat-0005": { - "class": "Repeat", - "rule": "The range attribute of a Repeat, if present, must be a RangeInline object.", - "message": "Attribute '{attr}' of {class} '{id}' has value '{value}', which is not a RangeInline object.", - "severity": "error", - "status": "active", - "check": "schema" - }, "Repeat-0006": { "class": "Repeat", "rule": "A Repeat must provide at least one of outputVariableMap or aggregateOutputVariables.", @@ -3063,22 +3039,6 @@ "status": "active", "check": "schema" }, - "SteadyState-0005": { - "class": "SteadyState", - "rule": "When the value of outputModel of a SteadyState is provided directly, it must be a boolean.", - "message": "Attribute '{attr}' of {class} '{id}' has value '{value}', which is not a boolean.", - "severity": "error", - "status": "active", - "check": "schema" - }, - "SteadyState-0006": { - "class": "SteadyState", - "rule": "When the value of outputModel of a SteadyState is a reference, it must be a reference to a boolean.", - "message": "Attribute '{attr}' of {class} '{id}' is the reference '{value}', which resolves to '{resolved-value}', not a boolean.", - "severity": "error", - "status": "active", - "check": "ref-type" - }, "StringFormation-0000": { "class": "StringFormation", "rule": "The element fails a JSON Schema constraint attributable to StringFormation that does not match any other numbered rule.", diff --git a/generator/emit_java.py b/generator/emit_java.py index 60bf08b..0011758 100644 --- a/generator/emit_java.py +++ b/generator/emit_java.py @@ -2342,13 +2342,16 @@ def _fmt_entry(name: str, spec: tuple) -> str: return result; } - /** entry["valid"] is true/false, or a boolean expr string over the - * task's own fields. Returns TRUE/FALSE, or null when a string expr - * couldn't be evaluated statically ("the rule does not fire"). */ + /** A suffix entry that is listed in outputs.json is valid; one that isn't + * listed is not (resolveOutput handles that). An entry's optional "valid" + * field is a boolean expr string over the task's own fields meaning + * "valid if"; no "valid" field means always valid. Returns TRUE/FALSE, or + * null when the expr couldn't be evaluated statically ("the rule does not + * fire"). */ static Boolean evalValid(JsonNode entry, Scope scope, Function> shapeOf) { JsonNode valid = entry.get("valid"); - if (valid != null && valid.isBoolean()) return valid.booleanValue(); - if (valid != null && valid.isTextual()) { + if (valid == null) return Boolean.TRUE; + if (valid.isTextual()) { try { return truthy(eval(parseExpr(valid.textValue()), scope, shapeOf)); } catch (NotStatic e) { @@ -2360,8 +2363,9 @@ def _fmt_entry(name: str, spec: tuple) -> str: /** The result of resolveOutput: see that method. */ public static final class Resolution { - /** TRUE (suffix exists and its "valid" evaluated true), FALSE (absent - * or evaluates false), or null (couldn't be determined statically). */ + /** TRUE (suffix is listed and has no "valid" field, or its "valid" + * ("valid if") expr evaluated true), FALSE (not listed, or the expr + * evaluates false), or null (couldn't be determined statically). */ public final Boolean ok; public final JsonNode entry; // the raw outputEntry, or null when the suffix key is absent public final List dimsBefore; // null unless ok == TRUE and the entry has resolvable "dimensions" diff --git a/generator/emit_python.py b/generator/emit_python.py index 42308bc..279f798 100644 --- a/generator/emit_python.py +++ b/generator/emit_python.py @@ -2411,13 +2411,15 @@ def _apply_index_chain(dims, index_accessors): def eval_valid(entry, scope, shape_of): - """entry["valid"] is True/False, or a boolean expr string over the - task's own fields. Returns True/False, or None when a string expr - couldn't be evaluated statically (SEDBase-0008: "the rule does not - fire" in that case).""" + """A suffix entry that is listed in outputs.json is valid; one that + isn't listed is not (resolve_output handles that). An entry's optional + "valid" field is a boolean expr string over the task's own fields + meaning "valid if". No "valid" field: always valid. Returns True/False, + or None when the expr couldn't be evaluated statically (SEDBase-0008: + "the rule does not fire" in that case).""" valid = entry.get("valid") - if valid is True or valid is False: - return valid + if valid is None: + return True if isinstance(valid, str): try: return bool(eval_expr(parse_expr(valid), scope, shape_of)) @@ -2433,8 +2435,9 @@ def resolve_output(outputs_json, fields, accessors, shape_of): `fields` is the referenced task's own _own_json_value() dict; `accessors` is a ParsedReference's own .accessors list. Returns (accessor_ok, entry, dims_before, dims_after, dot_name, index_accessors): - - accessor_ok: True (the suffix exists and its "valid" evaluated - true), False (suffix absent or "valid" is/evaluates false), or None + - accessor_ok: True (the suffix is listed and has no "valid" field, + or its "valid" ("valid if") expr evaluated true), False (suffix + not listed, or its "valid" expr evaluated false), or None (couldn't be determined statically - every caller treats this the same as False for "don't fire a positive claim" but ALSO suppresses every rule that would need to know for sure, per the "only fires diff --git a/schema/outputs-meta.schema.json b/schema/outputs-meta.schema.json index 7e4b90f..d94ad2d 100644 --- a/schema/outputs-meta.schema.json +++ b/schema/outputs-meta.schema.json @@ -2,7 +2,7 @@ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://sed-ml.org/schemas/meta/outputs-meta.schema.json", "title": "SED2 outputs.json meta-schema", - "description": "Validates the ENVELOPE shape of a per-class outputs.json file (specsheets/tasks//v1.0.0/outputs.json) - not the internal syntax of its 'expr'/'note' strings, which is documented in prose (see Design.md's Task Output Shapes section) rather than formally parsed here.", + "description": "Validates the ENVELOPE shape of a per-class outputs.json file (specsheets/tasks//v1.0.0/outputs.json) - every listed suffix is valid (optionally only 'valid' if a condition holds), every unlisted suffix is invalid - not the internal syntax of its 'expr'/'note' strings, which is documented in prose (see Design.md's Task Output Shapes section) rather than formally parsed here.", "$defs": { "sourced": { "description": "How a size, label set, or whole dimensions list is known.", @@ -87,17 +87,15 @@ "type": "object", "properties": { "valid": { - "description": "true, false, or a boolean expression string conditioning validity on the task's own fields (e.g. \"outputModel == true\", \"provided(range)\").", - "anyOf": [ { "type": "boolean" }, { "type": "string", "minLength": 1 } ] + "description": "Optional 'valid if' condition: a boolean expression string over the task's own fields (e.g. \"outputModel == true\", \"provided(range)\"). A suffix that is listed with no 'valid' field is always valid; a suffix that is not listed at all is never valid.", + "type": "string", + "minLength": 1 }, "type": { "enum": ["annotatedData", "model", "stringList"] }, "dimensions": { "$ref": "#/$defs/dimensions" }, "note": { "type": "string" } }, - "required": ["valid"], - "if": { "properties": { "valid": { "const": false } } }, - "then": {}, - "else": { "required": ["type"] }, + "required": ["type"], "additionalProperties": false } }, @@ -106,8 +104,7 @@ "outputs": { "type": "object", "propertyNames": { "pattern": "^\\[id\\]" }, - "additionalProperties": { "$ref": "#/$defs/outputEntry" }, - "minProperties": 1 + "additionalProperties": { "$ref": "#/$defs/outputEntry" } } }, "required": ["outputs"], diff --git a/specsheets/auxiliary/LoopVariable/v1.0.0/description.md b/specsheets/auxiliary/LoopVariable/v1.0.0/description.md index 69a4377..701852b 100644 --- a/specsheets/auxiliary/LoopVariable/v1.0.0/description.md +++ b/specsheets/auxiliary/LoopVariable/v1.0.0/description.md @@ -1,8 +1,6 @@ # LoopVariable -![LoopVariable UML diagram](../../../tasks/Loop/v1.0.0/Loop.png) - -*(`LoopVariable` has no standalone diagram of its own - the image above is `Loop`'s diagram, reused here because `LoopVariable` is drawn fully within it as a linked box, right next to `Loop`. Look for the `LoopVariable` box.)* +![LoopVariable UML diagram](./LoopVariable.png) **Category:** auxiliary **Version:** v1 diff --git a/specsheets/auxiliary/WorkingAlgorithm/v1.0.0/description.md b/specsheets/auxiliary/WorkingAlgorithm/v1.0.0/description.md index 11d4979..05a8391 100644 --- a/specsheets/auxiliary/WorkingAlgorithm/v1.0.0/description.md +++ b/specsheets/auxiliary/WorkingAlgorithm/v1.0.0/description.md @@ -1,8 +1,6 @@ # WorkingAlgorithm -![WorkingAlgorithm UML diagram](../../../tasks/AbstractSimulation/v1.0.0/AbstractSimulation.png) - -*(`WorkingAlgorithm` has no standalone diagram of its own - the image above is `AbstractSimulation`'s diagram, reused here because `WorkingAlgorithm` is drawn fully within it as a linked box, right next to `AbstractSimulation`. Look for the `workingAlgorithm` box.)* +![WorkingAlgorithm UML diagram](./WorkingAlgorithm.png) **Category:** auxiliary **Version:** v1 @@ -10,7 +8,7 @@ ## What it does -An algorithm used internally by a simulation task, attached via `AbstractSimulation`'s `workingAlgorithms` list. Beyond the fields it inherits from `SEDBase`, it carries a required `algorithm`. +An algorithm used internally by a task, attached via a `workingAlgorithms` list: the one `AbstractSimulation` defines (and so every ODE/stochastic simulation task has), or the one `SteadyState` and `FluxBalanceAnalysis` each declare directly. Beyond the fields it inherits from `SEDBase`, it carries a required `algorithm`. _(No description yet - placeholder. It's not yet clear from the diagram alone how `algorithm` relates to the task's own `_type` discriminator and `taskParameters`, or how multiple `workingAlgorithms` entries on one task are meant to be distinguished/used - needs updating once that's settled.)_ diff --git a/specsheets/auxiliary/WorkingAlgorithm/v1.0.0/schema.json b/specsheets/auxiliary/WorkingAlgorithm/v1.0.0/schema.json index 5822a1d..c742094 100644 --- a/specsheets/auxiliary/WorkingAlgorithm/v1.0.0/schema.json +++ b/specsheets/auxiliary/WorkingAlgorithm/v1.0.0/schema.json @@ -4,7 +4,7 @@ "title": "SED2 WorkingAlgorithm", "$defs": { "WorkingAlgorithm": { - "description": "An algorithm used internally by a simulation task, referenced via AbstractSimulation's workingAlgorithms list. Inherits from SEDBase.", + "description": "An algorithm used internally by a task, listed in a workingAlgorithms list (AbstractSimulation, SteadyState, FluxBalanceAnalysis). Inherits from SEDBase.", "type": "object", "allOf": [ { diff --git a/specsheets/core/SEDBase/v1.0.0/validation/SEDBase-0008.md b/specsheets/core/SEDBase/v1.0.0/validation/SEDBase-0008.md index c873ca4..b5278dd 100644 --- a/specsheets/core/SEDBase/v1.0.0/validation/SEDBase-0008.md +++ b/specsheets/core/SEDBase/v1.0.0/validation/SEDBase-0008.md @@ -7,9 +7,10 @@ status: active check: handwritten --- -For a task target, the accessor must appear in that task class's outputs.json, -and its "valid" field must be true, or be an expression that evaluates to true -against the target's own fields. When the expression cannot be evaluated +For a task target, the accessor must be listed in that task class's outputs.json +(a suffix that is not listed is not valid), and, if the entry has a "valid" +field, that field's expression must evaluate to true against the target's own +fields. An entry with no "valid" field is always valid. When the expression cannot be evaluated statically (it depends on a reference that resolves only at run time), the rule does not fire. diff --git a/specsheets/tasks/AbstractSimulation/v1.0.0/AbstractSimulation.png b/specsheets/tasks/AbstractSimulation/v1.0.0/AbstractSimulation.png index 23c5186..1079d19 100644 Binary files a/specsheets/tasks/AbstractSimulation/v1.0.0/AbstractSimulation.png and b/specsheets/tasks/AbstractSimulation/v1.0.0/AbstractSimulation.png differ diff --git a/specsheets/tasks/AbstractSimulation/v1.0.0/description.md b/specsheets/tasks/AbstractSimulation/v1.0.0/description.md index 508ad4a..c0088ac 100644 --- a/specsheets/tasks/AbstractSimulation/v1.0.0/description.md +++ b/specsheets/tasks/AbstractSimulation/v1.0.0/description.md @@ -8,7 +8,7 @@ ## What it does -`AbstractSimulation` is a schema-only mixin (composed via `allOf`, not instantiated directly, no `_type` or diagram box of its own beyond the one shown here) contributing the fields shared by every ODE or stochastic simulation task, by way of `AbstractODESimulation` and `AbstractStochasticSimulation`. It replaces the earlier `SimulationCommon`, and (unlike `SimulationCommon`) is no longer used by `SteadyState` or `FluxBalanceAnalysis`, which now declare their own fields directly. +`AbstractSimulation` is a schema-only mixin (composed via `allOf`, not instantiated directly, no `_type` or diagram box of its own beyond the one shown here) contributing the fields shared by every ODE or stochastic simulation task, by way of `AbstractODESimulation` and `AbstractStochasticSimulation`. It replaces the earlier `SimulationCommon`, and (unlike `SimulationCommon`) is no longer used by `SteadyState` or `FluxBalanceAnalysis`, which now declare their own fields directly (including their own `workingAlgorithms` lists). Beyond the fields it inherits from `AbstractTask`, it contributes `model`, `independentVariable`, `independentVariableInit`, `outputVariables`, and `workingAlgorithms` - a list of `WorkingAlgorithm` entries describing the algorithm(s) used internally by the simulation. diff --git a/specsheets/tasks/AggregationCalculation/v1.0.0/outputs.json b/specsheets/tasks/AggregationCalculation/v1.0.0/outputs.json index 4e5fabb..204132d 100644 --- a/specsheets/tasks/AggregationCalculation/v1.0.0/outputs.json +++ b/specsheets/tasks/AggregationCalculation/v1.0.0/outputs.json @@ -1,19 +1,12 @@ { "outputs": { "[id]": { - "valid": true, "type": "annotatedData", "dimensions": { "source": "static", "expr": "shapeOf(input) - dim(appliedDimensions or outermost)", "note": "shape is input's shape with the dimension(s) named in appliedDimensions removed (or the outermost dimension, if appliedDimensions is unset); dimension count/sizes are therefore only as knowable as input's own shape is" } - }, - "[id].model": { - "valid": false - }, - "[id].strings": { - "valid": false } } } diff --git a/specsheets/tasks/BoundedODESimulation/v1.0.0/outputs.json b/specsheets/tasks/BoundedODESimulation/v1.0.0/outputs.json index a62ad2f..ae89839 100644 --- a/specsheets/tasks/BoundedODESimulation/v1.0.0/outputs.json +++ b/specsheets/tasks/BoundedODESimulation/v1.0.0/outputs.json @@ -1,7 +1,6 @@ { "outputs": { "[id]": { - "valid": true, "type": "annotatedData", "dimensions": [ { @@ -24,11 +23,7 @@ ] }, "[id].model": { - "valid": true, "type": "model" - }, - "[id].strings": { - "valid": false } } } diff --git a/specsheets/tasks/BoundedStochasticSimulation/v1.0.0/outputs.json b/specsheets/tasks/BoundedStochasticSimulation/v1.0.0/outputs.json index a62ad2f..ae89839 100644 --- a/specsheets/tasks/BoundedStochasticSimulation/v1.0.0/outputs.json +++ b/specsheets/tasks/BoundedStochasticSimulation/v1.0.0/outputs.json @@ -1,7 +1,6 @@ { "outputs": { "[id]": { - "valid": true, "type": "annotatedData", "dimensions": [ { @@ -24,11 +23,7 @@ ] }, "[id].model": { - "valid": true, "type": "model" - }, - "[id].strings": { - "valid": false } } } diff --git a/specsheets/tasks/Calculation/v1.0.0/outputs.json b/specsheets/tasks/Calculation/v1.0.0/outputs.json index f2d04e9..29c695b 100644 --- a/specsheets/tasks/Calculation/v1.0.0/outputs.json +++ b/specsheets/tasks/Calculation/v1.0.0/outputs.json @@ -1,15 +1,11 @@ { "outputs": { "[id]": { - "valid": true, "type": "annotatedData", "dimensions": { "source": "runtime", "note": "shape matches the evaluated math expression: scalar if every operand is scalar, otherwise broadcasts across the shape of any AnnotatedData operand(s); not derivable without evaluating math against the operands' actual values" } - }, - "[id].model": { - "valid": false } } } diff --git a/specsheets/tasks/CreateDataBlock/v1.0.0/outputs.json b/specsheets/tasks/CreateDataBlock/v1.0.0/outputs.json index a6777b5..f932295 100644 --- a/specsheets/tasks/CreateDataBlock/v1.0.0/outputs.json +++ b/specsheets/tasks/CreateDataBlock/v1.0.0/outputs.json @@ -1,7 +1,6 @@ { "outputs": { "[id]": { - "valid": true, "type": "annotatedData", "dimensions": [ { @@ -16,9 +15,6 @@ "note": "base case: one entry per key in the data dictionary. If a value in data is itself multi-dimensional (a list or AnnotatedData), that entry's own dimensions carry through instead - how mixed-dimension entries combine into one overall shape is an open design question (see core-spec.md Section 10), so this formula covers only the uniform-scalar-values case" } ] - }, - "[id].model": { - "valid": false } } } diff --git a/specsheets/tasks/CsvImport/v1.0.0/outputs.json b/specsheets/tasks/CsvImport/v1.0.0/outputs.json index c770299..6e6db57 100644 --- a/specsheets/tasks/CsvImport/v1.0.0/outputs.json +++ b/specsheets/tasks/CsvImport/v1.0.0/outputs.json @@ -1,7 +1,6 @@ { "outputs": { "[id]": { - "valid": true, "type": "annotatedData", "dimensions": [ { @@ -28,12 +27,6 @@ } } ] - }, - "[id].model": { - "valid": false - }, - "[id].strings": { - "valid": false } } } diff --git a/specsheets/tasks/DataImport/v1.0.0/outputs.json b/specsheets/tasks/DataImport/v1.0.0/outputs.json index 0372af2..f0f0d26 100644 --- a/specsheets/tasks/DataImport/v1.0.0/outputs.json +++ b/specsheets/tasks/DataImport/v1.0.0/outputs.json @@ -1,7 +1,6 @@ { "outputs": { "[id]": { - "valid": true, "type": "annotatedData", "dimensions": { "source": "input-file", @@ -9,9 +8,6 @@ "extract": "shape", "note": "shape is whatever the imported file itself has; depends on format and the file at location - extraction is format-specific (format names how to parse it)" } - }, - "[id].model": { - "valid": false } } } diff --git a/specsheets/tasks/DrawFromDistribution/v1.0.0/outputs.json b/specsheets/tasks/DrawFromDistribution/v1.0.0/outputs.json index 7c7498b..8215458 100644 --- a/specsheets/tasks/DrawFromDistribution/v1.0.0/outputs.json +++ b/specsheets/tasks/DrawFromDistribution/v1.0.0/outputs.json @@ -1,16 +1,9 @@ { "outputs": { "[id]": { - "valid": true, "type": "annotatedData", "dimensions": [], "note": "currently always a single scalar value (0-D), indexed historically as [id][0]; the type is multidimensional AnnotatedData to leave room for future correlated multi-value draws (shape of that future case is not yet designed - see core-spec.md Section 10)" - }, - "[id].model": { - "valid": false - }, - "[id].strings": { - "valid": false } } } diff --git a/specsheets/tasks/ExplicitODESimulation/v1.0.0/outputs.json b/specsheets/tasks/ExplicitODESimulation/v1.0.0/outputs.json index 581851e..f7f3b24 100644 --- a/specsheets/tasks/ExplicitODESimulation/v1.0.0/outputs.json +++ b/specsheets/tasks/ExplicitODESimulation/v1.0.0/outputs.json @@ -1,7 +1,6 @@ { "outputs": { "[id]": { - "valid": true, "type": "annotatedData", "dimensions": [ { @@ -24,11 +23,7 @@ ] }, "[id].model": { - "valid": true, "type": "model" - }, - "[id].strings": { - "valid": false } } } diff --git a/specsheets/tasks/ExplicitStochasticSimulation/v1.0.0/outputs.json b/specsheets/tasks/ExplicitStochasticSimulation/v1.0.0/outputs.json index 253d20c..fb495cf 100644 --- a/specsheets/tasks/ExplicitStochasticSimulation/v1.0.0/outputs.json +++ b/specsheets/tasks/ExplicitStochasticSimulation/v1.0.0/outputs.json @@ -1,7 +1,6 @@ { "outputs": { "[id]": { - "valid": true, "type": "annotatedData", "dimensions": [ { @@ -24,11 +23,7 @@ ] }, "[id].model": { - "valid": true, "type": "model" - }, - "[id].strings": { - "valid": false } } } diff --git a/specsheets/tasks/FluxBalanceAnalysis/v1.0.0/FluxBalanceAnalysis.png b/specsheets/tasks/FluxBalanceAnalysis/v1.0.0/FluxBalanceAnalysis.png index 58001ae..9e98777 100644 Binary files a/specsheets/tasks/FluxBalanceAnalysis/v1.0.0/FluxBalanceAnalysis.png and b/specsheets/tasks/FluxBalanceAnalysis/v1.0.0/FluxBalanceAnalysis.png differ diff --git a/specsheets/tasks/FluxBalanceAnalysis/v1.0.0/description.md b/specsheets/tasks/FluxBalanceAnalysis/v1.0.0/description.md index c5e2098..b58503d 100644 --- a/specsheets/tasks/FluxBalanceAnalysis/v1.0.0/description.md +++ b/specsheets/tasks/FluxBalanceAnalysis/v1.0.0/description.md @@ -11,7 +11,7 @@ Uses an objective function and reaction rate bounds (both defined within the model itself) to determine the set of reaction rates that maximizes the objective function. Unlike the other simulation tasks, FBA has no independent variable. -This is an implementation of KISAO:0000437 (FBA). +This is an implementation of KISAO:0000437 (FBA). The algorithm(s) it uses internally may be listed in the optional `workingAlgorithms` (see `WorkingAlgorithm`). ## Attributes @@ -22,7 +22,7 @@ All classes additionally inherit the optional `name`, `description`, `notes`, an | `taskParameters` | array of TaskParameter | no | | | `model` | SIdRef | yes | | | `outputVariables` | ListOfStringsOrRef | yes | | -| `outputModel` | BooleanOrRef | no | | +| `workingAlgorithms` | array of WorkingAlgorithm | no | | ### Attribute details @@ -32,16 +32,14 @@ All classes additionally inherit the optional `name`, `description`, `notes`, an **`outputVariables`** (ListOfStringsOrRef, required) - _(no description yet - placeholder, needs to be filled in)_ -**`outputModel`** (BooleanOrRef, optional) - _(no description yet - placeholder, needs to be filled in)_ +**`workingAlgorithms`** (array of WorkingAlgorithm, optional) - _(no description yet - placeholder, needs to be filled in)_ ## Outputs -A dictionary of model variables (usually fluxes) to their final values, accessible via `outputVariables` as `[id]` - analogous to a `SteadyState` result. If `outputModel` is `true`, the resulting model state is also available as `[id].model`. +A dictionary of model variables (usually fluxes) to their final values, accessible via `outputVariables` as `[id]` - analogous to a `SteadyState` result. The resulting model state is always also available as `[id].model`. - `[id]`: **Valid** - Dimensions: 1D: one value per entry of `outputVariables` (typically reaction fluxes) - length depends on how many variables are named there. - `[id].model`: **Valid** - `[id].strings`: **Invalid** - -`[id].model` is only produced when `outputModel` is `true`. diff --git a/specsheets/tasks/FluxBalanceAnalysis/v1.0.0/outputs.json b/specsheets/tasks/FluxBalanceAnalysis/v1.0.0/outputs.json index 4f46b01..7ec8171 100644 --- a/specsheets/tasks/FluxBalanceAnalysis/v1.0.0/outputs.json +++ b/specsheets/tasks/FluxBalanceAnalysis/v1.0.0/outputs.json @@ -1,7 +1,6 @@ { "outputs": { "[id]": { - "valid": true, "type": "annotatedData", "dimensions": [ { @@ -17,11 +16,7 @@ ] }, "[id].model": { - "valid": "outputModel == true", "type": "model" - }, - "[id].strings": { - "valid": false } } } diff --git a/specsheets/tasks/FluxBalanceAnalysis/v1.0.0/schema.json b/specsheets/tasks/FluxBalanceAnalysis/v1.0.0/schema.json index d7b7a76..9600c3f 100644 --- a/specsheets/tasks/FluxBalanceAnalysis/v1.0.0/schema.json +++ b/specsheets/tasks/FluxBalanceAnalysis/v1.0.0/schema.json @@ -4,7 +4,7 @@ "title": "SED2 FluxBalanceAnalysis", "$defs": { "FluxBalanceAnalysis": { - "description": "Flux balance analysis. kisaoID must be KISAO:0000437 (FBA) or a child.", + "description": "Flux balance analysis.", "type": "object", "allOf": [ { @@ -28,12 +28,12 @@ "FluxBalanceAnalysis-0005" ] }, - "outputModel": { - "$ref": "../../../core/Types/v1.0.0/schema.json#/$defs/BooleanOrRef", - "x-rule-id": [ - "FluxBalanceAnalysis-0006", - "FluxBalanceAnalysis-0007" - ] + "workingAlgorithms": { + "type": "array", + "items": { + "$ref": "../../../auxiliary/WorkingAlgorithm/v1.0.0/schema.json#/$defs/WorkingAlgorithm" + }, + "x-rule-id": "FluxBalanceAnalysis-0009" } }, "required": [ diff --git a/specsheets/tasks/FluxBalanceAnalysis/v1.0.0/validation/FluxBalanceAnalysis-0006.md b/specsheets/tasks/FluxBalanceAnalysis/v1.0.0/validation/FluxBalanceAnalysis-0006.md deleted file mode 100644 index 55822ac..0000000 --- a/specsheets/tasks/FluxBalanceAnalysis/v1.0.0/validation/FluxBalanceAnalysis-0006.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -id: FluxBalanceAnalysis-0006 -rule: When the value of outputModel of a FluxBalanceAnalysis is provided directly, it must be a boolean. -message: "Attribute '{attr}' of {class} '{id}' has value '{value}', which is not a boolean." -severity: error -status: active -check: schema ---- - -`outputModel` is `BooleanOrRef`: the value, when not a reference, must be a boolean. diff --git a/specsheets/tasks/FluxBalanceAnalysis/v1.0.0/validation/FluxBalanceAnalysis-0007.md b/specsheets/tasks/FluxBalanceAnalysis/v1.0.0/validation/FluxBalanceAnalysis-0007.md deleted file mode 100644 index fbb8693..0000000 --- a/specsheets/tasks/FluxBalanceAnalysis/v1.0.0/validation/FluxBalanceAnalysis-0007.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -id: FluxBalanceAnalysis-0007 -rule: When the value of outputModel of a FluxBalanceAnalysis is a reference, it must be a reference to a boolean. -message: "Attribute '{attr}' of {class} '{id}' is the reference '{value}', which resolves to '{resolved-value}', not a boolean." -severity: error -status: active -check: ref-type ---- - -`outputModel` is `BooleanOrRef`: when the value is a reference, it must resolve to a boolean. diff --git a/specsheets/tasks/JacobianFull/v1.0.0/outputs.json b/specsheets/tasks/JacobianFull/v1.0.0/outputs.json index 2bbc84e..ebe2013 100644 --- a/specsheets/tasks/JacobianFull/v1.0.0/outputs.json +++ b/specsheets/tasks/JacobianFull/v1.0.0/outputs.json @@ -1,7 +1,6 @@ { "outputs": { "[id]": { - "valid": true, "type": "annotatedData", "dimensions": [ { @@ -33,12 +32,6 @@ } } ] - }, - "[id].model": { - "valid": false - }, - "[id].strings": { - "valid": false } } } diff --git a/specsheets/tasks/JacobianReduced/v1.0.0/outputs.json b/specsheets/tasks/JacobianReduced/v1.0.0/outputs.json index 81aabf3..c307f77 100644 --- a/specsheets/tasks/JacobianReduced/v1.0.0/outputs.json +++ b/specsheets/tasks/JacobianReduced/v1.0.0/outputs.json @@ -1,7 +1,6 @@ { "outputs": { "[id]": { - "valid": true, "type": "annotatedData", "dimensions": [ { @@ -33,12 +32,6 @@ } } ] - }, - "[id].model": { - "valid": false - }, - "[id].strings": { - "valid": false } } } diff --git a/specsheets/tasks/Loop/v1.0.0/Loop.png b/specsheets/tasks/Loop/v1.0.0/Loop.png index 9665f07..599f904 100644 Binary files a/specsheets/tasks/Loop/v1.0.0/Loop.png and b/specsheets/tasks/Loop/v1.0.0/Loop.png differ diff --git a/specsheets/tasks/Loop/v1.0.0/description.md b/specsheets/tasks/Loop/v1.0.0/description.md index 3dbb5cf..46aaa26 100644 --- a/specsheets/tasks/Loop/v1.0.0/description.md +++ b/specsheets/tasks/Loop/v1.0.0/description.md @@ -9,7 +9,7 @@ ## What it does -A `Repeat` whose iterations are chained: each depends on the output of the previous one. This is expressed with `loopVariables` - named `LoopVariable` entries whose value equals `initialValue` on the first iteration and thereafter equals `subsequentValues` (an output of one of the loop's `subTasks`). A subTask references a loop variable as `#tasks:[loop_id]:loopVariables:[loopvar_id]`. +A `Repeat` whose iterations are chained: each depends on the output of the previous one, with one iteration per element of its required `range` (a `Range`/`NumericRange`/`ParameterRange`), taken in order; a `Loop` always runs all of them and cannot end early. The chaining is expressed with `loopVariables` - named `LoopVariable` entries whose value equals `initialValue` on the first iteration and thereafter equals `subsequentValues` (an output of one of the loop's `subTasks`). A subTask references a loop variable as `#tasks:[loop_id]:loopVariables:[loopvar_id]`. ## Attributes @@ -21,7 +21,7 @@ All classes additionally inherit the optional `name`, `description`, `notes`, an | `subTasks` | object (values: AbstractTask) | yes | | | `outputVariableMap` | object (values: SIdRef) or SIdRef | no | | | `aggregateOutputVariables` | object (values: AggregationCalculation) | no | | -| `range` | RangeInline | no | | +| `range` | RangeInline | yes | | | `loopVariables` | object (values: LoopVariable) | yes | | ### Attribute details @@ -34,7 +34,7 @@ All classes additionally inherit the optional `name`, `description`, `notes`, an **`aggregateOutputVariables`** (object (values: AggregationCalculation), optional) - _(no description yet - placeholder, needs to be filled in)_ -**`range`** (RangeInline, optional) - _(no description yet - placeholder, needs to be filled in)_ +**`range`** (RangeInline, required) - _(no description yet - placeholder, needs to be filled in)_ **`loopVariables`** (object (values: LoopVariable), required) - _(no description yet - placeholder, needs to be filled in)_ @@ -44,7 +44,7 @@ All classes additionally inherit the optional `name`, `description`, `notes`, an `[id]`: an `AnnotatedData` whose first column is the range values and whose subsequent columns follow `outputVariableMap`. `[id].aggregates`: an `AnnotatedData` following `aggregateOutputVariables`, when defined. - `[id]`: **Valid** - - Dimensions: 2D (or more): first dimension = one row per iteration; remaining dimension(s) = one column per entry of `outputVariableMap`. Unlike `Scatter`, the row count isn't known in advance from a `range` - it's however many iterations the loop actually runs. _(Exact termination condition for a Loop's iteration count - placeholder, needs to be filled in from the spec.)_ + - Dimensions: 2D (or more): first dimension = one row per value in `range`; remaining dimension(s) = one column per entry of `outputVariableMap` (or just the range-values column alone, if `outputVariableMap` is empty). As with `Scatter`, the row count is known in advance from `range`. A column whose subTask output is itself multi-dimensional would add further dimensions - not pinned down further here. - `[id].model`: **Invalid** - `[id].strings`: **Invalid** @@ -53,7 +53,7 @@ Additional possible outputs beyond the three standard ones: - `[id].aggregates`: An `AnnotatedData` following `aggregateOutputVariables`, when that attribute is defined. - Dimensions: 1D: one entry per `aggregateOutputVariables` mapping, each collapsing the iteration dimension of `[id]` down to a single value (per `Repeat`, the applied dimension defaults to the Repeat's own iterations) - unless the underlying subTask output was itself multi-dimensional, in which case that dimensionality carries through per entry. -- `[id].range`: Within the loop, the current value of `range`, when `range` is defined (see `Repeat`). +- `[id].range`: Within the loop, the current value of `range`. Always valid, since `range` is required. - Dimensions: Scalar (0-D) per iteration. -- `[id].index`: Within the loop, the current index into `range`, when `range` is defined. +- `[id].index`: Within the loop, the current index into `range`. Always valid. - Dimensions: Scalar (0-D) per iteration. diff --git a/specsheets/tasks/Loop/v1.0.0/outputs.json b/specsheets/tasks/Loop/v1.0.0/outputs.json index d7f34a4..95aee2f 100644 --- a/specsheets/tasks/Loop/v1.0.0/outputs.json +++ b/specsheets/tasks/Loop/v1.0.0/outputs.json @@ -1,18 +1,25 @@ { "outputs": { "[id]": { - "valid": true, "type": "annotatedData", - "dimensions": { - "source": "runtime", - "note": "2D or more: first dimension = one row per iteration (iteration count is not knowable ahead of the loop actually running - Loop's exact termination condition is an open design question, see core-spec.md Section 10); remaining dimension(s) = one column per entry of outputVariableMap" - } - }, - "[id].model": { - "valid": false - }, - "[id].strings": { - "valid": false + "dimensions": [ + { + "size": { + "source": "static", + "expr": "len(range)" + }, + "labels": null, + "note": "one row per value in range; len(range) dispatches on range's actual Range/NumericRange/ParameterRange type" + }, + { + "size": { + "source": "static", + "expr": "len(outputVariableMap)" + }, + "labels": null, + "note": "one column per entry of outputVariableMap, or just the range-values column alone if outputVariableMap is empty; a column whose subTask output is itself multi-dimensional would add further dimensions beyond this, not captured here" + } + ] }, "[id].aggregates": { "valid": "provided(aggregateOutputVariables)", @@ -29,13 +36,11 @@ ] }, "[id].range": { - "valid": "provided(range)", "type": "annotatedData", "dimensions": [], "note": "the current value of range, within the loop" }, "[id].index": { - "valid": "provided(range)", "type": "annotatedData", "dimensions": [], "note": "the current index into range, within the loop" diff --git a/specsheets/tasks/Loop/v1.0.0/schema.json b/specsheets/tasks/Loop/v1.0.0/schema.json index 2d4e9a8..cac92e1 100644 --- a/specsheets/tasks/Loop/v1.0.0/schema.json +++ b/specsheets/tasks/Loop/v1.0.0/schema.json @@ -25,16 +25,22 @@ "$ref": "../../../auxiliary/LoopVariable/v1.0.0/schema.json#/$defs/LoopVariable" }, "x-rule-id": "Loop-0003" + }, + "range": { + "$ref": "../../../tasks/Range/v1.0.0/inline.schema.json#/$defs/RangeInline", + "x-rule-id": "Loop-0007" } }, "required": [ "_type", "subTasks", - "loopVariables" + "loopVariables", + "range" ], "x-required-rule-ids": { "subTasks": "Loop-0001", - "loopVariables": "Loop-0002" + "loopVariables": "Loop-0002", + "range": "Loop-0006" }, "unevaluatedProperties": false } diff --git a/specsheets/tasks/ModelChange/v1.0.0/outputs.json b/specsheets/tasks/ModelChange/v1.0.0/outputs.json index 5b3b00f..6440bd5 100644 --- a/specsheets/tasks/ModelChange/v1.0.0/outputs.json +++ b/specsheets/tasks/ModelChange/v1.0.0/outputs.json @@ -1,14 +1,7 @@ { "outputs": { - "[id]": { - "valid": false - }, "[id].model": { - "valid": true, "type": "model" - }, - "[id].strings": { - "valid": false } } } diff --git a/specsheets/tasks/ModelElementList/v1.0.0/outputs.json b/specsheets/tasks/ModelElementList/v1.0.0/outputs.json index 1c33e4f..6a4fe36 100644 --- a/specsheets/tasks/ModelElementList/v1.0.0/outputs.json +++ b/specsheets/tasks/ModelElementList/v1.0.0/outputs.json @@ -1,13 +1,6 @@ { "outputs": { - "[id]": { - "valid": false - }, - "[id].model": { - "valid": false - }, "[id].strings": { - "valid": true, "type": "stringList", "dimensions": [ { diff --git a/specsheets/tasks/ModelImport/v1.0.0/outputs.json b/specsheets/tasks/ModelImport/v1.0.0/outputs.json index 5b3b00f..6440bd5 100644 --- a/specsheets/tasks/ModelImport/v1.0.0/outputs.json +++ b/specsheets/tasks/ModelImport/v1.0.0/outputs.json @@ -1,14 +1,7 @@ { "outputs": { - "[id]": { - "valid": false - }, "[id].model": { - "valid": true, "type": "model" - }, - "[id].strings": { - "valid": false } } } diff --git a/specsheets/tasks/NumericRange/v1.0.0/outputs.json b/specsheets/tasks/NumericRange/v1.0.0/outputs.json index e313e17..4eecff0 100644 --- a/specsheets/tasks/NumericRange/v1.0.0/outputs.json +++ b/specsheets/tasks/NumericRange/v1.0.0/outputs.json @@ -1,7 +1,6 @@ { "outputs": { "[id]": { - "valid": true, "type": "annotatedData", "dimensions": [ { @@ -12,12 +11,6 @@ "labels": null } ] - }, - "[id].model": { - "valid": false - }, - "[id].strings": { - "valid": false } } } diff --git a/specsheets/tasks/OneStepODESimulation/v1.0.0/outputs.json b/specsheets/tasks/OneStepODESimulation/v1.0.0/outputs.json index 300a0b9..70693f4 100644 --- a/specsheets/tasks/OneStepODESimulation/v1.0.0/outputs.json +++ b/specsheets/tasks/OneStepODESimulation/v1.0.0/outputs.json @@ -1,7 +1,6 @@ { "outputs": { "[id]": { - "valid": true, "type": "annotatedData", "dimensions": [ { @@ -18,11 +17,7 @@ ] }, "[id].model": { - "valid": true, "type": "model" - }, - "[id].strings": { - "valid": false } } } diff --git a/specsheets/tasks/OneStepStochasticSimulation/v1.0.0/OneStepStochasticSimulation.png b/specsheets/tasks/OneStepStochasticSimulation/v1.0.0/OneStepStochasticSimulation.png index fd9d7ab..4e3eccb 100644 Binary files a/specsheets/tasks/OneStepStochasticSimulation/v1.0.0/OneStepStochasticSimulation.png and b/specsheets/tasks/OneStepStochasticSimulation/v1.0.0/OneStepStochasticSimulation.png differ diff --git a/specsheets/tasks/OneStepStochasticSimulation/v1.0.0/outputs.json b/specsheets/tasks/OneStepStochasticSimulation/v1.0.0/outputs.json index f747ea2..6831be1 100644 --- a/specsheets/tasks/OneStepStochasticSimulation/v1.0.0/outputs.json +++ b/specsheets/tasks/OneStepStochasticSimulation/v1.0.0/outputs.json @@ -1,7 +1,6 @@ { "outputs": { "[id]": { - "valid": true, "type": "annotatedData", "dimensions": [ { @@ -18,12 +17,8 @@ ] }, "[id].model": { - "valid": true, "type": "model" }, - "[id].strings": { - "valid": false - }, "[id].independentStep": { "valid": "!provided(independentStep)", "type": "annotatedData", diff --git a/specsheets/tasks/ParameterRange/v1.0.0/outputs.json b/specsheets/tasks/ParameterRange/v1.0.0/outputs.json index 0d93fa0..91c52b0 100644 --- a/specsheets/tasks/ParameterRange/v1.0.0/outputs.json +++ b/specsheets/tasks/ParameterRange/v1.0.0/outputs.json @@ -1,7 +1,6 @@ { "outputs": { "[id]": { - "valid": true, "type": "annotatedData", "dimensions": [ { @@ -13,12 +12,6 @@ "labels": null } ] - }, - "[id].model": { - "valid": false - }, - "[id].strings": { - "valid": false } } } diff --git a/specsheets/tasks/ParameterScan/v1.0.0/ParameterScan.png b/specsheets/tasks/ParameterScan/v1.0.0/ParameterScan.png index 793ccef..87c633b 100644 Binary files a/specsheets/tasks/ParameterScan/v1.0.0/ParameterScan.png and b/specsheets/tasks/ParameterScan/v1.0.0/ParameterScan.png differ diff --git a/specsheets/tasks/ParameterScan/v1.0.0/description.md b/specsheets/tasks/ParameterScan/v1.0.0/description.md index 8e02f0c..e74b984 100644 --- a/specsheets/tasks/ParameterScan/v1.0.0/description.md +++ b/specsheets/tasks/ParameterScan/v1.0.0/description.md @@ -9,7 +9,7 @@ ## What it does -Runs simulations/analyses over several systematically-varied versions of a model: a `Repeat` subclass that adds a `model` child (the model to scan) and one or more `ParameterRange` children (`parameterRanges`) - each scanned element adds a dimension to the output. Each `ParameterRange` must target a distinct `modelElement`, which must be an id within the child `model`. One of the `subTasks` must reference the scan's `model` child (`#tasks:[scanid]:model`) as its own input; the model is initialized with every combination of values across all the ranges. Mechanically it's otherwise identical to `Scatter`, and could in principle be reproduced with nested `Scatter`s plus careful `ModelChange` tasks. +Runs simulations/analyses over several systematically-varied versions of a model: a `Repeat` subclass that adds a `model` child (the model to scan) and one or more `ParameterRange` children (`parameterRanges`) - each scanned element adds a dimension to the output. Each `ParameterRange` must target a distinct `modelElement` (ParameterScan-0007), which must be an id within the child `model`; the `modelElement` also serves as the entry's name in `[id].ranges` and `[id].indexes`. One of the `subTasks` must reference the scan's `model` child (`#tasks:[scanid]:model`) as its own input; the model is initialized with every combination of values across all the ranges. Mechanically it's otherwise identical to `Scatter`, and could in principle be reproduced with nested `Scatter`s plus careful `ModelChange` tasks. Within the loop, the current value and index of each range are available as `[id].ranges` and `[id].indexes` (see Outputs below). ## Attributes @@ -36,7 +36,7 @@ All classes additionally inherit the optional `name`, `description`, `notes`, an **`model`** (SIdRef, required) - _(no description yet - placeholder, needs to be filled in)_ -**`parameterRanges`** (array of ParameterRangeInline, required) - _(no description yet - placeholder, needs to be filled in)_ +**`parameterRanges`** (array of ParameterRangeInline, required) - The ranges to scan; at least one. The `modelElement` of each entry must be distinct within the scan (ParameterScan-0007), and labels that entry in `[id].ranges` and `[id].indexes`. ## Outputs @@ -44,7 +44,7 @@ All classes additionally inherit the optional `name`, `description`, `notes`, an `[id]`: an `AnnotatedData` with one dimension per entry of `parameterRanges`, plus one further dimension sized by the number of entries in `outputVariableMap`. `[id].aggregates`: an `AnnotatedData` following `aggregateOutputVariables`, when defined. - `[id]`: **Valid** - - Dimensions: N-D: one dimension per entry in `parameterRanges` (each sized by that range's own number of steps), plus one further dimension sized by the number of entries in `outputVariableMap` - dimensionality grows with the number of ranges scanned. + - Dimensions: N-D: one dimension per entry in `parameterRanges` (each sized by that range's own number of steps, and each labeled with that range's `modelElement`), plus one further dimension sized by the number of entries in `outputVariableMap` - dimensionality grows with the number of ranges scanned. - `[id].model`: **Invalid** - `[id].strings`: **Invalid** @@ -52,3 +52,8 @@ Additional possible outputs beyond the three standard ones: - `[id].aggregates`: An `AnnotatedData` following `aggregateOutputVariables`, when that attribute is defined. - Dimensions: 1D: one entry per `aggregateOutputVariables` mapping. Each entry's aggregation collapses *all* of `[id]`'s scanned-range dimensions together (per `Repeat`, the applied dimension defaults to 'the Repeat' itself - here, the whole combined scan) down to a single value - unless the underlying subTask output was itself multi-dimensional, in which case that dimensionality carries through per entry. + +- `[id].ranges`: Within the loop only, the current value of each of the scan's `parameterRanges`. + - Dimensions: 1D `AnnotatedData`: one entry per `ParameterRange` child, in order, labeled with that child's `modelElement`. For example, with children whose `modelElement`s are `calc`, `phos`, and `ant`, it holds the current values of `calc`, `phos`, and `ant`, in that order, labeled accordingly. +- `[id].indexes`: Within the loop only, the current index into each of the scan's `parameterRanges`. + - Dimensions: 1D `AnnotatedData`: one entry per `ParameterRange` child, in order, labeled with that child's `modelElement` - the current index of `calc`, `phos`, and `ant`, in that order, in the example above. diff --git a/specsheets/tasks/ParameterScan/v1.0.0/outputs.json b/specsheets/tasks/ParameterScan/v1.0.0/outputs.json index e0c28c1..1aa0b90 100644 --- a/specsheets/tasks/ParameterScan/v1.0.0/outputs.json +++ b/specsheets/tasks/ParameterScan/v1.0.0/outputs.json @@ -1,7 +1,6 @@ { "outputs": { "[id]": { - "valid": true, "type": "annotatedData", "dimensions": [ { @@ -11,8 +10,11 @@ "source": "static", "expr": "len(self)" }, - "labels": null, - "note": "one dimension per entry of parameterRanges, each sized by that entry's own length; len(self) dispatches on the entry's actual Range/NumericRange/ParameterRange type - see core-spec.md Section 8" + "labels": { + "source": "static", + "expr": "modelElement" + }, + "note": "one dimension per entry of parameterRanges, each sized by that entry's own length; len(self) dispatches on the entry's actual Range/NumericRange/ParameterRange type - see core-spec.md Section 8; each dimension is labeled with (identified by) that entry's modelElement, in parameterRanges order" } }, { @@ -24,12 +26,6 @@ } ] }, - "[id].model": { - "valid": false - }, - "[id].strings": { - "valid": false - }, "[id].aggregates": { "valid": "provided(aggregateOutputVariables)", "type": "annotatedData", @@ -42,6 +38,40 @@ "labels": null } ] + }, + "[id].ranges": { + "type": "annotatedData", + "dimensions": [ + { + "size": { + "source": "static", + "expr": "len(parameterRanges)" + }, + "labels": { + "source": "static", + "expr": "parameterRanges.modelElement" + }, + "note": "one entry per ParameterRange child, in order, labeled with that child's modelElement (parameterRanges.modelElement is the modelElement of each entry, in order)" + } + ], + "note": "the current value of each entry of parameterRanges, within the loop only" + }, + "[id].indexes": { + "type": "annotatedData", + "dimensions": [ + { + "size": { + "source": "static", + "expr": "len(parameterRanges)" + }, + "labels": { + "source": "static", + "expr": "parameterRanges.modelElement" + }, + "note": "one entry per ParameterRange child, in order, labeled with that child's modelElement (parameterRanges.modelElement is the modelElement of each entry, in order)" + } + ], + "note": "the current index into each entry of parameterRanges, within the loop only" } } } diff --git a/specsheets/tasks/Range/v1.0.0/outputs.json b/specsheets/tasks/Range/v1.0.0/outputs.json index 3246fa3..dad7d33 100644 --- a/specsheets/tasks/Range/v1.0.0/outputs.json +++ b/specsheets/tasks/Range/v1.0.0/outputs.json @@ -1,7 +1,6 @@ { "outputs": { "[id]": { - "valid": true, "type": "annotatedData", "dimensions": [ { @@ -12,12 +11,6 @@ "labels": null } ] - }, - "[id].model": { - "valid": false - }, - "[id].strings": { - "valid": false } } } diff --git a/specsheets/tasks/RelabelData/v1.0.0/outputs.json b/specsheets/tasks/RelabelData/v1.0.0/outputs.json index 7b8f657..150a7fb 100644 --- a/specsheets/tasks/RelabelData/v1.0.0/outputs.json +++ b/specsheets/tasks/RelabelData/v1.0.0/outputs.json @@ -1,16 +1,12 @@ { "outputs": { "[id]": { - "valid": true, "type": "annotatedData", "dimensions": { "source": "static", "expr": "shapeOf(input)", "note": "same dimensions as the referenced input AnnotatedData - this task only replaces the topmost dimension's labels (from labels), not the shape" } - }, - "[id].model": { - "valid": false } } } diff --git a/specsheets/tasks/Repeat/v1.0.0/Repeat.png b/specsheets/tasks/Repeat/v1.0.0/Repeat.png index 1eead83..7021cf1 100644 Binary files a/specsheets/tasks/Repeat/v1.0.0/Repeat.png and b/specsheets/tasks/Repeat/v1.0.0/Repeat.png differ diff --git a/specsheets/tasks/Repeat/v1.0.0/description.md b/specsheets/tasks/Repeat/v1.0.0/description.md index d8d9e88..3fc493f 100644 --- a/specsheets/tasks/Repeat/v1.0.0/description.md +++ b/specsheets/tasks/Repeat/v1.0.0/description.md @@ -10,11 +10,11 @@ Like SED-ML Level 1's RepeatedTask, SED2 needs to repeat a group of tasks multiple times. `Repeat` is the set of fields shared by all three concrete subclasses (`Scatter`, `Loop`, `ParameterScan`), composed via `allOf` rather than instantiated on its own - the prose spec calls this abstract concept simply "Repeat". -The repeat's `subTasks` are true children (not references) of the parent, and may depend on each other, on outputs of tasks outside the repeat, or on the repeat's own `range`/`index` (the current iteration's range value and position, available as `[id].range`/`[id].index` - see Outputs below). `outputVariableMap` defines the columns of the repeat's own `[id]` output: the first column is always the range values, and each further named entry maps an output column name to a value produced by a subTask; if empty, `[id]` contains only the range values. `aggregateOutputVariables` defines the columns of `[id].aggregates` - used to efficiently collect running summary statistics (e.g. mean/stdev) across a very large number of repeats without keeping every individual run's output; entries here may not define their own `appliedDimensions` (the applied dimension is always 'the Repeat' itself), and each `input` must reference a subTask's output. +The repeat's `subTasks` are true children (not references) of the parent, and may depend on each other, on outputs of tasks outside the repeat, or on the repeat's own per-iteration outputs (the current iteration's range value and position: `[id].range`/`[id].index` for `Scatter` and `Loop`, `[id].ranges`/`[id].indexes` for `ParameterScan` - see those classes). `outputVariableMap` (optional) defines the columns of the repeat's own `[id]` output: each named entry maps an output column name to a value produced by a subTask. `Scatter` and `Loop` additionally make the first column the range values, so for them `[id]` contains only the range values if `outputVariableMap` is omitted; see each subclass for its exact `[id]` shape. `aggregateOutputVariables` defines the columns of `[id].aggregates` - used to efficiently collect running summary statistics (e.g. mean/stdev) across a very large number of repeats without keeping every individual run's output; entries here may not define their own `appliedDimensions` (the applied dimension is always 'the Repeat' itself), and each `input` must reference a subTask's output. A `Repeat`-derived task must define at least one of `outputVariableMap` or `aggregateOutputVariables`. -`range` (a `Range`/`NumericRange`/`ParameterRange`) is shared here rather than being redefined separately on each subclass - `Loop` and `Scatter` both use it directly; `ParameterScan` does not (it uses `parameterRanges` instead). +`Repeat` itself has no `range`: `Loop` and `Scatter` each define their own required `range` child (a `Range`/`NumericRange`/`ParameterRange`), and `ParameterScan` uses `parameterRanges` instead. ## Attributes @@ -23,9 +23,8 @@ All classes additionally inherit the optional `name`, `description`, `notes`, an | Attribute | Type | Required | Notes | |---|---|---|---| | `subTasks` | object (values: AbstractTask) | no | | -| `outputVariableMap` | object (values: SIdRef) or SIdRef | no | | +| `outputVariableMap` | object (values: SIdRef) or SIdRef | no | Optional, but at least one of this or `aggregateOutputVariables` must be provided (Repeat-0006). | | `aggregateOutputVariables` | object (values: AggregationCalculation) | no | | -| `range` | RangeInline | no | Used by `Loop`/`Scatter`; not used by `ParameterScan` (see `parameterRanges` there instead). | ### Attribute details @@ -35,14 +34,9 @@ All classes additionally inherit the optional `name`, `description`, `notes`, an **`aggregateOutputVariables`** (object (values: AggregationCalculation), optional) - _(no description yet - placeholder, needs to be filled in)_ -**`range`** (RangeInline, optional) - _(no description yet - placeholder, needs to be filled in)_ - ## Outputs -Not applicable on its own - see `Scatter`, `Loop`, and `ParameterScan` for their concrete output shapes (`[id]` per `outputVariableMap`, `[id].aggregates` per `aggregateOutputVariables`). - -- `[id].range`: Within the loop, the current value of `range`. _(No description yet - placeholder, needs to be filled in: exact reference form and availability when `range` is unset.)_ -- `[id].index`: Within the loop, the current index into `range`. _(No description yet - placeholder, needs to be filled in.)_ +Not applicable on its own - see `Scatter`, `Loop`, and `ParameterScan` for their concrete output shapes (`[id]` per `outputVariableMap`, `[id].aggregates` per `aggregateOutputVariables`). The per-iteration range outputs (`[id].range`/`[id].index` on `Scatter` and `Loop`, `[id].ranges`/`[id].indexes` on `ParameterScan`) belong to those subclasses, not to `Repeat`. Shared mixin for the three `Repeat` subclasses - not instantiated on its own; see `Scatter`, `Loop`, `ParameterScan`. diff --git a/specsheets/tasks/Repeat/v1.0.0/schema.json b/specsheets/tasks/Repeat/v1.0.0/schema.json index 64c4a57..91c6a06 100644 --- a/specsheets/tasks/Repeat/v1.0.0/schema.json +++ b/specsheets/tasks/Repeat/v1.0.0/schema.json @@ -51,10 +51,6 @@ "$ref": "../../../tasks/AggregationCalculation/v1.0.0/schema.json#/$defs/AggregationCalculation" }, "x-rule-id": "Repeat-0004" - }, - "range": { - "$ref": "../../../tasks/Range/v1.0.0/inline.schema.json#/$defs/RangeInline", - "x-rule-id": "Repeat-0005" } }, "anyOf": [ diff --git a/specsheets/tasks/Repeat/v1.0.0/validation/Repeat-0005.md b/specsheets/tasks/Repeat/v1.0.0/validation/Repeat-0005.md deleted file mode 100644 index b78d18f..0000000 --- a/specsheets/tasks/Repeat/v1.0.0/validation/Repeat-0005.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -id: Repeat-0005 -rule: The range attribute of a Repeat, if present, must be a RangeInline object. -message: "Attribute '{attr}' of {class} '{id}' has value '{value}', which is not a RangeInline object." -severity: error -status: active -check: schema ---- - -`range` is optional; when present, it must be a `Range`/`NumericRange`/`ParameterRange` object in its embedded `RangeInline` form. diff --git a/specsheets/tasks/Scatter/v1.0.0/Scatter.png b/specsheets/tasks/Scatter/v1.0.0/Scatter.png index da5c874..cbb43fe 100644 Binary files a/specsheets/tasks/Scatter/v1.0.0/Scatter.png and b/specsheets/tasks/Scatter/v1.0.0/Scatter.png differ diff --git a/specsheets/tasks/Scatter/v1.0.0/description.md b/specsheets/tasks/Scatter/v1.0.0/description.md index c2cde82..2492e2c 100644 --- a/specsheets/tasks/Scatter/v1.0.0/description.md +++ b/specsheets/tasks/Scatter/v1.0.0/description.md @@ -9,7 +9,7 @@ ## What it does -A `Repeat` whose iterations are guaranteed fully independent of one another - no subTask output from one iteration feeds into another - so a conforming interpreter may execute the iterations in parallel if it chooses. `range` (a `Range`/`NumericRange`/`ParameterRange`) defines one iteration per element. +A `Repeat` whose iterations are guaranteed fully independent of one another - no subTask output from one iteration feeds into another - so a conforming interpreter may execute the iterations in parallel if it chooses. `range` (a required `Range`/`NumericRange`/`ParameterRange` child) defines one iteration per element. ## Attributes @@ -21,7 +21,7 @@ All classes additionally inherit the optional `name`, `description`, `notes`, an | `subTasks` | object (values: AbstractTask) | yes | | | `outputVariableMap` | object (values: SIdRef) or SIdRef | no | | | `aggregateOutputVariables` | object (values: AggregationCalculation) | no | | -| `range` | RangeInline | no | | +| `range` | RangeInline | yes | | ### Attribute details @@ -33,7 +33,7 @@ All classes additionally inherit the optional `name`, `description`, `notes`, an **`aggregateOutputVariables`** (object (values: AggregationCalculation), optional) - _(no description yet - placeholder, needs to be filled in)_ -**`range`** (RangeInline, optional) - _(no description yet - placeholder, needs to be filled in)_ +**`range`** (RangeInline, required) - _(no description yet - placeholder, needs to be filled in)_ ## Outputs @@ -50,7 +50,7 @@ Additional possible outputs beyond the three standard ones: - `[id].aggregates`: An `AnnotatedData` following `aggregateOutputVariables`, when that attribute is defined. - Dimensions: 1D: one entry per `aggregateOutputVariables` mapping. Each entry's aggregation function collapses the `range` dimension of `[id]` (per `Repeat`, the applied dimension defaults to 'the Repeat' itself, i.e. this one) down to a single value - unless the underlying subTask output was itself multi-dimensional, in which case that dimensionality carries through per entry. -- `[id].range`: Within each iteration, the current value of `range` (see `Repeat`). +- `[id].range`: Within each iteration, the current value of `range`. Always valid, since `range` is required. - Dimensions: Scalar (0-D) per iteration. -- `[id].index`: Within each iteration, the current index into `range`. +- `[id].index`: Within each iteration, the current index into `range`. Always valid. - Dimensions: Scalar (0-D) per iteration. diff --git a/specsheets/tasks/Scatter/v1.0.0/outputs.json b/specsheets/tasks/Scatter/v1.0.0/outputs.json index c3efb9e..6f73d87 100644 --- a/specsheets/tasks/Scatter/v1.0.0/outputs.json +++ b/specsheets/tasks/Scatter/v1.0.0/outputs.json @@ -1,7 +1,6 @@ { "outputs": { "[id]": { - "valid": true, "type": "annotatedData", "dimensions": [ { @@ -22,12 +21,6 @@ } ] }, - "[id].model": { - "valid": false - }, - "[id].strings": { - "valid": false - }, "[id].aggregates": { "valid": "provided(aggregateOutputVariables)", "type": "annotatedData", @@ -43,13 +36,11 @@ ] }, "[id].range": { - "valid": "provided(range)", "type": "annotatedData", "dimensions": [], "note": "the current value of range, within each iteration" }, "[id].index": { - "valid": "provided(range)", "type": "annotatedData", "dimensions": [], "note": "the current index into range, within each iteration" diff --git a/specsheets/tasks/Scatter/v1.0.0/schema.json b/specsheets/tasks/Scatter/v1.0.0/schema.json index ef38356..b4b3175 100644 --- a/specsheets/tasks/Scatter/v1.0.0/schema.json +++ b/specsheets/tasks/Scatter/v1.0.0/schema.json @@ -15,14 +15,20 @@ "_type": { "const": "scatter", "x-rule-id": "Scatter-0003" + }, + "range": { + "$ref": "../../../tasks/Range/v1.0.0/inline.schema.json#/$defs/RangeInline", + "x-rule-id": "Scatter-0005" } }, "required": [ "_type", - "subTasks" + "subTasks", + "range" ], "x-required-rule-ids": { - "subTasks": "Scatter-0001" + "subTasks": "Scatter-0001", + "range": "Scatter-0004" }, "unevaluatedProperties": false } diff --git a/specsheets/tasks/Span/v1.0.0/outputs.json b/specsheets/tasks/Span/v1.0.0/outputs.json index 058a3b6..e5af762 100644 --- a/specsheets/tasks/Span/v1.0.0/outputs.json +++ b/specsheets/tasks/Span/v1.0.0/outputs.json @@ -1,13 +1,3 @@ { - "outputs": { - "[id]": { - "valid": false - }, - "[id].model": { - "valid": false - }, - "[id].strings": { - "valid": false - } - } + "outputs": {} } diff --git a/specsheets/tasks/SteadyState/v1.0.0/SteadyState.png b/specsheets/tasks/SteadyState/v1.0.0/SteadyState.png index 95dcaa2..dbe56d2 100644 Binary files a/specsheets/tasks/SteadyState/v1.0.0/SteadyState.png and b/specsheets/tasks/SteadyState/v1.0.0/SteadyState.png differ diff --git a/specsheets/tasks/SteadyState/v1.0.0/description.md b/specsheets/tasks/SteadyState/v1.0.0/description.md index 32faacf..43a8539 100644 --- a/specsheets/tasks/SteadyState/v1.0.0/description.md +++ b/specsheets/tasks/SteadyState/v1.0.0/description.md @@ -11,7 +11,7 @@ Computes the steady state of a model: where dX/dt = 0 for every varying element X of the model, with respect to the independent variable (usually time). `independentVariable` follows the same rules as the simulation tasks (either the model's own variable, or an implicit URN such as `urn:sedml:symbol:time`). -This is an implementation of KISAO:0000407 (steady-state root-finding method). +This is an implementation of KISAO:0000407 (steady-state root-finding method). The algorithm(s) it uses internally may be listed in the optional `workingAlgorithms` (see `WorkingAlgorithm`). ## Attributes @@ -23,7 +23,7 @@ All classes additionally inherit the optional `name`, `description`, `notes`, an | `model` | SIdRef | yes | | | `independentVariable` | StringOrRef | no | | | `outputVariables` | ListOfStringsOrRef | yes | | -| `outputModel` | BooleanOrRef | no | | +| `workingAlgorithms` | array of WorkingAlgorithm | no | | ### Attribute details @@ -35,16 +35,14 @@ All classes additionally inherit the optional `name`, `description`, `notes`, an **`outputVariables`** (ListOfStringsOrRef, required) - _(no description yet - placeholder, needs to be filled in)_ -**`outputModel`** (BooleanOrRef, optional) - _(no description yet - placeholder, needs to be filled in)_ +**`workingAlgorithms`** (array of WorkingAlgorithm, optional) - _(no description yet - placeholder, needs to be filled in)_ ## Outputs -The steady-state values of `outputVariables`, accessible as `[id]`. If `outputModel` is `true`, the resulting model state is also available as `[id].model`. +The steady-state values of `outputVariables`, accessible as `[id]`. The resulting model state is always also available as `[id].model`. - `[id]`: **Valid** - Dimensions: 1D: one value per entry of `outputVariables`, at steady state. - `[id].model`: **Valid** - `[id].strings`: **Invalid** - -`[id].model` is only produced when `outputModel` is `true`. diff --git a/specsheets/tasks/SteadyState/v1.0.0/outputs.json b/specsheets/tasks/SteadyState/v1.0.0/outputs.json index 4f46b01..7ec8171 100644 --- a/specsheets/tasks/SteadyState/v1.0.0/outputs.json +++ b/specsheets/tasks/SteadyState/v1.0.0/outputs.json @@ -1,7 +1,6 @@ { "outputs": { "[id]": { - "valid": true, "type": "annotatedData", "dimensions": [ { @@ -17,11 +16,7 @@ ] }, "[id].model": { - "valid": "outputModel == true", "type": "model" - }, - "[id].strings": { - "valid": false } } } diff --git a/specsheets/tasks/SteadyState/v1.0.0/schema.json b/specsheets/tasks/SteadyState/v1.0.0/schema.json index 8ba2e3e..4f60d0c 100644 --- a/specsheets/tasks/SteadyState/v1.0.0/schema.json +++ b/specsheets/tasks/SteadyState/v1.0.0/schema.json @@ -4,7 +4,7 @@ "title": "SED2 SteadyState", "$defs": { "SteadyState": { - "description": "Compute the steady state of a model. kisaoID must be KISAO:0000407 or a child.", + "description": "Compute the steady state of a model.", "type": "object", "allOf": [ { @@ -27,12 +27,12 @@ "outputVariables": { "$ref": "../../../core/Types/v1.0.0/schema.json#/$defs/ListOfStringsOrRef" }, - "outputModel": { - "$ref": "../../../core/Types/v1.0.0/schema.json#/$defs/BooleanOrRef", - "x-rule-id": [ - "SteadyState-0005", - "SteadyState-0006" - ] + "workingAlgorithms": { + "type": "array", + "items": { + "$ref": "../../../auxiliary/WorkingAlgorithm/v1.0.0/schema.json#/$defs/WorkingAlgorithm" + }, + "x-rule-id": "SteadyState-0007" } }, "required": [ diff --git a/specsheets/tasks/SteadyState/v1.0.0/validation/SteadyState-0005.md b/specsheets/tasks/SteadyState/v1.0.0/validation/SteadyState-0005.md deleted file mode 100644 index 6f739ef..0000000 --- a/specsheets/tasks/SteadyState/v1.0.0/validation/SteadyState-0005.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -id: SteadyState-0005 -rule: When the value of outputModel of a SteadyState is provided directly, it must be a boolean. -message: "Attribute '{attr}' of {class} '{id}' has value '{value}', which is not a boolean." -severity: error -status: active -check: schema ---- - -`outputModel` is `BooleanOrRef`: the value, when not a reference, must be a boolean. diff --git a/specsheets/tasks/SteadyState/v1.0.0/validation/SteadyState-0006.md b/specsheets/tasks/SteadyState/v1.0.0/validation/SteadyState-0006.md deleted file mode 100644 index 4e45ab3..0000000 --- a/specsheets/tasks/SteadyState/v1.0.0/validation/SteadyState-0006.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -id: SteadyState-0006 -rule: When the value of outputModel of a SteadyState is a reference, it must be a reference to a boolean. -message: "Attribute '{attr}' of {class} '{id}' is the reference '{value}', which resolves to '{resolved-value}', not a boolean." -severity: error -status: active -check: ref-type ---- - -`outputModel` is `BooleanOrRef`: when the value is a reference, it must resolve to a boolean. diff --git a/specsheets/tasks/StringFormation/v1.0.0/outputs.json b/specsheets/tasks/StringFormation/v1.0.0/outputs.json index 82ab3d2..6089362 100644 --- a/specsheets/tasks/StringFormation/v1.0.0/outputs.json +++ b/specsheets/tasks/StringFormation/v1.0.0/outputs.json @@ -1,18 +1,13 @@ { "outputs": { "[id]": { - "valid": true, "type": "annotatedData", "dimensions": { "source": "runtime", "note": "scalar when no element of concatenate is itself a list; otherwise N-D matching the shape of the list element(s) within concatenate (1D for one list element, higher-D when several list elements are combined pairwise, all sharing the same length/shape per dimension) - not derivable without evaluating concatenate's actual element values" } }, - "[id].model": { - "valid": false - }, "[id].strings": { - "valid": true, "type": "stringList", "dimensions": { "source": "runtime", diff --git a/templates/cpp/runtime/OutputsShape.hpp b/templates/cpp/runtime/OutputsShape.hpp index a544c2a..bd52c87 100644 --- a/templates/cpp/runtime/OutputsShape.hpp +++ b/templates/cpp/runtime/OutputsShape.hpp @@ -615,12 +615,15 @@ inline OptDims apply_index_chain(const OptDims& dims, const std::vector eval_valid(const Json& entry, const Scope& scope, const ShapeOf& shape_of) { const Json* valid = member(entry, "valid"); - if (valid && valid->is_bool()) return valid->as(); - if (valid && valid->is_string()) { + if (!valid) return true; + if (valid->is_string()) { try { return val_truthy(eval_expr(*parse_expr(valid->as()), scope, shape_of)); } catch (const NotStatic&) { diff --git a/test-specsheets/generated/cpp/include/sed2test/OutputsShape.hpp b/test-specsheets/generated/cpp/include/sed2test/OutputsShape.hpp index a544c2a..bd52c87 100644 --- a/test-specsheets/generated/cpp/include/sed2test/OutputsShape.hpp +++ b/test-specsheets/generated/cpp/include/sed2test/OutputsShape.hpp @@ -615,12 +615,15 @@ inline OptDims apply_index_chain(const OptDims& dims, const std::vector eval_valid(const Json& entry, const Scope& scope, const ShapeOf& shape_of) { const Json* valid = member(entry, "valid"); - if (valid && valid->is_bool()) return valid->as(); - if (valid && valid->is_string()) { + if (!valid) return true; + if (valid->is_string()) { try { return val_truthy(eval_expr(*parse_expr(valid->as()), scope, shape_of)); } catch (const NotStatic&) { diff --git a/test-specsheets/generated/java/src/main/java/org/sed2test/OutputsShape.java b/test-specsheets/generated/java/src/main/java/org/sed2test/OutputsShape.java index c0558b5..103daa9 100644 --- a/test-specsheets/generated/java/src/main/java/org/sed2test/OutputsShape.java +++ b/test-specsheets/generated/java/src/main/java/org/sed2test/OutputsShape.java @@ -704,13 +704,16 @@ static List applyIndexChain(List dims, List indexAccessors) return result; } - /** entry["valid"] is true/false, or a boolean expr string over the - * task's own fields. Returns TRUE/FALSE, or null when a string expr - * couldn't be evaluated statically ("the rule does not fire"). */ + /** A suffix entry that is listed in outputs.json is valid; one that isn't + * listed is not (resolveOutput handles that). An entry's optional "valid" + * field is a boolean expr string over the task's own fields meaning + * "valid if"; no "valid" field means always valid. Returns TRUE/FALSE, or + * null when the expr couldn't be evaluated statically ("the rule does not + * fire"). */ static Boolean evalValid(JsonNode entry, Scope scope, Function> shapeOf) { JsonNode valid = entry.get("valid"); - if (valid != null && valid.isBoolean()) return valid.booleanValue(); - if (valid != null && valid.isTextual()) { + if (valid == null) return Boolean.TRUE; + if (valid.isTextual()) { try { return truthy(eval(parseExpr(valid.textValue()), scope, shapeOf)); } catch (NotStatic e) { @@ -722,8 +725,9 @@ static Boolean evalValid(JsonNode entry, Scope scope, Function /** The result of resolveOutput: see that method. */ public static final class Resolution { - /** TRUE (suffix exists and its "valid" evaluated true), FALSE (absent - * or evaluates false), or null (couldn't be determined statically). */ + /** TRUE (suffix is listed and has no "valid" field, or its "valid" + * ("valid if") expr evaluated true), FALSE (not listed, or the expr + * evaluates false), or null (couldn't be determined statically). */ public final Boolean ok; public final JsonNode entry; // the raw outputEntry, or null when the suffix key is absent public final List dimsBefore; // null unless ok == TRUE and the entry has resolvable "dimensions" diff --git a/test-specsheets/generated/python/src/libsed2test/outputs_shape.py b/test-specsheets/generated/python/src/libsed2test/outputs_shape.py index db4c30a..f8766e0 100644 --- a/test-specsheets/generated/python/src/libsed2test/outputs_shape.py +++ b/test-specsheets/generated/python/src/libsed2test/outputs_shape.py @@ -530,13 +530,15 @@ def _apply_index_chain(dims, index_accessors): def eval_valid(entry, scope, shape_of): - """entry["valid"] is True/False, or a boolean expr string over the - task's own fields. Returns True/False, or None when a string expr - couldn't be evaluated statically (SEDBase-0008: "the rule does not - fire" in that case).""" + """A suffix entry that is listed in outputs.json is valid; one that + isn't listed is not (resolve_output handles that). An entry's optional + "valid" field is a boolean expr string over the task's own fields + meaning "valid if". No "valid" field: always valid. Returns True/False, + or None when the expr couldn't be evaluated statically (SEDBase-0008: + "the rule does not fire" in that case).""" valid = entry.get("valid") - if valid is True or valid is False: - return valid + if valid is None: + return True if isinstance(valid, str): try: return bool(eval_expr(parse_expr(valid), scope, shape_of)) @@ -552,8 +554,9 @@ def resolve_output(outputs_json, fields, accessors, shape_of): `fields` is the referenced task's own _own_json_value() dict; `accessors` is a ParsedReference's own .accessors list. Returns (accessor_ok, entry, dims_before, dims_after, dot_name, index_accessors): - - accessor_ok: True (the suffix exists and its "valid" evaluated - true), False (suffix absent or "valid" is/evaluates false), or None + - accessor_ok: True (the suffix is listed and has no "valid" field, + or its "valid" ("valid if") expr evaluated true), False (suffix + not listed, or its "valid" expr evaluated false), or None (couldn't be determined statically - every caller treats this the same as False for "don't fire a positive claim" but ALSO suppresses every rule that would need to know for sure, per the "only fires