Runs#
Exercise every run operation.
nominalexample_rundemo.m#
function results = nominalexample_rundemo(assetName)
%NOMINALEXAMPLE_RUNDEMO Exercise every run operation.
%
% nominalexample_rundemo % throwaway asset
% nominalexample_rundemo("engine-3") % under an existing asset
%
% Needs credentials. Creates an asset, a dataset, and a run over them, then
% closes it.
%
% Covers: create with an explicit start, get by RID, adding and removing
% an asset, a run from a tagged dataset with no asset, update, setting one
% property, all accessors, finish, and searching for it. Not addDataset: a
% run's data sources are its asset's, so there is nothing to attach.
%
% See also NOMINAL.RUN, NOMINALEXAMPLE_ASSETDEMO,
% NOMINALEXAMPLE_EVENTDEMO, NOMINALEXAMPLE_CONNECT
arguments
assetName (1,1) string = "nominal-matlab-demo-" + string(posixtime(datetime("now")))
end
client = nominalexample_connect();
asset = client.getOrCreateAsset(assetName);
% AttachExisting=false so a demo asset does not adopt someone else's
% existing "telemetry" dataset.
dataset = asset.getOrCreateDataset("telemetry", "tlm", AttachExisting=false);
fprintf('Asset %s / dataset %s\n', asset.Name, dataset.Name);
% --- create -------------------------------------------------------
%
% Started a minute ago so the window covers data already written. Omit
% the argument to start now.
%
% Each mutation below returns a new object: openRun -> sharedRun ->
% soloRun -> updatedRun -> notedRun -> finishedRun. Earlier objects keep reporting
% their older state.
runStartTime = datetime("now", TimeZone="UTC") - minutes(1);
openRun = asset.run("matlab-demo-run", runStartTime);
fprintf('Run "%s"\n', openRun.Name);
fprintf(' rid %s\n', openRun.Rid);
fprintf(' number %d\n', openRun.Number);
fprintf(' url %s\n', openRun.Url);
fprintf(' start %s\n', string(openRun.StartTime));
% An open run's EndTime is NaT. Test for it, since fprintf cannot format
% string(NaT).
if isnat(openRun.EndTime)
fprintf(' end (none yet - the run is open)\n');
else
fprintf(' end %s\n', string(openRun.EndTime));
end
% --- fetch by RID -------------------------------------------------
sameRunByRid = client.runByRid(openRun.Rid);
fprintf(' refetched by rid, number matches: %d\n', ...
sameRunByRid.Number == openRun.Number);
% --- the run's data ------------------------------------------------
%
% A run's data sources are its asset's, live. The dataset above is already
% on the run, and so is anything attached to the asset later. Nothing needs
% attaching, and nominal.Run.addDataset cannot succeed for a run made with
% asset.run().
fprintf(' data sources come from the asset; nothing to attach\n');
% --- more than one asset ------------------------------------------
%
% A run can span several assets, say a test chamber and the unit in it.
% createAsset always makes a new asset, where getOrCreateAsset would reuse
% one of the same name.
chamber = client.createAsset(asset.Name + " chamber");
sharedRun = openRun.addAsset(chamber);
fprintf(' on %d assets after addAsset\n', numel(sharedRun.AssetRids));
soloRun = sharedRun.removeAsset(chamber);
fprintf(' on %d asset after removeAsset\n', numel(soloRun.AssetRids));
% --- a run with no asset of its own -------------------------------
%
% For data with no physical system behind it, such as one run per
% simulation execution: the run reads only the series with these tags,
% and Nominal keeps it on a hidden asset.
executionRun = client.createRun(asset.Name + " execution 7", dataset, ...
Tags = dictionary(["model" "execution-id"], ["A" "7"]), ...
StartTime = int64(0), EndTime = int64(60e9));
fprintf(' from a dataset: %s to %s, %d visible asset(s) named after it\n', ...
string(executionRun.StartTime), string(executionRun.EndTime), ...
height(client.assets(executionRun.Name)));
% --- update -------------------------------------------------------
%
% update accepts start and end times as well as these metadata fields.
% Collections replace, they do not merge.
updatedRun = soloRun.update( ...
Description = "Created by the Nominal MATLAB demo", ...
Labels = ["matlab-demo" "smoke"], ...
Properties = struct(operator = "matlab", phase = "demo"));
fprintf(' description: %s\n', updatedRun.Description);
fprintf(' labels: %s\n', join(updatedRun.Labels, " "));
fprintf(' operator: %s\n', updatedRun.property("operator"));
% setProperty changes one key and keeps the rest. Properties is a
% containers.Map of all of them.
notedRun = updatedRun.setProperty("result", "pass");
fprintf(' properties: %s\n', strjoin(keys(notedRun.Properties), ", "));
% --- close it -----------------------------------------------------
%
% No argument means end now.
finishedRun = notedRun.finish();
fprintf(' end %s (closed)\n', string(finishedRun.EndTime));
fprintf(' span %s\n', string(finishedRun.EndTime - finishedRun.StartTime));
% --- find it again ------------------------------------------------
%
% Every label and property given must match. StartAfter keeps this
% search to runs from this demo.
found = client.runs("matlab-demo-run", Labels = "smoke", ...
Properties = struct(result = "pass"), StartAfter = runStartTime);
fprintf(' found by name, label and property: %d run(s)\n', height(found));
% --- results ------------------------------------------------------
%
% Read from finishedRun, the only object that reflects every change.
results = struct( ...
'Rid', finishedRun.Rid, ...
'Name', finishedRun.Name, ...
'Number', finishedRun.Number, ...
'Url', finishedRun.Url, ...
'Description', finishedRun.Description, ...
'Labels', finishedRun.Labels, ...
'StartTime', finishedRun.StartTime, ...
'EndTime', finishedRun.EndTime, ...
'DatasetRid', dataset.Rid);
% --- teardown -----------------------------------------------------
%
% Each object in the chain needs its own delete.
delete(finishedRun);
delete(notedRun);
delete(updatedRun);
delete(executionRun);
delete(soloRun);
delete(sharedRun);
delete(chamber);
delete(sameRunByRid);
delete(openRun);
delete(dataset);
delete(asset);
delete(client);
nominalexample_publish(results, "nominalRun");
end