@abi-software/simulationvuer 3.0.10-beta.0 → 3.0.10

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.
@@ -1,17 +1,14 @@
1
1
  <template>
2
2
  <div class="simulation-vuer" v-loading="showUserMessage" :element-loading-text="userMessage">
3
3
  <div class="container" v-if="opencorOmexFile === null">
4
- <p v-if="!hasValidSimulationUiInfo && !showUserMessage" class="default error">
5
- <span class="error">Error:</span> {{ errorMessage }}.
6
- </p>
4
+ <p v-if="!hasValidSimulationUiInfo && !showUserMessage" class="default error"><span class="error">Error:</span> {{ errorMessage }}.</p>
7
5
  <div class="main" v-if="hasValidSimulationUiInfo">
8
- <div class="main-left" :class="{ 'with-buttons': uuid }">
6
+ <div class="main-left" :class="{'with-buttons': uuid}">
9
7
  <p class="default name">{{ name }}</p>
10
8
  <el-divider></el-divider>
11
9
  <p class="default input-parameters">Input parameters</p>
12
10
  <div class="input scrollbar">
13
- <SimulationVuerInput
14
- v-for="(input, index) in simulationUiInfo.input"
11
+ <SimulationVuerInput v-for="(input, index) in simulationUiInfo.input"
15
12
  ref="simInput"
16
13
  :defaultValue="input.defaultValue"
17
14
  :key="`input-${index}`"
@@ -36,8 +33,7 @@
36
33
  </div>
37
34
  </div>
38
35
  <div class="main-right" ref="output" v-show="isSimulationValid">
39
- <PlotVuer
40
- v-for="(_outputPlot, index) in simulationUiInfo.output.plots"
36
+ <PlotVuer v-for="(_outputPlot, index) in simulationUiInfo.output.plots"
41
37
  :key="`output-${index}`"
42
38
  :metadata="plotMetadata(index)"
43
39
  :data-source="{ data: simulationResults[index] }"
@@ -47,155 +43,51 @@
47
43
  />
48
44
  </div>
49
45
  <div class="main-right" v-show="!isSimulationValid">
50
- <p class="default error">
51
- <span class="error">Error:</span>
52
- <span v-html="errorMessage"></span>.
53
- </p>
46
+ <p class="default error"><span class="error">Error:</span> <span v-html="errorMessage"></span>.</p>
54
47
  </div>
55
48
  </div>
56
49
  </div>
57
50
  <div v-else class="opencor">
58
- <OpenCOR :omex="opencorOmexFile" theme="light" />
51
+ <OpenCOR
52
+ ref="opencorRef"
53
+ :omex="opencorOmexFile"
54
+ theme="light"
55
+ @simulationData="onSimulationData($event)"
56
+ />
59
57
  </div>
60
58
  </div>
61
59
  </template>
62
60
 
63
- <script setup>
64
- import { onMounted, onUnmounted, ref } from 'vue'
65
-
66
- const emit = defineEmits(['data-notification'])
67
-
68
- const activeSubscriptions = ref([])
69
- // Only for demonstration purposes.
70
- let intervalTimer = null
71
-
72
- // Only for demonstration purposes.
73
- function getMockValue(type, tick) {
74
- if (type === 'sine') return Math.sin(tick * 0.1) * 10
75
- if (type === 'linear') return tick
76
- return Math.random() * 10
77
- }
78
-
79
- // Only for demonstration purposes.
80
- function mockType(req) {
81
- return Math.random() < 0.5 ? 'sine' : 'random'
82
- }
83
-
84
- // Only for demonstration purposes.
85
- function generateMockSeries(type, length = 100) {
86
- const data = []
87
- for (let i = 0; i < length; i++) {
88
- data.push(getMockValue(type, i))
89
- }
90
- return data
91
- }
92
-
93
- function addDataSubscription(subscription) {
94
- if (!subscription || typeof subscription !== 'object') {
95
- console.error('addDataSubscription: Subscription must be an object.')
96
- return
97
- }
98
-
99
- const EXPECTED_ID = 'nz.ac.auckland.simulation-data-request'
100
- const EXPECTED_MAJOR_VERSION = 0
101
-
102
- if (subscription.id !== EXPECTED_ID) {
103
- console.warn(`Request ignored: Invalid ID '${subscription.id}'`)
104
- return
105
- }
106
-
107
- const subscriptionMajorVersion = parseInt(subscription.version.split('.')[0])
108
- if (subscriptionMajorVersion !== EXPECTED_MAJOR_VERSION) {
109
- console.warn(
110
- `Request ignored: Version mismatch. Expected v${EXPECTED_MAJOR_VERSION}.x, got v${subscription.version}`
111
- )
112
- return
113
- }
114
-
115
- activeSubscriptions.value.push(subscription.payload)
116
- sendDataForSubscription(subscription.payload)
117
- }
118
-
119
- function sendDataForSubscription(dataSubscription) {
120
- // Only for demonstration purposes.
121
- const type = mockType(dataSubscription)
122
- let data = {
123
- y: generateMockSeries(type, 100),
124
- title: `${dataSubscription.component}.${dataSubscription.variable}`,
125
- }
126
- if (dataSubscription.withVOI) {
127
- const voi_type = 'linear'
128
- data.x = generateMockSeries(voi_type, 100)
129
- }
130
-
131
- const response = {
132
- id: 'nz.ac.auckland.simulation-data-response',
133
- version: '0.1.0',
134
- payload: {
135
- windowId: dataSubscription.windowId,
136
- ownerId: dataSubscription.ownerId,
137
- data: data,
138
- },
139
- }
140
-
141
- emit('data-notification', response)
142
- }
143
-
144
- function removeDataSubscription(subscriptionId) {
145
- activeSubscriptions.value = activeSubscriptions.value.filter(
146
- (sub) => sub.windowId !== subscriptionId
147
- )
148
- }
149
-
150
- defineExpose({ addDataSubscription, removeDataSubscription })
151
-
152
- // Only for demonstration purposes.
153
- onMounted(() => {
154
- intervalTimer = setInterval(() => {
155
- if (activeSubscriptions.value.length === 0) return
156
-
157
- activeSubscriptions.value.forEach((subscription) => {
158
- sendDataForSubscription(subscription)
159
- })
160
- }, 3000)
161
- })
162
-
163
- // Only for demonstration purposes.
164
- onUnmounted(() => {
165
- if (intervalTimer) clearInterval(intervalTimer)
166
- })
167
- </script>
168
-
169
61
  <script>
