@abi-software/simulationvuer 3.0.9 → 3.0.10-beta.0
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 +1 -1
- package/src/components/SimulationVuer.vue +313 -176
- package/src/components.d.ts +3 -0
- package/dist/favicon.ico +0 -0
- package/dist/index-fCMLAifd.js +0 -71260
- package/dist/index.html +0 -17
- package/dist/quill-CCULFmEg-CRsckMP4.js +0 -7524
- package/dist/simulationvuer.js +0 -4
- package/dist/simulationvuer.umd.cjs +0 -5334
- package/dist/style.css +0 -1
|
@@ -1,14 +1,17 @@
|
|
|
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"
|
|
4
|
+
<p v-if="!hasValidSimulationUiInfo && !showUserMessage" class="default error">
|
|
5
|
+
<span class="error">Error:</span> {{ errorMessage }}.
|
|
6
|
+
</p>
|
|
5
7
|
<div class="main" v-if="hasValidSimulationUiInfo">
|
|
6
|
-
<div class="main-left" :class="{'with-buttons': uuid}">
|
|
8
|
+
<div class="main-left" :class="{ 'with-buttons': uuid }">
|
|
7
9
|
<p class="default name">{{ name }}</p>
|
|
8
10
|
<el-divider></el-divider>
|
|
9
11
|
<p class="default input-parameters">Input parameters</p>
|
|
10
12
|
<div class="input scrollbar">
|
|
11
|
-
<SimulationVuerInput
|
|
13
|
+
<SimulationVuerInput
|
|
14
|
+
v-for="(input, index) in simulationUiInfo.input"
|
|
12
15
|
ref="simInput"
|
|
13
16
|
:defaultValue="input.defaultValue"
|
|
14
17
|
:key="`input-${index}`"
|
|
@@ -33,7 +36,8 @@
|
|
|
33
36
|
</div>
|
|
34
37
|
</div>
|
|
35
38
|
<div class="main-right" ref="output" v-show="isSimulationValid">
|
|
36
|
-
<PlotVuer
|
|
39
|
+
<PlotVuer
|
|
40
|
+
v-for="(_outputPlot, index) in simulationUiInfo.output.plots"
|
|
37
41
|
:key="`output-${index}`"
|
|
38
42
|
:metadata="plotMetadata(index)"
|
|
39
43
|
:data-source="{ data: simulationResults[index] }"
|
|
@@ -43,7 +47,10 @@
|
|
|
43
47
|
/>
|
|
44
48
|
</div>
|
|
45
49
|
<div class="main-right" v-show="!isSimulationValid">
|
|
46
|
-
<p class="default error"
|
|
50
|
+
<p class="default error">
|
|
51
|
+
<span class="error">Error:</span>
|
|
52
|
+
<span v-html="errorMessage"></span>.
|
|
53
|
+
</p>
|
|
47
54
|
</div>
|
|
48
55
|
</div>
|
|
49
56
|
</div>
|
|
@@ -53,33 +60,150 @@
|
|
|
53
60
|
</div>
|
|
54
61
|
</template>
|
|
55
62
|
|
|
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
|
+
|
|
56
169
|
<script>
|
|
57
|
-
import { PlotVuer } from
|
|
58
|
-
import
|
|
59
|
-
import SimulationVuerInput from
|
|
60
|
-
import { ElButton, ElDivider, ElLoading } from
|
|
61
|
-
import { evaluateValue, finaliseUi, OPENCOR_SOLVER_NAME } from
|
|
62
|
-
import { validJson } from
|
|
63
|
-
import { create, all } from
|
|
64
|
-
import OpenCOR from '@opencor/opencor'
|
|
65
|
-
import '@opencor/opencor/style.css'
|
|
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'
|
|
66
179
|
|
|
67
|
-
const PMR_URL =
|
|
180
|
+
const PMR_URL = 'https://models.physiomeproject.org/'
|
|
68
181
|
|
|
69
|
-
const math = create(all, {})
|
|
182
|
+
const math = create(all, {})
|
|
70
183
|
|
|
71
184
|
const IdType = Object.freeze({
|
|
72
185
|
DATASET_ID: 'dataset_id',
|
|
73
186
|
DATASET_URL: 'dataset_url',
|
|
74
187
|
PMR_PATH: 'pmr_path',
|
|
75
188
|
RAW_COMBINE_ARCHIVE: 'raw_combine_archive',
|
|
76
|
-
})
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
function isWebProtocol(urlString) {
|
|
192
|
+
try {
|
|
193
|
+
const url = new URL(urlString)
|
|
194
|
+
// Protocol property includes the colon, e.g., "https:".
|
|
195
|
+
return url.protocol === 'http:' || url.protocol === 'https:'
|
|
196
|
+
} catch (_err) {
|
|
197
|
+
// String was not a valid URL.
|
|
198
|
+
return false
|
|
199
|
+
}
|
|
200
|
+
}
|
|
77
201
|
|
|
78
202
|
/**
|
|
79
203
|
* SimulationVuer
|
|
80
204
|
*/
|
|
81
205
|
export default {
|
|
82
|
-
name:
|
|
206
|
+
name: 'SimulationVuer',
|
|
83
207
|
components: {
|
|
84
208
|
PlotVuer,
|
|
85
209
|
SimulationVuerInput,
|
|
@@ -111,39 +235,39 @@ export default {
|
|
|
111
235
|
data: function () {
|
|
112
236
|
// Determine the ID's type.
|
|
113
237
|
|
|
114
|
-
let idType
|
|
238
|
+
let idType
|
|
115
239
|
|
|
116
|
-
if (typeof this.id ===
|
|
117
|
-
idType = IdType.DATASET_ID
|
|
240
|
+
if (typeof this.id === 'number') {
|
|
241
|
+
idType = IdType.DATASET_ID
|
|
118
242
|
} else if (this.id instanceof Uint8Array) {
|
|
119
|
-
idType = IdType.RAW_COMBINE_ARCHIVE
|
|
120
|
-
} else if (this.id
|
|
121
|
-
idType = IdType.DATASET_URL
|
|
243
|
+
idType = IdType.RAW_COMBINE_ARCHIVE
|
|
244
|
+
} else if (isWebProtocol(this.id)) {
|
|
245
|
+
idType = IdType.DATASET_URL
|
|
122
246
|
} else {
|
|
123
|
-
idType = IdType.PMR_PATH
|
|
247
|
+
idType = IdType.PMR_PATH
|
|
124
248
|
}
|
|
125
249
|
|
|
126
250
|
// Retrieve some information about the dataset.
|
|
127
251
|
|
|
128
252
|
if (idType === IdType.DATASET_ID) {
|
|
129
|
-
const xmlhttp = new XMLHttpRequest()
|
|
253
|
+
const xmlhttp = new XMLHttpRequest()
|
|
130
254
|
|
|
131
|
-
xmlhttp.open(
|
|
255
|
+
xmlhttp.open('GET', this.apiLocation + '/sim/dataset/' + this.id)
|
|
132
256
|
xmlhttp.onreadystatechange = () => {
|
|
133
257
|
if (xmlhttp.readyState === 4) {
|
|
134
258
|
if (xmlhttp.status === 200) {
|
|
135
|
-
const datasetInfo = JSON.parse(xmlhttp.responseText)
|
|
259
|
+
const datasetInfo = JSON.parse(xmlhttp.responseText)
|
|
136
260
|
|
|
137
|
-
this.name = datasetInfo.name
|
|
138
|
-
this.uuid =
|
|
261
|
+
this.name = datasetInfo.name
|
|
262
|
+
this.uuid = datasetInfo.study !== undefined ? datasetInfo.study.uuid : undefined
|
|
139
263
|
}
|
|
140
264
|
}
|
|
141
|
-
}
|
|
142
|
-
xmlhttp.send()
|
|
265
|
+
}
|
|
266
|
+
xmlhttp.send()
|
|
143
267
|
}
|
|
144
268
|
|
|
145
269
|
return {
|
|
146
|
-
errorMessage:
|
|
270
|
+
errorMessage: '',
|
|
147
271
|
fileManager: undefined,
|
|
148
272
|
hasFinalisedUi: false,
|
|
149
273
|
hasValidSimulationUiInfo: false,
|
|
@@ -165,10 +289,10 @@ export default {
|
|
|
165
289
|
simulationResultsId: {},
|
|
166
290
|
simulationUiInfo: {},
|
|
167
291
|
solver: undefined,
|
|
168
|
-
userMessage:
|
|
292
|
+
userMessage: '',
|
|
169
293
|
ui: null,
|
|
170
294
|
uuid: null,
|
|
171
|
-
}
|
|
295
|
+
}
|
|
172
296
|
},
|
|
173
297
|
methods: {
|
|
174
298
|
/**
|
|
@@ -178,13 +302,13 @@ export default {
|
|
|
178
302
|
*/
|
|
179
303
|
plotMetadata(index) {
|
|
180
304
|
return {
|
|
181
|
-
version:
|
|
182
|
-
type:
|
|
305
|
+
version: '1.1.0',
|
|
306
|
+
type: 'plot',
|
|
183
307
|
attrs: {
|
|
184
|
-
style:
|
|
308
|
+
style: 'timeseries',
|
|
185
309
|
layout: this.layout[index],
|
|
186
310
|
},
|
|
187
|
-
}
|
|
311
|
+
}
|
|
188
312
|
},
|
|
189
313
|
/**
|
|
190
314
|
* @public
|
|
@@ -194,49 +318,49 @@ export default {
|
|
|
194
318
|
buildSimulationUi(simulationUiInfo) {
|
|
195
319
|
// Keep track of the simulation UI information.
|
|
196
320
|
|
|
197
|
-
this.simulationUiInfo = simulationUiInfo
|
|
321
|
+
this.simulationUiInfo = simulationUiInfo
|
|
198
322
|
|
|
199
323
|
// Make sure that the simulation UI information is valid.
|
|
200
324
|
|
|
201
|
-
this.hasValidSimulationUiInfo = validJson(this.simulationUiInfo)
|
|
325
|
+
this.hasValidSimulationUiInfo = validJson(this.simulationUiInfo)
|
|
202
326
|
|
|
203
327
|
if (!this.hasValidSimulationUiInfo) {
|
|
204
|
-
this.errorMessage =
|
|
328
|
+
this.errorMessage = 'the simulation.json file is malformed'
|
|
205
329
|
|
|
206
|
-
return
|
|
330
|
+
return
|
|
207
331
|
}
|
|
208
332
|
|
|
209
333
|
// Retrieve and keep track of the solver to be used for the simulation.
|
|
210
334
|
|
|
211
335
|
this.simulationUiInfo.simulation.solvers.forEach((solver) => {
|
|
212
|
-
if (
|
|
213
|
-
this.solver = solver
|
|
336
|
+
if (solver.if === undefined || evaluateValue(this, solver.if)) {
|
|
337
|
+
this.solver = solver
|
|
214
338
|
}
|
|
215
|
-
})
|
|
339
|
+
})
|
|
216
340
|
|
|
217
341
|
if (this.solver === undefined) {
|
|
218
|
-
this.hasValidSimulationUiInfo = false
|
|
219
|
-
this.errorMessage =
|
|
342
|
+
this.hasValidSimulationUiInfo = false
|
|
343
|
+
this.errorMessage = 'no solver name and/or solver version specified'
|
|
220
344
|
|
|
221
|
-
return
|
|
345
|
+
return
|
|
222
346
|
}
|
|
223
347
|
|
|
224
|
-
this.opencorBasedSimulation = this.solver.name === OPENCOR_SOLVER_NAME
|
|
348
|
+
this.opencorBasedSimulation = this.solver.name === OPENCOR_SOLVER_NAME
|
|
225
349
|
|
|
226
350
|
// Initialise our UI.
|
|
227
351
|
|
|
228
352
|
this.simulationUiInfo.output.data.forEach((data) => {
|
|
229
|
-
this.simulationResultsId[data.id] = data.name
|
|
230
|
-
})
|
|
353
|
+
this.simulationResultsId[data.id] = data.name
|
|
354
|
+
})
|
|
231
355
|
|
|
232
|
-
let index = -1
|
|
356
|
+
let index = -1
|
|
233
357
|
|
|
234
358
|
this.simulationUiInfo.output.plots.forEach((outputPlot) => {
|
|
235
|
-
++index
|
|
359
|
+
++index
|
|
236
360
|
|
|
237
361
|
this.layout[index] = {
|
|
238
|
-
paper_bgcolor:
|
|
239
|
-
plot_bgcolor:
|
|
362
|
+
paper_bgcolor: 'rgba(0, 0, 0, 0)',
|
|
363
|
+
plot_bgcolor: 'rgba(0, 0, 0, 0)',
|
|
240
364
|
autosize: true,
|
|
241
365
|
margin: {
|
|
242
366
|
t: 25,
|
|
@@ -250,7 +374,7 @@ export default {
|
|
|
250
374
|
responsive: true,
|
|
251
375
|
scrollZoom: true,
|
|
252
376
|
},
|
|
253
|
-
dragmode:
|
|
377
|
+
dragmode: 'pan',
|
|
254
378
|
xaxis: {
|
|
255
379
|
title: {
|
|
256
380
|
text: outputPlot.xAxisTitle,
|
|
@@ -267,8 +391,8 @@ export default {
|
|
|
267
391
|
},
|
|
268
392
|
},
|
|
269
393
|
},
|
|
270
|
-
}
|
|
271
|
-
})
|
|
394
|
+
}
|
|
395
|
+
})
|
|
272
396
|
|
|
273
397
|
// Finalise our UI.
|
|
274
398
|
// Note: we try both here and in the mounted() function since we have no
|
|
@@ -276,8 +400,8 @@ export default {
|
|
|
276
400
|
// information.
|
|
277
401
|
|
|
278
402
|
this.$nextTick(() => {
|
|
279
|
-
finaliseUi(this)
|
|
280
|
-
})
|
|
403
|
+
finaliseUi(this)
|
|
404
|
+
})
|
|
281
405
|
},
|
|
282
406
|
/**
|
|
283
407
|
* @public
|
|
@@ -286,7 +410,7 @@ export default {
|
|
|
286
410
|
* method.
|
|
287
411
|
*/
|
|
288
412
|
runOnOsparc() {
|
|
289
|
-
window.open(`https://osparc.io/study/${this.uuid}`,
|
|
413
|
+
window.open(`https://osparc.io/study/${this.uuid}`, '_blank')
|
|
290
414
|
},
|
|
291
415
|
/**
|
|
292
416
|
* @public
|
|
@@ -294,7 +418,7 @@ export default {
|
|
|
294
418
|
* clicked, calls this method.
|
|
295
419
|
*/
|
|
296
420
|
viewDataset() {
|
|
297
|
-
window.open(`https://sparc.science/datasets/${this.id}?type=dataset`,
|
|
421
|
+
window.open(`https://sparc.science/datasets/${this.id}?type=dataset`, '_blank')
|
|
298
422
|
},
|
|
299
423
|
/**
|
|
300
424
|
* @public
|
|
@@ -302,22 +426,22 @@ export default {
|
|
|
302
426
|
* calls this method.
|
|
303
427
|
*/
|
|
304
428
|
viewWorkspace() {
|
|
305
|
-
const url = PMR_URL + this.id
|
|
429
|
+
const url = PMR_URL + this.id
|
|
306
430
|
|
|
307
|
-
window.open(url.substring(0, url.lastIndexOf(
|
|
431
|
+
window.open(url.substring(0, url.lastIndexOf('/')), '_blank')
|
|
308
432
|
},
|
|
309
433
|
/**
|
|
310
434
|
* @public
|
|
311
435
|
* Data needed to set a model's parameters.
|
|
312
436
|
*/
|
|
313
437
|
parametersData() {
|
|
314
|
-
const res = {}
|
|
438
|
+
const res = {}
|
|
315
439
|
|
|
316
440
|
this.simulationUiInfo.parameters.forEach((parameter) => {
|
|
317
|
-
res[parameter.name] = evaluateValue(this, parameter.value)
|
|
318
|
-
})
|
|
441
|
+
res[parameter.name] = evaluateValue(this, parameter.value)
|
|
442
|
+
})
|
|
319
443
|
|
|
320
|
-
return res
|
|
444
|
+
return res
|
|
321
445
|
},
|
|
322
446
|
/**
|
|
323
447
|
* @public
|
|
@@ -326,15 +450,15 @@ export default {
|
|
|
326
450
|
outputData() {
|
|
327
451
|
if (this.output === undefined) {
|
|
328
452
|
if (this.simulationUiInfo.output.data !== undefined) {
|
|
329
|
-
this.output = []
|
|
453
|
+
this.output = []
|
|
330
454
|
|
|
331
455
|
this.simulationUiInfo.output.data.forEach((output) => {
|
|
332
|
-
this.output.push(output.name)
|
|
333
|
-
})
|
|
456
|
+
this.output.push(output.name)
|
|
457
|
+
})
|
|
334
458
|
}
|
|
335
459
|
}
|
|
336
460
|
|
|
337
|
-
return this.output
|
|
461
|
+
return this.output
|
|
338
462
|
},
|
|
339
463
|
/**
|
|
340
464
|
* @public
|
|
@@ -342,37 +466,39 @@ export default {
|
|
|
342
466
|
*/
|
|
343
467
|
retrieveRequest() {
|
|
344
468
|
const request = {
|
|
345
|
-
solver: this.solver
|
|
346
|
-
}
|
|
469
|
+
solver: this.solver,
|
|
470
|
+
}
|
|
347
471
|
|
|
348
472
|
if (this.opencorBasedSimulation) {
|
|
349
473
|
request.opencor = {
|
|
350
474
|
model_url: this.simulationUiInfo.simulation.opencor.resource,
|
|
351
475
|
json_config: {},
|
|
352
|
-
}
|
|
476
|
+
}
|
|
353
477
|
|
|
354
|
-
if (
|
|
355
|
-
|
|
478
|
+
if (
|
|
479
|
+
this.simulationUiInfo.simulation.opencor.endingPoint !== undefined &&
|
|
480
|
+
this.simulationUiInfo.simulation.opencor.pointInterval !== undefined
|
|
481
|
+
) {
|
|
356
482
|
request.opencor.json_config.simulation = {
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
}
|
|
483
|
+
'Ending point': this.simulationUiInfo.simulation.opencor.endingPoint,
|
|
484
|
+
'Point interval': this.simulationUiInfo.simulation.opencor.pointInterval,
|
|
485
|
+
}
|
|
360
486
|
}
|
|
361
487
|
|
|
362
|
-
request.opencor.json_config.parameters = this.parametersData()
|
|
488
|
+
request.opencor.json_config.parameters = this.parametersData()
|
|
363
489
|
|
|
364
|
-
const output = this.outputData()
|
|
490
|
+
const output = this.outputData()
|
|
365
491
|
|
|
366
492
|
if (output !== undefined) {
|
|
367
|
-
request.opencor.json_config.output = output
|
|
493
|
+
request.opencor.json_config.output = output
|
|
368
494
|
}
|
|
369
495
|
} else {
|
|
370
|
-
request.osparc = {}
|
|
496
|
+
request.osparc = {}
|
|
371
497
|
|
|
372
|
-
request.osparc.job_inputs = this.parametersData()
|
|
498
|
+
request.osparc.job_inputs = this.parametersData()
|
|
373
499
|
}
|
|
374
500
|
|
|
375
|
-
return request
|
|
501
|
+
return request
|
|
376
502
|
},
|
|
377
503
|
/**
|
|
378
504
|
* @public
|
|
@@ -384,50 +510,50 @@ export default {
|
|
|
384
510
|
// Convert, if needed, the results to a JSON format that is compatible
|
|
385
511
|
// with our OpenCOR results.
|
|
386
512
|
|
|
387
|
-
if (typeof
|
|
388
|
-
const SPACES = /[ \t]+/g
|
|
389
|
-
const lines = results.trim().split(
|
|
390
|
-
const iMax = lines[0].trim().split(SPACES).length
|
|
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
|
|
391
517
|
|
|
392
|
-
results = {}
|
|
518
|
+
results = {}
|
|
393
519
|
|
|
394
520
|
for (let i = 0; i < iMax; ++i) {
|
|
395
|
-
results[i] = []
|
|
521
|
+
results[i] = []
|
|
396
522
|
}
|
|
397
523
|
|
|
398
|
-
let i = -1
|
|
524
|
+
let i = -1
|
|
399
525
|
|
|
400
526
|
lines.forEach((line) => {
|
|
401
|
-
++i
|
|
527
|
+
++i
|
|
402
528
|
|
|
403
|
-
let j = -1
|
|
404
|
-
const values = line.trim().split(SPACES)
|
|
529
|
+
let j = -1
|
|
530
|
+
const values = line.trim().split(SPACES)
|
|
405
531
|
|
|
406
532
|
values.forEach((value) => {
|
|
407
|
-
results[++j][i] = Number(value)
|
|
408
|
-
})
|
|
409
|
-
})
|
|
533
|
+
results[++j][i] = Number(value)
|
|
534
|
+
})
|
|
535
|
+
})
|
|
410
536
|
}
|
|
411
537
|
|
|
412
538
|
// Get the results ready for plotting.
|
|
413
539
|
|
|
414
|
-
const parser = new math.parser()
|
|
540
|
+
const parser = new math.parser()
|
|
415
541
|
|
|
416
542
|
Object.keys(this.simulationResultsId).forEach((id) => {
|
|
417
|
-
parser.set(id, results[this.simulationResultsId[id]])
|
|
418
|
-
})
|
|
543
|
+
parser.set(id, results[this.simulationResultsId[id]])
|
|
544
|
+
})
|
|
419
545
|
|
|
420
|
-
let index = -1
|
|
546
|
+
let index = -1
|
|
421
547
|
|
|
422
548
|
this.simulationUiInfo.output.plots.forEach((outputPlot) => {
|
|
423
549
|
this.simulationResults[++index] = [
|
|
424
550
|
{
|
|
425
551
|
x: parser.evaluate(outputPlot.xValue),
|
|
426
552
|
y: parser.evaluate(outputPlot.yValue),
|
|
427
|
-
type:
|
|
553
|
+
type: 'scatter',
|
|
428
554
|
},
|
|
429
|
-
]
|
|
430
|
-
})
|
|
555
|
+
]
|
|
556
|
+
})
|
|
431
557
|
},
|
|
432
558
|
/**
|
|
433
559
|
* @public
|
|
@@ -435,9 +561,15 @@ export default {
|
|
|
435
561
|
* @arg `xmlhttp`
|
|
436
562
|
*/
|
|
437
563
|
showHttpIssue(xmlhttp) {
|
|
438
|
-
this.isSimulationValid = false
|
|
439
|
-
this.showUserMessage = false
|
|
440
|
-
this.errorMessage =
|
|
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>)'
|
|
441
573
|
},
|
|
442
574
|
/**
|
|
443
575
|
* @public
|
|
@@ -449,44 +581,44 @@ export default {
|
|
|
449
581
|
checkSimulation(data) {
|
|
450
582
|
// Check the simulation.
|
|
451
583
|
|
|
452
|
-
const xmlhttp = new XMLHttpRequest()
|
|
584
|
+
const xmlhttp = new XMLHttpRequest()
|
|
453
585
|
|
|
454
|
-
xmlhttp.open(
|
|
455
|
-
xmlhttp.setRequestHeader(
|
|
586
|
+
xmlhttp.open('POST', this.apiLocation + '/check_simulation')
|
|
587
|
+
xmlhttp.setRequestHeader('Content-type', 'application/json')
|
|
456
588
|
xmlhttp.onreadystatechange = () => {
|
|
457
589
|
if (xmlhttp.readyState === 4) {
|
|
458
590
|
if (xmlhttp.status === 200) {
|
|
459
|
-
let response = JSON.parse(xmlhttp.responseText)
|
|
591
|
+
let response = JSON.parse(xmlhttp.responseText)
|
|
460
592
|
|
|
461
|
-
this.isSimulationValid = response.status ===
|
|
593
|
+
this.isSimulationValid = response.status === 'ok'
|
|
462
594
|
|
|
463
595
|
if (this.isSimulationValid) {
|
|
464
596
|
if (response.results !== undefined) {
|
|
465
597
|
// The simulation is finished, so process its results.
|
|
466
598
|
|
|
467
|
-
this.showUserMessage = false
|
|
599
|
+
this.showUserMessage = false
|
|
468
600
|
|
|
469
|
-
this.processSimulationResults(response.results)
|
|
601
|
+
this.processSimulationResults(response.results)
|
|
470
602
|
} else {
|
|
471
603
|
// The simulation is not yet finished, so check again in a
|
|
472
604
|
// second.
|
|
473
605
|
|
|
474
|
-
let that = this
|
|
606
|
+
let that = this
|
|
475
607
|
|
|
476
608
|
setTimeout(function () {
|
|
477
|
-
that.checkSimulation(data)
|
|
478
|
-
}, 1000)
|
|
609
|
+
that.checkSimulation(data)
|
|
610
|
+
}, 1000)
|
|
479
611
|
}
|
|
480
612
|
} else {
|
|
481
|
-
this.showUserMessage = false
|
|
482
|
-
this.errorMessage = response.description
|
|
613
|
+
this.showUserMessage = false
|
|
614
|
+
this.errorMessage = response.description
|
|
483
615
|
}
|
|
484
616
|
} else {
|
|
485
|
-
this.showHttpIssue(xmlhttp)
|
|
617
|
+
this.showHttpIssue(xmlhttp)
|
|
486
618
|
}
|
|
487
619
|
}
|
|
488
|
-
}
|
|
489
|
-
xmlhttp.send(JSON.stringify(data))
|
|
620
|
+
}
|
|
621
|
+
xmlhttp.send(JSON.stringify(data))
|
|
490
622
|
},
|
|
491
623
|
/**
|
|
492
624
|
* @public
|
|
@@ -497,72 +629,73 @@ export default {
|
|
|
497
629
|
// Start the simulation (after resetting our previous simulation data, in
|
|
498
630
|
// case there were sonme).
|
|
499
631
|
|
|
500
|
-
this.userMessage =
|
|
501
|
-
this.showUserMessage = true
|
|
632
|
+
this.userMessage = 'Loading simulation results...'
|
|
633
|
+
this.showUserMessage = true
|
|
502
634
|
|
|
503
635
|
this.$nextTick(() => {
|
|
504
|
-
this.simulationResults = {}
|
|
636
|
+
this.simulationResults = {}
|
|
505
637
|
|
|
506
|
-
const xmlhttp = new XMLHttpRequest()
|
|
638
|
+
const xmlhttp = new XMLHttpRequest()
|
|
507
639
|
|
|
508
|
-
xmlhttp.open(
|
|
509
|
-
xmlhttp.setRequestHeader(
|
|
640
|
+
xmlhttp.open('POST', this.apiLocation + '/start_simulation')
|
|
641
|
+
xmlhttp.setRequestHeader('Content-type', 'application/json')
|
|
510
642
|
xmlhttp.onreadystatechange = () => {
|
|
511
643
|
if (xmlhttp.readyState === 4) {
|
|
512
644
|
if (xmlhttp.status === 200) {
|
|
513
|
-
let response = JSON.parse(xmlhttp.responseText)
|
|
645
|
+
let response = JSON.parse(xmlhttp.responseText)
|
|
514
646
|
|
|
515
|
-
this.isSimulationValid = response.status ===
|
|
647
|
+
this.isSimulationValid = response.status === 'ok'
|
|
516
648
|
|
|
517
649
|
if (this.isSimulationValid) {
|
|
518
|
-
this.checkSimulation(response.data)
|
|
650
|
+
this.checkSimulation(response.data)
|
|
519
651
|
} else {
|
|
520
|
-
this.showUserMessage = false
|
|
521
|
-
this.errorMessage = response.description
|
|
652
|
+
this.showUserMessage = false
|
|
653
|
+
this.errorMessage = response.description
|
|
522
654
|
}
|
|
523
655
|
} else {
|
|
524
|
-
this.showHttpIssue(xmlhttp)
|
|
656
|
+
this.showHttpIssue(xmlhttp)
|
|
525
657
|
}
|
|
526
658
|
}
|
|
527
|
-
}
|
|
528
|
-
xmlhttp.send(JSON.stringify(this.retrieveRequest()))
|
|
529
|
-
})
|
|
659
|
+
}
|
|
660
|
+
xmlhttp.send(JSON.stringify(this.retrieveRequest()))
|
|
661
|
+
})
|
|
530
662
|
},
|
|
531
663
|
},
|
|
532
664
|
created: function () {
|
|
533
665
|
// Try to retrieve the UI information.
|
|
534
666
|
|
|
535
667
|
if (this.idType === IdType.DATASET_ID) {
|
|
536
|
-
this.userMessage =
|
|
537
|
-
this.showUserMessage = true
|
|
668
|
+
this.userMessage = 'Retrieving UI information...'
|
|
669
|
+
this.showUserMessage = true
|
|
538
670
|
|
|
539
671
|
// Retrieve and build the simulation UI.
|
|
540
672
|
|
|
541
673
|
this.$nextTick(() => {
|
|
542
|
-
const xmlhttp = new XMLHttpRequest()
|
|
674
|
+
const xmlhttp = new XMLHttpRequest()
|
|
543
675
|
|
|
544
|
-
xmlhttp.open(
|
|
676
|
+
xmlhttp.open('GET', this.apiLocation + '/simulation_ui_file/' + this.id)
|
|
545
677
|
xmlhttp.onreadystatechange = () => {
|
|
546
678
|
if (xmlhttp.readyState === 4) {
|
|
547
|
-
this.showUserMessage = false
|
|
679
|
+
this.showUserMessage = false
|
|
548
680
|
|
|
549
681
|
if (xmlhttp.status === 200) {
|
|
550
682
|
this.$nextTick(() => {
|
|
551
|
-
this.buildSimulationUi(JSON.parse(xmlhttp.responseText))
|
|
552
|
-
})
|
|
683
|
+
this.buildSimulationUi(JSON.parse(xmlhttp.responseText))
|
|
684
|
+
})
|
|
553
685
|
} else {
|
|
554
|
-
this.errorMessage =
|
|
686
|
+
this.errorMessage = 'the simulation dataset could not be retrieved'
|
|
555
687
|
}
|
|
556
688
|
}
|
|
557
|
-
}
|
|
558
|
-
xmlhttp.send()
|
|
559
|
-
})
|
|
689
|
+
}
|
|
690
|
+
xmlhttp.send()
|
|
691
|
+
})
|
|
560
692
|
} else if (this.idType === IdType.DATASET_URL) {
|
|
561
|
-
this.opencorOmexFile = this.id
|
|
693
|
+
this.opencorOmexFile = this.id
|
|
562
694
|
} else if (this.idType === IdType.PMR_PATH) {
|
|
563
|
-
this.opencorOmexFile = PMR_URL + this.id
|
|
564
|
-
} else {
|
|
565
|
-
|
|
695
|
+
this.opencorOmexFile = PMR_URL + this.id
|
|
696
|
+
} else {
|
|
697
|
+
// IdType.RAW_COMBINE_ARCHIVE
|
|
698
|
+
this.opencorOmexFile = this.id
|
|
566
699
|
}
|
|
567
700
|
},
|
|
568
701
|
mounted: function () {
|
|
@@ -571,20 +704,20 @@ export default {
|
|
|
571
704
|
// idea how long it's going to take to retrieve the simulation UI
|
|
572
705
|
// information.
|
|
573
706
|
|
|
574
|
-
this.isMounted = true
|
|
707
|
+
this.isMounted = true
|
|
575
708
|
|
|
576
|
-
finaliseUi(this)
|
|
709
|
+
finaliseUi(this)
|
|
577
710
|
},
|
|
578
|
-
}
|
|
711
|
+
}
|
|
579
712
|
</script>
|
|
580
713
|
|
|
581
714
|
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
|
582
715
|
<style scoped lang="scss">
|
|
583
716
|
.simulation-vuer {
|
|
584
|
-
--el-color-primary: #
|
|
585
|
-
--el-color-primary-light-7: #
|
|
586
|
-
--el-color-primary-light-8: #
|
|
587
|
-
--el-color-primary-light-9: #
|
|
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;
|
|
588
721
|
}
|
|
589
722
|
|
|
590
723
|
:deep(.el-button:hover) {
|
|
@@ -598,29 +731,32 @@ export default {
|
|
|
598
731
|
|
|
599
732
|
:deep(.el-loading-spinner) {
|
|
600
733
|
.path {
|
|
601
|
-
stroke: #
|
|
734
|
+
stroke: #8300bf;
|
|
602
735
|
}
|
|
603
736
|
|
|
604
737
|
i,
|
|
605
738
|
.el-loading-text {
|
|
606
|
-
color: #
|
|
739
|
+
color: #8300bf;
|
|
607
740
|
}
|
|
608
741
|
}
|
|
609
742
|
|
|
610
|
-
:deep(.p-floatlabel:has(input:focus)) label,
|
|
611
|
-
|
|
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;
|
|
612
748
|
}
|
|
613
749
|
|
|
614
750
|
:deep(.p-inputtext:enabled:focus) {
|
|
615
|
-
|
|
751
|
+
border-color: #8300bf;
|
|
616
752
|
}
|
|
617
753
|
|
|
618
754
|
:deep(.p-select:not(.p-disabled).p-focus) {
|
|
619
|
-
|
|
755
|
+
border-color: #8300bf;
|
|
620
756
|
}
|
|
621
757
|
|
|
622
758
|
:deep(.p-slider-range) {
|
|
623
|
-
background-color: #
|
|
759
|
+
background-color: #8300bf;
|
|
624
760
|
}
|
|
625
761
|
|
|
626
762
|
div.input {
|
|
@@ -823,21 +959,22 @@ span.error {
|
|
|
823
959
|
/* Note: not sure why, but the following rules need to be global!? */
|
|
824
960
|
|
|
825
961
|
.p-select-option:not(.p-select-option-selected):not(.p-disabled).p-focus {
|
|
826
|
-
|
|
962
|
+
background: #f5f7fa !important;
|
|
827
963
|
}
|
|
828
964
|
|
|
829
965
|
.p-select-option.p-select-option-selected.p-focus {
|
|
830
|
-
|
|
831
|
-
|
|
966
|
+
background: #f5f7fa !important;
|
|
967
|
+
color: #8300bf !important;
|
|
832
968
|
}
|
|
833
969
|
|
|
834
970
|
.p-select-option.p-select-option-selected {
|
|
835
|
-
|
|
836
|
-
|
|
971
|
+
background: white !important;
|
|
972
|
+
color: #8300bf !important;
|
|
837
973
|
}
|
|
838
974
|
|
|
839
975
|
.p-select-option-label {
|
|
840
|
-
|
|
841
|
-
|
|
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;
|
|
842
979
|
}
|
|
843
980
|
</style>
|