@abi-software/simulationvuer 3.0.1 → 3.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abi-software/simulationvuer",
3
- "version": "3.0.1",
3
+ "version": "3.0.3",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "serve": "vite serve --host --force",
@@ -18,9 +18,10 @@
18
18
  },
19
19
  "dependencies": {
20
20
  "@abi-software/plotvuer": "1.0.7",
21
- "@opencor/opencor": "^0.20251112.0",
21
+ "@opencor/opencor": "^0.20251205.1",
22
22
  "element-plus": "2.8.4",
23
23
  "jsonschema": "^1.4.0",
24
+ "mathjs": "^15.1.0",
24
25
  "unplugin-vue-components": "^0.26.0",
25
26
  "vue": "^3.4.21"
26
27
  },
@@ -3,9 +3,9 @@
3
3
  <div class="container" v-if="opencorOmexFile === null">
4
4
  <p v-if="!hasValidSimulationUiInfo && !showUserMessage" class="default error"><span class="error">Error:</span> {{ errorMessage }}.</p>
5
5
  <div class="main" v-if="hasValidSimulationUiInfo">
6
- <div class="main-left" :class="{'with-buttons': !libopencorSet || uuid}">
7
- <p class="default name" v-if="!libopencorSet">{{ name }}</p>
8
- <el-divider v-if="!libopencorSet"></el-divider>
6
+ <div class="main-left" :class="{'with-buttons': uuid}">
7
+ <p class="default name">{{ name }}</p>
8
+ <el-divider></el-divider>
9
9
  <p class="default input-parameters">Input parameters</p>
10
10
  <div class="input scrollbar">
11
11
  <SimulationVuerInput v-for="(input, index) in simulationUiInfo.input"
@@ -20,18 +20,15 @@
20
20
  />
21
21
  </div>
22
22
  <div class="buttons-container">
23
- <div class="primary-button" v-if="!libopencorSet">
23
+ <div class="primary-button">
24
24
  <el-button type="primary" size="small" @click="startSimulation()">Run Simulation</el-button>
25
25
  </div>
26
26
  <div class="secondary-button" v-if="uuid">
27
27
  <el-button size="small" @click="runOnOsparc()">Run on oSPARC</el-button>
28
28
  </div>
29
- <div class="secondary-button" v-if="!libopencorSet">
29
+ <div class="secondary-button">
30
30
  <el-button size="small" @click="viewDataset()">View Dataset</el-button>
31
31
  </div>
32
- <div class="secondary-button" v-if="libopencorSet && idType === 'pmr_path'">
33
- <el-button size="small" @click="viewWorkspace()">View Workspace</el-button>
34
- </div>
35
32
  <p class="default note" v-if="uuid">Additional parameters are available on oSPARC</p>
36
33
  </div>
37
34
  </div>
@@ -63,8 +60,6 @@ import SimulationVuerInput from "./SimulationVuerInput.vue";
63
60
  import { ElButton, ElDivider, ElLoading } from "element-plus";
64
61
  import { evaluateValue, finaliseUi, OPENCOR_SOLVER_NAME } from "./common.js";
65
62
  import { validJson } from "./json.js";
66
- import libOpenCOR from "https://mapcore-demo.org/current/opencor-wasm/0.0.3/libopencor.js";
67
- import { markRaw } from "vue";
68
63
  import { create, all } from "mathjs";
69
64
  import OpenCOR from '@opencor/opencor';
70
65
  import '@opencor/opencor/style.css';
@@ -157,8 +152,6 @@ export default {
157
152
  isMounted: false,
158
153
  isSimulationValid: true,
159
154
  layout: [],
160
- libopencor: undefined,
161
- libopencorSet: false,
162
155
  model: undefined,
163
156
  name: null,
164
157
  opencorBasedSimulation: true,
@@ -193,150 +186,6 @@ export default {
193
186
  },
194
187
  };
195
188
  },