170
- import { PlotVuer } from '@abi-software/plotvuer'
171
- import '@abi-software/plotvuer/dist/style.css'
172
- import SimulationVuerInput from './SimulationVuerInput.vue'
173
- import { ElButton, ElDivider, ElLoading } from 'element-plus'
174
- import { evaluateValue, finaliseUi, OPENCOR_SOLVER_NAME } from './common.js'
175
- import { validJson } from './json.js'
176
- import { create, all } from 'mathjs'
177
- import OpenCOR from '@opencor/opencor'
178
- import '@opencor/opencor/style.css'
62
+ import { PlotVuer } from "@abi-software/plotvuer";
63
+ import "@abi-software/plotvuer/dist/style.css";
64
+ import SimulationVuerInput from "./SimulationVuerInput.vue";
65
+ import { ElButton, ElDivider, ElLoading } from "element-plus";
66
+ import { evaluateValue, finaliseUi, OPENCOR_SOLVER_NAME } from "./common.js";
67
+ import { validJson } from "./json.js";
68
+ import { create, all } from "mathjs";
69
+ import OpenCOR from '@opencor/opencor';
70
+ import '@opencor/opencor/style.css';
179
71
 
180
- const PMR_URL = 'https://models.physiomeproject.org/'
72
+ const PMR_URL = "https://models.physiomeproject.org/";
181
73
 
182
- const math = create(all, {})
74
+ const math = create(all, {});
183
75
 
184
76
  const IdType = Object.freeze({
185
77
  DATASET_ID: 'dataset_id',
186
78
  DATASET_URL: 'dataset_url',
187
79
  PMR_PATH: 'pmr_path',
188
80
  RAW_COMBINE_ARCHIVE: 'raw_combine_archive',
189
- })
81
+ });
190
82
 
191
83
  function isWebProtocol(urlString) {
192
84
  try {
193
- const url = new URL(urlString)
85
+ const url = new URL(urlString);
194
86
  // Protocol property includes the colon, e.g., "https:".
195
- return url.protocol === 'http:' || url.protocol === 'https:'
87
+ return url.protocol === "http:" || url.protocol === "https:";
196
88
  } catch (_err) {
197
89
  // String was not a valid URL.
198
- return false
90
+ return false;
199
91
  }
200
92
  }
201
93
 
