@abi-software/simulationvuer 3.0.1 → 3.0.2

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.2",
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.0",
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,7 +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
63
  import { markRaw } from "vue";
68
64
  import { create, all } from "mathjs";
69
65
  import OpenCOR from '@opencor/opencor';
@@ -157,8 +153,6 @@ export default {
157
153
  isMounted: false,
158
154
  isSimulationValid: true,
159
155
  layout: [],
160
- libopencor: undefined,
161
- libopencorSet: false,
162
156
  model: undefined,
163
157
  name: null,
164
158
  opencorBasedSimulation: true,
@@ -193,150 +187,6 @@ export default {
193
187
  },
194
188
  };
195
189
  },
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
190
  /**
341
191
  * @public
342
192
  * Build the simulation UI using `simulationUiInfo`, a JSON object that describes the contents of the simulation UI.
@@ -349,7 +199,7 @@ export default {
349
199
 
350
200
  // Make sure that the simulation UI information is valid.
351
201
 
352
- this.hasValidSimulationUiInfo = validJson(this.simulationUiInfo, this.libopencor === undefined);
202
+ this.hasValidSimulationUiInfo = validJson(this.simulationUiInfo);
353
203
 
354
204
  if (!this.hasValidSimulationUiInfo) {
355
205
  this.errorMessage = "the simulation.json file is malformed";
@@ -357,26 +207,23 @@ export default {
357
207
  return;
358
208
  }
359
209
 
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";
210
+ // Retrieve and keep track of the solver to be used for the simulation.
373
211
 
374
- return;
212
+ this.simulationUiInfo.simulation.solvers.forEach((solver) => {
213
+ if ((solver.if === undefined) || evaluateValue(this, solver.if)) {
214
+ this.solver = solver;
375
215
  }
216
+ });
376
217
 
377
- this.opencorBasedSimulation = this.solver.name === OPENCOR_SOLVER_NAME;
218
+ if (this.solver === undefined) {
219
+ this.hasValidSimulationUiInfo = false;
220
+ this.errorMessage = "no solver name and/or solver version specified";
221
+
222
+ return;
378
223
  }
379
224
 
225
+ this.opencorBasedSimulation = this.solver.name === OPENCOR_SOLVER_NAME;
226
+
380
227
  // Initialise our UI.
381
228
 
382
229
  this.simulationUiInfo.output.data.forEach((data) => {
@@ -433,40 +280,6 @@ export default {
433
280
  finaliseUi(this);
434
281
  });
435
282
  },
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
283
  /**
471
284
  * @public
472
285
  * Run the simulation-based dataset directly on oSPARC. Not all simulation-based datasets can be run directly on
@@ -749,18 +562,8 @@ export default {
749
562
  this.opencorOmexFile = this.id;
750
563
  } else if (this.idType === IdType.PMR_PATH) {
751
564
  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
- });
565
+ } else { // IdType.RAW_COMBINE_ARCHIVE
566
+ this.opencorOmexFile = this.id;
764
567
  }
765
568
  },
766
569
  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