196
- /**
197
- * @public
198
- * Manage the file associated with the given `url` and `fileContents`.
199
- * @arg `url`
200
- * @arg `fileContents`
201
- */
202
- manageFile(url, fileContents) {
203
- let file = this.fileManager.file(url);
204
-
205
- if (file === null) {
206
- file = new this.libopencor.File(url);
207
- }
208
-
209
- const fileContentsPtr = this.libopencor._malloc(fileContents.length);
210
- const mem = new Uint8Array(this.libopencor.HEAPU8.buffer, fileContentsPtr, fileContents.length);
211
-
212
- mem.set(fileContents);
213
-
214
- file.setContents(fileContentsPtr, fileContents.length);
215
-
216
- this.libopencor._free(fileContentsPtr);
217
-
218
- return file;
219
- },
220
- /**
221
- * @public
222
- * Run a PMR-based COMBINE archive using libOpenCOR.
223
- */
224
- runSimulation() {
225
- if (this.instance === undefined) {
226
- // Retrieve an instance of the model.
227
-
228
- const document = new this.libopencor.SedDocument(this.fileManager.file(PMR_URL + this.id));
229
-
230
- this.model = markRaw(document.model());
231
- this.instance = markRaw(document.instantiate());
232
-
233
- document.delete();
234
- }
235
-
236
- // Run the simulation after passing some changes, if any, to the model.
237
-
238
- this.model.removeAllChanges();
239
-
240
- for (const [parameter, value] of Object.entries(this.parametersData())) {
241
- const parameterParts = parameter.split("/")
242
-
243
- this.model.addChange(new this.libopencor.SedChangeAttribute(parameterParts[0], parameterParts[1], value.toString()));
244
- }
245
-
246
- this.instance.run();
247
-
248
- // Retrieve the simulation results.
249
-
250
- const res = {};
251
- const instanceTask = this.instance.task(0);
252
- let foundAllOutputs = true;
253
- let foundOutput;
254
-
255
- for (const output of this.outputData()) {
256
- foundOutput = false;
257
-
258
- if (output === instanceTask.voiName) {
259
- res[output] = instanceTask.voiAsArray;
260
-
261
- foundOutput = true;
262
- }
263
-
264
- if (res[output] === undefined) {
265
- for (let i = 0; i < instanceTask.stateCount; ++i) {
266
- if (output === instanceTask.stateName(i)) {
267
- res[output] = instanceTask.stateAsArray(i);
268
-
269
- foundOutput = true;
270
-
271
- break;
272
- }
273
- }
274
- }
275
-
276
- if (res[output] === undefined) {
277
- for (let i = 0; i < instanceTask.rateCount; ++i) {
278
- if (output === instanceTask.rateName(i)) {
279
- res[output] = instanceTask.rateAsArray(i);
280
-
281
- foundOutput = true;
282
-
283
- break;
284
- }
285
- }
286
- }
287
-
288
- if (res[output] === undefined) {
289
- for (let i = 0; i < instanceTask.constantCount; ++i) {
290
- if (output === instanceTask.constantName(i)) {
291
- res[output] = instanceTask.constantAsArray(i);
292
-
293
- foundOutput = true;
294
-
295
- break;
296
- }
297
- }
298
- }
299
-
300
- if (res[output] === undefined) {
301
- for (let i = 0; i < instanceTask.computedConstantCount; ++i) {
302
- if (output === instanceTask.computedConstantName(i)) {
303
- res[output] = instanceTask.computedConstantAsArray(i);
304
-
305
- foundOutput = true;
306
-
307
- break;
308
- }
309
- }
310
- }
311
-
312
- if (res[output] === undefined) {
313
- for (let i = 0; i < instanceTask.algebraicCount; ++i) {
314
- if (output === instanceTask.algebraicName(i)) {
315
- res[output] = instanceTask.algebraicAsArray(i);
316
-
317
- foundOutput = true;
318
-
319
- break;
320
- }
321
- }
322
- }
323
-
324
- if (!foundOutput) {
325
- console.warn("SIMULATION: output '" + output + "' could not be found.");
326
-
327
- foundAllOutputs = false;
328
- }
329
- }
330
-
331
- if (foundAllOutputs) {
332
- this.processSimulationResults(res);
333
- } else {
334
- this.hasValidSimulationUiInfo = false;
335
- this.errorMessage = "some outputs could not be found";
336
- }
337
-
338
- this.showUserMessage = false;
339
- },
340
189
  /**
341
190
  * @public
342
191
  * Build the simulation UI using `simulationUiInfo`, a JSON object that describes the contents of the simulation UI.
@@ -349,7 +198,7 @@ export default {
349
198
 
350
199
  // Make sure that the simulation UI information is valid.
351
200
 
352
- this.hasValidSimulationUiInfo = validJson(this.simulationUiInfo, this.libopencor === undefined);
201
+ this.hasValidSimulationUiInfo = validJson(this.simulationUiInfo);
353
202
 
354
203
  if (!this.hasValidSimulationUiInfo) {
355
204
  this.errorMessage = "the simulation.json file is malformed";
@@ -357,26 +206,23 @@ export default {
357
206
  return;
358
207
  }
359
208
 
360
- // Retrieve and keep track of the solver to be used for the simulation, if
361
- // needed.
362
-
363
- if (this.libopencor === undefined) {
364
- this.simulationUiInfo.simulation.solvers.forEach((solver) => {
365
- if ((solver.if === undefined) || evaluateValue(this, solver.if)) {
366
- this.solver = solver;
367
- }
368
- });
369
-
370
- if (this.solver === undefined) {
371
- this.hasValidSimulationUiInfo = false;
372
- this.errorMessage = "no solver name and/or solver version specified";
209
+ // Retrieve and keep track of the solver to be used for the simulation.
373
210
 
374
- return;
211
+ this.simulationUiInfo.simulation.solvers.forEach((solver) => {
212
+ if ((solver.if === undefined) || evaluateValue(this, solver.if)) {
213
+ this.solver = solver;
375
214
  }
215
+ });
376
216
 
377
- this.opencorBasedSimulation = this.solver.name === OPENCOR_SOLVER_NAME;
217
+ if (this.solver === undefined) {
218
+ this.hasValidSimulationUiInfo = false;
219
+ this.errorMessage = "no solver name and/or solver version specified";
220
+
221
+ return;
378
222
  }
379
223
 
224
+ this.opencorBasedSimulation = this.solver.name === OPENCOR_SOLVER_NAME;
225
+
380
226
  // Initialise our UI.
381
227
 
382
228
  this.simulationUiInfo.output.data.forEach((data) => {
@@ -433,40 +279,6 @@ export default {
433
279
  finaliseUi(this);
434
280
  });
435
281
  },
436
- /**
437
- * @public
438
- * Extract the simulation UI JSON file from the given file contents and build the simulation UI.
439
- * @arg `libopencor`
440
- * @arg `fileContents`
441
- */
442
- extractAndBuildSimulationUi(libopencor, fileContents) {
443
- this.libopencor = markRaw(libopencor);
444
- this.libopencorSet = true;
445
- this.fileManager = markRaw(this.libopencor.FileManager.instance());
446
-
447
- const file = this.manageFile(PMR_URL + this.id, fileContents);
448
-
449
- if (file.type.value !== libopencor.File.Type.COMBINE_ARCHIVE.value) {
450
- this.showUserMessage = false;
451
- } else {
452
- const decoder = new TextDecoder();
453
- const simulationJson = file.childFileFromFileName("simulation.json");
454
-
455
- if (simulationJson === null) {
456
- this.errorMessage = "no simulation JSON file could be found";
457
-
458
- this.showUserMessage = false;
459
- } else {
460
- const simulationUiInfo = JSON.parse(decoder.decode(simulationJson.contents()));
461
-
462
- this.showUserMessage = false;
463
-
464
- this.$nextTick(() => {
465
- this.buildSimulationUi(simulationUiInfo);
466
- });
467
- }
468
- }
469
- },
470
282
  /**
471
283
  * @public
472
284
  * Run the simulation-based dataset directly on oSPARC. Not all simulation-based datasets can be run directly on
@@ -749,18 +561,8 @@ export default {
749
561
  this.opencorOmexFile = this.id;
750
562
  } else if (this.idType === IdType.PMR_PATH) {
751
563
  this.opencorOmexFile = PMR_URL + this.id;
752
- } else {
753
- // Extract the simulation UI JSON file from the COMBINE archive and build
754
- // the simulation UI.
755
-
756
- this.userMessage = "Retrieving COMBINE archive...";
757
- this.showUserMessage = true;
758
-
759
- this.$nextTick(() => {
760
- libOpenCOR().then((libopencor) => {
761
- this.extractAndBuildSimulationUi(libopencor, this.id);
762
- });
763
- });
564
+ } else { // IdType.RAW_COMBINE_ARCHIVE
565
+ this.opencorOmexFile = this.id;
764
566
  }
765
567
  },
766
568
  mounted: function () {
@@ -28,15 +28,6 @@ export function updateUi(parent) {
28
28
 
29
29
  parent.$refs.simInput[index].visible = (input.visible === undefined) ? true : evaluateValue(parent, input.visible);
30
30
  });
31
-
32
- if (parent.libopencor !== undefined) {
33
- parent.userMessage = "Running the model...";
34
- parent.showUserMessage = true;
35
-
36
- parent.$nextTick(() => {
37
- parent.runSimulation();
38
- });
39
- }
40
31
  });
41
32
  }
42
33
 
@@ -1,7 +1,7 @@
1
1
  import { Validator } from "jsonschema";
2
2
  import { OPENCOR_SOLVER_NAME } from "./common.js";
3
3
 
4
- export function validJson(json, simulationInfoNeeded) {
4
+ export function validJson(json) {
5
5
  // Check the JSON against our schema.
6
6
 
7
7
  const validator = new Validator();
@@ -214,7 +214,7 @@ export function validJson(json, simulationInfoNeeded) {
214
214
  type: "array",
215
215
  },
216
216
  },
217
- required: simulationInfoNeeded,
217
+ required: true,
218
218
  type: "object",
219
219
  },
220
220
  },
@@ -436,87 +436,85 @@ export function validJson(json, simulationInfoNeeded) {
436
436
 
437
437
  // Make sure that the simulation information makes sense.
438
438
 
439
- if (simulationInfoNeeded) {
440
- let needOpencorSettings = false;
441
-
442
- if (!json.simulation.solvers.every((solver) => {
443
- if (solver.if !== undefined) {
444
- if (solver.if === "") {
445
- console.warn("JSON: a simulation solver if must not be empty.");
446
-
447
- return false;
448
- }
449
- }
450
-
451
- if (solver.input !== undefined) {
452
- if (solver.input.name === "") {
453
- console.warn("JSON: a simulation solver input name must not be empty.");
454
-
455
- return false;
456
- }
439
+ let needOpencorSettings = false;
457
440
 
458
- if (solver.input.value === "") {
459
- console.warn("JSON: a simulation solver input value must not be empty.");
441
+ if (!json.simulation.solvers.every((solver) => {
442
+ if (solver.if !== undefined) {
443
+ if (solver.if === "") {
444
+ console.warn("JSON: a simulation solver if must not be empty.");
460
445
 
461
- return false;
462
- }
446
+ return false;
463
447
  }
448
+ }
464
449
 
465
- if (solver.name === "") {
466
- console.warn("JSON: a simulation solver name must not be empty.");
450
+ if (solver.input !== undefined) {
451
+ if (solver.input.name === "") {
452
+ console.warn("JSON: a simulation solver input name must not be empty.");
467
453
 
468
454
  return false;
469
455
  }
470
456
 
471
- needOpencorSettings = needOpencorSettings || (solver.name === OPENCOR_SOLVER_NAME);
472
-
473
- if (solver.version === "") {
474
- console.warn("JSON: a simulation solver version must not be empty.");
457
+ if (solver.input.value === "") {
458
+ console.warn("JSON: a simulation solver input value must not be empty.");
475
459
 
476
460
  return false;
477
461
  }
462
+ }
463
+
464
+ if (solver.name === "") {
465
+ console.warn("JSON: a simulation solver name must not be empty.");
478
466
 
479
- return true;
480
- })) {
481
467
  return false;
482
468
  }
483
469
 
484
- if (needOpencorSettings && (json.simulation.opencor === undefined)) {
485
- console.warn("JSON: the simulation solver for OpenCOR is specified so simulation OpenCOR settings must also be specified.");
470
+ needOpencorSettings = needOpencorSettings || (solver.name === OPENCOR_SOLVER_NAME);
471
+
472
+ if (solver.version === "") {
473
+ console.warn("JSON: a simulation solver version must not be empty.");
486
474
 
487
475
  return false;
488
476
  }
489
477
 
490
- if (json.simulation.opencor !== undefined) {
491
- if (json.simulation.opencor.resource === "") {
492
- console.warn("JSON: the simulation OpenCOR resource must not be empty.");
478
+ return true;
479
+ })) {
480
+ return false;
481
+ }
493
482
 
494
- return false;
495
- }
483
+ if (needOpencorSettings && (json.simulation.opencor === undefined)) {
484
+ console.warn("JSON: the simulation solver for OpenCOR is specified so simulation OpenCOR settings must also be specified.");
496
485
 
497
- if (json.simulation.opencor.endingPoint !== undefined) {
498
- if (json.simulation.opencor.pointInterval !== undefined) {
499
- if (json.simulation.opencor.endingPoint <= 0.0) {
500
- console.warn("JSON: the simulation OpenCOR ending point (" + json.simulation.opencor.endingPoint + ") must be greater than zero.");
486
+ return false;
487
+ }
501
488
 
502
- return false;
503
- }
489
+ if (json.simulation.opencor !== undefined) {
490
+ if (json.simulation.opencor.resource === "") {
491
+ console.warn("JSON: the simulation OpenCOR resource must not be empty.");
504
492
 
505
- if (json.simulation.opencor.pointInterval <= 0.0) {
506
- console.warn("JSON: the simulation OpenCOR point interval (" + json.simulation.opencor.pointInterval + ") must be greater than zero.");
493
+ return false;
494
+ }
495
+
496
+ if (json.simulation.opencor.endingPoint !== undefined) {
497
+ if (json.simulation.opencor.pointInterval !== undefined) {
498
+ if (json.simulation.opencor.endingPoint <= 0.0) {
499
+ console.warn("JSON: the simulation OpenCOR ending point (" + json.simulation.opencor.endingPoint + ") must be greater than zero.");
500
+
501
+ return false;
502
+ }
507
503
 
508
- return false;
509
- }
510
- } else {
511
- console.warn("JSON: a simulation OpenCOR ending point is specified so a simulation OpenCOR point interval must also be specified.");
504
+ if (json.simulation.opencor.pointInterval <= 0.0) {
505
+ console.warn("JSON: the simulation OpenCOR point interval (" + json.simulation.opencor.pointInterval + ") must be greater than zero.");
512
506
 
513
507
  return false;
514
508
  }
515
- } else if (json.simulation.opencor.pointInterval !== undefined) {
516
- console.warn("JSON: a simulation OpenCOR point interval is specified so a simulation OpenCOR ending point must also be specified.");
509
+ } else {
510
+ console.warn("JSON: a simulation OpenCOR ending point is specified so a simulation OpenCOR point interval must also be specified.");
517
511
 
518
512
  return false;
519
513
  }
514
+ } else if (json.simulation.opencor.pointInterval !== undefined) {
515
+ console.warn("JSON: a simulation OpenCOR point interval is specified so a simulation OpenCOR ending point must also be specified.");
516
+
517
+ return false;
520
518
  }
521
519
  }
522
520