@@ -203,7 +95,7 @@ function isWebProtocol(urlString) {
203
95
  * SimulationVuer
204
96
  */
205
97
  export default {
206
- name: 'SimulationVuer',
98
+ name: "SimulationVuer",
207
99
  components: {
208
100
  PlotVuer,
209
101
  SimulationVuerInput,
@@ -235,39 +127,39 @@ export default {
235
127
  data: function () {
236
128
  // Determine the ID's type.
237
129
 
238
- let idType
130
+ let idType;
239
131
 
240
- if (typeof this.id === 'number') {
241
- idType = IdType.DATASET_ID
132
+ if (typeof this.id === "number") {
133
+ idType = IdType.DATASET_ID;
242
134
  } else if (this.id instanceof Uint8Array) {
243
- idType = IdType.RAW_COMBINE_ARCHIVE
135
+ idType = IdType.RAW_COMBINE_ARCHIVE;
244
136
  } else if (isWebProtocol(this.id)) {
245
- idType = IdType.DATASET_URL
137
+ idType = IdType.DATASET_URL;
246
138
  } else {
247
- idType = IdType.PMR_PATH
139
+ idType = IdType.PMR_PATH;
248
140
  }
249
141
 
250
142
  // Retrieve some information about the dataset.
251
143
 
252
144
  if (idType === IdType.DATASET_ID) {
253
- const xmlhttp = new XMLHttpRequest()
145
+ const xmlhttp = new XMLHttpRequest();
254
146
 
255
- xmlhttp.open('GET', this.apiLocation + '/sim/dataset/' + this.id)
147
+ xmlhttp.open("GET", this.apiLocation + "/sim/dataset/" + this.id);
256
148
  xmlhttp.onreadystatechange = () => {
257
149
  if (xmlhttp.readyState === 4) {
258
150
  if (xmlhttp.status === 200) {
259
- const datasetInfo = JSON.parse(xmlhttp.responseText)
151
+ const datasetInfo = JSON.parse(xmlhttp.responseText);
260
152
 
261
- this.name = datasetInfo.name
262
- this.uuid = datasetInfo.study !== undefined ? datasetInfo.study.uuid : undefined
153
+ this.name = datasetInfo.name;
154
+ this.uuid = (datasetInfo.study !== undefined) ? datasetInfo.study.uuid : undefined;
263
155
  }
264
156
  }
265
- }
266
- xmlhttp.send()
157
+ };
158
+ xmlhttp.send();
267
159
  }
268
160
 
269
161
  return {
270
- errorMessage: '',
162
+ errorMessage: "",
271
163
  fileManager: undefined,
272
164
  hasFinalisedUi: false,
273
165
  hasValidSimulationUiInfo: false,
@@ -289,12 +181,167 @@ export default {
289
181
  simulationResultsId: {},
290
182
  simulationUiInfo: {},
291
183
  solver: undefined,
292
- userMessage: '',
184
+ userMessage: "",
293
185
  ui: null,
294
186
  uuid: null,
295
- }
187
+ activeSubscriptions: [],
188
+ };
296
189
  },
297
190
  methods: {
191
+ /**
192
+ * @public
193
+ * Add a data subscription.
194
+ * @arg `subscription `
195
+ */
196
+ addDataSubscription(subscription) {
197
+ // Check that the subscription is valid.
198
+
199
+ if (!subscription || typeof subscription !== 'object') {
200
+ console.error('addDataSubscription: subscription must be an object.');
201
+
202
+ return;
203
+ }
204
+
205
+ // Check that the subscription has the expected ID.
206
+
207
+ const EXPECTED_ID = 'nz.ac.auckland.simulation-data-request';
208
+ const EXPECTED_MAJOR_VERSION = 0;
209
+
210
+ if (subscription.id !== EXPECTED_ID) {
211
+ console.warn(`addDataSubscription: invalid ID (expected '${EXPECTED_ID}' but got '${subscription.id}').`);
212
+
213
+ return;
214
+ }
215
+
216
+ // Check that the version is valid and compatible with what we expect.
217
+
218
+ if (typeof subscription.version !== 'string') {
219
+ console.warn(`addDataSubscription: missing or non-string version ('${subscription.version}').`);
220
+
221
+ return;
222
+ }
223
+
224
+ const versionParts = subscription.version.split('.');
225
+
226
+ if (versionParts.length < 1 || !/^[0-9]+$/.test(versionParts[0])) {
227
+ console.warn(`addDataSubscription: malformed version ('${subscription.version}').`);
228
+
229
+ return;
230
+ }
231
+
232
+ const subscriptionMajorVersion = parseInt(versionParts[0], 10);
233
+
234
+ if (Number.isNaN(subscriptionMajorVersion)) {
235
+ console.warn(`addDataSubscription: could not parse the major version from ('${subscription.version}')`);
236
+
237
+ return;
238
+ }
239
+
240
+ if (subscriptionMajorVersion !== EXPECTED_MAJOR_VERSION) {
241
+ console.warn(`addDataSubscription: version mismatch (expected v${EXPECTED_MAJOR_VERSION}.y.z but got v${subscription.version}).`);
242
+
243
+ return;
244
+ }
245
+
246
+ // Check that the payload contains the required fields.
247
+
248
+ const payload = subscription.payload || {};
249
+ const missing = [];
250
+
251
+ if (payload.windowId == null) {
252
+ missing.push('windowId');
253
+ }
254
+
255
+ if (payload.ownerId == null) {
256
+ missing.push('ownerId');
257
+ }
258
+
259
+ if (!payload.component) {
260
+ missing.push('component');
261
+ }
262
+
263
+ if (!payload.variable) {
264
+ missing.push('variable');
265
+ }
266
+
267
+ if (missing.length) {
268
+ console.warn(`addDataSubscription: payload missing fields: ${missing.join(', ')}.`);
269
+
270
+ return;
271
+ }
272
+
273
+ // The subscription is valid, so add it to our list of active subscriptions.
274
+
275
+ this.activeSubscriptions.push(payload);
276
+
277
+ // Build the list of model parameters to be tracked for this subscription.
278
+
279
+ const modelParameters = [];
280
+
281
+ if (subscription.payload?.withVOI) {
282
+ modelParameters.push('VOI');
283
+ }
284
+
285
+ modelParameters.push(`${subscription.payload?.component}/${subscription.payload?.variable}`);
286
+
287
+ this.$refs.opencorRef?.trackSimulationData(modelParameters);
288
+ },
289
+ /**
290
+ * @public
291
+ * Remove a data subscription.
292
+ * @arg `subscriptionId `
293
+ */
294
+ removeDataSubscription(subscriptionId) {
295
+ this.activeSubscriptions = this.activeSubscriptions.filter((activeSubscription) => {
296
+ return activeSubscription.windowId !== subscriptionId;
297
+ });
298
+ },
299
+ /**
300
+ * @public
301
+ * Let the outside world know that we have received some simulation data from OpenCOR by emitting a `data-notification` event.
302
+ * @arg `event`
303
+ */
304
+ onSimulationData(event) {
305
+ const simulationData = event.simulationData || {};
306
+ let voi;
307
+
308
+ this.activeSubscriptions.forEach((activeSubscription) => {
309
+ const modelParameter = `${activeSubscription.component}/${activeSubscription.variable}`;
310
+
311
+ if (simulationData[modelParameter] == null) {
312
+ console.warn(`onSimulationData: no data for ${modelParameter}.`);
313
+
314
+ return;
315
+ }
316
+
317
+ const data = {
318
+ y: Array.from(simulationData[modelParameter]),
319
+ title: `${activeSubscription.component}.${activeSubscription.variable}`,
320
+ };
321
+
322
+ if (activeSubscription.withVOI) {
323
+ if (simulationData.VOI == null) {
324
+ console.warn('onSimulationData: no data for VOI.');
325
+
326
+ return;
327
+ } else {
328
+ voi ??= Array.from(simulationData.VOI);
329
+
330
+ data.x = voi;
331
+ }
332
+ }
333
+
334
+ this.$emit('data-notification', {
335
+ id: 'nz.ac.auckland.simulation-data-response',
336
+ version: '0.1.0',
337
+ payload: {
338
+ windowId: activeSubscription.windowId,
339
+ ownerId: activeSubscription.ownerId,
340
+ data,
341
+ },
342
+ });
343
+ });
344
+ },
298
345
  /**
299
346
  * @public
300
347
  * Generate the metadata associated with the plot which `index` is given.
@@ -302,13 +349,13 @@ export default {
302
349
  */
303
350
  plotMetadata(index) {
304
351
  return {
305
- version: '1.1.0',
306
- type: 'plot',
352
+ version: "1.1.0",
353
+ type: "plot",
307
354
  attrs: {
308
- style: 'timeseries',
355
+ style: "timeseries",
309
356
  layout: this.layout[index],
310
357
  },
311
- }
358
+ };
312
359
  },
313
360
  /**
314
361
  * @public
@@ -318,49 +365,49 @@ export default {
318
365
  buildSimulationUi(simulationUiInfo) {
319
366
  // Keep track of the simulation UI information.
320
367
 
321
- this.simulationUiInfo = simulationUiInfo
368
+ this.simulationUiInfo = simulationUiInfo;
322
369
 
323
370
  // Make sure that the simulation UI information is valid.
324
371
 
325
- this.hasValidSimulationUiInfo = validJson(this.simulationUiInfo)
372
+ this.hasValidSimulationUiInfo = validJson(this.simulationUiInfo);
326
373
 
327
374
  if (!this.hasValidSimulationUiInfo) {
328
- this.errorMessage = 'the simulation.json file is malformed'
375
+ this.errorMessage = "the simulation.json file is malformed";
329
376
 
330
- return
377
+ return;
331
378
  }
332
379
 
333
380
  // Retrieve and keep track of the solver to be used for the simulation.
334
381
 
335
382
  this.simulationUiInfo.simulation.solvers.forEach((solver) => {
336
- if (solver.if === undefined || evaluateValue(this, solver.if)) {
337
- this.solver = solver
383
+ if ((solver.if === undefined) || evaluateValue(this, solver.if)) {
384
+ this.solver = solver;
338
385
  }
339
- })
386
+ });
340
387
 
341
388
  if (this.solver === undefined) {
342
- this.hasValidSimulationUiInfo = false
343
- this.errorMessage = 'no solver name and/or solver version specified'
389
+ this.hasValidSimulationUiInfo = false;
390
+ this.errorMessage = "no solver name and/or solver version specified";
344
391
 
345
- return
392
+ return;
346
393
  }
347
394
 
348
- this.opencorBasedSimulation = this.solver.name === OPENCOR_SOLVER_NAME
395
+ this.opencorBasedSimulation = this.solver.name === OPENCOR_SOLVER_NAME;
349
396
 
350
397
  // Initialise our UI.
351
398
 
352
399
  this.simulationUiInfo.output.data.forEach((data) => {
353
- this.simulationResultsId[data.id] = data.name
354
- })
400
+ this.simulationResultsId[data.id] = data.name;
401
+ });
355
402
 
356
- let index = -1
403
+ let index = -1;
357
404
 
358
405
  this.simulationUiInfo.output.plots.forEach((outputPlot) => {
359
- ++index
406
+ ++index;
360
407
 
361
408
  this.layout[index] = {
362
- paper_bgcolor: 'rgba(0, 0, 0, 0)',
363
- plot_bgcolor: 'rgba(0, 0, 0, 0)',
409
+ paper_bgcolor: "rgba(0, 0, 0, 0)",
410
+ plot_bgcolor: "rgba(0, 0, 0, 0)",
364
411
  autosize: true,
365
412
  margin: {
366
413
  t: 25,
@@ -374,7 +421,7 @@ export default {
374
421
  responsive: true,
375
422
  scrollZoom: true,
376
423
  },
377
- dragmode: 'pan',
424
+ dragmode: "pan",
378
425
  xaxis: {
379
426
  title: {
380
427
  text: outputPlot.xAxisTitle,
@@ -391,8 +438,8 @@ export default {
391
438
  },
392
439
  },
393
440
  },
394
- }
395
- })
441
+ };
442
+ });
396
443
 
397
444
  // Finalise our UI.
398
445
  // Note: we try both here and in the mounted() function since we have no
@@ -400,8 +447,8 @@ export default {
400
447
  // information.
401
448
 
402
449
  this.$nextTick(() => {
403
- finaliseUi(this)
404
- })
450
+ finaliseUi(this);
451
+ });
405
452
  },
406
453
  /**
407
454
  * @public
@@ -410,7 +457,7 @@ export default {
410
457
  * method.
411
458
  */
412
459
  runOnOsparc() {
413
- window.open(`https://osparc.io/study/${this.uuid}`, '_blank')
460
+ window.open(`https://osparc.io/study/${this.uuid}`, "_blank");
414
461
  },
415
462
  /**
416
463
  * @public
@@ -418,7 +465,7 @@ export default {
418
465
  * clicked, calls this method.
419
466
  */
420
467
  viewDataset() {
421
- window.open(`https://sparc.science/datasets/${this.id}?type=dataset`, '_blank')
468
+ window.open(`https://sparc.science/datasets/${this.id}?type=dataset`, "_blank");
422
469
  },
423
470
  /**
424
471
  * @public
@@ -426,22 +473,22 @@ export default {
426
473
  * calls this method.
427
474
  */
428
475
  viewWorkspace() {
429
- const url = PMR_URL + this.id
476
+ const url = PMR_URL + this.id;
430
477
 
431
- window.open(url.substring(0, url.lastIndexOf('/')), '_blank')
478
+ window.open(url.substring(0, url.lastIndexOf("/")), "_blank");
432
479
  },
433
480
  /**
434
481
  * @public
435
482
  * Data needed to set a model's parameters.
436
483
  */
437
484
  parametersData() {
438
- const res = {}
485
+ const res = {};
439
486
 
440
487
  this.simulationUiInfo.parameters.forEach((parameter) => {
441
- res[parameter.name] = evaluateValue(this, parameter.value)
442
- })
488
+ res[parameter.name] = evaluateValue(this, parameter.value);
489
+ });
443
490
 
444
- return res
491
+ return res;
445
492
  },
446
493
  /**
447
494
  * @public
@@ -450,15 +497,15 @@ export default {
450
497
  outputData() {
451
498
  if (this.output === undefined) {
452
499
  if (this.simulationUiInfo.output.data !== undefined) {
453
- this.output = []
500
+ this.output = [];
454
501
 
455
502
  this.simulationUiInfo.output.data.forEach((output) => {
456
- this.output.push(output.name)
457
- })
503
+ this.output.push(output.name);
504
+ });
458
505
  }
459
506
  }
460
507
 
461
- return this.output
508
+ return this.output;
462
509
  },
463
510
  /**
464
511
  * @public
@@ -466,39 +513,37 @@ export default {
466
513
  */
467
514
  retrieveRequest() {
468
515
  const request = {
469
- solver: this.solver,
470
- }
516
+ solver: this.solver
517
+ };
471
518
 
472
519
  if (this.opencorBasedSimulation) {
473
520
  request.opencor = {
474
521
  model_url: this.simulationUiInfo.simulation.opencor.resource,
475
522
  json_config: {},
476
- }
523
+ };
477
524
 
478
- if (
479
- this.simulationUiInfo.simulation.opencor.endingPoint !== undefined &&
480
- this.simulationUiInfo.simulation.opencor.pointInterval !== undefined
481
- ) {
525
+ if ((this.simulationUiInfo.simulation.opencor.endingPoint !== undefined)
526
+ && (this.simulationUiInfo.simulation.opencor.pointInterval !== undefined)) {
482
527
  request.opencor.json_config.simulation = {
483
- 'Ending point': this.simulationUiInfo.simulation.opencor.endingPoint,
484
- 'Point interval': this.simulationUiInfo.simulation.opencor.pointInterval,
485
- }
528
+ "Ending point": this.simulationUiInfo.simulation.opencor.endingPoint,
529
+ "Point interval": this.simulationUiInfo.simulation.opencor.pointInterval,
530
+ };
486
531
  }
487
532
 
488
- request.opencor.json_config.parameters = this.parametersData()
533
+ request.opencor.json_config.parameters = this.parametersData();
489
534
 
490
- const output = this.outputData()
535
+ const output = this.outputData();
491
536
 
492
537
  if (output !== undefined) {
493
- request.opencor.json_config.output = output
538
+ request.opencor.json_config.output = output;
494
539
  }
495
540
  } else {
496
- request.osparc = {}
541
+ request.osparc = {};
497
542
 
498
- request.osparc.job_inputs = this.parametersData()
543
+ request.osparc.job_inputs = this.parametersData();
499
544
  }
500
545
 
501
- return request
546
+ return request;
502
547
  },
