seqeyes-python 0.3.13__tar.gz → 0.3.15__tar.gz
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.
- {seqeyes_python-0.3.13 → seqeyes_python-0.3.15}/PKG-INFO +1 -1
- {seqeyes_python-0.3.13 → seqeyes_python-0.3.15}/pyproject.toml +1 -1
- {seqeyes_python-0.3.13 → seqeyes_python-0.3.15}/src/seqeyes/__init__.py +1 -1
- {seqeyes_python-0.3.13 → seqeyes_python-0.3.15}/src/seqeyes/resources/pulseq-bundle.js +228 -116
- {seqeyes_python-0.3.13 → seqeyes_python-0.3.15}/.gitignore +0 -0
- {seqeyes_python-0.3.13 → seqeyes_python-0.3.15}/README.md +0 -0
- {seqeyes_python-0.3.13 → seqeyes_python-0.3.15}/examples/demo.ipynb +0 -0
- {seqeyes_python-0.3.13 → seqeyes_python-0.3.15}/examples/demo.py +0 -0
- {seqeyes_python-0.3.13 → seqeyes_python-0.3.15}/src/seqeyes/_plot.py +0 -0
- {seqeyes_python-0.3.13 → seqeyes_python-0.3.15}/src/seqeyes/_renderer.py +0 -0
- {seqeyes_python-0.3.13 → seqeyes_python-0.3.15}/src/seqeyes/resources/seqeyes-labels.js +0 -0
- {seqeyes_python-0.3.13 → seqeyes_python-0.3.15}/src/seqeyes/resources/viewer.html +0 -0
- {seqeyes_python-0.3.13 → seqeyes_python-0.3.15}/src/seqeyes/resources/webview-bundle.js +0 -0
- {seqeyes_python-0.3.13 → seqeyes_python-0.3.15}/tests/conftest.py +0 -0
- {seqeyes_python-0.3.13 → seqeyes_python-0.3.15}/tests/debug_full.html +0 -0
- {seqeyes_python-0.3.13 → seqeyes_python-0.3.15}/tests/debug_minimal.html +0 -0
- {seqeyes_python-0.3.13 → seqeyes_python-0.3.15}/tests/debug_viewer.html +0 -0
- {seqeyes_python-0.3.13 → seqeyes_python-0.3.15}/tests/debug_viewer.py +0 -0
- {seqeyes_python-0.3.13 → seqeyes_python-0.3.15}/tests/integration_test.py +0 -0
- {seqeyes_python-0.3.13 → seqeyes_python-0.3.15}/tests/test_plot.py +0 -0
- {seqeyes_python-0.3.13 → seqeyes_python-0.3.15}/tests/test_renderer.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: seqeyes-python
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.15
|
|
4
4
|
Summary: Interactive Pulseq MRI sequence viewer for Jupyter — lightweight, beautiful, replaces seq.plot() in pypulseq.
|
|
5
5
|
Project-URL: Homepage, https://github.com/bughht/seqeyes_plugin
|
|
6
6
|
Project-URL: Repository, https://github.com/bughht/seqeyes_plugin
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "seqeyes-python"
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.15"
|
|
8
8
|
description = "Interactive Pulseq MRI sequence viewer for Jupyter — lightweight, beautiful, replaces seq.plot() in pypulseq."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "MIT"}
|
|
@@ -24,6 +24,7 @@ var Pulseq = (() => {
|
|
|
24
24
|
var pulseq_browser_exports = {};
|
|
25
25
|
__export(pulseq_browser_exports, {
|
|
26
26
|
INTERACTIVE_COMPUTE_LIMITS: () => INTERACTIVE_COMPUTE_LIMITS,
|
|
27
|
+
MAX_KSPACE_OVERVIEW_POINTS: () => MAX_KSPACE_OVERVIEW_POINTS,
|
|
27
28
|
MAX_RF_RESPONSE_BANDS: () => MAX_RF_RESPONSE_BANDS,
|
|
28
29
|
MAX_RF_RESPONSE_FFT_POINTS: () => MAX_RF_RESPONSE_FFT_POINTS,
|
|
29
30
|
MAX_RF_RESPONSE_SAMPLES: () => MAX_RF_RESPONSE_SAMPLES,
|
|
@@ -89,7 +90,7 @@ var Pulseq = (() => {
|
|
|
89
90
|
});
|
|
90
91
|
|
|
91
92
|
// package.json
|
|
92
|
-
var version = "0.3.
|
|
93
|
+
var version = "0.3.15";
|
|
93
94
|
|
|
94
95
|
// src/pulseq/decompressor.ts
|
|
95
96
|
function decompressShape(compressed, numSamples) {
|
|
@@ -2326,9 +2327,13 @@ var Pulseq = (() => {
|
|
|
2326
2327
|
};
|
|
2327
2328
|
}
|
|
2328
2329
|
function estimateKspacePeakMemoryBytes(estimate) {
|
|
2329
|
-
const gridBytes = Math.max(0, estimate.gridCandidatePoints) *
|
|
2330
|
-
const adcAndTransferBytes = Math.max(0, estimate.adcSamples) *
|
|
2331
|
-
|
|
2330
|
+
const gridBytes = Math.max(0, estimate.gridCandidatePoints) * 1;
|
|
2331
|
+
const adcAndTransferBytes = Math.max(0, estimate.adcSamples) * 43;
|
|
2332
|
+
const fixedOverheadBytes = 2 * 1024 * 1024;
|
|
2333
|
+
return Math.ceil(Math.min(
|
|
2334
|
+
Number.MAX_SAFE_INTEGER,
|
|
2335
|
+
(gridBytes + adcAndTransferBytes) * 1.25 + fixedOverheadBytes
|
|
2336
|
+
));
|
|
2332
2337
|
}
|
|
2333
2338
|
function kspaceExceedsInteractiveBudget(estimate) {
|
|
2334
2339
|
return estimate.rasterSamples > INTERACTIVE_COMPUTE_LIMITS.kspaceRasterSamples || estimate.adcSamples > INTERACTIVE_COMPUTE_LIMITS.kspaceAdcSamples || estimate.gridCandidatePoints > INTERACTIVE_COMPUTE_LIMITS.kspaceGridCandidates || estimateKspacePeakMemoryBytes(estimate) >= KSPACE_CONFIRMATION_MEMORY_BYTES;
|
|
@@ -3102,9 +3107,19 @@ var Pulseq = (() => {
|
|
|
3102
3107
|
}
|
|
3103
3108
|
}
|
|
3104
3109
|
const gradientSeries = buildGlobalGradientSeries(blocks, GR, totalDuration);
|
|
3105
|
-
|
|
3110
|
+
let candBound = 2;
|
|
3111
|
+
for (const series of gradientSeries) candBound += countSeriesSupport(series, gradientSupport);
|
|
3112
|
+
candBound += excT.length * 3 + refT.length * 2 + adcT.length;
|
|
3113
|
+
const cand = new Float64Array(candBound);
|
|
3114
|
+
let candCount = 0;
|
|
3115
|
+
let candOverflow = false;
|
|
3106
3116
|
const pushC = (t) => {
|
|
3107
|
-
if (isFinite(t) && t >= -tacc)
|
|
3117
|
+
if (!(isFinite(t) && t >= -tacc)) return;
|
|
3118
|
+
if (candCount >= cand.length) {
|
|
3119
|
+
candOverflow = true;
|
|
3120
|
+
return;
|
|
3121
|
+
}
|
|
3122
|
+
cand[candCount++] = Math.max(0, tacc * Math.round(t / tacc));
|
|
3108
3123
|
};
|
|
3109
3124
|
for (const series of gradientSeries) collectSeriesSupport(series, gradientSupport, pushC);
|
|
3110
3125
|
for (const t of excT) {
|
|
@@ -3119,100 +3134,208 @@ var Pulseq = (() => {
|
|
|
3119
3134
|
for (const t of adcT) pushC(t);
|
|
3120
3135
|
pushC(0);
|
|
3121
3136
|
pushC(totalDuration);
|
|
3122
|
-
if (
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3137
|
+
if (candOverflow) return null;
|
|
3138
|
+
if (candCount === 0) return null;
|
|
3139
|
+
cand.subarray(0, candCount).sort();
|
|
3140
|
+
let kept = 0;
|
|
3141
|
+
for (let i = 0; i < candCount; i++) {
|
|
3142
|
+
if (i === 0 || cand[i] - cand[i - 1] > tacc * 0.5) cand[kept++] = cand[i];
|
|
3143
|
+
}
|
|
3144
|
+
const storedCount = kept;
|
|
3145
|
+
const rasterSteps = totalDuration > 0 ? Math.max(1, Math.round(totalDuration / GR)) : -1;
|
|
3146
|
+
const rasterAt = (i) => Math.max(0, tacc * Math.round(i * GR / tacc));
|
|
3147
|
+
const makeGridWalk = () => {
|
|
3148
|
+
let storedIndex = 0;
|
|
3149
|
+
let rasterIndex = 0;
|
|
3150
|
+
let previous = 0;
|
|
3151
|
+
let started = false;
|
|
3152
|
+
return () => {
|
|
3153
|
+
for (; ; ) {
|
|
3154
|
+
const haveStored = storedIndex < storedCount;
|
|
3155
|
+
const haveRaster = rasterIndex <= rasterSteps;
|
|
3156
|
+
if (!haveStored && !haveRaster) return NaN;
|
|
3157
|
+
let value;
|
|
3158
|
+
if (!haveRaster) {
|
|
3159
|
+
value = cand[storedIndex++];
|
|
3160
|
+
} else if (!haveStored) {
|
|
3161
|
+
value = rasterAt(rasterIndex++);
|
|
3162
|
+
} else {
|
|
3163
|
+
const stored = cand[storedIndex];
|
|
3164
|
+
const raster = rasterAt(rasterIndex);
|
|
3165
|
+
if (stored <= raster) {
|
|
3166
|
+
value = stored;
|
|
3167
|
+
storedIndex++;
|
|
3168
|
+
if (stored === raster) rasterIndex++;
|
|
3169
|
+
} else {
|
|
3170
|
+
value = raster;
|
|
3171
|
+
rasterIndex++;
|
|
3172
|
+
}
|
|
3173
|
+
}
|
|
3174
|
+
if (!started || value !== previous) {
|
|
3175
|
+
previous = value;
|
|
3176
|
+
started = true;
|
|
3177
|
+
return value;
|
|
3178
|
+
}
|
|
3179
|
+
}
|
|
3180
|
+
};
|
|
3181
|
+
};
|
|
3182
|
+
const excSorted = Float64Array.from(excT);
|
|
3183
|
+
excSorted.sort();
|
|
3184
|
+
const refSorted = Float64Array.from(refT);
|
|
3185
|
+
refSorted.sort();
|
|
3186
|
+
const eIdx = [], rIdx = [];
|
|
3187
|
+
let excSeen = 0, refSeen = 0;
|
|
3188
|
+
let N = 0;
|
|
3189
|
+
{
|
|
3190
|
+
const nextGridTime2 = makeGridWalk();
|
|
3191
|
+
for (; ; ) {
|
|
3192
|
+
const t = nextGridTime2();
|
|
3193
|
+
if (Number.isNaN(t)) break;
|
|
3194
|
+
while (excSeen < excSorted.length && t >= excSorted[excSeen] - 1e-12) {
|
|
3195
|
+
eIdx.push(N);
|
|
3196
|
+
excSeen++;
|
|
3197
|
+
}
|
|
3198
|
+
while (refSeen < refSorted.length && t >= refSorted[refSeen] - 1e-12) {
|
|
3199
|
+
rIdx.push(N);
|
|
3200
|
+
refSeen++;
|
|
3201
|
+
}
|
|
3202
|
+
N++;
|
|
3203
|
+
}
|
|
3131
3204
|
}
|
|
3132
|
-
const N = grid.length;
|
|
3133
3205
|
if (N < 2) return null;
|
|
3134
3206
|
if (_options?.maxGridPoints && N > _options.maxGridPoints) return null;
|
|
3135
|
-
|
|
3207
|
+
let excCursor = 0, refCursor = 0;
|
|
3208
|
+
const excitationAtIndex = (i) => {
|
|
3209
|
+
while (excCursor < eIdx.length && eIdx[excCursor] < i) excCursor++;
|
|
3210
|
+
return excCursor < eIdx.length && eIdx[excCursor] === i;
|
|
3211
|
+
};
|
|
3212
|
+
const refocusingAtIndex = (i) => {
|
|
3213
|
+
while (refCursor < rIdx.length && rIdx[refCursor] < i) refCursor++;
|
|
3214
|
+
return refCursor < rIdx.length && rIdx[refCursor] === i;
|
|
3215
|
+
};
|
|
3216
|
+
const outCount = _options?.maxTrajectoryPoints && _options.maxTrajectoryPoints > 0 ? Math.min(_options.maxTrajectoryPoints, N) : N;
|
|
3217
|
+
const outStep = N / outCount;
|
|
3218
|
+
const outX = new Float64Array(outCount), outY = new Float64Array(outCount), outZ = new Float64Array(outCount);
|
|
3219
|
+
const outT = new Float64Array(outCount);
|
|
3220
|
+
const nA = adcT.length;
|
|
3221
|
+
const f32Adc = _options?.adcPrecision === "f32";
|
|
3222
|
+
const kxA = f32Adc ? new Float32Array(nA) : new Float64Array(nA);
|
|
3223
|
+
const kyA = f32Adc ? new Float32Array(nA) : new Float64Array(nA);
|
|
3224
|
+
const kzA = f32Adc ? new Float32Array(nA) : new Float64Array(nA);
|
|
3136
3225
|
const cursors = [0, 0, 0];
|
|
3137
|
-
for (let i = 0; i < N; i++) {
|
|
3138
|
-
const t = grid[i];
|
|
3139
|
-
gx[i] = sampleSeries(gradientSeries[0], t, cursors, 0);
|
|
3140
|
-
gy[i] = sampleSeries(gradientSeries[1], t, cursors, 1);
|
|
3141
|
-
gz[i] = sampleSeries(gradientSeries[2], t, cursors, 2);
|
|
3142
|
-
}
|
|
3143
|
-
const eIdx = [], rIdx = [];
|
|
3144
|
-
for (const t of excT) {
|
|
3145
|
-
const i = timeIdx(t, grid);
|
|
3146
|
-
if (i >= 0) eIdx.push(i);
|
|
3147
|
-
}
|
|
3148
|
-
for (const t of refT) {
|
|
3149
|
-
const i = timeIdx(t, grid);
|
|
3150
|
-
if (i >= 0) rIdx.push(i);
|
|
3151
|
-
}
|
|
3152
|
-
eIdx.sort((a, b) => a - b);
|
|
3153
|
-
rIdx.sort((a, b) => a - b);
|
|
3154
|
-
const excitationAt = new Uint8Array(N);
|
|
3155
|
-
const refocusingAt = new Uint8Array(N);
|
|
3156
|
-
for (const i of eIdx) excitationAt[i] = 1;
|
|
3157
|
-
for (const i of rIdx) refocusingAt[i] = 1;
|
|
3158
|
-
const kx = new Float64Array(N), ky = new Float64Array(N), kz = new Float64Array(N);
|
|
3159
3226
|
let cx = 0, cy = 0, cz = 0;
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3227
|
+
let lx = 0, ly = 0, lz = 0;
|
|
3228
|
+
let a = 0;
|
|
3229
|
+
let out = 0;
|
|
3230
|
+
let nextKeep = 0;
|
|
3231
|
+
let ec = 0;
|
|
3232
|
+
const nextGridTime = makeGridWalk();
|
|
3233
|
+
let tPrev = nextGridTime();
|
|
3234
|
+
let gxPrev = sampleSeries(gradientSeries[0], tPrev, cursors, 0);
|
|
3235
|
+
let gyPrev = sampleSeries(gradientSeries[1], tPrev, cursors, 1);
|
|
3236
|
+
let gzPrev = sampleSeries(gradientSeries[2], tPrev, cursors, 2);
|
|
3237
|
+
if (refocusingAtIndex(0) && !excitationAtIndex(0)) {
|
|
3238
|
+
lx = -lx;
|
|
3239
|
+
ly = -ly;
|
|
3240
|
+
lz = -lz;
|
|
3241
|
+
}
|
|
3242
|
+
if (nextKeep === 0) {
|
|
3243
|
+
while (ec < eIdx.length && eIdx[ec] < 1) ec++;
|
|
3244
|
+
const brk = ec < eIdx.length && eIdx[ec] === 1;
|
|
3245
|
+
outT[0] = tPrev;
|
|
3246
|
+
outX[0] = brk ? NaN : lx;
|
|
3247
|
+
outY[0] = brk ? NaN : ly;
|
|
3248
|
+
outZ[0] = brk ? NaN : lz;
|
|
3249
|
+
out = 1;
|
|
3250
|
+
nextKeep = out < outCount ? Math.floor(out * outStep) : -1;
|
|
3251
|
+
}
|
|
3252
|
+
while (a < nA && adcT[a] <= tPrev) {
|
|
3253
|
+
kxA[a] = lx;
|
|
3254
|
+
kyA[a] = ly;
|
|
3255
|
+
kzA[a] = lz;
|
|
3256
|
+
a++;
|
|
3164
3257
|
}
|
|
3165
3258
|
for (let i = 1; i < N; i++) {
|
|
3166
|
-
const
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3259
|
+
const tCur = nextGridTime();
|
|
3260
|
+
const gxi = sampleSeries(gradientSeries[0], tCur, cursors, 0);
|
|
3261
|
+
const gyi = sampleSeries(gradientSeries[1], tCur, cursors, 1);
|
|
3262
|
+
const gzi = sampleSeries(gradientSeries[2], tCur, cursors, 2);
|
|
3263
|
+
const dt = tCur - tPrev;
|
|
3264
|
+
const px = lx, py = ly, pz = lz;
|
|
3265
|
+
if (dt > 0) {
|
|
3266
|
+
const dx = 0.5 * (gxPrev + gxi) * dt;
|
|
3267
|
+
const dy = 0.5 * (gyPrev + gyi) * dt;
|
|
3268
|
+
const dz = 0.5 * (gzPrev + gzi) * dt;
|
|
3269
|
+
const yx = dx - cx, yy = dy - cy, yz = dz - cz;
|
|
3270
|
+
const nx = lx + yx, ny = ly + yy, nz = lz + yz;
|
|
3271
|
+
cx = nx - lx - yx;
|
|
3272
|
+
cy = ny - ly - yy;
|
|
3273
|
+
cz = nz - lz - yz;
|
|
3274
|
+
lx = nx;
|
|
3275
|
+
ly = ny;
|
|
3276
|
+
lz = nz;
|
|
3277
|
+
if (excitationAtIndex(i)) {
|
|
3278
|
+
lx = 0;
|
|
3279
|
+
ly = 0;
|
|
3280
|
+
lz = 0;
|
|
3281
|
+
cx = 0;
|
|
3282
|
+
cy = 0;
|
|
3283
|
+
cz = 0;
|
|
3284
|
+
} else if (refocusingAtIndex(i)) {
|
|
3285
|
+
lx = -lx;
|
|
3286
|
+
ly = -ly;
|
|
3287
|
+
lz = -lz;
|
|
3288
|
+
cx = -cx;
|
|
3289
|
+
cy = -cy;
|
|
3290
|
+
cz = -cz;
|
|
3291
|
+
}
|
|
3172
3292
|
}
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
cx = -cx;
|
|
3196
|
-
cy = -cy;
|
|
3197
|
-
cz = -cz;
|
|
3198
|
-
}
|
|
3199
|
-
}
|
|
3200
|
-
const kxP = new Float64Array(kx), kyP = new Float64Array(ky), kzP = new Float64Array(kz);
|
|
3201
|
-
for (const i of eIdx) {
|
|
3202
|
-
if (i > 0) {
|
|
3203
|
-
kxP[i - 1] = NaN;
|
|
3204
|
-
kyP[i - 1] = NaN;
|
|
3205
|
-
kzP[i - 1] = NaN;
|
|
3293
|
+
if (i === nextKeep) {
|
|
3294
|
+
while (ec < eIdx.length && eIdx[ec] < i + 1) ec++;
|
|
3295
|
+
const brk = ec < eIdx.length && eIdx[ec] === i + 1;
|
|
3296
|
+
outT[out] = tCur;
|
|
3297
|
+
outX[out] = brk ? NaN : lx;
|
|
3298
|
+
outY[out] = brk ? NaN : ly;
|
|
3299
|
+
outZ[out] = brk ? NaN : lz;
|
|
3300
|
+
out++;
|
|
3301
|
+
nextKeep = out < outCount ? Math.floor(out * outStep) : -1;
|
|
3302
|
+
}
|
|
3303
|
+
while (a < nA && adcT[a] <= tCur) {
|
|
3304
|
+
const t = adcT[a];
|
|
3305
|
+
if (Math.abs(tCur - t) < 1e-12 || dt <= 0) {
|
|
3306
|
+
kxA[a] = lx;
|
|
3307
|
+
kyA[a] = ly;
|
|
3308
|
+
kzA[a] = lz;
|
|
3309
|
+
} else {
|
|
3310
|
+
kxA[a] = px + (lx - px) * (t - tPrev) / dt;
|
|
3311
|
+
kyA[a] = py + (ly - py) * (t - tPrev) / dt;
|
|
3312
|
+
kzA[a] = pz + (lz - pz) * (t - tPrev) / dt;
|
|
3313
|
+
}
|
|
3314
|
+
a++;
|
|
3206
3315
|
}
|
|
3316
|
+
gxPrev = gxi;
|
|
3317
|
+
gyPrev = gyi;
|
|
3318
|
+
gzPrev = gzi;
|
|
3319
|
+
tPrev = tCur;
|
|
3207
3320
|
}
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
kzA[a] = interp(kz, grid, adcT[a]);
|
|
3321
|
+
while (a < nA) {
|
|
3322
|
+
kxA[a] = lx;
|
|
3323
|
+
kyA[a] = ly;
|
|
3324
|
+
kzA[a] = lz;
|
|
3325
|
+
a++;
|
|
3214
3326
|
}
|
|
3215
|
-
|
|
3327
|
+
const tAdc = adcIdx === adcT.length ? adcT : adcT.slice(0, adcIdx);
|
|
3328
|
+
return {
|
|
3329
|
+
ktraj: [outX, outY, outZ],
|
|
3330
|
+
t_ktraj: outT,
|
|
3331
|
+
ktraj_adc: [kxA, kyA, kzA],
|
|
3332
|
+
t_adc: tAdc,
|
|
3333
|
+
rasterSampleCount: N
|
|
3334
|
+
};
|
|
3335
|
+
}
|
|
3336
|
+
function countSeriesSupport(series, mode) {
|
|
3337
|
+
if (series.times.length < 2) return 0;
|
|
3338
|
+
return mode === "all" ? series.times.length : series.requiredSupport.length;
|
|
3216
3339
|
}
|
|
3217
3340
|
function collectSeriesSupport(series, mode, push) {
|
|
3218
3341
|
if (series.times.length < 2) return;
|
|
@@ -3222,6 +3345,17 @@ var Pulseq = (() => {
|
|
|
3222
3345
|
}
|
|
3223
3346
|
for (const time of series.requiredSupport) push(time);
|
|
3224
3347
|
}
|
|
3348
|
+
function freezeSeries(series) {
|
|
3349
|
+
const frozen = {
|
|
3350
|
+
times: Float64Array.from(series.times),
|
|
3351
|
+
values: Float64Array.from(series.values),
|
|
3352
|
+
requiredSupport: Float64Array.from(series.requiredSupport)
|
|
3353
|
+
};
|
|
3354
|
+
series.times.length = 0;
|
|
3355
|
+
series.values.length = 0;
|
|
3356
|
+
series.requiredSupport.length = 0;
|
|
3357
|
+
return frozen;
|
|
3358
|
+
}
|
|
3225
3359
|
function buildGlobalGradientSeries(blocks, gradientRaster, totalDuration) {
|
|
3226
3360
|
const output = [
|
|
3227
3361
|
{ times: [], values: [], requiredSupport: [] },
|
|
@@ -3249,7 +3383,7 @@ var Pulseq = (() => {
|
|
|
3249
3383
|
series.requiredSupport.push(last + POLYNOMIAL_SUPPORT_EPSILON_SEC, totalDuration + POLYNOMIAL_SUPPORT_EPSILON_SEC);
|
|
3250
3384
|
}
|
|
3251
3385
|
}
|
|
3252
|
-
return output;
|
|
3386
|
+
return [freezeSeries(output[0]), freezeSeries(output[1]), freezeSeries(output[2])];
|
|
3253
3387
|
}
|
|
3254
3388
|
function appendGradientPiece(target, piece, gradientRaster) {
|
|
3255
3389
|
if (!piece.times.length) return;
|
|
@@ -3303,31 +3437,9 @@ var Pulseq = (() => {
|
|
|
3303
3437
|
if (time >= t1) return v1;
|
|
3304
3438
|
return v0 + (v1 - v0) * (time - t0) / (t1 - t0);
|
|
3305
3439
|
}
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
const m = lo + hi >> 1;
|
|
3310
|
-
if (g[m] < t - 1e-12) lo = m + 1;
|
|
3311
|
-
else hi = m;
|
|
3312
|
-
}
|
|
3313
|
-
return lo < g.length ? lo : -1;
|
|
3314
|
-
}
|
|
3315
|
-
function interp(d, g, t) {
|
|
3316
|
-
const n = g.length;
|
|
3317
|
-
if (n === 0) return 0;
|
|
3318
|
-
let lo = 0, hi = n;
|
|
3319
|
-
while (lo < hi) {
|
|
3320
|
-
const m = lo + hi >> 1;
|
|
3321
|
-
if (g[m] < t) lo = m + 1;
|
|
3322
|
-
else hi = m;
|
|
3323
|
-
}
|
|
3324
|
-
if (lo === 0) return d[0];
|
|
3325
|
-
if (lo >= n) return d[n - 1];
|
|
3326
|
-
if (Math.abs(g[lo] - t) < 1e-12) return d[lo];
|
|
3327
|
-
const i0 = lo - 1, i1 = lo, dt = g[i1] - g[i0];
|
|
3328
|
-
if (dt <= 0) return d[i1];
|
|
3329
|
-
return d[i0] + (d[i1] - d[i0]) * (t - g[i0]) / dt;
|
|
3330
|
-
}
|
|
3440
|
+
|
|
3441
|
+
// src/editor/kspaceTransport.ts
|
|
3442
|
+
var MAX_KSPACE_OVERVIEW_POINTS = 3e4;
|
|
3331
3443
|
|
|
3332
3444
|
// src/pulseq/labels.ts
|
|
3333
3445
|
var COUNTER_ORDER = ["SLC", "SEG", "REP", "AVG", "SET", "ECO", "PHS", "LIN", "PAR", "ACQ", "TRID", "ONCE"];
|
|
@@ -5670,7 +5782,7 @@ var Pulseq = (() => {
|
|
|
5670
5782
|
},
|
|
5671
5783
|
totalDurationSec,
|
|
5672
5784
|
adcSampleCount: kspace.t_adc.length,
|
|
5673
|
-
trajectorySampleCount: kspace.
|
|
5785
|
+
trajectorySampleCount: kspace.rasterSampleCount,
|
|
5674
5786
|
units: {
|
|
5675
5787
|
trajectory: "1/m",
|
|
5676
5788
|
time: "s",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|