Which query is which¶
OpenSysML answers questions about a model through several surfaces that all carry the word query or behave like one. They read different things — the model's elements, the objects a session holds, one expression's value, a solver's assignment — and each is blind to what the others see. This page places them side by side: what each takes, what it returns, what it cannot see, and where to read the details. The pages linked from each section are the reference; this one only draws the boundaries.
| Surface | Reads | Returns | Cannot see | Entry points |
|---|---|---|---|---|
| Document queries | The model's elements: declarations, ownership, relationships, declared values | Ordered rows of elements, projected into typed columns | Objects unless the session holds them; nothing a solver would infer | %run-query, -run-query, RunDocumentQuery, tables and lists in a document |
| Object and verdict rows | The objects a session holds and the assertions about them | Rows standing for objects (by path and id) or for verdicts | Objects no session created; the model's relationships over an object row | The same, in a session with -instantiate/%instantiate |
| State and event rows | The state machines the held objects exhibit, as they stand now, and the trace the session recorded | One row per active leaf state; one row per trace record, at its instant | Anything outside the current session; a run no trace recorded | The same, in a session with a run and -trace/%trace on |
API Query |
The elements of one loaded model, by property | Elements with their properties, in declaration order | Objects, values, the library, traversal beyond containment | Query RPC, model.query(...) |
| OSLC Query text | The same elements, by prefixed property | Element identification only | The same; or |
%query, -query, oslc_query in Query |
Evaluate |
One expression in one scope, over a held object when named | One value — a scalar, a sequence, an object, an element | Rows, columns, anything the expression's scope does not reach | %eval, -eval, Evaluate RPC |
all T and collection operations |
The instances a definition classifies, as an expression | An ordered sequence, and whatever the library functions make of it | Data-type values; the state a machine is in; the trace | Inside %eval, -eval, Evaluate, any expression |
solve and its siblings |
A constraint, requirement or satisfaction assertion, with what is already fixed | A satisfying assignment, unsat with the conflict, or unknown |
What a run did; anything the solver's theory does not cover | %check, %solve, %explain, %configure, %optimize; the solve engine |
Document queries over elements¶
A document query is a calc def specializing DocumentQueries::Query whose
body composes the library's operations — OwnedElements, Descendants,
WhereType, WhereFeature, Project, OrderBy and the rest of the
vocabulary — into a relation over the model.
It answers with rows: each row stands for an element, and Project gives
the rows named, typed columns read from the element's properties or computed
by a Column using expression, cell, or path. The order of the rows is the model's
declaration order until an OrderBy says otherwise, which is what makes a
document regenerate byte-identically.
What it reads is the declared model: an element's name, type, multiplicity,
documentation, the value an attribute is declared with or redefined to, and
the relationships the model draws (RelatedElements). A derived value the
declaration does not spell out is not there — a WhereFeature on mass
reads the declared or redefined mass, not an expression's result — unless
a Column computes it or the row is an object row.
A feature the element does not declare itself but a member nested in it does
is still reachable: a properties/property string or a Column expression
spells it as a member path — stat.runs, 'Monte Carlo'.runs — each segment
a member of the element reached so far, own members first. A feature whose own
name contains a period is read by that name first; the path is only the
fallback. A row lacking a
segment makes the path absent on that row alone, and a member holding more
values than its multiplicity admits fails the column as a direct feature
column does. See
Computed columns.
Rows live in one place: a document's Table or List renders them, and
%run-query/-run-query print them. The query cookbook
is the recipe book; the command reference
lists the flags, and Interfaces the gRPC and Python calls.
What it cannot do: it does not evaluate arbitrary expressions over the model
(that is Evaluate), it does not
infer values (that is solve), and it does not
read objects a session has not created.
Object rows and verdict rows¶
In a session that holds objects — -instantiate <name> on the command line,
%instantiate at the prompt, Instantiate over gRPC — the same operations
read the objects as well as the elements. A binding written as a usage's
name binds the held object under that name while the session holds one, and
the element otherwise; Objects(type = T) enumerates every held object of a
type without a binding. An object row's WhereFeature, Project and
OrderBy read what the object holds now, after a run changed it, and the
row renders by path with its id (Cookbook::telescope.primaryMirror (#2)).
Verdicts(source, kind) turns object rows into verdict rows, one per
assertion checked on the object: holds, violated or undecided, with the
reason. See Objects the session holds
and Which constraints and requirements hold.
Two boundaries are worth keeping in mind. The session is the whole world:
Objects returns no rows in a session that holds nothing, and is refused
with a typed no-runtime error where there is no session at all — the
library evaluating a document on its own, as the editor's preview does.
And an object row is not an element: RelatedElements reads the model's
relationships and is refused over one (object-row); traverse from the
element and bind what you find.
Over gRPC, RunDocumentQuery answers an object row in the object arm of
DocumentValue and a verdict row in the verdict arm; see
Native document queries and rendering over gRPC.
A run %record/-record-run makes is model rows, not object rows: the
record is written into the model as elements annotated
@AnalysisRecords::RecordedRun, so WhereMetadata finds each one and
WhereFeature/Project/OrderBy read the values it bound — caseName,
kind, iteration, and a property per input and output. See
Recording analysis runs. A plain -analysis,
-sweep or trade study still prints and discards its results, so a run that
was not recorded leaves nothing a query can see;
the analysis-results demo
tables records in the same vocabulary, including records that flag themselves
stale when the model moves.
Runtime state and event queries¶
Object rows tell you what an object holds; three more operations tell you
where its behavior stands and what happened to it. They are document-query
operations like Objects and Verdicts: they take object rows, the row
operations (WhereType, WhereName, WhereFeature, Project, OrderBy,
Column) read their rows, and they are refused with the same typed
no-runtime error where there is no session.
States(source) answers, for each object row it is given (or each
object the session holds of an element named), the states the object's
exhibited machines are in now — one row per active leaf state, so a machine
in a parallel state contributes one row per region. The row is a state:
object and path are the object, machine the exhibited machine (lp),
name the leaf's own name, statePath its name qualified by the states
enclosing it (on.run), region the orthogonal region it runs in (""
outside one) and enclosing the composite states active with it, outermost
first; WhereName reads name, and the row answers the state declaration's
own properties too. It prints as lamp1.lp in on.run. An object exhibiting
no state machine is a typed no-state-machine error, not an empty row set.
A machine that has terminated has no active state and so contributes no row,
while a machine that has completed reports its final state. An object the run
destroyed leaves the population — Objects, InState and element-named
sources skip it, and Events still resolves its label — while a source
naming only destroyed objects is a typed object-destroyed refusal.
InState(name) is the inverse: the objects the session holds whose
machine is in the state named — a leaf or a state enclosing one, by name or
by dotted path (on.slow) — each object once, as object rows, so anything
that reads an object row reads them. A name no held object's machine declares
is a typed unknown-state error.
Events(source, kind, since, before) answers the trace as a relation in
the order it was recorded: one row per signal accepted (accept), per signal
sent (send), per transition fired (transition), per state entry, exit
and do step, per choice point the run drew (a due order among concurrent
reactions, a junction split) and per guard it could not evaluate. Each row
is an event: time is the instant read from the runtime clock, as a
duration in the clock's second when the library defines it; object, path
and machine say whose behavior made the record; state, from and to
name the state entered, exited or transitioned between; event the trigger;
target the object a send was addressed to; payload an accepted or sent
signal's parameters as name = value; alternatives and taken a choice's
draw; and text the line -trace prints. source keeps the rows of the
objects given (every object's when absent), kind the kinds named (all, or
kinds separated by commas), and since and before bound the instant as a
duration or a bare number of clock units — inclusive at since, exclusive at
before, so [0 [s], 1 [s]) and [1 [s], 2 [s]) partition the trace. It
prints as t=1 lamp1.lp: accept Dim.
The rows are the typed record the trace is kept as, which -trace and
%trace print from — not a parse of the printed lines. So a trace query needs
a session that records one: -trace on the command line, %trace on at the
prompt before the run (the population Instantiate builds over gRPC is
traced from the start, keeping the most recent OPENSYSML_GRPC_MAX_HELD_EVENTS
records; an interval reaching back past them is a typed trace-truncated
error naming the instant history is kept from, never a shortened relation);
without it the query is a typed no-trace error rather than an empty
relation, and %trace off discards the record. A bound that is not a
duration (1 [m]), an interval with before at or before since, and a
kind the trace does not record are invalid-interval and invalid-argument
errors; States(source = Events(...)), or Events over a verdict row, is an
event-row/verdict-row error, as a state or event row given to a
model-only operation such as RelatedElements is.
On the command line, -run-query runs after the -state/-action behaviors
and the -advance named, so a state query reads where the run left each
machine and an event query reads what the run recorded. The cookbook's
Where the objects stand and what they did
section has the recipes for the three questions this vocabulary exists to
answer.
What these cannot see: another session's run, a machine no object exhibits,
and the future — the rows are what has happened up to the instant the clock
reads now. Advancing the run is the REPL's job (%advance, %step, %send);
a query only reads, and never moves the clock or a queue.
The API Query over a project¶
The SysML v2 API & Services Query is an interoperability surface: the
structured Query shape the standard defines — scope, select, a where
tree of primitive and composite constraints — filtering the elements of one
loaded model by their properties (name, @type, multiplicityLower, …). It
answers elements with their properties, in declaration order. OSLC Query
text is a second spelling over the same elements (oslc.where=sysml:name="wheel"
with oslc.select, oslc.orderBy, oslc.properties and oslc.searchTerms),
accepted for element identification by tools that speak OSLC. The two differ
in what they can express — structured queries support or, OSLC compound
terms only and — so neither subsumes the other.
$ sysml cookbook.sysml -query 'sysml:name="primaryMirror"'
✓ package Cookbook
Cookbook::telescope::primaryMirror PartUsage
Both are element identification and nothing more: no traversal, no joins, no
ordering or paging beyond the OSLC orderBy, no derived values, and nothing
about objects, runs or verdicts. Neither reaches the standard library unless
a scope names a library element. An unknown parameter or property is refused
as written (unknown OSLC query parameter "rdf:type"), not answered empty.
Read SysML v2 API & Services Query
for the structured form and its comparison semantics, and
OSLC Query text for the text grammar; the
entry points are the Query RPC (query or oslc_query), model.query(...)
in Python, %query at the prompt and -query on the command line.
Evaluate: one expression in one scope¶
Evaluate is not a query over a set: it computes one expression and
answers one value. The expression is any SysML expression the evaluator
understands — arithmetic, feature chains, library function calls, all T,
a quantity with units — resolved in one scope, and the answer is what it
comes to: a number, a string, a sequence, an object reference, an element.
$ sysml cookbook.sysml -eval "Cookbook::telescope.instrumentCluster.mass"
✓ package Cookbook
✓ Cookbook::telescope.instrumentCluster.mass
= 4.5
The scope is the difference between the surfaces' spellings. -eval and %eval
resolve the expression in the last namespace the session declared, reading the
model — a feature the model leaves open is <undetermined>; %eval in <name> :
<expression> resolves it in a named element's namespace or, given an object
reference, on that held object, so a bare feature name reads the value the
object holds now, as an object row does; the Evaluate RPC takes the same as
context_symbol_id and subject_symbol_id. See %eval and %eval in in the
REPL command reference and the
Evaluate RPC on the wire.
What it cannot do: produce rows or columns (an expression's sequence renders as one value), read a trace, or find values a model does not fix — an unbound attribute evaluates to nothing, it is not solved for.
The runtime population all T¶
all T — KerML's extent operator — is the expression form of a runtime
query: the ordered sequence of the instances of T the run has, every
object the definition classifies, nested usages included, in declaration
order; for an enumeration its literals, for a variation its variants. It is
an expression, so it lives inside Evaluate and the collection operations of
the library apply to it:
$ sysml cookbook.sysml -eval "(all Cookbook::Subsystem).mass"
✓ (all Cookbook::Subsystem).mass
= [10.0, 4.5, 15.0]
$ sysml cookbook.sysml -eval "ControlFunctions::select(all Cookbook::Subsystem, {in s : Cookbook::Subsystem; s.mass > 5.0})"
✓ ControlFunctions::select(all Cookbook::Subsystem, {in s : Cookbook::Subsystem; s.mass > 5.0})
= [Instance(ID: 2), Instance(ID: 4)]
$ sysml cookbook.sysml -eval "RealFunctions::sum((all Cookbook::Subsystem).mass)"
✓ RealFunctions::sum((all Cookbook::Subsystem).mass)
= 29.5
Without an -instantiate the population is the declared one — the objects
the model's usages stand for; with one, the objects the session created.
all T over a scalar or structured data type is refused
(unbounded extent: ScalarValues::Real is a data type, whose values are not
enumerated), since a run creates no data values to enumerate. See
Extents.
Where the two runtime forms meet: all T is to Objects(type = T) what an
expression is to a relation. all T answers a sequence a further expression
consumes; Objects answers rows a document renders, a Project gives
columns and a WhereFeature filters. Neither sees which state an object's
machine is in or what the run accepted — that is what
States and Events are for.
solve over constraints¶
solve does not read what the model or a run has; it asks an external SMT
solver (z3 or cvc5) what could be. %check <name> asks whether a
constraint, requirement or satisfaction assertion can be satisfied and
answers sat with an assignment, unsat or unknown; %solve <name> asks
for values that satisfy it while keeping what is already fixed — the values
an object holds, or failing that the ones the model declares — and names the
fixed values that conflict when none exist; %explain reduces an unsat to
its conflicting conditions; %configure and %optimize ask the same
question over variation points and an objective. The same solver is the
solve analysis engine -engines tables, whose verdicts carry a
standing: of satisfiable/unsatisfiable.
sysml> %solve Cookbook::MirrorAssembly::lightweight
✗ Constraint lightweight has no values consistent with the value already fixed (z3, 9ms)
Already fixed:
Cookbook::MirrorAssembly::mass = 10 (declared)
In the conflict: Cookbook::MirrorAssembly::mass = 10
standing: unsatisfiable (proved over inputs: 1 query by solve)
Satisfiability is not evaluation: %solve finding an assignment says nothing
about whether the object holds — %constraint, %satisfy and the
Verdicts rows say that. Nor does it see a run: the trace, the state a
machine is in and the messages in flight are outside the solver's theory.
There is no Solve RPC: ListEngines advertises the solve engine, but no
gRPC call poses a satisfiability question, and -solve is not a command-line
flag. See the solving commands in the
REPL command reference,
Analysis engines and
installing a solver.
Choosing¶
- A table or a list in a document, or any question whose answer is rows —
a document query; over held objects and their verdicts when the session
holds them; over their states and their trace with
States,InStateandEvents. - A tool that speaks the SysML v2 API or OSLC and wants elements by property
—
Query. - One value —
Evaluate, withall Twhen the value is a population. - Values that do not exist yet, or whether any could —
solve.