503
548
  /**
504
549
  * @public
@@ -510,50 +555,50 @@ export default {
510
555
  // Convert, if needed, the results to a JSON format that is compatible
511
556
  // with our OpenCOR results.
512
557
 
513
- if (typeof results === 'string') {
514
- const SPACES = /[ \t]+/g
515
- const lines = results.trim().split('\n')
516
- const iMax = lines[0].trim().split(SPACES).length
558
+ if (typeof (results) === "string") {
559
+ const SPACES = /[ \t]+/g;
560
+ const lines = results.trim().split("\n");
561
+ const iMax = lines[0].trim().split(SPACES).length;
517
562
 
518
- results = {}
563
+ results = {};
519
564
 
520
565
  for (let i = 0; i < iMax; ++i) {
521
- results[i] = []
566
+ results[i] = [];
522
567
  }
523
568
 
524
- let i = -1
569
+ let i = -1;
525
570
 
526
571
  lines.forEach((line) => {
527
- ++i
572
+ ++i;
528
573
 
529
- let j = -1
530
- const values = line.trim().split(SPACES)
574
+ let j = -1;
575
+ const values = line.trim().split(SPACES);
531
576
 
532
577
  values.forEach((value) => {
533
- results[++j][i] = Number(value)
534
- })
535
- })
578
+ results[++j][i] = Number(value);
579
+ });
580
+ });
536
581
  }
537
582
 
538
583
  // Get the results ready for plotting.
539
584
 
540
- const parser = new math.parser()
585
+ const parser = new math.parser();
541
586
 
542
587
  Object.keys(this.simulationResultsId).forEach((id) => {
543
- parser.set(id, results[this.simulationResultsId[id]])
544
- })
588
+ parser.set(id, results[this.simulationResultsId[id]]);
589
+ });
545
590
 
546
- let index = -1
591
+ let index = -1;
547
592
 
548
593
  this.simulationUiInfo.output.plots.forEach((outputPlot) => {
549
594
  this.simulationResults[++index] = [
550
595
  {
551
596
  x: parser.evaluate(outputPlot.xValue),
552
597
  y: parser.evaluate(outputPlot.yValue),
553
- type: 'scatter',
598
+ type: "scatter",
554
599
  },
555
- ]
556
- })
600
+ ];
601
+ });
557
602
  },
558
603
  /**
559
604
  * @public
@@ -561,15 +606,9 @@ export default {
561
606
  * @arg `xmlhttp`
562
607
  */
563
608
  showHttpIssue(xmlhttp) {
564
- this.isSimulationValid = false
565
- this.showUserMessage = false
566
- this.errorMessage =
567
- xmlhttp.statusText.toLowerCase() +
568
- " (<a href='https://httpstatuses.com/" +
569
- xmlhttp.status +
570
- "/' target='_blank'>" +
571
- xmlhttp.status +
572
- '</a>)'
609
+ this.isSimulationValid = false;
610
+ this.showUserMessage = false;
611
+ this.errorMessage = xmlhttp.statusText.toLowerCase() + " (<a href='https://httpstatuses.com/" + xmlhttp.status + "/' target='_blank'>" + xmlhttp.status + "</a>)";
573
612
  },
574
613
  /**
575
614
  * @public
@@ -581,44 +620,44 @@ export default {
581
620
  checkSimulation(data) {
582
621
  // Check the simulation.
583
622
 
584
- const xmlhttp = new XMLHttpRequest()
623
+ const xmlhttp = new XMLHttpRequest();
585
624
 
586
- xmlhttp.open('POST', this.apiLocation + '/check_simulation')
587
- xmlhttp.setRequestHeader('Content-type', 'application/json')
625
+ xmlhttp.open("POST", this.apiLocation + "/check_simulation");
626
+ xmlhttp.setRequestHeader("Content-type", "application/json");
588
627
  xmlhttp.onreadystatechange = () => {
589
628
  if (xmlhttp.readyState === 4) {
590
629
  if (xmlhttp.status === 200) {
591
- let response = JSON.parse(xmlhttp.responseText)
630
+ let response = JSON.parse(xmlhttp.responseText);
592
631
 
593
- this.isSimulationValid = response.status === 'ok'
632
+ this.isSimulationValid = response.status === "ok";
594
633
 
595
634
  if (this.isSimulationValid) {
596
635
  if (response.results !== undefined) {
597
636
  // The simulation is finished, so process its results.
598
637
 
599
- this.showUserMessage = false
638
+ this.showUserMessage = false;
600
639
 
601
- this.processSimulationResults(response.results)
640
+ this.processSimulationResults(response.results);
602
641
  } else {
603
642
  // The simulation is not yet finished, so check again in a
604
643
  // second.
605
644
 
606
- let that = this
645
+ let that = this;
607
646
 
608
647
  setTimeout(function () {
609
- that.checkSimulation(data)
610
- }, 1000)
648
+ that.checkSimulation(data);
649
+ }, 1000);
611
650
  }
612
651
  } else {
613
- this.showUserMessage = false
614
- this.errorMessage = response.description
652
+ this.showUserMessage = false;
653
+ this.errorMessage = response.description;
615
654
  }
616
655
  } else {
617
- this.showHttpIssue(xmlhttp)
656
+ this.showHttpIssue(xmlhttp);
618
657
  }
619
658
  }
620
- }
621
- xmlhttp.send(JSON.stringify(data))
659
+ };
660
+ xmlhttp.send(JSON.stringify(data));
622
661
  },
623
662
  /**
624
663
  * @public
@@ -629,73 +668,72 @@ export default {
629
668
  // Start the simulation (after resetting our previous simulation data, in
630
669
  // case there were sonme).
631
670
 
632
- this.userMessage = 'Loading simulation results...'
633
- this.showUserMessage = true
671
+ this.userMessage = "Loading simulation results...";
672
+ this.showUserMessage = true;
634
673
 
635
674
  this.$nextTick(() => {
636
- this.simulationResults = {}
675
+ this.simulationResults = {};
637
676
 
638
- const xmlhttp = new XMLHttpRequest()
677
+ const xmlhttp = new XMLHttpRequest();
639
678
 
640
- xmlhttp.open('POST', this.apiLocation + '/start_simulation')
641
- xmlhttp.setRequestHeader('Content-type', 'application/json')
679
+ xmlhttp.open("POST", this.apiLocation + "/start_simulation");
680
+ xmlhttp.setRequestHeader("Content-type", "application/json");
642
681
  xmlhttp.onreadystatechange = () => {
643
682
  if (xmlhttp.readyState === 4) {
644
683
  if (xmlhttp.status === 200) {
645
- let response = JSON.parse(xmlhttp.responseText)
684
+ let response = JSON.parse(xmlhttp.responseText);
646
685
 
647
- this.isSimulationValid = response.status === 'ok'
686
+ this.isSimulationValid = response.status === "ok";
648
687
 
649
688
  if (this.isSimulationValid) {
650
- this.checkSimulation(response.data)
689
+ this.checkSimulation(response.data);
651
690
  } else {
652
- this.showUserMessage = false
653
- this.errorMessage = response.description
691
+ this.showUserMessage = false;
692
+ this.errorMessage = response.description;
654
693
  }
655
694
  } else {
656
- this.showHttpIssue(xmlhttp)
695
+ this.showHttpIssue(xmlhttp);
657
696
  }
658
697
  }
659
- }
660
- xmlhttp.send(JSON.stringify(this.retrieveRequest()))
661
- })
698
+ };
699
+ xmlhttp.send(JSON.stringify(this.retrieveRequest()));
700
+ });
662
701
  },
663
702
  },
664
703
  created: function () {
665
704
  // Try to retrieve the UI information.
666
705
 
667
706
  if (this.idType === IdType.DATASET_ID) {
668
- this.userMessage = 'Retrieving UI information...'
669
- this.showUserMessage = true
707
+ this.userMessage = "Retrieving UI information...";
708
+ this.showUserMessage = true;
670
709
 
671
710
  // Retrieve and build the simulation UI.
672
711
 
673
712
  this.$nextTick(() => {
674
- const xmlhttp = new XMLHttpRequest()
713
+ const xmlhttp = new XMLHttpRequest();
675
714
 
676
- xmlhttp.open('GET', this.apiLocation + '/simulation_ui_file/' + this.id)
715
+ xmlhttp.open("GET", this.apiLocation + "/simulation_ui_file/" + this.id);
677
716
  xmlhttp.onreadystatechange = () => {
678
717
  if (xmlhttp.readyState === 4) {
679
- this.showUserMessage = false
718
+ this.showUserMessage = false;
680
719
 
681
720
  if (xmlhttp.status === 200) {
682
721
  this.$nextTick(() => {
683
- this.buildSimulationUi(JSON.parse(xmlhttp.responseText))
684
- })
722
+ this.buildSimulationUi(JSON.parse(xmlhttp.responseText));
723
+ });
685
724
  } else {
686
- this.errorMessage = 'the simulation dataset could not be retrieved'
725
+ this.errorMessage = "the simulation dataset could not be retrieved";
687
726
  }
688
727
  }
689
- }
690
- xmlhttp.send()
691
- })
728
+ };
729
+ xmlhttp.send();
730
+ });
692
731
  } else if (this.idType === IdType.DATASET_URL) {
693
- this.opencorOmexFile = this.id
732
+ this.opencorOmexFile = this.id;
694
733
  } else if (this.idType === IdType.PMR_PATH) {
695
- this.opencorOmexFile = PMR_URL + this.id
696
- } else {
697
- // IdType.RAW_COMBINE_ARCHIVE
698
- this.opencorOmexFile = this.id
734
+ this.opencorOmexFile = PMR_URL + this.id;
735
+ } else { // IdType.RAW_COMBINE_ARCHIVE
736
+ this.opencorOmexFile = this.id;
699
737
  }
700
738
  },
701
739
  mounted: function () {
@@ -704,20 +742,20 @@ export default {
704
742
  // idea how long it's going to take to retrieve the simulation UI
705
743
  // information.
706
744
 
707
- this.isMounted = true
745
+ this.isMounted = true;
708
746
 
709
- finaliseUi(this)
747
+ finaliseUi(this);
710
748
  },
711
- }
749
+ };
712
750
  </script>
713
751
 
714
752
  <!-- Add "scoped" attribute to limit CSS to this component only -->
715
753
  <style scoped lang="scss">
716
754
  .simulation-vuer {
717
- --el-color-primary: #8300bf;
718
- --el-color-primary-light-7: #dab3ec;
719
- --el-color-primary-light-8: #e6ccf2;
720
- --el-color-primary-light-9: #f3e6f9;
755
+ --el-color-primary: #8300BF;
756
+ --el-color-primary-light-7: #DAB3EC;
757
+ --el-color-primary-light-8: #E6CCF2;
758
+ --el-color-primary-light-9: #F3E6F9;
721
759
  }
722
760
 
723
761
  :deep(.el-button:hover) {
@@ -731,32 +769,29 @@ export default {
731
769
 
732
770
  :deep(.el-loading-spinner) {
733
771
  .path {
734
- stroke: #8300bf;
772
+ stroke: #8300BF;
735
773
  }
736
774
 
737
775
  i,
738
776
  .el-loading-text {
739
- color: #8300bf;
777
+ color: #8300BF;
740
778
  }
741
779
  }
742
780
 
743
- :deep(.p-floatlabel:has(input:focus)) label,
744
- :deep(.p-floatlabel:has(input:-webkit-autofill)) label,
745
- :deep(.p-floatlabel:has(textarea:focus)) label,
746
- :deep(.p-floatlabel:has(.p-inputwrapper-focus)) label {
747
- color: #8300bf;
781
+ :deep(.p-floatlabel:has(input:focus)) label, :deep(.p-floatlabel:has(input:-webkit-autofill)) label, :deep(.p-floatlabel:has(textarea:focus)) label, :deep(.p-floatlabel:has(.p-inputwrapper-focus)) label {
782
+ color: #8300BF;
748
783
  }
749
784
 
750
785
  :deep(.p-inputtext:enabled:focus) {
751
- border-color: #8300bf;
786
+ border-color: #8300BF;
752
787
  }
753
788
 
754
789
  :deep(.p-select:not(.p-disabled).p-focus) {
755
- border-color: #8300bf;
790
+ border-color: #8300BF;
756
791
  }
757
792
 
758
793
  :deep(.p-slider-range) {
759
- background-color: #8300bf;
794
+ background-color: #8300BF;
760
795
  }
761
796
 
762
797
  div.input {
@@ -958,23 +993,26 @@ span.error {
958
993
  <style>
959
994
  /* Note: not sure why, but the following rules need to be global!? */
960
995
 
996
+ .p-progressbar-value {
997
+ background-color: #8300BF !important;
998
+ }
999
+
961
1000
  .p-select-option:not(.p-select-option-selected):not(.p-disabled).p-focus {
962
- background: #f5f7fa !important;
1001
+ background: #F5F7FA !important;
963
1002
  }
964
1003
 
965
1004
  .p-select-option.p-select-option-selected.p-focus {
966
- background: #f5f7fa !important;
967
- color: #8300bf !important;
1005
+ background: #F5F7FA !important;
1006
+ color: #8300BF !important;
968
1007
  }
969
1008
 
970
1009
  .p-select-option.p-select-option-selected {
971
- background: white !important;
972
- color: #8300bf !important;
1010
+ background: white !important;
1011
+ color: #8300BF !important;
973
1012
  }
974
1013
 
975
1014
  .p-select-option-label {
976
- font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Fira Sans',
977
- 'Droid Sans', 'Helvetica Neue', sans-serif;
978
- font-size: 0.875rem;
1015
+ font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
1016
+ font-size: 0.875rem;
979
1017
  }
980
1018
  </style>